]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/dblookup.c
merge
[plan9front.git] / sys / src / cmd / ndb / dblookup.c
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 enum {
9         Nibwidth = 4,
10         Nibmask = (1<<Nibwidth) - 1,
11         V6maxrevdomdepth = 128 / Nibwidth,      /* bits / bits-per-nibble */
12
13         /*
14          * ttl for generated ptr records.  it was zero, which might seem
15          * like a good idea, but some dns implementations seem to be
16          * confused by a zero ttl, and instead of using the data and then
17          * discarding the RR, they conclude that they don't have valid data.
18          */
19         Ptrttl = 120,
20 };
21
22 static Ndb *db;
23 static Lock     dblock;
24
25 static RR*      addrrr(Ndbtuple*, Ndbtuple*);
26 static RR*      cnamerr(Ndbtuple*, Ndbtuple*);
27 static void     createptrs(void);
28 static RR*      dblookup1(char*, int, int, int);
29 static RR*      doaxfr(Ndb*, char*);
30 static Ndbtuple*look(Ndbtuple*, Ndbtuple*, char*);
31 static RR*      mxrr(Ndbtuple*, Ndbtuple*);
32 static RR*      nsrr(Ndbtuple*, Ndbtuple*);
33 static RR*      nullrr(Ndbtuple*, Ndbtuple*);
34 static RR*      ptrrr(Ndbtuple*, Ndbtuple*);
35 static RR*      soarr(Ndbtuple*, Ndbtuple*);
36 static RR*      srvrr(Ndbtuple*, Ndbtuple*);
37 static RR*      txtrr(Ndbtuple*, Ndbtuple*);
38
39 static int      implemented[Tall] =
40 {
41         [Ta]            1,
42         [Taaaa]         1,
43         [Tcname]        1,
44         [Tmx]           1,
45         [Tns]           1,
46         [Tnull]         1,
47         [Tptr]          1,
48         [Tsoa]          1,
49         [Tsrv]          1,
50         [Ttxt]          1,
51 };
52
53 /* straddle server configuration */
54 static Ndbtuple *indoms, *innmsrvs, *outnmsrvs;
55
56 static void
57 nstrcpy(char *to, char *from, int len)
58 {
59         strncpy(to, from, len);
60         to[len-1] = 0;
61 }
62
63 int
64 opendatabase(void)
65 {
66         char netdbnm[256];
67         Ndb *xdb, *netdb;
68
69         if (db)
70                 return 0;
71
72         xdb = ndbopen(dbfile);          /* /lib/ndb */
73
74         snprint(netdbnm, sizeof netdbnm, "%s/ndb", mntpt);
75         for(netdb = xdb; netdb; netdb = netdb->next)
76                 if(strcmp(netdb->file, netdbnm) == 0){
77                         db = xdb;
78                         return 0;
79                 }
80
81         netdb = ndbopen(netdbnm);       /* /net/ndb */
82         if(netdb)
83                 netdb->nohash = 1;
84
85         db = ndbcat(netdb, xdb);        /* both */
86         return db? 0: -1;
87 }
88
89 /*
90  *  lookup an RR in the network database, look for matches
91  *  against both the domain name and the wildcarded domain name.
92  *
93  *  the lock makes sure only one process can be accessing the data
94  *  base at a time.  This is important since there's a lot of
95  *  shared state there.
96  *
97  *  e.g. for x.research.bell-labs.com, first look for a match against
98  *       the x.research.bell-labs.com.  If nothing matches,
99  *       try *.research.bell-labs.com.
100  */
101 RR*
102 dblookup(char *name, int class, int type, int auth, int ttl)
103 {
104         int err;
105         char *wild, *cp;
106         char buf[256];
107         RR *rp, *tp;
108         DN *dp, *ndp;
109
110         /* so far only internet lookups are implemented */
111         if(class != Cin)
112                 return 0;
113
114         err = Rname;
115         rp = nil;
116
117         if(type == Tall){
118                 for (type = Ta; type < Tall; type++)
119                         if(implemented[type])
120                                 rrcat(&rp, dblookup(name, class, type, auth, ttl));
121
122                 return rp;
123         }
124
125         lock(&dblock);
126         dp = dnlookup(name, class, 1);
127
128         if(opendatabase() < 0)
129                 goto out;
130         if(dp->rr)
131                 err = 0;
132
133         /* first try the given name */
134         if(cfg.cachedb)
135                 rp = rrlookup(dp, type, NOneg);
136         else
137                 rp = dblookup1(name, type, auth, ttl);
138         if(rp)
139                 goto out;
140
141         /* try lower case version */
142         for(cp = name; *cp; cp++)
143                 *cp = tolower(*cp);
144         if(cfg.cachedb)
145                 rp = rrlookup(dp, type, NOneg);
146         else
147                 rp = dblookup1(name, type, auth, ttl);
148         if(rp)
149                 goto out;
150
151         /* walk the domain name trying the wildcard '*' at each position */
152         for(wild = strchr(name, '.'); wild; wild = strchr(wild+1, '.')){
153                 snprint(buf, sizeof buf, "*%s", wild);
154                 ndp = dnlookup(buf, class, 1);
155                 if(ndp->rr)
156                         err = 0;
157                 if(cfg.cachedb)
158                         rp = rrlookup(ndp, type, NOneg);
159                 else
160                         rp = dblookup1(buf, type, auth, ttl);
161                 if(rp)
162                         break;
163         }
164 out:
165         /* add owner to uncached records */
166         if(rp)
167                 for(tp = rp; tp; tp = tp->next)
168                         tp->owner = dp;
169         else {
170                 /*
171                  * don't call it non-existent if it's not ours
172                  * (unless we're a resolver).
173                  */
174                 if(err == Rname && (!inmyarea(name) || cfg.resolver))
175                         err = Rserver;
176                 dp->respcode = err;
177         }
178
179         unlock(&dblock);
180         return rp;
181 }
182
183 static ulong
184 intval(Ndbtuple *entry, Ndbtuple *pair, char *attr, ulong def)
185 {
186         Ndbtuple *t = look(entry, pair, attr);
187
188         return (t? strtoul(t->val, 0, 10): def);
189 }
190
191 /*
192  *  lookup an RR in the network database
193  */
194 static RR*
195 dblookup1(char *name, int type, int auth, int ttl)
196 {
197         Ndbtuple *t, *nt;
198         RR *rp, *list, **l;
199         Ndbs s;
200         char dname[Domlen];
201         char *attr;
202         DN *dp;
203         RR *(*f)(Ndbtuple*, Ndbtuple*);
204         int found, x;
205
206         dp = nil;
207         switch(type){
208         case Tptr:
209                 attr = "ptr";
210                 f = ptrrr;
211                 break;
212         case Ta:
213                 attr = "ip";
214                 f = addrrr;
215                 break;
216         case Taaaa:
217                 attr = "ipv6";
218                 f = addrrr;
219                 break;
220         case Tnull:
221                 attr = "nullrr";
222                 f = nullrr;
223                 break;
224         case Tns:
225                 attr = "ns";
226                 f = nsrr;
227                 break;
228         case Tsoa:
229                 attr = "soa";
230                 f = soarr;
231                 break;
232         case Tsrv:
233                 attr = "srv";
234                 f = srvrr;
235                 break;
236         case Tmx:
237                 attr = "mx";
238                 f = mxrr;
239                 break;
240         case Tcname:
241                 attr = "cname";
242                 f = cnamerr;
243                 break;
244         case Taxfr:
245         case Tixfr:
246                 return doaxfr(db, name);
247         default:
248 //              dnslog("dnlookup1(%s) bad type", name);
249                 return nil;
250         }
251
252         /*
253          *  find a matching entry in the database
254          */
255         t = nil;
256         free(ndbgetvalue(db, &s, "dom", name, attr, &t));
257
258         /*
259          *  hack for local names
260          */
261         if(t == nil && strchr(name, '.') == nil)
262                 free(ndbgetvalue(db, &s, "sys", name, attr, &t));
263         if(t == nil) {
264 //              dnslog("dnlookup1(%s) name not found", name);
265                 return nil;
266         }
267
268         /* search whole entry for default domain name */
269         strncpy(dname, name, sizeof dname);
270         for(nt = t; nt; nt = nt->entry)
271                 if(strcmp(nt->attr, "dom") == 0){
272                         nstrcpy(dname, nt->val, sizeof dname);
273                         break;
274                 }
275
276         /* ttl is maximum of soa minttl and entry's ttl ala rfc883 */
277         x = intval(t, s.t, "ttl", 0);
278         if(x > ttl)
279                 ttl = x;
280
281         /* default ttl is one day */
282         if(ttl < 0)
283                 ttl = DEFTTL;
284
285         /*
286          *  The database has 2 levels of precedence; line and entry.
287          *  Pairs on the same line bind tighter than pairs in the
288          *  same entry, so we search the line first.
289          */
290         found = 0;
291         list = 0;
292         l = &list;
293         for(nt = s.t;; ){
294                 if(found == 0 && strcmp(nt->attr, "dom") == 0){
295                         nstrcpy(dname, nt->val, sizeof dname);
296                         found = 1;
297                 }
298                 if(cistrcmp(attr, nt->attr) == 0){
299                         rp = (*f)(t, nt);
300                         rp->auth = auth;
301                         rp->db = 1;
302                         if(ttl)
303                                 rp->ttl = ttl;
304                         if(dp == nil)
305                                 dp = dnlookup(dname, Cin, 1);
306                         rp->owner = dp;
307                         *l = rp;
308                         l = &rp->next;
309                         nt->ptr = 1;
310                 }
311                 nt = nt->line;
312                 if(nt == s.t)
313                         break;
314         }
315
316         /* search whole entry */
317         for(nt = t; nt; nt = nt->entry)
318                 if(nt->ptr == 0 && cistrcmp(attr, nt->attr) == 0){
319                         rp = (*f)(t, nt);
320                         rp->db = 1;
321                         if(ttl)
322                                 rp->ttl = ttl;
323                         rp->auth = auth;
324                         if(dp == nil)
325                                 dp = dnlookup(dname, Cin, 1);
326                         rp->owner = dp;
327                         *l = rp;
328                         l = &rp->next;
329                 }
330         ndbfree(t);
331
332 //      dnslog("dnlookup1(%s) -> %#p", name, list);
333         return list;
334 }
335
336 /*
337  *  make various types of resource records from a database entry
338  */
339 static RR*
340 addrrr(Ndbtuple *entry, Ndbtuple *pair)
341 {
342         RR *rp;
343         uchar addr[IPaddrlen];
344
345         USED(entry);
346         parseip(addr, pair->val);
347         if(isv4(addr))
348                 rp = rralloc(Ta);
349         else
350                 rp = rralloc(Taaaa);
351         rp->ip = dnlookup(pair->val, Cin, 1);
352         return rp;
353 }
354 static RR*
355 nullrr(Ndbtuple *entry, Ndbtuple *pair)
356 {
357         RR *rp;
358
359         USED(entry);
360         rp = rralloc(Tnull);
361         rp->null->data = (uchar*)estrdup(pair->val);
362         rp->null->dlen = strlen((char*)rp->null->data);
363         return rp;
364 }
365 /*
366  *  txt rr strings are at most 255 bytes long.  one
367  *  can represent longer strings by multiple concatenated
368  *  <= 255 byte ones.
369  */
370 static RR*
371 txtrr(Ndbtuple *entry, Ndbtuple *pair)
372 {
373         RR *rp;
374         Txt *t, **l;
375         int i, len, sofar;
376
377         USED(entry);
378         rp = rralloc(Ttxt);
379         l = &rp->txt;
380         rp->txt = nil;
381         len = strlen(pair->val);
382         sofar = 0;
383         while(len > sofar){
384                 t = emalloc(sizeof(*t));
385                 t->next = nil;
386
387                 i = len-sofar;
388                 if(i > 255)
389                         i = 255;
390
391                 t->p = emalloc(i+1);
392                 memmove(t->p, pair->val+sofar, i);
393                 t->p[i] = 0;
394                 sofar += i;
395
396                 *l = t;
397                 l = &t->next;
398         }
399         return rp;
400 }
401 static RR*
402 cnamerr(Ndbtuple *entry, Ndbtuple *pair)
403 {
404         RR *rp;
405
406         USED(entry);
407         rp = rralloc(Tcname);
408         rp->host = dnlookup(pair->val, Cin, 1);
409         return rp;
410 }
411 static RR*
412 mxrr(Ndbtuple *entry, Ndbtuple *pair)
413 {
414         RR *rp;
415
416         rp = rralloc(Tmx);
417         rp->host = dnlookup(pair->val, Cin, 1);
418         rp->pref = intval(entry, pair, "pref", 1);
419         return rp;
420 }
421 static RR*
422 nsrr(Ndbtuple *entry, Ndbtuple *pair)
423 {
424         RR *rp;
425         Ndbtuple *t;
426
427         rp = rralloc(Tns);
428         rp->host = dnlookup(pair->val, Cin, 1);
429         t = look(entry, pair, "soa");
430         if(t && t->val[0] == 0)
431                 rp->local = 1;
432         return rp;
433 }
434 static RR*
435 ptrrr(Ndbtuple *entry, Ndbtuple *pair)
436 {
437         RR *rp;
438
439         USED(entry);
440         rp = rralloc(Tns);
441         rp->ptr = dnlookup(pair->val, Cin, 1);
442         return rp;
443 }
444 static RR*
445 soarr(Ndbtuple *entry, Ndbtuple *pair)
446 {
447         RR *rp;
448         Ndbtuple *ns, *mb, *t;
449         char mailbox[Domlen];
450         Ndb *ndb;
451         char *p;
452
453         rp = rralloc(Tsoa);
454         rp->soa->serial = 1;
455         for(ndb = db; ndb; ndb = ndb->next)
456                 if(ndb->mtime > rp->soa->serial)
457                         rp->soa->serial = ndb->mtime;
458
459         rp->soa->retry  = intval(entry, pair, "retry", Hour);
460         rp->soa->expire = intval(entry, pair, "expire", Day);
461         rp->soa->minttl = intval(entry, pair, "ttl", Day);
462         rp->soa->refresh = intval(entry, pair, "refresh", Day);
463         rp->soa->serial = intval(entry, pair, "serial", rp->soa->serial);
464
465         ns = look(entry, pair, "ns");
466         if(ns == nil)
467                 ns = look(entry, pair, "dom");
468         rp->host = dnlookup(ns->val, Cin, 1);
469
470         /* accept all of:
471          *  mbox=person
472          *  mbox=person@machine.dom
473          *  mbox=person.machine.dom
474          */
475         mb = look(entry, pair, "mbox");
476         if(mb == nil)
477                 mb = look(entry, pair, "mb");
478         if(mb)
479                 if(strchr(mb->val, '.')) {
480                         p = strchr(mb->val, '@');
481                         if(p != nil)
482                                 *p = '.';
483                         rp->rmb = dnlookup(mb->val, Cin, 1);
484                 } else {
485                         snprint(mailbox, sizeof mailbox, "%s.%s",
486                                 mb->val, ns->val);
487                         rp->rmb = dnlookup(mailbox, Cin, 1);
488                 }
489         else {
490                 snprint(mailbox, sizeof mailbox, "postmaster.%s", ns->val);
491                 rp->rmb = dnlookup(mailbox, Cin, 1);
492         }
493
494         /*
495          *  hang dns slaves off of the soa.  this is
496          *  for managing the area.
497          */
498         for(t = entry; t != nil; t = t->entry)
499                 if(strcmp(t->attr, "dnsslave") == 0)
500                         addserver(&rp->soa->slaves, t->val);
501
502         return rp;
503 }
504
505 static RR*
506 srvrr(Ndbtuple *entry, Ndbtuple *pair)
507 {
508         RR *rp;
509
510         rp = rralloc(Tsrv);
511         rp->host = dnlookup(pair->val, Cin, 1);
512         rp->srv->pri = intval(entry, pair, "pri", 0);
513         rp->srv->weight = intval(entry, pair, "weight", 0);
514         /* TODO: translate service name to port # */
515         rp->port = intval(entry, pair, "port", 0);
516         return rp;
517 }
518
519 /*
520  *  Look for a pair with the given attribute.  look first on the same line,
521  *  then in the whole entry.
522  */
523 static Ndbtuple*
524 look(Ndbtuple *entry, Ndbtuple *line, char *attr)
525 {
526         Ndbtuple *nt;
527
528         /* first look on same line (closer binding) */
529         for(nt = line;;){
530                 if(cistrcmp(attr, nt->attr) == 0)
531                         return nt;
532                 nt = nt->line;
533                 if(nt == line)
534                         break;
535         }
536         /* search whole tuple */
537         for(nt = entry; nt; nt = nt->entry)
538                 if(cistrcmp(attr, nt->attr) == 0)
539                         return nt;
540         return 0;
541 }
542
543 static RR**
544 linkrr(RR *rp, DN *dp, RR **l)
545 {
546         rp->owner = dp;
547         rp->auth = 1;
548         rp->db = 1;
549         *l = rp;
550         return &rp->next;
551 }
552
553 /* these are answered specially by the tcp version */
554 static RR*
555 doaxfr(Ndb *db, char *name)
556 {
557         USED(db, name);
558         return 0;
559 }
560
561
562 /*
563  *  read the all the soa's from the database to determine area's.
564  *  this is only used when we're not caching the database.
565  */
566 static void
567 dbfile2area(Ndb *db)
568 {
569         Ndbtuple *t;
570
571         if(debug)
572                 dnslog("rereading %s", db->file);
573         Bseek(&db->b, 0, 0);
574         while(t = ndbparse(db))
575                 ndbfree(t);
576 }
577
578 /*
579  *  read the database into the cache
580  */
581 static void
582 dbpair2cache(DN *dp, Ndbtuple *entry, Ndbtuple *pair)
583 {
584         RR *rp;
585         static ulong ord;
586
587         rp = 0;
588         if(cistrcmp(pair->attr, "ip") == 0 ||
589            cistrcmp(pair->attr, "ipv6") == 0){
590                 dp->ordinal = ord++;
591                 rp = addrrr(entry, pair);
592         } else  if(cistrcmp(pair->attr, "ns") == 0)
593                 rp = nsrr(entry, pair);
594         else if(cistrcmp(pair->attr, "soa") == 0) {
595                 rp = soarr(entry, pair);
596                 addarea(dp, rp, pair);
597         } else if(cistrcmp(pair->attr, "mx") == 0)
598                 rp = mxrr(entry, pair);
599         else if(cistrcmp(pair->attr, "srv") == 0)
600                 rp = srvrr(entry, pair);
601         else if(cistrcmp(pair->attr, "cname") == 0)
602                 rp = cnamerr(entry, pair);
603         else if(cistrcmp(pair->attr, "nullrr") == 0)
604                 rp = nullrr(entry, pair);
605         else if(cistrcmp(pair->attr, "txtrr") == 0)
606                 rp = txtrr(entry, pair);
607         if(rp == nil)
608                 return;
609
610         rp->owner = dp;
611         dnagenever(dp, 1);
612         rp->db = 1;
613         rp->ttl = intval(entry, pair, "ttl", rp->ttl);
614         rrattach(rp, Notauthoritative);
615 }
616 static void
617 dbtuple2cache(Ndbtuple *t)
618 {
619         Ndbtuple *et, *nt;
620         DN *dp;
621
622         for(et = t; et; et = et->entry)
623                 if(strcmp(et->attr, "dom") == 0){
624                         dp = dnlookup(et->val, Cin, 1);
625
626                         /* first same line */
627                         for(nt = et->line; nt != et; nt = nt->line){
628                                 dbpair2cache(dp, t, nt);
629                                 nt->ptr = 1;
630                         }
631
632                         /* then rest of entry */
633                         for(nt = t; nt; nt = nt->entry){
634                                 if(nt->ptr == 0)
635                                         dbpair2cache(dp, t, nt);
636                                 nt->ptr = 0;
637                         }
638                 }
639 }
640 static void
641 dbfile2cache(Ndb *db)
642 {
643         Ndbtuple *t;
644
645         if(debug)
646                 dnslog("rereading %s", db->file);
647         Bseek(&db->b, 0, 0);
648         while(t = ndbparse(db)){
649                 dbtuple2cache(t);
650                 ndbfree(t);
651         }
652 }
653
654 /* called with dblock held */
655 static void
656 loaddomsrvs(void)
657 {
658         Ndbs s;
659
660         if (!cfg.inside || !cfg.straddle || !cfg.serve)
661                 return;
662         if (indoms) {
663                 ndbfree(indoms);
664                 ndbfree(innmsrvs);
665                 ndbfree(outnmsrvs);
666                 indoms = innmsrvs = outnmsrvs = nil;
667         }
668         if (db == nil)
669                 opendatabase();
670         free(ndbgetvalue(db, &s, "sys", "inside-dom", "dom", &indoms));
671         free(ndbgetvalue(db, &s, "sys", "inside-ns",  "ip",  &innmsrvs));
672         free(ndbgetvalue(db, &s, "sys", "outside-ns", "ip",  &outnmsrvs));
673         dnslog("[%d] ndb changed: reloaded inside-dom, inside-ns, outside-ns",
674                 getpid());
675 }
676
677 void
678 db2cache(int doit)
679 {
680         ulong youngest;
681         Ndb *ndb;
682         Dir *d;
683         static ulong lastcheck, lastyoungest;
684
685         /* no faster than once every 2 minutes */
686         if(now < lastcheck + 2*Min && !doit)
687                 return;
688
689         refresh_areas(owned);
690
691         lock(&dblock);
692
693         if(opendatabase() < 0){
694                 unlock(&dblock);
695                 return;
696         }
697
698         /*
699          *  file may be changing as we are reading it, so loop till
700          *  mod times are consistent.
701          *
702          *  we don't use the times in the ndb records because they may
703          *  change outside of refreshing our cached knowledge.
704          */
705         for(;;){
706                 lastcheck = now;
707                 youngest = 0;
708                 for(ndb = db; ndb; ndb = ndb->next)
709                         /* dirfstat avoids walking the mount table each time */
710                         if((d = dirfstat(Bfildes(&ndb->b))) != nil ||
711                            (d = dirstat(ndb->file)) != nil){
712                                 if(d->mtime > youngest)
713                                         youngest = d->mtime;
714                                 free(d);
715                         }
716                 if(!doit && youngest == lastyoungest)
717                         break;
718
719                 /* forget our area definition */
720                 freearea(&owned);
721                 freearea(&delegated);
722
723                 /* reopen all the files (to get oldest for time stamp) */
724                 for(ndb = db; ndb; ndb = ndb->next)
725                         ndbreopen(ndb);
726
727                 /* reload straddle-server configuration */
728                 loaddomsrvs();
729
730                 if(cfg.cachedb){
731                         /* mark all db records as timed out */
732                         dnagedb();
733
734                         /* read in new entries */
735                         for(ndb = db; ndb; ndb = ndb->next)
736                                 dbfile2cache(ndb);
737
738                         /* mark as authoritative anything in our domain */
739                         dnauthdb();
740
741                         /* remove old entries */
742                         dnageall(1);
743                 } else
744                         /* read all the soa's to get database defaults */
745                         for(ndb = db; ndb; ndb = ndb->next)
746                                 dbfile2area(ndb);
747
748                 doit = 0;
749                 lastyoungest = youngest;
750                 createptrs();
751         }
752
753         unlock(&dblock);
754 }
755
756 extern char     mntpt[Maxpath];         /* net mountpoint */
757 static uchar    ipaddr[IPaddrlen];      /* my ip address */
758
759 /*
760  *  get all my xxx
761  *  caller ndbfrees the result
762  */
763 Ndbtuple*
764 lookupinfo(char *attr)
765 {
766         char buf[64];
767         char *a[2];
768         Ndbtuple *t;
769
770         if(ipcmp(ipaddr, IPnoaddr) == 0)
771                 if(myipaddr(ipaddr, mntpt) < 0)
772                         return nil;
773
774         snprint(buf, sizeof buf, "%I", ipaddr);
775         a[0] = attr;
776
777         lock(&dblock);
778         if(opendatabase() < 0){
779                 unlock(&dblock);
780                 return nil;
781         }
782         t = ndbipinfo(db, "ip", buf, a, 1);
783         unlock(&dblock);
784         return t;
785 }
786
787 char *localservers =      "local#dns#servers";
788 char *localserverprefix = "local#dns#server";
789
790 /*
791  *  return non-zero if this is a bad delegation
792  */
793 int
794 baddelegation(RR *rp, RR *nsrp, uchar *addr)
795 {
796         Ndbtuple *nt;
797         static int whined;
798         static Ndbtuple *t;
799
800         if(t == nil)
801                 t = lookupinfo("dom");
802
803         for(; rp; rp = rp->next){
804                 if(rp->type != Tns)
805                         continue;
806
807                 /* see if delegation is looping */
808                 if(nsrp)
809                 if(rp->owner != nsrp->owner)
810                 if(subsume(rp->owner->name, nsrp->owner->name) &&
811                    strcmp(nsrp->owner->name, localservers) != 0){
812                         dnslog("delegation loop %R -> %R from %I",
813                                 nsrp, rp, addr);
814                         return 1;
815                 }
816
817                 if(t == nil)
818                         continue;
819
820                 /* see if delegating to us what we don't own */
821                 for(nt = t; nt != nil; nt = nt->entry)
822                         if(rp->host && cistrcmp(rp->host->name, nt->val) == 0)
823                                 break;
824                 if(nt != nil && !inmyarea(rp->owner->name)){
825                         if (!whined) {
826                                 whined = 1;
827                                 dnslog("bad delegation %R from %I; "
828                                         "no further logging of them", rp, addr);
829                         }
830                         return 1;
831                 }
832         }
833
834         return 0;
835 }
836
837 int
838 myaddr(char *addr)
839 {
840         char *line, *sp;
841         char buf[64];
842         Biobuf *bp;
843
844         if(ipcmp(ipaddr, IPnoaddr) == 0)
845                 if(myipaddr(ipaddr, mntpt) < 0)
846                         return -1;
847
848         snprint(buf, sizeof buf, "%I", ipaddr);
849         if (strcmp(addr, buf) == 0) {
850                 dnslog("rejecting my ip %s as local dns server", addr);
851                 return 1;
852         }
853
854         snprint(buf, sizeof buf, "%s/ipselftab", mntpt);
855         bp = Bopen(buf, OREAD);
856         if (bp != nil) {
857                 while ((line = Brdline(bp, '\n')) != nil) {
858                         line[Blinelen(bp) - 1] = '\0';
859                         sp = strchr(line, ' ');
860                         if (sp) {
861                                 *sp = '\0';
862                                 if (strcmp(addr, line) == 0) {
863                                         dnslog("rejecting my ip %s as local dns server",
864                                                 addr);
865                                         return 1;
866                                 }
867                         }
868                 }
869                 Bterm(bp);
870         }
871         return 0;
872 }
873
874 static char *locdns[20];
875 static QLock locdnslck;
876
877 static void
878 addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
879 {
880         int n;
881         DN *nsdp;
882         RR *rp;
883         char buf[32];
884         uchar ip[IPaddrlen];
885
886         /* reject our own ip addresses so we don't query ourselves via udp */
887         if (myaddr(ipaddr))
888                 return;
889
890         qlock(&locdnslck);
891         for (n = 0; n < i && n < nelem(locdns) && locdns[n]; n++)
892                 if (strcmp(locdns[n], ipaddr) == 0) {
893                         dnslog("rejecting duplicate local dns server ip %s",
894                                 ipaddr);
895                         qunlock(&locdnslck);
896                         return;
897                 }
898         if (n < nelem(locdns))
899                 if (locdns[n] == nil || ++n < nelem(locdns))
900                         locdns[n] = strdup(ipaddr); /* remember 1st few local ns */
901         qunlock(&locdnslck);
902
903         /* ns record for name server, make up an impossible name */
904         rp = rralloc(Tns);
905         snprint(buf, sizeof buf, "%s%d", localserverprefix, i);
906         nsdp = dnlookup(buf, class, 1);
907         rp->host = nsdp;
908         rp->owner = dp;                 /* e.g., local#dns#servers */
909         rp->local = 1;
910         rp->db = 1;
911 //      rp->ttl = 10*Min;               /* seems too short */
912         rp->ttl = (1UL<<31)-1;
913         rrattach(rp, Authoritative);    /* will not attach rrs in my area */
914
915         /* A or AAAA record */
916         if (parseip(ip, ipaddr) >= 0 && isv4(ip))
917                 rp = rralloc(Ta);
918         else
919                 rp = rralloc(Taaaa);
920         rp->ip = dnlookup(ipaddr, class, 1);
921         rp->owner = nsdp;
922         rp->local = 1;
923         rp->db = 1;
924 //      rp->ttl = 10*Min;               /* seems too short */
925         rp->ttl = (1UL<<31)-1;
926         rrattach(rp, Authoritative);    /* will not attach rrs in my area */
927
928         dnslog("added local dns server %s at %s", buf, ipaddr);
929 }
930
931 /*
932  *  return list of dns server addresses to use when
933  *  acting just as a resolver.
934  */
935 RR*
936 dnsservers(int class)
937 {
938         int i, n;
939         char *p;
940         char *args[5];
941         Ndbtuple *t, *nt;
942         RR *nsrp;
943         DN *dp;
944
945         dp = dnlookup(localservers, class, 1);
946         nsrp = rrlookup(dp, Tns, NOneg);
947         if(nsrp != nil)
948                 return nsrp;
949
950         p = getenv("DNSSERVER");                /* list of ip addresses */
951         if(p != nil){
952                 n = tokenize(p, args, nelem(args));
953                 for(i = 0; i < n; i++)
954                         addlocaldnsserver(dp, class, args[i], i);
955                 free(p);
956         } else {
957                 t = lookupinfo("@dns");         /* @dns=ip1 @dns=ip2 ... */
958                 if(t == nil)
959                         return nil;
960                 i = 0;
961                 for(nt = t; nt != nil; nt = nt->entry){
962                         addlocaldnsserver(dp, class, nt->val, i);
963                         i++;
964                 }
965                 ndbfree(t);
966         }
967
968         return rrlookup(dp, Tns, NOneg);
969 }
970
971 static void
972 addlocaldnsdomain(DN *dp, int class, char *domain)
973 {
974         RR *rp;
975
976         /* ptr record */
977         rp = rralloc(Tptr);
978         rp->ptr = dnlookup(domain, class, 1);
979         rp->owner = dp;
980         rp->db = 1;
981         rp->ttl = 10*Min;
982         rrattach(rp, Authoritative);
983 }
984
985 /*
986  *  return list of domains to use when resolving names without '.'s
987  */
988 RR*
989 domainlist(int class)
990 {
991         Ndbtuple *t, *nt;
992         RR *rp;
993         DN *dp;
994
995         dp = dnlookup("local#dns#domains", class, 1);
996         rp = rrlookup(dp, Tptr, NOneg);
997         if(rp != nil)
998                 return rp;
999
1000         t = lookupinfo("dnsdomain");
1001         if(t == nil)
1002                 return nil;
1003         for(nt = t; nt != nil; nt = nt->entry)
1004                 addlocaldnsdomain(dp, class, nt->val);
1005         ndbfree(t);
1006
1007         return rrlookup(dp, Tptr, NOneg);
1008 }
1009
1010 char *v4ptrdom = ".in-addr.arpa";
1011 char *v6ptrdom = ".ip6.arpa";           /* ip6.int deprecated, rfc 3152 */
1012
1013 char *attribs[] = {
1014         "ipmask",
1015         0
1016 };
1017
1018 /*
1019  *  create ptrs that are in our v4 areas
1020  */
1021 static void
1022 createv4ptrs(void)
1023 {
1024         int len, dlen, n;
1025         char *dom;
1026         char buf[Domlen+1], ipa[48];
1027         char *f[40];
1028         uchar net[IPaddrlen], mask[IPaddrlen];
1029         Area *s;
1030         Ndbtuple *t, *nt;
1031
1032         dlen = strlen(v4ptrdom);
1033         for(s = owned; s; s = s->next){
1034                 dom = s->soarr->owner->name;
1035                 len = strlen(dom);
1036                 if((len <= dlen || cistrcmp(dom+len-dlen, v4ptrdom) != 0) &&
1037                     cistrcmp(dom, v4ptrdom+1) != 0)
1038                         continue;
1039
1040                 /* get mask and net value */
1041                 strncpy(buf, dom, sizeof buf);
1042                 buf[sizeof buf-1] = 0;
1043                 /* buf contains something like 178.204.in-addr.arpa (n==4) */
1044                 n = getfields(buf, f, nelem(f), 0, ".");
1045                 memset(mask, 0xff, IPaddrlen);
1046                 ipmove(net, v4prefix);
1047                 switch(n){
1048                 case 3:                 /* /8 */
1049                         net[IPv4off] = atoi(f[0]);
1050                         mask[IPv4off+1] = 0;
1051                         mask[IPv4off+2] = 0;
1052                         mask[IPv4off+3] = 0;
1053                         break;
1054                 case 4:                 /* /16 */
1055                         net[IPv4off] = atoi(f[1]);
1056                         net[IPv4off+1] = atoi(f[0]);
1057                         mask[IPv4off+2] = 0;
1058                         mask[IPv4off+3] = 0;
1059                         break;
1060                 case 5:                 /* /24 */
1061                         net[IPv4off] = atoi(f[2]);
1062                         net[IPv4off+1] = atoi(f[1]);
1063                         net[IPv4off+2] = atoi(f[0]);
1064                         mask[IPv4off+3] = 0;
1065                         break;
1066                 case 6:         /* rfc2317: classless in-addr.arpa delegation */
1067                         net[IPv4off] = atoi(f[3]);
1068                         net[IPv4off+1] = atoi(f[2]);
1069                         net[IPv4off+2] = atoi(f[1]);
1070                         net[IPv4off+3] = atoi(f[0]);
1071                         sprint(ipa, "%I", net);
1072                         t = ndbipinfo(db, "ip", ipa, attribs, 1);
1073                         if(t == nil)    /* could be a reverse with no forward */
1074                                 continue;
1075                         nt = look(t, t, "ipmask");
1076                         if(nt == nil){          /* we're confused */
1077                                 ndbfree(t);
1078                                 continue;
1079                         }
1080                         parseipmask(mask, nt->val);
1081                         ndbfree(t);
1082                         n = 5;
1083                         break;
1084                 default:
1085                         continue;
1086                 }
1087
1088                 /*
1089                  * go through all domain entries looking for RR's
1090                  * in this network and create ptrs.
1091                  * +2 for ".in-addr.arpa".
1092                  */
1093                 dnptr(net, mask, dom, Ta, 4+2-n, Ptrttl);
1094         }
1095 }
1096
1097 /* convert bytes to nibbles, big-endian */
1098 void
1099 bytes2nibbles(uchar *nibbles, uchar *bytes, int nbytes)
1100 {
1101         while (nbytes-- > 0) {
1102                 *nibbles++ = *bytes >> Nibwidth;
1103                 *nibbles++ = *bytes++ & Nibmask;
1104         }
1105 }
1106
1107 void
1108 nibbles2bytes(uchar *bytes, uchar *nibbles, int nnibs)
1109 {
1110         for (; nnibs >= 2; nnibs -= 2) {
1111                 *bytes++ = nibbles[0] << Nibwidth | (nibbles[1]&Nibmask);
1112                 nibbles += 2;
1113         }
1114         if (nnibs > 0)
1115                 *bytes = nibbles[0] << Nibwidth;
1116 }
1117
1118 /*
1119  *  create ptrs that are in our v6 areas.  see rfc3596
1120  */
1121 static void
1122 createv6ptrs(void)
1123 {
1124         int len, dlen, i, n, pfxnibs;
1125         char *dom;
1126         char buf[Domlen+1];
1127         char *f[40];
1128         uchar net[IPaddrlen], mask[IPaddrlen];
1129         uchar nibnet[IPaddrlen*2], nibmask[IPaddrlen*2];
1130         Area *s;
1131
1132         dlen = strlen(v6ptrdom);
1133         for(s = owned; s; s = s->next){
1134                 dom = s->soarr->owner->name;
1135                 len = strlen(dom);
1136                 if((len <= dlen || cistrcmp(dom+len-dlen, v6ptrdom) != 0) &&
1137                     cistrcmp(dom, v6ptrdom+1) != 0)
1138                         continue;
1139
1140                 /* get mask and net value */
1141                 strncpy(buf, dom, sizeof buf);
1142                 buf[sizeof buf-1] = 0;
1143                 /* buf contains something like 2.0.0.2.ip6.arpa (n==6) */
1144                 n = getfields(buf, f, nelem(f), 0, ".");
1145                 pfxnibs = n - 2;                /* 2 for .ip6.arpa */
1146                 if (pfxnibs < 0 || pfxnibs > V6maxrevdomdepth)
1147                         continue;
1148
1149                 memset(net, 0, IPaddrlen);
1150                 memset(mask, 0xff, IPaddrlen);
1151                 bytes2nibbles(nibnet, net, IPaddrlen);
1152                 bytes2nibbles(nibmask, mask, IPaddrlen);
1153
1154                 /* copy prefix of f, in reverse order, to start of net. */
1155                 for (i = 0; i < pfxnibs; i++)
1156                         nibnet[i] = strtol(f[pfxnibs - 1 - i], nil, 16);
1157                 /* zero nibbles of mask after prefix in net */
1158                 memset(nibmask + pfxnibs, 0, V6maxrevdomdepth - pfxnibs);
1159
1160                 nibbles2bytes(net, nibnet, 2*IPaddrlen);
1161                 nibbles2bytes(mask, nibmask, 2*IPaddrlen);
1162
1163                 /*
1164                  * go through all domain entries looking for RR's
1165                  * in this network and create ptrs.
1166                  */
1167                 dnptr(net, mask, dom, Taaaa, V6maxrevdomdepth - pfxnibs, Ptrttl);
1168         }
1169 }
1170
1171 /*
1172  *  create ptrs that are in our areas
1173  */
1174 static void
1175 createptrs(void)
1176 {
1177         createv4ptrs();
1178         createv6ptrs();
1179 }
1180
1181 /*
1182  * is this domain (or DOMAIN or Domain or dOMAIN)
1183  * internal to our organisation (behind our firewall)?
1184  * only inside straddling servers care, everybody else gets told `yes',
1185  * so they'll use mntpt for their queries.
1186  */
1187 int
1188 insideaddr(char *dom)
1189 {
1190         int domlen, vallen, rv;
1191         Ndbtuple *t;
1192
1193         if (!cfg.inside || !cfg.straddle || !cfg.serve)
1194                 return 1;
1195         if (dom[0] == '\0' || strcmp(dom, ".") == 0)    /* dns root? */
1196                 return 1;                       /* hack for initialisation */
1197
1198         lock(&dblock);
1199         if (indoms == nil)
1200                 loaddomsrvs();
1201         if (indoms == nil) {
1202                 unlock(&dblock);
1203                 return 1;  /* no "inside-dom" sys, try inside nameservers */
1204         }
1205
1206         rv = 0;
1207         domlen = strlen(dom);
1208         for (t = indoms; t != nil; t = t->entry) {
1209                 if (strcmp(t->attr, "dom") != 0)
1210                         continue;
1211                 vallen = strlen(t->val);
1212                 if (cistrcmp(dom, t->val) == 0 ||
1213                     domlen > vallen &&
1214                      cistrcmp(dom + domlen - vallen, t->val) == 0 &&
1215                      dom[domlen - vallen - 1] == '.') {
1216                         rv = 1;
1217                         break;
1218                 }
1219         }
1220         unlock(&dblock);
1221         return rv;
1222 }
1223
1224 int
1225 insidens(uchar *ip)
1226 {
1227         uchar ipa[IPaddrlen];
1228         Ndbtuple *t;
1229
1230         for (t = innmsrvs; t != nil; t = t->entry)
1231                 if (strcmp(t->attr, "ip") == 0) {
1232                         parseip(ipa, t->val);
1233                         if (memcmp(ipa, ip, sizeof ipa) == 0)
1234                                 return 1;
1235                 }
1236         return 0;
1237 }
1238
1239 int
1240 outsidensip(int n, uchar *ip)
1241 {
1242         int i;
1243         Ndbtuple *t;
1244
1245         i = 0;
1246         for (t = outnmsrvs; t != nil; t = t->entry)
1247                 if (strcmp(t->attr, "ip") == 0 && i++ == n) {
1248                         parseip(ip, t->val);
1249                         return 0;
1250                 }
1251         return -1;
1252 }