]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/ndb/dnresolve.c
ndb/dns: lookup *all* entries in dblookup(), v4 and v6 queries in parallel, remove...
[plan9front.git] / sys / src / cmd / ndb / dnresolve.c
index 6e8709e943aefcf6e4b75eaecb7cdd37daa2e05a..bc2614c69b30a67c72ddea598692d88e7b139880 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, };
@@ -43,7 +35,8 @@ enum { Outns, Inns, };
 struct Dest
 {
        uchar   a[IPaddrlen];   /* ip address */
-       DN      *s;             /* name server */
+       DN      *s;             /* name server name */
+       RR      *n;             /* name server rr */
        int     nx;             /* number of transmissions */
        int     code;           /* response code; used to clear dp->respcode */
 };
@@ -52,9 +45,10 @@ struct Query {
        DN      *dp;            /* domain */
        ushort  type;           /* and type to look up */
        Request *req;
+       Query   *prev;          /* previous query */
+
        RR      *nsrp;          /* name servers to consult */
 
-       /* dest must not be on the stack due to forking in slave() */
        Dest    *dest;          /* array of destinations */
        Dest    *curdest;       /* pointer to next to fill */
        int     ndest;          /* transmit to this many on this round */
@@ -67,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);
 
@@ -175,7 +154,7 @@ dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth,
         *  try the name directly
         */
        rp = dnresolve1(name, class, type, req, depth, recurse);
-       if(rp == nil && (dp = dnlookup(name, class, 0)) != nil) {
+       if(rp == nil && (dp = idnlookup(name, class, 0)) != nil) {
                /*
                 * try it as a canonical name if we weren't told
                 * that the name didn't exist
@@ -225,14 +204,18 @@ queryinit(Query *qp, DN *dp, int type, Request *req)
        qp->type = type;
        if (qp->type != type)
                dnslog("queryinit: bogus type %d", type);
-       qp->req = req;
        qp->nsrp = nil;
        qp->dest = qp->curdest = nil;
+       qp->prev = req->aux;
+       qp->req = req;
+       req->aux = qp;
 }
 
 static void
 querydestroy(Query *qp)
 {
+       if(qp->req->aux == qp)
+               qp->req->aux = qp->prev;
        /* leave udpfd open */
        if (qp->tcpfd >= 0)
                close(qp->tcpfd);
@@ -288,6 +271,8 @@ netqueryns(Query *qp, int depth, RR *nsrp)
 {
        int rv;
 
+       if(nsrp == nil)
+               return Answnone;
        qp->nsrp = nsrp;
        rv = netquery(qp, depth);
        qp->nsrp = nil;         /* prevent accidents */
@@ -340,7 +325,7 @@ issuequery(Query *qp, char *name, int class, int depth, int recurse)
                }
 
                /* look for ns in cache */
-               nsdp = dnlookup(cp, class, 0);
+               nsdp = idnlookup(cp, class, 0);
                nsrp = nil;
                if(nsdp)
                        nsrp = randomize(rrlookup(nsdp, Tns, NOneg));
@@ -379,7 +364,7 @@ dnresolve1(char *name, int class, int type, Request *req, int depth,
        if(class != Cin)
                return nil;
 
-       dp = dnlookup(name, class, 1);
+       dp = idnlookup(name, class, 1);
 
        /*
         *  Try the cache first
@@ -739,13 +724,36 @@ ipisbm(uchar *ip)
        return 0;
 }
 
+static int
+queryloops(Query *qp, RR *rp)
+{
+       DN *ns = rp->host;
+
+       /*
+        *  looking up a server under itself
+        */
+       if(subsume(rp->owner->name, ns->name))
+               return 1;
+
+       /*
+        *  cycle on name servers refering
+        *  to each another.
+        */
+       for(; qp; qp = qp->prev)
+               if(qp->dp == ns)
+                       return 1;
+
+       return 0;
+}
+
 /*
- *  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? */
@@ -756,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;
                }
        }
