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