Blob


1 #include <u.h>
2 #include <sys/time.h>
3 #include <libc.h>
4 #include <ip.h>
5 #include <bio.h>
6 #include <ndb.h>
7 #include "dns.h"
9 enum
10 {
11 Maxdest= 24, /* maximum destinations for a request message */
12 Maxtrans= 3 /* maximum transmissions to a server */
13 };
15 static int netquery(DN*, int, RR*, Request*, int);
16 static RR* dnresolve1(char*, int, int, Request*, int, int);
18 char *LOG = "dns";
20 /*
21 * lookup 'type' info for domain name 'name'. If it doesn't exist, try
22 * looking it up as a canonical name.
23 */
24 RR*
25 dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, int recurse, int rooted, int *status)
26 {
27 RR *rp, *nrp, *drp;
28 DN *dp;
29 int loops;
30 char nname[Domlen];
32 if(status)
33 *status = 0;
35 /*
36 * hack for systems that don't have resolve search
37 * lists. Just look up the simple name in the database.
38 */
39 if(!rooted && strchr(name, '.') == 0){
40 rp = nil;
41 drp = domainlist(class);
42 for(nrp = drp; nrp != nil; nrp = nrp->next){
43 snprint(nname, sizeof(nname), "%s.%s", name, nrp->ptr->name);
44 rp = dnresolve(nname, class, type, req,cn, depth, recurse, rooted, status);
45 rrfreelist(rrremneg(&rp));
46 if(rp != nil)
47 break;
48 }
49 if(drp != nil)
50 rrfree(drp);
51 return rp;
52 }
54 /*
55 * try the name directly
56 */
57 rp = dnresolve1(name, class, type, req, depth, recurse);
58 if(rp)
59 return randomize(rp);
61 /* try it as a canonical name if we weren't told the name didn't exist */
62 dp = dnlookup(name, class, 0);
63 if(type != Tptr && dp->nonexistent != Rname){
64 for(loops=0; rp == nil && loops < 32; loops++){
65 rp = dnresolve1(name, class, Tcname, req, depth, recurse);
66 if(rp == nil)
67 break;
69 if(rp->negative){
70 rrfreelist(rp);
71 rp = nil;
72 break;
73 }
75 name = rp->host->name;
76 if(cn)
77 rrcat(cn, rp);
78 else
79 rrfreelist(rp);
81 rp = dnresolve1(name, class, type, req, depth, recurse);
82 }
83 }
85 /* distinction between not found and not good */
86 if(rp == 0 && status != 0 && dp->nonexistent != 0)
87 *status = dp->nonexistent;
89 return randomize(rp);
90 }
92 static RR*
93 dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse)
94 {
95 DN *dp, *nsdp;
96 RR *rp, *nsrp, *dbnsrp;
97 char *cp;
99 if(debug)
100 syslog(0, LOG, "dnresolve1 %s %d %d", name, type, class);
102 /* only class Cin implemented so far */
103 if(class != Cin)
104 return 0;
106 dp = dnlookup(name, class, 1);
108 /*
109 * Try the cache first
110 */
111 rp = rrlookup(dp, type, OKneg);
112 if(rp){
113 if(rp->db){
114 /* unauthenticated db entries are hints */
115 if(rp->auth)
116 return rp;
117 } else {
118 /* cached entry must still be valid */
119 if(rp->ttl > now){
120 /* but Tall entries are special */
121 if(type != Tall || rp->query == Tall)
122 return rp;
126 rrfreelist(rp);
128 /*
129 * try the cache for a canonical name. if found punt
130 * since we'll find it during the canonical name search
131 * in dnresolve().
132 */
133 if(type != Tcname){
134 rp = rrlookup(dp, Tcname, NOneg);
135 rrfreelist(rp);
136 if(rp)
137 return 0;
140 /*
141 * if we're running as just a resolver, go to our
142 * designated name servers
143 */
144 if(resolver){
145 nsrp = randomize(getdnsservers(class));
146 if(nsrp != nil) {
147 if(netquery(dp, type, nsrp, req, depth+1)){
148 rrfreelist(nsrp);
149 return rrlookup(dp, type, OKneg);
151 rrfreelist(nsrp);
155 /*
156 * walk up the domain name looking for
157 * a name server for the domain.
158 */
159 for(cp = name; cp; cp = walkup(cp)){
160 /*
161 * if this is a local (served by us) domain,
162 * return answer
163 */
164 dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0));
165 if(dbnsrp && dbnsrp->local){
166 rp = dblookup(name, class, type, 1, dbnsrp->ttl);
167 rrfreelist(dbnsrp);
168 return rp;
171 /*
172 * if recursion isn't set, just accept local
173 * entries
174 */
175 if(recurse == Dontrecurse){
176 if(dbnsrp)
177 rrfreelist(dbnsrp);
178 continue;
181 /* look for ns in cache */
182 nsdp = dnlookup(cp, class, 0);
183 nsrp = nil;
184 if(nsdp)
185 nsrp = randomize(rrlookup(nsdp, Tns, NOneg));
187 /* if the entry timed out, ignore it */
188 if(nsrp && nsrp->ttl < now){
189 rrfreelist(nsrp);
190 nsrp = nil;
193 if(nsrp){
194 rrfreelist(dbnsrp);
196 /* try the name servers found in cache */
197 if(netquery(dp, type, nsrp, req, depth+1)){
198 rrfreelist(nsrp);
199 return rrlookup(dp, type, OKneg);
201 rrfreelist(nsrp);
202 continue;
205 /* use ns from db */
206 if(dbnsrp){
207 /* try the name servers found in db */
208 if(netquery(dp, type, dbnsrp, req, depth+1)){
209 /* we got an answer */
210 rrfreelist(dbnsrp);
211 return rrlookup(dp, type, NOneg);
213 rrfreelist(dbnsrp);
217 /* settle for a non-authoritative answer */
218 rp = rrlookup(dp, type, OKneg);
219 if(rp)
220 return rp;
222 /* noone answered. try the database, we might have a chance. */
223 return dblookup(name, class, type, 0, 0);
226 /*
227 * walk a domain name one element to the right. return a pointer to that element.
228 * in other words, return a pointer to the parent domain name.
229 */
230 char*
231 walkup(char *name)
233 char *cp;
235 cp = strchr(name, '.');
236 if(cp)
237 return cp+1;
238 else if(*name)
239 return "";
240 else
241 return 0;
244 /*
245 * Get a udpport for requests and replies.
246 */
247 int
248 udpport(void)
250 int fd;
252 if((fd = dial("udp!0!53", nil, nil, nil)) < 0)
253 warning("can't get udp port");
254 return fd;
257 int
258 mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno)
260 DNSmsg m;
261 int len;
262 Udphdr *uh = (Udphdr*)buf;
264 /* stuff port number into output buffer */
265 memset(uh, 0, sizeof(*uh));
266 hnputs(uh->rport, 53);
268 /* make request and convert it to output format */
269 memset(&m, 0, sizeof(m));
270 m.flags = flags;
271 m.id = reqno;
272 m.qd = rralloc(type);
273 m.qd->owner = dp;
274 m.qd->type = type;
275 len = convDNS2M(&m, &buf[Udphdrsize], Maxudp);
276 if(len < 0)
277 abort(); /* "can't convert" */;
278 rrfree(m.qd);
279 return len;
282 static void
283 freeanswers(DNSmsg *mp)
285 rrfreelist(mp->qd);
286 rrfreelist(mp->an);
287 rrfreelist(mp->ns);
288 rrfreelist(mp->ar);
291 /*
292 * read replies to a request. ignore any of the wrong type. wait at most 5 seconds.
293 */
294 static int udpreadtimeout(int, Udphdr*, void*, int, int);
295 static int
296 readreply(int fd, DN *dp, int type, ushort req,
297 uchar *ibuf, DNSmsg *mp, ulong endtime, Request *reqp)
299 char *err;
300 int len;
301 ulong now;
302 RR *rp;
304 for(; ; freeanswers(mp)){
305 now = time(0);
306 if(now >= endtime)
307 return -1; /* timed out */
309 /* timed read */
310 len = udpreadtimeout(fd, (Udphdr*)ibuf, ibuf+Udphdrsize, Maxudpin, (endtime-now)*1000);
311 if(len < 0)
312 return -1; /* timed out */
314 /* convert into internal format */
315 memset(mp, 0, sizeof(*mp));
316 err = convM2DNS(&ibuf[Udphdrsize], len, mp);
317 if(err){
318 syslog(0, LOG, "input err %s: %I", err, ibuf);
319 continue;
321 if(debug)
322 logreply(reqp->id, ibuf, mp);
324 /* answering the right question? */
325 if(mp->id != req){
326 syslog(0, LOG, "%d: id %d instead of %d: %I", reqp->id,
327 mp->id, req, ibuf);
328 continue;
330 if(mp->qd == 0){
331 syslog(0, LOG, "%d: no question RR: %I", reqp->id, ibuf);
332 continue;
334 if(mp->qd->owner != dp){
335 syslog(0, LOG, "%d: owner %s instead of %s: %I", reqp->id,
336 mp->qd->owner->name, dp->name, ibuf);
337 continue;
339 if(mp->qd->type != type){
340 syslog(0, LOG, "%d: type %d instead of %d: %I", reqp->id,
341 mp->qd->type, type, ibuf);
342 continue;
345 /* remember what request this is in answer to */
346 for(rp = mp->an; rp; rp = rp->next)
347 rp->query = type;
349 return 0;
352 return 0; /* never reached */
355 static int
356 udpreadtimeout(int fd, Udphdr *h, void *data, int n, int ms)
358 fd_set rd;
359 struct timeval tv;
361 FD_ZERO(&rd);
362 FD_SET(fd, &rd);
364 tv.tv_sec = ms/1000;
365 tv.tv_usec = (ms%1000)*1000;
367 if(select(fd+1, &rd, 0, 0, &tv) != 1)
368 return -1;
369 return udpread(fd, h, data, n);
372 /*
373 * return non-0 if first list includes second list
374 */
375 int
376 contains(RR *rp1, RR *rp2)
378 RR *trp1, *trp2;
380 for(trp2 = rp2; trp2; trp2 = trp2->next){
381 for(trp1 = rp1; trp1; trp1 = trp1->next){
382 if(trp1->type == trp2->type)
383 if(trp1->host == trp2->host)
384 if(trp1->owner == trp2->owner)
385 break;
387 if(trp1 == 0)
388 return 0;
391 return 1;
395 typedef struct Dest Dest;
396 struct Dest
398 uchar a[IPaddrlen]; /* ip address */
399 DN *s; /* name server */
400 int nx; /* number of transmissions */
401 int code;
402 };
405 /*
406 * return multicast version if any
407 */
408 int
409 ipisbm(uchar *ip)
411 if(isv4(ip)){
412 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
413 return 4;
414 if(ipcmp(ip, IPv4bcast) == 0)
415 return 4;
416 } else {
417 if(ip[0] == 0xff)
418 return 6;
420 return 0;
423 /*
424 * Get next server address
425 */
426 static int
427 serveraddrs(RR *nsrp, Dest *dest, int nd, int depth, Request *reqp)
429 RR *rp, *arp, *trp;
430 Dest *cur;
432 if(nd >= Maxdest)
433 return 0;
435 /*
436 * look for a server whose address we already know.
437 * if we find one, mark it so we ignore this on
438 * subsequent passes.
439 */
440 arp = 0;
441 for(rp = nsrp; rp; rp = rp->next){
442 assert(rp->magic == RRmagic);
443 if(rp->marker)
444 continue;
445 arp = rrlookup(rp->host, Ta, NOneg);
446 if(arp){
447 rp->marker = 1;
448 break;
450 arp = dblookup(rp->host->name, Cin, Ta, 0, 0);
451 if(arp){
452 rp->marker = 1;
453 break;
457 /*
458 * if the cache and database lookup didn't find any new
459 * server addresses, try resolving one via the network.
460 * Mark any we try to resolve so we don't try a second time.
461 */
462 if(arp == 0){
463 for(rp = nsrp; rp; rp = rp->next){
464 if(rp->marker)
465 continue;
466 rp->marker = 1;
468 /*
469 * avoid loops looking up a server under itself
470 */
471 if(subsume(rp->owner->name, rp->host->name))
472 continue;
474 arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0, depth+1, Recurse, 1, 0);
475 rrfreelist(rrremneg(&arp));
476 if(arp)
477 break;
481 /* use any addresses that we found */
482 for(trp = arp; trp; trp = trp->next){
483 if(nd >= Maxdest)
484 break;
485 cur = &dest[nd];
486 parseip(cur->a, trp->ip->name);
487 if(ipisbm(cur->a))
488 continue;
489 cur->nx = 0;
490 cur->s = trp->owner;
491 cur->code = Rtimeout;
492 nd++;
494 rrfreelist(arp);
495 return nd;
498 /*
499 * cache negative responses
500 */
501 static void
502 cacheneg(DN *dp, int type, int rcode, RR *soarr)
504 RR *rp;
505 DN *soaowner;
506 ulong ttl;
508 /* no cache time specified, don' make anything up */
509 if(soarr != nil){
510 if(soarr->next != nil){
511 rrfreelist(soarr->next);
512 soarr->next = nil;
514 soaowner = soarr->owner;
515 } else
516 soaowner = nil;
518 /* the attach can cause soarr to be freed so mine it now */
519 if(soarr != nil && soarr->soa != nil)
520 ttl = soarr->soa->minttl+now;
521 else
522 ttl = 5*Min;
524 /* add soa and negative RR to the database */
525 rrattach(soarr, 1);
527 rp = rralloc(type);
528 rp->owner = dp;
529 rp->negative = 1;
530 rp->negsoaowner = soaowner;
531 rp->negrcode = rcode;
532 rp->ttl = ttl;
533 rrattach(rp, 1);
536 /*
537 * query name servers. If the name server returns a pointer to another
538 * name server, recurse.
539 */
540 static int
541 netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *ibuf, uchar *obuf)
543 int ndest, j, len, replywaits, rv;
544 ushort req;
545 RR *tp, *soarr;
546 Dest *p, *l, *np;
547 DN *ndp;
548 Dest dest[Maxdest];
549 DNSmsg m;
550 ulong endtime;
551 Udphdr *uh;
553 /* pack request into a message */
554 req = rand();
555 len = mkreq(dp, type, obuf, Frecurse|Oquery, req);
557 /* no server addresses yet */
558 l = dest;
560 /*
561 * transmit requests and wait for answers.
562 * at most Maxtrans attempts to each address.
563 * each cycle send one more message than the previous.
564 */
565 for(ndest = 1; ndest < Maxdest; ndest++){
566 p = dest;
568 endtime = time(0);
569 if(endtime >= reqp->aborttime)
570 break;
572 /* get a server address if we need one */
573 if(ndest > l - p){
574 j = serveraddrs(nsrp, dest, l - p, depth, reqp);
575 l = &dest[j];
578 /* no servers, punt */
579 if(l == dest)
580 break;
582 /* send to first 'ndest' destinations */
583 j = 0;
584 for(; p < &dest[ndest] && p < l; p++){
585 /* skip destinations we've finished with */
586 if(p->nx >= Maxtrans)
587 continue;
589 j++;
591 /* exponential backoff of requests */
592 if((1<<p->nx) > ndest)
593 continue;
595 memmove(obuf, p->a, sizeof(p->a));
596 if(debug)
597 logsend(reqp->id, depth, obuf, p->s->name,
598 dp->name, type);
599 uh = (Udphdr*)obuf;
600 fprint(2, "send %I %I %d %d\n", uh->raddr, uh->laddr, nhgets(uh->rport), nhgets(uh->lport));
601 if(udpwrite(fd, uh, obuf+Udphdrsize, len) < 0)
602 warning("sending udp msg %r");
603 p->nx++;
605 if(j == 0)
606 break; /* no destinations left */
608 /* wait up to 5 seconds for replies */
609 endtime = time(0) + 5;
610 if(endtime > reqp->aborttime)
611 endtime = reqp->aborttime;
613 for(replywaits = 0; replywaits < ndest; replywaits++){
614 if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) < 0)
615 break; /* timed out */
617 /* find responder */
618 for(p = dest; p < l; p++)
619 if(memcmp(p->a, ibuf, sizeof(p->a)) == 0)
620 break;
622 /* remove all addrs of responding server from list */
623 for(np = dest; np < l; np++)
624 if(np->s == p->s)
625 p->nx = Maxtrans;
627 /* ignore any error replies */
628 if((m.flags & Rmask) == Rserver){
629 rrfreelist(m.qd);
630 rrfreelist(m.an);
631 rrfreelist(m.ar);
632 rrfreelist(m.ns);
633 if(p != l)
634 p->code = Rserver;
635 continue;
638 /* ignore any bad delegations */
639 if(m.ns && baddelegation(m.ns, nsrp, ibuf)){
640 rrfreelist(m.ns);
641 m.ns = nil;
642 if(m.an == nil){
643 rrfreelist(m.qd);
644 rrfreelist(m.ar);
645 if(p != l)
646 p->code = Rserver;
647 continue;
652 /* remove any soa's from the authority section */
653 soarr = rrremtype(&m.ns, Tsoa);
655 /* incorporate answers */
656 if(m.an)
657 rrattach(m.an, (m.flags & Fauth) ? 1 : 0);
658 if(m.ar)
659 rrattach(m.ar, 0);
660 if(m.ns){
661 ndp = m.ns->owner;
662 rrattach(m.ns, 0);
663 } else
664 ndp = 0;
666 /* free the question */
667 if(m.qd)
668 rrfreelist(m.qd);
670 /*
671 * Any reply from an authoritative server,
672 * or a positive reply terminates the search
673 */
674 if(m.an != nil || (m.flags & Fauth)){
675 if(m.an == nil && (m.flags & Rmask) == Rname)
676 dp->nonexistent = Rname;
677 else
678 dp->nonexistent = 0;
680 /*
681 * cache any negative responses, free soarr
682 */
683 if((m.flags & Fauth) && m.an == nil)
684 cacheneg(dp, type, (m.flags & Rmask), soarr);
685 else
686 rrfreelist(soarr);
687 return 1;
689 rrfreelist(soarr);
691 /*
692 * if we've been given better name servers
693 * recurse
694 */
695 if(m.ns){
696 tp = rrlookup(ndp, Tns, NOneg);
697 if(!contains(nsrp, tp)){
698 rv = netquery(dp, type, tp, reqp, depth+1);
699 rrfreelist(tp);
700 return rv;
701 } else
702 rrfreelist(tp);
707 /* if all servers returned failure, propogate it */
708 dp->nonexistent = Rserver;
709 for(p = dest; p < l; p++)
710 if(p->code != Rserver)
711 dp->nonexistent = 0;
713 return 0;
716 typedef struct Qarg Qarg;
717 struct Qarg
719 DN *dp;
720 int type;
721 RR *nsrp;
722 Request *reqp;
723 int depth;
724 };
727 static int
728 netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth)
730 uchar *obuf;
731 uchar *ibuf;
732 RR *rp;
733 int fd, rv;
735 if(depth > 12)
736 return 0;
738 /* use alloced buffers rather than ones from the stack */
739 ibuf = emalloc(Maxudpin+Udphdrsize);
740 obuf = emalloc(Maxudp+Udphdrsize);
742 /* prepare server RR's for incremental lookup */
743 for(rp = nsrp; rp; rp = rp->next)
744 rp->marker = 0;
746 fd = udpport();
747 if(fd < 0)
748 return 0;
749 rv = netquery1(fd, dp, type, nsrp, reqp, depth, ibuf, obuf);
750 close(fd);
751 free(ibuf);
752 free(obuf);
754 return rv;