]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/ndb/dnresolve.c
ndb/dns: do recursive lookup for dnsslave=
[plan9front.git] / sys / src / cmd / ndb / dnresolve.c
index a93c29151da4efb09497eacbe9316cefd11448b8..f595ce39d5fda9e32cd948edbfdf9f3760e5e3e6 100644 (file)
@@ -18,24 +18,16 @@ enum
        Answerr=        -1,
        Answnone,
 
-       Maxdest=        24,     /* maximum destinations for a request message */
+       Maxdest=        32,     /* maximum destinations for a request message */
        Maxoutstanding= 15,     /* max. outstanding queries per domain name */
-       Remntretry=     15,     /* min. sec.s between /net.alt remount tries */
 
        /*
         * these are the old values; we're trying longer timeouts now
         * primarily for the benefit of remote nameservers querying us
         * during times of bad connectivity.
         */
-//     Maxtrans=       3,      /* maximum transmissions to a server */
-//     Maxretries=     3, /* cname+actual resends: was 32; have pity on user */
-//     Maxwaitms=      1000,   /* wait no longer for a remote dns query */
-//     Minwaitms=      100,    /* willing to wait for a remote dns query */
-
        Maxtrans=       5,      /* maximum transmissions to a server */
-       Maxretries=     5, /* cname+actual resends: was 32; have pity on user */
-       Maxwaitms=      5000,   /* wait no longer for a remote dns query */
-       Minwaitms=      500,    /* willing to wait for a remote dns query */
+       Maxretries=     10,     /* cname+actual resends: was 32; have pity on user */
 };
 enum { Hurry, Patient, };
 enum { Outns, Inns, };
@@ -69,21 +61,6 @@ struct Query {
        uchar   tcpip[IPaddrlen];
 };
 
-/* estimated % probability of such a record existing at all */
-int likely[] = {
-       [Ta]            95,
-       [Taaaa]         10,
-       [Tcname]        15,
-       [Tmx]           60,
-       [Tns]           90,
-       [Tnull]         5,
-       [Tptr]          35,
-       [Tsoa]          90,
-       [Tsrv]          60,
-       [Ttxt]          15,
-       [Tall]          95,
-};
-
 static RR*     dnresolve1(char*, int, int, Request*, int, int);
 static int     netquery(Query *, int);
 
@@ -168,7 +145,7 @@ dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth,
                }
                if(drp != nil)
                        rrfreelist(drp);
-               procsetname(procname);
+               procsetname("%s", procname);
                free(procname);
                return rp;
        }
@@ -211,7 +188,7 @@ dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth,
                if(rp == nil && status != nil && dp->respcode != Rok)
                        *status = dp->respcode;
        }
-       procsetname(procname);
+       procsetname("%s", procname);
        free(procname);
        return randomize(rp);
 }
@@ -770,12 +747,13 @@ queryloops(Query *qp, RR *rp)
 }
 
 /*
- *  Get next server address(es) into qp->dest[nd] and beyond
+ *  Get next server type address(es) into qp->dest[nd] and beyond
  */
 static int
