2 * domain name resolvers, see rfcs 1035 and 1123
11 typedef struct Dest Dest;
12 typedef struct Query Query;
21 Maxdest= 32, /* maximum destinations for a request message */
22 Maxoutstanding= 15, /* max. outstanding queries per domain name */
25 * these are the old values; we're trying longer timeouts now
26 * primarily for the benefit of remote nameservers querying us
27 * during times of bad connectivity.
29 Maxtrans= 5, /* maximum transmissions to a server */
30 Maxretries= 10, /* cname+actual resends: was 32; have pity on user */
32 enum { Hurry, Patient, };
33 enum { Outns, Inns, };
37 uchar a[IPaddrlen]; /* ip address */
38 DN *s; /* name server name */
39 RR *n; /* name server rr */
40 int nx; /* number of transmissions */
41 int code; /* response code; used to clear dp->respcode */
46 ushort type; /* and type to look up */
48 Query *prev; /* previous query */
50 RR *nsrp; /* name servers to consult */
52 Dest *dest; /* array of destinations */
53 Dest *curdest; /* pointer to next to fill */
54 int ndest; /* transmit to this many on this round */
59 int tcpfd; /* if Tcp, read replies from here */
61 uchar tcpip[IPaddrlen];
64 static RR* dnresolve1(char*, int, int, Request*, int, int);
65 static int netquery(Query *, int);
68 * reading /proc/pid/args yields either "name args" or "name [display args]",
69 * so return only display args, if any.
78 snprint(buf, sizeof buf, "#p/%d/args", getpid());
79 if((fd = open(buf, OREAD)) < 0)
82 n = read(fd, buf, sizeof buf-1);
86 if ((lp = strchr(buf, '[')) == nil ||
87 (rp = strrchr(buf, ']')) == nil)
94 rrfreelistptr(RR **rpp)
98 if (rpp == nil || *rpp == nil)
101 *rpp = nil; /* update pointer in memory before freeing list */
106 * lookup 'type' info for domain name 'name'. If it doesn't exist, try
107 * looking it up as a canonical name.
109 * this process can be quite slow if time-outs are set too high when querying
110 * nameservers that just don't respond to certain query types. in that case,
111 * there will be multiple udp retries, multiple nameservers will be queried,
112 * and this will be repeated for a cname query. the whole thing will be
113 * retried several times until we get an answer or a time-out.
116 dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth,
117 int recurse, int rooted, int *status)
128 if(depth > 12) /* in a recursive loop? */
131 procname = procgetname();
133 * hack for systems that don't have resolve search
134 * lists. Just look up the simple name in the database.
136 if(!rooted && strchr(name, '.') == nil){
138 drp = domainlist(class);
139 for(nrp = drp; rp == nil && nrp != nil; nrp = nrp->next){
140 snprint(nname, sizeof nname, "%s.%s", name,
142 rp = dnresolve(nname, class, type, req, cn, depth+1,
143 recurse, rooted, status);
144 rrfreelist(rrremneg(&rp));
148 procsetname("%s", procname);
154 * try the name directly
156 rp = dnresolve1(name, class, type, req, depth, recurse);
157 if(rp == nil && (dp = idnlookup(name, class, 0)) != nil) {
159 * try it as a canonical name if we weren't told
160 * that the name didn't exist
162 if(type != Tptr && dp->respcode != Rname)
163 for(loops = 0; rp == nil && loops < Maxretries; loops++){
164 /* retry cname, then the actual type */
165 rp = dnresolve1(name, class, Tcname, req,
170 /* rp->host == nil shouldn't happen, but does */
171 if(rp->negative || rp->host == nil){
177 name = rp->host->name;
183 rp = dnresolve1(name, class, type, req,
187 /* distinction between not found and not good */
188 if(rp == nil && status != nil && dp->respcode != Rok)
189 *status = dp->respcode;
191 procsetname("%s", procname);
193 return randomize(rp);
197 queryinit(Query *qp, DN *dp, int type, Request *req)
199 assert(dp && dp->magic == DNmagic);
201 memset(qp, 0, sizeof *qp);
202 qp->udpfd = qp->tcpfd = qp->tcpctlfd = -1;
205 if (qp->type != type)
206 dnslog("queryinit: bogus type %d", type);
208 qp->dest = qp->curdest = nil;
215 querydestroy(Query *qp)
217 if(qp->req->aux == qp)
218 qp->req->aux = qp->prev;
219 /* leave udpfd open */
222 if (qp->tcpctlfd >= 0) {
223 hangup(qp->tcpctlfd);
226 memset(qp, 0, sizeof *qp); /* prevent accidents */
227 qp->udpfd = qp->tcpfd = qp->tcpctlfd = -1;
231 * if the response to a query hasn't arrived within 100 ms.,
232 * it's unlikely to arrive at all. after 1 s., it's really unlikely.
233 * queries for missing RRs are likely to produce time-outs rather than
234 * negative responses, so cname and aaaa queries are likely to time out,
235 * thus we don't wait very long for them.
238 notestats(vlong start, int tmout, int type)
245 else if (type == Tcname)
248 long wait10ths = NS2MS(nsec() - start) / 100;
251 stats.under10ths[0]++;
252 else if (wait10ths >= nelem(stats.under10ths))
253 stats.under10ths[nelem(stats.under10ths) - 1]++;
255 stats.under10ths[wait10ths]++;
268 /* netquery with given name servers, free ns rrs when done */
270 netqueryns(Query *qp, int depth, RR *nsrp)
277 rv = netquery(qp, depth);
278 qp->nsrp = nil; /* prevent accidents */
284 issuequery(Query *qp, char *name, int class, int depth, int recurse)
288 RR *rp, *nsrp, *dbnsrp;
291 * if we're running as just a resolver, query our
292 * designated name servers
295 nsrp = randomize(getdnsservers(class));
297 if(netqueryns(qp, depth+1, nsrp) > Answnone)
298 return rrlookup(qp->dp, qp->type, OKneg);
302 * walk up the domain name looking for
303 * a name server for the domain.
305 for(cp = name; cp; cp = walkup(cp)){
307 * if this is a local (served by us) domain,
310 dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0));
311 if(dbnsrp && dbnsrp->local){
312 rp = dblookup(name, class, qp->type, 1, dbnsrp->ttl);
318 * if recursion isn't set, just accept local
321 if(recurse == Dontrecurse){
327 /* look for ns in cache */
328 nsdp = idnlookup(cp, class, 0);
331 nsrp = randomize(rrlookup(nsdp, Tns, NOneg));
333 /* if the entry timed out, ignore it */
334 if(nsrp && !nsrp->db && (long)(nsrp->expire - now) <= 0)
335 rrfreelistptr(&nsrp);
338 rrfreelistptr(&dbnsrp);
340 /* query the name servers found in cache */
341 if(netqueryns(qp, depth+1, nsrp) > Answnone)
342 return rrlookup(qp->dp, qp->type, OKneg);
344 /* try the name servers found in db */
345 if(netqueryns(qp, depth+1, dbnsrp) > Answnone)
346 return rrlookup(qp->dp, qp->type, NOneg);
352 dnresolve1(char *name, int class, int type, Request *req, int depth,
361 dnslog("[%d] dnresolve1 %s %d %d", getpid(), name, type, class);
363 /* only class Cin implemented so far */
367 dp = idnlookup(name, class, 1);
370 * Try the cache first
372 rp = rrlookup(dp, type, OKneg);
375 /* unauthoritative db entries are hints */
379 dnslog("[%d] dnresolve1 %s %d %d: auth rr in db",
380 getpid(), name, type, class);
384 /* cached entry must still be valid */
385 if((long)(rp->expire - now) > 0)
386 /* but Tall entries are special */
387 if(type != Tall || rp->query == Tall) {
390 dnslog("[%d] dnresolve1 %s %d %d: rr not in db",
391 getpid(), name, type, class);
395 rp = nil; /* accident prevention */
399 * try the cache for a canonical name. if found punt
400 * since we'll find it during the canonical name search
404 rp = rrlookup(dp, Tcname, NOneg);
408 dnslog("[%d] dnresolve1 %s %d %d: rr from rrlookup for non-cname",
409 getpid(), name, type, class);
415 * if the domain name is within an area of ours,
416 * we should have found its data in memory by now.
418 area = inmyarea(dp->name);
419 if (area || strncmp(dp->name, "local#", 6) == 0)
422 queryinit(&q, dp, type, req);
423 rp = issuequery(&q, name, class, depth, recurse);
428 dnslog("[%d] dnresolve1 %s %d %d: rr from query",
429 getpid(), name, type, class);
433 /* settle for a non-authoritative answer */
434 rp = rrlookup(dp, type, OKneg);
437 dnslog("[%d] dnresolve1 %s %d %d: rr from rrlookup",
438 getpid(), name, type, class);
442 /* noone answered. try the database, we might have a chance. */
443 rp = dblookup(name, class, type, 0, 0);
446 dnslog("[%d] dnresolve1 %s %d %d: rr from dblookup",
447 getpid(), name, type, class);
450 dnslog("[%d] dnresolve1 %s %d %d: no rr from dblookup; crapped out",
451 getpid(), name, type, class);
457 * walk a domain name one element to the right.
458 * return a pointer to that element.
459 * in other words, return a pointer to the parent domain name.
466 cp = strchr(name, '.');
476 * Get a udp port for sending requests and reading replies. Put the port
477 * into "headers" mode.
479 static char *hmsg = "headers";
485 char ds[64], adir[64];
488 snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt && *mtpt) ? mtpt : "/net");
489 ctl = announce(ds, adir);
491 /* warning("can't get udp port"); */
495 /* turn on header style interface */
496 if(write(ctl, hmsg, strlen(hmsg)) != strlen(hmsg)){
502 /* grab the data file */
503 snprint(ds, sizeof ds, "%s/data", adir);
504 fd = open(ds, ORDWR);
507 warning("can't open udp port %s: %r", ds);
512 initdnsmsg(DNSmsg *mp, RR *rp, int flags, ushort reqno)
514 memset(mp, 0, sizeof *mp);
522 /* generate a DNS UDP query packet */
524 mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno)
528 Udphdr *uh = (Udphdr*)buf;
531 /* stuff port number into output buffer */
532 memset(uh, 0, sizeof *uh);
533 hnputs(uh->rport, 53);
535 /* make request and convert it to output format */
538 initdnsmsg(&m, rp, flags, reqno);
539 len = convDNS2M(&m, &buf[Udphdrsize], Maxudp);
545 freeanswers(DNSmsg *mp)
547 rrfreelistptr(&mp->qd);
548 rrfreelistptr(&mp->an);
549 rrfreelistptr(&mp->ns);
550 rrfreelistptr(&mp->ar);
551 mp->qdcount = mp->ancount = mp->nscount = mp->arcount = 0;
554 /* timed read of reply. sets srcip. ibuf must be 64K to handle tcp answers. */
556 readnet(Query *qp, int medium, uchar *ibuf, uvlong endms, uchar **replyp,
561 vlong startns = nsec();
565 len = -1; /* pessimism */
567 memset(srcip, 0, IPaddrlen);
568 ms = endms - NS2MS(startns);
570 return -1; /* taking too long */
576 dnslog("readnet: qp->udpfd closed");
578 len = read(qp->udpfd, ibuf, Udphdrsize+Maxudpin);
580 notestats(startns, len < 0, qp->type);
581 if (len >= IPaddrlen)
582 memmove(srcip, ibuf, IPaddrlen);
583 if (len >= Udphdrsize) {
590 dnslog("readnet: tcp params not set");
593 dnslog("readnet: %s: tcp fd unset for dest %I",
594 qp->dp->name, qp->tcpip);
595 else if (readn(fd, lenbuf, 2) != 2) {
596 dnslog("readnet: short read of 2-byte tcp msg size from %I",
598 /* probably a time-out */
599 notestats(startns, 1, qp->type);
601 len = lenbuf[0]<<8 | lenbuf[1];
602 if (readn(fd, ibuf, len) != len) {
603 dnslog("readnet: short read of tcp data from %I",
605 /* probably a time-out */
606 notestats(startns, 1, qp->type);
610 memmove(srcip, qp->tcpip, IPaddrlen);
618 * read replies to a request and remember the rrs in the answer(s).
619 * ignore any of the wrong type.
620 * wait at most until endms.
623 readreply(Query *qp, int medium, ushort req, uchar *ibuf, DNSmsg *mp,
630 uchar srcip[IPaddrlen];
633 for (; timems() < endms &&
634 (len = readnet(qp, medium, ibuf, endms, &reply, srcip)) >= 0;
636 /* convert into internal format */
637 memset(mp, 0, sizeof *mp);
638 err = convM2DNS(reply, len, mp, nil);
639 if (mp->flags & Ftrunc) {
642 /* notify our caller to retry the query via tcp. */
645 dnslog("readreply: %s: input err, len %d: %s: %I",
646 qp->dp->name, len, err, srcip);
651 logreply(qp->req->id, srcip, mp);
653 /* answering the right question? */
655 dnslog("%d: id %d instead of %d: %I", qp->req->id,
658 dnslog("%d: no question RR: %I", qp->req->id, srcip);
659 else if(mp->qd->owner != qp->dp)
660 dnslog("%d: owner %s instead of %s: %I", qp->req->id,
661 mp->qd->owner->name, qp->dp->name, srcip);
662 else if(mp->qd->type != qp->type)
663 dnslog("%d: qp->type %d instead of %d: %I",
664 qp->req->id, mp->qd->type, qp->type, srcip);
666 /* remember what request this is in answer to */
667 for(rp = mp->an; rp; rp = rp->next)
668 rp->query = qp->type;
672 if (timems() >= endms) {
673 ; /* query expired */
675 /* this happens routinely when a read times out */
676 dnslog("readreply: %s type %s: ns %I read error or eof "
677 "(returned %d): %r", qp->dp->name, rrname(qp->type,
678 tbuf, sizeof tbuf), srcip, len);
680 for (rp = qp->nsrp; rp != nil; rp = rp->next)
682 dnslog("readreply: %s: query sent to "
683 "ns %s", qp->dp->name,
686 memset(mp, 0, sizeof *mp);
691 * return non-0 if first list includes second list
694 contains(RR *rp1, RR *rp2)
698 for(trp2 = rp2; trp2; trp2 = trp2->next){
699 for(trp1 = rp1; trp1; trp1 = trp1->next)
700 if(trp1->type == trp2->type)
701 if(trp1->host == trp2->host)
702 if(trp1->owner == trp2->owner)
712 * return multicast version if any
718 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 ||
719 ipcmp(ip, IPv4bcast) == 0)
728 queryloops(Query *qp, RR *rp)
733 * looking up a server under itself
735 if(subsume(rp->owner->name, ns->name))
739 * cycle on name servers refering
742 for(; qp; qp = qp->prev)
750 * Get next server type address(es) into qp->dest[nd] and beyond
753 serveraddrs(Query *qp, int nd, int depth, int type)
759 if(nd >= Maxdest) /* dest array is full? */
763 * look for a server whose address we already know.
764 * if we find one, mark it so we ignore this on
769 for(rp = qp->nsrp; rp; rp = rp->next){
770 assert(rp->magic == RRmagic);
771 if(rp->marker & mark)
773 arp = rrlookup(rp->host, type, NOneg);
778 arp = dblookup(rp->host->name, Cin, type, 0, 0);
786 * if the cache and database lookup didn't find any new
787 * server addresses, try resolving one via the network.
788 * Mark any we try to resolve so we don't try a second time.
791 for(rp = qp->nsrp; rp; rp = rp->next)
792 if((rp->marker & mark) == 0)
793 if(queryloops(qp, rp))
795 * give up as we should have got the address
796 * by higher up nameserver when recursing
797 * down, or will be queried when recursing up.
801 for(rp = qp->nsrp; rp; rp = rp->next){
802 if(rp->marker & mark)
805 arp = dnresolve(rp->host->name, Cin, type, qp->req, 0,
806 depth+1, Recurse, 1, 0);
807 rrfreelist(rrremneg(&arp));
813 /* use any addresses that we found */
814 for(trp = arp; trp && nd < Maxdest; trp = trp->next){
816 memset(p, 0, sizeof *p);
817 if(parseip(p->a, trp->ip->name) == -1)
821 * straddling servers can reject all nameservers if they are all
822 * inside, so be sure to list at least one outside ns at
823 * the end of the ns list in /lib/ndb for `dom='.
826 cfg.straddle && !insideaddr(qp->dp->name) && insidens(p->a))
831 for(rp = qp->nsrp; rp; rp = rp->next){
832 if(rp->host == p->s){
845 * cache negative responses
848 cacheneg(DN *dp, int type, int rcode, RR *soarr)
858 /* no cache time specified, don't make anything up */
860 if(soarr->next != nil)
861 rrfreelistptr(&soarr->next);
862 soaowner = soarr->owner;
866 /* the attach can cause soarr to be freed so mine it now */
867 if(soarr != nil && soarr->soa != nil)
868 ttl = soarr->soa->minttl;
872 /* add soa and negative RR to the database */
873 rrattach(soarr, Authoritative);
878 rp->negsoaowner = soaowner;
879 rp->negrcode = rcode;
881 rrattach(rp, Authoritative);
885 setdestoutns(Dest *p, int n)
887 memset(p, 0, sizeof *p);
888 if (outsidensip(n, p->a) < 0){
890 dnslog("[%d] no outside-ns in ndb", getpid());
893 p->s = dnlookup("outside-ns-ips", Cin, 1);
898 * issue query via UDP or TCP as appropriate.
899 * for TCP, returns with qp->tcpip set from udppkt header.
902 mydnsquery(Query *qp, int medium, uchar *udppkt, int len)
905 char conndir[40], addr[128];
914 nfd = dup(qp->udpfd, -1);
916 warning("mydnsquery: qp->udpfd %d: %r", qp->udpfd);
917 close(qp->udpfd); /* ensure it's closed */
918 qp->udpfd = -1; /* poison it */
924 dnslog("mydnsquery: qp->udpfd %d closed", qp->udpfd);
926 if (write(qp->udpfd, udppkt, len+Udphdrsize) !=
928 warning("sending udp msg: %r");
938 /* send via TCP & keep fd around for reply */
939 memmove(qp->tcpip, udppkt, sizeof qp->tcpip);
940 snprint(addr, sizeof addr, "%s/tcp!%I!dns",
941 (mntpt && *mntpt) ? mntpt : "/net", udppkt);
943 qp->tcpfd = dial(addr, nil, conndir, &qp->tcpctlfd);
946 dnslog("can't dial %s: %r", addr);
949 nci = getnetconninfo(conndir, qp->tcpfd);
951 parseip(qp->tcpip, nci->rsys);
952 freenetconninfo(nci);
954 dnslog("mydnsquery: getnetconninfo failed");
959 if (write(qp->tcpfd, belen, 2) != 2 ||
960 write(qp->tcpfd, udppkt + Udphdrsize, len) != len)
961 warning("sending tcp msg: %r");
970 * send query to all UDP destinations or one TCP destination,
971 * taken from obuf (udp packet) header
974 xmitquery(Query *qp, int medium, int depth, uchar *obuf, int inns, int len)
980 if(timems() >= qp->req->aborttime)
984 * if we send tcp query, we just take the dest ip address from
985 * the udp header placed there by tcpquery().
988 procsetname("tcp %sside query for %s %s", (inns? "in": "out"),
989 qp->dp->name, rrname(qp->type, buf, sizeof buf));
990 if(mydnsquery(qp, medium, obuf, len) < 0) /* sets qp->tcpip from obuf */
993 logsend(qp->req->id, depth, qp->tcpip, "", qp->dp->name,
999 * get a nameserver address if we need one.
1000 * we're to transmit to more destinations than we currently have,
1004 n = qp->curdest - p;
1005 if (qp->ndest > n) {
1006 /* populates qp->dest with v4 and v6 addresses. */
1007 n = serveraddrs(qp, n, depth, Ta);
1008 n = serveraddrs(qp, n, depth, Taaaa);
1009 if (n == 0 && cfg.straddle && cfg.inside) {
1010 /* get ips of "outside-ns-ips" */
1012 if (setdestoutns(&qp->dest[n], n) < 0)
1017 dnslog("xmitquery: %s: no outside-ns nameservers",
1020 qp->curdest = &qp->dest[n];
1023 for(n = 0; p < &qp->dest[qp->ndest] && p < qp->curdest; p++){
1024 /* skip destinations we've finished with */
1025 if(p->nx >= Maxtrans)
1027 /* exponential backoff of requests */
1028 if((1<<p->nx) > qp->ndest)
1031 if(ipcmp(p->a, IPnoaddr) == 0)
1032 continue; /* mistake */
1034 procsetname("udp %sside query to %I/%s %s %s",
1035 (inns? "in": "out"), p->a, p->s->name,
1036 qp->dp->name, rrname(qp->type, buf, sizeof buf));
1038 logsend(qp->req->id, depth, p->a, p->s->name,
1039 qp->dp->name, qp->type);
1041 /* fill in UDP destination addr & send it */
1042 memmove(obuf, p->a, sizeof p->a);
1043 if(mydnsquery(qp, medium, obuf, len) == 0)
1048 return n == 0 ? -1 : 0;
1051 /* is mp a cachable negative response (with Rname set)? */
1053 isnegrname(DNSmsg *mp)
1055 /* TODO: could add || cfg.justforw to RHS of && */
1056 return mp->an == nil && (mp->flags & Rmask) == Rname;
1060 filterhints(RR *rp, void *arg)
1064 if(rp->type != Ta && rp->type != Taaaa)
1067 for(nsrp = arg; nsrp; nsrp = nsrp->next)
1068 if(nsrp->type == Tns && rp->owner == nsrp->host)
1075 filterauth(RR *rp, void *arg)
1085 if(rp->type == Tsoa && rp->owner != nsrp->owner
1086 && !subsume(nsrp->owner->name, rp->owner->name)
1087 && strncmp(nsrp->owner->name, "local#", 6) != 0)
1093 if(rp->owner != nsrp->owner
1094 && !subsume(nsrp->owner->name, rp->owner->name)
1095 && strncmp(nsrp->owner->name, "local#", 6) != 0)
1098 return baddelegation(rp, nsrp, dest->a);
1102 reportandfree(RR *l, char *note, Dest *p)
1110 dnslog("ignoring %s from %I/%s: %R",
1111 note, p->a, p->s->name, rp);
1116 /* returns Answerr (-1) on errors, else number of answers, which can be zero. */
1118 procansw(Query *qp, DNSmsg *mp, int depth, Dest *p)
1129 /* ignore any error replies */
1130 switch(mp->flags & Rmask){
1139 /* ignore any bad delegations */
1140 if((tp = rrremfilter(&mp->ns, filterauth, p)) != 0)
1141 reportandfree(tp, "bad delegation", p);
1143 /* remove any soa's from the authority section */
1144 soarr = rrremtype(&mp->ns, Tsoa);
1146 /* only nameservers remaining */
1147 if((tp = rrremtype(&mp->ns, Tns)) != 0){
1148 reportandfree(mp->ns, "non-nameserver", p);
1152 /* remove answers not related to the question. */
1153 if((tp = rrremowner(&mp->an, qp->dp)) != 0){
1154 reportandfree(mp->an, "wrong subject answer", p);
1157 if(qp->type != Tall){
1158 if((tp = rrremtype(&mp->an, qp->type)) != 0){
1159 reportandfree(mp->an, "wrong type answer", p);
1164 /* incorporate answers */
1171 * only use cname answer when returned. some dns servers
1172 * attach (potential) spam hint address records which poisons
1175 if((tp = rrremtype(&mp->an, Tcname)) != 0){
1176 reportandfree(mp->an, "ip in cname answer", p);
1179 rrattach(mp->an, (mp->flags & Fauth) != 0);
1182 /* restrict hints to address rr's for nameservers only */
1183 if((tp = rrremfilter(&mp->ar, filterhints, mp->ns)) != 0){
1184 reportandfree(mp->ar, "hint", p);
1187 rrattach(mp->ar, Notauthoritative);
1189 if(mp->ns && !cfg.justforw){
1190 ndp = mp->ns->owner;
1191 rrattach(mp->ns, Notauthoritative);
1194 rrfreelistptr(&mp->ns);
1198 /* free the question */
1200 rrfreelistptr(&mp->qd);
1205 * Any reply from an authoritative server
1206 * that does not provide more nameservers,
1207 * or a positive reply terminates the search.
1208 * A negative response now also terminates the search.
1210 if(mp->an || (mp->flags & Fauth) && mp->ns == nil){
1212 qp->dp->respcode = Rname;
1214 qp->dp->respcode = Rok;
1217 * cache any negative responses, free soarr.
1218 * negative responses need not be authoritative:
1219 * they can legitimately come from a cache.
1221 if( /* (mp->flags & Fauth) && */ mp->an == nil)
1222 cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr);
1226 } else if (isnegrname(mp)) {
1227 qp->dp->respcode = Rname;
1229 * cache negative response.
1230 * negative responses need not be authoritative:
1231 * they can legitimately come from a cache.
1233 cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr);
1240 * if we've been given better name servers, recurse.
1241 * if we're a pure resolver, don't recurse, we have
1242 * to forward to a fixed set of named servers.
1244 if(mp->ns == nil || cfg.resolver && cfg.justforw)
1246 tp = rrlookup(ndp, Tns, NOneg);
1247 if(contains(qp->nsrp, tp)){
1251 procsetname("recursive query for %s %s", qp->dp->name,
1252 rrname(qp->type, buf, sizeof buf));
1254 queryinit(&nq, qp->dp, qp->type, qp->req);
1255 rv = netqueryns(&nq, depth+1, tp);
1262 * send a query via tcp to a single address (from ibuf's udp header)
1263 * and read the answer(s) into mp->an.
1266 tcpquery(Query *qp, DNSmsg *mp, int depth, uchar *ibuf, uchar *obuf, int len,
1267 ulong waitms, int inns, ushort req)
1272 endms = timems() + waitms;
1273 if(endms > qp->req->aborttime)
1274 endms = qp->req->aborttime;
1277 dnslog("%s: udp reply truncated; retrying query via tcp to %I",
1278 qp->dp->name, qp->tcpip);
1280 memmove(obuf, ibuf, IPaddrlen); /* send back to respondent */
1281 memset(mp, 0, sizeof *mp);
1282 if (xmitquery(qp, Tcp, depth, obuf, inns, len) < 0 ||
1283 readreply(qp, Tcp, req, ibuf, mp, endms) < 0)
1285 if (qp->tcpfd >= 0) {
1286 hangup(qp->tcpctlfd);
1287 close(qp->tcpctlfd);
1290 qp->tcpfd = qp->tcpctlfd = -1;
1296 * query name servers. fill in obuf with on-the-wire representation of a
1297 * DNSmsg derived from qp. if the name server returns a pointer to another
1298 * name server, recurse.
1301 queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, ulong waitms, int inns)
1303 int ndest, len, replywaits, rv, flag;
1307 uchar srcip[IPaddrlen];
1308 Dest *p, *np, dest[Maxdest];
1312 /* request recursion only for local dns servers */
1314 if(strncmp(qp->nsrp->owner->name, "local#", 6) == 0)
1317 /* pack request into a udp message */
1318 len = mkreq(qp->dp, qp->type, obuf, flag, req);
1320 /* no server addresses yet */
1321 memset(dest, 0, sizeof dest);
1322 qp->curdest = qp->dest = dest;
1325 * transmit udp requests and wait for answers.
1326 * at most Maxtrans attempts to each address.
1327 * each cycle send one more message than the previous.
1328 * retry a query via tcp if its response is truncated.
1330 for(ndest = 2; ndest < Maxdest; ndest += 2){
1333 if (xmitquery(qp, Udp, depth, obuf, inns, len) < 0)
1336 endms = timems() + waitms;
1337 if(endms > qp->req->aborttime)
1338 endms = qp->req->aborttime;
1340 for(replywaits = 0; replywaits < ndest; replywaits++){
1343 procsetname("reading %sside reply from %I: %s %s from %s",
1344 (inns? "in": "out"), obuf, qp->dp->name,
1345 rrname(qp->type, buf, sizeof buf), qp->req->from);
1347 /* read udp answer into m */
1348 if (readreply(qp, Udp, req, ibuf, &m, endms) >= 0)
1349 memmove(srcip, ibuf, IPaddrlen);
1350 else if (!(m.flags & Ftrunc)) {
1352 break; /* timed out on this dest */
1354 /* whoops, it was truncated! ask again via tcp */
1356 rv = tcpquery(qp, &m, depth, ibuf, obuf, len,
1357 waitms, inns, req); /* answer in m */
1360 break; /* failed via tcp too */
1362 memmove(srcip, qp->tcpip, IPaddrlen);
1365 /* find responder */
1367 dnslog("queryns got reply from %I", srcip);
1368 for(p = qp->dest; p < qp->curdest; p++)
1369 if(ipcmp(p->a, srcip) == 0)
1371 if(p >= qp->curdest){
1372 dnslog("response from %I but no destination", srcip);
1376 /* remove all addrs of responding server from list */
1377 for(np = qp->dest; np < qp->curdest; np++)
1381 /* free or incorporate RRs in m */
1382 rv = procansw(qp, &m, depth, p);
1383 if (rv > Answnone) {
1384 qp->dest = qp->curdest = nil; /* prevent accidents */
1390 /* if all servers returned failure, propagate it */
1391 qp->dp->respcode = Rserver;
1392 for(p = dest; p < qp->curdest; p++)
1393 if(p->code != Rserver)
1394 qp->dp->respcode = Rok;
1396 // if (qp->dp->respcode)
1397 // dnslog("queryns setting Rserver for %s", qp->dp->name);
1399 qp->dest = qp->curdest = nil; /* prevent accidents */
1404 * in principle we could use a single descriptor for a udp port
1405 * to send all queries and receive all the answers to them,
1406 * but we'd have to sort out the answers by dns-query id.
1409 udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
1414 /* use alloced buffers rather than ones from the stack */
1415 ibuf = emalloc(64*1024); /* max. tcp reply size */
1416 obuf = emalloc(Maxudp+Udphdrsize);
1418 fd = udpport(mntpt);
1420 dnslog("can't get udpport for %s query of name %s: %r",
1421 mntpt, qp->dp->name);
1426 rv = queryns(qp, depth, ibuf, obuf, 500UL<<(patient != 0), inns);
1437 * look up (qp->dp->name, qp->type) rr in dns,
1438 * using nameservers in qp->nsrp.
1441 netquery(Query *qp, int depth)
1443 int rv, triedin, inname;
1446 rv = Answnone; /* pessimism */
1447 if(depth > 12) /* in a recursive loop? */
1453 * slave might have forked. if so, the parent process longjmped to
1454 * req->mret; we're usually the child slave, but if there are too
1455 * many children already, we're still the same process. under no
1456 * circumstances block the 9p loop.
1458 if(!qp->req->isslave && strcmp(qp->req->from, "9p") == 0)
1461 procsetname("netquery: %s", qp->dp->name);
1463 /* prepare server RR's for incremental lookup */
1464 for(rp = qp->nsrp; rp; rp = rp->next)
1470 * normal resolvers and servers will just use mntpt for all addresses,
1471 * even on the outside. straddling servers will use mntpt (/net)
1472 * for inside addresses and /net.alt for outside addresses,
1473 * thus bypassing other inside nameservers.
1475 inname = insideaddr(qp->dp->name);
1476 if (!cfg.straddle || inname) {
1477 rv = udpquery(qp, mntpt, depth, Hurry, (cfg.inside? Inns: Outns));
1482 * if we're still looking, are inside, and have an outside domain,
1483 * try it on our outside interface, if any.
1485 if (rv == Answnone && cfg.inside && !inname) {
1488 "[%d] netquery: internal nameservers failed for %s; trying external",
1489 getpid(), qp->dp->name);
1491 /* prepare server RR's for incremental lookup */
1492 for(rp = qp->nsrp; rp; rp = rp->next)
1495 rv = udpquery(qp, "/net.alt", depth, Patient, Outns);
1510 memset(&req, 0, sizeof req);
1512 req.aborttime = timems() + Maxreqtm;
1513 req.from = "internal";
1514 queryinit(&q, dnlookup(root, Cin, 1), Tns, &req);
1515 nsrp = randomize(dblookup(root, Cin, Tns, 0, 0));
1516 for (rr = nsrp; rr != nil; rr = rr->next)
1517 dnslog("seerootns query nsrp: %R", rr);
1518 rv = netqueryns(&q, 0, nsrp); /* lookup ". ns" using nsrp */