@@ -782,33 +787,36 @@ 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)
-               for(rp = qp->nsrp; rp; rp = rp->next){
-                       if(rp->marker)
-                               continue;
-                       rp->marker = 1;
+       if(arp == nil){
+               for(rp = qp->nsrp; rp; rp = rp->next)
+                       if((rp->marker & mark) == 0)
+                       if(queryloops(qp, rp))
+                               /*
+                                * give up as we should have got the address
+                                * by higher up nameserver when recursing
+                                * down, or will be queried when recursing up.
+                                */
+                               return nd;
 
-                       /*
-                        *  avoid loops looking up a server under itself
-                        */
-                       if(subsume(rp->owner->name, rp->host->name))
+               for(rp = qp->nsrp; rp; rp = rp->next){
+                       if(rp->marker & mark)
                                continue;
-
-                       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;
                }
+       }
 
        /* use any addresses that we found */
        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
@@ -818,7 +826,14 @@ serveraddrs(Query *qp, int nd, int depth)
                    cfg.straddle && !insideaddr(qp->dp->name) && insidens(p->a))
                        continue;
                p->nx = 0;
+               p->n = nil;
                p->s = trp->owner;
+               for(rp = qp->nsrp; rp; rp = rp->next){
+                       if(rp->host == p->s){
+                               p->n = rp;
+                               break;
+                       }
+               }
                p->code = Rtimeout;
                nd++;
        }
@@ -887,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:
@@ -923,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);
@@ -990,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){
@@ -1014,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",
@@ -1042,9 +1056,66 @@ isnegrname(DNSmsg *mp)
        return mp->an == nil && (mp->flags & Rmask) == Rname;
 }
 
+static int
+filterhints(RR *rp, void *arg)
+{
+       RR *nsrp;
+
+       if(rp->type != Ta && rp->type != Taaaa)
+               return 0;
+
+       for(nsrp = arg; nsrp; nsrp = nsrp->next)
+               if(nsrp->type == Tns && rp->owner == nsrp->host)
+                       return 1;
+
+       return 0;
+}
+
+static int
+filterauth(RR *rp, void *arg)
+{
+       Dest *dest;
+       RR *nsrp;
+
+       dest = arg;
+       nsrp = dest->n;
+       if(nsrp == nil)
+               return 0;
+
+       if(rp->type == Tsoa && rp->owner != nsrp->owner
+       && !subsume(nsrp->owner->name, rp->owner->name)
+       && strncmp(nsrp->owner->name, "local#", 6) != 0)
+               return 1;
+
+       if(rp->type != Tns)
+               return 0;
+
+       if(rp->owner != nsrp->owner
+       && !subsume(nsrp->owner->name, rp->owner->name)
+       && strncmp(nsrp->owner->name, "local#", 6) != 0)
+               return 1;
+
+       return baddelegation(rp, nsrp, dest->a);
+}
+
+static void
+reportandfree(RR *l, char *note, Dest *p)
+{
+       RR *rp;
+
+       while(rp = l){
+               l = l->next;
+               rp->next = nil;
+               if(debug)
+                       dnslog("ignoring %s from %I/%s: %R",
+                               note, p->a, p->s->name, rp);
+               rrfree(rp);
+       }
+}
+
 /* returns Answerr (-1) on errors, else number of answers, which can be zero. */
 static int
-procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p)
+procansw(Query *qp, DNSmsg *mp, int depth, Dest *p)
 {
        int rv;
        char buf[32];
@@ -1052,37 +1123,44 @@ procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p)
        Query nq;
        RR *tp, *soarr;
 
-       if (mp->an == nil)
+       if(mp->an == nil)
                stats.negans++;
 
        /* ignore any error replies */
