commit e8c148ff092a5780d04aa2fd4a07a5732207b698 Author: Russ Cox Date: Fri Mar 7 11:13:05 2025 -0500 ndb/dns: add support for domain-specific dns resolvers If a system has a dns config like dns=1.2.3.4 dns=5.6.7.8 suffix=internal.net then DNS lookups for names ending in internal.net go (only) to 5.6.7.8 and lookups for all other names go to 1.2.3.4. diff --git a/sys/man/6/ndb b/sys/man/6/ndb index 2f0de34f..d14628ef 100755 --- a/sys/man/6/ndb +++ b/sys/man/6/ndb @@ -44,7 +44,7 @@ database= declares the database to be composed of the three files .BR /lib/ndb/common , .BR /lib/ndb/local , -and +and .BR /lib/ndb/global . By default, .B /lib/ndb/local @@ -115,7 +115,7 @@ and servers. The search starts by looking for an entry with .BR sys=anna . -We find the anna entry. Since it has an +We find the anna entry. Since it has an .B smtp=smtp2.cs.bell-labs.com pair, we're done looking for that attribute. @@ -247,6 +247,11 @@ pairs. .B dns a DNS server to use (for DNS and DHCP) .TP +.B suffix +on the same line as a +.B dns +pair, indicates that the server should be used for names with that suffix +.TP .B ntp an NTP server to use (for DHCP) .TP diff --git a/sys/src/cmd/ndb/dblookup.c b/sys/src/cmd/ndb/dblookup.c index 9d9a5082..333c1e72 100755 --- a/sys/src/cmd/ndb/dblookup.c +++ b/sys/src/cmd/ndb/dblookup.c @@ -768,18 +768,19 @@ Ndbtuple* lookupinfo(char *attr) { char buf[64]; - char *a[2]; + char *a[3]; Ndbtuple *t; snprint(buf, sizeof buf, "%I", ipaddr); a[0] = attr; + a[1] = "suffix"; lock(&dblock); if(opendatabase() < 0){ unlock(&dblock); return nil; } - t = ndbipinfo(db, "ip", buf, a, 1); + t = ndbipinfo(db, "ip", buf, a, 2); unlock(&dblock); return t; } @@ -871,7 +872,7 @@ static char *locdns[20]; static QLock locdnslck; static void -addlocaldnsserver(DN *dp, int class, char *ipaddr, int i) +addlocaldnsserver(DN *dp, int class, char *ipaddr, char *suffix, int i) { int n; DN *nsdp; @@ -906,6 +907,8 @@ addlocaldnsserver(DN *dp, int class, char *ipaddr, int i) rp->db = 1; // rp->ttl = 10*Min; /* seems too short */ rp->ttl = (1UL<<31)-1; + if(suffix != nil) + rp->suffix = strdup(suffix); rrattach(rp, Authoritative); /* will not attach rrs in my area */ /* A or AAAA record */ @@ -919,35 +922,87 @@ addlocaldnsserver(DN *dp, int class, char *ipaddr, int i) rp->db = 1; // rp->ttl = 10*Min; /* seems too short */ rp->ttl = (1UL<<31)-1; + if(suffix != nil) + rp->suffix = strdup(suffix); rrattach(rp, Authoritative); /* will not attach rrs in my area */ dnslog("added local dns server %s at %s", buf, ipaddr); } +static int +dnssuffix(char *name, char *suffix) +{ + int i, j; + + if(suffix == nil) + return 0; + + i = strlen(name); + if(i > 0 && name[i-1] == '.') + i--; + j = strlen(suffix); + if(j > 0 && suffix[j-1] == '.') + j--; + if(j > i || (j < i && name[i-j-1] != '.') || cistrncmp(name+i-j, suffix, j) != 0) + return -1; // no match for suffix + return j; // suffix length +} + +static RR* +dnsfilter(char *name, RR *rr) +{ + int best, n; + RR *rp, **tail; + + // Find the most specific suffix match. + best = 0; + for(rp = rr; rp; rp = rp->next) + if((n = dnssuffix(name, rp->suffix)) > best) + best = n; + + // Remove all the entries with worse matches. + tail = &rr; + for(rp = *tail; rp; rp = *tail){ + n = dnssuffix(name, rp->suffix); + if(n < best){ + *tail = rp->next; + rp->next = nil; + rrfree(rp); + } else { + *tail = rp; + tail = &rp->next; + } + } + return rr; +} + /* * return list of dns server addresses to use when * acting just as a resolver. */ RR* -dnsservers(int class) +dnsservers(char *name, int class) { int i, n; - char *p; + char *p, *suffix; char *args[5]; - Ndbtuple *t, *nt; + Ndbtuple *t, *nt, *lt; RR *nsrp; DN *dp; dp = dnlookup(localservers, class, 1); nsrp = rrlookup(dp, Tns, NOneg); if(nsrp != nil) - return nsrp; + return dnsfilter(name, nsrp); p = getenv("DNSSERVER"); /* list of ip addresses */ if(p != nil){ n = tokenize(p, args, nelem(args)); - for(i = 0; i < n; i++) - addlocaldnsserver(dp, class, args[i], i); + for(i = 0; i < n; i++){ + if((suffix = strchr(args[i], '@')) != nil) + *suffix++ = '\0'; + addlocaldnsserver(dp, class, args[i], suffix, i); + } free(p); } else { t = lookupinfo("@dns"); /* @dns=ip1 @dns=ip2 ... */ @@ -955,13 +1010,22 @@ dnsservers(int class) return nil; i = 0; for(nt = t; nt != nil; nt = nt->entry){ - addlocaldnsserver(dp, class, nt->val, i); + if(strcmp(nt->attr, "dns") != 0) + continue; + suffix = nil; + for(lt = nt->line; lt != nil && lt != nt; lt = lt->line){ + if(strcmp(lt->attr, "suffix") == 0){ + suffix = strdup(lt->val); + break; + } + } + addlocaldnsserver(dp, class, nt->val, suffix, i); i++; } ndbfree(t); } - return rrlookup(dp, Tns, NOneg); + return dnsfilter(name, rrlookup(dp, Tns, NOneg)); } static void diff --git a/sys/src/cmd/ndb/dn.c b/sys/src/cmd/ndb/dn.c index cf5c9b8b..c78261a4 100755 --- a/sys/src/cmd/ndb/dn.c +++ b/sys/src/cmd/ndb/dn.c @@ -815,7 +815,7 @@ rrattach1(RR *new, int auth) if(rp->negative != new->negative) { /* rp == *l before; *l == rp->next after */ rrdelhead(l); - continue; + continue; } /* all things equal, pick the newer one */ else if(rp->arg0 == new->arg0 && rp->arg1 == new->arg1){ @@ -973,6 +973,8 @@ rrcopy(RR *rp, RR **last) *nrp = *rp; break; } + if(rp->suffix != nil) + nrp->suffix = estrdup(rp->suffix); nrp->cached = 0; nrp->next = 0; *last = nrp; @@ -1316,6 +1318,8 @@ rrfmt(Fmt *f) rp->cert->type, rp->cert->tag, rp->cert->alg); break; } + if(rp->suffix != nil) + fmtprint(&fstr, " suffix=%s", rp->suffix); out: strp = fmtstrflush(&fstr); rv = fmtstrcpy(f, strp); @@ -2078,6 +2082,7 @@ rrfree(RR *rp) break; } + free(rp->suffix); rp->magic = ~rp->magic; memset(rp, 0, sizeof *rp); /* cause trouble */ free(rp); diff --git a/sys/src/cmd/ndb/dnresolve.c b/sys/src/cmd/ndb/dnresolve.c index 4c1eac44..57eca308 100755 --- a/sys/src/cmd/ndb/dnresolve.c +++ b/sys/src/cmd/ndb/dnresolve.c @@ -354,7 +354,7 @@ issuequery(Query *qp, char *name, int class, int depth, int recurse) * designated name servers */ if(cfg.resolver){ - nsrp = randomize(getdnsservers(class)); + nsrp = randomize(getdnsservers(name, class)); if(nsrp != nil) if(netqueryns(qp, depth+1, nsrp) > Answnone) return rrlookup(qp->dp, qp->type, OKneg); diff --git a/sys/src/cmd/ndb/dns.c b/sys/src/cmd/ndb/dns.c index 16815bad..53e8e036 100755 --- a/sys/src/cmd/ndb/dns.c +++ b/sys/src/cmd/ndb/dns.c @@ -1051,7 +1051,18 @@ logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) } RR* -getdnsservers(int class) +getdnsservers(char *name, int class) { - return dnsservers(class); + RR *rr, *rp; + + rp = nil; + USED(rp); + + rr = dnsservers(name, class); + if(0){ + print("dnsservers %s\n", name); + for(rp = rr; rp; rp = rp->next) + print("\t%R\n", rp); + } + return rr; } diff --git a/sys/src/cmd/ndb/dns.h b/sys/src/cmd/ndb/dns.h index 0a1a6d2f..b9d186e8 100755 --- a/sys/src/cmd/ndb/dns.h +++ b/sys/src/cmd/ndb/dns.h @@ -278,6 +278,7 @@ struct RR ulong magic; DN *owner; /* domain that owns this resource record */ uintptr pc; /* for tracking memory allocation */ + char *suffix; /* domain suffix to use this DNS resolver for */ ulong ttl; /* time to live to be passed on */ ulong expire; /* time this entry expires locally */ ulong marker; /* used locally when scanning rrlists */ @@ -520,7 +521,7 @@ int baddelegation(RR*, RR*, uchar*); RR* dbinaddr(DN*, int); RR* dblookup(char*, int, int, int, int); void dnforceage(void); -RR* dnsservers(int); +RR* dnsservers(char*, int); RR* domainlist(int); int insideaddr(char *dom); int insidens(uchar *ip); @@ -530,7 +531,7 @@ uchar* outsidens(int); /* dns.c */ char* walkup(char*); -RR* getdnsservers(int); +RR* getdnsservers(char*, int); void logreply(int, uchar*, DNSmsg*); void logsend(int, int, uchar*, char*, char*, int); void procsetname(char *fmt, ...); diff --git a/sys/src/cmd/ndb/dnsdebug.c b/sys/src/cmd/ndb/dnsdebug.c index bac32bfa..45af1df2 100755 --- a/sys/src/cmd/ndb/dnsdebug.c +++ b/sys/src/cmd/ndb/dnsdebug.c @@ -283,12 +283,12 @@ logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) } RR* -getdnsservers(int class) +getdnsservers(char *name, int class) { RR *rr; if(servername == nil) - return dnsservers(class); + return dnsservers(name, class); rr = rralloc(Tns); rr->owner = dnlookup("local#dns#servers", class, 1); @@ -311,7 +311,7 @@ squirrelserveraddrs(void) if(serveraddrs) rrfreelist(serveraddrs); serveraddrs = nil; - rr = getdnsservers(Cin); + rr = getdnsservers("", Cin); l = &serveraddrs; for(rp = rr; rp != nil; rp = rp->next){ attr = ipattr(rp->host->name); diff --git a/sys/src/cmd/ndb/dnstcp.c b/sys/src/cmd/ndb/dnstcp.c index 837a7746..d02dbc67 100755 --- a/sys/src/cmd/ndb/dnstcp.c +++ b/sys/src/cmd/ndb/dnstcp.c @@ -376,7 +376,7 @@ logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type) } RR* -getdnsservers(int class) +getdnsservers(char *name, int class) { - return dnsservers(class); + return dnsservers(name, class); } commit 1d0642ae493bf5ce798a6aa64a745bc6316baa11 Author: Russ Cox Date: Sat Mar 22 15:18:17 2025 -0400 ndb/dnsdebug: update for suffix-specific dns server selection diff --git a/sys/src/cmd/ndb/dnsdebug.c b/sys/src/cmd/ndb/dnsdebug.c index 45af1df2..f96976c6 100755 --- a/sys/src/cmd/ndb/dnsdebug.c +++ b/sys/src/cmd/ndb/dnsdebug.c @@ -16,6 +16,7 @@ static char *servername; static RR *serverrr; static RR *serveraddrs; +int customserver; char *dbfile; int debug; uchar ipaddr[IPaddrlen]; /* my ip address */ @@ -34,8 +35,8 @@ void docmd(int, char**); void doquery(char*, char*); void preloadserveraddrs(void); int prettyrrfmt(Fmt*); -int setserver(char*); -void squirrelserveraddrs(void); +int setserver(char*, char*); +void squirrelserveraddrs(char*); void usage(void) @@ -79,7 +80,7 @@ main(int argc, char *argv[]) opendatabase(); if(cfg.resolver) - squirrelserveraddrs(); + squirrelserveraddrs(""); debug = 1; @@ -298,7 +299,7 @@ getdnsservers(char *name, int class) } void -squirrelserveraddrs(void) +squirrelserveraddrs(char *name) { int v4; char *attr; @@ -311,7 +312,7 @@ squirrelserveraddrs(void) if(serveraddrs) rrfreelist(serveraddrs); serveraddrs = nil; - rr = getdnsservers("", Cin); + rr = getdnsservers(name, Cin); l = &serveraddrs; for(rp = rr; rp != nil; rp = rp->next){ attr = ipattr(rp->host->name); @@ -352,7 +353,7 @@ preloadserveraddrs(void) } int -setserver(char *server) +setserver(char *server, char *name) { if(servername != nil){ free(servername); @@ -362,7 +363,7 @@ setserver(char *server) if(server == nil || *server == 0) return 0; servername = strdup(server); - squirrelserveraddrs(); + squirrelserveraddrs(name); if(serveraddrs == nil){ print("can't resolve %s\n", servername); cfg.resolver = 0; @@ -454,10 +455,13 @@ docmd(int n, char **f) tmpsrv = 0; if(*f[0] == '@') { - if(setserver(f[0]+1) < 0) + if(setserver(f[0]+1, "") < 0) return; switch(n){ + default: + customserver = *(f[0]+1) != '\0'; + break; case 3: type = f[2]; /* fall through */ @@ -479,8 +483,10 @@ docmd(int n, char **f) if(name == nil) return; + if(!customserver && !tmpsrv) + squirrelserveraddrs(name); doquery(name, type); if(tmpsrv) - setserver(""); + setserver("", ""); }