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