-       if((mp->flags & Rmask) == Rserver){
+       switch(mp->flags & Rmask){
+       case Rrefused:
+       case Rserver:
                stats.negserver++;
                freeanswers(mp);
-               if(p != nil)
-                       p->code = Rserver;
+               p->code = Rserver;
                return Answerr;
        }
 
        /* ignore any bad delegations */
-       if(mp->ns && baddelegation(mp->ns, qp->nsrp, srcip)){
-               stats.negbaddeleg++;
-               if(mp->an == nil){
-                       stats.negbdnoans++;
-                       freeanswers(mp);
-                       if(p != nil)
-                               p->code = Rserver;
-                       dnslog(" and no answers");
-                       return Answerr;
-               }
-               dnslog(" but has answers; ignoring ns");
-               rrfreelistptr(&mp->ns);
-               mp->nscount = 0;
-       }
+       if((tp = rrremfilter(&mp->ns, filterauth, p)) != 0)
+               reportandfree(tp, "bad delegation", p);
 
        /* remove any soa's from the authority section */
        soarr = rrremtype(&mp->ns, Tsoa);
 
+       /* only nameservers remaining */
+       if((tp = rrremtype(&mp->ns, Tns)) != 0){
+               reportandfree(mp->ns, "non-nameserver", p);
+               mp->ns = tp;
+       }
+
+       /* remove answers not related to the question. */
+       if((tp = rrremowner(&mp->an, qp->dp)) != 0){
+               reportandfree(mp->an, "wrong subject answer", p);
+               mp->an = tp;
+       }
+       if(qp->type != Tall){
+               if((tp = rrremtype(&mp->an, qp->type)) != 0){
+                       reportandfree(mp->an, "wrong type answer", p);
+                       mp->an = tp;
+               }
+       }
+
        /* incorporate answers */
        unique(mp->an);
        unique(mp->ns);
@@ -1091,17 +1169,23 @@ procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p)
        if(mp->an){
                /*
                 * only use cname answer when returned. some dns servers
-                * attach (potential) spam hint address records which poisons the cache.
+                * attach (potential) spam hint address records which poisons
+                * the cache.
                 */
                if((tp = rrremtype(&mp->an, Tcname)) != 0){
-                       if(mp->an)
-                               rrfreelist(mp->an);
+                       reportandfree(mp->an, "ip in cname answer", p);
                        mp->an = tp;
                }
                rrattach(mp->an, (mp->flags & Fauth) != 0);
        }
-       if(mp->ar)
+       if(mp->ar){
+               /* restrict hints to address rr's for nameservers only */
+               if((tp = rrremfilter(&mp->ar, filterhints, mp->ns)) != 0){
+                       reportandfree(mp->ar, "hint", p);
+                       mp->ar = tp;
+               }
                rrattach(mp->ar, Notauthoritative);
+       }
        if(mp->ns && !cfg.justforw){
                ndp = mp->ns->owner;
                rrattach(mp->ns, Notauthoritative);
@@ -1118,11 +1202,12 @@ procansw(Query *qp, DNSmsg *mp, uchar *srcip, 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
@@ -1156,7 +1241,7 @@ procansw(Query *qp, DNSmsg *mp, uchar *srcip, 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)){
@@ -1215,16 +1300,22 @@ tcpquery(Query *qp, DNSmsg *mp, int depth, uchar *ibuf, uchar *obuf, int len,
 static int
 queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, ulong waitms, int inns)
 {
-       int ndest, len, replywaits, rv;
+       int ndest, len, replywaits, rv, flag;
        ushort req;
        uvlong endms;
        char buf[32];
        uchar srcip[IPaddrlen];
        Dest *p, *np, dest[Maxdest];
 
-       /* pack request into a udp message */
        req = rand();
-       len = mkreq(qp->dp, qp->type, obuf, Frecurse|Oquery, req);
+
+       /* request recursion only for local dns servers */
+       flag = Oquery;
+       if(strncmp(qp->nsrp->owner->name, "local#", 6) == 0)
+               flag |= Frecurse;
+
+       /* pack request into a udp message */
+       len = mkreq(qp->dp, qp->type, obuf, flag, req);
 
        /* no server addresses yet */
        memset(dest, 0, sizeof dest);
@@ -1236,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)
@@ -1272,21 +1363,23 @@ queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, ulong waitms, int inns)
                        }
 
                        /* find responder */
-                       // dnslog("queryns got reply from %I", srcip);
+                       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);
+                               continue;
+                       }
 
-                       if(p != qp->curdest) {
-                               /* remove all addrs of responding server from list */
-                               for(np = qp->dest; np < qp->curdest; np++)
-                                       if(np->s == p->s)
-                                               np->nx = Maxtrans;
-                       } else
-                               p = nil;
+                       /* remove all addrs of responding server from list */
+                       for(np = qp->dest; np < qp->curdest; np++)
+                               if(np->s == p->s)
+                                       np->nx = Maxtrans;
 
                        /* free or incorporate RRs in m */
-                       rv = procansw(qp, &m, srcip, depth, p);
+                       rv = procansw(qp, &m, depth, p);
                        if (rv > Answnone) {
                                qp->dest = qp->curdest = nil; /* prevent accidents */
                                return rv;
@@ -1307,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,
@@ -1355,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);
 
@@ -1502,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 */