shithub: riscv

Download patch

ref: c45386588ba849f2859833ab9c368b7bc6cc0a31
parent: 5f87d8dcc814700f10f40c10a0225400e4828ef9
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;
 };
 
 /*
--