URI:
       tdblookup.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tdblookup.c (18040B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <ndb.h>
            5 #include <ip.h>
            6 #include "dns.h"
            7 
            8 static Ndb *db;
            9 
           10 static RR*        dblookup1(char*, int, int, int);
           11 static RR*        addrrr(Ndbtuple*, Ndbtuple*);
           12 static RR*        nsrr(Ndbtuple*, Ndbtuple*);
           13 static RR*        cnamerr(Ndbtuple*, Ndbtuple*);
           14 static RR*        mxrr(Ndbtuple*, Ndbtuple*);
           15 static RR*        soarr(Ndbtuple*, Ndbtuple*);
           16 static RR*        ptrrr(Ndbtuple*, Ndbtuple*);
           17 static Ndbtuple* look(Ndbtuple*, Ndbtuple*, char*);
           18 static RR*        doaxfr(Ndb*, char*);
           19 static RR*        nullrr(Ndbtuple *entry, Ndbtuple *pair);
           20 static RR*        txtrr(Ndbtuple *entry, Ndbtuple *pair);
           21 static Lock        dblock;
           22 static void        createptrs(void);
           23 
           24 static int        implemented[Tall] =
           25 {
           26         0,
           27         /* Ta */ 1,
           28         /* Tns */ 1,
           29         0,
           30         0,
           31         /* Tcname */ 1,
           32         /* Tsoa */ 1,
           33         0,
           34         0,
           35         0,
           36         /* Tnull */ 1,
           37         0,
           38         /* Tptr */ 1,
           39         0,
           40         0,
           41         /* Tmx */ 1,
           42         /* Ttxt */ 1
           43 };
           44 
           45 static void
           46 nstrcpy(char *to, char *from, int len)
           47 {
           48         strncpy(to, from, len);
           49         to[len-1] = 0;
           50 }
           51 
           52 int
           53 opendatabase(void)
           54 {
           55         char buf[256];
           56         Ndb *xdb;
           57 
           58         if(db == nil){
           59                 snprint(buf, sizeof(buf), "%s/ndb", mntpt);
           60                 xdb = ndbopen(dbfile);
           61                 if(xdb != nil)
           62                         xdb->nohash = 1;
           63                 db = ndbcat(ndbopen(buf), xdb);
           64         }
           65         if(db == nil)
           66                 return -1;
           67         else
           68                 return 0;
           69 }
           70 
           71 /*
           72  *  lookup an RR in the network database, look for matches
           73  *  against both the domain name and the wildcarded domain name.
           74  *
           75  *  the lock makes sure only one process can be accessing the data
           76  *  base at a time.  This is important since there's a lot of
           77  *  shared state there.
           78  *
           79  *  e.g. for x.research.bell-labs.com, first look for a match against
           80  *       the x.research.bell-labs.com.  If nothing matches, try *.research.bell-labs.com.
           81  */
           82 RR*
           83 dblookup(char *name, int class, int type, int auth, int ttl)
           84 {
           85         RR *rp, *tp;
           86         char buf[256];
           87         char *wild, *cp;
           88         DN *dp, *ndp;
           89         int err;
           90 
           91         /* so far only internet lookups are implemented */
           92         if(class != Cin)
           93                 return 0;
           94 
           95         err = Rname;
           96 
           97         if(type == Tall){
           98                 rp = 0;
           99                 for (type = Ta; type < Tall; type++)
          100                         if(implemented[type])
          101                                 rrcat(&rp, dblookup(name, class, type, auth, ttl));
          102                 return rp;
          103         }
          104 
          105         lock(&dblock);
          106         rp = nil;
          107         dp = dnlookup(name, class, 1);
          108         if(opendatabase() < 0)
          109                 goto out;
          110         if(dp->rr)
          111                 err = 0;
          112 
          113         /* first try the given name */
          114         rp = 0;
          115         if(cachedb)
          116                 rp = rrlookup(dp, type, NOneg);
          117         else
          118                 rp = dblookup1(name, type, auth, ttl);
          119         if(rp)
          120                 goto out;
          121 
          122         /* try lower case version */
          123         for(cp = name; *cp; cp++)
          124                 *cp = tolower((uchar)*cp);
          125         if(cachedb)
          126                 rp = rrlookup(dp, type, NOneg);
          127         else
          128                 rp = dblookup1(name, type, auth, ttl);
          129         if(rp)
          130                 goto out;
          131 
          132         /* walk the domain name trying the wildcard '*' at each position */
          133         for(wild = strchr(name, '.'); wild; wild = strchr(wild+1, '.')){
          134                 snprint(buf, sizeof(buf), "*%s", wild);
          135                 ndp = dnlookup(buf, class, 1);
          136                 if(ndp->rr)
          137                         err = 0;
          138                 if(cachedb)
          139                         rp = rrlookup(ndp, type, NOneg);
          140                 else
          141                         rp = dblookup1(buf, type, auth, ttl);
          142                 if(rp)
          143                         break;
          144         }
          145 out:
          146         /* add owner to uncached records */
          147         if(rp){
          148                 for(tp = rp; tp; tp = tp->next)
          149                         tp->owner = dp;
          150         } else {
          151                 /* don't call it non-existent if it's not ours */
          152                 if(err == Rname && !inmyarea(name))
          153                         err = Rserver;
          154                 dp->nonexistent = err;
          155         }
          156 
          157         unlock(&dblock);
          158         return rp;
          159 }
          160 
          161 /*
          162  *  lookup an RR in the network database
          163  */
          164 static RR*
          165 dblookup1(char *name, int type, int auth, int ttl)
          166 {
          167         Ndbtuple *t, *nt;
          168         RR *rp, *list, **l;
          169         Ndbs s;
          170         char dname[Domlen];
          171         char *attr;
          172         DN *dp;
          173         RR *(*f)(Ndbtuple*, Ndbtuple*);
          174         int found, x;
          175 
          176         dp = 0;
          177         switch(type){
          178         case Tptr:
          179                 attr = "ptr";
          180                 f = ptrrr;
          181                 break;
          182         case Ta:
          183                 attr = "ip";
          184                 f = addrrr;
          185                 break;
          186         case Tnull:
          187                 attr = "nullrr";
          188                 f = nullrr;
          189                 break;
          190         case Tns:
          191                 attr = "ns";
          192                 f = nsrr;
          193                 break;
          194         case Tsoa:
          195                 attr = "soa";
          196                 f = soarr;
          197                 break;
          198         case Tmx:
          199                 attr = "mx";
          200                 f = mxrr;
          201                 break;
          202         case Tcname:
          203                 attr = "cname";
          204                 f = cnamerr;
          205                 break;
          206         case Taxfr:
          207         case Tixfr:
          208                 return doaxfr(db, name);
          209         default:
          210                 return nil;
          211         }
          212 
          213         /*
          214          *  find a matching entry in the database
          215          */
          216         free(ndbgetvalue(db, &s, "dom", name, attr, &t));
          217 
          218         /*
          219          *  hack for local names
          220          */
          221         if(t == 0 && strchr(name, '.') == 0)
          222                 free(ndbgetvalue(db, &s, "sys", name, attr, &t));
          223         if(t == 0)
          224                 return nil;
          225 
          226         /* search whole entry for default domain name */
          227         strncpy(dname, name, sizeof dname);
          228         for(nt = t; nt; nt = nt->entry)
          229                 if(strcmp(nt->attr, "dom") == 0){
          230                         nstrcpy(dname, nt->val, sizeof dname);
          231                         break;
          232                 }
          233 
          234         /* ttl is maximum of soa minttl and entry's ttl ala rfc883 */
          235         nt = look(t, s.t, "ttl");
          236         if(nt){
          237                 x = atoi(nt->val);
          238                 if(x > ttl)
          239                         ttl = x;
          240         }
          241 
          242         /* default ttl is one day */
          243         if(ttl < 0)
          244                 ttl = DEFTTL;
          245 
          246         /*
          247          *  The database has 2 levels of precedence; line and entry.
          248          *  Pairs on the same line bind tighter than pairs in the
          249          *  same entry, so we search the line first.
          250          */
          251         found = 0;
          252         list = 0;
          253         l = &list;
          254         for(nt = s.t;; ){
          255                 if(found == 0 && strcmp(nt->attr, "dom") == 0){
          256                         nstrcpy(dname, nt->val, sizeof dname);
          257                         found = 1;
          258                 }
          259                 if(cistrcmp(attr, nt->attr) == 0){
          260                         rp = (*f)(t, nt);
          261                         rp->auth = auth;
          262                         rp->db = 1;
          263                         if(ttl)
          264                                 rp->ttl = ttl;
          265                         if(dp == 0)
          266                                 dp = dnlookup(dname, Cin, 1);
          267                         rp->owner = dp;
          268                         *l = rp;
          269                         l = &rp->next;
          270                         nt->ptr = 1;
          271                 }
          272                 nt = nt->line;
          273                 if(nt == s.t)
          274                         break;
          275         }
          276 
          277         /* search whole entry */
          278         for(nt = t; nt; nt = nt->entry)
          279                 if(nt->ptr == 0 && cistrcmp(attr, nt->attr) == 0){
          280                         rp = (*f)(t, nt);
          281                         rp->db = 1;
          282                         if(ttl)
          283                                 rp->ttl = ttl;
          284                         rp->auth = auth;
          285                         if(dp == 0)
          286                                 dp = dnlookup(dname, Cin, 1);
          287                         rp->owner = dp;
          288                         *l = rp;
          289                         l = &rp->next;
          290                 }
          291         ndbfree(t);
          292 
          293         return list;
          294 }
          295 
          296 /*
          297  *  make various types of resource records from a database entry
          298  */
          299 static RR*
          300 addrrr(Ndbtuple *entry, Ndbtuple *pair)
          301 {
          302         RR *rp;
          303         uchar addr[IPaddrlen];
          304 
          305         USED(entry);
          306         parseip(addr, pair->val);
          307         if(isv4(addr))
          308                 rp = rralloc(Ta);
          309         else
          310                 rp = rralloc(Taaaa);
          311         rp->ip = dnlookup(pair->val, Cin, 1);
          312         return rp;
          313 }
          314 static RR*
          315 nullrr(Ndbtuple *entry, Ndbtuple *pair)
          316 {
          317         RR *rp;
          318 
          319         USED(entry);
          320         rp = rralloc(Tnull);
          321         rp->null->data = (uchar*)estrdup(pair->val);
          322         rp->null->dlen = strlen((char*)rp->null->data);
          323         return rp;
          324 }
          325 /*
          326  *  txt rr strings are at most 255 bytes long.  one
          327  *  can represent longer strings by multiple concatenated
          328  *  <= 255 byte ones.
          329  */
          330 static RR*
          331 txtrr(Ndbtuple *entry, Ndbtuple *pair)
          332 {
          333         RR *rp;
          334         Txt *t, **l;
          335         int i, len, sofar;
          336 
          337         USED(entry);
          338         rp = rralloc(Ttxt);
          339         l = &rp->txt;
          340         rp->txt = nil;
          341         len = strlen(pair->val);
          342         sofar = 0;
          343         while(len > sofar){
          344                 t = emalloc(sizeof(*t));
          345                 t->next = nil;
          346 
          347                 i = len-sofar;
          348                 if(i > 255)
          349                         i = 255;
          350 
          351                 t->p = emalloc(i+1);
          352                 memmove(t->p, pair->val+sofar, i);
          353                 t->p[i] = 0;
          354                 sofar += i;
          355 
          356                 *l = t;
          357                 l = &t->next;
          358         }
          359         return rp;
          360 }
          361 static RR*
          362 cnamerr(Ndbtuple *entry, Ndbtuple *pair)
          363 {
          364         RR *rp;
          365 
          366         USED(entry);
          367         rp = rralloc(Tcname);
          368         rp->host = dnlookup(pair->val, Cin, 1);
          369         return rp;
          370 }
          371 static RR*
          372 mxrr(Ndbtuple *entry, Ndbtuple *pair)
          373 {
          374         RR * rp;
          375 
          376         rp = rralloc(Tmx);
          377         rp->host = dnlookup(pair->val, Cin, 1);
          378         pair = look(entry, pair, "pref");
          379         if(pair)
          380                 rp->pref = atoi(pair->val);
          381         else
          382                 rp->pref = 1;
          383         return rp;
          384 }
          385 static RR*
          386 nsrr(Ndbtuple *entry, Ndbtuple *pair)
          387 {
          388         RR *rp;
          389         Ndbtuple *t;
          390 
          391         rp = rralloc(Tns);
          392         rp->host = dnlookup(pair->val, Cin, 1);
          393         t = look(entry, pair, "soa");
          394         if(t && t->val[0] == 0)
          395                 rp->local = 1;
          396         return rp;
          397 }
          398 static RR*
          399 ptrrr(Ndbtuple *entry, Ndbtuple *pair)
          400 {
          401         RR *rp;
          402 
          403         USED(entry);
          404         rp = rralloc(Tns);
          405         rp->ptr = dnlookup(pair->val, Cin, 1);
          406         return rp;
          407 }
          408 static RR*
          409 soarr(Ndbtuple *entry, Ndbtuple *pair)
          410 {
          411         RR *rp;
          412         Ndbtuple *ns, *mb, *t;
          413         char mailbox[Domlen];
          414         Ndb *ndb;
          415         char *p;
          416 
          417         rp = rralloc(Tsoa);
          418         rp->soa->serial = 1;
          419         for(ndb = db; ndb; ndb = ndb->next)
          420                 if(ndb->mtime > rp->soa->serial)
          421                         rp->soa->serial = ndb->mtime;
          422         rp->soa->refresh = Day;
          423         rp->soa->retry = Hour;
          424         rp->soa->expire = Day;
          425         rp->soa->minttl = Day;
          426         t = look(entry, pair, "ttl");
          427         if(t)
          428                 rp->soa->minttl = atoi(t->val);
          429         t = look(entry, pair, "refresh");
          430         if(t)
          431                 rp->soa->refresh = atoi(t->val);
          432         t = look(entry, pair, "serial");
          433         if(t)
          434                 rp->soa->serial = strtoul(t->val, 0, 10);
          435 
          436         ns = look(entry, pair, "ns");
          437         if(ns == 0)
          438                 ns = look(entry, pair, "dom");
          439         rp->host = dnlookup(ns->val, Cin, 1);
          440 
          441         /* accept all of:
          442          *  mbox=person
          443          *  mbox=person@machine.dom
          444          *  mbox=person.machine.dom
          445          */
          446         mb = look(entry, pair, "mbox");
          447         if(mb == nil)
          448                 mb = look(entry, pair, "mb");
          449         if(mb){
          450                 if(strchr(mb->val, '.')) {
          451                         p = strchr(mb->val, '@');
          452                         if(p != nil)
          453                                 *p = '.';
          454                         rp->rmb = dnlookup(mb->val, Cin, 1);
          455                 } else {
          456                         snprint(mailbox, sizeof(mailbox), "%s.%s",
          457                                 mb->val, ns->val);
          458                         rp->rmb = dnlookup(mailbox, Cin, 1);
          459                 }
          460         } else {
          461                 snprint(mailbox, sizeof(mailbox), "postmaster.%s",
          462                         ns->val);
          463                 rp->rmb = dnlookup(mailbox, Cin, 1);
          464         }
          465 
          466         /*  hang dns slaves off of the soa.  this is
          467          *  for managing the area.
          468          */
          469         for(t = entry; t != nil; t = t->entry)
          470                 if(strcmp(t->attr, "dnsslave") == 0)
          471                         addserver(&rp->soa->slaves, t->val);
          472 
          473         return rp;
          474 }
          475 
          476 /*
          477  *  Look for a pair with the given attribute.  look first on the same line,
          478  *  then in the whole entry.
          479  */
          480 static Ndbtuple*
          481 look(Ndbtuple *entry, Ndbtuple *line, char *attr)
          482 {
          483         Ndbtuple *nt;
          484 
          485         /* first look on same line (closer binding) */
          486         for(nt = line;;){
          487                 if(cistrcmp(attr, nt->attr) == 0)
          488                         return nt;
          489                 nt = nt->line;
          490                 if(nt == line)
          491                         break;
          492         }
          493         /* search whole tuple */
          494         for(nt = entry; nt; nt = nt->entry)
          495                 if(cistrcmp(attr, nt->attr) == 0)
          496                         return nt;
          497         return 0;
          498 }
          499 
          500 /* these are answered specially by the tcp version */
          501 static RR*
          502 doaxfr(Ndb *db, char *name)
          503 {
          504         USED(db);
          505         USED(name);
          506         return 0;
          507 }
          508 
          509 
          510 /*
          511  *  read the all the soa's from the database to determine area's.
          512  *  this is only used when we're not caching the database.
          513  */
          514 static void
          515 dbfile2area(Ndb *db)
          516 {
          517         Ndbtuple *t;
          518 
          519         if(debug)
          520                 syslog(0, logfile, "rereading %s", db->file);
          521         Bseek(&db->b, 0, 0);
          522         while(t = ndbparse(db)){
          523                 ndbfree(t);
          524         }
          525 }
          526 
          527 /*
          528  *  read the database into the cache
          529  */
          530 static void
          531 dbpair2cache(DN *dp, Ndbtuple *entry, Ndbtuple *pair)
          532 {
          533         RR *rp;
          534         Ndbtuple *t;
          535         static ulong ord;
          536 
          537         rp = 0;
          538         if(cistrcmp(pair->attr, "ip") == 0){
          539                 dp->ordinal = ord++;
          540                 rp = addrrr(entry, pair);
          541         } else         if(cistrcmp(pair->attr, "ns") == 0){
          542                 rp = nsrr(entry, pair);
          543         } else if(cistrcmp(pair->attr, "soa") == 0){
          544                 rp = soarr(entry, pair);
          545                 addarea(dp, rp, pair);
          546         } else if(cistrcmp(pair->attr, "mx") == 0){
          547                 rp = mxrr(entry, pair);
          548         } else if(cistrcmp(pair->attr, "cname") == 0){
          549                 rp = cnamerr(entry, pair);
          550         } else if(cistrcmp(pair->attr, "nullrr") == 0){
          551                 rp = nullrr(entry, pair);
          552         } else if(cistrcmp(pair->attr, "txtrr") == 0){
          553                 rp = txtrr(entry, pair);
          554         }
          555 
          556         if(rp == 0)
          557                 return;
          558 
          559         rp->owner = dp;
          560         rp->db = 1;
          561         t = look(entry, pair, "ttl");
          562         if(t)
          563                 rp->ttl = atoi(t->val);
          564         rrattach(rp, 0);
          565 }
          566 static void
          567 dbtuple2cache(Ndbtuple *t)
          568 {
          569         Ndbtuple *et, *nt;
          570         DN *dp;
          571 
          572         for(et = t; et; et = et->entry){
          573                 if(strcmp(et->attr, "dom") == 0){
          574                         dp = dnlookup(et->val, Cin, 1);
          575 
          576                         /* first same line */
          577                         for(nt = et->line; nt != et; nt = nt->line){
          578                                 dbpair2cache(dp, t, nt);
          579                                 nt->ptr = 1;
          580                         }
          581 
          582                         /* then rest of entry */
          583                         for(nt = t; nt; nt = nt->entry){
          584                                 if(nt->ptr == 0)
          585                                         dbpair2cache(dp, t, nt);
          586                                 nt->ptr = 0;
          587                         }
          588                 }
          589         }
          590 }
          591 static void
          592 dbfile2cache(Ndb *db)
          593 {
          594         Ndbtuple *t;
          595 
          596         if(debug)
          597                 syslog(0, logfile, "rereading %s", db->file);
          598         Bseek(&db->b, 0, 0);
          599         while(t = ndbparse(db)){
          600                 dbtuple2cache(t);
          601                 ndbfree(t);
          602         }
          603 }
          604 void
          605 db2cache(int doit)
          606 {
          607         Ndb *ndb;
          608         Dir *d;
          609         ulong youngest, temp;
          610         static ulong lastcheck;
          611         static ulong lastyoungest;
          612 
          613         /* no faster than once every 2 minutes */
          614         if(now < lastcheck + 2*Min && !doit)
          615                 return;
          616 
          617         refresh_areas(owned);
          618 
          619         lock(&dblock);
          620 
          621         if(opendatabase() < 0){
          622                 unlock(&dblock);
          623                 return;
          624         }
          625 
          626         /*
          627          *  file may be changing as we are reading it, so loop till
          628          *  mod times are consistent.
          629          *
          630          *  we don't use the times in the ndb records because they may
          631          *  change outside of refreshing our cached knowledge.
          632          */
          633         for(;;){
          634                 lastcheck = now;
          635                 youngest = 0;
          636                 for(ndb = db; ndb; ndb = ndb->next){
          637                         /* the dirfstat avoids walking the mount table each time */
          638                         if((d = dirfstat(Bfildes(&ndb->b))) != nil ||
          639                            (d = dirstat(ndb->file)) != nil){
          640                                 temp = d->mtime;                /* ulong vs int crap */
          641                                 if(temp > youngest)
          642                                         youngest = temp;
          643                                 free(d);
          644                         }
          645                 }
          646                 if(!doit && youngest == lastyoungest){
          647                         unlock(&dblock);
          648                         return;
          649                 }
          650 
          651                 /* forget our area definition */
          652                 freearea(&owned);
          653                 freearea(&delegated);
          654 
          655                 /* reopen all the files (to get oldest for time stamp) */
          656                 for(ndb = db; ndb; ndb = ndb->next)
          657                         ndbreopen(ndb);
          658 
          659                 if(cachedb){
          660                         /* mark all db records as timed out */
          661                         dnagedb();
          662 
          663                         /* read in new entries */
          664                         for(ndb = db; ndb; ndb = ndb->next)
          665                                 dbfile2cache(ndb);
          666 
          667                         /* mark as authentic anything in our domain */
          668                         dnauthdb();
          669 
          670                         /* remove old entries */
          671                         dnageall(1);
          672                 } else {
          673                         /* read all the soa's to get database defaults */
          674                         for(ndb = db; ndb; ndb = ndb->next)
          675                                 dbfile2area(ndb);
          676                 }
          677 
          678                 doit = 0;
          679                 lastyoungest = youngest;
          680                 createptrs();
          681         }
          682 
          683         unlock(&dblock);
          684 }
          685 
          686 extern uchar        ipaddr[IPaddrlen];
          687 
          688 /*
          689  *  get all my xxx
          690  */
          691 Ndbtuple*
          692 lookupinfo(char *attr)
          693 {
          694         char buf[64];
          695         char *a[2];
          696         static Ndbtuple *t;
          697 
          698         snprint(buf, sizeof buf, "%I", ipaddr);
          699         a[0] = attr;
          700 
          701         lock(&dblock);
          702         if(opendatabase() < 0){
          703                 unlock(&dblock);
          704                 return nil;
          705         }
          706         t = ndbipinfo(db, "ip", buf, a, 1);
          707         unlock(&dblock);
          708         return t;
          709 }
          710 
          711 char *localservers = "local#dns#servers";
          712 char *localserverprefix = "local#dns#server";
          713 
          714 /*
          715  *  return non-zero is this is a bad delegation
          716  */
          717 int
          718 baddelegation(RR *rp, RR *nsrp, uchar *addr)
          719 {
          720         Ndbtuple *nt;
          721         static Ndbtuple *t;
          722 
          723         if(t == nil)
          724                 t = lookupinfo("dom");
          725         if(t == nil)
          726                 return 0;
          727 
          728         for(; rp; rp = rp->next){
          729                 if(rp->type != Tns)
          730                         continue;
          731 
          732                 /* see if delegation is looping */
          733                 if(nsrp)
          734                 if(rp->owner != nsrp->owner)
          735                 if(subsume(rp->owner->name, nsrp->owner->name) &&
          736                    strcmp(nsrp->owner->name, localservers) != 0){
          737                         syslog(0, logfile, "delegation loop %R -> %R from %I", nsrp, rp, addr);
          738                         return 1;
          739                 }
          740 
          741                 /* see if delegating to us what we don't own */
          742                 for(nt = t; nt != nil; nt = nt->entry)
          743                         if(rp->host && cistrcmp(rp->host->name, nt->val) == 0)
          744                                 break;
          745                 if(nt != nil && !inmyarea(rp->owner->name)){
          746                         syslog(0, logfile, "bad delegation %R from %I", rp, addr);
          747                         return 1;
          748                 }
          749         }
          750 
          751         return 0;
          752 }
          753 
          754 static void
          755 addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
          756 {
          757         DN *nsdp;
          758         RR *rp;
          759         char buf[32];
          760 
          761         /* ns record for name server, make up an impossible name */
          762         rp = rralloc(Tns);
          763         snprint(buf, sizeof(buf), "%s%d", localserverprefix, i);
          764         nsdp = dnlookup(buf, class, 1);
          765         rp->host = nsdp;
          766         rp->owner = dp;
          767         rp->local = 1;
          768         rp->db = 1;
          769         rp->ttl = 10*Min;
          770         rrattach(rp, 1);
          771 
          772 print("dns %s\n", ipaddr);
          773         /* A record */
          774         rp = rralloc(Ta);
          775         rp->ip = dnlookup(ipaddr, class, 1);
          776         rp->owner = nsdp;
          777         rp->local = 1;
          778         rp->db = 1;
          779         rp->ttl = 10*Min;
          780         rrattach(rp, 1);
          781 }
          782 
          783 /*
          784  *  return list of dns server addresses to use when
          785  *  acting just as a resolver.
          786  */
          787 RR*
          788 dnsservers(int class)
          789 {
          790         Ndbtuple *t, *nt;
          791         RR *nsrp;
          792         DN *dp;
          793         char *p;
          794         int i, n;
          795         char *buf, *args[5];
          796 
          797         dp = dnlookup(localservers, class, 1);
          798         nsrp = rrlookup(dp, Tns, NOneg);
          799         if(nsrp != nil)
          800                 return nsrp;
          801 
          802         p = getenv("DNSSERVER");
          803         if(p != nil){
          804                 buf = estrdup(p);
          805                 n = tokenize(buf, args, nelem(args));
          806                 for(i = 0; i < n; i++)
          807                         addlocaldnsserver(dp, class, args[i], i);
          808                 free(buf);
          809         } else {
          810                 t = lookupinfo("@dns");
          811                 if(t == nil)
          812                         return nil;
          813                 i = 0;
          814                 for(nt = t; nt != nil; nt = nt->entry){
          815                         addlocaldnsserver(dp, class, nt->val, i);
          816                         i++;
          817                 }
          818                 ndbfree(t);
          819         }
          820 
          821         return rrlookup(dp, Tns, NOneg);
          822 }
          823 
          824 static void
          825 addlocaldnsdomain(DN *dp, int class, char *domain)
          826 {
          827         RR *rp;
          828 
          829         /* A record */
          830         rp = rralloc(Tptr);
          831         rp->ptr = dnlookup(domain, class, 1);
          832         rp->owner = dp;
          833         rp->db = 1;
          834         rp->ttl = 10*Min;
          835         rrattach(rp, 1);
          836 }
          837 
          838 /*
          839  *  return list of domains to use when resolving names without '.'s
          840  */
          841 RR*
          842 domainlist(int class)
          843 {
          844         Ndbtuple *t, *nt;
          845         RR *rp;
          846         DN *dp;
          847 
          848         dp = dnlookup("local#dns#domains", class, 1);
          849         rp = rrlookup(dp, Tptr, NOneg);
          850         if(rp != nil)
          851                 return rp;
          852 
          853         t = lookupinfo("dnsdomain");
          854         if(t == nil)
          855                 return nil;
          856         for(nt = t; nt != nil; nt = nt->entry)
          857                 addlocaldnsdomain(dp, class, nt->val);
          858         ndbfree(t);
          859 
          860         return rrlookup(dp, Tptr, NOneg);
          861 }
          862 
          863 char *v4ptrdom = ".in-addr.arpa";
          864 char *v6ptrdom = ".ip6.arpa";                /* ip6.int deprecated, rfc 3152 */
          865 
          866 char *attribs[] = {
          867         "ipmask",
          868         0
          869 };
          870 
          871 /*
          872  *  create ptrs that are in our areas
          873  */
          874 static void
          875 createptrs(void)
          876 {
          877         int len, dlen, n;
          878         Area *s;
          879         char *f[40];
          880         char buf[Domlen+1];
          881         uchar net[IPaddrlen];
          882         uchar mask[IPaddrlen];
          883         char ipa[48];
          884         Ndbtuple *t, *nt;
          885 
          886         dlen = strlen(v4ptrdom);
          887         for(s = owned; s; s = s->next){
          888                 len = strlen(s->soarr->owner->name);
          889                 if(len <= dlen)
          890                         continue;
          891                 if(cistrcmp(s->soarr->owner->name+len-dlen, v4ptrdom) != 0)
          892                         continue;
          893 
          894                 /* get mask and net value */
          895                 strncpy(buf, s->soarr->owner->name, sizeof(buf));
          896                 buf[sizeof(buf)-1] = 0;
          897                 n = getfields(buf, f, nelem(f), 0, ".");
          898                 memset(mask, 0xff, IPaddrlen);
          899                 ipmove(net, v4prefix);
          900                 switch(n){
          901                 case 3: /* /8 */
          902                         net[IPv4off] = atoi(f[0]);
          903                         mask[IPv4off+1] = 0;
          904                         mask[IPv4off+2] = 0;
          905                         mask[IPv4off+3] = 0;
          906                         break;
          907                 case 4: /* /16 */
          908                         net[IPv4off] = atoi(f[1]);
          909                         net[IPv4off+1] = atoi(f[0]);
          910                         mask[IPv4off+2] = 0;
          911                         mask[IPv4off+3] = 0;
          912                         break;
          913                 case 5: /* /24 */
          914                         net[IPv4off] = atoi(f[2]);
          915                         net[IPv4off+1] = atoi(f[1]);
          916                         net[IPv4off+2] = atoi(f[0]);
          917                         mask[IPv4off+3] = 0;
          918                         break;
          919                 case 6:        /* rfc2317 */
          920                         net[IPv4off] = atoi(f[3]);
          921                         net[IPv4off+1] = atoi(f[2]);
          922                         net[IPv4off+2] = atoi(f[1]);
          923                         net[IPv4off+3] = atoi(f[0]);
          924                         sprint(ipa, "%I", net);
          925                         t = ndbipinfo(db, "ip", ipa, attribs, 1);
          926                         if(t == nil) /* could be a reverse with no forward */
          927                                 continue;
          928                         nt = look(t, t, "ipmask");
          929                         if(nt == nil){        /* we're confused */
          930                                 ndbfree(t);
          931                                 continue;
          932                         }
          933                         parseipmask(mask, nt->val);
          934                         n = 5;
          935                         break;
          936                 default:
          937                         continue;
          938                 }
          939 
          940                 /* go through all domain entries looking for RR's in this network and create ptrs */
          941                 dnptr(net, mask, s->soarr->owner->name, 6-n, 0);
          942         }
          943 }