Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Server address list management
0003  *
0004  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/slab.h>
0009 #include <linux/ctype.h>
0010 #include <linux/dns_resolver.h>
0011 #include <linux/inet.h>
0012 #include <keys/rxrpc-type.h>
0013 #include "internal.h"
0014 #include "afs_fs.h"
0015 
0016 /*
0017  * Release an address list.
0018  */
0019 void afs_put_addrlist(struct afs_addr_list *alist)
0020 {
0021     if (alist && refcount_dec_and_test(&alist->usage))
0022         kfree_rcu(alist, rcu);
0023 }
0024 
0025 /*
0026  * Allocate an address list.
0027  */
0028 struct afs_addr_list *afs_alloc_addrlist(unsigned int nr,
0029                      unsigned short service,
0030                      unsigned short port)
0031 {
0032     struct afs_addr_list *alist;
0033     unsigned int i;
0034 
0035     _enter("%u,%u,%u", nr, service, port);
0036 
0037     if (nr > AFS_MAX_ADDRESSES)
0038         nr = AFS_MAX_ADDRESSES;
0039 
0040     alist = kzalloc(struct_size(alist, addrs, nr), GFP_KERNEL);
0041     if (!alist)
0042         return NULL;
0043 
0044     refcount_set(&alist->usage, 1);
0045     alist->max_addrs = nr;
0046 
0047     for (i = 0; i < nr; i++) {
0048         struct sockaddr_rxrpc *srx = &alist->addrs[i];
0049         srx->srx_family         = AF_RXRPC;
0050         srx->srx_service        = service;
0051         srx->transport_type     = SOCK_DGRAM;
0052         srx->transport_len      = sizeof(srx->transport.sin6);
0053         srx->transport.sin6.sin6_family = AF_INET6;
0054         srx->transport.sin6.sin6_port   = htons(port);
0055     }
0056 
0057     return alist;
0058 }
0059 
0060 /*
0061  * Parse a text string consisting of delimited addresses.
0062  */
0063 struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *net,
0064                            const char *text, size_t len,
0065                            char delim,
0066                            unsigned short service,
0067                            unsigned short port)
0068 {
0069     struct afs_vlserver_list *vllist;
0070     struct afs_addr_list *alist;
0071     const char *p, *end = text + len;
0072     const char *problem;
0073     unsigned int nr = 0;
0074     int ret = -ENOMEM;
0075 
0076     _enter("%*.*s,%c", (int)len, (int)len, text, delim);
0077 
0078     if (!len) {
0079         _leave(" = -EDESTADDRREQ [empty]");
0080         return ERR_PTR(-EDESTADDRREQ);
0081     }
0082 
0083     if (delim == ':' && (memchr(text, ',', len) || !memchr(text, '.', len)))
0084         delim = ',';
0085 
0086     /* Count the addresses */
0087     p = text;
0088     do {
0089         if (!*p) {
0090             problem = "nul";
0091             goto inval;
0092         }
0093         if (*p == delim)
0094             continue;
0095         nr++;
0096         if (*p == '[') {
0097             p++;
0098             if (p == end) {
0099                 problem = "brace1";
0100                 goto inval;
0101             }
0102             p = memchr(p, ']', end - p);
0103             if (!p) {
0104                 problem = "brace2";
0105                 goto inval;
0106             }
0107             p++;
0108             if (p >= end)
0109                 break;
0110         }
0111 
0112         p = memchr(p, delim, end - p);
0113         if (!p)
0114             break;
0115         p++;
0116     } while (p < end);
0117 
0118     _debug("%u/%u addresses", nr, AFS_MAX_ADDRESSES);
0119 
0120     vllist = afs_alloc_vlserver_list(1);
0121     if (!vllist)
0122         return ERR_PTR(-ENOMEM);
0123 
0124     vllist->nr_servers = 1;
0125     vllist->servers[0].server = afs_alloc_vlserver("<dummy>", 7, AFS_VL_PORT);
0126     if (!vllist->servers[0].server)
0127         goto error_vl;
0128 
0129     alist = afs_alloc_addrlist(nr, service, AFS_VL_PORT);
0130     if (!alist)
0131         goto error;
0132 
0133     /* Extract the addresses */
0134     p = text;
0135     do {
0136         const char *q, *stop;
0137         unsigned int xport = port;
0138         __be32 x[4];
0139         int family;
0140 
0141         if (*p == delim) {
0142             p++;
0143             continue;
0144         }
0145 
0146         if (*p == '[') {
0147             p++;
0148             q = memchr(p, ']', end - p);
0149         } else {
0150             for (q = p; q < end; q++)
0151                 if (*q == '+' || *q == delim)
0152                     break;
0153         }
0154 
0155         if (in4_pton(p, q - p, (u8 *)&x[0], -1, &stop)) {
0156             family = AF_INET;
0157         } else if (in6_pton(p, q - p, (u8 *)x, -1, &stop)) {
0158             family = AF_INET6;
0159         } else {
0160             problem = "family";
0161             goto bad_address;
0162         }
0163 
0164         p = q;
0165         if (stop != p) {
0166             problem = "nostop";
0167             goto bad_address;
0168         }
0169 
0170         if (q < end && *q == ']')
0171             p++;
0172 
0173         if (p < end) {
0174             if (*p == '+') {
0175                 /* Port number specification "+1234" */
0176                 xport = 0;
0177                 p++;
0178                 if (p >= end || !isdigit(*p)) {
0179                     problem = "port";
0180                     goto bad_address;
0181                 }
0182                 do {
0183                     xport *= 10;
0184                     xport += *p - '0';
0185                     if (xport > 65535) {
0186                         problem = "pval";
0187                         goto bad_address;
0188                     }
0189                     p++;
0190                 } while (p < end && isdigit(*p));
0191             } else if (*p == delim) {
0192                 p++;
0193             } else {
0194                 problem = "weird";
0195                 goto bad_address;
0196             }
0197         }
0198 
0199         if (family == AF_INET)
0200             afs_merge_fs_addr4(alist, x[0], xport);
0201         else
0202             afs_merge_fs_addr6(alist, x, xport);
0203 
0204     } while (p < end);
0205 
0206     rcu_assign_pointer(vllist->servers[0].server->addresses, alist);
0207     _leave(" = [nr %u]", alist->nr_addrs);
0208     return vllist;
0209 
0210 inval:
0211     _leave(" = -EINVAL [%s %zu %*.*s]",
0212            problem, p - text, (int)len, (int)len, text);
0213     return ERR_PTR(-EINVAL);
0214 bad_address:
0215     _leave(" = -EINVAL [%s %zu %*.*s]",
0216            problem, p - text, (int)len, (int)len, text);
0217     ret = -EINVAL;
0218 error:
0219     afs_put_addrlist(alist);
0220 error_vl:
0221     afs_put_vlserverlist(net, vllist);
0222     return ERR_PTR(ret);
0223 }
0224 
0225 /*
0226  * Compare old and new address lists to see if there's been any change.
0227  * - How to do this in better than O(Nlog(N)) time?
0228  *   - We don't really want to sort the address list, but would rather take the
0229  *     list as we got it so as not to undo record rotation by the DNS server.
0230  */
0231 #if 0
0232 static int afs_cmp_addr_list(const struct afs_addr_list *a1,
0233                  const struct afs_addr_list *a2)
0234 {
0235 }
0236 #endif
0237 
0238 /*
0239  * Perform a DNS query for VL servers and build a up an address list.
0240  */
0241 struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry)
0242 {
0243     struct afs_vlserver_list *vllist;
0244     char *result = NULL;
0245     int ret;
0246 
0247     _enter("%s", cell->name);
0248 
0249     ret = dns_query(cell->net->net, "afsdb", cell->name, cell->name_len,
0250             "srv=1", &result, _expiry, true);
0251     if (ret < 0) {
0252         _leave(" = %d [dns]", ret);
0253         return ERR_PTR(ret);
0254     }
0255 
0256     if (*_expiry == 0)
0257         *_expiry = ktime_get_real_seconds() + 60;
0258 
0259     if (ret > 1 && result[0] == 0)
0260         vllist = afs_extract_vlserver_list(cell, result, ret);
0261     else
0262         vllist = afs_parse_text_addrs(cell->net, result, ret, ',',
0263                           VL_SERVICE, AFS_VL_PORT);
0264     kfree(result);
0265     if (IS_ERR(vllist) && vllist != ERR_PTR(-ENOMEM))
0266         pr_err("Failed to parse DNS data %ld\n", PTR_ERR(vllist));
0267 
0268     return vllist;
0269 }
0270 
0271 /*
0272  * Merge an IPv4 entry into a fileserver address list.
0273  */
0274 void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)
0275 {
0276     struct sockaddr_rxrpc *srx;
0277     u32 addr = ntohl(xdr);
0278     int i;
0279 
0280     if (alist->nr_addrs >= alist->max_addrs)
0281         return;
0282 
0283     for (i = 0; i < alist->nr_ipv4; i++) {
0284         struct sockaddr_in *a = &alist->addrs[i].transport.sin;
0285         u32 a_addr = ntohl(a->sin_addr.s_addr);
0286         u16 a_port = ntohs(a->sin_port);
0287 
0288         if (addr == a_addr && port == a_port)
0289             return;
0290         if (addr == a_addr && port < a_port)
0291             break;
0292         if (addr < a_addr)
0293             break;
0294     }
0295 
0296     if (i < alist->nr_addrs)
0297         memmove(alist->addrs + i + 1,
0298             alist->addrs + i,
0299             sizeof(alist->addrs[0]) * (alist->nr_addrs - i));
0300 
0301     srx = &alist->addrs[i];
0302     srx->srx_family = AF_RXRPC;
0303     srx->transport_type = SOCK_DGRAM;
0304     srx->transport_len = sizeof(srx->transport.sin);
0305     srx->transport.sin.sin_family = AF_INET;
0306     srx->transport.sin.sin_port = htons(port);
0307     srx->transport.sin.sin_addr.s_addr = xdr;
0308     alist->nr_ipv4++;
0309     alist->nr_addrs++;
0310 }
0311 
0312 /*
0313  * Merge an IPv6 entry into a fileserver address list.
0314  */
0315 void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)
0316 {
0317     struct sockaddr_rxrpc *srx;
0318     int i, diff;
0319 
0320     if (alist->nr_addrs >= alist->max_addrs)
0321         return;
0322 
0323     for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
0324         struct sockaddr_in6 *a = &alist->addrs[i].transport.sin6;
0325         u16 a_port = ntohs(a->sin6_port);
0326 
0327         diff = memcmp(xdr, &a->sin6_addr, 16);
0328         if (diff == 0 && port == a_port)
0329             return;
0330         if (diff == 0 && port < a_port)
0331             break;
0332         if (diff < 0)
0333             break;
0334     }
0335 
0336     if (i < alist->nr_addrs)
0337         memmove(alist->addrs + i + 1,
0338             alist->addrs + i,
0339             sizeof(alist->addrs[0]) * (alist->nr_addrs - i));
0340 
0341     srx = &alist->addrs[i];
0342     srx->srx_family = AF_RXRPC;
0343     srx->transport_type = SOCK_DGRAM;
0344     srx->transport_len = sizeof(srx->transport.sin6);
0345     srx->transport.sin6.sin6_family = AF_INET6;
0346     srx->transport.sin6.sin6_port = htons(port);
0347     memcpy(&srx->transport.sin6.sin6_addr, xdr, 16);
0348     alist->nr_addrs++;
0349 }
0350 
0351 /*
0352  * Get an address to try.
0353  */
0354 bool afs_iterate_addresses(struct afs_addr_cursor *ac)
0355 {
0356     unsigned long set, failed;
0357     int index;
0358 
0359     if (!ac->alist)
0360         return false;
0361 
0362     set = ac->alist->responded;
0363     failed = ac->alist->failed;
0364     _enter("%lx-%lx-%lx,%d", set, failed, ac->tried, ac->index);
0365 
0366     ac->nr_iterations++;
0367 
0368     set &= ~(failed | ac->tried);
0369 
0370     if (!set)
0371         return false;
0372 
0373     index = READ_ONCE(ac->alist->preferred);
0374     if (test_bit(index, &set))
0375         goto selected;
0376 
0377     index = __ffs(set);
0378 
0379 selected:
0380     ac->index = index;
0381     set_bit(index, &ac->tried);
0382     ac->responded = false;
0383     return true;
0384 }
0385 
0386 /*
0387  * Release an address list cursor.
0388  */
0389 int afs_end_cursor(struct afs_addr_cursor *ac)
0390 {
0391     struct afs_addr_list *alist;
0392 
0393     alist = ac->alist;
0394     if (alist) {
0395         if (ac->responded &&
0396             ac->index != alist->preferred &&
0397             test_bit(ac->alist->preferred, &ac->tried))
0398             WRITE_ONCE(alist->preferred, ac->index);
0399         afs_put_addrlist(alist);
0400         ac->alist = NULL;
0401     }
0402 
0403     return ac->error;
0404 }