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