xref: /plan9-contrib/sys/src/cmd/ndb/dn.c (revision ed2a258a218962e0b4e0f5cbbab48c6ce1bcbf02)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <pool.h>
5 #include <ctype.h>
6 #include "dns.h"
7 
8 /*
9  *  this comment used to say `our target is 4000 names cached, this should
10  *  be larger on large servers'.  dns at Bell Labs starts off with
11  *  about 1780 names.
12  *
13  * aging seems to corrupt the cache, so raise the trigger from 4000 until we
14  * figure it out.
15  */
16 enum {
17 	Deftarget = 100000,
18 };
19 enum {
20 	Minage		= 10*60,
21 	Defagefreq	= 30*60,	/* age names this often (seconds) */
22 };
23 
24 /*
25  *  Hash table for domain names.  The hash is based only on the
26  *  first element of the domain name.
27  */
28 DN *ht[HTLEN];
29 
30 static struct {
31 	Lock;
32 	ulong	names;		/* names allocated */
33 	ulong	oldest;		/* longest we'll leave a name around */
34 	int	active;
35 	int	mutex;
36 	ushort	id;		/* same size as in packet */
37 } dnvars;
38 
39 /* names of RR types */
40 char *rrtname[] =
41 {
42 [Ta]		"ip",
43 [Tns]		"ns",
44 [Tmd]		"md",
45 [Tmf]		"mf",
46 [Tcname]	"cname",
47 [Tsoa]		"soa",
48 [Tmb]		"mb",
49 [Tmg]		"mg",
50 [Tmr]		"mr",
51 [Tnull]		"null",
52 [Twks]		"wks",
53 [Tptr]		"ptr",
54 [Thinfo]	"hinfo",
55 [Tminfo]	"minfo",
56 [Tmx]		"mx",
57 [Ttxt]		"txt",
58 [Trp]		"rp",
59 [Tafsdb]	"afsdb",
60 [Tx25]		"x.25",
61 [Tisdn]		"isdn",
62 [Trt]		"rt",
63 [Tnsap]		"nsap",
64 [Tnsapptr]	"nsap-ptr",
65 [Tsig]		"sig",
66 [Tkey]		"key",
67 [Tpx]		"px",
68 [Tgpos]		"gpos",
69 [Taaaa]		"ipv6",
70 [Tloc]		"loc",
71 [Tnxt]		"nxt",
72 [Teid]		"eid",
73 [Tnimloc]	"nimrod",
74 [Tsrv]		"srv",
75 [Tatma]		"atma",
76 [Tnaptr]	"naptr",
77 [Tkx]		"kx",
78 [Tcert]		"cert",
79 [Ta6]		"a6",
80 [Tdname]	"dname",
81 [Tsink]		"sink",
82 [Topt]		"opt",
83 [Tapl]		"apl",
84 [Tds]		"ds",
85 [Tsshfp]	"sshfp",
86 [Tipseckey]	"ipseckey",
87 [Trrsig]	"rrsig",
88 [Tnsec]		"nsec",
89 [Tdnskey]	"dnskey",
90 [Tspf]		"spf",
91 [Tuinfo]	"uinfo",
92 [Tuid]		"uid",
93 [Tgid]		"gid",
94 [Tunspec]	"unspec",
95 [Ttkey]		"tkey",
96 [Ttsig]		"tsig",
97 [Tixfr]		"ixfr",
98 [Taxfr]		"axfr",
99 [Tmailb]	"mailb",
100 [Tmaila]	"maila",
101 [Tall]		"all",
102 		0,
103 };
104 
105 /* names of response codes */
106 char *rname[Rmask+1] =
107 {
108 [Rok]			"ok",
109 [Rformat]		"format error",
110 [Rserver]		"server failure",
111 [Rname]			"bad name",
112 [Runimplimented]	"unimplemented",
113 [Rrefused]		"we don't like you",
114 [Ryxdomain]		"name should not exist",
115 [Ryxrrset]		"rr set should not exist",
116 [Rnxrrset]		"rr set should exist",
117 [Rnotauth]		"not authorative",
118 [Rnotzone]		"not in zone",
119 [Rbadvers]		"bad opt version",
120 /* [Rbadsig]		"bad signature", */
121 [Rbadkey]		"bad key",
122 [Rbadtime]		"bad signature time",
123 [Rbadmode]		"bad mode",
124 [Rbadname]		"duplicate key name",
125 [Rbadalg]		"bad algorithm",
126 };
127 unsigned nrname = nelem(rname);
128 
129 /* names of op codes */
130 char *opname[] =
131 {
132 [Oquery]	"query",
133 [Oinverse]	"inverse query (retired)",
134 [Ostatus]	"status",
135 [Oupdate]	"update",
136 };
137 
138 ulong target = Deftarget;
139 Lock	dnlock;
140 
141 static ulong agefreq = Defagefreq;
142 
143 static int sencodefmt(Fmt*);
144 
145 void
146 dninit(void)
147 {
148 	fmtinstall('E', eipfmt);
149 	fmtinstall('I', eipfmt);
150 	fmtinstall('V', eipfmt);
151 	fmtinstall('R', rrfmt);
152 	fmtinstall('Q', rravfmt);
153 	fmtinstall('H', sencodefmt);
154 
155 	dnvars.oldest = maxage;
156 	dnvars.names = 0;
157 	dnvars.id = truerand();	/* don't start with same id every time */
158 }
159 
160 /*
161  *  hash for a domain name
162  */
163 static ulong
164 dnhash(char *name)
165 {
166 	ulong hash;
167 	uchar *val = (uchar*)name;
168 
169 	for(hash = 0; *val; val++)
170 		hash = hash*13 + tolower(*val)-'a';
171 	return hash % HTLEN;
172 }
173 
174 /*
175  *  lookup a symbol.  if enter is not zero and the name is
176  *  not found, create it.
177  */
178 DN*
179 dnlookup(char *name, int class, int enter)
180 {
181 	DN **l;
182 	DN *dp;
183 
184 	l = &ht[dnhash(name)];
185 	lock(&dnlock);
186 	for(dp = *l; dp; dp = dp->next) {
187 		assert(dp->magic == DNmagic);
188 		if(dp->class == class && cistrcmp(dp->name, name) == 0){
189 			dp->referenced = now;
190 			unlock(&dnlock);
191 			return dp;
192 		}
193 		l = &dp->next;
194 	}
195 
196 	if(!enter){
197 		unlock(&dnlock);
198 		return 0;
199 	}
200 	dnvars.names++;
201 	dp = emalloc(sizeof(*dp));
202 	dp->magic = DNmagic;
203 	dp->name = estrdup(name);
204 	assert(dp->name != nil);
205 	dp->class = class;
206 	dp->rr = 0;
207 	dp->next = 0;
208 	dp->referenced = now;
209 	*l = dp;
210 	unlock(&dnlock);
211 
212 	return dp;
213 }
214 
215 /*
216  *  dump the cache
217  */
218 void
219 dndump(char *file)
220 {
221 	DN *dp;
222 	int i, fd;
223 	RR *rp;
224 
225 	fd = create(file, OWRITE, 0666);
226 	if(fd < 0)
227 		return;
228 
229 	qlock(&stats);
230 	fprint(fd, "# slave procs high-water mark\t%lud\n", stats.slavehiwat);
231 	fprint(fd, "# queries received by 9p\t%lud\n", stats.qrecvd9p);
232 	fprint(fd, "# queries received by udp\t%lud\n", stats.qrecvdudp);
233 	fprint(fd, "# queries answered from memory\t%lud\n", stats.answinmem);
234 	fprint(fd, "# queries sent by udp\t%lud\n", stats.qsent);
235 	for (i = 0; i < nelem(stats.under10ths); i++)
236 		if (stats.under10ths[i] || i == nelem(stats.under10ths) - 1)
237 			fprint(fd, "# responses arriving within %.1f s.\t%lud\n",
238 				(double)(i+1)/10, stats.under10ths[i]);
239 	fprint(fd, "\n# queries sent & timed-out\t%lud\n", stats.tmout);
240 	fprint(fd, "# cname queries timed-out\t%lud\n", stats.tmoutcname);
241 	fprint(fd, "# ipv6  queries timed-out\t%lud\n", stats.tmoutv6);
242 	fprint(fd, "\n# negative answers received\t%lud\n", stats.negans);
243 	fprint(fd, "# negative answers w Rserver set\t%lud\n", stats.negserver);
244 	fprint(fd, "# negative answers w bad delegation\t%lud\n",
245 		stats.negbaddeleg);
246 	fprint(fd, "# negative answers w bad delegation & no answers\t%lud\n",
247 		stats.negbdnoans);
248 	fprint(fd, "# negative answers w no Rname set\t%lud\n", stats.negnorname);
249 	fprint(fd, "# negative answers cached\t%lud\n", stats.negcached);
250 	qunlock(&stats);
251 
252 	lock(&dnlock);
253 	fprint(fd, "\n# domain names %lud target %lud\n", dnvars.names, target);
254 	for(i = 0; i < HTLEN; i++)
255 		for(dp = ht[i]; dp; dp = dp->next){
256 			fprint(fd, "%s\n", dp->name);
257 			for(rp = dp->rr; rp; rp = rp->next)
258 				fprint(fd, "\t%R %c%c %lud/%lud\n",
259 					rp, rp->auth? 'A': 'U',
260 					rp->db? 'D': 'N', rp->expire, rp->ttl);
261 		}
262 	unlock(&dnlock);
263 	close(fd);
264 }
265 
266 /*
267  *  purge all records
268  */
269 void
270 dnpurge(void)
271 {
272 	DN *dp;
273 	RR *rp, *srp;
274 	int i;
275 
276 	lock(&dnlock);
277 
278 	for(i = 0; i < HTLEN; i++)
279 		for(dp = ht[i]; dp; dp = dp->next){
280 			srp = rp = dp->rr;
281 			dp->rr = nil;
282 			for(; rp != nil; rp = rp->next)
283 				rp->cached = 0;
284 			rrfreelist(srp);
285 		}
286 
287 	unlock(&dnlock);
288 }
289 
290 /*
291  *  check the age of resource records, free any that have timed out
292  */
293 void
294 dnage(DN *dp)
295 {
296 	RR **l;
297 	RR *rp, *next;
298 	ulong diff;
299 
300 	diff = now - dp->referenced;
301 	if(diff < Reserved || dp->keep)
302 		return;
303 
304 	l = &dp->rr;
305 	for(rp = dp->rr; rp; rp = next){
306 		assert(rp->magic == RRmagic && rp->cached);
307 		next = rp->next;
308 		if(!rp->db)
309 		if(rp->expire < now || diff > dnvars.oldest){
310 			*l = next;
311 			rp->cached = 0;
312 			rrfree(rp);
313 			continue;
314 		}
315 		l = &rp->next;
316 	}
317 }
318 
319 #define MARK(dp)	{ if (dp) (dp)->keep = 1; }
320 
321 /* mark all current domain names as never to be aged */
322 void
323 dnagenever(void)
324 {
325 	int i;
326 	DN *dp;
327 	RR *rp;
328 
329 	lock(&dnlock);
330 
331 	/* mark all referenced domain names */
332 	for(i = 0; i < HTLEN; i++)
333 		for(dp = ht[i]; dp; dp = dp->next) {
334 			MARK(dp);
335 			for(rp = dp->rr; rp; rp = rp->next){
336 				MARK(rp->owner);
337 				if(rp->negative){
338 					MARK(rp->negsoaowner);
339 					continue;
340 				}
341 				switch(rp->type){
342 				case Thinfo:
343 					MARK(rp->cpu);
344 					MARK(rp->os);
345 					break;
346 				case Ttxt:
347 					break;
348 				case Tcname:
349 				case Tmb:
350 				case Tmd:
351 				case Tmf:
352 				case Tns:
353 				case Tmx:
354 					MARK(rp->host);
355 					break;
356 				case Tmg:
357 				case Tmr:
358 					MARK(rp->mb);
359 					break;
360 				case Tminfo:
361 					MARK(rp->rmb);
362 					MARK(rp->mb);
363 					break;
364 				case Trp:
365 					MARK(rp->rmb);
366 					MARK(rp->rp);
367 					break;
368 				case Ta:
369 				case Taaaa:
370 					MARK(rp->ip);
371 					break;
372 				case Tptr:
373 					MARK(rp->ptr);
374 					break;
375 				case Tsoa:
376 					MARK(rp->host);
377 					MARK(rp->rmb);
378 					break;
379 				case Tsrv:
380 					MARK(rp->srv->target);
381 					break;
382 				}
383 			}
384 		}
385 
386 	unlock(&dnlock);
387 
388 	dnslog("%ld initial domain names; target is %ld", dnvars.names, target);
389 	if(dnvars.names >= target)
390 		dnslog("more initial domain names (%ld) than target (%ld)",
391 			dnvars.names, target);
392 }
393 
394 #define REF(dp)	{ if (dp) (dp)->refs++; }
395 
396 /*
397  *  periodicly sweep for old records and remove unreferenced domain names
398  *
399  *  only called when all other threads are locked out
400  */
401 void
402 dnageall(int doit)
403 {
404 	DN *dp, **l;
405 	int i, n;
406 	RR *rp;
407 	static ulong nextage;
408 
409 	if(dnvars.names < target || (now < nextage && !doit)){
410 		dnvars.oldest = maxage;
411 		return;
412 	}
413 
414 	if(dnvars.names >= target) {
415 		dnslog("more names (%lud) than target (%lud)", dnvars.names,
416 			target);
417 		dnvars.oldest /= 2;
418 		if (dnvars.oldest < Minage)
419 			dnvars.oldest = Minage;		/* don't be silly */
420 	}
421 	if (agefreq > dnvars.oldest / 2)
422 		nextage = now + dnvars.oldest / 2;
423 	else
424 		nextage = now + agefreq;
425 
426 	lock(&dnlock);
427 
428 	/* time out all old entries (and set refs to 0) */
429 	for(i = 0; i < HTLEN; i++)
430 		for(dp = ht[i]; dp; dp = dp->next){
431 			dp->refs = 0;
432 			dnage(dp);
433 		}
434 
435 	/* mark all referenced domain names */
436 	for(i = 0; i < HTLEN; i++)
437 		for(dp = ht[i]; dp; dp = dp->next)
438 			for(rp = dp->rr; rp; rp = rp->next){
439 				REF(rp->owner);
440 				if(rp->negative){
441 					REF(rp->negsoaowner);
442 					continue;
443 				}
444 				switch(rp->type){
445 				case Thinfo:
446 					REF(rp->cpu);
447 					REF(rp->os);
448 					break;
449 				case Ttxt:
450 					break;
451 				case Tcname:
452 				case Tmb:
453 				case Tmd:
454 				case Tmf:
455 				case Tns:
456 				case Tmx:
457 					REF(rp->host);
458 					break;
459 				case Tmg:
460 				case Tmr:
461 					REF(rp->mb);
462 					break;
463 				case Tminfo:
464 					REF(rp->rmb);
465 					REF(rp->mb);
466 					break;
467 				case Trp:
468 					REF(rp->rmb);
469 					REF(rp->rp);
470 					break;
471 				case Ta:
472 				case Taaaa:
473 					REF(rp->ip);
474 					break;
475 				case Tptr:
476 					REF(rp->ptr);
477 					break;
478 				case Tsoa:
479 					REF(rp->host);
480 					REF(rp->rmb);
481 					break;
482 				case Tsrv:
483 					REF(rp->srv->target);
484 					break;
485 				}
486 			}
487 
488 	/* sweep and remove unreferenced domain names */
489 	for(i = 0; i < HTLEN; i++){
490 		l = &ht[i];
491 		for(dp = *l; dp; dp = *l){
492 			if(dp->rr == 0 && dp->refs == 0 && !dp->keep){
493 				assert(dp->magic == DNmagic);
494 				*l = dp->next;
495 
496 				for (n = 0; n < Maxlcks; n++)
497 					if (canqlock(&dp->querylck[n]))
498 						qunlock(&dp->querylck[n]);
499 					else
500 						dnslog("dnageall: %s querylck[%d] held when freeing",
501 							dp->name, n);
502 				if(dp->name)
503 					free(dp->name);
504 				dp->magic = ~dp->magic;
505 				dnvars.names--;
506 				memset(dp, 0, sizeof *dp); /* cause trouble */
507 				free(dp);
508 
509 				continue;
510 			}
511 			l = &dp->next;
512 		}
513 	}
514 
515 	unlock(&dnlock);
516 }
517 
518 /*
519  *  timeout all database records (used when rereading db)
520  */
521 void
522 dnagedb(void)
523 {
524 	DN *dp;
525 	int i;
526 	RR *rp;
527 	static ulong nextage;
528 
529 	lock(&dnlock);
530 
531 	/* time out all database entries */
532 	for(i = 0; i < HTLEN; i++)
533 		for(dp = ht[i]; dp; dp = dp->next)
534 			for(rp = dp->rr; rp; rp = rp->next)
535 				if(rp->db)
536 					rp->expire = 0;
537 
538 	unlock(&dnlock);
539 }
540 
541 /*
542  *  mark all local db records about my area as authoritative,
543  *  time out any others
544  */
545 void
546 dnauthdb(void)
547 {
548 	int i;
549 	ulong minttl;
550 	Area *area;
551 	DN *dp;
552 	RR *rp;
553 	static ulong nextage;
554 
555 	lock(&dnlock);
556 
557 	/* time out all database entries */
558 	for(i = 0; i < HTLEN; i++)
559 		for(dp = ht[i]; dp; dp = dp->next){
560 			area = inmyarea(dp->name);
561 			for(rp = dp->rr; rp; rp = rp->next)
562 				if(rp->db){
563 					if(area){
564 						minttl = area->soarr->soa->minttl;
565 						if(rp->ttl < minttl)
566 							rp->ttl = minttl;
567 						rp->auth = 1;
568 					}
569 					if(rp->expire == 0){
570 						rp->db = 0;
571 						dp->referenced = now-Reserved-1;
572 					}
573 				}
574 		}
575 
576 	unlock(&dnlock);
577 }
578 
579 /*
580  *  keep track of other processes to know if we can
581  *  garbage collect.  block while garbage collecting.
582  */
583 int
584 getactivity(Request *req, int recursive)
585 {
586 	int rv;
587 
588 	if(traceactivity)
589 		dnslog("get: %d active by pid %d from %p",
590 			dnvars.active, getpid(), getcallerpc(&req));
591 	lock(&dnvars);
592 	/*
593 	 * can't block here if we're already holding one
594 	 * of the dnvars.active (recursive).  will deadlock.
595 	 */
596 	while(!recursive && dnvars.mutex){
597 		unlock(&dnvars);
598 		sleep(100);			/* tune; was 200 */
599 		lock(&dnvars);
600 	}
601 	rv = ++dnvars.active;
602 	now = time(nil);
603 	nowns = nsec();
604 	req->id = ++dnvars.id;
605 	unlock(&dnvars);
606 
607 	return rv;
608 }
609 void
610 putactivity(int recursive)
611 {
612 	static ulong lastclean;
613 
614 	if(traceactivity)
615 		dnslog("put: %d active by pid %d",
616 			dnvars.active, getpid());
617 	lock(&dnvars);
618 	dnvars.active--;
619 	assert(dnvars.active >= 0); /* "dnvars.active %d", dnvars.active */
620 
621 	/*
622 	 *  clean out old entries and check for new db periodicly
623 	 *  can't block here if being called to let go a "recursive" lock
624 	 *  or we'll deadlock waiting for ourselves to give up the dnvars.active.
625 	 */
626 	if (recursive || dnvars.mutex ||
627 	    (needrefresh == 0 && dnvars.active > 0)){
628 		unlock(&dnvars);
629 		return;
630 	}
631 
632 	/* wait till we're alone */
633 	dnvars.mutex = 1;
634 	while(dnvars.active > 0){
635 		unlock(&dnvars);
636 		sleep(100);		/* tune; was 100 */
637 		lock(&dnvars);
638 	}
639 	unlock(&dnvars);
640 
641 	db2cache(needrefresh);
642 	dnageall(0);
643 
644 	/* let others back in */
645 	lastclean = now;
646 	needrefresh = 0;
647 	dnvars.mutex = 0;
648 }
649 
650 /*
651  *  Attach a single resource record to a domain name (new->owner).
652  *	- Avoid duplicates with already present RR's
653  *	- Chain all RR's of the same type adjacent to one another
654  *	- chain authoritative RR's ahead of non-authoritative ones
655  *	- remove any expired RR's
656  *  Must be called with dnlock held.
657  */
658 static void
659 rrattach1(RR *new, int auth)
660 {
661 	RR **l;
662 	RR *rp;
663 	DN *dp;
664 
665 	assert(new->magic == RRmagic && !new->cached);
666 
667 //	dnslog("rrattach1: %s", new->owner->name);
668 	if(!new->db)
669 		new->expire = new->ttl;
670 	else
671 		new->expire = now + Year;
672 	dp = new->owner;
673 	assert(dp->magic == DNmagic);
674 	new->auth |= auth;
675 	new->next = 0;
676 
677 	/*
678 	 *  find first rr of the right type
679 	 */
680 	l = &dp->rr;
681 	for(rp = *l; rp; rp = *l){
682 		assert(rp->magic == RRmagic && rp->cached);
683 		if(rp->type == new->type)
684 			break;
685 		l = &rp->next;
686 	}
687 
688 	/*
689 	 *  negative entries replace positive entries
690 	 *  positive entries replace negative entries
691 	 *  newer entries replace older entries with the same fields
692 	 */
693 	for(rp = *l; rp; rp = *l){
694 		assert(rp->magic == RRmagic && rp->cached);
695 		if(rp->type != new->type)
696 			break;
697 
698 		if(rp->db == new->db && rp->auth == new->auth){
699 			/* negative drives out positive and vice versa */
700 			if(rp->negative != new->negative){
701 				*l = rp->next;
702 				rp->cached = 0;
703 				rrfree(rp);
704 				continue;
705 			}
706 
707 			/* all things equal, pick the newer one */
708 			if(rp->arg0 == new->arg0 && rp->arg1 == new->arg1 &&
709 			    (rp->type != Tsrv || rp->srv == new->srv)){
710 				/* new drives out old */
711 				if (new->ttl > rp->ttl ||
712 				    new->expire > rp->expire){
713 					*l = rp->next;
714 					rp->cached = 0;
715 					rrfree(rp);
716 					continue;
717 				} else {
718 					rrfree(new);
719 					return;
720 				}
721 			}
722 
723 			/*  Hack for pointer records.  This makes sure
724 			 *  the ordering in the list reflects the ordering
725 			 *  received or read from the database
726 			 */
727 			if(rp->type == Tptr)
728 				if(!rp->negative && !new->negative
729 				&& rp->ptr->ordinal > new->ptr->ordinal)
730 					break;
731 		}
732 		l = &rp->next;
733 	}
734 
735 	/*
736 	 *  add to chain
737 	 */
738 	new->cached = 1;
739 	new->next = *l;
740 	*l = new;
741 }
742 
743 /*
744  *  Attach a list of resource records to a domain name.
745  *  See rrattach1 for properties preserved.
746  */
747 void
748 rrattach(RR *rp, int auth)
749 {
750 	RR *next;
751 
752 	lock(&dnlock);
753 	for(; rp; rp = next){
754 		next = rp->next;
755 		rp->next = nil;
756 
757 		/* avoid any outside spoofing */
758 //		dnslog("rrattach: %s", rp->owner->name);
759 		if(cfg.cachedb && !rp->db && inmyarea(rp->owner->name))
760 			rrfree(rp);
761 		else
762 			rrattach1(rp, auth);
763 	}
764 	unlock(&dnlock);
765 }
766 
767 RR**
768 rrcopy(RR *rp, RR **last)
769 {
770 	Cert *cert;
771 	Key *key;
772 	Null *null;
773 	RR *nrp;
774 	SOA *soa;
775 	Sig *sig;
776 	Srv *srv;
777 	Txt *t, *nt, **l;
778 
779 	nrp = rralloc(rp->type);
780 	setmalloctag(nrp, getcallerpc(&rp));
781 	switch(rp->type){
782 	case Ttxt:
783 		*nrp = *rp;
784 		l = &nrp->txt;
785 		*l = nil;
786 		for(t = rp->txt; t != nil; t = t->next){
787 			nt = emalloc(sizeof(*nt));
788 			nt->p = estrdup(t->p);
789 			nt->next = nil;
790 			*l = nt;
791 			l = &nt->next;
792 		}
793 		break;
794 	case Tsoa:
795 		soa = nrp->soa;
796 		*nrp = *rp;
797 		nrp->soa = soa;
798 		*nrp->soa = *rp->soa;
799 		nrp->soa->slaves = copyserverlist(rp->soa->slaves);
800 		break;
801 	case Tsrv:
802 		srv = nrp->srv;
803 		*nrp = *rp;
804 		nrp->srv = srv;
805 		*nrp->srv = *rp->srv;
806 		break;
807 	case Tkey:
808 		key = nrp->key;
809 		*nrp = *rp;
810 		nrp->key = key;
811 		*key = *rp->key;
812 		key->data = emalloc(key->dlen);
813 		memmove(key->data, rp->key->data, rp->key->dlen);
814 		break;
815 	case Tsig:
816 		sig = nrp->sig;
817 		*nrp = *rp;
818 		nrp->sig = sig;
819 		*sig = *rp->sig;
820 		sig->data = emalloc(sig->dlen);
821 		memmove(sig->data, rp->sig->data, rp->sig->dlen);
822 		break;
823 	case Tcert:
824 		cert = nrp->cert;
825 		*nrp = *rp;
826 		nrp->cert = cert;
827 		*cert = *rp->cert;
828 		cert->data = emalloc(cert->dlen);
829 		memmove(cert->data, rp->cert->data, rp->cert->dlen);
830 		break;
831 	case Tnull:
832 		null = nrp->null;
833 		*nrp = *rp;
834 		nrp->null = null;
835 		*null = *rp->null;
836 		null->data = emalloc(null->dlen);
837 		memmove(null->data, rp->null->data, rp->null->dlen);
838 		break;
839 	default:
840 		*nrp = *rp;
841 		break;
842 	}
843 	nrp->cached = 0;
844 	nrp->next = 0;
845 	*last = nrp;
846 	return &nrp->next;
847 }
848 
849 /*
850  *  lookup a resource record of a particular type and
851  *  class attached to a domain name.  Return copies.
852  *
853  *  Priority ordering is:
854  *	db authoritative
855  *	not timed out network authoritative
856  *	not timed out network unauthoritative
857  *	unauthoritative db
858  *
859  *  if flag NOneg is set, don't return negative cached entries.
860  *  return nothing instead.
861  */
862 RR*
863 rrlookup(DN *dp, int type, int flag)
864 {
865 	RR *rp, *first, **last;
866 
867 	assert(dp->magic == DNmagic);
868 
869 	first = 0;
870 	last = &first;
871 	lock(&dnlock);
872 
873 	/* try for an authoritative db entry */
874 	for(rp = dp->rr; rp; rp = rp->next){
875 		assert(rp->magic == RRmagic && rp->cached);
876 		if(rp->db)
877 		if(rp->auth)
878 		if(tsame(type, rp->type)) {
879 			last = rrcopy(rp, last);
880 			// setmalloctag(*last, getcallerpc(&dp));
881 		}
882 	}
883 	if(first)
884 		goto out;
885 
886 	/* try for a living authoritative network entry */
887 	for(rp = dp->rr; rp; rp = rp->next){
888 		if(!rp->db)
889 		if(rp->auth)
890 		if(rp->ttl + 60 > now)
891 		if(tsame(type, rp->type)){
892 			if(flag == NOneg && rp->negative)
893 				goto out;
894 			last = rrcopy(rp, last);
895 		}
896 	}
897 	if(first)
898 		goto out;
899 
900 	/* try for a living unauthoritative network entry */
901 	for(rp = dp->rr; rp; rp = rp->next){
902 		if(!rp->db)
903 		if(rp->ttl + 60 > now)
904 		if(tsame(type, rp->type)){
905 			if(flag == NOneg && rp->negative)
906 				goto out;
907 			last = rrcopy(rp, last);
908 		}
909 	}
910 	if(first)
911 		goto out;
912 
913 	/* try for an unauthoritative db entry */
914 	for(rp = dp->rr; rp; rp = rp->next){
915 		if(rp->db)
916 		if(tsame(type, rp->type))
917 			last = rrcopy(rp, last);
918 	}
919 	if(first)
920 		goto out;
921 
922 	/* otherwise, settle for anything we got (except for negative caches) */
923 	for(rp = dp->rr; rp; rp = rp->next)
924 		if(tsame(type, rp->type)){
925 			if(rp->negative)
926 				goto out;
927 			last = rrcopy(rp, last);
928 		}
929 
930 out:
931 	unlock(&dnlock);
932 	unique(first);
933 //	dnslog("rrlookup(%s) -> %#p\t# in-core only", dp->name, first);
934 //	if (first)
935 //		setmalloctag(first, getcallerpc(&dp));
936 	return first;
937 }
938 
939 /*
940  *  convert an ascii RR type name to its integer representation
941  */
942 int
943 rrtype(char *atype)
944 {
945 	int i;
946 
947 	for(i = 0; i <= Tall; i++)
948 		if(rrtname[i] && strcmp(rrtname[i], atype) == 0)
949 			return i;
950 
951 	/* make any a synonym for all */
952 	if(strcmp(atype, "any") == 0)
953 		return Tall;
954 	return atoi(atype);
955 }
956 
957 /*
958  *  return 0 if not a supported rr type
959  */
960 int
961 rrsupported(int type)
962 {
963 	if(type < 0 || type >Tall)
964 		return 0;
965 	return rrtname[type] != nil;
966 }
967 
968 /*
969  *  compare 2 types
970  */
971 int
972 tsame(int t1, int t2)
973 {
974 	return t1 == t2 || t1 == Tall;
975 }
976 
977 /*
978  *  Add resource records to a list, duplicate them if they are cached
979  *  RR's since these are shared.
980  */
981 RR*
982 rrcat(RR **start, RR *rp)
983 {
984 	RR **last;
985 
986 	last = start;
987 	while(*last != nil)
988 		last = &(*last)->next;
989 
990 	*last = rp;
991 	return *start;
992 }
993 
994 /*
995  *  remove negative cache rr's from an rr list
996  */
997 RR*
998 rrremneg(RR **l)
999 {
1000 	RR **nl, *rp;
1001 	RR *first;
1002 
1003 	first = nil;
1004 	nl = &first;
1005 	while(*l != nil){
1006 		rp = *l;
1007 		if(rp->negative){
1008 			*l = rp->next;
1009 			*nl = rp;
1010 			nl = &rp->next;
1011 			*nl = nil;
1012 		} else
1013 			l = &rp->next;
1014 	}
1015 
1016 	return first;
1017 }
1018 
1019 /*
1020  *  remove rr's of a particular type from an rr list
1021  */
1022 RR*
1023 rrremtype(RR **l, int type)
1024 {
1025 	RR *first, *rp;
1026 	RR **nl;
1027 
1028 	first = nil;
1029 	nl = &first;
1030 	while(*l != nil){
1031 		rp = *l;
1032 		if(rp->type == type){
1033 			*l = rp->next;
1034 			*nl = rp;
1035 			nl = &rp->next;
1036 			*nl = nil;
1037 		} else
1038 			l = &(*l)->next;
1039 	}
1040 
1041 	return first;
1042 }
1043 
1044 static char *
1045 dnname(DN *dn)
1046 {
1047 	return dn? dn->name: "<null>";
1048 }
1049 
1050 /*
1051  *  print conversion for rr records
1052  */
1053 int
1054 rrfmt(Fmt *f)
1055 {
1056 	int rv;
1057 	char *strp;
1058 	char buf[Domlen];
1059 	Fmt fstr;
1060 	RR *rp;
1061 	Server *s;
1062 	SOA *soa;
1063 	Srv *srv;
1064 	Txt *t;
1065 
1066 	fmtstrinit(&fstr);
1067 
1068 	rp = va_arg(f->args, RR*);
1069 	if(rp == nil){
1070 		fmtprint(&fstr, "<null>");
1071 		goto out;
1072 	}
1073 
1074 	fmtprint(&fstr, "%s %s", dnname(rp->owner),
1075 		rrname(rp->type, buf, sizeof buf));
1076 
1077 	if(rp->negative){
1078 		fmtprint(&fstr, "\tnegative - rcode %d", rp->negrcode);
1079 		goto out;
1080 	}
1081 
1082 	switch(rp->type){
1083 	case Thinfo:
1084 		fmtprint(&fstr, "\t%s %s", dnname(rp->cpu), dnname(rp->os));
1085 		break;
1086 	case Tcname:
1087 	case Tmb:
1088 	case Tmd:
1089 	case Tmf:
1090 	case Tns:
1091 		fmtprint(&fstr, "\t%s", dnname(rp->host));
1092 		break;
1093 	case Tmg:
1094 	case Tmr:
1095 		fmtprint(&fstr, "\t%s", dnname(rp->mb));
1096 		break;
1097 	case Tminfo:
1098 		fmtprint(&fstr, "\t%s %s", dnname(rp->mb), dnname(rp->rmb));
1099 		break;
1100 	case Tmx:
1101 		fmtprint(&fstr, "\t%lud %s", rp->pref, dnname(rp->host));
1102 		break;
1103 	case Ta:
1104 	case Taaaa:
1105 		fmtprint(&fstr, "\t%s", dnname(rp->ip));
1106 		break;
1107 	case Tptr:
1108 //		fmtprint(&fstr, "\t%s(%lud)", dnname(rp->ptr),
1109 //			rp->ptr? rp->ptr->ordinal: "<null>");
1110 		fmtprint(&fstr, "\t%s", dnname(rp->ptr));
1111 		break;
1112 	case Tsoa:
1113 		soa = rp->soa;
1114 		fmtprint(&fstr, "\t%s %s %lud %lud %lud %lud %lud",
1115 			dnname(rp->host), dnname(rp->rmb),
1116 			(soa? soa->serial: 0),
1117 			(soa? soa->refresh: 0), (soa? soa->retry: 0),
1118 			(soa? soa->expire: 0), (soa? soa->minttl: 0));
1119 		if (soa)
1120 			for(s = soa->slaves; s != nil; s = s->next)
1121 				fmtprint(&fstr, " %s", s->name);
1122 		break;
1123 	case Tsrv:
1124 		srv = rp->srv;
1125 		fmtprint(&fstr, "\t%ud %ud %ud %s",
1126 			(srv? srv->pri: 0), (srv? srv->weight: 0),
1127 			(srv? srv->port: 0), (srv? dnname(srv->target): ""));
1128 		break;
1129 	case Tnull:
1130 		if (rp->null == nil)
1131 			fmtprint(&fstr, "\t<null>");
1132 		else
1133 			fmtprint(&fstr, "\t%.*H", rp->null->dlen,
1134 				rp->null->data);
1135 		break;
1136 	case Ttxt:
1137 		fmtprint(&fstr, "\t");
1138 		for(t = rp->txt; t != nil; t = t->next)
1139 			fmtprint(&fstr, "%s", t->p);
1140 		break;
1141 	case Trp:
1142 		fmtprint(&fstr, "\t%s %s", dnname(rp->rmb), dnname(rp->rp));
1143 		break;
1144 	case Tkey:
1145 		if (rp->key == nil)
1146 			fmtprint(&fstr, "\t<null> <null> <null>");
1147 		else
1148 			fmtprint(&fstr, "\t%d %d %d", rp->key->flags,
1149 				rp->key->proto, rp->key->alg);
1150 		break;
1151 	case Tsig:
1152 		if (rp->sig == nil)
1153 			fmtprint(&fstr,
1154 		   "\t<null> <null> <null> <null> <null> <null> <null> <null>");
1155 		else
1156 			fmtprint(&fstr, "\t%d %d %d %lud %lud %lud %d %s",
1157 				rp->sig->type, rp->sig->alg, rp->sig->labels,
1158 				rp->sig->ttl, rp->sig->exp, rp->sig->incep,
1159 				rp->sig->tag, dnname(rp->sig->signer));
1160 		break;
1161 	case Tcert:
1162 		if (rp->cert == nil)
1163 			fmtprint(&fstr, "\t<null> <null> <null>");
1164 		else
1165 			fmtprint(&fstr, "\t%d %d %d",
1166 				rp->cert->type, rp->cert->tag, rp->cert->alg);
1167 		break;
1168 	}
1169 out:
1170 	strp = fmtstrflush(&fstr);
1171 	rv = fmtstrcpy(f, strp);
1172 	free(strp);
1173 	return rv;
1174 }
1175 
1176 /*
1177  *  print conversion for rr records in attribute value form
1178  */
1179 int
1180 rravfmt(Fmt *f)
1181 {
1182 	int rv, quote;
1183 	char *strp;
1184 	Fmt fstr;
1185 	RR *rp;
1186 	Server *s;
1187 	SOA *soa;
1188 	Srv *srv;
1189 	Txt *t;
1190 
1191 	fmtstrinit(&fstr);
1192 
1193 	rp = va_arg(f->args, RR*);
1194 	if(rp == nil){
1195 		fmtprint(&fstr, "<null>");
1196 		goto out;
1197 	}
1198 
1199 	if(rp->type == Tptr)
1200 		fmtprint(&fstr, "ptr=%s", dnname(rp->owner));
1201 	else
1202 		fmtprint(&fstr, "dom=%s", dnname(rp->owner));
1203 
1204 	switch(rp->type){
1205 	case Thinfo:
1206 		fmtprint(&fstr, " cpu=%s os=%s",
1207 			dnname(rp->cpu), dnname(rp->os));
1208 		break;
1209 	case Tcname:
1210 		fmtprint(&fstr, " cname=%s", dnname(rp->host));
1211 		break;
1212 	case Tmb:
1213 	case Tmd:
1214 	case Tmf:
1215 		fmtprint(&fstr, " mbox=%s", dnname(rp->host));
1216 		break;
1217 	case Tns:
1218 		fmtprint(&fstr,  " ns=%s", dnname(rp->host));
1219 		break;
1220 	case Tmg:
1221 	case Tmr:
1222 		fmtprint(&fstr, " mbox=%s", dnname(rp->mb));
1223 		break;
1224 	case Tminfo:
1225 		fmtprint(&fstr, " mbox=%s mbox=%s",
1226 			dnname(rp->mb), dnname(rp->rmb));
1227 		break;
1228 	case Tmx:
1229 		fmtprint(&fstr, " pref=%lud mx=%s", rp->pref, dnname(rp->host));
1230 		break;
1231 	case Ta:
1232 	case Taaaa:
1233 		fmtprint(&fstr, " ip=%s", dnname(rp->ip));
1234 		break;
1235 	case Tptr:
1236 		fmtprint(&fstr, " dom=%s", dnname(rp->ptr));
1237 		break;
1238 	case Tsoa:
1239 		soa = rp->soa;
1240 		fmtprint(&fstr,
1241 " ns=%s mbox=%s serial=%lud refresh=%lud retry=%lud expire=%lud ttl=%lud",
1242 			dnname(rp->host), dnname(rp->rmb),
1243 			(soa? soa->serial: 0),
1244 			(soa? soa->refresh: 0), (soa? soa->retry: 0),
1245 			(soa? soa->expire: 0), (soa? soa->minttl: 0));
1246 		for(s = soa->slaves; s != nil; s = s->next)
1247 			fmtprint(&fstr, " dnsslave=%s", s->name);
1248 		break;
1249 	case Tsrv:
1250 		srv = rp->srv;
1251 		fmtprint(&fstr, " pri=%ud weight=%ud port=%ud target=%s",
1252 			(srv? srv->pri: 0), (srv? srv->weight: 0),
1253 			(srv? srv->port: 0), (srv? dnname(srv->target): ""));
1254 		break;
1255 	case Tnull:
1256 		if (rp->null == nil)
1257 			fmtprint(&fstr, " null=<null>");
1258 		else
1259 			fmtprint(&fstr, " null=%.*H", rp->null->dlen,
1260 				rp->null->data);
1261 		break;
1262 	case Ttxt:
1263 		fmtprint(&fstr, " txt=");
1264 		quote = 0;
1265 		for(t = rp->txt; t != nil; t = t->next)
1266 			if(strchr(t->p, ' '))
1267 				quote = 1;
1268 		if(quote)
1269 			fmtprint(&fstr, "\"");
1270 		for(t = rp->txt; t != nil; t = t->next)
1271 			fmtprint(&fstr, "%s", t->p);
1272 		if(quote)
1273 			fmtprint(&fstr, "\"");
1274 		break;
1275 	case Trp:
1276 		fmtprint(&fstr, " rp=%s txt=%s",
1277 			dnname(rp->rmb), dnname(rp->rp));
1278 		break;
1279 	case Tkey:
1280 		if (rp->key == nil)
1281 			fmtprint(&fstr, " flags=<null> proto=<null> alg=<null>");
1282 		else
1283 			fmtprint(&fstr, " flags=%d proto=%d alg=%d",
1284 				rp->key->flags, rp->key->proto, rp->key->alg);
1285 		break;
1286 	case Tsig:
1287 		if (rp->sig == nil)
1288 			fmtprint(&fstr,
1289 " type=<null> alg=<null> labels=<null> ttl=<null> exp=<null> incep=<null> tag=<null> signer=<null>");
1290 		else
1291 			fmtprint(&fstr,
1292 " type=%d alg=%d labels=%d ttl=%lud exp=%lud incep=%lud tag=%d signer=%s",
1293 				rp->sig->type, rp->sig->alg, rp->sig->labels,
1294 				rp->sig->ttl, rp->sig->exp, rp->sig->incep,
1295 				rp->sig->tag, dnname(rp->sig->signer));
1296 		break;
1297 	case Tcert:
1298 		if (rp->cert == nil)
1299 			fmtprint(&fstr, " type=<null> tag=<null> alg=<null>");
1300 		else
1301 			fmtprint(&fstr, " type=%d tag=%d alg=%d",
1302 				rp->cert->type, rp->cert->tag, rp->cert->alg);
1303 		break;
1304 	}
1305 out:
1306 	strp = fmtstrflush(&fstr);
1307 	rv = fmtstrcpy(f, strp);
1308 	free(strp);
1309 	return rv;
1310 }
1311 
1312 void
1313 warning(char *fmt, ...)
1314 {
1315 	char dnserr[256];
1316 	va_list arg;
1317 
1318 	va_start(arg, fmt);
1319 	vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
1320 	va_end(arg);
1321 	syslog(1, logfile, dnserr);		/* on console too */
1322 }
1323 
1324 void
1325 dnslog(char *fmt, ...)
1326 {
1327 	char dnserr[256];
1328 	va_list arg;
1329 
1330 	va_start(arg, fmt);
1331 	vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
1332 	va_end(arg);
1333 	syslog(0, logfile, dnserr);
1334 }
1335 
1336 /*
1337  * based on libthread's threadsetname, but drags in less library code.
1338  * actually just sets the arguments displayed.
1339  */
1340 void
1341 procsetname(char *fmt, ...)
1342 {
1343 	int fd;
1344 	char *cmdname;
1345 	char buf[128];
1346 	va_list arg;
1347 
1348 	va_start(arg, fmt);
1349 	cmdname = vsmprint(fmt, arg);
1350 	va_end(arg);
1351 	if (cmdname == nil)
1352 		return;
1353 	snprint(buf, sizeof buf, "#p/%d/args", getpid());
1354 	if((fd = open(buf, OWRITE)) >= 0){
1355 		write(fd, cmdname, strlen(cmdname)+1);
1356 		close(fd);
1357 	}
1358 	free(cmdname);
1359 }
1360 
1361 /*
1362  *  create a slave process to handle a request to avoid one request blocking
1363  *  another
1364  */
1365 void
1366 slave(Request *req)
1367 {
1368 	int ppid, procs;
1369 
1370 	if(req->isslave)
1371 		return;		/* we're already a slave process */
1372 
1373 	/*
1374 	 * These calls to putactivity cannot block.
1375 	 * After getactivity(), the current process is counted
1376 	 * twice in dnvars.active (one will pass to the child).
1377 	 * If putactivity tries to wait for dnvars.active == 0,
1378 	 * it will never happen.
1379 	 */
1380 
1381 	/* limit parallelism */
1382 	procs = getactivity(req, 1);
1383 	if (procs > stats.slavehiwat)
1384 		stats.slavehiwat = procs;
1385 	if(procs > Maxactive){
1386 		if(traceactivity)
1387 			dnslog("[%d] too much activity", getpid());
1388 		putactivity(1);
1389 		return;
1390 	}
1391 
1392 	/* parent returns to main loop, child does the work */
1393 	ppid = getpid();
1394 	switch(rfork(RFPROC|RFNOTEG|RFMEM|RFNOWAIT)){
1395 	case -1:
1396 		putactivity(1);
1397 		break;
1398 	case 0:
1399 		procsetname("request slave of pid %d", ppid);
1400  		if(traceactivity)
1401 			dnslog("[%d] take activity from %d", getpid(), ppid);
1402 		req->isslave = 1;	/* why not `= getpid()'? */
1403 		break;
1404 	default:
1405 		/*
1406 		 * this relies on rfork producing separate, initially-identical
1407 		 * stacks, thus giving us two copies of `req', one in each
1408 		 * process.
1409 		 */
1410 		longjmp(req->mret, 1);
1411 	}
1412 }
1413 
1414 /*
1415  *  chasing down double free's
1416  */
1417 void
1418 dncheck(void *p, int dolock)
1419 {
1420 	int i;
1421 	DN *dp;
1422 	RR *rp;
1423 
1424 	if(p != nil){
1425 		dp = p;
1426 		assert(dp->magic == DNmagic);
1427 	}
1428 
1429 	if(!testing)
1430 		return;
1431 
1432 	if(dolock)
1433 		lock(&dnlock);
1434 	poolcheck(mainmem);
1435 	for(i = 0; i < HTLEN; i++)
1436 		for(dp = ht[i]; dp; dp = dp->next){
1437 			assert(dp != p);
1438 			assert(dp->magic == DNmagic);
1439 			for(rp = dp->rr; rp; rp = rp->next){
1440 				assert(rp->magic == RRmagic);
1441 				assert(rp->cached);
1442 				assert(rp->owner == dp);
1443 			}
1444 		}
1445 	if(dolock)
1446 		unlock(&dnlock);
1447 }
1448 
1449 static int
1450 rrequiv(RR *r1, RR *r2)
1451 {
1452 	return r1->owner == r2->owner
1453 		&& r1->type == r2->type
1454 		&& r1->arg0 == r2->arg0
1455 		&& r1->arg1 == r2->arg1
1456 		&& (r1->type != Tsrv || r1->srv == r2->srv);
1457 }
1458 
1459 void
1460 unique(RR *rp)
1461 {
1462 	RR **l, *nrp;
1463 
1464 	for(; rp; rp = rp->next){
1465 		l = &rp->next;
1466 		for(nrp = *l; nrp; nrp = *l)
1467 			if(rrequiv(rp, nrp)){
1468 				*l = nrp->next;
1469 				rrfree(nrp);
1470 			} else
1471 				l = &nrp->next;
1472 	}
1473 }
1474 
1475 /*
1476  *  true if second domain is subsumed by the first
1477  */
1478 int
1479 subsume(char *higher, char *lower)
1480 {
1481 	int hn, ln;
1482 
1483 	ln = strlen(lower);
1484 	hn = strlen(higher);
1485 	if (ln < hn || cistrcmp(lower + ln - hn, higher) != 0 ||
1486 	    ln > hn && hn != 0 && lower[ln - hn - 1] != '.')
1487 		return 0;
1488 	return 1;
1489 }
1490 
1491 /*
1492  *  randomize the order we return items to provide some
1493  *  load balancing for servers.
1494  *
1495  *  only randomize the first class of entries
1496  */
1497 RR*
1498 randomize(RR *rp)
1499 {
1500 	RR *first, *last, *x, *base;
1501 	ulong n;
1502 
1503 	if(rp == nil || rp->next == nil)
1504 		return rp;
1505 
1506 	/* just randomize addresses, mx's and ns's */
1507 	for(x = rp; x; x = x->next)
1508 		if(x->type != Ta && x->type != Tmx && x->type != Tns)
1509 			return rp;
1510 
1511 	base = rp;
1512 
1513 	n = rand();
1514 	last = first = nil;
1515 	while(rp != nil){
1516 		/* stop randomizing if we've moved past our class */
1517 		if(base->auth != rp->auth || base->db != rp->db){
1518 			last->next = rp;
1519 			break;
1520 		}
1521 
1522 		/* unchain */
1523 		x = rp;
1524 		rp = x->next;
1525 		x->next = nil;
1526 
1527 		if(n&1 && x->type == Tns /* && rrisslug(x) */ ){
1528 			/* add to tail */
1529 			if(last == nil)
1530 				first = x;
1531 			else
1532 				last->next = x;
1533 			last = x;
1534 		} else {
1535 			/* add to head */
1536 			if(last == nil)
1537 				last = x;
1538 			x->next = first;
1539 			first = x;
1540 		}
1541 
1542 		/* reroll the dice */
1543 		n >>= 1;
1544 	}
1545 
1546 	return first;
1547 }
1548 
1549 static int
1550 sencodefmt(Fmt *f)
1551 {
1552 	int i, len, ilen, rv;
1553 	char *out, *buf;
1554 	uchar *b;
1555 	char obuf[64];		/* rsc optimization */
1556 
1557 	if(!(f->flags&FmtPrec) || f->prec < 1)
1558 		goto error;
1559 
1560 	b = va_arg(f->args, uchar*);
1561 	if(b == nil)
1562 		goto error;
1563 
1564 	/* if it's a printable, go for it */
1565 	len = f->prec;
1566 	for(i = 0; i < len; i++)
1567 		if(!isprint(b[i]))
1568 			break;
1569 	if(i == len){
1570 		if(len >= sizeof obuf)
1571 			len = sizeof(obuf)-1;
1572 		memmove(obuf, b, len);
1573 		obuf[len] = 0;
1574 		fmtstrcpy(f, obuf);
1575 		return 0;
1576 	}
1577 
1578 	ilen = f->prec;
1579 	f->prec = 0;
1580 	f->flags &= ~FmtPrec;
1581 	switch(f->r){
1582 	case '<':
1583 		len = (8*ilen+4)/5 + 3;
1584 		break;
1585 	case '[':
1586 		len = (8*ilen+5)/6 + 4;
1587 		break;
1588 	case 'H':
1589 		len = 2*ilen + 1;
1590 		break;
1591 	default:
1592 		goto error;
1593 	}
1594 
1595 	if(len > sizeof(obuf)){
1596 		buf = malloc(len);
1597 		if(buf == nil)
1598 			goto error;
1599 	} else
1600 		buf = obuf;
1601 
1602 	/* convert */
1603 	out = buf;
1604 	switch(f->r){
1605 	case '<':
1606 		rv = enc32(out, len, b, ilen);
1607 		break;
1608 	case '[':
1609 		rv = enc64(out, len, b, ilen);
1610 		break;
1611 	case 'H':
1612 		rv = enc16(out, len, b, ilen);
1613 		break;
1614 	default:
1615 		rv = -1;
1616 		break;
1617 	}
1618 	if(rv < 0)
1619 		goto error;
1620 
1621 	fmtstrcpy(f, buf);
1622 	if(buf != obuf)
1623 		free(buf);
1624 	return 0;
1625 
1626 error:
1627 	return fmtstrcpy(f, "<encodefmt>");
1628 }
1629 
1630 void*
1631 emalloc(int size)
1632 {
1633 	char *x;
1634 
1635 	x = mallocz(size, 1);
1636 	if(x == nil)
1637 		abort();
1638 	setmalloctag(x, getcallerpc(&size));
1639 	return x;
1640 }
1641 
1642 char*
1643 estrdup(char *s)
1644 {
1645 	int size;
1646 	char *p;
1647 
1648 	size = strlen(s)+1;
1649 	p = mallocz(size, 0);
1650 	if(p == nil)
1651 		abort();
1652 	memmove(p, s, size);
1653 	setmalloctag(p, getcallerpc(&s));
1654 	return p;
1655 }
1656 
1657 /*
1658  *  create a pointer record
1659  */
1660 static RR*
1661 mkptr(DN *dp, char *ptr, ulong ttl)
1662 {
1663 	DN *ipdp;
1664 	RR *rp;
1665 
1666 	ipdp = dnlookup(ptr, Cin, 1);
1667 
1668 	rp = rralloc(Tptr);
1669 	rp->ptr = dp;
1670 	rp->owner = ipdp;
1671 	rp->db = 1;
1672 	if(ttl)
1673 		rp->ttl = ttl;
1674 	return rp;
1675 }
1676 
1677 void	bytes2nibbles(uchar *nibbles, uchar *bytes, int nbytes);
1678 
1679 /*
1680  *  look for all ip addresses in this network and make
1681  *  pointer records for them.
1682  */
1683 void
1684 dnptr(uchar *net, uchar *mask, char *dom, int forwtype, int subdoms, int ttl)
1685 {
1686 	int i, j, len;
1687 	char *p, *e;
1688 	char ptr[Domlen];
1689 	uchar *ipp;
1690 	uchar ip[IPaddrlen], nnet[IPaddrlen];
1691 	uchar nibip[IPaddrlen*2];
1692 	DN *dp;
1693 	RR *rp, *nrp, *first, **l;
1694 
1695 	l = &first;
1696 	first = nil;
1697 	for(i = 0; i < HTLEN; i++)
1698 		for(dp = ht[i]; dp; dp = dp->next)
1699 			for(rp = dp->rr; rp; rp = rp->next){
1700 				if(rp->type != forwtype || rp->negative)
1701 					continue;
1702 				parseip(ip, rp->ip->name);
1703 				maskip(ip, mask, nnet);
1704 				if(ipcmp(net, nnet) != 0)
1705 					continue;
1706 
1707 				ipp = ip;
1708 				len = IPaddrlen;
1709 				if (forwtype == Taaaa) {
1710 					bytes2nibbles(nibip, ip, IPaddrlen);
1711 					ipp = nibip;
1712 					len = 2*IPaddrlen;
1713 				}
1714 
1715 				p = ptr;
1716 				e = ptr+sizeof(ptr);
1717 				for(j = len - 1; j >= len - subdoms; j--)
1718 					p = seprint(p, e, (forwtype == Ta?
1719 						"%d.": "%x."), ipp[j]);
1720 				seprint(p, e, "%s", dom);
1721 
1722 				nrp = mkptr(dp, ptr, ttl);
1723 				*l = nrp;
1724 				l = &nrp->next;
1725 			}
1726 
1727 	for(rp = first; rp != nil; rp = nrp){
1728 		nrp = rp->next;
1729 		rp->next = nil;
1730 		rrattach(rp, Authoritative);
1731 	}
1732 }
1733 
1734 void
1735 addserver(Server **l, char *name)
1736 {
1737 	Server *s;
1738 
1739 	while(*l)
1740 		l = &(*l)->next;
1741 	s = malloc(sizeof(Server)+strlen(name)+1);
1742 	if(s == nil)
1743 		return;
1744 	s->name = (char*)(s+1);
1745 	strcpy(s->name, name);
1746 	s->next = nil;
1747 	*l = s;
1748 }
1749 
1750 Server*
1751 copyserverlist(Server *s)
1752 {
1753 	Server *ns;
1754 
1755 	for(ns = nil; s != nil; s = s->next)
1756 		addserver(&ns, s->name);
1757 	return ns;
1758 }
1759 
1760 
1761 /* from here down is copied to ip/snoopy/dns.c periodically to update it */
1762 
1763 /*
1764  *  convert an integer RR type to it's ascii name
1765  */
1766 char*
1767 rrname(int type, char *buf, int len)
1768 {
1769 	char *t;
1770 
1771 	t = nil;
1772 	if(type >= 0 && type <= Tall)
1773 		t = rrtname[type];
1774 	if(t==nil){
1775 		snprint(buf, len, "%d", type);
1776 		t = buf;
1777 	}
1778 	return t;
1779 }
1780 
1781 /*
1782  *  free a list of resource records and any related structs
1783  */
1784 void
1785 rrfreelist(RR *rp)
1786 {
1787 	RR *next;
1788 
1789 	for(; rp; rp = next){
1790 		next = rp->next;
1791 		rrfree(rp);
1792 	}
1793 }
1794 
1795 void
1796 freeserverlist(Server *s)
1797 {
1798 	Server *next;
1799 
1800 	for(; s != nil; s = next){
1801 		next = s->next;
1802 		free(s);
1803 	}
1804 }
1805 
1806 /*
1807  *  allocate a resource record of a given type
1808  */
1809 RR*
1810 rralloc(int type)
1811 {
1812 	RR *rp;
1813 
1814 	rp = emalloc(sizeof(*rp));
1815 	rp->magic = RRmagic;
1816 	rp->pc = getcallerpc(&type);
1817 	rp->type = type;
1818 	setmalloctag(rp, rp->pc);
1819 	switch(type){
1820 	case Tsoa:
1821 		rp->soa = emalloc(sizeof(*rp->soa));
1822 		rp->soa->slaves = nil;
1823 		setmalloctag(rp->soa, rp->pc);
1824 		break;
1825 	case Tsrv:
1826 		rp->srv = emalloc(sizeof(*rp->srv));
1827 		setmalloctag(rp->srv, rp->pc);
1828 		break;
1829 	case Tkey:
1830 		rp->key = emalloc(sizeof(*rp->key));
1831 		setmalloctag(rp->key, rp->pc);
1832 		break;
1833 	case Tcert:
1834 		rp->cert = emalloc(sizeof(*rp->cert));
1835 		setmalloctag(rp->cert, rp->pc);
1836 		break;
1837 	case Tsig:
1838 		rp->sig = emalloc(sizeof(*rp->sig));
1839 		setmalloctag(rp->sig, rp->pc);
1840 		break;
1841 	case Tnull:
1842 		rp->null = emalloc(sizeof(*rp->null));
1843 		setmalloctag(rp->null, rp->pc);
1844 		break;
1845 	}
1846 	rp->ttl = 0;
1847 	rp->expire = 0;
1848 	rp->next = 0;
1849 	return rp;
1850 }
1851 
1852 /*
1853  *  free a resource record and any related structs
1854  */
1855 void
1856 rrfree(RR *rp)
1857 {
1858 	DN *dp;
1859 	RR *nrp;
1860 	Txt *t;
1861 
1862 	assert(rp->magic = RRmagic);
1863 	assert(!rp->cached);
1864 
1865 	dp = rp->owner;
1866 	if(dp){
1867 		assert(dp->magic == DNmagic);
1868 		for(nrp = dp->rr; nrp; nrp = nrp->next)
1869 			assert(nrp != rp);	/* "rrfree of live rr" */
1870 	}
1871 
1872 	switch(rp->type){
1873 	case Tsoa:
1874 		freeserverlist(rp->soa->slaves);
1875 		memset(rp->soa, 0, sizeof *rp->soa);	/* cause trouble */
1876 		free(rp->soa);
1877 		break;
1878 	case Tsrv:
1879 		memset(rp->srv, 0, sizeof *rp->srv);	/* cause trouble */
1880 		free(rp->srv);
1881 		break;
1882 	case Tkey:
1883 		free(rp->key->data);
1884 		memset(rp->key, 0, sizeof *rp->key);	/* cause trouble */
1885 		free(rp->key);
1886 		break;
1887 	case Tcert:
1888 		free(rp->cert->data);
1889 		memset(rp->cert, 0, sizeof *rp->cert);	/* cause trouble */
1890 		free(rp->cert);
1891 		break;
1892 	case Tsig:
1893 		free(rp->sig->data);
1894 		memset(rp->sig, 0, sizeof *rp->sig);	/* cause trouble */
1895 		free(rp->sig);
1896 		break;
1897 	case Tnull:
1898 		free(rp->null->data);
1899 		memset(rp->null, 0, sizeof *rp->null);	/* cause trouble */
1900 		free(rp->null);
1901 		break;
1902 	case Ttxt:
1903 		while(rp->txt != nil){
1904 			t = rp->txt;
1905 			rp->txt = t->next;
1906 			free(t->p);
1907 			memset(t, 0, sizeof *t);	/* cause trouble */
1908 			free(t);
1909 		}
1910 		break;
1911 	}
1912 
1913 	rp->magic = ~rp->magic;
1914 	memset(rp, 0, sizeof *rp);		/* cause trouble */
1915 	free(rp);
1916 }
1917