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/sunrpc/clnt.h> 12 #include <linux/dns_resolver.h> 13 14 ssize_t nfs_dns_resolve_name(char *name, size_t namelen, 15 struct sockaddr *sa, size_t salen) 16 { 17 ssize_t ret; 18 char *ip_addr = NULL; 19 int ip_len; 20 21 ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL); 22 if (ip_len > 0) 23 ret = rpc_pton(ip_addr, ip_len, sa, salen); 24 else 25 ret = -ESRCH; 26 kfree(ip_addr); 27 return ret; 28 } 29 30 #else 31 32 #include <linux/hash.h> 33 #include <linux/string.h> 34 #include <linux/kmod.h> 35 #include <linux/slab.h> 36 #include <linux/module.h> 37 #include <linux/socket.h> 38 #include <linux/seq_file.h> 39 #include <linux/inet.h> 40 #include <linux/sunrpc/clnt.h> 41 #include <linux/sunrpc/cache.h> 42 #include <linux/sunrpc/svcauth.h> 43 44 #include "dns_resolve.h" 45 #include "cache_lib.h" 46 47 #define NFS_DNS_HASHBITS 4 48 #define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS) 49 50 static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE]; 51 52 struct nfs_dns_ent { 53 struct cache_head h; 54 55 char *hostname; 56 size_t namelen; 57 58 struct sockaddr_storage addr; 59 size_t addrlen; 60 }; 61 62 63 static void nfs_dns_ent_update(struct cache_head *cnew, 64 struct cache_head *ckey) 65 { 66 struct nfs_dns_ent *new; 67 struct nfs_dns_ent *key; 68 69 new = container_of(cnew, struct nfs_dns_ent, h); 70 key = container_of(ckey, struct nfs_dns_ent, h); 71 72 memcpy(&new->addr, &key->addr, key->addrlen); 73 new->addrlen = key->addrlen; 74 } 75 76 static void nfs_dns_ent_init(struct cache_head *cnew, 77 struct cache_head *ckey) 78 { 79 struct nfs_dns_ent *new; 80 struct nfs_dns_ent *key; 81 82 new = container_of(cnew, struct nfs_dns_ent, h); 83 key = container_of(ckey, struct nfs_dns_ent, h); 84 85 kfree(new->hostname); 86 new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); 87 if (new->hostname) { 88 new->namelen = key->namelen; 89 nfs_dns_ent_update(cnew, ckey); 90 } else { 91 new->namelen = 0; 92 new->addrlen = 0; 93 } 94 } 95 96 static void nfs_dns_ent_put(struct kref *ref) 97 { 98 struct nfs_dns_ent *item; 99 100 item = container_of(ref, struct nfs_dns_ent, h.ref); 101 kfree(item->hostname); 102 kfree(item); 103 } 104 105 static struct cache_head *nfs_dns_ent_alloc(void) 106 { 107 struct nfs_dns_ent *item = kmalloc(sizeof(*item), GFP_KERNEL); 108 109 if (item != NULL) { 110 item->hostname = NULL; 111 item->namelen = 0; 112 item->addrlen = 0; 113 return &item->h; 114 } 115 return NULL; 116 }; 117 118 static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key) 119 { 120 return hash_str(key->hostname, NFS_DNS_HASHBITS); 121 } 122 123 static void nfs_dns_request(struct cache_detail *cd, 124 struct cache_head *ch, 125 char **bpp, int *blen) 126 { 127 struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); 128 129 qword_add(bpp, blen, key->hostname); 130 (*bpp)[-1] = '\n'; 131 } 132 133 static int nfs_dns_upcall(struct cache_detail *cd, 134 struct cache_head *ch) 135 { 136 struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); 137 int ret; 138 139 ret = nfs_cache_upcall(cd, key->hostname); 140 if (ret) 141 ret = sunrpc_cache_pipe_upcall(cd, ch, nfs_dns_request); 142 return ret; 143 } 144 145 static int nfs_dns_match(struct cache_head *ca, 146 struct cache_head *cb) 147 { 148 struct nfs_dns_ent *a; 149 struct nfs_dns_ent *b; 150 151 a = container_of(ca, struct nfs_dns_ent, h); 152 b = container_of(cb, struct nfs_dns_ent, h); 153 154 if (a->namelen == 0 || a->namelen != b->namelen) 155 return 0; 156 return memcmp(a->hostname, b->hostname, a->namelen) == 0; 157 } 158 159 static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd, 160 struct cache_head *h) 161 { 162 struct nfs_dns_ent *item; 163 long ttl; 164 165 if (h == NULL) { 166 seq_puts(m, "# ip address hostname ttl\n"); 167 return 0; 168 } 169 item = container_of(h, struct nfs_dns_ent, h); 170 ttl = item->h.expiry_time - seconds_since_boot(); 171 if (ttl < 0) 172 ttl = 0; 173 174 if (!test_bit(CACHE_NEGATIVE, &h->flags)) { 175 char buf[INET6_ADDRSTRLEN+IPV6_SCOPE_ID_LEN+1]; 176 177 rpc_ntop((struct sockaddr *)&item->addr, buf, sizeof(buf)); 178 seq_printf(m, "%15s ", buf); 179 } else 180 seq_puts(m, "<none> "); 181 seq_printf(m, "%15s %ld\n", item->hostname, ttl); 182 return 0; 183 } 184 185 static struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd, 186 struct nfs_dns_ent *key) 187 { 188 struct cache_head *ch; 189 190 ch = sunrpc_cache_lookup(cd, 191 &key->h, 192 nfs_dns_hash(key)); 193 if (!ch) 194 return NULL; 195 return container_of(ch, struct nfs_dns_ent, h); 196 } 197 198 static struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd, 199 struct nfs_dns_ent *new, 200 struct nfs_dns_ent *key) 201 { 202 struct cache_head *ch; 203 204 ch = sunrpc_cache_update(cd, 205 &new->h, &key->h, 206 nfs_dns_hash(key)); 207 if (!ch) 208 return NULL; 209 return container_of(ch, struct nfs_dns_ent, h); 210 } 211 212 static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) 213 { 214 char buf1[NFS_DNS_HOSTNAME_MAXLEN+1]; 215 struct nfs_dns_ent key, *item; 216 unsigned long ttl; 217 ssize_t len; 218 int ret = -EINVAL; 219 220 if (buf[buflen-1] != '\n') 221 goto out; 222 buf[buflen-1] = '\0'; 223 224 len = qword_get(&buf, buf1, sizeof(buf1)); 225 if (len <= 0) 226 goto out; 227 key.addrlen = rpc_pton(buf1, len, 228 (struct sockaddr *)&key.addr, 229 sizeof(key.addr)); 230 231 len = qword_get(&buf, buf1, sizeof(buf1)); 232 if (len <= 0) 233 goto out; 234 235 key.hostname = buf1; 236 key.namelen = len; 237 memset(&key.h, 0, sizeof(key.h)); 238 239 ttl = get_expiry(&buf); 240 if (ttl == 0) 241 goto out; 242 key.h.expiry_time = ttl + seconds_since_boot(); 243 244 ret = -ENOMEM; 245 item = nfs_dns_lookup(cd, &key); 246 if (item == NULL) 247 goto out; 248 249 if (key.addrlen == 0) 250 set_bit(CACHE_NEGATIVE, &key.h.flags); 251 252 item = nfs_dns_update(cd, &key, item); 253 if (item == NULL) 254 goto out; 255 256 ret = 0; 257 cache_put(&item->h, cd); 258 out: 259 return ret; 260 } 261 262 static struct cache_detail nfs_dns_resolve = { 263 .owner = THIS_MODULE, 264 .hash_size = NFS_DNS_HASHTBL_SIZE, 265 .hash_table = nfs_dns_table, 266 .name = "dns_resolve", 267 .cache_put = nfs_dns_ent_put, 268 .cache_upcall = nfs_dns_upcall, 269 .cache_parse = nfs_dns_parse, 270 .cache_show = nfs_dns_show, 271 .match = nfs_dns_match, 272 .init = nfs_dns_ent_init, 273 .update = nfs_dns_ent_update, 274 .alloc = nfs_dns_ent_alloc, 275 }; 276 277 static int do_cache_lookup(struct cache_detail *cd, 278 struct nfs_dns_ent *key, 279 struct nfs_dns_ent **item, 280 struct nfs_cache_defer_req *dreq) 281 { 282 int ret = -ENOMEM; 283 284 *item = nfs_dns_lookup(cd, key); 285 if (*item) { 286 ret = cache_check(cd, &(*item)->h, &dreq->req); 287 if (ret) 288 *item = NULL; 289 } 290 return ret; 291 } 292 293 static int do_cache_lookup_nowait(struct cache_detail *cd, 294 struct nfs_dns_ent *key, 295 struct nfs_dns_ent **item) 296 { 297 int ret = -ENOMEM; 298 299 *item = nfs_dns_lookup(cd, key); 300 if (!*item) 301 goto out_err; 302 ret = -ETIMEDOUT; 303 if (!test_bit(CACHE_VALID, &(*item)->h.flags) 304 || (*item)->h.expiry_time < seconds_since_boot() 305 || cd->flush_time > (*item)->h.last_refresh) 306 goto out_put; 307 ret = -ENOENT; 308 if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags)) 309 goto out_put; 310 return 0; 311 out_put: 312 cache_put(&(*item)->h, cd); 313 out_err: 314 *item = NULL; 315 return ret; 316 } 317 318 static int do_cache_lookup_wait(struct cache_detail *cd, 319 struct nfs_dns_ent *key, 320 struct nfs_dns_ent **item) 321 { 322 struct nfs_cache_defer_req *dreq; 323 int ret = -ENOMEM; 324 325 dreq = nfs_cache_defer_req_alloc(); 326 if (!dreq) 327 goto out; 328 ret = do_cache_lookup(cd, key, item, dreq); 329 if (ret == -EAGAIN) { 330 ret = nfs_cache_wait_for_upcall(dreq); 331 if (!ret) 332 ret = do_cache_lookup_nowait(cd, key, item); 333 } 334 nfs_cache_defer_req_put(dreq); 335 out: 336 return ret; 337 } 338 339 ssize_t nfs_dns_resolve_name(char *name, size_t namelen, 340 struct sockaddr *sa, size_t salen) 341 { 342 struct nfs_dns_ent key = { 343 .hostname = name, 344 .namelen = namelen, 345 }; 346 struct nfs_dns_ent *item = NULL; 347 ssize_t ret; 348 349 ret = do_cache_lookup_wait(&nfs_dns_resolve, &key, &item); 350 if (ret == 0) { 351 if (salen >= item->addrlen) { 352 memcpy(sa, &item->addr, item->addrlen); 353 ret = item->addrlen; 354 } else 355 ret = -EOVERFLOW; 356 cache_put(&item->h, &nfs_dns_resolve); 357 } else if (ret == -ENOENT) 358 ret = -ESRCH; 359 return ret; 360 } 361 362 int nfs_dns_resolver_init(void) 363 { 364 return nfs_cache_register(&nfs_dns_resolve); 365 } 366 367 void nfs_dns_resolver_destroy(void) 368 { 369 nfs_cache_unregister(&nfs_dns_resolve); 370 } 371 372 #endif 373