13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 3*28a8a86bSDavid du Colombier #include <ip.h> 4*28a8a86bSDavid du Colombier #include <bio.h> 5*28a8a86bSDavid du Colombier #include <ndb.h> 63e12c5d1SDavid du Colombier #include "dns.h" 73e12c5d1SDavid du Colombier 83e12c5d1SDavid du Colombier enum 93e12c5d1SDavid du Colombier { 107dd7cddfSDavid du Colombier Maxdest= 24, /* maximum destinations for a request message */ 113e12c5d1SDavid du Colombier Maxtrans= 3, /* maximum transmissions to a server */ 123e12c5d1SDavid du Colombier }; 133e12c5d1SDavid du Colombier 147dd7cddfSDavid du Colombier static int netquery(DN*, int, RR*, Request*, int); 157dd7cddfSDavid du Colombier static RR* dnresolve1(char*, int, int, Request*, int, int); 163e12c5d1SDavid du Colombier 177dd7cddfSDavid du Colombier char *LOG = "dns"; 183e12c5d1SDavid du Colombier 193e12c5d1SDavid du Colombier /* 205aa528faSDavid du Colombier * reading /proc/pid/args yields either "name" or "name [display args]", 215aa528faSDavid du Colombier * so return only display args, if any. 225aa528faSDavid du Colombier */ 235aa528faSDavid du Colombier static char * 245aa528faSDavid du Colombier procgetname(void) 255aa528faSDavid du Colombier { 265aa528faSDavid du Colombier int fd, n; 275aa528faSDavid du Colombier char *lp, *rp; 285aa528faSDavid du Colombier char buf[256]; 295aa528faSDavid du Colombier 305aa528faSDavid du Colombier snprint(buf, sizeof buf, "#p/%d/args", getpid()); 315aa528faSDavid du Colombier if((fd = open(buf, OREAD)) < 0) 325aa528faSDavid du Colombier return strdup(""); 335aa528faSDavid du Colombier *buf = '\0'; 345aa528faSDavid du Colombier n = read(fd, buf, sizeof buf-1); 355aa528faSDavid du Colombier close(fd); 365aa528faSDavid du Colombier if (n >= 0) 375aa528faSDavid du Colombier buf[n] = '\0'; 385aa528faSDavid du Colombier if ((lp = strchr(buf, '[')) == nil || 395aa528faSDavid du Colombier (rp = strrchr(buf, ']')) == nil) 405aa528faSDavid du Colombier return strdup(""); 415aa528faSDavid du Colombier *rp = '\0'; 425aa528faSDavid du Colombier return strdup(lp+1); 435aa528faSDavid du Colombier } 445aa528faSDavid du Colombier 455aa528faSDavid du Colombier /* 463e12c5d1SDavid du Colombier * lookup 'type' info for domain name 'name'. If it doesn't exist, try 473e12c5d1SDavid du Colombier * looking it up as a canonical name. 483e12c5d1SDavid du Colombier */ 493e12c5d1SDavid du Colombier RR* 505aa528faSDavid du Colombier dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, 515aa528faSDavid du Colombier int recurse, int rooted, int *status) 523e12c5d1SDavid du Colombier { 537dd7cddfSDavid du Colombier RR *rp, *nrp, *drp; 543e12c5d1SDavid du Colombier DN *dp; 557dd7cddfSDavid du Colombier int loops; 565aa528faSDavid du Colombier char *procname; 577dd7cddfSDavid du Colombier char nname[Domlen]; 583e12c5d1SDavid du Colombier 597dd7cddfSDavid du Colombier if(status) 607dd7cddfSDavid du Colombier *status = 0; 617dd7cddfSDavid du Colombier 625aa528faSDavid du Colombier procname = procgetname(); 637dd7cddfSDavid du Colombier /* 647dd7cddfSDavid du Colombier * hack for systems that don't have resolve search 657dd7cddfSDavid du Colombier * lists. Just look up the simple name in the database. 667dd7cddfSDavid du Colombier */ 677dd7cddfSDavid du Colombier if(!rooted && strchr(name, '.') == 0){ 687dd7cddfSDavid du Colombier rp = nil; 697dd7cddfSDavid du Colombier drp = domainlist(class); 707dd7cddfSDavid du Colombier for(nrp = drp; nrp != nil; nrp = nrp->next){ 715aa528faSDavid du Colombier snprint(nname, sizeof nname, "%s.%s", name, 725aa528faSDavid du Colombier nrp->ptr->name); 735aa528faSDavid du Colombier rp = dnresolve(nname, class, type, req, cn, depth, 745aa528faSDavid du Colombier recurse, rooted, status); 75271b8d73SDavid du Colombier rrfreelist(rrremneg(&rp)); 767dd7cddfSDavid du Colombier if(rp != nil) 777dd7cddfSDavid du Colombier break; 787dd7cddfSDavid du Colombier } 797dd7cddfSDavid du Colombier if(drp != nil) 807dd7cddfSDavid du Colombier rrfree(drp); 815aa528faSDavid du Colombier procsetname(procname); 825aa528faSDavid du Colombier free(procname); 833e12c5d1SDavid du Colombier return rp; 847dd7cddfSDavid du Colombier } 853e12c5d1SDavid du Colombier 867dd7cddfSDavid du Colombier /* 877dd7cddfSDavid du Colombier * try the name directly 887dd7cddfSDavid du Colombier */ 897dd7cddfSDavid du Colombier rp = dnresolve1(name, class, type, req, depth, recurse); 905aa528faSDavid du Colombier if(rp) { 915aa528faSDavid du Colombier procsetname(procname); 925aa528faSDavid du Colombier free(procname); 937dd7cddfSDavid du Colombier return randomize(rp); 945aa528faSDavid du Colombier } 957dd7cddfSDavid du Colombier 967dd7cddfSDavid du Colombier /* try it as a canonical name if we weren't told the name didn't exist */ 977dd7cddfSDavid du Colombier dp = dnlookup(name, class, 0); 985aa528faSDavid du Colombier if(type != Tptr && dp->nonexistent != Rname) 997dd7cddfSDavid du Colombier for(loops=0; rp == nil && loops < 32; loops++){ 1007dd7cddfSDavid du Colombier rp = dnresolve1(name, class, Tcname, req, depth, recurse); 1017dd7cddfSDavid du Colombier if(rp == nil) 1027dd7cddfSDavid du Colombier break; 10380ee5cbfSDavid du Colombier 10480ee5cbfSDavid du Colombier if(rp->negative){ 10580ee5cbfSDavid du Colombier rrfreelist(rp); 10680ee5cbfSDavid du Colombier rp = nil; 10780ee5cbfSDavid du Colombier break; 10880ee5cbfSDavid du Colombier } 1097dd7cddfSDavid du Colombier 1107dd7cddfSDavid du Colombier name = rp->host->name; 1117dd7cddfSDavid du Colombier if(cn) 1127dd7cddfSDavid du Colombier rrcat(cn, rp); 1137dd7cddfSDavid du Colombier else 1147dd7cddfSDavid du Colombier rrfreelist(rp); 1157dd7cddfSDavid du Colombier 1167dd7cddfSDavid du Colombier rp = dnresolve1(name, class, type, req, depth, recurse); 1177dd7cddfSDavid du Colombier } 1187dd7cddfSDavid du Colombier 1197dd7cddfSDavid du Colombier /* distinction between not found and not good */ 1205aa528faSDavid du Colombier if(rp == nil && status != nil && dp->nonexistent != 0) 1217dd7cddfSDavid du Colombier *status = dp->nonexistent; 1227dd7cddfSDavid du Colombier 1235aa528faSDavid du Colombier procsetname(procname); 1245aa528faSDavid du Colombier free(procname); 1257dd7cddfSDavid du Colombier return randomize(rp); 1263e12c5d1SDavid du Colombier } 1273e12c5d1SDavid du Colombier 1283e12c5d1SDavid du Colombier static RR* 1295aa528faSDavid du Colombier dnresolve1(char *name, int class, int type, Request *req, int depth, 1305aa528faSDavid du Colombier int recurse) 1313e12c5d1SDavid du Colombier { 1323e12c5d1SDavid du Colombier DN *dp, *nsdp; 1337dd7cddfSDavid du Colombier RR *rp, *nsrp, *dbnsrp; 1343e12c5d1SDavid du Colombier char *cp; 1353e12c5d1SDavid du Colombier 1367dd7cddfSDavid du Colombier if(debug) 1375aa528faSDavid du Colombier syslog(0, LOG, "[%d] dnresolve1 %s %d %d", 1385aa528faSDavid du Colombier getpid(), name, type, class); 1397dd7cddfSDavid du Colombier 1403e12c5d1SDavid du Colombier /* only class Cin implemented so far */ 1413e12c5d1SDavid du Colombier if(class != Cin) 1425aa528faSDavid du Colombier return nil; 1433e12c5d1SDavid du Colombier 1443e12c5d1SDavid du Colombier dp = dnlookup(name, class, 1); 1453e12c5d1SDavid du Colombier 1467dd7cddfSDavid du Colombier /* 1477dd7cddfSDavid du Colombier * Try the cache first 1487dd7cddfSDavid du Colombier */ 1497dd7cddfSDavid du Colombier rp = rrlookup(dp, type, OKneg); 1505aa528faSDavid du Colombier if(rp) 1517dd7cddfSDavid du Colombier if(rp->db){ 1527dd7cddfSDavid du Colombier /* unauthenticated db entries are hints */ 1537dd7cddfSDavid du Colombier if(rp->auth) 1543e12c5d1SDavid du Colombier return rp; 1555aa528faSDavid du Colombier } else 1567dd7cddfSDavid du Colombier /* cached entry must still be valid */ 1575aa528faSDavid du Colombier if(rp->ttl > now) 1587dd7cddfSDavid du Colombier /* but Tall entries are special */ 1597dd7cddfSDavid du Colombier if(type != Tall || rp->query == Tall) 1607dd7cddfSDavid du Colombier return rp; 1615aa528faSDavid du Colombier 1627dd7cddfSDavid du Colombier rrfreelist(rp); 1633e12c5d1SDavid du Colombier 1647dd7cddfSDavid du Colombier /* 1657dd7cddfSDavid du Colombier * try the cache for a canonical name. if found punt 1667dd7cddfSDavid du Colombier * since we'll find it during the canonical name search 1677dd7cddfSDavid du Colombier * in dnresolve(). 1687dd7cddfSDavid du Colombier */ 1697dd7cddfSDavid du Colombier if(type != Tcname){ 1707dd7cddfSDavid du Colombier rp = rrlookup(dp, Tcname, NOneg); 1717dd7cddfSDavid du Colombier rrfreelist(rp); 1723e12c5d1SDavid du Colombier if(rp) 1735aa528faSDavid du Colombier return nil; 1743e12c5d1SDavid du Colombier } 1753e12c5d1SDavid du Colombier 1763e12c5d1SDavid du Colombier /* 1777dd7cddfSDavid du Colombier * if we're running as just a resolver, go to our 1787dd7cddfSDavid du Colombier * designated name servers 179219b2ee8SDavid du Colombier */ 1807dd7cddfSDavid du Colombier if(resolver){ 1817dd7cddfSDavid du Colombier nsrp = randomize(getdnsservers(class)); 1827dd7cddfSDavid du Colombier if(nsrp != nil) { 1837dd7cddfSDavid du Colombier if(netquery(dp, type, nsrp, req, depth+1)){ 1847dd7cddfSDavid du Colombier rrfreelist(nsrp); 1857dd7cddfSDavid du Colombier return rrlookup(dp, type, OKneg); 1867dd7cddfSDavid du Colombier } 1877dd7cddfSDavid du Colombier rrfreelist(nsrp); 1887dd7cddfSDavid du Colombier } 189219b2ee8SDavid du Colombier } 190219b2ee8SDavid du Colombier 191219b2ee8SDavid du Colombier /* 1923e12c5d1SDavid du Colombier * walk up the domain name looking for 1933e12c5d1SDavid du Colombier * a name server for the domain. 1943e12c5d1SDavid du Colombier */ 1953e12c5d1SDavid du Colombier for(cp = name; cp; cp = walkup(cp)){ 1967dd7cddfSDavid du Colombier /* 1977dd7cddfSDavid du Colombier * if this is a local (served by us) domain, 1987dd7cddfSDavid du Colombier * return answer 1997dd7cddfSDavid du Colombier */ 2007dd7cddfSDavid du Colombier dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0)); 2017dd7cddfSDavid du Colombier if(dbnsrp && dbnsrp->local){ 2027dd7cddfSDavid du Colombier rp = dblookup(name, class, type, 1, dbnsrp->ttl); 2037dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 2047dd7cddfSDavid du Colombier return rp; 2057dd7cddfSDavid du Colombier } 2067dd7cddfSDavid du Colombier 2077dd7cddfSDavid du Colombier /* 2087dd7cddfSDavid du Colombier * if recursion isn't set, just accept local 2097dd7cddfSDavid du Colombier * entries 2107dd7cddfSDavid du Colombier */ 2117dd7cddfSDavid du Colombier if(recurse == Dontrecurse){ 2127dd7cddfSDavid du Colombier if(dbnsrp) 2137dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 2147dd7cddfSDavid du Colombier continue; 2157dd7cddfSDavid du Colombier } 2167dd7cddfSDavid du Colombier 2177dd7cddfSDavid du Colombier /* look for ns in cache */ 2183e12c5d1SDavid du Colombier nsdp = dnlookup(cp, class, 0); 2197dd7cddfSDavid du Colombier nsrp = nil; 2203e12c5d1SDavid du Colombier if(nsdp) 2217dd7cddfSDavid du Colombier nsrp = randomize(rrlookup(nsdp, Tns, NOneg)); 2227dd7cddfSDavid du Colombier 2237dd7cddfSDavid du Colombier /* if the entry timed out, ignore it */ 2247dd7cddfSDavid du Colombier if(nsrp && nsrp->ttl < now){ 2257dd7cddfSDavid du Colombier rrfreelist(nsrp); 2267dd7cddfSDavid du Colombier nsrp = nil; 2277dd7cddfSDavid du Colombier } 2283e12c5d1SDavid du Colombier 2293e12c5d1SDavid du Colombier if(nsrp){ 2307dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 2317dd7cddfSDavid du Colombier 2327dd7cddfSDavid du Colombier /* try the name servers found in cache */ 2337dd7cddfSDavid du Colombier if(netquery(dp, type, nsrp, req, depth+1)){ 2343e12c5d1SDavid du Colombier rrfreelist(nsrp); 2357dd7cddfSDavid du Colombier return rrlookup(dp, type, OKneg); 2367dd7cddfSDavid du Colombier } 2377dd7cddfSDavid du Colombier rrfreelist(nsrp); 2387dd7cddfSDavid du Colombier continue; 2393e12c5d1SDavid du Colombier } 2403e12c5d1SDavid du Colombier 2417dd7cddfSDavid du Colombier /* use ns from db */ 2427dd7cddfSDavid du Colombier if(dbnsrp){ 2437dd7cddfSDavid du Colombier /* try the name servers found in db */ 2447dd7cddfSDavid du Colombier if(netquery(dp, type, dbnsrp, req, depth+1)){ 2453e12c5d1SDavid du Colombier /* we got an answer */ 2467dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 2477dd7cddfSDavid du Colombier return rrlookup(dp, type, NOneg); 2483e12c5d1SDavid du Colombier } 2497dd7cddfSDavid du Colombier rrfreelist(dbnsrp); 2503e12c5d1SDavid du Colombier } 2513e12c5d1SDavid du Colombier } 2523e12c5d1SDavid du Colombier 2537dd7cddfSDavid du Colombier /* settle for a non-authoritative answer */ 2547dd7cddfSDavid du Colombier rp = rrlookup(dp, type, OKneg); 2557dd7cddfSDavid du Colombier if(rp) 2567dd7cddfSDavid du Colombier return rp; 2577dd7cddfSDavid du Colombier 2587dd7cddfSDavid du Colombier /* noone answered. try the database, we might have a chance. */ 2597dd7cddfSDavid du Colombier return dblookup(name, class, type, 0, 0); 2603e12c5d1SDavid du Colombier } 2613e12c5d1SDavid du Colombier 2623e12c5d1SDavid du Colombier /* 2635aa528faSDavid du Colombier * walk a domain name one element to the right. 2645aa528faSDavid du Colombier * return a pointer to that element. 2653e12c5d1SDavid du Colombier * in other words, return a pointer to the parent domain name. 2663e12c5d1SDavid du Colombier */ 2673e12c5d1SDavid du Colombier char* 2683e12c5d1SDavid du Colombier walkup(char *name) 2693e12c5d1SDavid du Colombier { 2703e12c5d1SDavid du Colombier char *cp; 2713e12c5d1SDavid du Colombier 2723e12c5d1SDavid du Colombier cp = strchr(name, '.'); 2733e12c5d1SDavid du Colombier if(cp) 2743e12c5d1SDavid du Colombier return cp+1; 2753e12c5d1SDavid du Colombier else if(*name) 2763e12c5d1SDavid du Colombier return ""; 2773e12c5d1SDavid du Colombier else 2783e12c5d1SDavid du Colombier return 0; 2793e12c5d1SDavid du Colombier } 2803e12c5d1SDavid du Colombier 2813e12c5d1SDavid du Colombier /* 2823e12c5d1SDavid du Colombier * Get a udpport for requests and replies. Put the port 2833e12c5d1SDavid du Colombier * into "headers" mode. 2843e12c5d1SDavid du Colombier */ 2853e12c5d1SDavid du Colombier static char *hmsg = "headers"; 2861e8349ebSDavid du Colombier static char *ohmsg = "oldheaders"; 2873e12c5d1SDavid du Colombier 288dc5a79c1SDavid du Colombier int 289*28a8a86bSDavid du Colombier udpport(char *mtpt) 2903e12c5d1SDavid du Colombier { 2913e12c5d1SDavid du Colombier int fd, ctl; 2925aa528faSDavid du Colombier char ds[64], adir[64]; 2933e12c5d1SDavid du Colombier 2943e12c5d1SDavid du Colombier /* get a udp port */ 295*28a8a86bSDavid du Colombier snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt? mtpt: "/net")); 2967dd7cddfSDavid du Colombier ctl = announce(ds, adir); 2977dd7cddfSDavid du Colombier if(ctl < 0){ 2987dd7cddfSDavid du Colombier /* warning("can't get udp port"); */ 299bd389b36SDavid du Colombier return -1; 300bd389b36SDavid du Colombier } 3013e12c5d1SDavid du Colombier 3023e12c5d1SDavid du Colombier /* turn on header style interface */ 303bd389b36SDavid du Colombier if(write(ctl, hmsg, strlen(hmsg)) , 0){ 3047dd7cddfSDavid du Colombier close(ctl); 305bd389b36SDavid du Colombier warning(hmsg); 306bd389b36SDavid du Colombier return -1; 307bd389b36SDavid du Colombier } 3081e8349ebSDavid du Colombier write(ctl, ohmsg, strlen(ohmsg)); 3093e12c5d1SDavid du Colombier 3107dd7cddfSDavid du Colombier /* grab the data file */ 311*28a8a86bSDavid du Colombier snprint(ds, sizeof ds, "%s/data", adir); 3127dd7cddfSDavid du Colombier fd = open(ds, ORDWR); 3133e12c5d1SDavid du Colombier close(ctl); 3145aa528faSDavid du Colombier if(fd < 0) 315*28a8a86bSDavid du Colombier warning("can't open udp port %s: %r", ds); 3163e12c5d1SDavid du Colombier return fd; 3173e12c5d1SDavid du Colombier } 3183e12c5d1SDavid du Colombier 319dc5a79c1SDavid du Colombier int 320dc5a79c1SDavid du Colombier mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno) 3213e12c5d1SDavid du Colombier { 3223e12c5d1SDavid du Colombier DNSmsg m; 3233e12c5d1SDavid du Colombier int len; 324d9dc5dd1SDavid du Colombier OUdphdr *uh = (OUdphdr*)buf; 3253e12c5d1SDavid du Colombier 3263e12c5d1SDavid du Colombier /* stuff port number into output buffer */ 3277dd7cddfSDavid du Colombier memset(uh, 0, sizeof(*uh)); 3287dd7cddfSDavid du Colombier hnputs(uh->rport, 53); 3293e12c5d1SDavid du Colombier 3303e12c5d1SDavid du Colombier /* make request and convert it to output format */ 3313e12c5d1SDavid du Colombier memset(&m, 0, sizeof(m)); 332dc5a79c1SDavid du Colombier m.flags = flags; 3333e12c5d1SDavid du Colombier m.id = reqno; 3343e12c5d1SDavid du Colombier m.qd = rralloc(type); 3353e12c5d1SDavid du Colombier m.qd->owner = dp; 3363e12c5d1SDavid du Colombier m.qd->type = type; 337d9dc5dd1SDavid du Colombier len = convDNS2M(&m, &buf[OUdphdrsize], Maxudp); 3383e12c5d1SDavid du Colombier if(len < 0) 3395aa528faSDavid du Colombier abort(); /* "can't convert" */ 3407dd7cddfSDavid du Colombier rrfree(m.qd); 3413e12c5d1SDavid du Colombier return len; 3423e12c5d1SDavid du Colombier } 3433e12c5d1SDavid du Colombier 3447dd7cddfSDavid du Colombier /* for alarms in readreply */ 3453e12c5d1SDavid du Colombier static void 3463e12c5d1SDavid du Colombier ding(void *x, char *msg) 3473e12c5d1SDavid du Colombier { 3483e12c5d1SDavid du Colombier USED(x); 3493e12c5d1SDavid du Colombier if(strcmp(msg, "alarm") == 0) 3503e12c5d1SDavid du Colombier noted(NCONT); 3513e12c5d1SDavid du Colombier else 3523e12c5d1SDavid du Colombier noted(NDFLT); 3533e12c5d1SDavid du Colombier } 3547dd7cddfSDavid du Colombier 3557dd7cddfSDavid du Colombier static void 3567dd7cddfSDavid du Colombier freeanswers(DNSmsg *mp) 3573e12c5d1SDavid du Colombier { 3587dd7cddfSDavid du Colombier rrfreelist(mp->qd); 3597dd7cddfSDavid du Colombier rrfreelist(mp->an); 3607dd7cddfSDavid du Colombier rrfreelist(mp->ns); 3617dd7cddfSDavid du Colombier rrfreelist(mp->ar); 3625aa528faSDavid du Colombier mp->qd = mp->an = mp->ns = mp->ar = nil; 3637dd7cddfSDavid du Colombier } 3647dd7cddfSDavid du Colombier 3657dd7cddfSDavid du Colombier /* 3665aa528faSDavid du Colombier * read replies to a request. ignore any of the wrong type. 3675aa528faSDavid du Colombier * wait at most 5 seconds. 3687dd7cddfSDavid du Colombier */ 3697dd7cddfSDavid du Colombier static int 3707dd7cddfSDavid du Colombier readreply(int fd, DN *dp, int type, ushort req, 3717dd7cddfSDavid du Colombier uchar *ibuf, DNSmsg *mp, ulong endtime, Request *reqp) 3727dd7cddfSDavid du Colombier { 3737dd7cddfSDavid du Colombier char *err; 3747dd7cddfSDavid du Colombier int len; 3757dd7cddfSDavid du Colombier ulong now; 3763e12c5d1SDavid du Colombier RR *rp; 3777dd7cddfSDavid du Colombier 3787dd7cddfSDavid du Colombier notify(ding); 3797dd7cddfSDavid du Colombier 3807dd7cddfSDavid du Colombier for(; ; freeanswers(mp)){ 3817dd7cddfSDavid du Colombier now = time(0); 3827dd7cddfSDavid du Colombier if(now >= endtime) 3837dd7cddfSDavid du Colombier return -1; /* timed out */ 3847dd7cddfSDavid du Colombier 3857dd7cddfSDavid du Colombier /* timed read */ 38659cc4ca5SDavid du Colombier alarm((endtime - now) * 1000); 387d9dc5dd1SDavid du Colombier len = read(fd, ibuf, OUdphdrsize+Maxudpin); 3887dd7cddfSDavid du Colombier alarm(0); 389d9dc5dd1SDavid du Colombier len -= OUdphdrsize; 3907dd7cddfSDavid du Colombier if(len < 0) 3917dd7cddfSDavid du Colombier return -1; /* timed out */ 3927dd7cddfSDavid du Colombier 3937dd7cddfSDavid du Colombier /* convert into internal format */ 3947dd7cddfSDavid du Colombier memset(mp, 0, sizeof(*mp)); 3955aa528faSDavid du Colombier err = convM2DNS(&ibuf[OUdphdrsize], len, mp, nil); 3967dd7cddfSDavid du Colombier if(err){ 3975aa528faSDavid du Colombier syslog(0, LOG, "input err: %s: %I", err, ibuf); 3987dd7cddfSDavid du Colombier continue; 3997dd7cddfSDavid du Colombier } 4007dd7cddfSDavid du Colombier if(debug) 4017dd7cddfSDavid du Colombier logreply(reqp->id, ibuf, mp); 4027dd7cddfSDavid du Colombier 4037dd7cddfSDavid du Colombier /* answering the right question? */ 4047dd7cddfSDavid du Colombier if(mp->id != req){ 4057dd7cddfSDavid du Colombier syslog(0, LOG, "%d: id %d instead of %d: %I", reqp->id, 4067dd7cddfSDavid du Colombier mp->id, req, ibuf); 4077dd7cddfSDavid du Colombier continue; 4087dd7cddfSDavid du Colombier } 4097dd7cddfSDavid du Colombier if(mp->qd == 0){ 4107dd7cddfSDavid du Colombier syslog(0, LOG, "%d: no question RR: %I", reqp->id, ibuf); 4117dd7cddfSDavid du Colombier continue; 4127dd7cddfSDavid du Colombier } 4137dd7cddfSDavid du Colombier if(mp->qd->owner != dp){ 4145aa528faSDavid du Colombier syslog(0, LOG, "%d: owner %s instead of %s: %I", 4155aa528faSDavid du Colombier reqp->id, mp->qd->owner->name, dp->name, ibuf); 4167dd7cddfSDavid du Colombier continue; 4177dd7cddfSDavid du Colombier } 4187dd7cddfSDavid du Colombier if(mp->qd->type != type){ 4195aa528faSDavid du Colombier syslog(0, LOG, "%d: type %d instead of %d: %I", 4205aa528faSDavid du Colombier reqp->id, mp->qd->type, type, ibuf); 4217dd7cddfSDavid du Colombier continue; 4227dd7cddfSDavid du Colombier } 4237dd7cddfSDavid du Colombier 4247dd7cddfSDavid du Colombier /* remember what request this is in answer to */ 4257dd7cddfSDavid du Colombier for(rp = mp->an; rp; rp = rp->next) 4267dd7cddfSDavid du Colombier rp->query = type; 4277dd7cddfSDavid du Colombier 4287dd7cddfSDavid du Colombier return 0; 4297dd7cddfSDavid du Colombier } 4307dd7cddfSDavid du Colombier } 4317dd7cddfSDavid du Colombier 4327dd7cddfSDavid du Colombier /* 4337dd7cddfSDavid du Colombier * return non-0 if first list includes second list 4347dd7cddfSDavid du Colombier */ 4357dd7cddfSDavid du Colombier int 4367dd7cddfSDavid du Colombier contains(RR *rp1, RR *rp2) 4377dd7cddfSDavid du Colombier { 4387dd7cddfSDavid du Colombier RR *trp1, *trp2; 4397dd7cddfSDavid du Colombier 4407dd7cddfSDavid du Colombier for(trp2 = rp2; trp2; trp2 = trp2->next){ 4417dd7cddfSDavid du Colombier for(trp1 = rp1; trp1; trp1 = trp1->next){ 4427dd7cddfSDavid du Colombier if(trp1->type == trp2->type) 4437dd7cddfSDavid du Colombier if(trp1->host == trp2->host) 4447dd7cddfSDavid du Colombier if(trp1->owner == trp2->owner) 4457dd7cddfSDavid du Colombier break; 4467dd7cddfSDavid du Colombier } 4475aa528faSDavid du Colombier if(trp1 == nil) 4487dd7cddfSDavid du Colombier return 0; 4497dd7cddfSDavid du Colombier } 4507dd7cddfSDavid du Colombier return 1; 4517dd7cddfSDavid du Colombier } 4527dd7cddfSDavid du Colombier 4537dd7cddfSDavid du Colombier 4547dd7cddfSDavid du Colombier typedef struct Dest Dest; 4557dd7cddfSDavid du Colombier struct Dest 4567dd7cddfSDavid du Colombier { 4577dd7cddfSDavid du Colombier uchar a[IPaddrlen]; /* ip address */ 4587dd7cddfSDavid du Colombier DN *s; /* name server */ 4597dd7cddfSDavid du Colombier int nx; /* number of transmissions */ 4607dd7cddfSDavid du Colombier int code; 4617dd7cddfSDavid du Colombier }; 4627dd7cddfSDavid du Colombier 4636b6b9ac8SDavid du Colombier 4646b6b9ac8SDavid du Colombier /* 4656b6b9ac8SDavid du Colombier * return multicast version if any 4666b6b9ac8SDavid du Colombier */ 4676b6b9ac8SDavid du Colombier int 4686b6b9ac8SDavid du Colombier ipisbm(uchar *ip) 4696b6b9ac8SDavid du Colombier { 4706b6b9ac8SDavid du Colombier if(isv4(ip)){ 4715aa528faSDavid du Colombier if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 || 4725aa528faSDavid du Colombier ipcmp(ip, IPv4bcast) == 0) 4736b6b9ac8SDavid du Colombier return 4; 4745aa528faSDavid du Colombier } else 4756b6b9ac8SDavid du Colombier if(ip[0] == 0xff) 4766b6b9ac8SDavid du Colombier return 6; 4776b6b9ac8SDavid du Colombier return 0; 4786b6b9ac8SDavid du Colombier } 4796b6b9ac8SDavid du Colombier 480*28a8a86bSDavid du Colombier static Ndbtuple *indoms, *innmsrvs, *outnmsrvs; 481*28a8a86bSDavid du Colombier static QLock readlock; 482*28a8a86bSDavid du Colombier 483*28a8a86bSDavid du Colombier /* 484*28a8a86bSDavid du Colombier * is this domain (or DOMAIN or Domain or dOMAIN) 485*28a8a86bSDavid du Colombier * internal to our organisation (behind our firewall)? 486*28a8a86bSDavid du Colombier */ 487*28a8a86bSDavid du Colombier static int 488*28a8a86bSDavid du Colombier insideaddr(char *dom) 489*28a8a86bSDavid du Colombier { 490*28a8a86bSDavid du Colombier int domlen, vallen; 491*28a8a86bSDavid du Colombier Ndb *db; 492*28a8a86bSDavid du Colombier Ndbs s; 493*28a8a86bSDavid du Colombier Ndbtuple *t; 494*28a8a86bSDavid du Colombier 495*28a8a86bSDavid du Colombier if (0 && indoms == nil) { /* not ready for prime time */ 496*28a8a86bSDavid du Colombier db = ndbopen("/lib/ndb/local"); 497*28a8a86bSDavid du Colombier if (db != nil) { 498*28a8a86bSDavid du Colombier qlock(&readlock); 499*28a8a86bSDavid du Colombier if (indoms == nil) { /* retest under lock */ 500*28a8a86bSDavid du Colombier free(ndbgetvalue(db, &s, "sys", "inside-dom", 501*28a8a86bSDavid du Colombier "dom", &indoms)); 502*28a8a86bSDavid du Colombier free(ndbgetvalue(db, &s, "sys", "inside-ns", 503*28a8a86bSDavid du Colombier "ip", &innmsrvs)); 504*28a8a86bSDavid du Colombier free(ndbgetvalue(db, &s, "sys", "outside-ns", 505*28a8a86bSDavid du Colombier "ip", &outnmsrvs)); 506*28a8a86bSDavid du Colombier } 507*28a8a86bSDavid du Colombier qunlock(&readlock); 508*28a8a86bSDavid du Colombier ndbclose(db); /* destroys *indoms, *innmsrvs? */ 509*28a8a86bSDavid du Colombier } 510*28a8a86bSDavid du Colombier } 511*28a8a86bSDavid du Colombier if (indoms == nil) 512*28a8a86bSDavid du Colombier return 1; /* no "inside" sys, try inside nameservers */ 513*28a8a86bSDavid du Colombier 514*28a8a86bSDavid du Colombier domlen = strlen(dom); 515*28a8a86bSDavid du Colombier for (t = indoms; t != nil; t = t->entry) { 516*28a8a86bSDavid du Colombier if (strcmp(t->attr, "dom") != 0) 517*28a8a86bSDavid du Colombier continue; 518*28a8a86bSDavid du Colombier vallen = strlen(t->val); 519*28a8a86bSDavid du Colombier if (cistrcmp(dom, t->val) == 0 || 520*28a8a86bSDavid du Colombier domlen > vallen && 521*28a8a86bSDavid du Colombier cistrcmp(dom + domlen - vallen, t->val) == 0 && 522*28a8a86bSDavid du Colombier dom[domlen - vallen - 1] == '.') 523*28a8a86bSDavid du Colombier return 1; 524*28a8a86bSDavid du Colombier } 525*28a8a86bSDavid du Colombier return 0; 526*28a8a86bSDavid du Colombier } 527*28a8a86bSDavid du Colombier 528*28a8a86bSDavid du Colombier static int 529*28a8a86bSDavid du Colombier insidens(uchar *ip) 530*28a8a86bSDavid du Colombier { 531*28a8a86bSDavid du Colombier uchar ipa[IPaddrlen]; 532*28a8a86bSDavid du Colombier Ndbtuple *t; 533*28a8a86bSDavid du Colombier 534*28a8a86bSDavid du Colombier for (t = innmsrvs; t != nil; t = t->entry) 535*28a8a86bSDavid du Colombier if (strcmp(t->attr, "ip") == 0) { 536*28a8a86bSDavid du Colombier parseip(ipa, t->val); 537*28a8a86bSDavid du Colombier if (memcmp(ipa, ip, sizeof ipa) == 0) 538*28a8a86bSDavid du Colombier return 1; 539*28a8a86bSDavid du Colombier } 540*28a8a86bSDavid du Colombier return 0; 541*28a8a86bSDavid du Colombier } 542*28a8a86bSDavid du Colombier 543*28a8a86bSDavid du Colombier static uchar * 544*28a8a86bSDavid du Colombier outsidens(void) 545*28a8a86bSDavid du Colombier { 546*28a8a86bSDavid du Colombier Ndbtuple *t; 547*28a8a86bSDavid du Colombier static uchar ipa[IPaddrlen]; 548*28a8a86bSDavid du Colombier 549*28a8a86bSDavid du Colombier for (t = outnmsrvs; t != nil; t = t->entry) 550*28a8a86bSDavid du Colombier if (strcmp(t->attr, "ip") == 0) { 551*28a8a86bSDavid du Colombier parseip(ipa, t->val); 552*28a8a86bSDavid du Colombier return ipa; 553*28a8a86bSDavid du Colombier } 554*28a8a86bSDavid du Colombier return nil; 555*28a8a86bSDavid du Colombier } 556*28a8a86bSDavid du Colombier 5577dd7cddfSDavid du Colombier /* 5587dd7cddfSDavid du Colombier * Get next server address 5597dd7cddfSDavid du Colombier */ 5607dd7cddfSDavid du Colombier static int 561*28a8a86bSDavid du Colombier serveraddrs(DN *dp, RR *nsrp, Dest *dest, int nd, int depth, Request *reqp) 5627dd7cddfSDavid du Colombier { 5637dd7cddfSDavid du Colombier RR *rp, *arp, *trp; 5647dd7cddfSDavid du Colombier Dest *cur; 5657dd7cddfSDavid du Colombier 5667dd7cddfSDavid du Colombier if(nd >= Maxdest) 5677dd7cddfSDavid du Colombier return 0; 5687dd7cddfSDavid du Colombier 5697dd7cddfSDavid du Colombier /* 5707dd7cddfSDavid du Colombier * look for a server whose address we already know. 5717dd7cddfSDavid du Colombier * if we find one, mark it so we ignore this on 5727dd7cddfSDavid du Colombier * subsequent passes. 5737dd7cddfSDavid du Colombier */ 5747dd7cddfSDavid du Colombier arp = 0; 5757dd7cddfSDavid du Colombier for(rp = nsrp; rp; rp = rp->next){ 57634f77ae3SDavid du Colombier assert(rp->magic == RRmagic); 5777dd7cddfSDavid du Colombier if(rp->marker) 5787dd7cddfSDavid du Colombier continue; 5797dd7cddfSDavid du Colombier arp = rrlookup(rp->host, Ta, NOneg); 5807dd7cddfSDavid du Colombier if(arp){ 5817dd7cddfSDavid du Colombier rp->marker = 1; 5827dd7cddfSDavid du Colombier break; 5837dd7cddfSDavid du Colombier } 5847dd7cddfSDavid du Colombier arp = dblookup(rp->host->name, Cin, Ta, 0, 0); 5857dd7cddfSDavid du Colombier if(arp){ 5867dd7cddfSDavid du Colombier rp->marker = 1; 5877dd7cddfSDavid du Colombier break; 5887dd7cddfSDavid du Colombier } 5897dd7cddfSDavid du Colombier } 5907dd7cddfSDavid du Colombier 5917dd7cddfSDavid du Colombier /* 5927dd7cddfSDavid du Colombier * if the cache and database lookup didn't find any new 5937dd7cddfSDavid du Colombier * server addresses, try resolving one via the network. 5947dd7cddfSDavid du Colombier * Mark any we try to resolve so we don't try a second time. 5957dd7cddfSDavid du Colombier */ 5965aa528faSDavid du Colombier if(arp == 0) 5977dd7cddfSDavid du Colombier for(rp = nsrp; rp; rp = rp->next){ 5987dd7cddfSDavid du Colombier if(rp->marker) 5997dd7cddfSDavid du Colombier continue; 6007dd7cddfSDavid du Colombier rp->marker = 1; 6017dd7cddfSDavid du Colombier 6027dd7cddfSDavid du Colombier /* 6037dd7cddfSDavid du Colombier * avoid loops looking up a server under itself 6047dd7cddfSDavid du Colombier */ 6057dd7cddfSDavid du Colombier if(subsume(rp->owner->name, rp->host->name)) 6067dd7cddfSDavid du Colombier continue; 6077dd7cddfSDavid du Colombier 6085aa528faSDavid du Colombier arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0, 6095aa528faSDavid du Colombier depth+1, Recurse, 1, 0); 6107dd7cddfSDavid du Colombier rrfreelist(rrremneg(&arp)); 6117dd7cddfSDavid du Colombier if(arp) 6127dd7cddfSDavid du Colombier break; 6137dd7cddfSDavid du Colombier } 6147dd7cddfSDavid du Colombier 6157dd7cddfSDavid du Colombier /* use any addresses that we found */ 6167dd7cddfSDavid du Colombier for(trp = arp; trp; trp = trp->next){ 6177dd7cddfSDavid du Colombier if(nd >= Maxdest) 6187dd7cddfSDavid du Colombier break; 6196b6b9ac8SDavid du Colombier cur = &dest[nd]; 6207dd7cddfSDavid du Colombier parseip(cur->a, trp->ip->name); 621*28a8a86bSDavid du Colombier if (ipisbm(cur->a) || 622*28a8a86bSDavid du Colombier !insideaddr(dp->name) && insidens(cur->a)) 6236b6b9ac8SDavid du Colombier continue; 6247dd7cddfSDavid du Colombier cur->nx = 0; 6257dd7cddfSDavid du Colombier cur->s = trp->owner; 6267dd7cddfSDavid du Colombier cur->code = Rtimeout; 6276b6b9ac8SDavid du Colombier nd++; 6287dd7cddfSDavid du Colombier } 6297dd7cddfSDavid du Colombier rrfreelist(arp); 6307dd7cddfSDavid du Colombier return nd; 6317dd7cddfSDavid du Colombier } 6327dd7cddfSDavid du Colombier 6337dd7cddfSDavid du Colombier /* 6347dd7cddfSDavid du Colombier * cache negative responses 6357dd7cddfSDavid du Colombier */ 6367dd7cddfSDavid du Colombier static void 6377dd7cddfSDavid du Colombier cacheneg(DN *dp, int type, int rcode, RR *soarr) 6387dd7cddfSDavid du Colombier { 6397dd7cddfSDavid du Colombier RR *rp; 6407dd7cddfSDavid du Colombier DN *soaowner; 6419a747e4fSDavid du Colombier ulong ttl; 6427dd7cddfSDavid du Colombier 6435aa528faSDavid du Colombier /* no cache time specified, don't make anything up */ 6447dd7cddfSDavid du Colombier if(soarr != nil){ 6457dd7cddfSDavid du Colombier if(soarr->next != nil){ 6467dd7cddfSDavid du Colombier rrfreelist(soarr->next); 6477dd7cddfSDavid du Colombier soarr->next = nil; 6487dd7cddfSDavid du Colombier } 6497dd7cddfSDavid du Colombier soaowner = soarr->owner; 6507dd7cddfSDavid du Colombier } else 6517dd7cddfSDavid du Colombier soaowner = nil; 6527dd7cddfSDavid du Colombier 6539a747e4fSDavid du Colombier /* the attach can cause soarr to be freed so mine it now */ 6549a747e4fSDavid du Colombier if(soarr != nil && soarr->soa != nil) 6559a747e4fSDavid du Colombier ttl = soarr->soa->minttl+now; 6569a747e4fSDavid du Colombier else 6579a747e4fSDavid du Colombier ttl = 5*Min; 6589a747e4fSDavid du Colombier 6597dd7cddfSDavid du Colombier /* add soa and negative RR to the database */ 6607dd7cddfSDavid du Colombier rrattach(soarr, 1); 6617dd7cddfSDavid du Colombier 6627dd7cddfSDavid du Colombier rp = rralloc(type); 6637dd7cddfSDavid du Colombier rp->owner = dp; 6647dd7cddfSDavid du Colombier rp->negative = 1; 6657dd7cddfSDavid du Colombier rp->negsoaowner = soaowner; 6667dd7cddfSDavid du Colombier rp->negrcode = rcode; 6679a747e4fSDavid du Colombier rp->ttl = ttl; 6687dd7cddfSDavid du Colombier rrattach(rp, 1); 6697dd7cddfSDavid du Colombier } 6707dd7cddfSDavid du Colombier 6717dd7cddfSDavid du Colombier /* 6727dd7cddfSDavid du Colombier * query name servers. If the name server returns a pointer to another 6737dd7cddfSDavid du Colombier * name server, recurse. 6747dd7cddfSDavid du Colombier */ 6757dd7cddfSDavid du Colombier static int 6765aa528faSDavid du Colombier netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, 677*28a8a86bSDavid du Colombier uchar *ibuf, uchar *obuf, int waitsecs, int inns) 6787dd7cddfSDavid du Colombier { 6797dd7cddfSDavid du Colombier int ndest, j, len, replywaits, rv; 6807dd7cddfSDavid du Colombier ulong endtime; 6815aa528faSDavid du Colombier ushort req; 6825aa528faSDavid du Colombier char buf[12]; 6835aa528faSDavid du Colombier DN *ndp; 6845aa528faSDavid du Colombier DNSmsg m; 6855aa528faSDavid du Colombier Dest *p, *l, *np; 6865aa528faSDavid du Colombier Dest dest[Maxdest]; 6875aa528faSDavid du Colombier RR *tp, *soarr; 6883e12c5d1SDavid du Colombier 6893e12c5d1SDavid du Colombier /* pack request into a message */ 6907dd7cddfSDavid du Colombier req = rand(); 691dc5a79c1SDavid du Colombier len = mkreq(dp, type, obuf, Frecurse|Oquery, req); 6923e12c5d1SDavid du Colombier 6937dd7cddfSDavid du Colombier /* no server addresses yet */ 6947dd7cddfSDavid du Colombier l = dest; 6957dd7cddfSDavid du Colombier 6963e12c5d1SDavid du Colombier /* 6973e12c5d1SDavid du Colombier * transmit requests and wait for answers. 698219b2ee8SDavid du Colombier * at most Maxtrans attempts to each address. 6993e12c5d1SDavid du Colombier * each cycle send one more message than the previous. 7003e12c5d1SDavid du Colombier */ 7017dd7cddfSDavid du Colombier for(ndest = 1; ndest < Maxdest; ndest++){ 7023e12c5d1SDavid du Colombier p = dest; 7037dd7cddfSDavid du Colombier 7047dd7cddfSDavid du Colombier endtime = time(0); 7057dd7cddfSDavid du Colombier if(endtime >= reqp->aborttime) 7063e12c5d1SDavid du Colombier break; 7073e12c5d1SDavid du Colombier 7087dd7cddfSDavid du Colombier /* get a server address if we need one */ 7097dd7cddfSDavid du Colombier if(ndest > l - p){ 710*28a8a86bSDavid du Colombier j = serveraddrs(dp, nsrp, dest, l - p, depth, reqp); 7117dd7cddfSDavid du Colombier l = &dest[j]; 7127dd7cddfSDavid du Colombier } 7137dd7cddfSDavid du Colombier 7147dd7cddfSDavid du Colombier /* no servers, punt */ 7157dd7cddfSDavid du Colombier if(l == dest) 716*28a8a86bSDavid du Colombier if (0 && inside) { /* not ready for prime time */ 717*28a8a86bSDavid du Colombier /* HACK: use sys=outside ips */ 718*28a8a86bSDavid du Colombier if (0 && outsidens() == nil) 719*28a8a86bSDavid du Colombier sysfatal("no outside-ns in ndb"); 720*28a8a86bSDavid du Colombier p = dest; 721*28a8a86bSDavid du Colombier memmove(p->a, outsidens(), sizeof p->a); 722*28a8a86bSDavid du Colombier p->s = dnlookup("outside", Cin, 1); 723*28a8a86bSDavid du Colombier p->nx = p->code = 0; 724*28a8a86bSDavid du Colombier l = p + 1; 725*28a8a86bSDavid du Colombier } else { 726*28a8a86bSDavid du Colombier syslog(0, LOG, "netquery1: no servers for %s", dp->name); // DEBUG 7277dd7cddfSDavid du Colombier break; 728*28a8a86bSDavid du Colombier } 7297dd7cddfSDavid du Colombier 7307dd7cddfSDavid du Colombier /* send to first 'ndest' destinations */ 7317dd7cddfSDavid du Colombier j = 0; 7327dd7cddfSDavid du Colombier for(; p < &dest[ndest] && p < l; p++){ 7337dd7cddfSDavid du Colombier /* skip destinations we've finished with */ 7347dd7cddfSDavid du Colombier if(p->nx >= Maxtrans) 7357dd7cddfSDavid du Colombier continue; 7367dd7cddfSDavid du Colombier 7377dd7cddfSDavid du Colombier j++; 7387dd7cddfSDavid du Colombier 7397dd7cddfSDavid du Colombier /* exponential backoff of requests */ 7407dd7cddfSDavid du Colombier if((1<<p->nx) > ndest) 7417dd7cddfSDavid du Colombier continue; 7427dd7cddfSDavid du Colombier 7435aa528faSDavid du Colombier memmove(obuf, p->a, sizeof p->a); 744*28a8a86bSDavid du Colombier procsetname("req slave: %sside query to %I/%s %s %s", 745*28a8a86bSDavid du Colombier (inns? "in": "out"), obuf, p->s->name, dp->name, 746*28a8a86bSDavid du Colombier rrname(type, buf, sizeof buf)); 747219b2ee8SDavid du Colombier if(debug) 7487dd7cddfSDavid du Colombier logsend(reqp->id, depth, obuf, p->s->name, 7497dd7cddfSDavid du Colombier dp->name, type); 750*28a8a86bSDavid du Colombier 751*28a8a86bSDavid du Colombier /* actually send the UDP packet */ 752d9dc5dd1SDavid du Colombier if(write(fd, obuf, len + OUdphdrsize) < 0) 753bd389b36SDavid du Colombier warning("sending udp msg %r"); 7547dd7cddfSDavid du Colombier p->nx++; 7553e12c5d1SDavid du Colombier } 7563e12c5d1SDavid du Colombier if(j == 0) 7573e12c5d1SDavid du Colombier break; /* no destinations left */ 7583e12c5d1SDavid du Colombier 759*28a8a86bSDavid du Colombier endtime = time(0) + waitsecs; 7607dd7cddfSDavid du Colombier if(endtime > reqp->aborttime) 7617dd7cddfSDavid du Colombier endtime = reqp->aborttime; 7627dd7cddfSDavid du Colombier 7637dd7cddfSDavid du Colombier for(replywaits = 0; replywaits < ndest; replywaits++){ 764*28a8a86bSDavid du Colombier procsetname( 765*28a8a86bSDavid du Colombier "req slave: reading %sside reply from %I for %s %s", 766*28a8a86bSDavid du Colombier (inns? "in": "out"), obuf, dp->name, 767*28a8a86bSDavid du Colombier rrname(type, buf, sizeof buf)); 7685aa528faSDavid du Colombier memset(&m, 0, sizeof m); 7697dd7cddfSDavid du Colombier if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) < 0) 7703e12c5d1SDavid du Colombier break; /* timed out */ 7713e12c5d1SDavid du Colombier 7727dd7cddfSDavid du Colombier /* find responder */ 7733e12c5d1SDavid du Colombier for(p = dest; p < l; p++) 7747dd7cddfSDavid du Colombier if(memcmp(p->a, ibuf, sizeof(p->a)) == 0) 7753e12c5d1SDavid du Colombier break; 7767dd7cddfSDavid du Colombier 7777dd7cddfSDavid du Colombier /* remove all addrs of responding server from list */ 7787dd7cddfSDavid du Colombier for(np = dest; np < l; np++) 7797dd7cddfSDavid du Colombier if(np->s == p->s) 7807dd7cddfSDavid du Colombier p->nx = Maxtrans; 7817dd7cddfSDavid du Colombier 78259cc4ca5SDavid du Colombier /* ignore any error replies */ 78359cc4ca5SDavid du Colombier if((m.flags & Rmask) == Rserver){ 7847dd7cddfSDavid du Colombier rrfreelist(m.qd); 7857dd7cddfSDavid du Colombier rrfreelist(m.an); 7867dd7cddfSDavid du Colombier rrfreelist(m.ar); 7877dd7cddfSDavid du Colombier rrfreelist(m.ns); 7887dd7cddfSDavid du Colombier if(p != l) 7897dd7cddfSDavid du Colombier p->code = Rserver; 7907dd7cddfSDavid du Colombier continue; 7913e12c5d1SDavid du Colombier } 7923e12c5d1SDavid du Colombier 79359cc4ca5SDavid du Colombier /* ignore any bad delegations */ 79459cc4ca5SDavid du Colombier if(m.ns && baddelegation(m.ns, nsrp, ibuf)){ 79559cc4ca5SDavid du Colombier rrfreelist(m.ns); 79659cc4ca5SDavid du Colombier m.ns = nil; 79759cc4ca5SDavid du Colombier if(m.an == nil){ 79859cc4ca5SDavid du Colombier rrfreelist(m.qd); 79959cc4ca5SDavid du Colombier rrfreelist(m.ar); 80059cc4ca5SDavid du Colombier if(p != l) 80159cc4ca5SDavid du Colombier p->code = Rserver; 80259cc4ca5SDavid du Colombier continue; 80359cc4ca5SDavid du Colombier } 80459cc4ca5SDavid du Colombier } 80559cc4ca5SDavid du Colombier 80659cc4ca5SDavid du Colombier 8077dd7cddfSDavid du Colombier /* remove any soa's from the authority section */ 8087dd7cddfSDavid du Colombier soarr = rrremtype(&m.ns, Tsoa); 8097dd7cddfSDavid du Colombier 8103e12c5d1SDavid du Colombier /* incorporate answers */ 8113e12c5d1SDavid du Colombier if(m.an) 8125aa528faSDavid du Colombier rrattach(m.an, (m.flags & Fauth) != 0); 8133e12c5d1SDavid du Colombier if(m.ar) 8143e12c5d1SDavid du Colombier rrattach(m.ar, 0); 8157dd7cddfSDavid du Colombier if(m.ns){ 8167dd7cddfSDavid du Colombier ndp = m.ns->owner; 8177dd7cddfSDavid du Colombier rrattach(m.ns, 0); 8187dd7cddfSDavid du Colombier } else 819*28a8a86bSDavid du Colombier ndp = nil; 8207dd7cddfSDavid du Colombier 8217dd7cddfSDavid du Colombier /* free the question */ 8227dd7cddfSDavid du Colombier if(m.qd) 8237dd7cddfSDavid du Colombier rrfreelist(m.qd); 8243e12c5d1SDavid du Colombier 8253e12c5d1SDavid du Colombier /* 8263e12c5d1SDavid du Colombier * Any reply from an authoritative server, 8273e12c5d1SDavid du Colombier * or a positive reply terminates the search 8283e12c5d1SDavid du Colombier */ 8297dd7cddfSDavid du Colombier if(m.an != nil || (m.flags & Fauth)){ 8307dd7cddfSDavid du Colombier if(m.an == nil && (m.flags & Rmask) == Rname) 8317dd7cddfSDavid du Colombier dp->nonexistent = Rname; 8327dd7cddfSDavid du Colombier else 8337dd7cddfSDavid du Colombier dp->nonexistent = 0; 8347dd7cddfSDavid du Colombier 8357dd7cddfSDavid du Colombier /* 8367dd7cddfSDavid du Colombier * cache any negative responses, free soarr 8377dd7cddfSDavid du Colombier */ 8387dd7cddfSDavid du Colombier if((m.flags & Fauth) && m.an == nil) 8395aa528faSDavid du Colombier cacheneg(dp, type, (m.flags & Rmask), 8405aa528faSDavid du Colombier soarr); 8417dd7cddfSDavid du Colombier else 8427dd7cddfSDavid du Colombier rrfreelist(soarr); 8433e12c5d1SDavid du Colombier return 1; 8443e12c5d1SDavid du Colombier } 8457dd7cddfSDavid du Colombier rrfreelist(soarr); 8463e12c5d1SDavid du Colombier 8473e12c5d1SDavid du Colombier /* 848*28a8a86bSDavid du Colombier * if we've been given better name servers, 849*28a8a86bSDavid du Colombier * recurse. we're called from udpquery, called from 850*28a8a86bSDavid du Colombier * netquery, which current holds dp->querylck, 851*28a8a86bSDavid du Colombier * so release it now and acquire it upon return. 8523e12c5d1SDavid du Colombier */ 8533e12c5d1SDavid du Colombier if(m.ns){ 8547dd7cddfSDavid du Colombier tp = rrlookup(ndp, Tns, NOneg); 8557dd7cddfSDavid du Colombier if(!contains(nsrp, tp)){ 8565aa528faSDavid du Colombier procsetname( 8575aa528faSDavid du Colombier "req slave: recursive query for %s %s", 8585aa528faSDavid du Colombier dp->name, 8595aa528faSDavid du Colombier rrname(type, buf, sizeof buf)); 860*28a8a86bSDavid du Colombier qunlock(&dp->querylck); 8615aa528faSDavid du Colombier rv = netquery(dp, type, tp, reqp, 8625aa528faSDavid du Colombier depth + 1); 863*28a8a86bSDavid du Colombier qlock(&dp->querylck); 8647dd7cddfSDavid du Colombier rrfreelist(tp); 8657dd7cddfSDavid du Colombier return rv; 8667dd7cddfSDavid du Colombier } else 8677dd7cddfSDavid du Colombier rrfreelist(tp); 8683e12c5d1SDavid du Colombier } 8693e12c5d1SDavid du Colombier } 8703e12c5d1SDavid du Colombier } 8717dd7cddfSDavid du Colombier 8725aa528faSDavid du Colombier /* if all servers returned failure, propagate it */ 8737dd7cddfSDavid du Colombier dp->nonexistent = Rserver; 8747dd7cddfSDavid du Colombier for(p = dest; p < l; p++) 8757dd7cddfSDavid du Colombier if(p->code != Rserver) 8767dd7cddfSDavid du Colombier dp->nonexistent = 0; 8777dd7cddfSDavid du Colombier 8783e12c5d1SDavid du Colombier return 0; 8793e12c5d1SDavid du Colombier } 8807dd7cddfSDavid du Colombier 881*28a8a86bSDavid du Colombier enum { Hurry, Patient, }; 882*28a8a86bSDavid du Colombier enum { Outns, Inns, }; 8837dd7cddfSDavid du Colombier 884*28a8a86bSDavid du Colombier static int 885*28a8a86bSDavid du Colombier udpquery(char *mntpt, DN *dp, int type, RR *nsrp, Request *reqp, int depth, 886*28a8a86bSDavid du Colombier int patient, int inns) 887*28a8a86bSDavid du Colombier { 888*28a8a86bSDavid du Colombier int fd, rv = 0; 889*28a8a86bSDavid du Colombier uchar *obuf, *ibuf; 8907dd7cddfSDavid du Colombier 8917dd7cddfSDavid du Colombier /* use alloced buffers rather than ones from the stack */ 892d9dc5dd1SDavid du Colombier ibuf = emalloc(Maxudpin+OUdphdrsize); 893d9dc5dd1SDavid du Colombier obuf = emalloc(Maxudp+OUdphdrsize); 8947dd7cddfSDavid du Colombier 895*28a8a86bSDavid du Colombier fd = udpport(mntpt); 896*28a8a86bSDavid du Colombier if(fd >= 0) { 897*28a8a86bSDavid du Colombier reqp->aborttime = time(0) + (patient? Maxreqtm: Maxreqtm/2); 898*28a8a86bSDavid du Colombier rv = netquery1(fd, dp, type, nsrp, reqp, depth, 899*28a8a86bSDavid du Colombier ibuf, obuf, (patient? 15: 10), inns); 900*28a8a86bSDavid du Colombier close(fd); 901*28a8a86bSDavid du Colombier } 902*28a8a86bSDavid du Colombier 903*28a8a86bSDavid du Colombier free(obuf); 904*28a8a86bSDavid du Colombier free(ibuf); 905*28a8a86bSDavid du Colombier return rv; 906*28a8a86bSDavid du Colombier } 907*28a8a86bSDavid du Colombier 908*28a8a86bSDavid du Colombier /* look up (dp->name,type) via *nsrp with results in *reqp */ 909*28a8a86bSDavid du Colombier static int 910*28a8a86bSDavid du Colombier netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth) 911*28a8a86bSDavid du Colombier { 912*28a8a86bSDavid du Colombier int lock, rv, triedin; 913*28a8a86bSDavid du Colombier RR *rp; 914*28a8a86bSDavid du Colombier 915*28a8a86bSDavid du Colombier if(depth > 12) /* in a recursive loop? */ 916*28a8a86bSDavid du Colombier return 0; 917*28a8a86bSDavid du Colombier 918*28a8a86bSDavid du Colombier slave(reqp); /* might fork */ 919*28a8a86bSDavid du Colombier /* if so, parent process longjmped to req->mret; we're child slave */ 920*28a8a86bSDavid du Colombier if (!reqp->isslave) 921*28a8a86bSDavid du Colombier syslog(0, LOG, 922*28a8a86bSDavid du Colombier "[%d] netquery: slave returned with reqp->isslave==0", 923*28a8a86bSDavid du Colombier getpid()); 924*28a8a86bSDavid du Colombier 925*28a8a86bSDavid du Colombier /* don't lock before call to slave so only children can block */ 926*28a8a86bSDavid du Colombier lock = reqp->isslave != 0; 927*28a8a86bSDavid du Colombier if(lock) { 928*28a8a86bSDavid du Colombier procsetname("waiting for query lock on %s", dp->name); 929*28a8a86bSDavid du Colombier /* don't make concurrent queries for this name */ 930*28a8a86bSDavid du Colombier qlock(&dp->querylck); 931*28a8a86bSDavid du Colombier procsetname("netquery: %s", dp->name); 932*28a8a86bSDavid du Colombier } 9337dd7cddfSDavid du Colombier 9347dd7cddfSDavid du Colombier /* prepare server RR's for incremental lookup */ 9357dd7cddfSDavid du Colombier for(rp = nsrp; rp; rp = rp->next) 9367dd7cddfSDavid du Colombier rp->marker = 0; 9377dd7cddfSDavid du Colombier 938*28a8a86bSDavid du Colombier rv = 0; /* pessimism */ 939*28a8a86bSDavid du Colombier triedin = 0; 940*28a8a86bSDavid du Colombier /* 941*28a8a86bSDavid du Colombier * don't bother to query the broken inside nameservers for outside 942*28a8a86bSDavid du Colombier * addresses. 943*28a8a86bSDavid du Colombier */ 944*28a8a86bSDavid du Colombier if (!inside || insideaddr(dp->name)) { 945*28a8a86bSDavid du Colombier rv = udpquery(mntpt, dp, type, nsrp, reqp, depth, Hurry, 946*28a8a86bSDavid du Colombier (inside? Inns: Outns)); 947*28a8a86bSDavid du Colombier triedin = 1; 948*28a8a86bSDavid du Colombier } 949*28a8a86bSDavid du Colombier 950*28a8a86bSDavid du Colombier /* 951*28a8a86bSDavid du Colombier * if we're still looking and have an outside address, 952*28a8a86bSDavid du Colombier * try it on our outside interface, if any. 953*28a8a86bSDavid du Colombier */ 954*28a8a86bSDavid du Colombier if (rv == 0 && inside && !insideaddr(dp->name)) { 955*28a8a86bSDavid du Colombier if (triedin) 956*28a8a86bSDavid du Colombier syslog(0, LOG, 957*28a8a86bSDavid du Colombier "[%d] netquery: internal nameservers failed for %s; trying external", 958*28a8a86bSDavid du Colombier getpid(), dp->name); 959*28a8a86bSDavid du Colombier 960*28a8a86bSDavid du Colombier /* prepare server RR's for incremental lookup */ 961*28a8a86bSDavid du Colombier for(rp = nsrp; rp; rp = rp->next) 962*28a8a86bSDavid du Colombier rp->marker = 0; 963*28a8a86bSDavid du Colombier 964*28a8a86bSDavid du Colombier rv = udpquery("/net.alt", dp, type, nsrp, reqp, depth, Patient, 965*28a8a86bSDavid du Colombier Outns); 966*28a8a86bSDavid du Colombier if (rv == 0) 967*28a8a86bSDavid du Colombier syslog(0, LOG, "[%d] netquery: no luck for %s", 968*28a8a86bSDavid du Colombier getpid(), dp->name); 969*28a8a86bSDavid du Colombier } 970*28a8a86bSDavid du Colombier 971*28a8a86bSDavid du Colombier if(lock) 972*28a8a86bSDavid du Colombier qunlock(&dp->querylck); 9737dd7cddfSDavid du Colombier 9747dd7cddfSDavid du Colombier return rv; 9757dd7cddfSDavid du Colombier } 976