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