10 Maxdest= 24, /* maximum destinations for a request message */
11 Maxtrans= 3, /* maximum transmissions to a server */
14 static int netquery(DN*, int, RR*, Request*, int);
15 static RR* dnresolve1(char*, int, int, Request*, int, int);
20 * lookup 'type' info for domain name 'name'. If it doesn't exist, try
21 * looking it up as a canonical name.
24 dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, int recurse, int rooted, int *status)
35 * hack for systems that don't have resolve search
36 * lists. Just look up the simple name in the database.
38 if(!rooted && strchr(name, '.') == 0){
40 drp = domainlist(class);
41 for(nrp = drp; nrp != nil; nrp = nrp->next){
42 snprint(nname, sizeof(nname), "%s.%s", name, nrp->ptr->name);
43 rp = dnresolve(nname, class, type, req,cn, depth, recurse, rooted, status);
44 rrfreelist(rrremneg(&rp));
54 * try the name directly
56 rp = dnresolve1(name, class, type, req, depth, recurse);
60 /* try it as a canonical name if we weren't told the name didn't exist */
61 dp = dnlookup(name, class, 0);
62 if(type != Tptr && dp->nonexistent != Rname){
63 for(loops=0; rp == nil && loops < 32; loops++){
64 rp = dnresolve1(name, class, Tcname, req, depth, recurse);
74 name = rp->host->name;
80 rp = dnresolve1(name, class, type, req, depth, recurse);
84 /* distinction between not found and not good */
85 if(rp == 0 && status != 0 && dp->nonexistent != 0)
86 *status = dp->nonexistent;
92 dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse)
95 RR *rp, *nsrp, *dbnsrp;
99 syslog(0, LOG, "dnresolve1 %s %d %d", name, type, class);
101 /* only class Cin implemented so far */
105 dp = dnlookup(name, class, 1);
108 * Try the cache first
110 rp = rrlookup(dp, type, OKneg);
113 /* unauthenticated db entries are hints */
117 /* cached entry must still be valid */
119 /* but Tall entries are special */
120 if(type != Tall || rp->query == Tall)
128 * try the cache for a canonical name. if found punt
129 * since we'll find it during the canonical name search
133 rp = rrlookup(dp, Tcname, NOneg);
140 * if we're running as just a resolver, go to our
141 * designated name servers
144 nsrp = randomize(getdnsservers(class));
146 if(netquery(dp, type, nsrp, req, depth+1)){
148 return rrlookup(dp, type, OKneg);
155 * walk up the domain name looking for
156 * a name server for the domain.
158 for(cp = name; cp; cp = walkup(cp)){
160 * if this is a local (served by us) domain,
163 dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0));
164 if(dbnsrp && dbnsrp->local){
165 rp = dblookup(name, class, type, 1, dbnsrp->ttl);
171 * if recursion isn't set, just accept local
174 if(recurse == Dontrecurse){
180 /* look for ns in cache */
181 nsdp = dnlookup(cp, class, 0);
184 nsrp = randomize(rrlookup(nsdp, Tns, NOneg));
186 /* if the entry timed out, ignore it */
187 if(nsrp && nsrp->ttl < now){
195 /* try the name servers found in cache */
196 if(netquery(dp, type, nsrp, req, depth+1)){
198 return rrlookup(dp, type, OKneg);
206 /* try the name servers found in db */
207 if(netquery(dp, type, dbnsrp, req, depth+1)){
208 /* we got an answer */
210 return rrlookup(dp, type, NOneg);
216 /* settle for a non-authoritative answer */
217 rp = rrlookup(dp, type, OKneg);
221 /* noone answered. try the database, we might have a chance. */
222 return dblookup(name, class, type, 0, 0);
226 * walk a domain name one element to the right. return a pointer to that element.
227 * in other words, return a pointer to the parent domain name.
234 cp = strchr(name, '.');
244 * Get a udpport for requests and replies.
251 if((fd = dial("udp!0!53", nil, nil, nil)) < 0)
252 warning("can't get udp port");
257 mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno)
261 OUdphdr *uh = (OUdphdr*)buf;
263 /* stuff port number into output buffer */
264 memset(uh, 0, sizeof(*uh));
265 hnputs(uh->rport, 53);
267 /* make request and convert it to output format */
268 memset(&m, 0, sizeof(m));
271 m.qd = rralloc(type);
274 len = convDNS2M(&m, &buf[OUdphdrsize], Maxudp);
276 abort(); /* "can't convert" */;
281 /* for alarms in readreply */
283 ding(void *x, char *msg)
286 if(strcmp(msg, "alarm") == 0)
293 freeanswers(DNSmsg *mp)
302 * read replies to a request. ignore any of the wrong type. wait at most 5 seconds.
305 readreply(int fd, DN *dp, int type, ushort req,
306 uchar *ibuf, DNSmsg *mp, ulong endtime, Request *reqp)
315 for(; ; freeanswers(mp)){
318 return -1; /* timed out */
321 alarm((endtime - now) * 1000);
322 len = udpread(fd, (OUdphdr*)ibuf, ibuf+OUdphdrsize, Maxudpin);
325 return -1; /* timed out */
327 /* convert into internal format */
328 memset(mp, 0, sizeof(*mp));
329 err = convM2DNS(&ibuf[OUdphdrsize], len, mp);
331 syslog(0, LOG, "input err %s: %I", err, ibuf);
335 logreply(reqp->id, ibuf, mp);
337 /* answering the right question? */
339 syslog(0, LOG, "%d: id %d instead of %d: %I", reqp->id,
344 syslog(0, LOG, "%d: no question RR: %I", reqp->id, ibuf);
347 if(mp->qd->owner != dp){
348 syslog(0, LOG, "%d: owner %s instead of %s: %I", reqp->id,
349 mp->qd->owner->name, dp->name, ibuf);
352 if(mp->qd->type != type){
353 syslog(0, LOG, "%d: type %d instead of %d: %I", reqp->id,
354 mp->qd->type, type, ibuf);
358 /* remember what request this is in answer to */
359 for(rp = mp->an; rp; rp = rp->next)
365 return 0; /* never reached */
369 * return non-0 if first list includes second list
372 contains(RR *rp1, RR *rp2)
376 for(trp2 = rp2; trp2; trp2 = trp2->next){
377 for(trp1 = rp1; trp1; trp1 = trp1->next){
378 if(trp1->type == trp2->type)
379 if(trp1->host == trp2->host)
380 if(trp1->owner == trp2->owner)
391 typedef struct Dest Dest;
394 uchar a[IPaddrlen]; /* ip address */
395 DN *s; /* name server */
396 int nx; /* number of transmissions */
402 * return multicast version if any
408 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
410 if(ipcmp(ip, IPv4bcast) == 0)
420 * Get next server address
423 serveraddrs(RR *nsrp, Dest *dest, int nd, int depth, Request *reqp)
432 * look for a server whose address we already know.
433 * if we find one, mark it so we ignore this on
437 for(rp = nsrp; rp; rp = rp->next){
438 assert(rp->magic == RRmagic);
441 arp = rrlookup(rp->host, Ta, NOneg);
446 arp = dblookup(rp->host->name, Cin, Ta, 0, 0);
454 * if the cache and database lookup didn't find any new
455 * server addresses, try resolving one via the network.
456 * Mark any we try to resolve so we don't try a second time.
459 for(rp = nsrp; rp; rp = rp->next){
465 * avoid loops looking up a server under itself
467 if(subsume(rp->owner->name, rp->host->name))
470 arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0, depth+1, Recurse, 1, 0);
471 rrfreelist(rrremneg(&arp));
477 /* use any addresses that we found */
478 for(trp = arp; trp; trp = trp->next){
482 parseip(cur->a, trp->ip->name);
487 cur->code = Rtimeout;
495 * cache negative responses
498 cacheneg(DN *dp, int type, int rcode, RR *soarr)
504 /* no cache time specified, don' make anything up */
506 if(soarr->next != nil){
507 rrfreelist(soarr->next);
510 soaowner = soarr->owner;
514 /* the attach can cause soarr to be freed so mine it now */
515 if(soarr != nil && soarr->soa != nil)
516 ttl = soarr->soa->minttl+now;
520 /* add soa and negative RR to the database */
526 rp->negsoaowner = soaowner;
527 rp->negrcode = rcode;
533 * query name servers. If the name server returns a pointer to another
534 * name server, recurse.
537 netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *ibuf, uchar *obuf)
539 int ndest, j, len, replywaits, rv;
548 /* pack request into a message */
550 len = mkreq(dp, type, obuf, Frecurse|Oquery, req);
552 /* no server addresses yet */
556 * transmit requests and wait for answers.
557 * at most Maxtrans attempts to each address.
558 * each cycle send one more message than the previous.
560 for(ndest = 1; ndest < Maxdest; ndest++){
564 if(endtime >= reqp->aborttime)
567 /* get a server address if we need one */
569 j = serveraddrs(nsrp, dest, l - p, depth, reqp);
573 /* no servers, punt */
577 /* send to first 'ndest' destinations */
579 for(; p < &dest[ndest] && p < l; p++){
580 /* skip destinations we've finished with */
581 if(p->nx >= Maxtrans)
586 /* exponential backoff of requests */
587 if((1<<p->nx) > ndest)
590 memmove(obuf, p->a, sizeof(p->a));
592 logsend(reqp->id, depth, obuf, p->s->name,
594 {Udphdr *uh = (Udphdr*)obuf;
595 print("send %I %I %d %d\n", uh->raddr, uh->laddr, nhgets(uh->rport), nhgets(uh->lport));
597 if(udpwrite(fd, (OUdphdr*)obuf, obuf+OUdphdrsize, len) < 0)
598 warning("sending udp msg %r");
602 break; /* no destinations left */
604 /* wait up to 5 seconds for replies */
605 endtime = time(0) + 5;
606 if(endtime > reqp->aborttime)
607 endtime = reqp->aborttime;
609 for(replywaits = 0; replywaits < ndest; replywaits++){
610 if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) < 0)
611 break; /* timed out */
614 for(p = dest; p < l; p++)
615 if(memcmp(p->a, ibuf, sizeof(p->a)) == 0)
618 /* remove all addrs of responding server from list */
619 for(np = dest; np < l; np++)
623 /* ignore any error replies */
624 if((m.flags & Rmask) == Rserver){
634 /* ignore any bad delegations */
635 if(m.ns && baddelegation(m.ns, nsrp, ibuf)){
648 /* remove any soa's from the authority section */
649 soarr = rrremtype(&m.ns, Tsoa);
651 /* incorporate answers */
653 rrattach(m.an, (m.flags & Fauth) ? 1 : 0);
662 /* free the question */
667 * Any reply from an authoritative server,
668 * or a positive reply terminates the search
670 if(m.an != nil || (m.flags & Fauth)){
671 if(m.an == nil && (m.flags & Rmask) == Rname)
672 dp->nonexistent = Rname;
677 * cache any negative responses, free soarr
679 if((m.flags & Fauth) && m.an == nil)
680 cacheneg(dp, type, (m.flags & Rmask), soarr);
688 * if we've been given better name servers
692 tp = rrlookup(ndp, Tns, NOneg);
693 if(!contains(nsrp, tp)){
694 rv = netquery(dp, type, tp, reqp, depth+1);
703 /* if all servers returned failure, propogate it */
704 dp->nonexistent = Rserver;
705 for(p = dest; p < l; p++)
706 if(p->code != Rserver)
712 typedef struct Qarg Qarg;
724 netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth)
734 /* use alloced buffers rather than ones from the stack */
735 ibuf = emalloc(Maxudpin+OUdphdrsize);
736 obuf = emalloc(Maxudp+OUdphdrsize);
740 /* prepare server RR's for incremental lookup */
741 for(rp = nsrp; rp; rp = rp->next)
747 rv = netquery1(fd, dp, type, nsrp, reqp, depth, ibuf, obuf);