1 /* Server address list management 2 * 3 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11 12 #include <linux/slab.h> 13 #include <linux/ctype.h> 14 #include <linux/dns_resolver.h> 15 #include <linux/inet.h> 16 #include <keys/rxrpc-type.h> 17 #include "internal.h" 18 #include "afs_fs.h" 19 20 /* 21 * Release an address list. 22 */ 23 void afs_put_addrlist(struct afs_addr_list *alist) 24 { 25 if (alist && refcount_dec_and_test(&alist->usage)) 26 call_rcu(&alist->rcu, (rcu_callback_t)kfree); 27 } 28 29 /* 30 * Allocate an address list. 31 */ 32 struct afs_addr_list *afs_alloc_addrlist(unsigned int nr, 33 unsigned short service, 34 unsigned short port) 35 { 36 struct afs_addr_list *alist; 37 unsigned int i; 38 39 _enter("%u,%u,%u", nr, service, port); 40 41 if (nr > AFS_MAX_ADDRESSES) 42 nr = AFS_MAX_ADDRESSES; 43 44 alist = kzalloc(struct_size(alist, addrs, nr), GFP_KERNEL); 45 if (!alist) 46 return NULL; 47 48 refcount_set(&alist->usage, 1); 49 alist->max_addrs = nr; 50 51 for (i = 0; i < nr; i++) { 52 struct sockaddr_rxrpc *srx = &alist->addrs[i]; 53 srx->srx_family = AF_RXRPC; 54 srx->srx_service = service; 55 srx->transport_type = SOCK_DGRAM; 56 srx->transport_len = sizeof(srx->transport.sin6); 57 srx->transport.sin6.sin6_family = AF_INET6; 58 srx->transport.sin6.sin6_port = htons(port); 59 } 60 61 return alist; 62 } 63 64 /* 65 * Parse a text string consisting of delimited addresses. 66 */ 67 struct afs_addr_list *afs_parse_text_addrs(const char *text, size_t len, 68 char delim, 69 unsigned short service, 70 unsigned short port) 71 { 72 struct afs_addr_list *alist; 73 const char *p, *end = text + len; 74 unsigned int nr = 0; 75 76 _enter("%*.*s,%c", (int)len, (int)len, text, delim); 77 78 if (!len) 79 return ERR_PTR(-EDESTADDRREQ); 80 81 if (delim == ':' && (memchr(text, ',', len) || !memchr(text, '.', len))) 82 delim = ','; 83 84 /* Count the addresses */ 85 p = text; 86 do { 87 if (!*p) 88 return ERR_PTR(-EINVAL); 89 if (*p == delim) 90 continue; 91 nr++; 92 if (*p == '[') { 93 p++; 94 if (p == end) 95 return ERR_PTR(-EINVAL); 96 p = memchr(p, ']', end - p); 97 if (!p) 98 return ERR_PTR(-EINVAL); 99 p++; 100 if (p >= end) 101 break; 102 } 103 104 p = memchr(p, delim, end - p); 105 if (!p) 106 break; 107 p++; 108 } while (p < end); 109 110 _debug("%u/%u addresses", nr, AFS_MAX_ADDRESSES); 111 112 alist = afs_alloc_addrlist(nr, service, port); 113 if (!alist) 114 return ERR_PTR(-ENOMEM); 115 116 /* Extract the addresses */ 117 p = text; 118 do { 119 const char *q, *stop; 120 unsigned int xport = port; 121 __be32 x[4]; 122 int family; 123 124 if (*p == delim) { 125 p++; 126 continue; 127 } 128 129 if (*p == '[') { 130 p++; 131 q = memchr(p, ']', end - p); 132 } else { 133 for (q = p; q < end; q++) 134 if (*q == '+' || *q == delim) 135 break; 136 } 137 138 if (in4_pton(p, q - p, (u8 *)&x[0], -1, &stop)) 139 family = AF_INET; 140 else if (in6_pton(p, q - p, (u8 *)x, -1, &stop)) 141 family = AF_INET6; 142 else 143 goto bad_address; 144 145 if (stop != q) 146 goto bad_address; 147 148 p = q; 149 if (q < end && *q == ']') 150 p++; 151 152 if (p < end) { 153 if (*p == '+') { 154 /* Port number specification "+1234" */ 155 xport = 0; 156 p++; 157 if (p >= end || !isdigit(*p)) 158 goto bad_address; 159 do { 160 xport *= 10; 161 xport += *p - '0'; 162 if (xport > 65535) 163 goto bad_address; 164 p++; 165 } while (p < end && isdigit(*p)); 166 } else if (*p == delim) { 167 p++; 168 } else { 169 goto bad_address; 170 } 171 } 172 173 if (family == AF_INET) 174 afs_merge_fs_addr4(alist, x[0], xport); 175 else 176 afs_merge_fs_addr6(alist, x, xport); 177 178 } while (p < end); 179 180 _leave(" = [nr %u]", alist->nr_addrs); 181 return alist; 182 183 bad_address: 184 kfree(alist); 185 return ERR_PTR(-EINVAL); 186 } 187 188 /* 189 * Compare old and new address lists to see if there's been any change. 190 * - How to do this in better than O(Nlog(N)) time? 191 * - We don't really want to sort the address list, but would rather take the 192 * list as we got it so as not to undo record rotation by the DNS server. 193 */ 194 #if 0 195 static int afs_cmp_addr_list(const struct afs_addr_list *a1, 196 const struct afs_addr_list *a2) 197 { 198 } 199 #endif 200 201 /* 202 * Perform a DNS query for VL servers and build a up an address list. 203 */ 204 struct afs_addr_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry) 205 { 206 struct afs_addr_list *alist; 207 char *vllist = NULL; 208 int ret; 209 210 _enter("%s", cell->name); 211 212 ret = dns_query("afsdb", cell->name, cell->name_len, 213 "", &vllist, _expiry); 214 if (ret < 0) 215 return ERR_PTR(ret); 216 217 alist = afs_parse_text_addrs(vllist, strlen(vllist), ',', 218 VL_SERVICE, AFS_VL_PORT); 219 if (IS_ERR(alist)) { 220 kfree(vllist); 221 if (alist != ERR_PTR(-ENOMEM)) 222 pr_err("Failed to parse DNS data\n"); 223 return alist; 224 } 225 226 kfree(vllist); 227 return alist; 228 } 229 230 /* 231 * Merge an IPv4 entry into a fileserver address list. 232 */ 233 void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) 234 { 235 struct sockaddr_rxrpc *srx; 236 u32 addr = ntohl(xdr); 237 int i; 238 239 if (alist->nr_addrs >= alist->max_addrs) 240 return; 241 242 for (i = 0; i < alist->nr_ipv4; i++) { 243 struct sockaddr_in *a = &alist->addrs[i].transport.sin; 244 u32 a_addr = ntohl(a->sin_addr.s_addr); 245 u16 a_port = ntohs(a->sin_port); 246 247 if (addr == a_addr && port == a_port) 248 return; 249 if (addr == a_addr && port < a_port) 250 break; 251 if (addr < a_addr) 252 break; 253 } 254 255 if (i < alist->nr_addrs) 256 memmove(alist->addrs + i + 1, 257 alist->addrs + i, 258 sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); 259 260 srx = &alist->addrs[i]; 261 srx->transport_len = sizeof(srx->transport.sin); 262 srx->transport.sin.sin_family = AF_INET; 263 srx->transport.sin.sin_port = htons(port); 264 srx->transport.sin.sin_addr.s_addr = xdr; 265 alist->nr_ipv4++; 266 alist->nr_addrs++; 267 } 268 269 /* 270 * Merge an IPv6 entry into a fileserver address list. 271 */ 272 void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) 273 { 274 struct sockaddr_rxrpc *srx; 275 int i, diff; 276 277 if (alist->nr_addrs >= alist->max_addrs) 278 return; 279 280 for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { 281 struct sockaddr_in6 *a = &alist->addrs[i].transport.sin6; 282 u16 a_port = ntohs(a->sin6_port); 283 284 diff = memcmp(xdr, &a->sin6_addr, 16); 285 if (diff == 0 && port == a_port) 286 return; 287 if (diff == 0 && port < a_port) 288 break; 289 if (diff < 0) 290 break; 291 } 292 293 if (i < alist->nr_addrs) 294 memmove(alist->addrs + i + 1, 295 alist->addrs + i, 296 sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); 297 298 srx = &alist->addrs[i]; 299 srx->transport_len = sizeof(srx->transport.sin6); 300 srx->transport.sin6.sin6_family = AF_INET6; 301 srx->transport.sin6.sin6_port = htons(port); 302 memcpy(&srx->transport.sin6.sin6_addr, xdr, 16); 303 alist->nr_addrs++; 304 } 305 306 /* 307 * Get an address to try. 308 */ 309 bool afs_iterate_addresses(struct afs_addr_cursor *ac) 310 { 311 _enter("%hu+%hd", ac->start, (short)ac->index); 312 313 if (!ac->alist) 314 return false; 315 316 if (ac->begun) { 317 ac->index++; 318 if (ac->index == ac->alist->nr_addrs) 319 ac->index = 0; 320 321 if (ac->index == ac->start) { 322 ac->error = -EDESTADDRREQ; 323 return false; 324 } 325 } 326 327 ac->begun = true; 328 ac->responded = false; 329 ac->addr = &ac->alist->addrs[ac->index]; 330 return true; 331 } 332 333 /* 334 * Release an address list cursor. 335 */ 336 int afs_end_cursor(struct afs_addr_cursor *ac) 337 { 338 struct afs_addr_list *alist; 339 340 alist = ac->alist; 341 if (alist) { 342 if (ac->responded && ac->index != ac->start) 343 WRITE_ONCE(alist->index, ac->index); 344 afs_put_addrlist(alist); 345 } 346 347 ac->addr = NULL; 348 ac->alist = NULL; 349 ac->begun = false; 350 return ac->error; 351 } 352 353 /* 354 * Set the address cursor for iterating over VL servers. 355 */ 356 int afs_set_vl_cursor(struct afs_addr_cursor *ac, struct afs_cell *cell) 357 { 358 struct afs_addr_list *alist; 359 int ret; 360 361 if (!rcu_access_pointer(cell->vl_addrs)) { 362 ret = wait_on_bit(&cell->flags, AFS_CELL_FL_NO_LOOKUP_YET, 363 TASK_INTERRUPTIBLE); 364 if (ret < 0) 365 return ret; 366 367 if (!rcu_access_pointer(cell->vl_addrs) && 368 ktime_get_real_seconds() < cell->dns_expiry) 369 return cell->error; 370 } 371 372 read_lock(&cell->vl_addrs_lock); 373 alist = rcu_dereference_protected(cell->vl_addrs, 374 lockdep_is_held(&cell->vl_addrs_lock)); 375 if (alist->nr_addrs > 0) 376 afs_get_addrlist(alist); 377 else 378 alist = NULL; 379 read_unlock(&cell->vl_addrs_lock); 380 381 if (!alist) 382 return -EDESTADDRREQ; 383 384 ac->alist = alist; 385 ac->addr = NULL; 386 ac->start = READ_ONCE(alist->index); 387 ac->index = ac->start; 388 ac->error = 0; 389 ac->begun = false; 390 return 0; 391 } 392