shithub: riscv

Download patch

ref: 2728e065895e7af2493ed7af3b8897caa416adf6
parent: d5cf062e7a0e3a6b2c2939c7615ffd722cdbf1a8
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri May 11 18:37:28 EDT 2018

ndb/dns: lookup *all* entries in dblookup(), v4 and v6 queries in parallel, remove weigthed timeouts

dblookup() used to only return the first matching entry. in
case of ipv6, we want all entries returned to get both v4
and v6 addresses... and these might not neccesarily be in
the same entry (see /lib/ndb/common). note also this makes
it behave the same as in cachedb mode which reads in the
whole database.

we do not know if v4 or v6 routing works, so the simplest
is just to query v4 and v6 nameservers in parallel. this is
done by changing serveraddrs() to return one address type,
and we make sure to get at least one v4 and one v6 address
each round.

get rid of the weigthed timeout code... there where too many
assumptions. instead, we give a round 500ms timeout (or 1 second
in patient mode) and honor the maximum query time.

--- a/sys/src/cmd/ndb/dblookup.c
+++ b/sys/src/cmd/ndb/dblookup.c
@@ -257,6 +257,7 @@
 	/*
 	 *  find a matching entry in the database
 	 */
+	t = nil;
 	nstrcpy(dname, name, sizeof dname);
 	for(x=0; x<4; x++){
 		switch(x){
@@ -277,10 +278,23 @@
 				continue;
 			break;
 		}
-		t = nil;
-		free(ndbgetvalue(db, &s, "dom", dname, attr, &t));
-		if(t == nil && strchr(dname, '.') == nil)
-			free(ndbgetvalue(db, &s, "sys", dname, attr, &t));
+		for(nt = ndbsearch(db, &s, "dom", dname); nt != nil; nt = ndbsnext(&s, "dom", dname)) {
+			if(ndbfindattr(nt, s.t, attr) == nil) {
+				ndbfree(nt);
+				continue;
+			}
+			t = ndbconcatenate(t, ndbreorder(nt, s.t));
+		}
+		if(t == nil && strchr(dname, '.') == nil) {
+			for(nt = ndbsearch(db, &s, "sys", dname); nt != nil; nt = ndbsnext(&s, "sys", dname)) {
+				if(ndbfindattr(nt, s.t, attr) == nil) {
+					ndbfree(nt);
+					continue;
+				}
+				t = ndbconcatenate(t, ndbreorder(nt, s.t));
+			}
+		}
+		s.t = t;
 		if(t != nil)
 			break;
 	}
@@ -289,6 +303,7 @@
 //		dnslog("dblookup1(%s) name not found", name);
 		return nil;
 	}
+
 
 	/* search whole entry for default domain name */
 	for(nt = t; nt; nt = nt->entry)
--- a/sys/src/cmd/ndb/dnresolve.c
+++ b/sys/src/cmd/ndb/dnresolve.c
@@ -18,7 +18,7 @@
 	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 */
 
 	/*
@@ -28,8 +28,6 @@
 	 */
 	Maxtrans=	5,	/* maximum transmissions to a server */
 	Maxretries=	10,	/* 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 */
 };
 enum { Hurry, Patient, };
 enum { Outns, Inns, };
@@ -63,21 +61,6 @@
 	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);
 
@@ -764,12 +747,13 @@
 }
 
 /*
- *  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? */
@@ -780,23 +764,20 @@
 	 *  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;
 		}
 	}
@@ -806,9 +787,9 @@
 	 *  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
@@ -818,14 +799,11 @@
 				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;
@@ -836,7 +814,9 @@
 	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
@@ -1023,8 +1003,9 @@
 	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){
@@ -1346,7 +1327,7 @@
 	 *  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)
@@ -1419,20 +1400,6 @@
 	return Answnone;
 }
 
-/* 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,
@@ -1442,12 +1409,8 @@
 udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
 {
 	int fd, rv;
-	ulong pcntprob;
-	uvlong wait, reqtm;
 	uchar *obuf, *ibuf;
 
-	rv = -1;
-
 	/* use alloced buffers rather than ones from the stack */
 	ibuf = emalloc(64*1024);		/* max. tcp reply size */
 	obuf = emalloc(Maxudp+Udphdrsize);
@@ -1456,24 +1419,11 @@
 	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);
 
@@ -1562,7 +1512,7 @@
 	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 */
--- a/sys/src/cmd/ndb/dns.c
+++ b/sys/src/cmd/ndb/dns.c
@@ -197,7 +197,7 @@
 	free(dir);
 	mountinit(servefile, mntpt);	/* forks, parent exits */
 
-	srand(now*getpid());
+	srand(truerand());
 	db2cache(1);
 
 	if (cfg.straddle && !seerootns())
--- a/sys/src/cmd/ndb/dnsdebug.c
+++ b/sys/src/cmd/ndb/dnsdebug.c
@@ -73,6 +73,7 @@
 	dninit();
 	fmtinstall('R', prettyrrfmt);
 	opendatabase();
+	srand(truerand());
 
 	if(cfg.resolver)
 		squirrelserveraddrs();