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