root/fs/nfs/dns_resolve.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfs_dns_resolve_name
  2. nfs_dns_ent_update
  3. nfs_dns_ent_init
  4. nfs_dns_ent_free_rcu
  5. nfs_dns_ent_put
  6. nfs_dns_ent_alloc
  7. nfs_dns_hash
  8. nfs_dns_request
  9. nfs_dns_upcall
  10. nfs_dns_match
  11. nfs_dns_show
  12. nfs_dns_lookup
  13. nfs_dns_update
  14. nfs_dns_parse
  15. do_cache_lookup
  16. do_cache_lookup_nowait
  17. do_cache_lookup_wait
  18. nfs_dns_resolve_name
  19. nfs_dns_resolver_cache_init
  20. nfs_dns_resolver_cache_destroy
  21. nfs4_dns_net_init
  22. nfs4_dns_net_exit
  23. rpc_pipefs_event
  24. nfs_dns_resolver_init
  25. nfs_dns_resolver_destroy

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * linux/fs/nfs/dns_resolve.c
   4  *
   5  * Copyright (c) 2009 Trond Myklebust <Trond.Myklebust@netapp.com>
   6  *
   7  * Resolves DNS hostnames into valid ip addresses
   8  */
   9 
  10 #ifdef CONFIG_NFS_USE_KERNEL_DNS
  11 
  12 #include <linux/module.h>
  13 #include <linux/sunrpc/clnt.h>
  14 #include <linux/sunrpc/addr.h>
  15 #include <linux/dns_resolver.h>
  16 #include "dns_resolve.h"
  17 
  18 ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
  19                 struct sockaddr *sa, size_t salen)
  20 {
  21         ssize_t ret;
  22         char *ip_addr = NULL;
  23         int ip_len;
  24 
  25         ip_len = dns_query(net, NULL, name, namelen, NULL, &ip_addr, NULL,
  26                            false);
  27         if (ip_len > 0)
  28                 ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
  29         else
  30                 ret = -ESRCH;
  31         kfree(ip_addr);
  32         return ret;
  33 }
  34 
  35 #else
  36 
  37 #include <linux/module.h>
  38 #include <linux/hash.h>
  39 #include <linux/string.h>
  40 #include <linux/kmod.h>
  41 #include <linux/slab.h>
  42 #include <linux/module.h>
  43 #include <linux/socket.h>
  44 #include <linux/seq_file.h>
  45 #include <linux/inet.h>
  46 #include <linux/sunrpc/clnt.h>
  47 #include <linux/sunrpc/addr.h>
  48 #include <linux/sunrpc/cache.h>
  49 #include <linux/sunrpc/svcauth.h>
  50 #include <linux/sunrpc/rpc_pipe_fs.h>
  51 #include <linux/nfs_fs.h>
  52 
  53 #include "nfs4_fs.h"
  54 #include "dns_resolve.h"
  55 #include "cache_lib.h"
  56 #include "netns.h"
  57 
  58 #define NFS_DNS_HASHBITS 4
  59 #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS)
  60 
  61 struct nfs_dns_ent {
  62         struct cache_head h;
  63 
  64         char *hostname;
  65         size_t namelen;
  66 
  67         struct sockaddr_storage addr;
  68         size_t addrlen;
  69         struct rcu_head rcu_head;
  70 };
  71 
  72 
  73 static void nfs_dns_ent_update(struct cache_head *cnew,
  74                 struct cache_head *ckey)
  75 {
  76         struct nfs_dns_ent *new;
  77         struct nfs_dns_ent *key;
  78 
  79         new = container_of(cnew, struct nfs_dns_ent, h);
  80         key = container_of(ckey, struct nfs_dns_ent, h);
  81 
  82         memcpy(&new->addr, &key->addr, key->addrlen);
  83         new->addrlen = key->addrlen;
  84 }
  85 
  86 static void nfs_dns_ent_init(struct cache_head *cnew,
  87                 struct cache_head *ckey)
  88 {
  89         struct nfs_dns_ent *new;
  90         struct nfs_dns_ent *key;
  91 
  92         new = container_of(cnew, struct nfs_dns_ent, h);
  93         key = container_of(ckey, struct nfs_dns_ent, h);
  94 
  95         kfree(new->hostname);
  96         new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL);
  97         if (new->hostname) {
  98                 new->namelen = key->namelen;
  99                 nfs_dns_ent_update(cnew, ckey);
 100         } else {
 101                 new->namelen = 0;
 102                 new->addrlen = 0;
 103         }
 104 }
 105 
 106 static void nfs_dns_ent_free_rcu(struct rcu_head *head)
 107 {
 108         struct nfs_dns_ent *item;
 109 
 110         item = container_of(head, struct nfs_dns_ent, rcu_head);
 111         kfree(item->hostname);
 112         kfree(item);
 113 }
 114 
 115 static void nfs_dns_ent_put(struct kref *ref)
 116 {
 117         struct nfs_dns_ent *item;
 118 
 119         item = container_of(ref, struct nfs_dns_ent, h.ref);
 120         call_rcu(&item->rcu_head, nfs_dns_ent_free_rcu);
 121 }
 122 
 123 static struct cache_head *nfs_dns_ent_alloc(void)
 124 {
 125         struct nfs_dns_ent *item = kmalloc(sizeof(*item), GFP_KERNEL);
 126 
 127         if (item != NULL) {
 128                 item->hostname = NULL;
 129                 item->namelen = 0;
 130                 item->addrlen = 0;
 131                 return &item->h;
 132         }
 133         return NULL;
 134 };
 135 
 136 static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key)
 137 {
 138         return hash_str(key->hostname, NFS_DNS_HASHBITS);
 139 }
 140 
 141 static void nfs_dns_request(struct cache_detail *cd,
 142                 struct cache_head *ch,
 143                 char **bpp, int *blen)
 144 {
 145         struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h);
 146 
 147         qword_add(bpp, blen, key->hostname);
 148         (*bpp)[-1] = '\n';
 149 }
 150 
 151 static int nfs_dns_upcall(struct cache_detail *cd,
 152                 struct cache_head *ch)
 153 {
 154         struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h);
 155         int ret;
 156 
 157         ret = nfs_cache_upcall(cd, key->hostname);
 158         if (ret)
 159                 ret = sunrpc_cache_pipe_upcall(cd, ch);
 160         return ret;
 161 }
 162 
 163 static int nfs_dns_match(struct cache_head *ca,
 164                 struct cache_head *cb)
 165 {
 166         struct nfs_dns_ent *a;
 167         struct nfs_dns_ent *b;
 168 
 169         a = container_of(ca, struct nfs_dns_ent, h);
 170         b = container_of(cb, struct nfs_dns_ent, h);
 171 
 172         if (a->namelen == 0 || a->namelen != b->namelen)
 173                 return 0;
 174         return memcmp(a->hostname, b->hostname, a->namelen) == 0;
 175 }
 176 
 177 static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd,
 178                 struct cache_head *h)
 179 {
 180         struct nfs_dns_ent *item;
 181         long ttl;
 182 
 183         if (h == NULL) {
 184                 seq_puts(m, "# ip address      hostname        ttl\n");
 185                 return 0;
 186         }
 187         item = container_of(h, struct nfs_dns_ent, h);
 188         ttl = item->h.expiry_time - seconds_since_boot();
 189         if (ttl < 0)
 190                 ttl = 0;
 191 
 192         if (!test_bit(CACHE_NEGATIVE, &h->flags)) {
 193                 char buf[INET6_ADDRSTRLEN+IPV6_SCOPE_ID_LEN+1];
 194 
 195                 rpc_ntop((struct sockaddr *)&item->addr, buf, sizeof(buf));
 196                 seq_printf(m, "%15s ", buf);
 197         } else
 198                 seq_puts(m, "<none>          ");
 199         seq_printf(m, "%15s %ld\n", item->hostname, ttl);
 200         return 0;
 201 }
 202 
 203 static struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd,
 204                 struct nfs_dns_ent *key)
 205 {
 206         struct cache_head *ch;
 207 
 208         ch = sunrpc_cache_lookup_rcu(cd,
 209                         &key->h,
 210                         nfs_dns_hash(key));
 211         if (!ch)
 212                 return NULL;
 213         return container_of(ch, struct nfs_dns_ent, h);
 214 }
 215 
 216 static struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd,
 217                 struct nfs_dns_ent *new,
 218                 struct nfs_dns_ent *key)
 219 {
 220         struct cache_head *ch;
 221 
 222         ch = sunrpc_cache_update(cd,
 223                         &new->h, &key->h,
 224                         nfs_dns_hash(key));
 225         if (!ch)
 226                 return NULL;
 227         return container_of(ch, struct nfs_dns_ent, h);
 228 }
 229 
 230 static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen)
 231 {
 232         char buf1[NFS_DNS_HOSTNAME_MAXLEN+1];
 233         struct nfs_dns_ent key, *item;
 234         unsigned int ttl;
 235         ssize_t len;
 236         int ret = -EINVAL;
 237 
 238         if (buf[buflen-1] != '\n')
 239                 goto out;
 240         buf[buflen-1] = '\0';
 241 
 242         len = qword_get(&buf, buf1, sizeof(buf1));
 243         if (len <= 0)
 244                 goto out;
 245         key.addrlen = rpc_pton(cd->net, buf1, len,
 246                         (struct sockaddr *)&key.addr,
 247                         sizeof(key.addr));
 248 
 249         len = qword_get(&buf, buf1, sizeof(buf1));
 250         if (len <= 0)
 251                 goto out;
 252 
 253         key.hostname = buf1;
 254         key.namelen = len;
 255         memset(&key.h, 0, sizeof(key.h));
 256 
 257         if (get_uint(&buf, &ttl) < 0)
 258                 goto out;
 259         if (ttl == 0)
 260                 goto out;
 261         key.h.expiry_time = ttl + seconds_since_boot();
 262 
 263         ret = -ENOMEM;
 264         item = nfs_dns_lookup(cd, &key);
 265         if (item == NULL)
 266                 goto out;
 267 
 268         if (key.addrlen == 0)
 269                 set_bit(CACHE_NEGATIVE, &key.h.flags);
 270 
 271         item = nfs_dns_update(cd, &key, item);
 272         if (item == NULL)
 273                 goto out;
 274 
 275         ret = 0;
 276         cache_put(&item->h, cd);
 277 out:
 278         return ret;
 279 }
 280 
 281 static int do_cache_lookup(struct cache_detail *cd,
 282                 struct nfs_dns_ent *key,
 283                 struct nfs_dns_ent **item,
 284                 struct nfs_cache_defer_req *dreq)
 285 {
 286         int ret = -ENOMEM;
 287 
 288         *item = nfs_dns_lookup(cd, key);
 289         if (*item) {
 290                 ret = cache_check(cd, &(*item)->h, &dreq->req);
 291                 if (ret)
 292                         *item = NULL;
 293         }
 294         return ret;
 295 }
 296 
 297 static int do_cache_lookup_nowait(struct cache_detail *cd,
 298                 struct nfs_dns_ent *key,
 299                 struct nfs_dns_ent **item)
 300 {
 301         int ret = -ENOMEM;
 302 
 303         *item = nfs_dns_lookup(cd, key);
 304         if (!*item)
 305                 goto out_err;
 306         ret = -ETIMEDOUT;
 307         if (!test_bit(CACHE_VALID, &(*item)->h.flags)
 308                         || (*item)->h.expiry_time < seconds_since_boot()
 309                         || cd->flush_time > (*item)->h.last_refresh)
 310                 goto out_put;
 311         ret = -ENOENT;
 312         if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags))
 313                 goto out_put;
 314         return 0;
 315 out_put:
 316         cache_put(&(*item)->h, cd);
 317 out_err:
 318         *item = NULL;
 319         return ret;
 320 }
 321 
 322 static int do_cache_lookup_wait(struct cache_detail *cd,
 323                 struct nfs_dns_ent *key,
 324                 struct nfs_dns_ent **item)
 325 {
 326         struct nfs_cache_defer_req *dreq;
 327         int ret = -ENOMEM;
 328 
 329         dreq = nfs_cache_defer_req_alloc();
 330         if (!dreq)
 331                 goto out;
 332         ret = do_cache_lookup(cd, key, item, dreq);
 333         if (ret == -EAGAIN) {
 334                 ret = nfs_cache_wait_for_upcall(dreq);
 335                 if (!ret)
 336                         ret = do_cache_lookup_nowait(cd, key, item);
 337         }
 338         nfs_cache_defer_req_put(dreq);
 339 out:
 340         return ret;
 341 }
 342 
 343 ssize_t nfs_dns_resolve_name(struct net *net, char *name,
 344                 size_t namelen, struct sockaddr *sa, size_t salen)
 345 {
 346         struct nfs_dns_ent key = {
 347                 .hostname = name,
 348                 .namelen = namelen,
 349         };
 350         struct nfs_dns_ent *item = NULL;
 351         ssize_t ret;
 352         struct nfs_net *nn = net_generic(net, nfs_net_id);
 353 
 354         ret = do_cache_lookup_wait(nn->nfs_dns_resolve, &key, &item);
 355         if (ret == 0) {
 356                 if (salen >= item->addrlen) {
 357                         memcpy(sa, &item->addr, item->addrlen);
 358                         ret = item->addrlen;
 359                 } else
 360                         ret = -EOVERFLOW;
 361                 cache_put(&item->h, nn->nfs_dns_resolve);
 362         } else if (ret == -ENOENT)
 363                 ret = -ESRCH;
 364         return ret;
 365 }
 366 
 367 static struct cache_detail nfs_dns_resolve_template = {
 368         .owner          = THIS_MODULE,
 369         .hash_size      = NFS_DNS_HASHTBL_SIZE,
 370         .name           = "dns_resolve",
 371         .cache_put      = nfs_dns_ent_put,
 372         .cache_upcall   = nfs_dns_upcall,
 373         .cache_request  = nfs_dns_request,
 374         .cache_parse    = nfs_dns_parse,
 375         .cache_show     = nfs_dns_show,
 376         .match          = nfs_dns_match,
 377         .init           = nfs_dns_ent_init,
 378         .update         = nfs_dns_ent_update,
 379         .alloc          = nfs_dns_ent_alloc,
 380 };
 381 
 382 
 383 int nfs_dns_resolver_cache_init(struct net *net)
 384 {
 385         int err;
 386         struct nfs_net *nn = net_generic(net, nfs_net_id);
 387 
 388         nn->nfs_dns_resolve = cache_create_net(&nfs_dns_resolve_template, net);
 389         if (IS_ERR(nn->nfs_dns_resolve))
 390                 return PTR_ERR(nn->nfs_dns_resolve);
 391 
 392         err = nfs_cache_register_net(net, nn->nfs_dns_resolve);
 393         if (err)
 394                 goto err_reg;
 395         return 0;
 396 
 397 err_reg:
 398         cache_destroy_net(nn->nfs_dns_resolve, net);
 399         return err;
 400 }
 401 
 402 void nfs_dns_resolver_cache_destroy(struct net *net)
 403 {
 404         struct nfs_net *nn = net_generic(net, nfs_net_id);
 405 
 406         nfs_cache_unregister_net(net, nn->nfs_dns_resolve);
 407         cache_destroy_net(nn->nfs_dns_resolve, net);
 408 }
 409 
 410 static int nfs4_dns_net_init(struct net *net)
 411 {
 412         return nfs_dns_resolver_cache_init(net);
 413 }
 414 
 415 static void nfs4_dns_net_exit(struct net *net)
 416 {
 417         nfs_dns_resolver_cache_destroy(net);
 418 }
 419 
 420 static struct pernet_operations nfs4_dns_resolver_ops = {
 421         .init = nfs4_dns_net_init,
 422         .exit = nfs4_dns_net_exit,
 423 };
 424 
 425 static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
 426                            void *ptr)
 427 {
 428         struct super_block *sb = ptr;
 429         struct net *net = sb->s_fs_info;
 430         struct nfs_net *nn = net_generic(net, nfs_net_id);
 431         struct cache_detail *cd = nn->nfs_dns_resolve;
 432         int ret = 0;
 433 
 434         if (cd == NULL)
 435                 return 0;
 436 
 437         if (!try_module_get(THIS_MODULE))
 438                 return 0;
 439 
 440         switch (event) {
 441         case RPC_PIPEFS_MOUNT:
 442                 ret = nfs_cache_register_sb(sb, cd);
 443                 break;
 444         case RPC_PIPEFS_UMOUNT:
 445                 nfs_cache_unregister_sb(sb, cd);
 446                 break;
 447         default:
 448                 ret = -ENOTSUPP;
 449                 break;
 450         }
 451         module_put(THIS_MODULE);
 452         return ret;
 453 }
 454 
 455 static struct notifier_block nfs_dns_resolver_block = {
 456         .notifier_call  = rpc_pipefs_event,
 457 };
 458 
 459 int nfs_dns_resolver_init(void)
 460 {
 461         int err;
 462 
 463         err = register_pernet_subsys(&nfs4_dns_resolver_ops);
 464         if (err < 0)
 465                 goto out;
 466         err = rpc_pipefs_notifier_register(&nfs_dns_resolver_block);
 467         if (err < 0)
 468                 goto out1;
 469         return 0;
 470 out1:
 471         unregister_pernet_subsys(&nfs4_dns_resolver_ops);
 472 out:
 473         return err;
 474 }
 475 
 476 void nfs_dns_resolver_destroy(void)
 477 {
 478         rpc_pipefs_notifier_unregister(&nfs_dns_resolver_block);
 479         unregister_pernet_subsys(&nfs4_dns_resolver_ops);
 480 }
 481 #endif

/* [<][>][^][v][top][bottom][index][help] */