LCOV - code coverage report
Current view: top level - fs/nfs - dns_resolve.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 9 0.0 %
Date: 2022-04-01 14:58:12 Functions: 0 1 0.0 %
Branches: 0 2 0.0 %

           Branch data     Line data    Source code
       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                 :          0 : ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
      19                 :            :                 struct sockaddr *sa, size_t salen)
      20                 :            : {
      21                 :          0 :         ssize_t ret;
      22                 :          0 :         char *ip_addr = NULL;
      23                 :          0 :         int ip_len;
      24                 :            : 
      25                 :          0 :         ip_len = dns_query(net, NULL, name, namelen, NULL, &ip_addr, NULL,
      26                 :            :                            false);
      27         [ #  # ]:          0 :         if (ip_len > 0)
      28                 :          0 :                 ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
      29                 :            :         else
      30                 :            :                 ret = -ESRCH;
      31                 :          0 :         kfree(ip_addr);
      32                 :          0 :         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 = kmemdup_nul(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

Generated by: LCOV version 1.14