-serveraddrs(Query *qp, int nd, int depth)
+serveraddrs(Query *qp, int nd, int depth, int type)
 {
        RR *rp, *arp, *trp;
+       ulong mark;
        Dest *p;
 
        if(nd >= Maxdest)               /* dest array is full? */
@@ -786,23 +764,20 @@ serveraddrs(Query *qp, int nd, int depth)
         *  if we find one, mark it so we ignore this on
         *  subsequent passes.
         */
-       arp = 0;
+       mark = 1UL<<type;
+       arp = nil;
        for(rp = qp->nsrp; rp; rp = rp->next){
                assert(rp->magic == RRmagic);
-               if(rp->marker)
+               if(rp->marker & mark)
                        continue;
-               arp = rrlookup(rp->host, Ta, NOneg);
-               if(arp == nil)
-                       arp = rrlookup(rp->host, Taaaa, NOneg);
+               arp = rrlookup(rp->host, type, NOneg);
                if(arp){
-                       rp->marker = 1;
+                       rp->marker |= mark;
                        break;
                }
-               arp = dblookup(rp->host->name, Cin, Ta, 0, 0);
-               if(arp == nil)
-                       arp = dblookup(rp->host->name, Cin, Taaaa, 0, 0);
+               arp = dblookup(rp->host->name, Cin, type, 0, 0);
                if(arp){
-                       rp->marker = 1;
+                       rp->marker |= mark;
                        break;
                }
        }
@@ -812,9 +787,9 @@ serveraddrs(Query *qp, int nd, int depth)
         *  server addresses, try resolving one via the network.
         *  Mark any we try to resolve so we don't try a second time.
         */
-       if(arp == 0){
+       if(arp == nil){
                for(rp = qp->nsrp; rp; rp = rp->next)
-                       if(rp->marker == 0)
+                       if((rp->marker & mark) == 0)
                        if(queryloops(qp, rp))
                                /*
                                 * give up as we should have got the address
@@ -824,14 +799,11 @@ serveraddrs(Query *qp, int nd, int depth)
                                return nd;
 
                for(rp = qp->nsrp; rp; rp = rp->next){
-                       if(rp->marker)
+                       if(rp->marker & mark)
                                continue;
-                       rp->marker = 1;
-                       arp = dnresolve(rp->host->name, Cin, Ta, qp->req, 0,
+                       rp->marker |= mark;
+                       arp = dnresolve(rp->host->name, Cin, type, qp->req, 0,
                                depth+1, Recurse, 1, 0);
-                       if(arp == nil)
-                               arp = dnresolve(rp->host->name, Cin, Taaaa,
-                                       qp->req, 0, depth+1, Recurse, 1, 0);
                        rrfreelist(rrremneg(&arp));
                        if(arp)
                                break;
@@ -842,7 +814,9 @@ serveraddrs(Query *qp, int nd, int depth)
        for(trp = arp; trp && nd < Maxdest; trp = trp->next){
                p = &qp->dest[nd];
                memset(p, 0, sizeof *p);
-               parseip(p->a, trp->ip->name);
+               if(parseip(p->a, trp->ip->name) == -1)
+                       continue;
+
                /*
                 * straddling servers can reject all nameservers if they are all
                 * inside, so be sure to list at least one outside ns at
@@ -928,13 +902,12 @@ static int
 mydnsquery(Query *qp, int medium, uchar *udppkt, int len)
 {
        int rv, nfd;
-       char conndir[40], addr[128], domain[64];
+       char conndir[40], addr[128];
        uchar belen[2];
        NetConnInfo *nci;
 
        rv = -1;
-       snprint(domain, sizeof(domain), "%I", udppkt);
-       if (myaddr(domain))
+       if (myip(udppkt))
                return rv;
        switch (medium) {
        case Udp:
@@ -964,9 +937,8 @@ mydnsquery(Query *qp, int medium, uchar *udppkt, int len)
        case Tcp:
                /* send via TCP & keep fd around for reply */
                memmove(qp->tcpip, udppkt, sizeof qp->tcpip);
-               snprint(addr, sizeof addr, "%s/tcp!%s!dns",
-                               (mntpt && *mntpt) ? mntpt : "/net",
-                               domain);
+               snprint(addr, sizeof addr, "%s/tcp!%I!dns",
+                       (mntpt && *mntpt) ? mntpt : "/net", udppkt);
                alarm(10*1000);
                qp->tcpfd = dial(addr, nil, conndir, &qp->tcpctlfd);
                alarm(0);
@@ -1031,8 +1003,9 @@ xmitquery(Query *qp, int medium, int depth, uchar *obuf, int inns, int len)
        p = qp->dest;
        n = qp->curdest - p;
        if (qp->ndest > n) {
-               n = serveraddrs(qp, n, depth);  /* populates qp->dest. */
-               assert(n >= 0 && n <= Maxdest);
+               /* populates qp->dest with v4 and v6 addresses. */
+               n = serveraddrs(qp, n, depth, Ta);
+               n = serveraddrs(qp, n, depth, Taaaa);
                if (n == 0 && cfg.straddle && cfg.inside) {
                        /* get ips of "outside-ns-ips" */
                        while(n < Maxdest){
@@ -1055,7 +1028,7 @@ xmitquery(Query *qp, int medium, int depth, uchar *obuf, int inns, int len)
                if((1<<p->nx) > qp->ndest)
                        continue;
 
-               if(memcmp(p->a, IPnoaddr, sizeof IPnoaddr) == 0)
+               if(ipcmp(p->a, IPnoaddr) == 0)
                        continue;               /* mistake */
 
                procsetname("udp %sside query to %I/%s %s %s",
@@ -1229,11 +1202,12 @@ procansw(Query *qp, DNSmsg *mp, int depth, Dest *p)
        }
 
        /*
-        *  Any reply from an authoritative server,
+        *  Any reply from an authoritative server
+        *  that does not provide more nameservers,
         *  or a positive reply terminates the search.
         *  A negative response now also terminates the search.
         */
-       if(mp->an != nil || (mp->flags & Fauth)){
+       if(mp->an || (mp->flags & Fauth) && mp->ns == nil){
                if(isnegrname(mp))
                        qp->dp->respcode = Rname;
                else
@@ -1267,7 +1241,7 @@ procansw(Query *qp, DNSmsg *mp, int depth, Dest *p)
         *  if we're a pure resolver, don't recurse, we have
         *  to forward to a fixed set of named servers.
         */
-       if(!mp->ns || cfg.resolver && cfg.justforw)
+       if(mp->ns == nil || cfg.resolver && cfg.justforw)
                return Answnone;
        tp = rrlookup(ndp, Tns, NOneg);
        if(contains(qp->nsrp, tp)){
@@ -1353,7 +1327,7 @@ queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, ulong waitms, int inns)
         *  each cycle send one more message than the previous.
         *  retry a query via tcp if its response is truncated.
         */
-       for(ndest = 1; ndest < Maxdest; ndest++){
+       for(ndest = 2; ndest < Maxdest; ndest += 2){
                qp->ndest = ndest;
                qp->tcpset = 0;
                if (xmitquery(qp, Udp, depth, obuf, inns, len) < 0)
@@ -1392,7 +1366,7 @@ queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, ulong waitms, int inns)
                        if(debug)
                                dnslog("queryns got reply from %I", srcip);
                        for(p = qp->dest; p < qp->curdest; p++)
-                               if(memcmp(p->a, srcip, sizeof p->a) == 0)
+                               if(ipcmp(p->a, srcip) == 0)
                                        break;
                        if(p >= qp->curdest){
                                dnslog("response from %I but no destination", srcip);
@@ -1426,45 +1400,6 @@ queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, ulong waitms, int inns)
        return Answnone;
 }
 
-/*
- *  run a command with a supplied fd as standard input
- */
-char *
-system(int fd, char *cmd)
-{
-       int pid, p, i;
-       static Waitmsg msg;
-
-       if((pid = fork()) == -1)
-               sysfatal("fork failed: %r");
-       else if(pid == 0){
-               dup(fd, 0);
-               close(fd);
-               for (i = 3; i < 200; i++)
-                       close(i);               /* don't leak fds */
-               execl("/bin/rc", "rc", "-c", cmd, nil);
-               sysfatal("exec rc: %r");
-       }
-       for(p = waitpid(); p >= 0; p = waitpid())
-               if(p == pid)
-                       return msg.msg;
-       return "lost child";
-}
-
-/* compute wait, weighted by probability of success, with bounds */
-static ulong
-weight(ulong ms, unsigned pcntprob)
-{
-       ulong wait;
-
-       wait = (ms * pcntprob) / 100;
-       if (wait < Minwaitms)
-               wait = Minwaitms;
-       if (wait > Maxwaitms)
-               wait = Maxwaitms;
-       return wait;
-}
-
 /*
  * in principle we could use a single descriptor for a udp port
  * to send all queries and receive all the answers to them,
@@ -1474,65 +1409,21 @@ static int
 udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
 {
        int fd, rv;
-       long now;
-       ulong pcntprob;
-       uvlong wait, reqtm;
-       char *msg;
        uchar *obuf, *ibuf;
-       static QLock mntlck;
-       static ulong lastmount;
-
-       rv = -1;
 
        /* use alloced buffers rather than ones from the stack */
        ibuf = emalloc(64*1024);                /* max. tcp reply size */
        obuf = emalloc(Maxudp+Udphdrsize);
 
        fd = udpport(mntpt);
-       while (fd < 0 && cfg.straddle && strcmp(mntpt, "/net.alt") == 0) {
-               /* HACK: remount /net.alt */
-               now = time(nil);
-               if (now < lastmount + Remntretry)
-                       sleep(S2MS(lastmount + Remntretry - now));
-               qlock(&mntlck);
-               fd = udpport(mntpt);    /* try again under lock */
-               if (fd < 0) {
-                       dnslog("[%d] remounting /net.alt", getpid());
-                       unmount(nil, "/net.alt");
-
-                       msg = system(open("/dev/null", ORDWR), "outside");
-
-                       lastmount = time(nil);
-                       if (msg && *msg) {
-                               dnslog("[%d] can't remount /net.alt: %s",
-                                       getpid(), msg);
-                               sleep(10*1000); /* don't spin remounting */
-                       } else
-                               fd = udpport(mntpt);
-               }
-               qunlock(&mntlck);
-       }
        if (fd < 0) {
                dnslog("can't get udpport for %s query of name %s: %r",
                        mntpt, qp->dp->name);
+               rv = -1;
                goto Out;
        }
-
-       /*
-        * Our QIP servers are busted and respond to AAAA and CNAME queries
-        * with (sometimes malformed [too short] packets and) no answers and
-        * just NS RRs but not Rname errors.  so make time-to-wait
-        * proportional to estimated probability of an RR of that type existing.
-        */
-       if (qp->type >= nelem(likely))
-               pcntprob = 35;                  /* unpopular query type */
-       else
-               pcntprob = likely[qp->type];
-       reqtm = (patient? 2 * Maxreqtm: Maxreqtm);
-       wait = weight(reqtm / 3, pcntprob);     /* time for one udp query */
-
        qp->udpfd = fd;
-       rv = queryns(qp, depth, ibuf, obuf, wait, inns);
+       rv = queryns(qp, depth, ibuf, obuf, 500UL<<(patient != 0), inns);
        qp->udpfd = -1;
        close(fd);
 
@@ -1621,7 +1512,7 @@ seerootns(void)
        req.aborttime = timems() + Maxreqtm;
        req.from = "internal";
        queryinit(&q, dnlookup(root, Cin, 1), Tns, &req);
-       nsrp = dblookup(root, Cin, Tns, 0, 0);
+       nsrp = randomize(dblookup(root, Cin, Tns, 0, 0));
        for (rr = nsrp; rr != nil; rr = rr->next)
                dnslog("seerootns query nsrp: %R", rr);
        rv = netqueryns(&q, 0, nsrp);           /* lookup ". ns" using nsrp */