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.
This commit is contained in:
parent
d5cf062e7a
commit
2728e06589
4 changed files with 47 additions and 81 deletions
|
@ -257,6 +257,7 @@ dblookup1(char *name, int type, int auth, int ttl)
|
||||||
/*
|
/*
|
||||||
* find a matching entry in the database
|
* find a matching entry in the database
|
||||||
*/
|
*/
|
||||||
|
t = nil;
|
||||||
nstrcpy(dname, name, sizeof dname);
|
nstrcpy(dname, name, sizeof dname);
|
||||||
for(x=0; x<4; x++){
|
for(x=0; x<4; x++){
|
||||||
switch(x){
|
switch(x){
|
||||||
|
@ -277,10 +278,23 @@ dblookup1(char *name, int type, int auth, int ttl)
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
t = nil;
|
for(nt = ndbsearch(db, &s, "dom", dname); nt != nil; nt = ndbsnext(&s, "dom", dname)) {
|
||||||
free(ndbgetvalue(db, &s, "dom", dname, attr, &t));
|
if(ndbfindattr(nt, s.t, attr) == nil) {
|
||||||
if(t == nil && strchr(dname, '.') == nil)
|
ndbfree(nt);
|
||||||
free(ndbgetvalue(db, &s, "sys", dname, attr, &t));
|
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)
|
if(t != nil)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -290,6 +304,7 @@ dblookup1(char *name, int type, int auth, int ttl)
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* search whole entry for default domain name */
|
/* search whole entry for default domain name */
|
||||||
for(nt = t; nt; nt = nt->entry)
|
for(nt = t; nt; nt = nt->entry)
|
||||||
if(strcmp(nt->attr, "dom") == 0){
|
if(strcmp(nt->attr, "dom") == 0){
|
||||||
|
|
|
@ -18,7 +18,7 @@ enum
|
||||||
Answerr= -1,
|
Answerr= -1,
|
||||||
Answnone,
|
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 */
|
Maxoutstanding= 15, /* max. outstanding queries per domain name */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -28,8 +28,6 @@ enum
|
||||||
*/
|
*/
|
||||||
Maxtrans= 5, /* maximum transmissions to a server */
|
Maxtrans= 5, /* maximum transmissions to a server */
|
||||||
Maxretries= 10, /* cname+actual resends: was 32; have pity on user */
|
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 { Hurry, Patient, };
|
||||||
enum { Outns, Inns, };
|
enum { Outns, Inns, };
|
||||||
|
@ -63,21 +61,6 @@ struct Query {
|
||||||
uchar tcpip[IPaddrlen];
|
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 RR* dnresolve1(char*, int, int, Request*, int, int);
|
||||||
static int netquery(Query *, int);
|
static int netquery(Query *, int);
|
||||||
|
|
||||||
|
@ -764,12 +747,13 @@ queryloops(Query *qp, RR *rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
static int
|
||||||
serveraddrs(Query *qp, int nd, int depth)
|
serveraddrs(Query *qp, int nd, int depth, int type)
|
||||||
{
|
{
|
||||||
RR *rp, *arp, *trp;
|
RR *rp, *arp, *trp;
|
||||||
|
ulong mark;
|
||||||
Dest *p;
|
Dest *p;
|
||||||
|
|
||||||
if(nd >= Maxdest) /* dest array is full? */
|
if(nd >= Maxdest) /* dest array is full? */
|
||||||
|
@ -780,23 +764,20 @@ serveraddrs(Query *qp, int nd, int depth)
|
||||||
* if we find one, mark it so we ignore this on
|
* if we find one, mark it so we ignore this on
|
||||||
* subsequent passes.
|
* subsequent passes.
|
||||||
*/
|
*/
|
||||||
arp = 0;
|
mark = 1UL<<type;
|
||||||
|
arp = nil;
|
||||||
for(rp = qp->nsrp; rp; rp = rp->next){
|
for(rp = qp->nsrp; rp; rp = rp->next){
|
||||||
assert(rp->magic == RRmagic);
|
assert(rp->magic == RRmagic);
|
||||||
if(rp->marker)
|
if(rp->marker & mark)
|
||||||
continue;
|
continue;
|
||||||
arp = rrlookup(rp->host, Ta, NOneg);
|
arp = rrlookup(rp->host, type, NOneg);
|
||||||
if(arp == nil)
|
|
||||||
arp = rrlookup(rp->host, Taaaa, NOneg);
|
|
||||||
if(arp){
|
if(arp){
|
||||||
rp->marker = 1;
|
rp->marker |= mark;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
arp = dblookup(rp->host->name, Cin, Ta, 0, 0);
|
arp = dblookup(rp->host->name, Cin, type, 0, 0);
|
||||||
if(arp == nil)
|
|
||||||
arp = dblookup(rp->host->name, Cin, Taaaa, 0, 0);
|
|
||||||
if(arp){
|
if(arp){
|
||||||
rp->marker = 1;
|
rp->marker |= mark;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -806,9 +787,9 @@ serveraddrs(Query *qp, int nd, int depth)
|
||||||
* server addresses, try resolving one via the network.
|
* server addresses, try resolving one via the network.
|
||||||
* Mark any we try to resolve so we don't try a second time.
|
* 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)
|
for(rp = qp->nsrp; rp; rp = rp->next)
|
||||||
if(rp->marker == 0)
|
if((rp->marker & mark) == 0)
|
||||||
if(queryloops(qp, rp))
|
if(queryloops(qp, rp))
|
||||||
/*
|
/*
|
||||||
* give up as we should have got the address
|
* give up as we should have got the address
|
||||||
|
@ -818,14 +799,11 @@ serveraddrs(Query *qp, int nd, int depth)
|
||||||
return nd;
|
return nd;
|
||||||
|
|
||||||
for(rp = qp->nsrp; rp; rp = rp->next){
|
for(rp = qp->nsrp; rp; rp = rp->next){
|
||||||
if(rp->marker)
|
if(rp->marker & mark)
|
||||||
continue;
|
continue;
|
||||||
rp->marker = 1;
|
rp->marker |= mark;
|
||||||
arp = dnresolve(rp->host->name, Cin, Ta, qp->req, 0,
|
arp = dnresolve(rp->host->name, Cin, type, qp->req, 0,
|
||||||
depth+1, Recurse, 1, 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));
|
rrfreelist(rrremneg(&arp));
|
||||||
if(arp)
|
if(arp)
|
||||||
break;
|
break;
|
||||||
|
@ -836,7 +814,9 @@ serveraddrs(Query *qp, int nd, int depth)
|
||||||
for(trp = arp; trp && nd < Maxdest; trp = trp->next){
|
for(trp = arp; trp && nd < Maxdest; trp = trp->next){
|
||||||
p = &qp->dest[nd];
|
p = &qp->dest[nd];
|
||||||
memset(p, 0, sizeof *p);
|
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
|
* straddling servers can reject all nameservers if they are all
|
||||||
* inside, so be sure to list at least one outside ns at
|
* inside, so be sure to list at least one outside ns at
|
||||||
|
@ -1023,8 +1003,9 @@ xmitquery(Query *qp, int medium, int depth, uchar *obuf, int inns, int len)
|
||||||
p = qp->dest;
|
p = qp->dest;
|
||||||
n = qp->curdest - p;
|
n = qp->curdest - p;
|
||||||
if (qp->ndest > n) {
|
if (qp->ndest > n) {
|
||||||
n = serveraddrs(qp, n, depth); /* populates qp->dest. */
|
/* populates qp->dest with v4 and v6 addresses. */
|
||||||
assert(n >= 0 && n <= Maxdest);
|
n = serveraddrs(qp, n, depth, Ta);
|
||||||
|
n = serveraddrs(qp, n, depth, Taaaa);
|
||||||
if (n == 0 && cfg.straddle && cfg.inside) {
|
if (n == 0 && cfg.straddle && cfg.inside) {
|
||||||
/* get ips of "outside-ns-ips" */
|
/* get ips of "outside-ns-ips" */
|
||||||
while(n < Maxdest){
|
while(n < Maxdest){
|
||||||
|
@ -1346,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.
|
* each cycle send one more message than the previous.
|
||||||
* retry a query via tcp if its response is truncated.
|
* 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->ndest = ndest;
|
||||||
qp->tcpset = 0;
|
qp->tcpset = 0;
|
||||||
if (xmitquery(qp, Udp, depth, obuf, inns, len) < 0)
|
if (xmitquery(qp, Udp, depth, obuf, inns, len) < 0)
|
||||||
|
@ -1419,20 +1400,6 @@ queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, ulong waitms, int inns)
|
||||||
return Answnone;
|
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
|
* in principle we could use a single descriptor for a udp port
|
||||||
* to send all queries and receive all the answers to them,
|
* to send all queries and receive all the answers to them,
|
||||||
|
@ -1442,12 +1409,8 @@ static int
|
||||||
udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
|
udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
|
||||||
{
|
{
|
||||||
int fd, rv;
|
int fd, rv;
|
||||||
ulong pcntprob;
|
|
||||||
uvlong wait, reqtm;
|
|
||||||
uchar *obuf, *ibuf;
|
uchar *obuf, *ibuf;
|
||||||
|
|
||||||
rv = -1;
|
|
||||||
|
|
||||||
/* use alloced buffers rather than ones from the stack */
|
/* use alloced buffers rather than ones from the stack */
|
||||||
ibuf = emalloc(64*1024); /* max. tcp reply size */
|
ibuf = emalloc(64*1024); /* max. tcp reply size */
|
||||||
obuf = emalloc(Maxudp+Udphdrsize);
|
obuf = emalloc(Maxudp+Udphdrsize);
|
||||||
|
@ -1456,24 +1419,11 @@ udpquery(Query *qp, char *mntpt, int depth, int patient, int inns)
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
dnslog("can't get udpport for %s query of name %s: %r",
|
dnslog("can't get udpport for %s query of name %s: %r",
|
||||||
mntpt, qp->dp->name);
|
mntpt, qp->dp->name);
|
||||||
|
rv = -1;
|
||||||
goto Out;
|
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;
|
qp->udpfd = fd;
|
||||||
rv = queryns(qp, depth, ibuf, obuf, wait, inns);
|
rv = queryns(qp, depth, ibuf, obuf, 500UL<<(patient != 0), inns);
|
||||||
qp->udpfd = -1;
|
qp->udpfd = -1;
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
@ -1562,7 +1512,7 @@ seerootns(void)
|
||||||
req.aborttime = timems() + Maxreqtm;
|
req.aborttime = timems() + Maxreqtm;
|
||||||
req.from = "internal";
|
req.from = "internal";
|
||||||
queryinit(&q, dnlookup(root, Cin, 1), Tns, &req);
|
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)
|
for (rr = nsrp; rr != nil; rr = rr->next)
|
||||||
dnslog("seerootns query nsrp: %R", rr);
|
dnslog("seerootns query nsrp: %R", rr);
|
||||||
rv = netqueryns(&q, 0, nsrp); /* lookup ". ns" using nsrp */
|
rv = netqueryns(&q, 0, nsrp); /* lookup ". ns" using nsrp */
|
||||||
|
|
|
@ -197,7 +197,7 @@ main(int argc, char *argv[])
|
||||||
free(dir);
|
free(dir);
|
||||||
mountinit(servefile, mntpt); /* forks, parent exits */
|
mountinit(servefile, mntpt); /* forks, parent exits */
|
||||||
|
|
||||||
srand(now*getpid());
|
srand(truerand());
|
||||||
db2cache(1);
|
db2cache(1);
|
||||||
|
|
||||||
if (cfg.straddle && !seerootns())
|
if (cfg.straddle && !seerootns())
|
||||||
|
|
|
@ -73,6 +73,7 @@ main(int argc, char *argv[])
|
||||||
dninit();
|
dninit();
|
||||||
fmtinstall('R', prettyrrfmt);
|
fmtinstall('R', prettyrrfmt);
|
||||||
opendatabase();
|
opendatabase();
|
||||||
|
srand(truerand());
|
||||||
|
|
||||||
if(cfg.resolver)
|
if(cfg.resolver)
|
||||||
squirrelserveraddrs();
|
squirrelserveraddrs();
|
||||||
|
|
Loading…
Reference in a new issue