From c45386588ba849f2859833ab9c368b7bc6cc0a31 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sat, 16 Nov 2013 04:42:09 +0100 Subject: 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. --- sys/src/cmd/ndb/dn.c | 1 + sys/src/cmd/ndb/dnresolve.c | 39 ++++++++++++++++++++++++++++++++------- sys/src/cmd/ndb/dns.h | 1 + 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/sys/src/cmd/ndb/dn.c b/sys/src/cmd/ndb/dn.c index 7383c9e4b..fcf262259 100644 --- a/sys/src/cmd/ndb/dn.c +++ b/sys/src/cmd/ndb/dn.c @@ -655,6 +655,7 @@ getactivity(Request *req, int recursive) now = time(nil); nowns = nsec(); req->id = ++dnvars.id; + req->aux = nil; unlock(&dnvars); return rv; diff --git a/sys/src/cmd/ndb/dnresolve.c b/sys/src/cmd/ndb/dnresolve.c index 6e8709e94..3c5942093 100644 --- a/sys/src/cmd/ndb/dnresolve.c +++ b/sys/src/cmd/ndb/dnresolve.c @@ -52,6 +52,8 @@ 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() */ @@ -225,14 +227,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); @@ -739,6 +745,30 @@ ipisbm(uchar *ip) 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 @@ serveraddrs(Query *qp, int nd, int depth) 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) diff --git a/sys/src/cmd/ndb/dns.h b/sys/src/cmd/ndb/dns.h index 1e0ae2e86..e14a20cdd 100644 --- a/sys/src/cmd/ndb/dns.h +++ b/sys/src/cmd/ndb/dns.h @@ -182,6 +182,7 @@ struct Request jmp_buf mret; /* where master jumps to after starting a slave */ int id; char *from; /* who asked us? */ + void *aux; }; /* -- cgit v1.2.3