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