| #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] = |
| { |
| 0, |
| /* Ta */ 1, |
| /* Tns */ 1, |
| 0, |
| 0, |
| /* Tcname */ 1, |
| /* Tsoa */ 1, |
| 0, |
| 0, |
| 0, |
| /* Tnull */ 1, |
| 0, |
| /* Tptr */ 1, |
| 0, |
| 0, |
| /* Tmx */ 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; |
| |
| /* 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); |
| rp = nil; |
| 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((uchar)*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; |
| } |
| |
| /* 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); |
| } |
| } |