plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

dblookup.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 }