ref: 8a1b65b7b638df4820ee14c3b168eedc1adec724
parent: 11c7bff2403f6fb953cc876d3d50ea51ec18c0c1
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Nov 15 23:42:09 EST 2013
ndb/dns: detect query loops never try to resolve a nameserver address when that nameserver is in the set of nameservers already being queried. this situation can happen when the Ta and Taaaa RR's expire, but the Tns records are still in the cache so there is no usable nameserver but they still refer to each another.
--- a/sys/src/cmd/ndb/dn.c
+++ b/sys/src/cmd/ndb/dn.c
@@ -655,6 +655,7 @@
now = time(nil);
nowns = nsec();
req->id = ++dnvars.id;
+ req->aux = nil;
unlock(&dnvars);
return rv;
--- a/sys/src/cmd/ndb/dnresolve.c
+++ b/sys/src/cmd/ndb/dnresolve.c
@@ -52,6 +52,8 @@
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() */
@@ -225,14 +227,18 @@
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);
@@ -739,6 +745,30 @@
return 0;
}
+static int
+queryloops(Query *qp, RR *rp)
+{+ DN *ns;
+
+ ns = rp->host;
+
+ /*
+ * avoid loops looking up a server under itself
+ */
+ if(subsume(rp->owner->name, ns->name))
+ return 1;
+
+ /*
+ * must not cycle on name servers refering
+ * to each another.
+ */
+ for(qp = qp->prev; qp; qp = qp->prev)
+ for(rp = qp->nsrp; rp; rp = rp->next)
+ if(rp->host == ns)
+ return 1;
+ return 0;
+}
+
/*
* Get next server address(es) into qp->dest[nd] and beyond
*/
@@ -787,13 +817,8 @@
if(rp->marker)
continue;
rp->marker = 1;
-
- /*
- * avoid loops looking up a server under itself
- */
- if(subsume(rp->owner->name, rp->host->name))
+ if(queryloops(qp, rp))
continue;
-
arp = dnresolve(rp->host->name, Cin, Ta, qp->req, 0,
depth+1, Recurse, 1, 0);
if(arp == nil)
--- a/sys/src/cmd/ndb/dns.h
+++ b/sys/src/cmd/ndb/dns.h
@@ -182,6 +182,7 @@
jmp_buf mret; /* where master jumps to after starting a slave */
int id;
char *from; /* who asked us? */
+ void *aux;
};
/*
--
⑨