/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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 = 120,}; 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 voidnstrcpy(char *to, char *from, int len){ strncpy(to, from, len); to[len-1] = 0;} intopendatabase(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; /* so far only internet lookups are implemented */ if(class != Cin) return 0; err = Rname; rp = nil; if(type == Tall){ for (type = Ta; type < Tall; type++) if(implemented[type]) { tp = dblookup(name, class, type, auth, ttl); lock(&dnlock); rrcat(&rp, tp); unlock(&dnlock); } return rp; } 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 ulongintval(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 Taaaa: attr = "ipv6"; 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); } /*Lines 1–500 of 1258. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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 = 120, }; 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; /* so far only internet lookups are implemented */ if(class != Cin) return 0; err = Rname; rp = nil; if(type == Tall){ for (type = Ta; type < Tall; type++) if(implemented[type]) { tp = dblookup(name, class, type, auth, ttl); lock(&dnlock); rrcat(&rp, tp); unlock(&dnlock); } return rp; } 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 Taaaa: attr = "ipv6"; 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); } /*