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