13cbadd90SDavid du Colombier /* 23cbadd90SDavid du Colombier * domain name resolvers, see rfcs 1035 and 1123 33cbadd90SDavid du Colombier */ 43e12c5d1SDavid du Colombier #include <u.h> 53e12c5d1SDavid du Colombier #include <libc.h> 64f8f669cSDavid du Colombier #include <ip.h> 74f8f669cSDavid du Colombier #include <bio.h> 84f8f669cSDavid du Colombier #include <ndb.h> 93e12c5d1SDavid du Colombier #include "dns.h" 103e12c5d1SDavid du Colombier 11a41547ffSDavid du Colombier #define NS2MS(ns) ((ns) / 1000000L) 12a41547ffSDavid du Colombier #define S2MS(s) ((s) * 1000) 130319257bSDavid du Colombier #define MS2S(ms) ((ms) / 1000) 14a41547ffSDavid du Colombier 153cbadd90SDavid du Colombier typedef struct Dest Dest; 163cbadd90SDavid du Colombier typedef struct Ipaddr Ipaddr; 173cbadd90SDavid du Colombier typedef struct Query Query; 183cbadd90SDavid du Colombier 193e12c5d1SDavid du Colombier enum 203e12c5d1SDavid du Colombier { 213cbadd90SDavid du Colombier Udp, Tcp, 227dd7cddfSDavid du Colombier Maxdest= 24, /* maximum destinations for a request message */ 233e12c5d1SDavid du Colombier Maxtrans= 3, /* maximum transmissions to a server */ 243cbadd90SDavid du Colombier Destmagic= 0xcafebabe, 253cbadd90SDavid du Colombier Querymagic= 0xdeadbeef, 263e12c5d1SDavid du Colombier }; 27a41547ffSDavid du Colombier enum { Hurry, Patient, }; 28a41547ffSDavid du Colombier enum { Outns, Inns, }; 29a41547ffSDavid du Colombier enum { Remntretry = 15, }; /* min. sec.s between remount attempts */ 303e12c5d1SDavid du Colombier 313cbadd90SDavid du Colombier struct Ipaddr { 323cbadd90SDavid du Colombier Ipaddr *next; 333cbadd90SDavid du Colombier uchar ip[IPaddrlen]; 343cbadd90SDavid du Colombier }; 353cbadd90SDavid du Colombier 363cbadd90SDavid du Colombier struct Dest 373cbadd90SDavid du Colombier { 383cbadd90SDavid du Colombier uchar a[IPaddrlen]; /* ip address */ 393cbadd90SDavid du Colombier DN *s; /* name server */ 403cbadd90SDavid du Colombier int nx; /* number of transmissions */ 413cbadd90SDavid du Colombier int code; /* response code; used to clear dp->respcode */ 423cbadd90SDavid du Colombier 433cbadd90SDavid du Colombier ulong magic; 443cbadd90SDavid du Colombier }; 453cbadd90SDavid du Colombier 46c73252aeSDavid du Colombier /* 47c73252aeSDavid du Colombier * Query has a QLock in it, thus it can't be an automatic 48c73252aeSDavid du Colombier * variable, since each process would see a separate copy 49c73252aeSDavid du Colombier * of the lock on its stack. 50c73252aeSDavid du Colombier */ 513cbadd90SDavid du Colombier struct Query { 523cbadd90SDavid du Colombier DN *dp; /* domain */ 53adb31a62SDavid du Colombier ushort type; /* and type to look up */ 543cbadd90SDavid du Colombier Request *req; 553cbadd90SDavid du Colombier RR *nsrp; /* name servers to consult */ 563cbadd90SDavid du Colombier 57a41547ffSDavid du Colombier /* dest must not be on the stack due to forking in slave() */ 583cbadd90SDavid du Colombier Dest *dest; /* array of destinations */ 593cbadd90SDavid du Colombier Dest *curdest; /* pointer to one of them */ 603cbadd90SDavid du Colombier int ndest; 613cbadd90SDavid du Colombier 62f46c709fSDavid du Colombier int udpfd; 633cbadd90SDavid du Colombier 643cbadd90SDavid du Colombier QLock tcplock; /* only one tcp call at a time per query */ 653cbadd90SDavid du Colombier int tcpset; 663cbadd90SDavid du Colombier int tcpfd; /* if Tcp, read replies from here */ 673cbadd90SDavid du Colombier int tcpctlfd; 683cbadd90SDavid du Colombier uchar tcpip[IPaddrlen]; 693cbadd90SDavid du Colombier 703cbadd90SDavid du Colombier ulong magic; 713cbadd90SDavid du Colombier }; 723cbadd90SDavid du Colombier 73a41547ffSDavid du Colombier /* estimated % probability of such a record existing at all */ 74a41547ffSDavid du Colombier int likely[] = { 75a41547ffSDavid du Colombier [Ta] 95, 76a41547ffSDavid du Colombier [Taaaa] 10, 77a41547ffSDavid du Colombier [Tcname] 15, 78a41547ffSDavid du Colombier [Tmx] 60, 79a41547ffSDavid du Colombier [Tns] 90, 80a41547ffSDavid du Colombier [Tnull] 5, 81a41547ffSDavid du Colombier [Tptr] 35, 82a41547ffSDavid du Colombier [Tsoa] 90, 83a41547ffSDavid du Colombier [Tsrv] 60, 84a41547ffSDavid du Colombier [Ttxt] 15, 85a41547ffSDavid du Colombier [Tall] 95, 863cbadd90SDavid du Colombier }; 873cbadd90SDavid du Colombier 887dd7cddfSDavid du Colombier static RR* dnresolve1(char*, int, int, Request*, int, int); 893cbadd90SDavid du Colombier static int netquery(Query *, int); 903cbadd90SDavid du Colombier 914f8f669cSDavid du Colombier /* 924f8f669cSDavid du Colombier * reading /proc/pid/args yields either "name" or "name [display args]", 934f8f669cSDavid du Colombier * so return only display args, if any. 944f8f669cSDavid du Colombier */ 954f8f669cSDavid du Colombier static char * 964f8f669cSDavid du Colombier procgetname(void) 974f8f669cSDavid du Colombier { 984f8f669cSDavid du Colombier int fd, n; 994f8f669cSDavid du Colombier char *lp, *rp; 1004f8f669cSDavid du Colombier char buf[256]; 1014f8f669cSDavid du Colombier 1024f8f669cSDavid du Colombier snprint(buf, sizeof buf, "#p/%d/args", getpid()); 1034f8f669cSDavid du Colombier if((fd = open(buf, OREAD)) < 0) 1044f8f669cSDavid du Colombier return strdup(""); 1054f8f669cSDavid du Colombier *buf = '\0'; 1064f8f669cSDavid du Colombier n = read(fd, buf, sizeof buf-1); 1074f8f669cSDavid du Colombier close(fd); 1084f8f669cSDavid du Colombier if (n >= 0) 1094f8f669cSDavid du Colombier buf[n] = '\0'; 1104f8f669cSDavid du Colombier if ((lp = strchr(buf, '[')) == nil || 1114f8f669cSDavid du Colombier (rp = strrchr(buf, ']')) == nil) 1124f8f669cSDavid du Colombier return strdup(""); 1134f8f669cSDavid du Colombier *rp = '\0'; 1144f8f669cSDavid du Colombier return strdup(lp+1); 1154f8f669cSDavid du Colombier } 1163e12c5d1SDavid du Colombier 1173e12c5d1SDavid du Colombier /* 1183e12c5d1SDavid du Colombier * lookup 'type' info for domain name 'name'. If it doesn't exist, try 1193e12c5d1SDavid du Colombier * looking it up as a canonical name. 1203e12c5d1SDavid du Colombier */ 1213e12c5d1SDavid du Colombier RR* 1224f8f669cSDavid du Colombier dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, 1234f8f669cSDavid du Colombier int recurse, int rooted, int *status) 1243e12c5d1SDavid du Colombier { 1257dd7cddfSDavid du Colombier RR *rp, *nrp, *drp; 1263e12c5d1SDavid du Colombier DN *dp; 1277dd7cddfSDavid du Colombier int loops; 1284f8f669cSDavid du Colombier char *procname; 1297dd7cddfSDavid du Colombier char nname[Domlen]; 1303e12c5d1SDavid du Colombier 1317dd7cddfSDavid du Colombier if(status) 1327dd7cddfSDavid du Colombier *status = 0; 1337dd7cddfSDavid du Colombier 134a41547ffSDavid du Colombier if(depth > 12) /* in a recursive loop? */ 135a41547ffSDavid du Colombier return nil; 136a41547ffSDavid du Colombier 1374f8f669cSDavid du Colombier procname = procgetname(); 1387dd7cddfSDavid du Colombier /* 1397dd7cddfSDavid du Colombier * hack for systems that don't have resolve search 1407dd7cddfSDavid du Colombier * lists. Just look up the simple name in the database. 1417dd7cddfSDavid du Colombier */ 1426dc4800dSDavid du Colombier if(!rooted && strchr(name, '.') == nil){ 1437dd7cddfSDavid du Colombier rp = nil; 1447dd7cddfSDavid du Colombier drp = domainlist(class); 145a41547ffSDavid du Colombier for(nrp = drp; rp == nil && nrp != nil; nrp = nrp->next){ 1464f8f669cSDavid du Colombier snprint(nname, sizeof nname, "%s.%s", name, 1474f8f669cSDavid du Colombier nrp->ptr->name); 148a41547ffSDavid du Colombier rp = dnresolve(nname, class, type, req, cn, depth+1, 1494f8f669cSDavid du Colombier recurse, rooted, status); 150271b8d73SDavid du Colombier rrfreelist(rrremneg(&rp)); 1517dd7cddfSDavid du Colombier } 1527dd7cddfSDavid du Colombier if(drp != nil) 1536aaebd7dSDavid du Colombier rrfreelist(drp); 1544f8f669cSDavid du Colombier procsetname(procname); 1554f8f669cSDavid du Colombier free(procname); 1563e12c5d1SDavid du Colombier return rp; 1577dd7cddfSDavid du Colombier } 1583e12c5d1SDavid du Colombier 1597dd7cddfSDavid du Colombier /* 1607dd7cddfSDavid du Colombier * try the name directly 1617dd7cddfSDavid du Colombier */ 1627dd7cddfSDavid du Colombier rp = dnresolve1(name, class, type, req, depth, recurse); 163225077b0SDavid du Colombier if(rp == nil) { 164225077b0SDavid du Colombier /* 165225077b0SDavid du Colombier * try it as a canonical name if we weren't told 166225077b0SDavid du Colombier * that the name didn't exist 167225077b0SDavid du Colombier */ 1687dd7cddfSDavid du Colombier dp = dnlookup(name, class, 0); 1694f8f669cSDavid du Colombier if(type != Tptr && dp->respcode != Rname) 1707dd7cddfSDavid du Colombier for(loops = 0; rp == nil && loops < 32; loops++){ 171225077b0SDavid du Colombier rp = dnresolve1(name, class, Tcname, req, 172225077b0SDavid du Colombier depth, recurse); 1737dd7cddfSDavid du Colombier if(rp == nil) 1747dd7cddfSDavid du Colombier break; 17580ee5cbfSDavid du Colombier 176c73252aeSDavid du Colombier /* rp->host == nil shouldn't happen, but does */ 177c73252aeSDavid du Colombier if(rp->negative || rp->host == nil){ 17880ee5cbfSDavid du Colombier rrfreelist(rp); 17980ee5cbfSDavid du Colombier rp = nil; 18080ee5cbfSDavid du Colombier break; 18180ee5cbfSDavid du Colombier } 1827dd7cddfSDavid du Colombier 1837dd7cddfSDavid du Colombier name = rp->host->name; 1847dd7cddfSDavid du Colombier if(cn) 1857dd7cddfSDavid du Colombier rrcat(cn, rp); 1867dd7cddfSDavid du Colombier else 1877dd7cddfSDavid du Colombier rrfreelist(rp); 1887dd7cddfSDavid du Colombier 189225077b0SDavid du Colombier rp = dnresolve1(name, class, type, req, 190225077b0SDavid du Colombier depth, recurse); 1917dd7cddfSDavid du Colombier } 1927dd7cddfSDavid du Colombier 1937dd7cddfSDavid du Colombier /* distinction between not found and not good */ 1944f8f669cSDavid du Colombier if(rp == nil && status != nil && dp->respcode != 0) 1954f8f669cSDavid du Colombier *status = dp->respcode; 196225077b0SDavid du Colombier } 1974f8f669cSDavid du Colombier procsetname(procname); 1984f8f669cSDavid du Colombier free(procname); 1997dd7cddfSDavid du Colombier return randomize(rp); 2003e12c5d1SDavid du Colombier } 2013e12c5d1SDavid du Colombier 2023cbadd90SDavid du Colombier static void 2033cbadd90SDavid du Colombier queryinit(Query *qp, DN *dp, int type, Request *req) 2043cbadd90SDavid du Colombier { 2053cbadd90SDavid du Colombier memset(qp, 0, sizeof *qp); 2064e7b9544SDavid du Colombier qp->udpfd = qp->tcpfd = qp->tcpctlfd = -1; 2073cbadd90SDavid du Colombier qp->dp = dp; 2083cbadd90SDavid du Colombier qp->type = type; 209adb31a62SDavid du Colombier if (qp->type != type) 210adb31a62SDavid du Colombier dnslog("queryinit: bogus type %d", type); 2113cbadd90SDavid du Colombier qp->req = req; 2123cbadd90SDavid du Colombier qp->nsrp = nil; 2133cbadd90SDavid du Colombier qp->dest = qp->curdest = nil; 2143cbadd90SDavid du Colombier qp->magic = Querymagic; 2153cbadd90SDavid du Colombier } 2163cbadd90SDavid du Colombier 2173cbadd90SDavid du Colombier static void 2183cbadd90SDavid du Colombier queryck(Query *qp) 2193cbadd90SDavid du Colombier { 2203cbadd90SDavid du Colombier assert(qp); 2213cbadd90SDavid du Colombier assert(qp->magic == Querymagic); 2223cbadd90SDavid du Colombier } 2233cbadd90SDavid du Colombier 2243cbadd90SDavid du Colombier static void 2254e7b9544SDavid du Colombier querydestroy(Query *qp) 2264e7b9544SDavid du Colombier { 2274e7b9544SDavid du Colombier queryck(qp); 228a41547ffSDavid du Colombier /* leave udpfd alone */ 2294e7b9544SDavid du Colombier if (qp->tcpfd > 0) 2304e7b9544SDavid du Colombier close(qp->tcpfd); 2314e7b9544SDavid du Colombier if (qp->tcpctlfd > 0) { 2324e7b9544SDavid du Colombier hangup(qp->tcpctlfd); 2334e7b9544SDavid du Colombier close(qp->tcpctlfd); 2344e7b9544SDavid du Colombier } 235a41547ffSDavid du Colombier free(qp->dest); 2364e7b9544SDavid du Colombier memset(qp, 0, sizeof *qp); /* prevent accidents */ 2374e7b9544SDavid du Colombier qp->udpfd = qp->tcpfd = qp->tcpctlfd = -1; 2384e7b9544SDavid du Colombier } 2394e7b9544SDavid du Colombier 2404e7b9544SDavid du Colombier static void 2413cbadd90SDavid du Colombier destinit(Dest *p) 2423cbadd90SDavid du Colombier { 2433cbadd90SDavid du Colombier memset(p, 0, sizeof *p); 2443cbadd90SDavid du Colombier p->magic = Destmagic; 2453cbadd90SDavid du Colombier } 2463cbadd90SDavid du Colombier 2473cbadd90SDavid du Colombier static void 2483cbadd90SDavid du Colombier destck(Dest *p) 2493cbadd90SDavid du Colombier { 2503cbadd90SDavid du Colombier assert(p); 2513cbadd90SDavid du Colombier assert(p->magic == Destmagic); 2523cbadd90SDavid du Colombier } 2533cbadd90SDavid du Colombier 254a41547ffSDavid du Colombier static void 255a41547ffSDavid du Colombier destdestroy(Dest *p) 256a41547ffSDavid du Colombier { 257a41547ffSDavid du Colombier USED(p); 258a41547ffSDavid du Colombier } 259a41547ffSDavid du Colombier 260a41547ffSDavid du Colombier /* 261a41547ffSDavid du Colombier * if the response to a query hasn't arrived within 100 ms., 262a41547ffSDavid du Colombier * it's unlikely to arrive at all. after 1 s., it's really unlikely. 263a41547ffSDavid du Colombier * queries for missing RRs are likely to produce time-outs rather than 264a41547ffSDavid du Colombier * negative responses, so cname and aaaa queries are likely to time out, 265a41547ffSDavid du Colombier * thus we don't wait very long for them. 266a41547ffSDavid du Colombier */ 267a41547ffSDavid du Colombier static void 268a41547ffSDavid du Colombier notestats(vlong start, int tmout, int type) 269a41547ffSDavid du Colombier { 270a41547ffSDavid du Colombier qlock(&stats); 271a41547ffSDavid du Colombier if (tmout) { 272a41547ffSDavid du Colombier stats.tmout++; 273a41547ffSDavid du Colombier if (type == Taaaa) 274a41547ffSDavid du Colombier stats.tmoutv6++; 275a41547ffSDavid du Colombier else if (type == Tcname) 276a41547ffSDavid du Colombier stats.tmoutcname++; 277a41547ffSDavid du Colombier } else { 278a41547ffSDavid du Colombier long wait10ths = NS2MS(nsec() - start) / 100; 279a41547ffSDavid du Colombier 28081730632SDavid du Colombier if (wait10ths <= 0) 281a41547ffSDavid du Colombier stats.under10ths[0]++; 282a41547ffSDavid du Colombier else if (wait10ths >= nelem(stats.under10ths)) 283a41547ffSDavid du Colombier stats.under10ths[nelem(stats.under10ths) - 1]++; 284a41547ffSDavid du Colombier else 285a41547ffSDavid du Colombier stats.under10ths[wait10ths]++; 286a41547ffSDavid du Colombier } 287a41547ffSDavid du Colombier qunlock(&stats); 288a41547ffSDavid du Colombier } 289a41547ffSDavid du Colombier 290a41547ffSDavid du Colombier static void 291a41547ffSDavid du Colombier noteinmem(void) 292a41547ffSDavid du Colombier { 293a41547ffSDavid du Colombier qlock(&stats); 294a41547ffSDavid du Colombier stats.answinmem++; 295a41547ffSDavid du Colombier qunlock(&stats); 296a41547ffSDavid du Colombier } 297a41547ffSDavid du Colombier 2983e12c5d1SDavid du Colombier static RR* 29946595261SDavid du Colombier issuequery(Query *qp, char *name, int class, int depth, int recurse) 3003e12c5d1SDavid du Colombier { 301f46c709fSDavid du Colombier char *cp; 302c73252aeSDavid du Colombier DN *nsdp; 30346595261SDavid du Colombier RR *rp, *nsrp, *dbnsrp; 3043cbadd90SDavid du Colombier 3053e12c5d1SDavid du Colombier /* 3064f8f669cSDavid du Colombier * if we're running as just a resolver, query our 3077dd7cddfSDavid du Colombier * designated name servers 308219b2ee8SDavid du Colombier */ 3094f8f669cSDavid du Colombier if(cfg.resolver){ 3107dd7cddfSDavid du Colombier nsrp = randomize(getdnsservers(class)); 3117dd7cddfSDavid du Colombier if(nsrp != nil) { 312c73252aeSDavid du Colombier qp->nsrp = nsrp; 313c73252aeSDavid du Colombier if(netquery(qp, depth+1)){ 3147dd7cddfSDavid du Colombier rrfreelist(nsrp); 315c73252aeSDavid du Colombier return rrlookup(qp->dp, qp->type, OKneg); 3167dd7cddfSDavid du Colombier } 3177dd7cddfSDavid du Colombier rrfreelist(nsrp); 3187dd7cddfSDavid du Colombier } 319219b2ee8SDavid du Colombier } 320219b2ee8SDavid du Colombier 321219b2ee8SDavid du Colombier /* 3223e12c5d1SDavid du Colombier * walk up the domain name looking for 3233e12c5d1SDavid du Colombier * a name server for the domain. 3243e12c5d1SDavid du Colombier */ 3253e12c5d1SDavid du Colombier for(cp = name; cp; cp = walkup(cp)){ 3267dd7cddfSDavid du Colombier /* 3277dd7cddfSDavid du Colombier * if this is a local (served by us) domain, 3287dd7cddfSDavid du Colombier * return answer 3297dd7cddfSDavid du Colombier */ 3307dd7cddfSDavid du Colombier dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0)); 3317dd7cddfSDavid du Colombier if(dbnsrp && dbnsrp->local){ 332c73252aeSDavid du Colombier rp = dblookup(name, class, qp->type, 1, dbnsrp->ttl); 3337dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 3347dd7cddfSDavid du Colombier return rp; 3357dd7cddfSDavid du Colombier } 3367dd7cddfSDavid du Colombier 3377dd7cddfSDavid du Colombier /* 3387dd7cddfSDavid du Colombier * if recursion isn't set, just accept local 3397dd7cddfSDavid du Colombier * entries 3407dd7cddfSDavid du Colombier */ 3417dd7cddfSDavid du Colombier if(recurse == Dontrecurse){ 3427dd7cddfSDavid du Colombier if(dbnsrp) 3437dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 3447dd7cddfSDavid du Colombier continue; 3457dd7cddfSDavid du Colombier } 3467dd7cddfSDavid du Colombier 3477dd7cddfSDavid du Colombier /* look for ns in cache */ 3483e12c5d1SDavid du Colombier nsdp = dnlookup(cp, class, 0); 3497dd7cddfSDavid du Colombier nsrp = nil; 3503e12c5d1SDavid du Colombier if(nsdp) 3517dd7cddfSDavid du Colombier nsrp = randomize(rrlookup(nsdp, Tns, NOneg)); 3527dd7cddfSDavid du Colombier 3537dd7cddfSDavid du Colombier /* if the entry timed out, ignore it */ 3547dd7cddfSDavid du Colombier if(nsrp && nsrp->ttl < now){ 3557dd7cddfSDavid du Colombier rrfreelist(nsrp); 3567dd7cddfSDavid du Colombier nsrp = nil; 3577dd7cddfSDavid du Colombier } 3583e12c5d1SDavid du Colombier 3593e12c5d1SDavid du Colombier if(nsrp){ 3607dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 3617dd7cddfSDavid du Colombier 3624f8f669cSDavid du Colombier /* query the name servers found in cache */ 363c73252aeSDavid du Colombier qp->nsrp = nsrp; 364c73252aeSDavid du Colombier if(netquery(qp, depth+1)){ 3653e12c5d1SDavid du Colombier rrfreelist(nsrp); 366c73252aeSDavid du Colombier return rrlookup(qp->dp, qp->type, OKneg); 3677dd7cddfSDavid du Colombier } 3687dd7cddfSDavid du Colombier rrfreelist(nsrp); 3697dd7cddfSDavid du Colombier continue; 3703e12c5d1SDavid du Colombier } 3713e12c5d1SDavid du Colombier 3727dd7cddfSDavid du Colombier /* use ns from db */ 3737dd7cddfSDavid du Colombier if(dbnsrp){ 3747dd7cddfSDavid du Colombier /* try the name servers found in db */ 375c73252aeSDavid du Colombier qp->nsrp = dbnsrp; 376c73252aeSDavid du Colombier if(netquery(qp, depth+1)){ 3773e12c5d1SDavid du Colombier /* we got an answer */ 3787dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 379c73252aeSDavid du Colombier return rrlookup(qp->dp, qp->type, NOneg); 3803e12c5d1SDavid du Colombier } 3817dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 3823e12c5d1SDavid du Colombier } 3833e12c5d1SDavid du Colombier } 38446595261SDavid du Colombier return nil; 385c73252aeSDavid du Colombier } 386c73252aeSDavid du Colombier 387c73252aeSDavid du Colombier static RR* 388c73252aeSDavid du Colombier dnresolve1(char *name, int class, int type, Request *req, int depth, 389c73252aeSDavid du Colombier int recurse) 390c73252aeSDavid du Colombier { 391c73252aeSDavid du Colombier Area *area; 392c73252aeSDavid du Colombier DN *dp; 393c73252aeSDavid du Colombier RR *rp; 394c73252aeSDavid du Colombier Query *qp; 395c73252aeSDavid du Colombier 396c73252aeSDavid du Colombier if(debug) 397c73252aeSDavid du Colombier dnslog("[%d] dnresolve1 %s %d %d", getpid(), name, type, class); 398c73252aeSDavid du Colombier 399c73252aeSDavid du Colombier /* only class Cin implemented so far */ 400c73252aeSDavid du Colombier if(class != Cin) 401c73252aeSDavid du Colombier return nil; 402c73252aeSDavid du Colombier 403c73252aeSDavid du Colombier dp = dnlookup(name, class, 1); 404c73252aeSDavid du Colombier 405c73252aeSDavid du Colombier /* 406c73252aeSDavid du Colombier * Try the cache first 407c73252aeSDavid du Colombier */ 408c73252aeSDavid du Colombier rp = rrlookup(dp, type, OKneg); 409c73252aeSDavid du Colombier if(rp) 410c73252aeSDavid du Colombier if(rp->db){ 411c73252aeSDavid du Colombier /* unauthoritative db entries are hints */ 412c73252aeSDavid du Colombier if(rp->auth) { 413c73252aeSDavid du Colombier noteinmem(); 414c73252aeSDavid du Colombier return rp; 415c73252aeSDavid du Colombier } 416c73252aeSDavid du Colombier } else 417c73252aeSDavid du Colombier /* cached entry must still be valid */ 418c73252aeSDavid du Colombier if(rp->ttl > now) 419c73252aeSDavid du Colombier /* but Tall entries are special */ 420c73252aeSDavid du Colombier if(type != Tall || rp->query == Tall) { 421c73252aeSDavid du Colombier noteinmem(); 422c73252aeSDavid du Colombier return rp; 423c73252aeSDavid du Colombier } 424c73252aeSDavid du Colombier rrfreelist(rp); 42546595261SDavid du Colombier rp = nil; /* accident prevention */ 42646595261SDavid du Colombier USED(rp); 427c73252aeSDavid du Colombier 428c73252aeSDavid du Colombier /* 429c73252aeSDavid du Colombier * try the cache for a canonical name. if found punt 430c73252aeSDavid du Colombier * since we'll find it during the canonical name search 431c73252aeSDavid du Colombier * in dnresolve(). 432c73252aeSDavid du Colombier */ 433c73252aeSDavid du Colombier if(type != Tcname){ 434c73252aeSDavid du Colombier rp = rrlookup(dp, Tcname, NOneg); 435c73252aeSDavid du Colombier rrfreelist(rp); 436c73252aeSDavid du Colombier if(rp) 437c73252aeSDavid du Colombier return nil; 438c73252aeSDavid du Colombier } 439c73252aeSDavid du Colombier 440c73252aeSDavid du Colombier /* 441c73252aeSDavid du Colombier * if the domain name is within an area of ours, 442c73252aeSDavid du Colombier * we should have found its data in memory by now. 443c73252aeSDavid du Colombier */ 444c73252aeSDavid du Colombier area = inmyarea(dp->name); 445c73252aeSDavid du Colombier if (area || strncmp(dp->name, "local#", 6) == 0) { 446c73252aeSDavid du Colombier // char buf[32]; 447c73252aeSDavid du Colombier 448c73252aeSDavid du Colombier // dnslog("%s %s: no data in area %s", dp->name, 449c73252aeSDavid du Colombier // rrname(type, buf, sizeof buf), area->soarr->owner->name); 450c73252aeSDavid du Colombier return nil; 451c73252aeSDavid du Colombier } 452c73252aeSDavid du Colombier 453c73252aeSDavid du Colombier qp = emalloc(sizeof *qp); 454c73252aeSDavid du Colombier queryinit(qp, dp, type, req); 45546595261SDavid du Colombier rp = issuequery(qp, name, class, depth, recurse); 456c73252aeSDavid du Colombier querydestroy(qp); 457c73252aeSDavid du Colombier free(qp); 458c73252aeSDavid du Colombier if(rp) 459c73252aeSDavid du Colombier return rp; 4603e12c5d1SDavid du Colombier 4617dd7cddfSDavid du Colombier /* settle for a non-authoritative answer */ 4627dd7cddfSDavid du Colombier rp = rrlookup(dp, type, OKneg); 4637dd7cddfSDavid du Colombier if(rp) 4647dd7cddfSDavid du Colombier return rp; 4657dd7cddfSDavid du Colombier 4667dd7cddfSDavid du Colombier /* noone answered. try the database, we might have a chance. */ 4677dd7cddfSDavid du Colombier return dblookup(name, class, type, 0, 0); 4683e12c5d1SDavid du Colombier } 4693e12c5d1SDavid du Colombier 4703e12c5d1SDavid du Colombier /* 4714f8f669cSDavid du Colombier * walk a domain name one element to the right. 4724f8f669cSDavid du Colombier * return a pointer to that element. 4733e12c5d1SDavid du Colombier * in other words, return a pointer to the parent domain name. 4743e12c5d1SDavid du Colombier */ 4753e12c5d1SDavid du Colombier char* 4763e12c5d1SDavid du Colombier walkup(char *name) 4773e12c5d1SDavid du Colombier { 4783e12c5d1SDavid du Colombier char *cp; 4793e12c5d1SDavid du Colombier 4803e12c5d1SDavid du Colombier cp = strchr(name, '.'); 4813e12c5d1SDavid du Colombier if(cp) 4823e12c5d1SDavid du Colombier return cp+1; 4833e12c5d1SDavid du Colombier else if(*name) 4843e12c5d1SDavid du Colombier return ""; 4853e12c5d1SDavid du Colombier else 4863e12c5d1SDavid du Colombier return 0; 4873e12c5d1SDavid du Colombier } 4883e12c5d1SDavid du Colombier 4893e12c5d1SDavid du Colombier /* 490a41547ffSDavid du Colombier * Get a udp port for sending requests and reading replies. Put the port 4913e12c5d1SDavid du Colombier * into "headers" mode. 4923e12c5d1SDavid du Colombier */ 4933e12c5d1SDavid du Colombier static char *hmsg = "headers"; 4943e12c5d1SDavid du Colombier 495dc5a79c1SDavid du Colombier int 4964f8f669cSDavid du Colombier udpport(char *mtpt) 4973e12c5d1SDavid du Colombier { 4983e12c5d1SDavid du Colombier int fd, ctl; 4994f8f669cSDavid du Colombier char ds[64], adir[64]; 5003e12c5d1SDavid du Colombier 5013e12c5d1SDavid du Colombier /* get a udp port */ 5024f8f669cSDavid du Colombier snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt? mtpt: "/net")); 5037dd7cddfSDavid du Colombier ctl = announce(ds, adir); 5047dd7cddfSDavid du Colombier if(ctl < 0){ 5057dd7cddfSDavid du Colombier /* warning("can't get udp port"); */ 506bd389b36SDavid du Colombier return -1; 507bd389b36SDavid du Colombier } 5083e12c5d1SDavid du Colombier 5093e12c5d1SDavid du Colombier /* turn on header style interface */ 510bd389b36SDavid du Colombier if(write(ctl, hmsg, strlen(hmsg)) , 0){ 5117dd7cddfSDavid du Colombier close(ctl); 512bd389b36SDavid du Colombier warning(hmsg); 513bd389b36SDavid du Colombier return -1; 514bd389b36SDavid du Colombier } 5153e12c5d1SDavid du Colombier 5167dd7cddfSDavid du Colombier /* grab the data file */ 5174f8f669cSDavid du Colombier snprint(ds, sizeof ds, "%s/data", adir); 5187dd7cddfSDavid du Colombier fd = open(ds, ORDWR); 5193e12c5d1SDavid du Colombier close(ctl); 5204f8f669cSDavid du Colombier if(fd < 0) 5214f8f669cSDavid du Colombier warning("can't open udp port %s: %r", ds); 5223e12c5d1SDavid du Colombier return fd; 5233e12c5d1SDavid du Colombier } 5243e12c5d1SDavid du Colombier 525d6d99297SDavid du Colombier /* generate a DNS UDP query packet */ 526dc5a79c1SDavid du Colombier int 527dc5a79c1SDavid du Colombier mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno) 5283e12c5d1SDavid du Colombier { 5293e12c5d1SDavid du Colombier DNSmsg m; 5303e12c5d1SDavid du Colombier int len; 531f27a9a5aSDavid du Colombier Udphdr *uh = (Udphdr*)buf; 5323e12c5d1SDavid du Colombier 5333e12c5d1SDavid du Colombier /* stuff port number into output buffer */ 5343cbadd90SDavid du Colombier memset(uh, 0, sizeof *uh); 5357dd7cddfSDavid du Colombier hnputs(uh->rport, 53); 5363e12c5d1SDavid du Colombier 5373e12c5d1SDavid du Colombier /* make request and convert it to output format */ 5383cbadd90SDavid du Colombier memset(&m, 0, sizeof m); 539dc5a79c1SDavid du Colombier m.flags = flags; 5403e12c5d1SDavid du Colombier m.id = reqno; 5413e12c5d1SDavid du Colombier m.qd = rralloc(type); 5423e12c5d1SDavid du Colombier m.qd->owner = dp; 5433e12c5d1SDavid du Colombier m.qd->type = type; 544adb31a62SDavid du Colombier if (m.qd->type != type) 545adb31a62SDavid du Colombier dnslog("mkreq: bogus type %d", type); 546f27a9a5aSDavid du Colombier len = convDNS2M(&m, &buf[Udphdrsize], Maxudp); 5477dd7cddfSDavid du Colombier rrfree(m.qd); 5486aaebd7dSDavid du Colombier memset(&m, 0, sizeof m); /* cause trouble */ 5493e12c5d1SDavid du Colombier return len; 5503e12c5d1SDavid du Colombier } 5513e12c5d1SDavid du Colombier 552a41547ffSDavid du Colombier void 5537dd7cddfSDavid du Colombier freeanswers(DNSmsg *mp) 5543e12c5d1SDavid du Colombier { 5557dd7cddfSDavid du Colombier rrfreelist(mp->qd); 5567dd7cddfSDavid du Colombier rrfreelist(mp->an); 5577dd7cddfSDavid du Colombier rrfreelist(mp->ns); 5587dd7cddfSDavid du Colombier rrfreelist(mp->ar); 5594f8f669cSDavid du Colombier mp->qd = mp->an = mp->ns = mp->ar = nil; 5607dd7cddfSDavid du Colombier } 5617dd7cddfSDavid du Colombier 5623cbadd90SDavid du Colombier /* sets srcip */ 5633cbadd90SDavid du Colombier static int 5643cbadd90SDavid du Colombier readnet(Query *qp, int medium, uchar *ibuf, ulong endtime, uchar **replyp, 5653cbadd90SDavid du Colombier uchar *srcip) 5663cbadd90SDavid du Colombier { 5673cbadd90SDavid du Colombier int len, fd; 568a41547ffSDavid du Colombier long ms; 569a41547ffSDavid du Colombier vlong startns = nsec(); 5703cbadd90SDavid du Colombier uchar *reply; 5713cbadd90SDavid du Colombier uchar lenbuf[2]; 5723cbadd90SDavid du Colombier 5733cbadd90SDavid du Colombier /* timed read of reply */ 574a41547ffSDavid du Colombier ms = S2MS(endtime) - NS2MS(startns); 575a41547ffSDavid du Colombier if (ms < 2000) 576a41547ffSDavid du Colombier ms = 2000; /* give the remote ns a fighting chance */ 5773cbadd90SDavid du Colombier reply = ibuf; 5783cbadd90SDavid du Colombier len = -1; /* pessimism */ 5794e7b9544SDavid du Colombier memset(srcip, 0, IPaddrlen); 580a41547ffSDavid du Colombier if (medium == Udp) 5814e7b9544SDavid du Colombier if (qp->udpfd <= 0) 5824e7b9544SDavid du Colombier dnslog("readnet: qp->udpfd closed"); 5834e7b9544SDavid du Colombier else { 584a41547ffSDavid du Colombier alarm(ms); 585f27a9a5aSDavid du Colombier len = read(qp->udpfd, ibuf, Udphdrsize+Maxudpin); 586a41547ffSDavid du Colombier alarm(0); 587a41547ffSDavid du Colombier notestats(startns, len < 0, qp->type); 5884e7b9544SDavid du Colombier if (len >= IPaddrlen) 5894e7b9544SDavid du Colombier memmove(srcip, ibuf, IPaddrlen); 590f27a9a5aSDavid du Colombier if (len >= Udphdrsize) { 591f27a9a5aSDavid du Colombier len -= Udphdrsize; 592f27a9a5aSDavid du Colombier reply += Udphdrsize; 5934e7b9544SDavid du Colombier } 5944e7b9544SDavid du Colombier } 595a41547ffSDavid du Colombier else { 5963cbadd90SDavid du Colombier if (!qp->tcpset) 5973cbadd90SDavid du Colombier dnslog("readnet: tcp params not set"); 598a41547ffSDavid du Colombier alarm(ms); 5993cbadd90SDavid du Colombier fd = qp->tcpfd; 6003cbadd90SDavid du Colombier if (fd <= 0) 6013cbadd90SDavid du Colombier dnslog("readnet: %s: tcp fd unset for dest %I", 6023cbadd90SDavid du Colombier qp->dp->name, qp->tcpip); 6033cbadd90SDavid du Colombier else if (readn(fd, lenbuf, 2) != 2) { 6043cbadd90SDavid du Colombier dnslog("readnet: short read of tcp size from %I", 6053cbadd90SDavid du Colombier qp->tcpip); 606a41547ffSDavid du Colombier /* probably a time-out */ 607a41547ffSDavid du Colombier notestats(startns, 1, qp->type); 6083cbadd90SDavid du Colombier } else { 6093cbadd90SDavid du Colombier len = lenbuf[0]<<8 | lenbuf[1]; 6103cbadd90SDavid du Colombier if (readn(fd, ibuf, len) != len) { 6113cbadd90SDavid du Colombier dnslog("readnet: short read of tcp data from %I", 6123cbadd90SDavid du Colombier qp->tcpip); 613a41547ffSDavid du Colombier /* probably a time-out */ 614a41547ffSDavid du Colombier notestats(startns, 1, qp->type); 6153cbadd90SDavid du Colombier len = -1; 6163cbadd90SDavid du Colombier } 6173cbadd90SDavid du Colombier } 618a41547ffSDavid du Colombier alarm(0); 6193cbadd90SDavid du Colombier memmove(srcip, qp->tcpip, IPaddrlen); 6203cbadd90SDavid du Colombier } 6213cbadd90SDavid du Colombier *replyp = reply; 6223cbadd90SDavid du Colombier return len; 6233cbadd90SDavid du Colombier } 6243cbadd90SDavid du Colombier 6257dd7cddfSDavid du Colombier /* 6263cbadd90SDavid du Colombier * read replies to a request and remember the rrs in the answer(s). 6273cbadd90SDavid du Colombier * ignore any of the wrong type. 6284f8f669cSDavid du Colombier * wait at most until endtime. 6297dd7cddfSDavid du Colombier */ 6307dd7cddfSDavid du Colombier static int 6313cbadd90SDavid du Colombier readreply(Query *qp, int medium, ushort req, uchar *ibuf, DNSmsg *mp, 6323cbadd90SDavid du Colombier ulong endtime) 6337dd7cddfSDavid du Colombier { 634a41547ffSDavid du Colombier int len, rv; 6357dd7cddfSDavid du Colombier char *err; 636a41547ffSDavid du Colombier char tbuf[32]; 6373cbadd90SDavid du Colombier uchar *reply; 6383cbadd90SDavid du Colombier uchar srcip[IPaddrlen]; 6393e12c5d1SDavid du Colombier RR *rp; 6407dd7cddfSDavid du Colombier 6413cbadd90SDavid du Colombier queryck(qp); 6423cbadd90SDavid du Colombier rv = 0; 6433cbadd90SDavid du Colombier memset(mp, 0, sizeof *mp); 6443cbadd90SDavid du Colombier if (time(nil) >= endtime) 6453cbadd90SDavid du Colombier return -1; /* timed out before we started */ 6467dd7cddfSDavid du Colombier 647a41547ffSDavid du Colombier memset(srcip, 0, sizeof srcip); 648a41547ffSDavid du Colombier if (0) 649a41547ffSDavid du Colombier len = -1; 6503cbadd90SDavid du Colombier for (; time(nil) < endtime && 6513cbadd90SDavid du Colombier (len = readnet(qp, medium, ibuf, endtime, &reply, srcip)) >= 0; 6523cbadd90SDavid du Colombier freeanswers(mp)){ 6537dd7cddfSDavid du Colombier /* convert into internal format */ 6543cbadd90SDavid du Colombier memset(mp, 0, sizeof *mp); 6553cbadd90SDavid du Colombier err = convM2DNS(reply, len, mp, nil); 656d6d99297SDavid du Colombier if (mp->flags & Ftrunc) { 657a41547ffSDavid du Colombier free(err); 658a41547ffSDavid du Colombier freeanswers(mp); 659a41547ffSDavid du Colombier /* notify our caller to retry the query via tcp. */ 6603cbadd90SDavid du Colombier return -1; 6613cbadd90SDavid du Colombier } else if(err){ 6623cbadd90SDavid du Colombier dnslog("readreply: %s: input err, len %d: %s: %I", 6633cbadd90SDavid du Colombier qp->dp->name, len, err, srcip); 6643cbadd90SDavid du Colombier free(err); 6657dd7cddfSDavid du Colombier continue; 6667dd7cddfSDavid du Colombier } 6677dd7cddfSDavid du Colombier if(debug) 6683cbadd90SDavid du Colombier logreply(qp->req->id, srcip, mp); 6697dd7cddfSDavid du Colombier 6707dd7cddfSDavid du Colombier /* answering the right question? */ 6713cbadd90SDavid du Colombier if(mp->id != req) 6723cbadd90SDavid du Colombier dnslog("%d: id %d instead of %d: %I", qp->req->id, 6733cbadd90SDavid du Colombier mp->id, req, srcip); 6743cbadd90SDavid du Colombier else if(mp->qd == 0) 6753cbadd90SDavid du Colombier dnslog("%d: no question RR: %I", qp->req->id, srcip); 6763cbadd90SDavid du Colombier else if(mp->qd->owner != qp->dp) 6773cbadd90SDavid du Colombier dnslog("%d: owner %s instead of %s: %I", qp->req->id, 6783cbadd90SDavid du Colombier mp->qd->owner->name, qp->dp->name, srcip); 6793cbadd90SDavid du Colombier else if(mp->qd->type != qp->type) 6803cbadd90SDavid du Colombier dnslog("%d: qp->type %d instead of %d: %I", 6813cbadd90SDavid du Colombier qp->req->id, mp->qd->type, qp->type, srcip); 6823cbadd90SDavid du Colombier else { 6837dd7cddfSDavid du Colombier /* remember what request this is in answer to */ 6847dd7cddfSDavid du Colombier for(rp = mp->an; rp; rp = rp->next) 6853cbadd90SDavid du Colombier rp->query = qp->type; 6863cbadd90SDavid du Colombier return rv; 6877dd7cddfSDavid du Colombier } 6887dd7cddfSDavid du Colombier } 689a41547ffSDavid du Colombier if (time(nil) >= endtime) { 690a41547ffSDavid du Colombier ; /* query expired */ 691a41547ffSDavid du Colombier } else if (0) { 692a41547ffSDavid du Colombier /* this happens routinely when a read times out */ 693a41547ffSDavid du Colombier dnslog("readreply: %s type %s: ns %I read error or eof " 694a41547ffSDavid du Colombier "(returned %d): %r", qp->dp->name, rrname(qp->type, 695a41547ffSDavid du Colombier tbuf, sizeof tbuf), srcip, len); 696a41547ffSDavid du Colombier if (medium == Udp) 697a41547ffSDavid du Colombier for (rp = qp->nsrp; rp != nil; rp = rp->next) 698a41547ffSDavid du Colombier if (rp->type == Tns) 699a41547ffSDavid du Colombier dnslog("readreply: %s: query sent to " 700a41547ffSDavid du Colombier "ns %s", qp->dp->name, 701a41547ffSDavid du Colombier rp->host->name); 702a41547ffSDavid du Colombier } 7033cbadd90SDavid du Colombier return -1; 7043cbadd90SDavid du Colombier } 7057dd7cddfSDavid du Colombier 7067dd7cddfSDavid du Colombier /* 7077dd7cddfSDavid du Colombier * return non-0 if first list includes second list 7087dd7cddfSDavid du Colombier */ 7097dd7cddfSDavid du Colombier int 7107dd7cddfSDavid du Colombier contains(RR *rp1, RR *rp2) 7117dd7cddfSDavid du Colombier { 7127dd7cddfSDavid du Colombier RR *trp1, *trp2; 7137dd7cddfSDavid du Colombier 7147dd7cddfSDavid du Colombier for(trp2 = rp2; trp2; trp2 = trp2->next){ 7153cbadd90SDavid du Colombier for(trp1 = rp1; trp1; trp1 = trp1->next) 7167dd7cddfSDavid du Colombier if(trp1->type == trp2->type) 7177dd7cddfSDavid du Colombier if(trp1->host == trp2->host) 7187dd7cddfSDavid du Colombier if(trp1->owner == trp2->owner) 7197dd7cddfSDavid du Colombier break; 7204f8f669cSDavid du Colombier if(trp1 == nil) 7217dd7cddfSDavid du Colombier return 0; 7227dd7cddfSDavid du Colombier } 7237dd7cddfSDavid du Colombier return 1; 7247dd7cddfSDavid du Colombier } 7257dd7cddfSDavid du Colombier 7267dd7cddfSDavid du Colombier 7276b6b9ac8SDavid du Colombier /* 7286b6b9ac8SDavid du Colombier * return multicast version if any 7296b6b9ac8SDavid du Colombier */ 7306b6b9ac8SDavid du Colombier int 7316b6b9ac8SDavid du Colombier ipisbm(uchar *ip) 7326b6b9ac8SDavid du Colombier { 7336b6b9ac8SDavid du Colombier if(isv4(ip)){ 7344f8f669cSDavid du Colombier if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 || 7354f8f669cSDavid du Colombier ipcmp(ip, IPv4bcast) == 0) 7366b6b9ac8SDavid du Colombier return 4; 7374f8f669cSDavid du Colombier } else 7386b6b9ac8SDavid du Colombier if(ip[0] == 0xff) 7396b6b9ac8SDavid du Colombier return 6; 74028a8a86bSDavid du Colombier return 0; 74128a8a86bSDavid du Colombier } 74228a8a86bSDavid du Colombier 7437dd7cddfSDavid du Colombier /* 7447dd7cddfSDavid du Colombier * Get next server address 7457dd7cddfSDavid du Colombier */ 7467dd7cddfSDavid du Colombier static int 7473cbadd90SDavid du Colombier serveraddrs(Query *qp, int nd, int depth) 7487dd7cddfSDavid du Colombier { 7497dd7cddfSDavid du Colombier RR *rp, *arp, *trp; 7507dd7cddfSDavid du Colombier Dest *cur; 7517dd7cddfSDavid du Colombier 7527dd7cddfSDavid du Colombier if(nd >= Maxdest) 7537dd7cddfSDavid du Colombier return 0; 7547dd7cddfSDavid du Colombier 7557dd7cddfSDavid du Colombier /* 7567dd7cddfSDavid du Colombier * look for a server whose address we already know. 7577dd7cddfSDavid du Colombier * if we find one, mark it so we ignore this on 7587dd7cddfSDavid du Colombier * subsequent passes. 7597dd7cddfSDavid du Colombier */ 7607dd7cddfSDavid du Colombier arp = 0; 7613cbadd90SDavid du Colombier for(rp = qp->nsrp; rp; rp = rp->next){ 76234f77ae3SDavid du Colombier assert(rp->magic == RRmagic); 7637dd7cddfSDavid du Colombier if(rp->marker) 7647dd7cddfSDavid du Colombier continue; 7657dd7cddfSDavid du Colombier arp = rrlookup(rp->host, Ta, NOneg); 7667dd7cddfSDavid du Colombier if(arp){ 7677dd7cddfSDavid du Colombier rp->marker = 1; 7687dd7cddfSDavid du Colombier break; 7697dd7cddfSDavid du Colombier } 7707dd7cddfSDavid du Colombier arp = dblookup(rp->host->name, Cin, Ta, 0, 0); 7717dd7cddfSDavid du Colombier if(arp){ 7727dd7cddfSDavid du Colombier rp->marker = 1; 7737dd7cddfSDavid du Colombier break; 7747dd7cddfSDavid du Colombier } 7757dd7cddfSDavid du Colombier } 7767dd7cddfSDavid du Colombier 7777dd7cddfSDavid du Colombier /* 7787dd7cddfSDavid du Colombier * if the cache and database lookup didn't find any new 7797dd7cddfSDavid du Colombier * server addresses, try resolving one via the network. 7807dd7cddfSDavid du Colombier * Mark any we try to resolve so we don't try a second time. 7817dd7cddfSDavid du Colombier */ 7824f8f669cSDavid du Colombier if(arp == 0) 7833cbadd90SDavid du Colombier for(rp = qp->nsrp; rp; rp = rp->next){ 7847dd7cddfSDavid du Colombier if(rp->marker) 7857dd7cddfSDavid du Colombier continue; 7867dd7cddfSDavid du Colombier rp->marker = 1; 7877dd7cddfSDavid du Colombier 7887dd7cddfSDavid du Colombier /* 7897dd7cddfSDavid du Colombier * avoid loops looking up a server under itself 7907dd7cddfSDavid du Colombier */ 7917dd7cddfSDavid du Colombier if(subsume(rp->owner->name, rp->host->name)) 7927dd7cddfSDavid du Colombier continue; 7937dd7cddfSDavid du Colombier 7943cbadd90SDavid du Colombier arp = dnresolve(rp->host->name, Cin, Ta, qp->req, 0, 7954f8f669cSDavid du Colombier depth+1, Recurse, 1, 0); 7967dd7cddfSDavid du Colombier rrfreelist(rrremneg(&arp)); 7977dd7cddfSDavid du Colombier if(arp) 7987dd7cddfSDavid du Colombier break; 7997dd7cddfSDavid du Colombier } 8007dd7cddfSDavid du Colombier 8017dd7cddfSDavid du Colombier /* use any addresses that we found */ 8023cbadd90SDavid du Colombier for(trp = arp; trp && nd < Maxdest; trp = trp->next){ 8033cbadd90SDavid du Colombier cur = &qp->dest[nd]; 8047dd7cddfSDavid du Colombier parseip(cur->a, trp->ip->name); 8054f8f669cSDavid du Colombier /* 8064f8f669cSDavid du Colombier * straddling servers can reject all nameservers if they are all 8074f8f669cSDavid du Colombier * inside, so be sure to list at least one outside ns at 8084f8f669cSDavid du Colombier * the end of the ns list in /lib/ndb for `dom='. 8094f8f669cSDavid du Colombier */ 8104f8f669cSDavid du Colombier if (ipisbm(cur->a) || 8113cbadd90SDavid du Colombier cfg.straddle && !insideaddr(qp->dp->name) && insidens(cur->a)) 8126b6b9ac8SDavid du Colombier continue; 8137dd7cddfSDavid du Colombier cur->nx = 0; 8147dd7cddfSDavid du Colombier cur->s = trp->owner; 8157dd7cddfSDavid du Colombier cur->code = Rtimeout; 8166b6b9ac8SDavid du Colombier nd++; 8177dd7cddfSDavid du Colombier } 8187dd7cddfSDavid du Colombier rrfreelist(arp); 8197dd7cddfSDavid du Colombier return nd; 8207dd7cddfSDavid du Colombier } 8217dd7cddfSDavid du Colombier 8227dd7cddfSDavid du Colombier /* 8237dd7cddfSDavid du Colombier * cache negative responses 8247dd7cddfSDavid du Colombier */ 8257dd7cddfSDavid du Colombier static void 8267dd7cddfSDavid du Colombier cacheneg(DN *dp, int type, int rcode, RR *soarr) 8277dd7cddfSDavid du Colombier { 8287dd7cddfSDavid du Colombier RR *rp; 8297dd7cddfSDavid du Colombier DN *soaowner; 8309a747e4fSDavid du Colombier ulong ttl; 8317dd7cddfSDavid du Colombier 832f46c709fSDavid du Colombier stats.negcached++; 833f46c709fSDavid du Colombier 8344f8f669cSDavid du Colombier /* no cache time specified, don't make anything up */ 8357dd7cddfSDavid du Colombier if(soarr != nil){ 8367dd7cddfSDavid du Colombier if(soarr->next != nil){ 8377dd7cddfSDavid du Colombier rrfreelist(soarr->next); 8387dd7cddfSDavid du Colombier soarr->next = nil; 8397dd7cddfSDavid du Colombier } 8407dd7cddfSDavid du Colombier soaowner = soarr->owner; 8417dd7cddfSDavid du Colombier } else 8427dd7cddfSDavid du Colombier soaowner = nil; 8437dd7cddfSDavid du Colombier 8449a747e4fSDavid du Colombier /* the attach can cause soarr to be freed so mine it now */ 8459a747e4fSDavid du Colombier if(soarr != nil && soarr->soa != nil) 8469a747e4fSDavid du Colombier ttl = soarr->soa->minttl+now; 8479a747e4fSDavid du Colombier else 8489a747e4fSDavid du Colombier ttl = 5*Min; 8499a747e4fSDavid du Colombier 8507dd7cddfSDavid du Colombier /* add soa and negative RR to the database */ 8516dc4800dSDavid du Colombier rrattach(soarr, Authoritative); 8527dd7cddfSDavid du Colombier 8537dd7cddfSDavid du Colombier rp = rralloc(type); 8547dd7cddfSDavid du Colombier rp->owner = dp; 8557dd7cddfSDavid du Colombier rp->negative = 1; 8567dd7cddfSDavid du Colombier rp->negsoaowner = soaowner; 8577dd7cddfSDavid du Colombier rp->negrcode = rcode; 8589a747e4fSDavid du Colombier rp->ttl = ttl; 8596dc4800dSDavid du Colombier rrattach(rp, Authoritative); 8607dd7cddfSDavid du Colombier } 8617dd7cddfSDavid du Colombier 8624f8f669cSDavid du Colombier static int 8634f8f669cSDavid du Colombier setdestoutns(Dest *p, int n) 8644f8f669cSDavid du Colombier { 8654f8f669cSDavid du Colombier uchar *outns = outsidens(n); 8664f8f669cSDavid du Colombier 8673cbadd90SDavid du Colombier destck(p); 8683cbadd90SDavid du Colombier destinit(p); 8694f8f669cSDavid du Colombier if (outns == nil) { 8704f8f669cSDavid du Colombier if (n == 0) 8714f8f669cSDavid du Colombier dnslog("[%d] no outside-ns in ndb", getpid()); 8724f8f669cSDavid du Colombier return -1; 8734f8f669cSDavid du Colombier } 8744f8f669cSDavid du Colombier memmove(p->a, outns, sizeof p->a); 8754f8f669cSDavid du Colombier p->s = dnlookup("outside-ns-ips", Cin, 1); 8764f8f669cSDavid du Colombier return 0; 8774f8f669cSDavid du Colombier } 8784f8f669cSDavid du Colombier 8797dd7cddfSDavid du Colombier /* 8803cbadd90SDavid du Colombier * issue query via UDP or TCP as appropriate. 8813cbadd90SDavid du Colombier * for TCP, returns with qp->tcpip set from udppkt header. 8827dd7cddfSDavid du Colombier */ 8837dd7cddfSDavid du Colombier static int 8843cbadd90SDavid du Colombier mydnsquery(Query *qp, int medium, uchar *udppkt, int len) 8857dd7cddfSDavid du Colombier { 886a41547ffSDavid du Colombier int rv = -1, nfd; 8873cbadd90SDavid du Colombier char *domain; 8883cbadd90SDavid du Colombier char conndir[40]; 889a41547ffSDavid du Colombier uchar belen[2]; 8903cbadd90SDavid du Colombier NetConnInfo *nci; 8914f8f669cSDavid du Colombier 8923cbadd90SDavid du Colombier queryck(qp); 8934e153993SDavid du Colombier domain = smprint("%I", udppkt); 8944e153993SDavid du Colombier if (myaddr(domain)) { 8954e153993SDavid du Colombier dnslog("mydnsquery: trying to send to myself (%s); bzzzt", 8964e153993SDavid du Colombier domain); 8974e153993SDavid du Colombier free(domain); 8984e153993SDavid du Colombier return rv; 8994e153993SDavid du Colombier } 9004e153993SDavid du Colombier 9013cbadd90SDavid du Colombier switch (medium) { 9023cbadd90SDavid du Colombier case Udp: 9034e153993SDavid du Colombier free(domain); 904a41547ffSDavid du Colombier nfd = dup(qp->udpfd, -1); 905a41547ffSDavid du Colombier if (nfd < 0) { 906a41547ffSDavid du Colombier warning("mydnsquery: qp->udpfd %d: %r", qp->udpfd); 907a41547ffSDavid du Colombier close(qp->udpfd); /* ensure it's closed */ 908a41547ffSDavid du Colombier qp->udpfd = -1; /* poison it */ 909a41547ffSDavid du Colombier return rv; 910a41547ffSDavid du Colombier } 911a41547ffSDavid du Colombier close(nfd); 912a41547ffSDavid du Colombier 9134e7b9544SDavid du Colombier if (qp->udpfd <= 0) 914a41547ffSDavid du Colombier dnslog("mydnsquery: qp->udpfd %d closed", qp->udpfd); 9154e7b9544SDavid du Colombier else { 916f27a9a5aSDavid du Colombier if (write(qp->udpfd, udppkt, len+Udphdrsize) != 917f27a9a5aSDavid du Colombier len+Udphdrsize) 918a41547ffSDavid du Colombier warning("sending udp msg: %r"); 919a41547ffSDavid du Colombier else { 920a41547ffSDavid du Colombier stats.qsent++; 9213cbadd90SDavid du Colombier rv = 0; 9224e7b9544SDavid du Colombier } 923a41547ffSDavid du Colombier } 9243cbadd90SDavid du Colombier break; 9253cbadd90SDavid du Colombier case Tcp: 9263cbadd90SDavid du Colombier /* send via TCP & keep fd around for reply */ 9273cbadd90SDavid du Colombier alarm(10*1000); 9283cbadd90SDavid du Colombier qp->tcpfd = rv = dial(netmkaddr(domain, "tcp", "dns"), nil, 9293cbadd90SDavid du Colombier conndir, &qp->tcpctlfd); 9303cbadd90SDavid du Colombier alarm(0); 9313cbadd90SDavid du Colombier if (qp->tcpfd < 0) { 9323cbadd90SDavid du Colombier dnslog("can't dial tcp!%s!dns: %r", domain); 933a41547ffSDavid du Colombier free(domain); 934a41547ffSDavid du Colombier break; 935a41547ffSDavid du Colombier } 936a41547ffSDavid du Colombier free(domain); 9373cbadd90SDavid du Colombier nci = getnetconninfo(conndir, qp->tcpfd); 9383cbadd90SDavid du Colombier if (nci) { 9393cbadd90SDavid du Colombier parseip(qp->tcpip, nci->rsys); 9403cbadd90SDavid du Colombier freenetconninfo(nci); 9413cbadd90SDavid du Colombier } else 9423cbadd90SDavid du Colombier dnslog("mydnsquery: getnetconninfo failed"); 9433cbadd90SDavid du Colombier qp->tcpset = 1; 9443e12c5d1SDavid du Colombier 9453cbadd90SDavid du Colombier belen[0] = len >> 8; 9463cbadd90SDavid du Colombier belen[1] = len; 9473cbadd90SDavid du Colombier if (write(qp->tcpfd, belen, 2) != 2 || 948f27a9a5aSDavid du Colombier write(qp->tcpfd, udppkt + Udphdrsize, len) != len) 949a41547ffSDavid du Colombier warning("sending tcp msg: %r"); 9503cbadd90SDavid du Colombier break; 9513cbadd90SDavid du Colombier default: 9523cbadd90SDavid du Colombier sysfatal("mydnsquery: bad medium"); 9533cbadd90SDavid du Colombier } 9543cbadd90SDavid du Colombier return rv; 9553cbadd90SDavid du Colombier } 9567dd7cddfSDavid du Colombier 9573e12c5d1SDavid du Colombier /* 9583cbadd90SDavid du Colombier * send query to all UDP destinations or one TCP destination, 9593cbadd90SDavid du Colombier * taken from obuf (udp packet) header 9603e12c5d1SDavid du Colombier */ 9613cbadd90SDavid du Colombier static int 9623cbadd90SDavid du Colombier xmitquery(Query *qp, int medium, int depth, uchar *obuf, int inns, int len) 9633cbadd90SDavid du Colombier { 9643cbadd90SDavid du Colombier int j, n; 9653cbadd90SDavid du Colombier char buf[32]; 9663cbadd90SDavid du Colombier Dest *p; 9673e12c5d1SDavid du Colombier 9683cbadd90SDavid du Colombier queryck(qp); 9693cbadd90SDavid du Colombier if(time(nil) >= qp->req->aborttime) 9703cbadd90SDavid du Colombier return -1; 9713cbadd90SDavid du Colombier 9723cbadd90SDavid du Colombier /* 9733cbadd90SDavid du Colombier * get a nameserver address if we need one. 9743cbadd90SDavid du Colombier * serveraddrs populates qp->dest. 9753cbadd90SDavid du Colombier */ 9763cbadd90SDavid du Colombier p = qp->dest; 9773cbadd90SDavid du Colombier destck(p); 9783cbadd90SDavid du Colombier if (qp->ndest < 0 || qp->ndest > Maxdest) 9793cbadd90SDavid du Colombier dnslog("qp->ndest %d out of range", qp->ndest); 9803cbadd90SDavid du Colombier if (qp->ndest > qp->curdest - p) 9813cbadd90SDavid du Colombier qp->curdest = &qp->dest[serveraddrs(qp, qp->curdest - p, depth)]; 9823cbadd90SDavid du Colombier destck(qp->curdest); 9837dd7cddfSDavid du Colombier 9847dd7cddfSDavid du Colombier /* no servers, punt */ 9853cbadd90SDavid du Colombier if (qp->curdest == qp->dest) 9864f8f669cSDavid du Colombier if (cfg.straddle && cfg.inside) { 9873cbadd90SDavid du Colombier /* get ips of "outside-ns-ips" */ 9883cbadd90SDavid du Colombier p = qp->curdest = qp->dest; 9893cbadd90SDavid du Colombier for(n = 0; n < Maxdest; n++, qp->curdest++) 9903cbadd90SDavid du Colombier if (setdestoutns(qp->curdest, n) < 0) 9917dd7cddfSDavid du Colombier break; 9924f8f669cSDavid du Colombier } else { 9934e7b9544SDavid du Colombier /* it's probably just a bogus domain, don't log it */ 9944e7b9544SDavid du Colombier // dnslog("xmitquery: %s: no nameservers", qp->dp->name); 9953cbadd90SDavid du Colombier return -1; 9964f8f669cSDavid du Colombier } 9977dd7cddfSDavid du Colombier 9983cbadd90SDavid du Colombier /* send to first 'qp->ndest' destinations */ 9997dd7cddfSDavid du Colombier j = 0; 10003cbadd90SDavid du Colombier if (medium == Tcp) { 10013cbadd90SDavid du Colombier j++; 10023cbadd90SDavid du Colombier queryck(qp); 10033cbadd90SDavid du Colombier assert(qp->dp); 10043cbadd90SDavid du Colombier procsetname("tcp %sside query for %s %s", (inns? "in": "out"), 10053cbadd90SDavid du Colombier qp->dp->name, rrname(qp->type, buf, sizeof buf)); 10063cbadd90SDavid du Colombier mydnsquery(qp, medium, obuf, len); /* sets qp->tcpip from obuf */ 10073cbadd90SDavid du Colombier if(debug) 10083cbadd90SDavid du Colombier logsend(qp->req->id, depth, qp->tcpip, "", qp->dp->name, 10093cbadd90SDavid du Colombier qp->type); 10103cbadd90SDavid du Colombier } else 10113cbadd90SDavid du Colombier for(; p < &qp->dest[qp->ndest] && p < qp->curdest; p++){ 10127dd7cddfSDavid du Colombier /* skip destinations we've finished with */ 10137dd7cddfSDavid du Colombier if(p->nx >= Maxtrans) 10147dd7cddfSDavid du Colombier continue; 10157dd7cddfSDavid du Colombier 10167dd7cddfSDavid du Colombier j++; 10177dd7cddfSDavid du Colombier 10187dd7cddfSDavid du Colombier /* exponential backoff of requests */ 10193cbadd90SDavid du Colombier if((1<<p->nx) > qp->ndest) 10207dd7cddfSDavid du Colombier continue; 10217dd7cddfSDavid du Colombier 10223cbadd90SDavid du Colombier procsetname("udp %sside query to %I/%s %s %s", 10233cbadd90SDavid du Colombier (inns? "in": "out"), p->a, p->s->name, 10243cbadd90SDavid du Colombier qp->dp->name, rrname(qp->type, buf, sizeof buf)); 1025219b2ee8SDavid du Colombier if(debug) 10263cbadd90SDavid du Colombier logsend(qp->req->id, depth, p->a, p->s->name, 10273cbadd90SDavid du Colombier qp->dp->name, qp->type); 10284f8f669cSDavid du Colombier 10293cbadd90SDavid du Colombier /* fill in UDP destination addr & send it */ 10303cbadd90SDavid du Colombier memmove(obuf, p->a, sizeof p->a); 10313cbadd90SDavid du Colombier mydnsquery(qp, medium, obuf, len); 10327dd7cddfSDavid du Colombier p->nx++; 10333e12c5d1SDavid du Colombier } 10343cbadd90SDavid du Colombier if(j == 0) { 10353cbadd90SDavid du Colombier // dnslog("xmitquery: %s: no destinations left", qp->dp->name); 10363cbadd90SDavid du Colombier return -1; 10373cbadd90SDavid du Colombier } 10383cbadd90SDavid du Colombier return 0; 10393cbadd90SDavid du Colombier } 10403e12c5d1SDavid du Colombier 1041f46c709fSDavid du Colombier static int lckindex[Maxlcks] = { 1042f46c709fSDavid du Colombier 0, /* all others map here */ 1043f46c709fSDavid du Colombier Ta, 1044f46c709fSDavid du Colombier Tns, 1045f46c709fSDavid du Colombier Tcname, 1046f46c709fSDavid du Colombier Tsoa, 1047f46c709fSDavid du Colombier Tptr, 1048f46c709fSDavid du Colombier Tmx, 1049f46c709fSDavid du Colombier Ttxt, 1050f46c709fSDavid du Colombier Taaaa, 1051f46c709fSDavid du Colombier }; 1052f46c709fSDavid du Colombier 1053f46c709fSDavid du Colombier static int 1054f46c709fSDavid du Colombier qtype2lck(int qtype) /* map query type to querylck index */ 1055f46c709fSDavid du Colombier { 1056f46c709fSDavid du Colombier int i; 1057f46c709fSDavid du Colombier 1058f46c709fSDavid du Colombier for (i = 1; i < nelem(lckindex); i++) 1059f46c709fSDavid du Colombier if (lckindex[i] == qtype) 1060f46c709fSDavid du Colombier return i; 1061f46c709fSDavid du Colombier return 0; 1062f46c709fSDavid du Colombier } 1063f46c709fSDavid du Colombier 10640319257bSDavid du Colombier /* is mp a cachable negative response (with Rname set)? */ 10650319257bSDavid du Colombier static int 10660319257bSDavid du Colombier isnegrname(DNSmsg *mp) 10670319257bSDavid du Colombier { 10680319257bSDavid du Colombier /* TODO: could add || cfg.justforw to RHS of && */ 10690319257bSDavid du Colombier return mp->an == nil && (mp->flags & Rmask) == Rname; 10700319257bSDavid du Colombier } 10710319257bSDavid du Colombier 10723cbadd90SDavid du Colombier static int 10733cbadd90SDavid du Colombier procansw(Query *qp, DNSmsg *mp, uchar *srcip, int depth, Dest *p) 10743cbadd90SDavid du Colombier { 10753cbadd90SDavid du Colombier int rv; 10764e5f5f32SDavid du Colombier // int lcktype; 10773cbadd90SDavid du Colombier char buf[32]; 10783cbadd90SDavid du Colombier DN *ndp; 1079c73252aeSDavid du Colombier Query *nqp; 10803cbadd90SDavid du Colombier RR *tp, *soarr; 10817dd7cddfSDavid du Colombier 1082f46c709fSDavid du Colombier if (mp->an == nil) 1083f46c709fSDavid du Colombier stats.negans++; 1084f46c709fSDavid du Colombier 108559cc4ca5SDavid du Colombier /* ignore any error replies */ 10863cbadd90SDavid du Colombier if((mp->flags & Rmask) == Rserver){ 10870319257bSDavid du Colombier stats.negserver++; 1088a41547ffSDavid du Colombier freeanswers(mp); 10893cbadd90SDavid du Colombier if(p != qp->curdest) 10907dd7cddfSDavid du Colombier p->code = Rserver; 10913cbadd90SDavid du Colombier return -1; 10923e12c5d1SDavid du Colombier } 10933e12c5d1SDavid du Colombier 109459cc4ca5SDavid du Colombier /* ignore any bad delegations */ 10953cbadd90SDavid du Colombier if(mp->ns && baddelegation(mp->ns, qp->nsrp, srcip)){ 10960319257bSDavid du Colombier stats.negbaddeleg++; 10973cbadd90SDavid du Colombier if(mp->an == nil){ 10980319257bSDavid du Colombier stats.negbdnoans++; 1099a41547ffSDavid du Colombier freeanswers(mp); 11003cbadd90SDavid du Colombier if(p != qp->curdest) 110159cc4ca5SDavid du Colombier p->code = Rserver; 11023cbadd90SDavid du Colombier return -1; 110359cc4ca5SDavid du Colombier } 1104a41547ffSDavid du Colombier rrfreelist(mp->ns); 1105a41547ffSDavid du Colombier mp->ns = nil; 110659cc4ca5SDavid du Colombier } 110759cc4ca5SDavid du Colombier 11087dd7cddfSDavid du Colombier /* remove any soa's from the authority section */ 11093cbadd90SDavid du Colombier soarr = rrremtype(&mp->ns, Tsoa); 11107dd7cddfSDavid du Colombier 11113e12c5d1SDavid du Colombier /* incorporate answers */ 11124e153993SDavid du Colombier unique(mp->an); 11134e153993SDavid du Colombier unique(mp->ns); 11144e153993SDavid du Colombier unique(mp->ar); 11153cbadd90SDavid du Colombier if(mp->an) 11163cbadd90SDavid du Colombier rrattach(mp->an, (mp->flags & Fauth) != 0); 11173cbadd90SDavid du Colombier if(mp->ar) 11186dc4800dSDavid du Colombier rrattach(mp->ar, Notauthoritative); 1119a41547ffSDavid du Colombier if(mp->ns && !cfg.justforw){ 11203cbadd90SDavid du Colombier ndp = mp->ns->owner; 11216dc4800dSDavid du Colombier rrattach(mp->ns, Notauthoritative); 11220319257bSDavid du Colombier } else { 11234f8f669cSDavid du Colombier ndp = nil; 11240319257bSDavid du Colombier rrfreelist(mp->ns); 11250319257bSDavid du Colombier mp->ns = nil; 11260319257bSDavid du Colombier } 11277dd7cddfSDavid du Colombier 11287dd7cddfSDavid du Colombier /* free the question */ 1129a41547ffSDavid du Colombier if(mp->qd) { 11303cbadd90SDavid du Colombier rrfreelist(mp->qd); 1131a41547ffSDavid du Colombier mp->qd = nil; 1132a41547ffSDavid du Colombier } 11333e12c5d1SDavid du Colombier 11343e12c5d1SDavid du Colombier /* 11353e12c5d1SDavid du Colombier * Any reply from an authoritative server, 1136a41547ffSDavid du Colombier * or a positive reply terminates the search. 1137a41547ffSDavid du Colombier * A negative response now also terminates the search. 11383e12c5d1SDavid du Colombier */ 11393cbadd90SDavid du Colombier if(mp->an != nil || (mp->flags & Fauth)){ 11400319257bSDavid du Colombier if(isnegrname(mp)) 11413cbadd90SDavid du Colombier qp->dp->respcode = Rname; 11427dd7cddfSDavid du Colombier else 11433cbadd90SDavid du Colombier qp->dp->respcode = 0; 11447dd7cddfSDavid du Colombier 11457dd7cddfSDavid du Colombier /* 1146a41547ffSDavid du Colombier * cache any negative responses, free soarr. 1147a41547ffSDavid du Colombier * negative responses need not be authoritative: 1148a41547ffSDavid du Colombier * they can legitimately come from a cache. 11497dd7cddfSDavid du Colombier */ 1150a41547ffSDavid du Colombier if( /* (mp->flags & Fauth) && */ mp->an == nil) 11513cbadd90SDavid du Colombier cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr); 11527dd7cddfSDavid du Colombier else 11537dd7cddfSDavid du Colombier rrfreelist(soarr); 11543e12c5d1SDavid du Colombier return 1; 11550319257bSDavid du Colombier } else if (isnegrname(mp)) { 1156a41547ffSDavid du Colombier qp->dp->respcode = Rname; 1157a41547ffSDavid du Colombier /* 1158a41547ffSDavid du Colombier * cache negative response. 1159a41547ffSDavid du Colombier * negative responses need not be authoritative: 1160a41547ffSDavid du Colombier * they can legitimately come from a cache. 1161a41547ffSDavid du Colombier */ 1162a41547ffSDavid du Colombier cacheneg(qp->dp, qp->type, (mp->flags & Rmask), soarr); 1163a41547ffSDavid du Colombier return 1; 11643e12c5d1SDavid du Colombier } 11650319257bSDavid du Colombier stats.negnorname++; 11667dd7cddfSDavid du Colombier rrfreelist(soarr); 11673e12c5d1SDavid du Colombier 11683e12c5d1SDavid du Colombier /* 1169a41547ffSDavid du Colombier * if we've been given better name servers, recurse. 1170a41547ffSDavid du Colombier * if we're a pure resolver, don't recurse, we have 1171a41547ffSDavid du Colombier * to forward to a fixed set of named servers. 11723e12c5d1SDavid du Colombier */ 1173a41547ffSDavid du Colombier if(!mp->ns || cfg.resolver && cfg.justforw) 11743cbadd90SDavid du Colombier return 0; 11757dd7cddfSDavid du Colombier tp = rrlookup(ndp, Tns, NOneg); 11763cbadd90SDavid du Colombier if(contains(qp->nsrp, tp)){ 11777dd7cddfSDavid du Colombier rrfreelist(tp); 11783cbadd90SDavid du Colombier return 0; 11793e12c5d1SDavid du Colombier } 11803cbadd90SDavid du Colombier procsetname("recursive query for %s %s", qp->dp->name, 11813cbadd90SDavid du Colombier rrname(qp->type, buf, sizeof buf)); 11824e5f5f32SDavid du Colombier /* 11834e5f5f32SDavid du Colombier * we're called from udpquery, called from 11844e5f5f32SDavid du Colombier * netquery, which current holds qp->dp->querylck, 11854e5f5f32SDavid du Colombier * so release it now and acquire it upon return. 11864e5f5f32SDavid du Colombier */ 11874e5f5f32SDavid du Colombier // lcktype = qtype2lck(qp->type); 11884e5f5f32SDavid du Colombier // qunlock(&qp->dp->querylck[lcktype]); 11893cbadd90SDavid du Colombier 1190c73252aeSDavid du Colombier nqp = emalloc(sizeof *nqp); 1191c73252aeSDavid du Colombier queryinit(nqp, qp->dp, qp->type, qp->req); 1192c73252aeSDavid du Colombier nqp->nsrp = tp; 1193c73252aeSDavid du Colombier rv = netquery(nqp, depth+1); 11943cbadd90SDavid du Colombier 11954e5f5f32SDavid du Colombier // qlock(&qp->dp->querylck[lcktype]); 1196adb31a62SDavid du Colombier rrfreelist(nqp->nsrp); 1197c73252aeSDavid du Colombier querydestroy(nqp); 1198c73252aeSDavid du Colombier free(nqp); 11993cbadd90SDavid du Colombier return rv; 12003cbadd90SDavid du Colombier } 12013cbadd90SDavid du Colombier 12023cbadd90SDavid du Colombier /* 12033cbadd90SDavid du Colombier * send a query via tcp to a single address (from ibuf's udp header) 12043cbadd90SDavid du Colombier * and read the answer(s) into mp->an. 12053cbadd90SDavid du Colombier */ 12063cbadd90SDavid du Colombier static int 12073cbadd90SDavid du Colombier tcpquery(Query *qp, DNSmsg *mp, int depth, uchar *ibuf, uchar *obuf, int len, 12083cbadd90SDavid du Colombier int waitsecs, int inns, ushort req) 12093cbadd90SDavid du Colombier { 12104e7b9544SDavid du Colombier int rv = 0; 12113cbadd90SDavid du Colombier ulong endtime; 12123cbadd90SDavid du Colombier 12133cbadd90SDavid du Colombier endtime = time(nil) + waitsecs; 12143cbadd90SDavid du Colombier if(endtime > qp->req->aborttime) 12153cbadd90SDavid du Colombier endtime = qp->req->aborttime; 12163cbadd90SDavid du Colombier 1217a41547ffSDavid du Colombier if (0) 12184e7b9544SDavid du Colombier dnslog("%s: udp reply truncated; retrying query via tcp to %I", 12194e7b9544SDavid du Colombier qp->dp->name, qp->tcpip); 12204e7b9544SDavid du Colombier 12213cbadd90SDavid du Colombier qlock(&qp->tcplock); 12223cbadd90SDavid du Colombier memmove(obuf, ibuf, IPaddrlen); /* send back to respondent */ 12233cbadd90SDavid du Colombier /* sets qp->tcpip from obuf's udp header */ 12244e7b9544SDavid du Colombier if (xmitquery(qp, Tcp, depth, obuf, inns, len) < 0 || 12254e7b9544SDavid du Colombier readreply(qp, Tcp, req, ibuf, mp, endtime) < 0) 12264e7b9544SDavid du Colombier rv = -1; 12273cbadd90SDavid du Colombier if (qp->tcpfd > 0) { 12283cbadd90SDavid du Colombier hangup(qp->tcpctlfd); 12293cbadd90SDavid du Colombier close(qp->tcpctlfd); 12303cbadd90SDavid du Colombier close(qp->tcpfd); 12313cbadd90SDavid du Colombier } 12323cbadd90SDavid du Colombier qp->tcpfd = qp->tcpctlfd = -1; 12333cbadd90SDavid du Colombier qunlock(&qp->tcplock); 12344e7b9544SDavid du Colombier return rv; 12353cbadd90SDavid du Colombier } 12363cbadd90SDavid du Colombier 12373cbadd90SDavid du Colombier /* 12383cbadd90SDavid du Colombier * query name servers. If the name server returns a pointer to another 12393cbadd90SDavid du Colombier * name server, recurse. 12403cbadd90SDavid du Colombier */ 12413cbadd90SDavid du Colombier static int 12424e5f5f32SDavid du Colombier queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, int waitsecs, int inns) 12433cbadd90SDavid du Colombier { 12443cbadd90SDavid du Colombier int ndest, len, replywaits, rv; 12453cbadd90SDavid du Colombier ushort req; 12463cbadd90SDavid du Colombier ulong endtime; 12473cbadd90SDavid du Colombier char buf[12]; 12483cbadd90SDavid du Colombier uchar srcip[IPaddrlen]; 1249a41547ffSDavid du Colombier Dest *p, *np, *dest; 1250a41547ffSDavid du Colombier // Dest dest[Maxdest]; 12513cbadd90SDavid du Colombier 12523cbadd90SDavid du Colombier /* pack request into a udp message */ 12533cbadd90SDavid du Colombier req = rand(); 12543cbadd90SDavid du Colombier len = mkreq(qp->dp, qp->type, obuf, Frecurse|Oquery, req); 12553cbadd90SDavid du Colombier 12563cbadd90SDavid du Colombier /* no server addresses yet */ 12573cbadd90SDavid du Colombier queryck(qp); 1258a41547ffSDavid du Colombier dest = emalloc(Maxdest * sizeof *dest); /* dest can't be on stack */ 1259a41547ffSDavid du Colombier for (p = dest; p < dest + Maxdest; p++) 12603cbadd90SDavid du Colombier destinit(p); 12611eb0187fSDavid du Colombier /* this dest array is local to this call of queryns() */ 12621eb0187fSDavid du Colombier free(qp->dest); 12633cbadd90SDavid du Colombier qp->curdest = qp->dest = dest; 12643cbadd90SDavid du Colombier 12653cbadd90SDavid du Colombier /* 12663cbadd90SDavid du Colombier * transmit udp requests and wait for answers. 12673cbadd90SDavid du Colombier * at most Maxtrans attempts to each address. 12683cbadd90SDavid du Colombier * each cycle send one more message than the previous. 12693cbadd90SDavid du Colombier * retry a query via tcp if its response is truncated. 12703cbadd90SDavid du Colombier */ 12713cbadd90SDavid du Colombier for(ndest = 1; ndest < Maxdest; ndest++){ 12723cbadd90SDavid du Colombier qp->ndest = ndest; 12733cbadd90SDavid du Colombier qp->tcpset = 0; 12743cbadd90SDavid du Colombier if (xmitquery(qp, Udp, depth, obuf, inns, len) < 0) 12753cbadd90SDavid du Colombier break; 12763cbadd90SDavid du Colombier 12773cbadd90SDavid du Colombier endtime = time(nil) + waitsecs; 12783cbadd90SDavid du Colombier if(endtime > qp->req->aborttime) 12793cbadd90SDavid du Colombier endtime = qp->req->aborttime; 12803cbadd90SDavid du Colombier 12813cbadd90SDavid du Colombier for(replywaits = 0; replywaits < ndest; replywaits++){ 128281730632SDavid du Colombier DNSmsg m; 128381730632SDavid du Colombier 1284f46c709fSDavid du Colombier procsetname("reading %sside reply from %I: %s %s from %s", 1285a41547ffSDavid du Colombier (inns? "in": "out"), obuf, qp->dp->name, 1286f46c709fSDavid du Colombier rrname(qp->type, buf, sizeof buf), qp->req->from); 12873cbadd90SDavid du Colombier 128881730632SDavid du Colombier /* read udp answer into m */ 12893cbadd90SDavid du Colombier if (readreply(qp, Udp, req, ibuf, &m, endtime) >= 0) 12903cbadd90SDavid du Colombier memmove(srcip, ibuf, IPaddrlen); 129181730632SDavid du Colombier else if (!(m.flags & Ftrunc)) { 129281730632SDavid du Colombier freeanswers(&m); 12933cbadd90SDavid du Colombier break; /* timed out on this dest */ 129481730632SDavid du Colombier } else { 12953cbadd90SDavid du Colombier /* whoops, it was truncated! ask again via tcp */ 12966aaebd7dSDavid du Colombier freeanswers(&m); 12973cbadd90SDavid du Colombier rv = tcpquery(qp, &m, depth, ibuf, obuf, len, 129881730632SDavid du Colombier waitsecs, inns, req); /* answer in m */ 129981730632SDavid du Colombier if (rv < 0) { 130081730632SDavid du Colombier freeanswers(&m); 13013cbadd90SDavid du Colombier break; /* failed via tcp too */ 130281730632SDavid du Colombier } 13033cbadd90SDavid du Colombier memmove(srcip, qp->tcpip, IPaddrlen); 13043cbadd90SDavid du Colombier } 13053cbadd90SDavid du Colombier 13063cbadd90SDavid du Colombier /* find responder */ 13074e5f5f32SDavid du Colombier // dnslog("queryns got reply from %I", srcip); 13083cbadd90SDavid du Colombier for(p = qp->dest; p < qp->curdest; p++) 13093cbadd90SDavid du Colombier if(memcmp(p->a, srcip, sizeof p->a) == 0) 13103cbadd90SDavid du Colombier break; 13113cbadd90SDavid du Colombier 13123cbadd90SDavid du Colombier /* remove all addrs of responding server from list */ 13133cbadd90SDavid du Colombier for(np = qp->dest; np < qp->curdest; np++) 13143cbadd90SDavid du Colombier if(np->s == p->s) 13153cbadd90SDavid du Colombier p->nx = Maxtrans; 13163cbadd90SDavid du Colombier 131781730632SDavid du Colombier /* free or incorporate RRs in m */ 13183cbadd90SDavid du Colombier rv = procansw(qp, &m, srcip, depth, p); 13191eb0187fSDavid du Colombier if (rv > 0) { 13201eb0187fSDavid du Colombier free(qp->dest); 13211eb0187fSDavid du Colombier qp->dest = qp->curdest = nil; /* prevent accidents */ 13223cbadd90SDavid du Colombier return rv; 13233e12c5d1SDavid du Colombier } 13243e12c5d1SDavid du Colombier } 13251eb0187fSDavid du Colombier } 13267dd7cddfSDavid du Colombier 13274f8f669cSDavid du Colombier /* if all servers returned failure, propagate it */ 13283cbadd90SDavid du Colombier qp->dp->respcode = Rserver; 13293cbadd90SDavid du Colombier for(p = dest; p < qp->curdest; p++) { 13303cbadd90SDavid du Colombier destck(p); 13317dd7cddfSDavid du Colombier if(p->code != Rserver) 13323cbadd90SDavid du Colombier qp->dp->respcode = 0; 13333cbadd90SDavid du Colombier p->magic = 0; /* prevent accidents */ 13343cbadd90SDavid du Colombier } 13354f8f669cSDavid du Colombier 13363cbadd90SDavid du Colombier // if (qp->dp->respcode) 13374e5f5f32SDavid du Colombier // dnslog("queryns setting Rserver for %s", qp->dp->name); 13387dd7cddfSDavid du Colombier 1339a41547ffSDavid du Colombier free(qp->dest); 13403cbadd90SDavid du Colombier qp->dest = qp->curdest = nil; /* prevent accidents */ 13413e12c5d1SDavid du Colombier return 0; 13423e12c5d1SDavid du Colombier } 13437dd7cddfSDavid du Colombier 13444f8f669cSDavid du Colombier /* 13454f8f669cSDavid du Colombier * run a command with a supplied fd as standard input 13464f8f669cSDavid du Colombier */ 13474f8f669cSDavid du Colombier char * 13484f8f669cSDavid du Colombier system(int fd, char *cmd) 134928a8a86bSDavid du Colombier { 13504f8f669cSDavid du Colombier int pid, p, i; 13514f8f669cSDavid du Colombier static Waitmsg msg; 13526b0d5c8bSDavid du Colombier 13534f8f669cSDavid du Colombier if((pid = fork()) == -1) 13544f8f669cSDavid du Colombier sysfatal("fork failed: %r"); 13554f8f669cSDavid du Colombier else if(pid == 0){ 13564f8f669cSDavid du Colombier dup(fd, 0); 13574f8f669cSDavid du Colombier close(fd); 13584f8f669cSDavid du Colombier for (i = 3; i < 200; i++) 13594f8f669cSDavid du Colombier close(i); /* don't leak fds */ 13604f8f669cSDavid du Colombier execl("/bin/rc", "rc", "-c", cmd, nil); 13614f8f669cSDavid du Colombier sysfatal("exec rc: %r"); 13624f8f669cSDavid du Colombier } 13634f8f669cSDavid du Colombier for(p = waitpid(); p >= 0; p = waitpid()) 13644f8f669cSDavid du Colombier if(p == pid) 13654f8f669cSDavid du Colombier return msg.msg; 13664f8f669cSDavid du Colombier return "lost child"; 13674f8f669cSDavid du Colombier } 13684f8f669cSDavid du Colombier 13690319257bSDavid du Colombier /* compute wait, weighted by probability of success, with minimum */ 13700319257bSDavid du Colombier static ulong 13710319257bSDavid du Colombier weight(ulong ms, unsigned pcntprob) 13720319257bSDavid du Colombier { 13730319257bSDavid du Colombier ulong wait; 13740319257bSDavid du Colombier 13750319257bSDavid du Colombier wait = (ms * pcntprob) / 100; 13760319257bSDavid du Colombier if (wait < 1500) 13770319257bSDavid du Colombier wait = 1500; 13780319257bSDavid du Colombier return wait; 13790319257bSDavid du Colombier } 13800319257bSDavid du Colombier 1381a41547ffSDavid du Colombier /* 1382a41547ffSDavid du Colombier * in principle we could use a single descriptor for a udp port 1383a41547ffSDavid du Colombier * to send all queries and receive all the answers to them, 1384a41547ffSDavid du Colombier * but we'd have to sort out the answers by dns-query id. 1385a41547ffSDavid du Colombier */ 13864f8f669cSDavid du Colombier static int 13873cbadd90SDavid du Colombier udpquery(Query *qp, char *mntpt, int depth, int patient, int inns) 13884f8f669cSDavid du Colombier { 13890319257bSDavid du Colombier int fd, rv; 13904f8f669cSDavid du Colombier long now; 13910319257bSDavid du Colombier ulong pcntprob, wait, reqtm; 13924f8f669cSDavid du Colombier char *msg; 13934f8f669cSDavid du Colombier uchar *obuf, *ibuf; 13944f8f669cSDavid du Colombier static QLock mntlck; 13954f8f669cSDavid du Colombier static ulong lastmount; 13967dd7cddfSDavid du Colombier 13977dd7cddfSDavid du Colombier /* use alloced buffers rather than ones from the stack */ 1398f27a9a5aSDavid du Colombier // ibuf = emalloc(Maxudpin+Udphdrsize); 13993cbadd90SDavid du Colombier ibuf = emalloc(64*1024); /* max. tcp reply size */ 1400f27a9a5aSDavid du Colombier obuf = emalloc(Maxudp+Udphdrsize); 14017dd7cddfSDavid du Colombier 14024f8f669cSDavid du Colombier fd = udpport(mntpt); 14034f8f669cSDavid du Colombier while (fd < 0 && cfg.straddle && strcmp(mntpt, "/net.alt") == 0) { 14044f8f669cSDavid du Colombier /* HACK: remount /net.alt */ 14054f8f669cSDavid du Colombier now = time(nil); 14064f8f669cSDavid du Colombier if (now < lastmount + Remntretry) 14074f8f669cSDavid du Colombier sleep((lastmount + Remntretry - now)*1000); 14084f8f669cSDavid du Colombier qlock(&mntlck); 14094f8f669cSDavid du Colombier fd = udpport(mntpt); /* try again under lock */ 14104f8f669cSDavid du Colombier if (fd < 0) { 14114f8f669cSDavid du Colombier dnslog("[%d] remounting /net.alt", getpid()); 14124f8f669cSDavid du Colombier unmount(nil, "/net.alt"); 14134f8f669cSDavid du Colombier 14144f8f669cSDavid du Colombier msg = system(open("/dev/null", ORDWR), "outside"); 14154f8f669cSDavid du Colombier 14164f8f669cSDavid du Colombier lastmount = time(nil); 14174f8f669cSDavid du Colombier if (msg && *msg) { 14184f8f669cSDavid du Colombier dnslog("[%d] can't remount /net.alt: %s", 14194f8f669cSDavid du Colombier getpid(), msg); 14204f8f669cSDavid du Colombier sleep(10*1000); /* don't spin wildly */ 14214f8f669cSDavid du Colombier } else 14224f8f669cSDavid du Colombier fd = udpport(mntpt); 14234f8f669cSDavid du Colombier } 14244f8f669cSDavid du Colombier qunlock(&mntlck); 14254f8f669cSDavid du Colombier } 1426a41547ffSDavid du Colombier if (fd < 0) { 14274f8f669cSDavid du Colombier dnslog("can't get udpport for %s query of name %s: %r", 14283cbadd90SDavid du Colombier mntpt, qp->dp->name); 1429a41547ffSDavid du Colombier sysfatal("out of udp conversations"); /* we're buggered */ 1430a41547ffSDavid du Colombier } 1431a41547ffSDavid du Colombier 1432a41547ffSDavid du Colombier /* 14330319257bSDavid du Colombier * Our QIP servers are busted, don't answer AAAA and 14340319257bSDavid du Colombier * take forever to answer CNAME if there isn't one. 14350319257bSDavid du Colombier * They rarely set Rname. 1436a41547ffSDavid du Colombier * make time-to-wait proportional to estimated probability of an 1437a41547ffSDavid du Colombier * RR of that type existing. 1438a41547ffSDavid du Colombier */ 1439adb31a62SDavid du Colombier if (qp->type >= nelem(likely)) 14400319257bSDavid du Colombier pcntprob = 35; /* unpopular query type */ 14410319257bSDavid du Colombier else 14420319257bSDavid du Colombier pcntprob = likely[qp->type]; 14430319257bSDavid du Colombier reqtm = (patient? 2*Maxreqtm: Maxreqtm); 14440319257bSDavid du Colombier /* time for a single outgoing udp query */ 14450319257bSDavid du Colombier wait = weight(S2MS(reqtm)/3, pcntprob); 14460319257bSDavid du Colombier qp->req->aborttime = time(nil) + MS2S(3*wait); /* for all udp queries */ 1447a41547ffSDavid du Colombier 14480319257bSDavid du Colombier qp->udpfd = fd; 14494e5f5f32SDavid du Colombier rv = queryns(qp, depth, ibuf, obuf, MS2S(wait), inns); 1450a41547ffSDavid du Colombier close(fd); 1451a41547ffSDavid du Colombier qp->udpfd = -1; 14524f8f669cSDavid du Colombier 14534f8f669cSDavid du Colombier free(obuf); 14544f8f669cSDavid du Colombier free(ibuf); 14554f8f669cSDavid du Colombier return rv; 14564f8f669cSDavid du Colombier } 14574f8f669cSDavid du Colombier 14584e5f5f32SDavid du Colombier /* look up (qp->dp->name,qp->type) rr in dns, via *nsrp with results in *reqp */ 14594f8f669cSDavid du Colombier static int 14603cbadd90SDavid du Colombier netquery(Query *qp, int depth) 14614f8f669cSDavid du Colombier { 1462225077b0SDavid du Colombier int lock, rv, triedin, inname, cnt; 1463225077b0SDavid du Colombier // char buf[32]; 14644f8f669cSDavid du Colombier RR *rp; 14654e153993SDavid du Colombier DN *dp; 1466225077b0SDavid du Colombier Querylck *qlp; 1467225077b0SDavid du Colombier static int whined; 14684f8f669cSDavid du Colombier 1469225077b0SDavid du Colombier rv = 0; /* pessimism */ 14704f8f669cSDavid du Colombier if(depth > 12) /* in a recursive loop? */ 14714f8f669cSDavid du Colombier return 0; 14724f8f669cSDavid du Colombier 14733cbadd90SDavid du Colombier slave(qp->req); 1474d3907fe5SDavid du Colombier /* 1475d3907fe5SDavid du Colombier * slave might have forked. if so, the parent process longjmped to 1476d3907fe5SDavid du Colombier * req->mret; we're usually the child slave, but if there are too 1477d3907fe5SDavid du Colombier * many children already, we're still the same process. 1478d3907fe5SDavid du Colombier */ 14794f8f669cSDavid du Colombier 14804e5f5f32SDavid du Colombier /* 14814e5f5f32SDavid du Colombier * don't lock before call to slave so only children can block. 14824e5f5f32SDavid du Colombier * just lock at top-level invocation. 14834e5f5f32SDavid du Colombier */ 1484225077b0SDavid du Colombier lock = depth <= 1 && qp->req->isslave; 14854e153993SDavid du Colombier dp = qp->dp; /* ensure that it doesn't change underfoot */ 1486225077b0SDavid du Colombier qlp = nil; 14874e5f5f32SDavid du Colombier if(lock) { 1488225077b0SDavid du Colombier // procsetname("query lock wait: %s %s from %s", dp->name, 1489225077b0SDavid du Colombier // rrname(qp->type, buf, sizeof buf), qp->req->from); 1490ccf6439bSDavid du Colombier /* 1491ccf6439bSDavid du Colombier * don't make concurrent queries for this name. 149281730632SDavid du Colombier * dozens of processes blocking here probably indicates 149381730632SDavid du Colombier * an error in our dns data that causes us to not 149481730632SDavid du Colombier * recognise a zone (area) as one of our own, thus 149581730632SDavid du Colombier * causing us to query other nameservers. 1496ccf6439bSDavid du Colombier */ 1497225077b0SDavid du Colombier qlp = &dp->querylck[qtype2lck(qp->type)]; 1498225077b0SDavid du Colombier incref(qlp); 1499225077b0SDavid du Colombier qlock(qlp); 1500225077b0SDavid du Colombier cnt = qlp->Ref.ref; 1501225077b0SDavid du Colombier qunlock(qlp); 1502225077b0SDavid du Colombier if (cnt > 10) { 1503225077b0SDavid du Colombier decref(qlp); 1504225077b0SDavid du Colombier if (!whined) { 1505225077b0SDavid du Colombier whined = 1; 1506225077b0SDavid du Colombier dnslog("too many outstanding queries for %s;" 1507*13fec586SDavid du Colombier " dropping this one; no further logging" 1508*13fec586SDavid du Colombier " of drops", dp->name); 1509225077b0SDavid du Colombier } 1510225077b0SDavid du Colombier return 0; 1511225077b0SDavid du Colombier } 1512225077b0SDavid du Colombier } 15134e153993SDavid du Colombier procsetname("netquery: %s", dp->name); 15146b0d5c8bSDavid du Colombier 15156b0d5c8bSDavid du Colombier /* prepare server RR's for incremental lookup */ 15163cbadd90SDavid du Colombier for(rp = qp->nsrp; rp; rp = rp->next) 15176b0d5c8bSDavid du Colombier rp->marker = 0; 15186b0d5c8bSDavid du Colombier 15194f8f669cSDavid du Colombier triedin = 0; 1520a41547ffSDavid du Colombier 15214f8f669cSDavid du Colombier /* 15224f8f669cSDavid du Colombier * normal resolvers and servers will just use mntpt for all addresses, 15234f8f669cSDavid du Colombier * even on the outside. straddling servers will use mntpt (/net) 15244f8f669cSDavid du Colombier * for inside addresses and /net.alt for outside addresses, 15254f8f669cSDavid du Colombier * thus bypassing other inside nameservers. 15264f8f669cSDavid du Colombier */ 15274e153993SDavid du Colombier inname = insideaddr(dp->name); 15284f8f669cSDavid du Colombier if (!cfg.straddle || inname) { 15293cbadd90SDavid du Colombier rv = udpquery(qp, mntpt, depth, Hurry, (cfg.inside? Inns: Outns)); 15304f8f669cSDavid du Colombier triedin = 1; 15314f8f669cSDavid du Colombier } 15324f8f669cSDavid du Colombier 15334f8f669cSDavid du Colombier /* 15344f8f669cSDavid du Colombier * if we're still looking, are inside, and have an outside domain, 15354f8f669cSDavid du Colombier * try it on our outside interface, if any. 15364f8f669cSDavid du Colombier */ 15374f8f669cSDavid du Colombier if (rv == 0 && cfg.inside && !inname) { 15384f8f669cSDavid du Colombier if (triedin) 15394f8f669cSDavid du Colombier dnslog( 15404f8f669cSDavid du Colombier "[%d] netquery: internal nameservers failed for %s; trying external", 15414e153993SDavid du Colombier getpid(), dp->name); 15424f8f669cSDavid du Colombier 15434f8f669cSDavid du Colombier /* prepare server RR's for incremental lookup */ 15443cbadd90SDavid du Colombier for(rp = qp->nsrp; rp; rp = rp->next) 15454f8f669cSDavid du Colombier rp->marker = 0; 15464f8f669cSDavid du Colombier 15473cbadd90SDavid du Colombier rv = udpquery(qp, "/net.alt", depth, Patient, Outns); 15484f8f669cSDavid du Colombier } 15493cbadd90SDavid du Colombier // if (rv == 0) /* could ask /net.alt/dns directly */ 15504e153993SDavid du Colombier // askoutdns(dp, qp->type); 15514f8f669cSDavid du Colombier 1552225077b0SDavid du Colombier if(lock && qlp) 1553225077b0SDavid du Colombier decref(qlp); 15547dd7cddfSDavid du Colombier return rv; 15557dd7cddfSDavid du Colombier } 15564f8f669cSDavid du Colombier 15574f8f669cSDavid du Colombier int 15584f8f669cSDavid du Colombier seerootns(void) 15594f8f669cSDavid du Colombier { 15603cbadd90SDavid du Colombier int rv; 15614f8f669cSDavid du Colombier char root[] = ""; 15624f8f669cSDavid du Colombier Request req; 1563c73252aeSDavid du Colombier Query *qp; 15644f8f669cSDavid du Colombier 15654f8f669cSDavid du Colombier memset(&req, 0, sizeof req); 15664f8f669cSDavid du Colombier req.isslave = 1; 1567ccf6439bSDavid du Colombier req.aborttime = now + Maxreqtm; 1568f46c709fSDavid du Colombier req.from = "internal"; 1569c73252aeSDavid du Colombier qp = emalloc(sizeof *qp); 1570c73252aeSDavid du Colombier queryinit(qp, dnlookup(root, Cin, 1), Tns, &req); 1571c73252aeSDavid du Colombier 1572c73252aeSDavid du Colombier qp->nsrp = dblookup(root, Cin, Tns, 0, 0); 1573c73252aeSDavid du Colombier rv = netquery(qp, 0); 1574c73252aeSDavid du Colombier 1575c73252aeSDavid du Colombier rrfreelist(qp->nsrp); 1576c73252aeSDavid du Colombier querydestroy(qp); 1577c73252aeSDavid du Colombier free(qp); 15783cbadd90SDavid du Colombier return rv; 15794f8f669cSDavid du Colombier } 1580