1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <ndb.h>
- #include <ip.h>
- #include "dns.h"
- enum {
- Nibwidth = 4,
- Nibmask = (1<<Nibwidth) - 1,
- V6maxrevdomdepth = 128 / Nibwidth, /* bits / bits-per-nibble */
- /*
- * ttl for generated ptr records. it was zero, which might seem
- * like a good idea, but some dns implementations seem to be
- * confused by a zero ttl, and instead of using the data and then
- * discarding the RR, they conclude that they don't have valid data.
- */
- Ptrttl = 300,
- };
- static Ndb *db;
- static Lock dblock;
- static RR* addrrr(Ndbtuple*, Ndbtuple*);
- static RR* cnamerr(Ndbtuple*, Ndbtuple*);
- static void createptrs(void);
- static RR* dblookup1(char*, int, int, int);
- static RR* doaxfr(Ndb*, char*);
- static Ndbtuple*look(Ndbtuple*, Ndbtuple*, char*);
- static RR* mxrr(Ndbtuple*, Ndbtuple*);
- static RR* nsrr(Ndbtuple*, Ndbtuple*);
- static RR* nullrr(Ndbtuple*, Ndbtuple*);
- static RR* ptrrr(Ndbtuple*, Ndbtuple*);
- static RR* soarr(Ndbtuple*, Ndbtuple*);
- static RR* srvrr(Ndbtuple*, Ndbtuple*);
- static RR* txtrr(Ndbtuple*, Ndbtuple*);
- static int implemented[Tall] =
- {
- [Ta] 1,
- [Taaaa] 1,
- [Tcname] 1,
- [Tmx] 1,
- [Tns] 1,
- [Tnull] 1,
- [Tptr] 1,
- [Tsoa] 1,
- [Tsrv] 1,
- [Ttxt] 1,
- };
- /* straddle server configuration */
- static Ndbtuple *indoms, *innmsrvs, *outnmsrvs;
- static void
- nstrcpy(char *to, char *from, int len)
- {
- strncpy(to, from, len);
- to[len-1] = 0;
- }
- int
- opendatabase(void)
- {
- char netdbnm[256];
- Ndb *xdb, *netdb;
- if (db)
- return 0;
- xdb = ndbopen(dbfile); /* /lib/ndb */
- snprint(netdbnm, sizeof netdbnm, "%s/ndb", mntpt);
- netdb = ndbopen(netdbnm); /* /net/ndb */
- if(netdb)
- netdb->nohash = 1;
- db = ndbcat(netdb, xdb); /* both */
- return db? 0: -1;
- }
- /*
- * lookup an RR in the network database, look for matches
- * against both the domain name and the wildcarded domain name.
- *
- * the lock makes sure only one process can be accessing the data
- * base at a time. This is important since there's a lot of
- * shared state there.
- *
- * e.g. for x.research.bell-labs.com, first look for a match against
- * the x.research.bell-labs.com. If nothing matches,
- * try *.research.bell-labs.com.
- */
- RR*
- dblookup(char *name, int class, int type, int auth, int ttl)
- {
- int err;
- char *wild, *cp;
- char buf[256];
- RR *rp, *tp;
- DN *dp, *ndp;
- static int parallel;
- static int parfd[2];
- static char token[1];
- /* so far only internet lookups are implemented */
- if(class != Cin)
- return 0;
- err = Rname;
- if(type == Tall){
- rp = nil;
- for (type = Ta; type < Tall; type++)
- /* HACK: exclude Taaaa (ipv6) for speed for now */
- if(implemented[type] && (1 || type != Taaaa))
- rrcat(&rp, dblookup(name, class, type, auth, ttl));
- return rp;
- }
- rp = nil;
- lock(&dblock);
- dp = dnlookup(name, class, 1);
- if(opendatabase() < 0)
- goto out;
- if(dp->rr)
- err = 0;
- /* first try the given name */
- if(cfg.cachedb)
- rp = rrlookup(dp, type, NOneg);
- else
- rp = dblookup1(name, type, auth, ttl);
- if(rp)
- goto out;
- /* try lower case version */
- for(cp = name; *cp; cp++)
- *cp = tolower(*cp);
- if(cfg.cachedb)
- rp = rrlookup(dp, type, NOneg);
- else
- rp = dblookup1(name, type, auth, ttl);
- if(rp)
- goto out;
- /* walk the domain name trying the wildcard '*' at each position */
- for(wild = strchr(name, '.'); wild; wild = strchr(wild+1, '.')){
- snprint(buf, sizeof buf, "*%s", wild);
- ndp = dnlookup(buf, class, 1);
- if(ndp->rr)
- err = 0;
- if(cfg.cachedb)
- rp = rrlookup(ndp, type, NOneg);
- else
- rp = dblookup1(buf, type, auth, ttl);
- if(rp)
- break;
- }
- out:
- /* add owner to uncached records */
- if(rp)
- for(tp = rp; tp; tp = tp->next)
- tp->owner = dp;
- else {
- /*
- * don't call it non-existent if it's not ours
- * (unless we're a resolver).
- */
- if(err == Rname && (!inmyarea(name) || cfg.resolver))
- err = Rserver;
- dp->respcode = err;
- }
- unlock(&dblock);
- return rp;
- }
- static ulong
- intval(Ndbtuple *entry, Ndbtuple *pair, char *attr, ulong def)
- {
- Ndbtuple *t = look(entry, pair, attr);
- return (t? strtoul(t->val, 0, 10): def);
- }
- /*
- * lookup an RR in the network database
- */
- static RR*
- dblookup1(char *name, int type, int auth, int ttl)
- {
- Ndbtuple *t, *nt;
- RR *rp, *list, **l;
- Ndbs s;
- char dname[Domlen];
- char *attr;
- DN *dp;
- RR *(*f)(Ndbtuple*, Ndbtuple*);
- int found, x;
- dp = nil;
- switch(type){
- case Tptr:
- attr = "ptr";
- f = ptrrr;
- break;
- case Ta:
- attr = "ip";
- f = addrrr;
- break;
- case Tnull:
- attr = "nullrr";
- f = nullrr;
- break;
- case Tns:
- attr = "ns";
- f = nsrr;
- break;
- case Tsoa:
- attr = "soa";
- f = soarr;
- break;
- case Tsrv:
- attr = "srv";
- f = srvrr;
- break;
- case Tmx:
- attr = "mx";
- f = mxrr;
- break;
- case Tcname:
- attr = "cname";
- f = cnamerr;
- break;
- case Taxfr:
- case Tixfr:
- return doaxfr(db, name);
- default:
- // dnslog("dnlookup1(%s) bad type", name);
- return nil;
- }
- /*
- * find a matching entry in the database
- */
- t = nil;
- free(ndbgetvalue(db, &s, "dom", name, attr, &t));
- /*
- * hack for local names
- */
- if(t == nil && strchr(name, '.') == nil)
- free(ndbgetvalue(db, &s, "sys", name, attr, &t));
- if(t == nil) {
- // dnslog("dnlookup1(%s) name not found", name);
- return nil;
- }
- /* search whole entry for default domain name */
- strncpy(dname, name, sizeof dname);
- for(nt = t; nt; nt = nt->entry)
- if(strcmp(nt->attr, "dom") == 0){
- nstrcpy(dname, nt->val, sizeof dname);
- break;
- }
- /* ttl is maximum of soa minttl and entry's ttl ala rfc883 */
- x = intval(t, s.t, "ttl", 0);
- if(x > ttl)
- ttl = x;
- /* default ttl is one day */
- if(ttl < 0)
- ttl = DEFTTL;
- /*
- * The database has 2 levels of precedence; line and entry.
- * Pairs on the same line bind tighter than pairs in the
- * same entry, so we search the line first.
- */
- found = 0;
- list = 0;
- l = &list;
- for(nt = s.t;; ){
- if(found == 0 && strcmp(nt->attr, "dom") == 0){
- nstrcpy(dname, nt->val, sizeof dname);
- found = 1;
- }
- if(cistrcmp(attr, nt->attr) == 0){
- rp = (*f)(t, nt);
- rp->auth = auth;
- rp->db = 1;
- if(ttl)
- rp->ttl = ttl;
- if(dp == nil)
- dp = dnlookup(dname, Cin, 1);
- rp->owner = dp;
- *l = rp;
- l = &rp->next;
- nt->ptr = 1;
- }
- nt = nt->line;
- if(nt == s.t)
- break;
- }
- /* search whole entry */
- for(nt = t; nt; nt = nt->entry)
- if(nt->ptr == 0 && cistrcmp(attr, nt->attr) == 0){
- rp = (*f)(t, nt);
- rp->db = 1;
- if(ttl)
- rp->ttl = ttl;
- rp->auth = auth;
- if(dp == nil)
- dp = dnlookup(dname, Cin, 1);
- rp->owner = dp;
- *l = rp;
- l = &rp->next;
- }
- ndbfree(t);
- // dnslog("dnlookup1(%s) -> %#p", name, list);
- return list;
- }
- /*
- * make various types of resource records from a database entry
- */
- static RR*
- addrrr(Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- uchar addr[IPaddrlen];
- USED(entry);
- parseip(addr, pair->val);
- if(isv4(addr))
- rp = rralloc(Ta);
- else
- rp = rralloc(Taaaa);
- rp->ip = dnlookup(pair->val, Cin, 1);
- return rp;
- }
- static RR*
- nullrr(Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- USED(entry);
- rp = rralloc(Tnull);
- rp->null->data = (uchar*)estrdup(pair->val);
- rp->null->dlen = strlen((char*)rp->null->data);
- return rp;
- }
- /*
- * txt rr strings are at most 255 bytes long. one
- * can represent longer strings by multiple concatenated
- * <= 255 byte ones.
- */
- static RR*
- txtrr(Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- Txt *t, **l;
- int i, len, sofar;
- USED(entry);
- rp = rralloc(Ttxt);
- l = &rp->txt;
- rp->txt = nil;
- len = strlen(pair->val);
- sofar = 0;
- while(len > sofar){
- t = emalloc(sizeof(*t));
- t->next = nil;
- i = len-sofar;
- if(i > 255)
- i = 255;
- t->p = emalloc(i+1);
- memmove(t->p, pair->val+sofar, i);
- t->p[i] = 0;
- sofar += i;
- *l = t;
- l = &t->next;
- }
- return rp;
- }
- static RR*
- cnamerr(Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- USED(entry);
- rp = rralloc(Tcname);
- rp->host = dnlookup(pair->val, Cin, 1);
- return rp;
- }
- static RR*
- mxrr(Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- rp = rralloc(Tmx);
- rp->host = dnlookup(pair->val, Cin, 1);
- rp->pref = intval(entry, pair, "pref", 1);
- return rp;
- }
- static RR*
- nsrr(Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- Ndbtuple *t;
- rp = rralloc(Tns);
- rp->host = dnlookup(pair->val, Cin, 1);
- t = look(entry, pair, "soa");
- if(t && t->val[0] == 0)
- rp->local = 1;
- return rp;
- }
- static RR*
- ptrrr(Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- USED(entry);
- rp = rralloc(Tns);
- rp->ptr = dnlookup(pair->val, Cin, 1);
- return rp;
- }
- static RR*
- soarr(Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- Ndbtuple *ns, *mb, *t;
- char mailbox[Domlen];
- Ndb *ndb;
- char *p;
- rp = rralloc(Tsoa);
- rp->soa->serial = 1;
- for(ndb = db; ndb; ndb = ndb->next)
- if(ndb->mtime > rp->soa->serial)
- rp->soa->serial = ndb->mtime;
- rp->soa->retry = intval(entry, pair, "retry", Hour);
- rp->soa->expire = intval(entry, pair, "expire", Day);
- rp->soa->minttl = intval(entry, pair, "ttl", Day);
- rp->soa->refresh = intval(entry, pair, "refresh", Day);
- rp->soa->serial = intval(entry, pair, "serial", rp->soa->serial);
- ns = look(entry, pair, "ns");
- if(ns == nil)
- ns = look(entry, pair, "dom");
- rp->host = dnlookup(ns->val, Cin, 1);
- /* accept all of:
- * mbox=person
- * mbox=person@machine.dom
- * mbox=person.machine.dom
- */
- mb = look(entry, pair, "mbox");
- if(mb == nil)
- mb = look(entry, pair, "mb");
- if(mb)
- if(strchr(mb->val, '.')) {
- p = strchr(mb->val, '@');
- if(p != nil)
- *p = '.';
- rp->rmb = dnlookup(mb->val, Cin, 1);
- } else {
- snprint(mailbox, sizeof mailbox, "%s.%s",
- mb->val, ns->val);
- rp->rmb = dnlookup(mailbox, Cin, 1);
- }
- else {
- snprint(mailbox, sizeof mailbox, "postmaster.%s", ns->val);
- rp->rmb = dnlookup(mailbox, Cin, 1);
- }
- /*
- * hang dns slaves off of the soa. this is
- * for managing the area.
- */
- for(t = entry; t != nil; t = t->entry)
- if(strcmp(t->attr, "dnsslave") == 0)
- addserver(&rp->soa->slaves, t->val);
- return rp;
- }
- static RR*
- srvrr(Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- rp = rralloc(Tsrv);
- rp->host = dnlookup(pair->val, Cin, 1);
- rp->srv->pri = intval(entry, pair, "pri", 0);
- rp->srv->weight = intval(entry, pair, "weight", 0);
- /* TODO: translate service name to port # */
- rp->port = intval(entry, pair, "port", 0);
- return rp;
- }
- /*
- * Look for a pair with the given attribute. look first on the same line,
- * then in the whole entry.
- */
- static Ndbtuple*
- look(Ndbtuple *entry, Ndbtuple *line, char *attr)
- {
- Ndbtuple *nt;
- /* first look on same line (closer binding) */
- for(nt = line;;){
- if(cistrcmp(attr, nt->attr) == 0)
- return nt;
- nt = nt->line;
- if(nt == line)
- break;
- }
- /* search whole tuple */
- for(nt = entry; nt; nt = nt->entry)
- if(cistrcmp(attr, nt->attr) == 0)
- return nt;
- return 0;
- }
- static RR**
- linkrr(RR *rp, DN *dp, RR **l)
- {
- rp->owner = dp;
- rp->auth = 1;
- rp->db = 1;
- *l = rp;
- return &rp->next;
- }
- /* these are answered specially by the tcp version */
- static RR*
- doaxfr(Ndb *db, char *name)
- {
- USED(db, name);
- return 0;
- }
- /*
- * read the all the soa's from the database to determine area's.
- * this is only used when we're not caching the database.
- */
- static void
- dbfile2area(Ndb *db)
- {
- Ndbtuple *t;
- if(debug)
- dnslog("rereading %s", db->file);
- Bseek(&db->b, 0, 0);
- while(t = ndbparse(db))
- ndbfree(t);
- }
- /*
- * read the database into the cache
- */
- static void
- dbpair2cache(DN *dp, Ndbtuple *entry, Ndbtuple *pair)
- {
- RR *rp;
- static ulong ord;
- rp = 0;
- if(cistrcmp(pair->attr, "ip") == 0){
- dp->ordinal = ord++;
- rp = addrrr(entry, pair);
- } else if(cistrcmp(pair->attr, "ns") == 0)
- rp = nsrr(entry, pair);
- else if(cistrcmp(pair->attr, "soa") == 0) {
- rp = soarr(entry, pair);
- addarea(dp, rp, pair);
- } else if(cistrcmp(pair->attr, "mx") == 0)
- rp = mxrr(entry, pair);
- else if(cistrcmp(pair->attr, "srv") == 0)
- rp = srvrr(entry, pair);
- else if(cistrcmp(pair->attr, "cname") == 0)
- rp = cnamerr(entry, pair);
- else if(cistrcmp(pair->attr, "nullrr") == 0)
- rp = nullrr(entry, pair);
- else if(cistrcmp(pair->attr, "txtrr") == 0)
- rp = txtrr(entry, pair);
- if(rp == nil)
- return;
- rp->owner = dp;
- rp->db = 1;
- rp->ttl = intval(entry, pair, "ttl", rp->ttl);
- rrattach(rp, Notauthoritative);
- }
- static void
- dbtuple2cache(Ndbtuple *t)
- {
- Ndbtuple *et, *nt;
- DN *dp;
- for(et = t; et; et = et->entry)
- if(strcmp(et->attr, "dom") == 0){
- dp = dnlookup(et->val, Cin, 1);
- /* first same line */
- for(nt = et->line; nt != et; nt = nt->line){
- dbpair2cache(dp, t, nt);
- nt->ptr = 1;
- }
- /* then rest of entry */
- for(nt = t; nt; nt = nt->entry){
- if(nt->ptr == 0)
- dbpair2cache(dp, t, nt);
- nt->ptr = 0;
- }
- }
- }
- static void
- dbfile2cache(Ndb *db)
- {
- Ndbtuple *t;
- if(debug)
- dnslog("rereading %s", db->file);
- Bseek(&db->b, 0, 0);
- while(t = ndbparse(db)){
- dbtuple2cache(t);
- ndbfree(t);
- }
- }
- /* called with dblock held */
- static void
- loaddomsrvs(void)
- {
- Ndbs s;
- if (!cfg.inside || !cfg.straddle || !cfg.serve)
- return;
- if (indoms) {
- ndbfree(indoms);
- ndbfree(innmsrvs);
- ndbfree(outnmsrvs);
- indoms = innmsrvs = outnmsrvs = nil;
- }
- if (db == nil)
- opendatabase();
- free(ndbgetvalue(db, &s, "sys", "inside-dom", "dom", &indoms));
- free(ndbgetvalue(db, &s, "sys", "inside-ns", "ip", &innmsrvs));
- free(ndbgetvalue(db, &s, "sys", "outside-ns", "ip", &outnmsrvs));
- dnslog("[%d] ndb changed: reloaded inside-dom, inside-ns, outside-ns",
- getpid());
- }
- void
- db2cache(int doit)
- {
- ulong youngest, temp;
- Ndb *ndb;
- Dir *d;
- static ulong lastcheck, lastyoungest;
- /* no faster than once every 2 minutes */
- if(now < lastcheck + 2*Min && !doit)
- return;
- refresh_areas(owned);
- lock(&dblock);
- if(opendatabase() < 0){
- unlock(&dblock);
- return;
- }
- /*
- * file may be changing as we are reading it, so loop till
- * mod times are consistent.
- *
- * we don't use the times in the ndb records because they may
- * change outside of refreshing our cached knowledge.
- */
- for(;;){
- lastcheck = now;
- youngest = 0;
- for(ndb = db; ndb; ndb = ndb->next)
- /* dirfstat avoids walking the mount table each time */
- if((d = dirfstat(Bfildes(&ndb->b))) != nil ||
- (d = dirstat(ndb->file)) != nil){
- temp = d->mtime; /* ulong vs int crap */
- if(temp > youngest)
- youngest = temp;
- free(d);
- }
- if(!doit && youngest == lastyoungest)
- break;
- /* forget our area definition */
- freearea(&owned);
- freearea(&delegated);
- /* reopen all the files (to get oldest for time stamp) */
- for(ndb = db; ndb; ndb = ndb->next)
- ndbreopen(ndb);
- /* reload straddle-server configuration */
- loaddomsrvs();
- if(cfg.cachedb){
- /* mark all db records as timed out */
- dnagedb();
- /* read in new entries */
- for(ndb = db; ndb; ndb = ndb->next)
- dbfile2cache(ndb);
- /* mark as authoritative anything in our domain */
- dnauthdb();
- /* remove old entries */
- dnageall(1);
- } else
- /* read all the soa's to get database defaults */
- for(ndb = db; ndb; ndb = ndb->next)
- dbfile2area(ndb);
- doit = 0;
- lastyoungest = youngest;
- createptrs();
- }
- unlock(&dblock);
- }
- void
- dnforceage(void)
- {
- lock(&dblock);
- dnageall(1);
- unlock(&dblock);
- }
- extern uchar ipaddr[IPaddrlen]; /* my ip address */
- /*
- * get all my xxx
- * caller ndbfrees the result
- */
- Ndbtuple*
- lookupinfo(char *attr)
- {
- char buf[64];
- char *a[2];
- Ndbtuple *t;
- snprint(buf, sizeof buf, "%I", ipaddr);
- a[0] = attr;
- lock(&dblock);
- if(opendatabase() < 0){
- unlock(&dblock);
- return nil;
- }
- t = ndbipinfo(db, "ip", buf, a, 1);
- unlock(&dblock);
- return t;
- }
- char *localservers = "local#dns#servers";
- char *localserverprefix = "local#dns#server";
- /*
- * return non-zero if this is a bad delegation
- */
- int
- baddelegation(RR *rp, RR *nsrp, uchar *addr)
- {
- Ndbtuple *nt;
- static int whined;
- static Ndbtuple *t;
- if(t == nil)
- t = lookupinfo("dom");
- if(t == nil)
- return 0;
- for(; rp; rp = rp->next){
- if(rp->type != Tns)
- continue;
- /* see if delegation is looping */
- if(nsrp)
- if(rp->owner != nsrp->owner)
- if(subsume(rp->owner->name, nsrp->owner->name) &&
- strcmp(nsrp->owner->name, localservers) != 0){
- dnslog("delegation loop %R -> %R from %I",
- nsrp, rp, addr);
- return 1;
- }
- /* see if delegating to us what we don't own */
- for(nt = t; nt != nil; nt = nt->entry)
- if(rp->host && cistrcmp(rp->host->name, nt->val) == 0)
- break;
- if(nt != nil && !inmyarea(rp->owner->name)){
- if (!whined) {
- whined = 1;
- dnslog("bad delegation %R from %I; "
- "no further logging of them", rp, addr);
- }
- return 1;
- }
- }
- return 0;
- }
- int
- myaddr(char *addr)
- {
- char *name, *line, *sp;
- char buf[64];
- Biobuf *bp;
- snprint(buf, sizeof buf, "%I", ipaddr);
- if (strcmp(addr, buf) == 0) {
- dnslog("rejecting my ip %s as local dns server", addr);
- return 1;
- }
- name = smprint("%s/ipselftab", mntpt);
- bp = Bopen(name, OREAD);
- free(name);
- if (bp != nil) {
- while ((line = Brdline(bp, '\n')) != nil) {
- line[Blinelen(bp) - 1] = '\0';
- sp = strchr(line, ' ');
- if (sp) {
- *sp = '\0';
- if (strcmp(addr, line) == 0) {
- dnslog("rejecting my ip %s as local dns server",
- addr);
- return 1;
- }
- }
- }
- Bterm(bp);
- }
- return 0;
- }
- static char *locdns[20];
- static QLock locdnslck;
- static void
- addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
- {
- int n;
- DN *nsdp;
- RR *rp;
- char buf[32];
- /* reject our own ip addresses so we don't query ourselves via udp */
- if (myaddr(ipaddr))
- return;
- qlock(&locdnslck);
- for (n = 0; n < i && n < nelem(locdns) && locdns[n]; n++)
- if (strcmp(locdns[n], ipaddr) == 0) {
- dnslog("rejecting duplicate local dns server ip %s",
- ipaddr);
- qunlock(&locdnslck);
- return;
- }
- if (n < nelem(locdns))
- if (locdns[n] == nil || ++n < nelem(locdns))
- locdns[n] = strdup(ipaddr); /* remember 1st few local ns */
- qunlock(&locdnslck);
- /* ns record for name server, make up an impossible name */
- rp = rralloc(Tns);
- snprint(buf, sizeof buf, "%s%d", localserverprefix, i);
- nsdp = dnlookup(buf, class, 1);
- rp->host = nsdp;
- rp->owner = dp; /* e.g., local#dns#servers */
- rp->local = 1;
- rp->db = 1;
- // rp->ttl = 10*Min; /* seems too short */
- rp->ttl = (1UL<<31)-1;
- rrattach(rp, Authoritative); /* will not attach rrs in my area */
- /* A record */
- rp = rralloc(Ta);
- rp->ip = dnlookup(ipaddr, class, 1);
- rp->owner = nsdp;
- rp->local = 1;
- rp->db = 1;
- // rp->ttl = 10*Min; /* seems too short */
- rp->ttl = (1UL<<31)-1;
- rrattach(rp, Authoritative); /* will not attach rrs in my area */
- dnslog("added local dns server %s at %s", buf, ipaddr);
- }
- /*
- * return list of dns server addresses to use when
- * acting just as a resolver.
- */
- RR*
- dnsservers(int class)
- {
- int i, n;
- char *p;
- char *args[5];
- Ndbtuple *t, *nt;
- RR *nsrp;
- DN *dp;
- dp = dnlookup(localservers, class, 1);
- nsrp = rrlookup(dp, Tns, NOneg);
- if(nsrp != nil)
- return 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);
- free(p);
- } else {
- t = lookupinfo("@dns"); /* @dns=ip1 @dns=ip2 ... */
- if(t == nil)
- return nil;
- i = 0;
- for(nt = t; nt != nil; nt = nt->entry){
- addlocaldnsserver(dp, class, nt->val, i);
- i++;
- }
- ndbfree(t);
- }
- return rrlookup(dp, Tns, NOneg);
- }
- static void
- addlocaldnsdomain(DN *dp, int class, char *domain)
- {
- RR *rp;
- /* ptr record */
- rp = rralloc(Tptr);
- rp->ptr = dnlookup(domain, class, 1);
- rp->owner = dp;
- rp->db = 1;
- rp->ttl = 10*Min;
- rrattach(rp, Authoritative);
- }
- /*
- * return list of domains to use when resolving names without '.'s
- */
- RR*
- domainlist(int class)
- {
- Ndbtuple *t, *nt;
- RR *rp;
- DN *dp;
- dp = dnlookup("local#dns#domains", class, 1);
- rp = rrlookup(dp, Tptr, NOneg);
- if(rp != nil)
- return rp;
- t = lookupinfo("dnsdomain");
- if(t == nil)
- return nil;
- for(nt = t; nt != nil; nt = nt->entry)
- addlocaldnsdomain(dp, class, nt->val);
- ndbfree(t);
- return rrlookup(dp, Tptr, NOneg);
- }
- char *v4ptrdom = ".in-addr.arpa";
- char *v6ptrdom = ".ip6.arpa"; /* ip6.int deprecated, rfc 3152 */
- char *attribs[] = {
- "ipmask",
- 0
- };
- /*
- * create ptrs that are in our v4 areas
- */
- static void
- createv4ptrs(void)
- {
- int len, dlen, n;
- char *dom;
- char buf[Domlen+1], ipa[48];
- char *f[40];
- uchar net[IPaddrlen], mask[IPaddrlen];
- Area *s;
- Ndbtuple *t, *nt;
- dlen = strlen(v4ptrdom);
- for(s = owned; s; s = s->next){
- dom = s->soarr->owner->name;
- len = strlen(dom);
- if((len <= dlen || cistrcmp(dom+len-dlen, v4ptrdom) != 0) &&
- cistrcmp(dom, v4ptrdom+1) != 0)
- continue;
- /* get mask and net value */
- strncpy(buf, dom, sizeof buf);
- buf[sizeof buf-1] = 0;
- /* buf contains something like 178.204.in-addr.arpa (n==4) */
- n = getfields(buf, f, nelem(f), 0, ".");
- memset(mask, 0xff, IPaddrlen);
- ipmove(net, v4prefix);
- switch(n){
- case 3: /* /8 */
- net[IPv4off] = atoi(f[0]);
- mask[IPv4off+1] = 0;
- mask[IPv4off+2] = 0;
- mask[IPv4off+3] = 0;
- break;
- case 4: /* /16 */
- net[IPv4off] = atoi(f[1]);
- net[IPv4off+1] = atoi(f[0]);
- mask[IPv4off+2] = 0;
- mask[IPv4off+3] = 0;
- break;
- case 5: /* /24 */
- net[IPv4off] = atoi(f[2]);
- net[IPv4off+1] = atoi(f[1]);
- net[IPv4off+2] = atoi(f[0]);
- mask[IPv4off+3] = 0;
- break;
- case 6: /* rfc2317: classless in-addr.arpa delegation */
- net[IPv4off] = atoi(f[3]);
- net[IPv4off+1] = atoi(f[2]);
- net[IPv4off+2] = atoi(f[1]);
- net[IPv4off+3] = atoi(f[0]);
- sprint(ipa, "%I", net);
- t = ndbipinfo(db, "ip", ipa, attribs, 1);
- if(t == nil) /* could be a reverse with no forward */
- continue;
- nt = look(t, t, "ipmask");
- if(nt == nil){ /* we're confused */
- ndbfree(t);
- continue;
- }
- parseipmask(mask, nt->val);
- ndbfree(t);
- n = 5;
- break;
- default:
- continue;
- }
- /*
- * go through all domain entries looking for RR's
- * in this network and create ptrs.
- * +2 for ".in-addr.arpa".
- */
- dnptr(net, mask, dom, Ta, 4+2-n, Ptrttl);
- }
- }
- /* convert bytes to nibbles, big-endian */
- void
- bytes2nibbles(uchar *nibbles, uchar *bytes, int nbytes)
- {
- while (nbytes-- > 0) {
- *nibbles++ = *bytes >> Nibwidth;
- *nibbles++ = *bytes++ & Nibmask;
- }
- }
- void
- nibbles2bytes(uchar *bytes, uchar *nibbles, int nnibs)
- {
- for (; nnibs >= 2; nnibs -= 2) {
- *bytes++ = nibbles[0] << Nibwidth | (nibbles[1]&Nibmask);
- nibbles += 2;
- }
- if (nnibs > 0)
- *bytes = nibbles[0] << Nibwidth;
- }
- /*
- * create ptrs that are in our v6 areas. see rfc3596
- */
- static void
- createv6ptrs(void)
- {
- int len, dlen, i, n, pfxnibs;
- char *dom;
- char buf[Domlen+1];
- char *f[40];
- uchar net[IPaddrlen], mask[IPaddrlen];
- uchar nibnet[IPaddrlen*2], nibmask[IPaddrlen*2];
- Area *s;
- dlen = strlen(v6ptrdom);
- for(s = owned; s; s = s->next){
- dom = s->soarr->owner->name;
- len = strlen(dom);
- if((len <= dlen || cistrcmp(dom+len-dlen, v6ptrdom) != 0) &&
- cistrcmp(dom, v6ptrdom+1) != 0)
- continue;
- /* get mask and net value */
- strncpy(buf, dom, sizeof buf);
- buf[sizeof buf-1] = 0;
- /* buf contains something like 2.0.0.2.ip6.arpa (n==6) */
- n = getfields(buf, f, nelem(f), 0, ".");
- pfxnibs = n - 2; /* 2 for .ip6.arpa */
- if (pfxnibs < 0 || pfxnibs > V6maxrevdomdepth)
- continue;
- memset(net, 0, IPaddrlen);
- memset(mask, 0xff, IPaddrlen);
- bytes2nibbles(nibnet, net, IPaddrlen);
- bytes2nibbles(nibmask, mask, IPaddrlen);
- /* copy prefix of f, in reverse order, to start of net. */
- for (i = 0; i < pfxnibs; i++)
- nibnet[i] = strtol(f[pfxnibs - 1 - i], nil, 16);
- /* zero nibbles of mask after prefix in net */
- memset(nibmask + pfxnibs, 0, V6maxrevdomdepth - pfxnibs);
- nibbles2bytes(net, nibnet, 2*IPaddrlen);
- nibbles2bytes(mask, nibmask, 2*IPaddrlen);
- /*
- * go through all domain entries looking for RR's
- * in this network and create ptrs.
- */
- dnptr(net, mask, dom, Taaaa, V6maxrevdomdepth - pfxnibs, Ptrttl);
- }
- }
- /*
- * create ptrs that are in our areas
- */
- static void
- createptrs(void)
- {
- createv4ptrs();
- createv6ptrs();
- }
- /*
- * is this domain (or DOMAIN or Domain or dOMAIN)
- * internal to our organisation (behind our firewall)?
- * only inside straddling servers care, everybody else gets told `yes',
- * so they'll use mntpt for their queries.
- */
- int
- insideaddr(char *dom)
- {
- int domlen, vallen, rv;
- Ndbtuple *t;
- if (!cfg.inside || !cfg.straddle || !cfg.serve)
- return 1;
- lock(&dblock);
- if (indoms == nil)
- loaddomsrvs();
- if (indoms == nil) {
- unlock(&dblock);
- return 1; /* no "inside" sys, try inside nameservers */
- }
- rv = 0;
- domlen = strlen(dom);
- for (t = indoms; t != nil; t = t->entry) {
- if (strcmp(t->attr, "dom") != 0)
- continue;
- vallen = strlen(t->val);
- if (cistrcmp(dom, t->val) == 0 ||
- domlen > vallen &&
- cistrcmp(dom + domlen - vallen, t->val) == 0 &&
- dom[domlen - vallen - 1] == '.') {
- rv = 1;
- break;
- }
- }
- unlock(&dblock);
- return rv;
- }
- int
- insidens(uchar *ip)
- {
- uchar ipa[IPaddrlen];
- Ndbtuple *t;
- for (t = innmsrvs; t != nil; t = t->entry)
- if (strcmp(t->attr, "ip") == 0) {
- parseip(ipa, t->val);
- if (memcmp(ipa, ip, sizeof ipa) == 0)
- return 1;
- }
- return 0;
- }
- uchar *
- outsidens(int n)
- {
- int i;
- Ndbtuple *t;
- static uchar ipa[IPaddrlen];
- i = 0;
- for (t = outnmsrvs; t != nil; t = t->entry)
- if (strcmp(t->attr, "ip") == 0 && i++ == n) {
- parseip(ipa, t->val);
- return ipa;
- }
- return nil;
- }
|