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