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