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(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
  61struct 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
  73static 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
  86static 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
 106static 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
 115static 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
 123static 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
 136static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key)
 137{
 138        return hash_str(key->hostname, NFS_DNS_HASHBITS);
 139}
 140
 141static 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
 151static 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
 163static 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
 177static 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
 203static 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
 216static 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
 230static 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);
 277out:
 278        return ret;
 279}
 280
 281static 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
 297static 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;
 315out_put:
 316        cache_put(&(*item)->h, cd);
 317out_err:
 318        *item = NULL;
 319        return ret;
 320}
 321
 322static 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);
 339out:
 340        return ret;
 341}
 342
 343ssize_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
 367static 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
 383int 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
 397err_reg:
 398        cache_destroy_net(nn->nfs_dns_resolve, net);
 399        return err;
 400}
 401
 402void 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
 410static int nfs4_dns_net_init(struct net *net)
 411{
 412        return nfs_dns_resolver_cache_init(net);
 413}
 414
 415static void nfs4_dns_net_exit(struct net *net)
 416{
 417        nfs_dns_resolver_cache_destroy(net);
 418}
 419
 420static struct pernet_operations nfs4_dns_resolver_ops = {
 421        .init = nfs4_dns_net_init,
 422        .exit = nfs4_dns_net_exit,
 423};
 424
 425static 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
 455static struct notifier_block nfs_dns_resolver_block = {
 456        .notifier_call  = rpc_pipefs_event,
 457};
 458
 459int 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;
 470out1:
 471        unregister_pernet_subsys(&nfs4_dns_resolver_ops);
 472out:
 473        return err;
 474}
 475
 476void 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
 482