Branch data Line data Source code
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 : :
17 : 0 : ssize_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 : 0 : char *ip_addr = NULL;
22 : : int ip_len;
23 : :
24 : 0 : ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL);
25 [ # # ]: 0 : if (ip_len > 0)
26 : 0 : ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
27 : : else
28 : : ret = -ESRCH;
29 : 0 : kfree(ip_addr);
30 : 0 : 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 : :
59 : : struct 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 : :
70 : : static 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 : :
83 : : static 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 : :
103 : : static 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 : :
112 : : static 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 : :
125 : : static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key)
126 : : {
127 : : return hash_str(key->hostname, NFS_DNS_HASHBITS);
128 : : }
129 : :
130 : : static 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 : :
140 : : static 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 : :
152 : : static 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 : :
166 : : static 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 : :
192 : : static 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 : :
205 : : static 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 : :
219 : : static 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);
266 : : out:
267 : : return ret;
268 : : }
269 : :
270 : : static 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 : :
286 : : static 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;
304 : : out_put:
305 : : cache_put(&(*item)->h, cd);
306 : : out_err:
307 : : *item = NULL;
308 : : return ret;
309 : : }
310 : :
311 : : static 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);
328 : : out:
329 : : return ret;
330 : : }
331 : :
332 : : ssize_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 : :
356 : : static 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 : :
372 : : int 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 : :
386 : : err_reg:
387 : : cache_destroy_net(nn->nfs_dns_resolve, net);
388 : : return err;
389 : : }
390 : :
391 : : void 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 : :
399 : : static int nfs4_dns_net_init(struct net *net)
400 : : {
401 : : return nfs_dns_resolver_cache_init(net);
402 : : }
403 : :
404 : : static void nfs4_dns_net_exit(struct net *net)
405 : : {
406 : : nfs_dns_resolver_cache_destroy(net);
407 : : }
408 : :
409 : : static struct pernet_operations nfs4_dns_resolver_ops = {
410 : : .init = nfs4_dns_net_init,
411 : : .exit = nfs4_dns_net_exit,
412 : : };
413 : :
414 : : static 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 : :
444 : : static struct notifier_block nfs_dns_resolver_block = {
445 : : .notifier_call = rpc_pipefs_event,
446 : : };
447 : :
448 : : int 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;
459 : : out1:
460 : : unregister_pernet_subsys(&nfs4_dns_resolver_ops);
461 : : out:
462 : : return err;
463 : : }
464 : :
465 : : void 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
|