aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ndb/dblookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ndb/dblookup.c')
-rwxr-xr-xsrc/cmd/ndb/dblookup.c946
1 files changed, 946 insertions, 0 deletions
diff --git a/src/cmd/ndb/dblookup.c b/src/cmd/ndb/dblookup.c
new file mode 100755
index 00000000..f81f37df
--- /dev/null
+++ b/src/cmd/ndb/dblookup.c
@@ -0,0 +1,946 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ndb.h>
+#include <ip.h>
+#include "dns.h"
+
+static Ndb *db;
+
+static RR* dblookup1(char*, int, int, int);
+static RR* addrrr(Ndbtuple*, Ndbtuple*);
+static RR* nsrr(Ndbtuple*, Ndbtuple*);
+static RR* cnamerr(Ndbtuple*, Ndbtuple*);
+static RR* mxrr(Ndbtuple*, Ndbtuple*);
+static RR* soarr(Ndbtuple*, Ndbtuple*);
+static RR* ptrrr(Ndbtuple*, Ndbtuple*);
+static Ndbtuple* look(Ndbtuple*, Ndbtuple*, char*);
+static RR* doaxfr(Ndb*, char*);
+static RR* nullrr(Ndbtuple *entry, Ndbtuple *pair);
+static RR* txtrr(Ndbtuple *entry, Ndbtuple *pair);
+static Lock dblock;
+static void createptrs(void);
+
+static int implemented[Tall] =
+{
+ [Ta] 1,
+ [Tns] 1,
+ [Tsoa] 1,
+ [Tmx] 1,
+ [Tptr] 1,
+ [Tcname] 1,
+ [Tnull] 1,
+ [Ttxt] 1,
+};
+
+static void
+nstrcpy(char *to, char *from, int len)
+{
+ strncpy(to, from, len);
+ to[len-1] = 0;
+}
+
+int
+opendatabase(void)
+{
+ char buf[256];
+ Ndb *xdb;
+
+ if(db == nil){
+ snprint(buf, sizeof(buf), "%s/ndb", mntpt);
+ xdb = ndbopen(dbfile);
+ if(xdb != nil)
+ xdb->nohash = 1;
+ db = ndbcat(ndbopen(buf), xdb);
+ }
+ if(db == nil)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+ * 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)
+{
+ RR *rp, *tp;
+ char buf[256];
+ char *wild, *cp;
+ DN *dp, *ndp;
+ int err;
+ 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 = 0;
+ for (type = Ta; type < Tall; type++)
+ if(implemented[type])
+ rrcat(&rp, dblookup(name, class, type, auth, ttl));
+ return rp;
+ }
+
+ lock(&dblock);
+ dp = dnlookup(name, class, 1);
+ if(opendatabase() < 0)
+ goto out;
+ if(dp->rr)
+ err = 0;
+
+ /* first try the given name */
+ rp = 0;
+ if(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(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(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 */
+ if(err == Rname && !inmyarea(name))
+ err = Rserver;
+ dp->nonexistent = err;
+ }
+
+ unlock(&dblock);
+ return rp;
+}
+
+/*
+ * 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 = 0;
+ 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 Tmx:
+ attr = "mx";
+ f = mxrr;
+ break;
+ case Tcname:
+ attr = "cname";
+ f = cnamerr;
+ break;
+ case Taxfr:
+ case Tixfr:
+ return doaxfr(db, name);
+ default:
+ return nil;
+ }
+
+ /*
+ * find a matching entry in the database
+ */
+ free(ndbgetvalue(db, &s, "dom", name, attr, &t));
+
+ /*
+ * hack for local names
+ */
+ if(t == 0 && strchr(name, '.') == 0)
+ free(ndbgetvalue(db, &s, "sys", name, attr, &t));
+ if(t == 0)
+ 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 */
+ nt = look(t, s.t, "ttl");
+ if(nt){
+ x = atoi(nt->val);
+ 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 == 0)
+ 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 == 0)
+ dp = dnlookup(dname, Cin, 1);
+ rp->owner = dp;
+ *l = rp;
+ l = &rp->next;
+ }
+ ndbfree(t);
+
+ 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);
+ pair = look(entry, pair, "pref");
+ if(pair)
+ rp->pref = atoi(pair->val);
+ else
+ rp->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->refresh = Day;
+ rp->soa->retry = Hour;
+ rp->soa->expire = Day;
+ rp->soa->minttl = Day;
+ t = look(entry, pair, "ttl");
+ if(t)
+ rp->soa->minttl = atoi(t->val);
+ t = look(entry, pair, "refresh");
+ if(t)
+ rp->soa->refresh = atoi(t->val);
+ t = look(entry, pair, "serial");
+ if(t)
+ rp->soa->serial = strtoul(t->val, 0, 10);
+
+ ns = look(entry, pair, "ns");
+ if(ns == 0)
+ 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;
+}
+
+/*
+ * 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);
+ USED(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)
+ syslog(0, logfile, "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;
+ Ndbtuple *t;
+ 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, "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 == 0)
+ return;
+
+ rp->owner = dp;
+ rp->db = 1;
+ t = look(entry, pair, "ttl");
+ if(t)
+ rp->ttl = atoi(t->val);
+ rrattach(rp, 0);
+}
+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)
+ syslog(0, logfile, "rereading %s", db->file);
+ Bseek(&db->b, 0, 0);
+ while(t = ndbparse(db)){
+ dbtuple2cache(t);
+ ndbfree(t);
+ }
+}
+void
+db2cache(int doit)
+{
+ Ndb *ndb;
+ Dir *d;
+ ulong youngest, temp;
+ static ulong lastcheck;
+ static ulong 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){
+ /* the 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){
+ unlock(&dblock);
+ return;
+ }
+
+ /* 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);
+
+ if(cachedb){
+ /* mark all db records as timed out */
+ dnagedb();
+
+ /* read in new entries */
+ for(ndb = db; ndb; ndb = ndb->next)
+ dbfile2cache(ndb);
+
+ /* mark as authentic 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);
+}
+
+extern uchar ipaddr[IPaddrlen];
+
+/*
+ * get all my xxx
+ */
+Ndbtuple*
+lookupinfo(char *attr)
+{
+ char buf[64];
+ char *a[2];
+ static 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 is this is a bad delegation
+ */
+int
+baddelegation(RR *rp, RR *nsrp, uchar *addr)
+{
+ Ndbtuple *nt;
+ 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){
+ syslog(0, logfile, "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)){
+ syslog(0, logfile, "bad delegation %R from %I", rp, addr);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
+{
+ DN *nsdp;
+ RR *rp;
+ char buf[32];
+
+ /* 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;
+ rp->local = 1;
+ rp->db = 1;
+ rp->ttl = 10*Min;
+ rrattach(rp, 1);
+
+print("dns %s\n", ipaddr);
+ /* A record */
+ rp = rralloc(Ta);
+ rp->ip = dnlookup(ipaddr, class, 1);
+ rp->owner = nsdp;
+ rp->local = 1;
+ rp->db = 1;
+ rp->ttl = 10*Min;
+ rrattach(rp, 1);
+}
+
+/*
+ * return list of dns server addresses to use when
+ * acting just as a resolver.
+ */
+RR*
+dnsservers(int class)
+{
+ Ndbtuple *t, *nt;
+ RR *nsrp;
+ DN *dp;
+ char *p;
+ int i, n;
+ char *buf, *args[5];
+
+ dp = dnlookup(localservers, class, 1);
+ nsrp = rrlookup(dp, Tns, NOneg);
+ if(nsrp != nil)
+ return nsrp;
+
+ p = getenv("DNSSERVER");
+ if(p != nil){
+ buf = estrdup(p);
+ n = tokenize(buf, args, nelem(args));
+ for(i = 0; i < n; i++)
+ addlocaldnsserver(dp, class, args[i], i);
+ free(buf);
+ } else {
+ t = lookupinfo("@dns");
+ 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;
+
+ /* A record */
+ rp = rralloc(Tptr);
+ rp->ptr = dnlookup(domain, class, 1);
+ rp->owner = dp;
+ rp->db = 1;
+ rp->ttl = 10*Min;
+ rrattach(rp, 1);
+}
+
+/*
+ * 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 areas
+ */
+static void
+createptrs(void)
+{
+ int len, dlen, n;
+ Area *s;
+ char *f[40];
+ char buf[Domlen+1];
+ uchar net[IPaddrlen];
+ uchar mask[IPaddrlen];
+ char ipa[48];
+ Ndbtuple *t, *nt;
+
+ dlen = strlen(v4ptrdom);
+ for(s = owned; s; s = s->next){
+ len = strlen(s->soarr->owner->name);
+ if(len <= dlen)
+ continue;
+ if(cistrcmp(s->soarr->owner->name+len-dlen, v4ptrdom) != 0)
+ continue;
+
+ /* get mask and net value */
+ strncpy(buf, s->soarr->owner->name, sizeof(buf));
+ buf[sizeof(buf)-1] = 0;
+ 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 */
+ 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);
+ n = 5;
+ break;
+ default:
+ continue;
+ }
+
+ /* go through all domain entries looking for RR's in this network and create ptrs */
+ dnptr(net, mask, s->soarr->owner->name, 6-n, 0);
+ }
+}