2 * domain name resolvers, see rfcs 1035 and 1123
11 typedef struct Dest Dest;
12 typedef struct Query Query;
21 Maxdest= 24, /* maximum destinations for a request message */
22 Maxoutstanding= 15, /* max. outstanding queries per domain name */
23 Remntretry= 15, /* min. sec.s between /net.alt remount tries */
26 * these are the old values; we're trying longer timeouts now
27 * primarily for the benefit of remote nameservers querying us
28 * during times of bad connectivity.
30 // Maxtrans= 3, /* maximum transmissions to a server */
31 // Maxretries= 3, /* cname+actual resends: was 32; have pity on user */
32 // Maxwaitms= 1000, /* wait no longer for a remote dns query */
33 // Minwaitms= 100, /* willing to wait for a remote dns query */
35 Maxtrans= 5, /* maximum transmissions to a server */
36 Maxretries= 5, /* cname+actual resends: was 32; have pity on user */
37 Maxwaitms= 5000, /* wait no longer for a remote dns query */
38 Minwaitms= 500, /* willing to wait for a remote dns query */
40 enum { Hurry, Patient, };
41 enum { Outns, Inns, };
45 uchar a[IPaddrlen]; /* ip address */
46 DN *s; /* name server */
47 int nx; /* number of transmissions */
48 int code; /* response code; used to clear dp->respcode */
53 ushort type; /* and type to look up */
55 RR *nsrp; /* name servers to consult */
57 /* dest must not be on the stack due to forking in slave() */
58 Dest *dest; /* array of destinations */
59 Dest *curdest; /* pointer to next to fill */
60 int ndest; /* transmit to this many on this round */
65 int tcpfd; /* if Tcp, read replies from here */
67 uchar tcpip[IPaddrlen];
70 /* estimated % probability of such a record existing at all */
85 static RR* dnresolve1(char*, int, int, Request*, int, int);
86 static int netquery(Query *, int);
89 * reading /proc/pid/args yields either "name args" or "name [display args]",
90 * so return only display args, if any.
99 snprint(buf, sizeof buf, "#p/%d/args", getpid());
100 if((fd = open(buf, OREAD)) < 0)
103 n = read(fd, buf, sizeof buf-1);
107 if ((lp = strchr(buf, '[')) == nil ||
108 (rp = strrchr(buf, ']')) == nil)
115 rrfreelistptr(RR **rpp)
119 if (rpp == nil || *rpp == nil)
122 *rpp = nil; /* update pointer in memory before freeing list */
127 * lookup 'type' info for domain name 'name'. If it doesn't exist, try
128 * looking it up as a canonical name.
130 * this process can be quite slow if time-outs are set too high when querying
131 * nameservers that just don't respond to certain query types. in that case,
132 * there will be multiple udp retries, multiple nameservers will be queried,
133 * and this will be repeated for a cname query. the whole thing will be
134 * retried several times until we get an answer or a time-out.
137 dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth,
138 int recurse, int rooted, int *status)
149 if(depth > 12) /* in a recursive loop? */
152 procname = procgetname();
154 * hack for systems that don't have resolve search
155 * lists. Just look up the simple name in the database.
157 if(!rooted && strchr(name, '.') == nil){
159 drp = domainlist(class);
160 for(nrp = drp; rp == nil && nrp != nil; nrp = nrp->next){
161 snprint(nname, sizeof nname, "%s.%s", name,
163 rp = dnresolve(nname, class, type, req, cn, depth+1,
164 recurse, rooted, status);
165 rrfreelist(rrremneg(&rp));
169 procsetname(procname);
175 * try the name directly
177 rp = dnresolve1(name, class, type, req, depth, recurse);
178 if(rp == nil && (dp = dnlookup(name, class, 0)) != nil) {
180 * try it as a canonical name if we weren't told
181 * that the name didn't exist
183 if(type != Tptr && dp->respcode != Rname)
184 for(loops = 0; rp == nil && loops < Maxretries; loops++){
185 /* retry cname, then the actual type */
186 rp = dnresolve1(name, class, Tcname, req,
191 /* rp->host == nil shouldn't happen, but does */
192 if(rp->negative || rp->host == nil){
198 name = rp->host->name;
204 rp = dnresolve1(name, class, type, req,
208 /* distinction between not found and not good */
209 if(rp == nil && status != nil && dp->respcode != Rok)
210 *status = dp->respcode;
212 procsetname(procname);
214 return randomize(rp);
218 queryinit(Query *qp, DN *dp, int type, Request *req)
220 assert(dp && dp->magic == DNmagic);
222 memset(qp, 0, sizeof *qp);
223 qp->udpfd = qp->tcpfd = qp->tcpctlfd = -1;
226 if (qp->type != type)
227 dnslog("queryinit: bogus type %d", type);
230 qp->dest = qp->curdest = nil;
234 querydestroy(Query *qp)
236 /* leave udpfd open */
239 if (qp->tcpctlfd >= 0) {
240 hangup(qp->tcpctlfd);
243 memset(qp, 0, sizeof *qp); /* prevent accidents */
244 qp->udpfd = qp->tcpfd = qp->tcpctlfd = -1;
248 * if the response to a query hasn't arrived within 100 ms.,
249 * it's unlikely to arrive at all. after 1 s., it's really unlikely.
250 * queries for missing RRs are likely to produce time-outs rather than
251 * negative responses, so cname and aaaa queries are likely to time out,
252 * thus we don't wait very long for them.
255 notestats(vlong start, int tmout, int type)
262 else if (type == Tcname)
265 long wait10ths = NS2MS(nsec() - start) / 100;
268 stats.under10ths[0]++;
269 else if (wait10ths >= nelem(stats.under10ths))
270 stats.under10ths[nelem(stats.under10ths) - 1]++;
272 stats.under10ths[wait10ths]++;
285 /* netquery with given name servers, free ns rrs when done */
287 netqueryns(Query *qp, int depth, RR *nsrp)
292 rv = netquery(qp, depth);
293 qp->nsrp = nil; /* prevent accidents */
299 issuequery(Query *qp, char *name, int class, int depth, int recurse)
303 RR *rp, *nsrp, *dbnsrp;
306 * if we're running as just a resolver, query our
307 * designated name servers
310 nsrp = randomize(getdnsservers(class));
312 if(netqueryns(qp, depth+1, nsrp) > Answnone)
313 return rrlookup(qp->dp, qp->type, OKneg);
317 * walk up the domain name looking for
318 * a name server for the domain.
320 for(cp = name; cp; cp = walkup(cp)){
322 * if this is a local (served by us) domain,
325 dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0));
326 if(dbnsrp && dbnsrp->local){
327 rp = dblookup(name, class, qp->type, 1, dbnsrp->ttl);
333 * if recursion isn't set, just accept local
336 if(recurse == Dontrecurse){
342 /* look for ns in cache */
343 nsdp = dnlookup(cp, class, 0);
346 nsrp = randomize(rrlookup(nsdp, Tns, NOneg));
348 /* if the entry timed out, ignore it */
349 if(nsrp && nsrp->ttl < now)
350 rrfreelistptr(&nsrp);
353 rrfreelistptr(&dbnsrp);
355 /* query the name servers found in cache */
356 if(netqueryns(qp, depth+1, nsrp) > Answnone)
357 return rrlookup(qp->dp, qp->type, OKneg);
359 /* try the name servers found in db */
360 if(netqueryns(qp, depth+1, dbnsrp) > Answnone)
361 return rrlookup(qp->dp, qp->type, NOneg);
367 dnresolve1(char *name, int class, int type, Request *req, int depth,
376 dnslog("[%d] dnresolve1 %s %d %d", getpid(), name, type, class);
378 /* only class Cin implemented so far */
382 dp = dnlookup(name, class, 1);
385 * Try the cache first
387 rp = rrlookup(dp, type, OKneg);
390 /* unauthoritative db entries are hints */
394 dnslog("[%d] dnresolve1 %s %d %d: auth rr in db",
395 getpid(), name, type, class);
399 /* cached entry must still be valid */
401 /* but Tall entries are special */
402 if(type != Tall || rp->query == Tall) {
405 dnslog("[%d] dnresolve1 %s %d %d: rr not in db",
406 getpid(), name, type, class);
410 rp = nil; /* accident prevention */
414 * try the cache for a canonical name. if found punt
415 * since we'll find it during the canonical name search
419 rp = rrlookup(dp, Tcname, NOneg);
423 dnslog("[%d] dnresolve1 %s %d %d: rr from rrlookup for non-cname",
424 getpid(), name, type, class);
430 * if the domain name is within an area of ours,
431 * we should have found its data in memory by now.
433 area = inmyarea(dp->name);
434 if (area || strncmp(dp->name, "local#", 6) == 0)
437 queryinit(&q, dp, type, req);
438 rp = issuequery(&q, name, class, depth, recurse);
443 dnslog("[%d] dnresolve1 %s %d %d: rr from query",
444 getpid(), name, type, class);
448 /* settle for a non-authoritative answer */
449 rp = rrlookup(dp, type, OKneg);
452 dnslog("[%d] dnresolve1 %s %d %d: rr from rrlookup",
453 getpid(), name, type, class);
457 /* noone answered. try the database, we might have a chance. */
458 rp = dblookup(name, class, type, 0, 0);
461 dnslog("[%d] dnresolve1 %s %d %d: rr from dblookup",
462 getpid(), name, type, class);
465 dnslog("[%d] dnresolve1 %s %d %d: no rr from dblookup; crapped out",
466 getpid(), name, type, class);
472 * walk a domain name one element to the right.
473 * return a pointer to that element.
474 * in other words, return a pointer to the parent domain name.
481 cp = strchr(name, '.');
491 * Get a udp port for sending requests and reading replies. Put the port
492 * into "headers" mode.
494 static char *hmsg = "headers";
500 char ds[64], adir[64];
503 snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt && *mtpt) ? mtpt : "/net");
504 ctl = announce(ds, adir);
506 /* warning("can't get udp port"); */
510 /* turn on header style interface */
511 if(write(ctl, hmsg, strlen(hmsg)) != strlen(hmsg)){
517 /* grab the data file */
518 snprint(ds, sizeof ds, "%s/data", adir);
519 fd = open(ds, ORDWR);
522 warning("can't open udp port %s: %r", ds);
527 initdnsmsg(DNSmsg *mp, RR *rp, int flags, ushort reqno)
529 memset(mp, 0, sizeof *mp);
537 /* generate a DNS UDP query packet */
539 mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno)
543 Udphdr *uh = (Udphdr*)buf;
546 /* stuff port number into output buffer */
547 memset(uh, 0, sizeof *uh);
548 hnputs(uh->rport, 53);
550 /* make request and convert it to output format */
553 initdnsmsg(&m, rp, flags, reqno);
554 len = convDNS2M(&m, &buf[Udphdrsize], Maxudp);
560 freeanswers(DNSmsg *mp)
562 rrfreelistptr(&mp->qd);
563 rrfreelistptr(&mp->an);
564 rrfreelistptr(&mp->ns);
565 rrfreelistptr(&mp->ar);
566 mp->qdcount = mp->ancount = mp->nscount = mp->arcount = 0;
569 /* timed read of reply. sets srcip. ibuf must be 64K to handle tcp answers. */
571 readnet(Query *qp, int medium, uchar *ibuf, uvlong endms, uchar **replyp,
576 vlong startns = nsec();
580 len = -1; /* pessimism */
582 memset(srcip, 0, IPaddrlen);
583 ms = endms - NS2MS(startns);
585 return -1; /* taking too long */
591 dnslog("readnet: qp->udpfd closed");
593 len = read(qp->udpfd, ibuf, Udphdrsize+Maxudpin);
595 notestats(startns, len < 0, qp->type);
596 if (len >= IPaddrlen)
597 memmove(srcip, ibuf, IPaddrlen);
598 if (len >= Udphdrsize) {
605 dnslog("readnet: tcp params not set");
608 dnslog("readnet: %s: tcp fd unset for dest %I",
609 qp->dp->name, qp->tcpip);
610 else if (readn(fd, lenbuf, 2) != 2) {
611 dnslog("readnet: short read of 2-byte tcp msg size from %I",
613 /* probably a time-out */
614 notestats(startns, 1, qp->type);
616 len = lenbuf[0]<<8 | lenbuf[1];
617 if (readn(fd, ibuf, len) != len) {
618 dnslog("readnet: short read of tcp data from %I",
620 /* probably a time-out */
621 notestats(startns, 1, qp->type);
625 memmove(srcip, qp->tcpip, IPaddrlen);
633 * read replies to a request and remember the rrs in the answer(s).
634 * ignore any of the wrong type.
635 * wait at most until endms.
638 readreply(Query *qp, int medium, ushort req, uchar *ibuf, DNSmsg *mp,
645 uchar srcip[IPaddrlen];
648 for (; timems() < endms &&
649 (len = readnet(qp, medium, ibuf, endms, &reply, srcip)) >= 0;
651 /* convert into internal format */
652 memset(mp, 0, sizeof *mp);
653 err = convM2DNS(reply, len, mp, nil);
654 if (mp->flags & Ftrunc) {
657 /* notify our caller to retry the query via tcp. */
660 dnslog("readreply: %s: input err, len %d: %s: %I",
661 qp->dp->name, len, err, srcip);
666 logreply(qp->req->id, srcip, mp);
668 /* answering the right question? */
670 dnslog("%d: id %d instead of %d: %I", qp->req->id,
673 dnslog("%d: no question RR: %I", qp->req->id, srcip);
674 else if(mp->qd->owner != qp->dp)
675 dnslog("%d: owner %s instead of %s: %I", qp->req->id,
676 mp->qd->owner->name, qp->dp->name, srcip);
677 else if(mp->qd->type != qp->type)
678 dnslog("%d: qp->type %d instead of %d: %I",
679 qp->req->id, mp->qd->type, qp->type, srcip);
681 /* remember what request this is in answer to */
682 for(rp = mp->an; rp; rp = rp->next)
683 rp->query = qp->type;
687 if (timems() >= endms) {
688 ; /* query expired */
690 /* this happens routinely when a read times out */
691 dnslog("readreply: %s type %s: ns %I read error or eof "
692 "(returned %d): %r", qp->dp->name, rrname(qp->type,
693 tbuf, sizeof tbuf), srcip, len);
695 for (rp = qp->nsrp; rp != nil; rp = rp->next)
697 dnslog("readreply: %s: query sent to "
698 "ns %s", qp->dp->name,
701 memset(mp, 0, sizeof *mp);
706 * return non-0 if first list includes second list
709 contains(RR *rp1, RR *rp2)
713 for(trp2 = rp2; trp2; trp2 = trp2->next){
714 for(trp1 = rp1; trp1; trp1 = trp1->next)
715 if(trp1->type == trp2->type)
716 if(trp1->host == trp2->host)
717 if(trp1->owner == trp2->owner)
727 * return multicast version if any
733 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 ||
734 ipcmp(ip, IPv4bcast) == 0)
743 * Get next server address(es) into qp->dest[nd] and beyond
746 serveraddrs(Query *qp, int nd, int depth)
751 if(nd >= Maxdest) /* dest array is full? */
755 * look for a server whose address we already know.
756 * if we find one, mark it so we ignore this on
760 for(rp = qp->nsrp; rp; rp = rp->next){
761 assert(rp->magic == RRmagic);
764 arp = rrlookup(rp->host, Ta, NOneg);
766 arp = rrlookup(rp->host, Taaaa, NOneg);
771 arp = dblookup(rp->host->name, Cin, Ta, 0, 0);
773 arp = dblookup(rp->host->name, Cin, Taaaa, 0, 0);
781 * if the cache and database lookup didn't find any new
782 * server addresses, try resolving one via the network.
783 * Mark any we try to resolve so we don't try a second time.
786 for(rp = qp->nsrp; rp; rp = rp->next){
792 * avoid loops looking up a server under itself
794 if(subsume(rp->owner->name, rp->host->name))
797 arp = dnresolve(rp->host->name, Cin, Ta, qp->req, 0,
798 depth+1, Recurse, 1, 0);
800 arp = dnresolve(rp->host->name, Cin, Taaaa,
801 qp->req, 0, depth+1, Recurse, 1, 0);
802 rrfreelist(rrremneg(&arp));
807 /* use any addresses that we found */
808 for(trp = arp; trp && nd < Maxdest; trp = trp->next){
810 memset(p, 0, sizeof *p);
811 parseip(p->a, trp->ip->name);
813 * straddling servers can reject all nameservers if they are all
814 * inside, so be sure to list at least one outside ns at
815 * the end of the ns list in /lib/ndb for `dom='.
818 cfg.straddle && !insideaddr(qp->dp->name) && insidens(p->a))
830 * cache negative responses
833 cacheneg(DN *dp, int type, int rcode, RR *soarr)
843 /* no cache time specified, don't make anything up */
845 if(soarr->next != nil)
846 rrfreelistptr(&soarr->next);
847 soaowner = soarr->owner;
851 /* the attach can cause soarr to be freed so mine it now */
852 if(soarr != nil && soarr->soa != nil)
853 ttl = soarr->soa->minttl+now;
857 /* add soa and negative RR to the database */
858 rrattach(soarr, Authoritative);
863 rp->negsoaowner = soaowner;
864 rp->negrcode = rcode;
866 rrattach(rp, Authoritative);
870 setdestoutns(Dest *p, int n)
872 memset(p, 0, sizeof *p);
873 if (outsidensip(n, p->a) < 0){
875 dnslog("[%d] no outside-ns in ndb", getpid());
878 p->s = dnlookup("outside-ns-ips", Cin, 1);
883 * issue query via UDP or TCP as appropriate.
884 * for TCP, returns with qp->tcpip set from udppkt header.
887 mydnsquery(Query *qp, int medium, uchar *udppkt, int len)
890 char conndir[40], addr[128], domain[64];
895 snprint(domain, sizeof(domain), "%I", udppkt);
896 if (myaddr(domain)) {
897 dnslog("mydnsquery: trying to send to myself (%s); bzzzt",
903 nfd = dup(qp->udpfd, -1);
905 warning("mydnsquery: qp->udpfd %d: %r", qp->udpfd);
906 close(qp->udpfd); /* ensure it's closed */
907 qp->udpfd = -1; /* poison it */
913 dnslog("mydnsquery: qp->udpfd %d closed", qp->udpfd);
915 if (write(qp->udpfd, udppkt, len+Udphdrsize) !=
917 warning("sending udp msg: %r");
927 /* send via TCP & keep fd around for reply */
928 memmove(qp->tcpip, udppkt, sizeof qp->tcpip);
929 snprint(addr, sizeof addr, "%s/tcp!%s!dns",
930 (mntpt && *mntpt) ? mntpt : "/net",
933 qp->tcpfd = dial(addr, nil, conndir, &qp->tcpctlfd);
936 dnslog("can't dial %s: %r", addr);
939 nci = getnetconninfo(conndir, qp->tcpfd);
941 parseip(qp->tcpip, nci->rsys);
942 freenetconninfo(nci);
944 dnslog("mydnsquery: getnetconninfo failed");
949 if (write(qp->tcpfd, belen, 2) != 2 ||
950 write(qp->tcpfd, udppkt + Udphdrsize, len) != len)
951 warning("sending tcp msg: %r");
960 * send query to all UDP destinations or one TCP destination,
961 * taken from obuf (udp packet) header
964 xmitquery(Query *qp, int medium, int depth, uchar *obuf, int inns, int len)
970 if(timems() >= qp->req->aborttime)
974 * if we send tcp query, we just take the dest ip address from
975 * the udp header placed there by tcpquery().
978 procsetname("tcp %sside query for %s %s", (inns? "in": "out"),
979 qp->dp->name, rrname(qp->type, buf, sizeof buf));
980 if(mydnsquery(qp, medium, obuf, len) < 0) /* sets qp->tcpip from obuf */
983 logsend(qp->req->id, depth, qp->tcpip, "", qp->dp->name,
989 * get a nameserver address if we need one.
990 * we're to transmit to more destinations than we currently have,
996 n = serveraddrs(qp, n, depth); /* populates qp->dest. */
997 assert(n >= 0 && n <= Maxdest);
998 if (n == 0 && cfg.straddle && cfg.inside) {
999 /* get ips of "outside-ns-ips" */
1001 if (setdestoutns(&qp->dest[n], n) < 0)
1006 dnslog("xmitquery: %s: no outside-ns nameservers",
1009 qp->curdest = &qp->dest[n];
1012 for(n = 0; p < &qp->dest[qp->ndest] && p < qp->curdest; p++){
1013 /* skip destinations we've finished with */
1014 if(p->nx >= Maxtrans)
1016 /* exponential backoff of requests */
1017 if((1<<p->nx) > qp->ndest)
1020 if(memcmp(p->a, IPnoaddr, sizeof IPnoaddr) == 0)
1021 continue; /* mistake */
1023 procsetname("udp %sside query to %I/%s %s %s",
1024 (inns? "in": "out"), p->a, p->s->name,
1025 qp->dp->name, rrname(qp->type, buf, sizeof buf));
1027 logsend(qp->req->id, depth, p->a, p->s->name,
1028 qp->dp->name, qp->type);
1030 /* fill in UDP destination addr & send it */
1031 memmove(obuf, p->a, sizeof p->a);
1032 if(mydnsquery(qp, medium, obuf, len) == 0)
1037 return n == 0 ? -1 : 0;
1040 /* is mp a cachable negative response (with Rname set)? */
1042 isnegrname(DNSmsg *mp)
1044 /* TODO: could add || cfg.justforw to RHS of && */
1045 return mp->an == nil && (mp->flags & Rmask) == Rname;
1048 /* returns Answerr (-1) on errors, else number of answers, which can be zero. */
1050 procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p)
1061 /* ignore any error replies */
1062 if((mp->flags & Rmask) == Rserver){
1070 /* ignore any bad delegations */
1071 if(mp->ns && baddelegation(mp->ns, qp->nsrp, srcip)){
1072 stats.negbaddeleg++;
1078 dnslog(" and no answers");
1081 dnslog(" but has answers; ignoring ns");
1082 rrfreelistptr(&mp->ns);
1086 /* remove any soa's from the authority section */
1087 soarr = rrremtype(&mp->ns, Tsoa);
1089 /* incorporate answers */
1095 rrattach(mp->an, (mp->flags & Fauth) != 0);
1097 rrattach(mp->ar, Notauthoritative);
1098 if(mp->ns && !cfg.justforw){
1099 ndp = mp->ns->owner;
1100 rrattach(mp->ns, Notauthoritative);
1103 rrfreelistptr(&mp->ns);
1107 /* free the question */
1109 rrfreelistptr(&mp->qd);
1114 * Any reply from an authoritative server,
1115 * or a positive reply terminates the search.
1116 * A negative response now also terminates the search.
1118 if(mp->an != nil || (mp->flags & Fauth)){
1120 qp->dp->respcode = Rname;
1122 qp->dp->respcode = Rok;
1125 * cache any negative responses, free soarr.
1126 * negative responses need not be authoritative:
1127 * they can legitimately come from a cache.
1129 if( /* (mp->flags & Fauth) && */ mp->an == nil)
1130 cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr);
1134 } else if (isnegrname(mp)) {
1135 qp->dp->respcode = Rname;
1137 * cache negative response.
1138 * negative responses need not be authoritative:
1139 * they can legitimately come from a cache.
1141 cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr);
1148 * if we've been given better name servers, recurse.
1149 * if we're a pure resolver, don't recurse, we have
1150 * to forward to a fixed set of named servers.
1152 if(!mp->ns || cfg.resolver && cfg.justforw)
1154 tp = rrlookup(ndp, Tns, NOneg);
1155 if(contains(qp->nsrp, tp)){
1159 procsetname("recursive query for %s %s", qp->dp->name,
1160 rrname(qp->type, buf, sizeof buf));
1162 queryinit(&nq, qp->dp, qp->type, qp->req);
1163 rv = netqueryns(&nq, depth+1, tp);
1170 * send a query via tcp to a single address (from ibuf's udp header)
1171 * and read the answer(s) into mp->an.
1174 tcpquery(Query *qp, DNSmsg *mp, int depth, uchar *ibuf, uchar *obuf, int len,
1175 ulong waitms, int inns, ushort req)
1180 endms = timems() + waitms;
1181 if(endms > qp->req->aborttime)
1182 endms = qp->req->aborttime;
1185 dnslog("%s: udp reply truncated; retrying query via tcp to %I",
1186 qp->dp->name, qp->tcpip);
1188 memmove(obuf, ibuf, IPaddrlen); /* send back to respondent */
1189 memset(mp, 0, sizeof *mp);
1190 if (xmitquery(qp, Tcp, depth, obuf, inns, len) < 0 ||
1191 readreply(qp, Tcp, req, ibuf, mp, endms) < 0)
1193 if (qp->tcpfd >= 0) {
1194 hangup(qp->tcpctlfd);
1195 close(qp->tcpctlfd);
1198 qp->tcpfd = qp->tcpctlfd = -1;
1204 * query name servers. fill in obuf with on-the-wire representation of a
1205 * DNSmsg derived from qp. if the name server returns a pointer to another
1206 * name server, recurse.
1209 queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, ulong waitms, int inns)
1211 int ndest, len, replywaits, rv;
1215 uchar srcip[IPaddrlen];
1216 Dest *p, *np, dest[Maxdest];
1218 /* pack request into a udp message */
1220 len = mkreq(qp->dp, qp->type, obuf, Frecurse|Oquery, req);
1222 /* no server addresses yet */
1223 memset(dest, 0, sizeof dest);
1224 qp->curdest = qp->dest = dest;
1227 * transmit udp requests and wait for answers.
1228 * at most Maxtrans attempts to each address.
1229 * each cycle send one more message than the previous.
1230 * retry a query via tcp if its response is truncated.
1232 for(ndest = 1; ndest < Maxdest; ndest++){
1235 if (xmitquery(qp, Udp, depth, obuf, inns, len) < 0)
1238 endms = timems() + waitms;
1239 if(endms > qp->req->aborttime)
1240 endms = qp->req->aborttime;
1242 for(replywaits = 0; replywaits < ndest; replywaits++){
1245 procsetname("reading %sside reply from %I: %s %s from %s",
1246 (inns? "in": "out"), obuf, qp->dp->name,
1247 rrname(qp->type, buf, sizeof buf), qp->req->from);
1249 /* read udp answer into m */
1250 if (readreply(qp, Udp, req, ibuf, &m, endms) >= 0)
1251 memmove(srcip, ibuf, IPaddrlen);
1252 else if (!(m.flags & Ftrunc)) {
1254 break; /* timed out on this dest */
1256 /* whoops, it was truncated! ask again via tcp */
1258 rv = tcpquery(qp, &m, depth, ibuf, obuf, len,
1259 waitms, inns, req); /* answer in m */
1262 break; /* failed via tcp too */
1264 memmove(srcip, qp->tcpip, IPaddrlen);
1267 /* find responder */
1268 // dnslog("queryns got reply from %I", srcip);
1269 for(p = qp->dest; p < qp->curdest; p++)
1270 if(memcmp(p->a, srcip, sizeof p->a) == 0)
1273 if(p != qp->curdest) {
1274 /* remove all addrs of responding server from list */
1275 for(np = qp->dest; np < qp->curdest; np++)
1281 /* free or incorporate RRs in m */
1282 rv = procansw(qp, &m, srcip, depth, p);
1283 if (rv > Answnone) {
1284 qp->dest = qp->curdest = nil; /* prevent accidents */
1290 /* if all servers returned failure, propagate it */
1291 qp->dp->respcode = Rserver;
1292 for(p = dest; p < qp->curdest; p++)
1293 if(p->code != Rserver)
1294 qp->dp->respcode = Rok;
1296 // if (qp->dp->respcode)
1297 // dnslog("queryns setting Rserver for %s", qp->dp->name);
1299 qp->dest = qp->curdest = nil; /* prevent accidents */
1304 * run a command with a supplied fd as standard input
1307 system(int fd, char *cmd)
1312 if((pid = fork()) == -1)
1313 sysfatal("fork failed: %r");
1317 for (i = 3; i < 200; i++)
1318 close(i); /* don't leak fds */
1319 execl("/bin/rc", "rc", "-c", cmd, nil);
1320 sysfatal("exec rc: %r");
1322 for(p = waitpid(); p >= 0; p = waitpid())
1325 return "lost child";
1328 /* compute wait, weighted by probability of success, with bounds */
1330 weight(ulong ms, unsigned pcntprob)
1334 wait = (ms * pcntprob) / 100;
1335 if (wait < Minwaitms)
1337 if (wait > Maxwaitms)
1343 * in principle we could use a single descriptor for a udp port
1344 * to send all queries and receive all the answers to them,
1345 * but we'd have to sort out the answers by dns-query id.
1348 udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
1356 static QLock mntlck;
1357 static ulong lastmount;
1361 /* use alloced buffers rather than ones from the stack */
1362 ibuf = emalloc(64*1024); /* max. tcp reply size */
1363 obuf = emalloc(Maxudp+Udphdrsize);
1365 fd = udpport(mntpt);
1366 while (fd < 0 && cfg.straddle && strcmp(mntpt, "/net.alt") == 0) {
1367 /* HACK: remount /net.alt */
1369 if (now < lastmount + Remntretry)
1370 sleep(S2MS(lastmount + Remntretry - now));
1372 fd = udpport(mntpt); /* try again under lock */
1374 dnslog("[%d] remounting /net.alt", getpid());
1375 unmount(nil, "/net.alt");
1377 msg = system(open("/dev/null", ORDWR), "outside");
1379 lastmount = time(nil);
1381 dnslog("[%d] can't remount /net.alt: %s",
1383 sleep(10*1000); /* don't spin remounting */
1385 fd = udpport(mntpt);
1390 dnslog("can't get udpport for %s query of name %s: %r",
1391 mntpt, qp->dp->name);
1396 * Our QIP servers are busted and respond to AAAA and CNAME queries
1397 * with (sometimes malformed [too short] packets and) no answers and
1398 * just NS RRs but not Rname errors. so make time-to-wait
1399 * proportional to estimated probability of an RR of that type existing.
1401 if (qp->type >= nelem(likely))
1402 pcntprob = 35; /* unpopular query type */
1404 pcntprob = likely[qp->type];
1405 reqtm = (patient? 2 * Maxreqtm: Maxreqtm);
1406 wait = weight(reqtm / 3, pcntprob); /* time for one udp query */
1409 rv = queryns(qp, depth, ibuf, obuf, wait, inns);
1420 * look up (qp->dp->name, qp->type) rr in dns,
1421 * using nameservers in qp->nsrp.
1424 netquery(Query *qp, int depth)
1426 int rv, triedin, inname;
1429 rv = Answnone; /* pessimism */
1430 if(depth > 12) /* in a recursive loop? */
1436 * slave might have forked. if so, the parent process longjmped to
1437 * req->mret; we're usually the child slave, but if there are too
1438 * many children already, we're still the same process. under no
1439 * circumstances block the 9p loop.
1441 if(!qp->req->isslave && strcmp(qp->req->from, "9p") == 0)
1444 procsetname("netquery: %s", qp->dp->name);
1446 /* prepare server RR's for incremental lookup */
1447 for(rp = qp->nsrp; rp; rp = rp->next)
1453 * normal resolvers and servers will just use mntpt for all addresses,
1454 * even on the outside. straddling servers will use mntpt (/net)
1455 * for inside addresses and /net.alt for outside addresses,
1456 * thus bypassing other inside nameservers.
1458 inname = insideaddr(qp->dp->name);
1459 if (!cfg.straddle || inname) {
1460 rv = udpquery(qp, mntpt, depth, Hurry, (cfg.inside? Inns: Outns));
1465 * if we're still looking, are inside, and have an outside domain,
1466 * try it on our outside interface, if any.
1468 if (rv == Answnone && cfg.inside && !inname) {
1471 "[%d] netquery: internal nameservers failed for %s; trying external",
1472 getpid(), qp->dp->name);
1474 /* prepare server RR's for incremental lookup */
1475 for(rp = qp->nsrp; rp; rp = rp->next)
1478 rv = udpquery(qp, "/net.alt", depth, Patient, Outns);
1493 memset(&req, 0, sizeof req);
1495 req.aborttime = timems() + Maxreqtm;
1496 req.from = "internal";
1497 queryinit(&q, dnlookup(root, Cin, 1), Tns, &req);
1498 nsrp = dblookup(root, Cin, Tns, 0, 0);
1499 for (rr = nsrp; rr != nil; rr = rr->next)
1500 dnslog("seerootns query nsrp: %R", rr);
1501 rv = netqueryns(&q, 0, nsrp); /* lookup ". ns" using nsrp */