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_vlserver_list *afs_parse_text_addrs(struct afs_net *net, 68 const char *text, size_t len, 69 char delim, 70 unsigned short service, 71 unsigned short port) 72 { 73 struct afs_vlserver_list *vllist; 74 struct afs_addr_list *alist; 75 const char *p, *end = text + len; 76 const char *problem; 77 unsigned int nr = 0; 78 int ret = -ENOMEM; 79 80 _enter("%*.*s,%c", (int)len, (int)len, text, delim); 81 82 if (!len) { 83 _leave(" = -EDESTADDRREQ [empty]"); 84 return ERR_PTR(-EDESTADDRREQ); 85 } 86 87 if (delim == ':' && (memchr(text, ',', len) || !memchr(text, '.', len))) 88 delim = ','; 89 90 /* Count the addresses */ 91 p = text; 92 do { 93 if (!*p) { 94 problem = "nul"; 95 goto inval; 96 } 97 if (*p == delim) 98 continue; 99 nr++; 100 if (*p == '[') { 101 p++; 102 if (p == end) { 103 problem = "brace1"; 104 goto inval; 105 } 106 p = memchr(p, ']', end - p); 107 if (!p) { 108 problem = "brace2"; 109 goto inval; 110 } 111 p++; 112 if (p >= end) 113 break; 114 } 115 116 p = memchr(p, delim, end - p); 117 if (!p) 118 break; 119 p++; 120 } while (p < end); 121 122 _debug("%u/%u addresses", nr, AFS_MAX_ADDRESSES); 123 124 vllist = afs_alloc_vlserver_list(1); 125 if (!vllist) 126 return ERR_PTR(-ENOMEM); 127 128 vllist->nr_servers = 1; 129 vllist->servers[0].server = afs_alloc_vlserver("<dummy>", 7, AFS_VL_PORT); 130 if (!vllist->servers[0].server) 131 goto error_vl; 132 133 alist = afs_alloc_addrlist(nr, service, AFS_VL_PORT); 134 if (!alist) 135 goto error; 136 137 /* Extract the addresses */ 138 p = text; 139 do { 140 const char *q, *stop; 141 unsigned int xport = port; 142 __be32 x[4]; 143 int family; 144 145 if (*p == delim) { 146 p++; 147 continue; 148 } 149 150 if (*p == '[') { 151 p++; 152 q = memchr(p, ']', end - p); 153 } else { 154 for (q = p; q < end; q++) 155 if (*q == '+' || *q == delim) 156 break; 157 } 158 159 if (in4_pton(p, q - p, (u8 *)&x[0], -1, &stop)) { 160 family = AF_INET; 161 } else if (in6_pton(p, q - p, (u8 *)x, -1, &stop)) { 162 family = AF_INET6; 163 } else { 164 problem = "family"; 165 goto bad_address; 166 } 167 168 p = q; 169 if (stop != p) { 170 problem = "nostop"; 171 goto bad_address; 172 } 173 174 if (q < end && *q == ']') 175 p++; 176 177 if (p < end) { 178 if (*p == '+') { 179 /* Port number specification "+1234" */ 180 xport = 0; 181 p++; 182 if (p >= end || !isdigit(*p)) { 183 problem = "port"; 184 goto bad_address; 185 } 186 do { 187 xport *= 10; 188 xport += *p - '0'; 189 if (xport > 65535) { 190 problem = "pval"; 191 goto bad_address; 192 } 193 p++; 194 } while (p < end && isdigit(*p)); 195 } else if (*p == delim) { 196 p++; 197 } else { 198 problem = "weird"; 199 goto bad_address; 200 } 201 } 202 203 if (family == AF_INET) 204 afs_merge_fs_addr4(alist, x[0], xport); 205 else 206 afs_merge_fs_addr6(alist, x, xport); 207 208 } while (p < end); 209 210 rcu_assign_pointer(vllist->servers[0].server->addresses, alist); 211 _leave(" = [nr %u]", alist->nr_addrs); 212 return vllist; 213 214 inval: 215 _leave(" = -EINVAL [%s %zu %*.*s]", 216 problem, p - text, (int)len, (int)len, text); 217 return ERR_PTR(-EINVAL); 218 bad_address: 219 _leave(" = -EINVAL [%s %zu %*.*s]", 220 problem, p - text, (int)len, (int)len, text); 221 ret = -EINVAL; 222 error: 223 afs_put_addrlist(alist); 224 error_vl: 225 afs_put_vlserverlist(net, vllist); 226 return ERR_PTR(ret); 227 } 228 229 /* 230 * Compare old and new address lists to see if there's been any change. 231 * - How to do this in better than O(Nlog(N)) time? 232 * - We don't really want to sort the address list, but would rather take the 233 * list as we got it so as not to undo record rotation by the DNS server. 234 */ 235 #if 0 236 static int afs_cmp_addr_list(const struct afs_addr_list *a1, 237 const struct afs_addr_list *a2) 238 { 239 } 240 #endif 241 242 /* 243 * Perform a DNS query for VL servers and build a up an address list. 244 */ 245 struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry) 246 { 247 struct afs_vlserver_list *vllist; 248 char *result = NULL; 249 int ret; 250 251 _enter("%s", cell->name); 252 253 ret = dns_query("afsdb", cell->name, cell->name_len, "srv=1", 254 &result, _expiry); 255 if (ret < 0) { 256 _leave(" = %d [dns]", ret); 257 return ERR_PTR(ret); 258 } 259 260 if (*_expiry == 0) 261 *_expiry = ktime_get_real_seconds() + 60; 262 263 if (ret > 1 && result[0] == 0) 264 vllist = afs_extract_vlserver_list(cell, result, ret); 265 else 266 vllist = afs_parse_text_addrs(cell->net, result, ret, ',', 267 VL_SERVICE, AFS_VL_PORT); 268 kfree(result); 269 if (IS_ERR(vllist) && vllist != ERR_PTR(-ENOMEM)) 270 pr_err("Failed to parse DNS data %ld\n", PTR_ERR(vllist)); 271 272 return vllist; 273 } 274 275 /* 276 * Merge an IPv4 entry into a fileserver address list. 277 */ 278 void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) 279 { 280 struct sockaddr_rxrpc *srx; 281 u32 addr = ntohl(xdr); 282 int i; 283 284 if (alist->nr_addrs >= alist->max_addrs) 285 return; 286 287 for (i = 0; i < alist->nr_ipv4; i++) { 288 struct sockaddr_in *a = &alist->addrs[i].transport.sin; 289 u32 a_addr = ntohl(a->sin_addr.s_addr); 290 u16 a_port = ntohs(a->sin_port); 291 292 if (addr == a_addr && port == a_port) 293 return; 294 if (addr == a_addr && port < a_port) 295 break; 296 if (addr < a_addr) 297 break; 298 } 299 300 if (i < alist->nr_addrs) 301 memmove(alist->addrs + i + 1, 302 alist->addrs + i, 303 sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); 304 305 srx = &alist->addrs[i]; 306 srx->srx_family = AF_RXRPC; 307 srx->transport_type = SOCK_DGRAM; 308 srx->transport_len = sizeof(srx->transport.sin); 309 srx->transport.sin.sin_family = AF_INET; 310 srx->transport.sin.sin_port = htons(port); 311 srx->transport.sin.sin_addr.s_addr = xdr; 312 alist->nr_ipv4++; 313 alist->nr_addrs++; 314 } 315 316 /* 317 * Merge an IPv6 entry into a fileserver address list. 318 */ 319 void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) 320 { 321 struct sockaddr_rxrpc *srx; 322 int i, diff; 323 324 if (alist->nr_addrs >= alist->max_addrs) 325 return; 326 327 for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { 328 struct sockaddr_in6 *a = &alist->addrs[i].transport.sin6; 329 u16 a_port = ntohs(a->sin6_port); 330 331 diff = memcmp(xdr, &a->sin6_addr, 16); 332 if (diff == 0 && port == a_port) 333 return; 334 if (diff == 0 && port < a_port) 335 break; 336 if (diff < 0) 337 break; 338 } 339 340 if (i < alist->nr_addrs) 341 memmove(alist->addrs + i + 1, 342 alist->addrs + i, 343 sizeof(alist->addrs[0]) * (alist->nr_addrs - i)); 344 345 srx = &alist->addrs[i]; 346 srx->srx_family = AF_RXRPC; 347 srx->transport_type = SOCK_DGRAM; 348 srx->transport_len = sizeof(srx->transport.sin6); 349 srx->transport.sin6.sin6_family = AF_INET6; 350 srx->transport.sin6.sin6_port = htons(port); 351 memcpy(&srx->transport.sin6.sin6_addr, xdr, 16); 352 alist->nr_addrs++; 353 } 354 355 /* 356 * Get an address to try. 357 */ 358 bool afs_iterate_addresses(struct afs_addr_cursor *ac) 359 { 360 unsigned long set, failed; 361 int index; 362 363 if (!ac->alist) 364 return false; 365 366 set = ac->alist->responded; 367 failed = ac->alist->failed; 368 _enter("%lx-%lx-%lx,%d", set, failed, ac->tried, ac->index); 369 370 ac->nr_iterations++; 371 372 set &= ~(failed | ac->tried); 373 374 if (!set) 375 return false; 376 377 index = READ_ONCE(ac->alist->preferred); 378 if (test_bit(index, &set)) 379 goto selected; 380 381 index = __ffs(set); 382 383 selected: 384 ac->index = index; 385 set_bit(index, &ac->tried); 386 ac->responded = false; 387 return true; 388 } 389 390 /* 391 * Release an address list cursor. 392 */ 393 int afs_end_cursor(struct afs_addr_cursor *ac) 394 { 395 struct afs_addr_list *alist; 396 397 alist = ac->alist; 398 if (alist) { 399 if (ac->responded && 400 ac->index != alist->preferred && 401 test_bit(ac->alist->preferred, &ac->tried)) 402 WRITE_ONCE(alist->preferred, ac->index); 403 afs_put_addrlist(alist); 404 ac->alist = NULL; 405 } 406 407 return ac->error; 408 } 409