xref: /plan9/sys/src/cmd/ndb/dn.c (revision d9924332ebdbff1ae6e4e81162ea52d38508aa08)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <ip.h>
47dd7cddfSDavid du Colombier #include <pool.h>
59a747e4fSDavid du Colombier #include <ctype.h>
63e12c5d1SDavid du Colombier #include "dns.h"
73e12c5d1SDavid du Colombier 
821abd8f2SDavid du Colombier /*
921abd8f2SDavid du Colombier  *  this comment used to say `our target is 4000 names cached, this should
1021abd8f2SDavid du Colombier  *  be larger on large servers'.  dns at Bell Labs starts off with
1121abd8f2SDavid du Colombier  *  about 1780 names.
1221abd8f2SDavid du Colombier  *
1321abd8f2SDavid du Colombier  * aging seems to corrupt the cache, so raise the trigger from 4000 until we
14410ea80bSDavid du Colombier  * figure it out.
1521abd8f2SDavid du Colombier  */
1621abd8f2SDavid du Colombier enum {
17410ea80bSDavid du Colombier 	Deftarget = 8000,
1821abd8f2SDavid du Colombier };
1981730632SDavid du Colombier enum {
2081730632SDavid du Colombier 	Minage		= 10*60,
21f46c709fSDavid du Colombier 	Defagefreq	= 30*60,	/* age names this often (seconds) */
2281730632SDavid du Colombier };
2381730632SDavid du Colombier 
243e12c5d1SDavid du Colombier /*
253e12c5d1SDavid du Colombier  *  Hash table for domain names.  The hash is based only on the
263e12c5d1SDavid du Colombier  *  first element of the domain name.
273e12c5d1SDavid du Colombier  */
287dd7cddfSDavid du Colombier DN *ht[HTLEN];
293e12c5d1SDavid du Colombier 
304f8f669cSDavid du Colombier static struct {
317dd7cddfSDavid du Colombier 	Lock;
327dd7cddfSDavid du Colombier 	ulong	names;		/* names allocated */
337dd7cddfSDavid du Colombier 	ulong	oldest;		/* longest we'll leave a name around */
347dd7cddfSDavid du Colombier 	int	active;
357dd7cddfSDavid du Colombier 	int	mutex;
364f8f669cSDavid du Colombier 	ushort	id;		/* same size as in packet */
377dd7cddfSDavid du Colombier } dnvars;
383e12c5d1SDavid du Colombier 
393e12c5d1SDavid du Colombier /* names of RR types */
403e12c5d1SDavid du Colombier char *rrtname[] =
413e12c5d1SDavid du Colombier {
423e12c5d1SDavid du Colombier [Ta]		"ip",
433e12c5d1SDavid du Colombier [Tns]		"ns",
443e12c5d1SDavid du Colombier [Tmd]		"md",
453e12c5d1SDavid du Colombier [Tmf]		"mf",
463e12c5d1SDavid du Colombier [Tcname]	"cname",
473e12c5d1SDavid du Colombier [Tsoa]		"soa",
483e12c5d1SDavid du Colombier [Tmb]		"mb",
493e12c5d1SDavid du Colombier [Tmg]		"mg",
503e12c5d1SDavid du Colombier [Tmr]		"mr",
513e12c5d1SDavid du Colombier [Tnull]		"null",
523e12c5d1SDavid du Colombier [Twks]		"wks",
533e12c5d1SDavid du Colombier [Tptr]		"ptr",
543e12c5d1SDavid du Colombier [Thinfo]	"hinfo",
553e12c5d1SDavid du Colombier [Tminfo]	"minfo",
563e12c5d1SDavid du Colombier [Tmx]		"mx",
573e12c5d1SDavid du Colombier [Ttxt]		"txt",
587dd7cddfSDavid du Colombier [Trp]		"rp",
59ab3dc52fSDavid du Colombier [Tafsdb]	"afsdb",
60ab3dc52fSDavid du Colombier [Tx25]		"x.25",
61ab3dc52fSDavid du Colombier [Tisdn]		"isdn",
62ab3dc52fSDavid du Colombier [Trt]		"rt",
63ab3dc52fSDavid du Colombier [Tnsap]		"nsap",
64ab3dc52fSDavid du Colombier [Tnsapptr]	"nsap-ptr",
657dd7cddfSDavid du Colombier [Tsig]		"sig",
66ab3dc52fSDavid du Colombier [Tkey]		"key",
67ab3dc52fSDavid du Colombier [Tpx]		"px",
68ab3dc52fSDavid du Colombier [Tgpos]		"gpos",
695d459b5aSDavid du Colombier [Taaaa]		"ipv6",
70ab3dc52fSDavid du Colombier [Tloc]		"loc",
71ab3dc52fSDavid du Colombier [Tnxt]		"nxt",
72ab3dc52fSDavid du Colombier [Teid]		"eid",
73ab3dc52fSDavid du Colombier [Tnimloc]	"nimrod",
74ab3dc52fSDavid du Colombier [Tsrv]		"srv",
75ab3dc52fSDavid du Colombier [Tatma]		"atma",
76ab3dc52fSDavid du Colombier [Tnaptr]	"naptr",
77ab3dc52fSDavid du Colombier [Tkx]		"kx",
78ab3dc52fSDavid du Colombier [Tcert]		"cert",
79ab3dc52fSDavid du Colombier [Ta6]		"a6",
80ab3dc52fSDavid du Colombier [Tdname]	"dname",
81ab3dc52fSDavid du Colombier [Tsink]		"sink",
82ab3dc52fSDavid du Colombier [Topt]		"opt",
83ab3dc52fSDavid du Colombier [Tapl]		"apl",
84ab3dc52fSDavid du Colombier [Tds]		"ds",
85ab3dc52fSDavid du Colombier [Tsshfp]	"sshfp",
86ab3dc52fSDavid du Colombier [Tipseckey]	"ipseckey",
87ab3dc52fSDavid du Colombier [Trrsig]	"rrsig",
88ab3dc52fSDavid du Colombier [Tnsec]		"nsec",
89ab3dc52fSDavid du Colombier [Tdnskey]	"dnskey",
90ab3dc52fSDavid du Colombier [Tspf]		"spf",
91ab3dc52fSDavid du Colombier [Tuinfo]	"uinfo",
92ab3dc52fSDavid du Colombier [Tuid]		"uid",
93ab3dc52fSDavid du Colombier [Tgid]		"gid",
94ab3dc52fSDavid du Colombier [Tunspec]	"unspec",
95ab3dc52fSDavid du Colombier [Ttkey]		"tkey",
96ab3dc52fSDavid du Colombier [Ttsig]		"tsig",
977dd7cddfSDavid du Colombier [Tixfr]		"ixfr",
987dd7cddfSDavid du Colombier [Taxfr]		"axfr",
99ab3dc52fSDavid du Colombier [Tmailb]	"mailb",
100ab3dc52fSDavid du Colombier [Tmaila]	"maila",
101219b2ee8SDavid du Colombier [Tall]		"all",
1023e12c5d1SDavid du Colombier 		0,
1033e12c5d1SDavid du Colombier };
1043e12c5d1SDavid du Colombier 
1053e12c5d1SDavid du Colombier /* names of response codes */
106271b8d73SDavid du Colombier char *rname[Rmask+1] =
1073e12c5d1SDavid du Colombier {
1083e12c5d1SDavid du Colombier [Rok]			"ok",
1093e12c5d1SDavid du Colombier [Rformat]		"format error",
1103e12c5d1SDavid du Colombier [Rserver]		"server failure",
1113e12c5d1SDavid du Colombier [Rname]			"bad name",
1123e12c5d1SDavid du Colombier [Runimplimented]	"unimplemented",
1133e12c5d1SDavid du Colombier [Rrefused]		"we don't like you",
114ab3dc52fSDavid du Colombier [Ryxdomain]		"name should not exist",
115ab3dc52fSDavid du Colombier [Ryxrrset]		"rr set should not exist",
116ab3dc52fSDavid du Colombier [Rnxrrset]		"rr set should exist",
117ab3dc52fSDavid du Colombier [Rnotauth]		"not authorative",
118ab3dc52fSDavid du Colombier [Rnotzone]		"not in zone",
119ab3dc52fSDavid du Colombier [Rbadvers]		"bad opt version",
120ab3dc52fSDavid du Colombier /* [Rbadsig]		"bad signature", */
121ab3dc52fSDavid du Colombier [Rbadkey]		"bad key",
122ab3dc52fSDavid du Colombier [Rbadtime]		"bad signature time",
123ab3dc52fSDavid du Colombier [Rbadmode]		"bad mode",
124ab3dc52fSDavid du Colombier [Rbadname]		"duplicate key name",
125ab3dc52fSDavid du Colombier [Rbadalg]		"bad algorithm",
1263e12c5d1SDavid du Colombier };
1274f8f669cSDavid du Colombier unsigned nrname = nelem(rname);
1283e12c5d1SDavid du Colombier 
1293e12c5d1SDavid du Colombier /* names of op codes */
1303e12c5d1SDavid du Colombier char *opname[] =
1313e12c5d1SDavid du Colombier {
1323e12c5d1SDavid du Colombier [Oquery]	"query",
133ab3dc52fSDavid du Colombier [Oinverse]	"inverse query (retired)",
1343e12c5d1SDavid du Colombier [Ostatus]	"status",
135ab3dc52fSDavid du Colombier [Oupdate]	"update",
1363e12c5d1SDavid du Colombier };
1373e12c5d1SDavid du Colombier 
13821abd8f2SDavid du Colombier ulong target = Deftarget;
139bd389b36SDavid du Colombier Lock	dnlock;
1403e12c5d1SDavid du Colombier 
141f46c709fSDavid du Colombier static ulong agefreq = Defagefreq;
142f46c709fSDavid du Colombier 
143225077b0SDavid du Colombier static int rrequiv(RR *r1, RR *r2);
1449a747e4fSDavid du Colombier static int sencodefmt(Fmt*);
14559cc4ca5SDavid du Colombier 
146254fe3d3SDavid du Colombier static void
147254fe3d3SDavid du Colombier ding(void*, char *msg)
148254fe3d3SDavid du Colombier {
149254fe3d3SDavid du Colombier 	if(strstr(msg, "alarm") != nil) {
150254fe3d3SDavid du Colombier 		stats.alarms++;
151254fe3d3SDavid du Colombier 		noted(NCONT);		/* resume with system call error */
152254fe3d3SDavid du Colombier 	} else
153254fe3d3SDavid du Colombier 		noted(NDFLT);		/* die */
154254fe3d3SDavid du Colombier }
155254fe3d3SDavid du Colombier 
1563e12c5d1SDavid du Colombier void
1573e12c5d1SDavid du Colombier dninit(void)
1583e12c5d1SDavid du Colombier {
1599a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
1609a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
1619a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
1629a747e4fSDavid du Colombier 	fmtinstall('R', rrfmt);
1639a747e4fSDavid du Colombier 	fmtinstall('Q', rravfmt);
1649a747e4fSDavid du Colombier 	fmtinstall('H', sencodefmt);
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier 	dnvars.oldest = maxage;
1677dd7cddfSDavid du Colombier 	dnvars.names = 0;
1684f8f669cSDavid du Colombier 	dnvars.id = truerand();	/* don't start with same id every time */
169254fe3d3SDavid du Colombier 
170254fe3d3SDavid du Colombier 	notify(ding);
1713e12c5d1SDavid du Colombier }
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier /*
1743e12c5d1SDavid du Colombier  *  hash for a domain name
1753e12c5d1SDavid du Colombier  */
1763e12c5d1SDavid du Colombier static ulong
1773e12c5d1SDavid du Colombier dnhash(char *name)
1783e12c5d1SDavid du Colombier {
1793e12c5d1SDavid du Colombier 	ulong hash;
1803e12c5d1SDavid du Colombier 	uchar *val = (uchar*)name;
1813e12c5d1SDavid du Colombier 
1827dd7cddfSDavid du Colombier 	for(hash = 0; *val; val++)
1834f8f669cSDavid du Colombier 		hash = hash*13 + tolower(*val)-'a';
1843e12c5d1SDavid du Colombier 	return hash % HTLEN;
1853e12c5d1SDavid du Colombier }
1863e12c5d1SDavid du Colombier 
1873e12c5d1SDavid du Colombier /*
1883e12c5d1SDavid du Colombier  *  lookup a symbol.  if enter is not zero and the name is
1893e12c5d1SDavid du Colombier  *  not found, create it.
1903e12c5d1SDavid du Colombier  */
1913e12c5d1SDavid du Colombier DN*
1923e12c5d1SDavid du Colombier dnlookup(char *name, int class, int enter)
1933e12c5d1SDavid du Colombier {
1943e12c5d1SDavid du Colombier 	DN **l;
1953e12c5d1SDavid du Colombier 	DN *dp;
1963e12c5d1SDavid du Colombier 
1973ff48bf5SDavid du Colombier 	l = &ht[dnhash(name)];
198bd389b36SDavid du Colombier 	lock(&dnlock);
1993e12c5d1SDavid du Colombier 	for(dp = *l; dp; dp = dp->next) {
2007dd7cddfSDavid du Colombier 		assert(dp->magic == DNmagic);
2013ff48bf5SDavid du Colombier 		if(dp->class == class && cistrcmp(dp->name, name) == 0){
2027dd7cddfSDavid du Colombier 			dp->referenced = now;
203bd389b36SDavid du Colombier 			unlock(&dnlock);
2043e12c5d1SDavid du Colombier 			return dp;
2053e12c5d1SDavid du Colombier 		}
2063e12c5d1SDavid du Colombier 		l = &dp->next;
2073e12c5d1SDavid du Colombier 	}
2084f8f669cSDavid du Colombier 
2094f8f669cSDavid du Colombier 	if(!enter){
210bd389b36SDavid du Colombier 		unlock(&dnlock);
2113e12c5d1SDavid du Colombier 		return 0;
2123e12c5d1SDavid du Colombier 	}
2137dd7cddfSDavid du Colombier 	dnvars.names++;
2149a747e4fSDavid du Colombier 	dp = emalloc(sizeof(*dp));
2157dd7cddfSDavid du Colombier 	dp->magic = DNmagic;
2169a747e4fSDavid du Colombier 	dp->name = estrdup(name);
2174f8f669cSDavid du Colombier 	assert(dp->name != nil);
2183e12c5d1SDavid du Colombier 	dp->class = class;
2193e12c5d1SDavid du Colombier 	dp->rr = 0;
2207dd7cddfSDavid du Colombier 	dp->referenced = now;
221530fef66SDavid du Colombier 	/* add new DN to tail of the hash list.  *l points to last next ptr. */
222530fef66SDavid du Colombier 	dp->next = nil;
2233e12c5d1SDavid du Colombier 	*l = dp;
224bd389b36SDavid du Colombier 	unlock(&dnlock);
2257dd7cddfSDavid du Colombier 
2263e12c5d1SDavid du Colombier 	return dp;
2273e12c5d1SDavid du Colombier }
2283e12c5d1SDavid du Colombier 
229225077b0SDavid du Colombier static int
230225077b0SDavid du Colombier rrsame(RR *rr1, RR *rr2)
231225077b0SDavid du Colombier {
232225077b0SDavid du Colombier 	return rr1 == rr2 || rr2 && rrequiv(rr1, rr2) &&
233225077b0SDavid du Colombier 		rr1->db == rr2->db && rr1->auth == rr2->auth;
234225077b0SDavid du Colombier }
235225077b0SDavid du Colombier 
236225077b0SDavid du Colombier static int
237225077b0SDavid du Colombier rronlist(RR *rp, RR *lp)
238225077b0SDavid du Colombier {
239225077b0SDavid du Colombier 	for(; lp; lp = lp->next)
2404f927735SDavid du Colombier 		if (rrsame(lp, rp))
241225077b0SDavid du Colombier 			return 1;
242225077b0SDavid du Colombier 	return 0;
243225077b0SDavid du Colombier }
244225077b0SDavid du Colombier 
2453e12c5d1SDavid du Colombier /*
2464f927735SDavid du Colombier  * dump the stats
247219b2ee8SDavid du Colombier  */
248219b2ee8SDavid du Colombier void
2494f927735SDavid du Colombier dnstats(char *file)
250219b2ee8SDavid du Colombier {
251219b2ee8SDavid du Colombier 	int i, fd;
252219b2ee8SDavid du Colombier 
25321abd8f2SDavid du Colombier 	fd = create(file, OWRITE, 0666);
254219b2ee8SDavid du Colombier 	if(fd < 0)
255219b2ee8SDavid du Colombier 		return;
256a41547ffSDavid du Colombier 
257a41547ffSDavid du Colombier 	qlock(&stats);
2584f927735SDavid du Colombier 	fprint(fd, "# system %s\n", sysname());
259f46c709fSDavid du Colombier 	fprint(fd, "# slave procs high-water mark\t%lud\n", stats.slavehiwat);
260f46c709fSDavid du Colombier 	fprint(fd, "# queries received by 9p\t%lud\n", stats.qrecvd9p);
261f46c709fSDavid du Colombier 	fprint(fd, "# queries received by udp\t%lud\n", stats.qrecvdudp);
262f46c709fSDavid du Colombier 	fprint(fd, "# queries answered from memory\t%lud\n", stats.answinmem);
263f46c709fSDavid du Colombier 	fprint(fd, "# queries sent by udp\t%lud\n", stats.qsent);
264a41547ffSDavid du Colombier 	for (i = 0; i < nelem(stats.under10ths); i++)
265a41547ffSDavid du Colombier 		if (stats.under10ths[i] || i == nelem(stats.under10ths) - 1)
266f46c709fSDavid du Colombier 			fprint(fd, "# responses arriving within %.1f s.\t%lud\n",
267a41547ffSDavid du Colombier 				(double)(i+1)/10, stats.under10ths[i]);
268f46c709fSDavid du Colombier 	fprint(fd, "\n# queries sent & timed-out\t%lud\n", stats.tmout);
269f46c709fSDavid du Colombier 	fprint(fd, "# cname queries timed-out\t%lud\n", stats.tmoutcname);
270f46c709fSDavid du Colombier 	fprint(fd, "# ipv6  queries timed-out\t%lud\n", stats.tmoutv6);
271f46c709fSDavid du Colombier 	fprint(fd, "\n# negative answers received\t%lud\n", stats.negans);
2720319257bSDavid du Colombier 	fprint(fd, "# negative answers w Rserver set\t%lud\n", stats.negserver);
2730319257bSDavid du Colombier 	fprint(fd, "# negative answers w bad delegation\t%lud\n",
2740319257bSDavid du Colombier 		stats.negbaddeleg);
2750319257bSDavid du Colombier 	fprint(fd, "# negative answers w bad delegation & no answers\t%lud\n",
2760319257bSDavid du Colombier 		stats.negbdnoans);
2770319257bSDavid du Colombier 	fprint(fd, "# negative answers w no Rname set\t%lud\n", stats.negnorname);
278f46c709fSDavid du Colombier 	fprint(fd, "# negative answers cached\t%lud\n", stats.negcached);
279a41547ffSDavid du Colombier 	qunlock(&stats);
280a41547ffSDavid du Colombier 
281219b2ee8SDavid du Colombier 	lock(&dnlock);
2826d8e4566SDavid du Colombier 	fprint(fd, "\n# domain names %lud target %lud\n", dnvars.names, target);
2834f927735SDavid du Colombier 	unlock(&dnlock);
2844f927735SDavid du Colombier 	close(fd);
2854f927735SDavid du Colombier }
2864f927735SDavid du Colombier 
2874f927735SDavid du Colombier /*
2884f927735SDavid du Colombier  *  dump the cache
2894f927735SDavid du Colombier  */
2904f927735SDavid du Colombier void
2914f927735SDavid du Colombier dndump(char *file)
2924f927735SDavid du Colombier {
2934f927735SDavid du Colombier 	int i, fd;
2944f927735SDavid du Colombier 	DN *dp;
2954f927735SDavid du Colombier 	RR *rp;
2964f927735SDavid du Colombier 
2974f927735SDavid du Colombier 	fd = create(file, OWRITE, 0666);
2984f927735SDavid du Colombier 	if(fd < 0)
2994f927735SDavid du Colombier 		return;
3004f927735SDavid du Colombier 
3014f927735SDavid du Colombier 	lock(&dnlock);
3024f8f669cSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
303219b2ee8SDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
304219b2ee8SDavid du Colombier 			fprint(fd, "%s\n", dp->name);
305225077b0SDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next) {
3066d8e4566SDavid du Colombier 				fprint(fd, "\t%R %c%c %lud/%lud\n",
3074f8f669cSDavid du Colombier 					rp, rp->auth? 'A': 'U',
3087dd7cddfSDavid du Colombier 					rp->db? 'D': 'N', rp->expire, rp->ttl);
309225077b0SDavid du Colombier 				if (rronlist(rp, rp->next))
310225077b0SDavid du Colombier 					fprint(fd, "*** duplicate:\n");
311225077b0SDavid du Colombier 			}
312219b2ee8SDavid du Colombier 		}
313219b2ee8SDavid du Colombier 	unlock(&dnlock);
314219b2ee8SDavid du Colombier 	close(fd);
315219b2ee8SDavid du Colombier }
316219b2ee8SDavid du Colombier 
317219b2ee8SDavid du Colombier /*
3187dd7cddfSDavid du Colombier  *  purge all records
3197dd7cddfSDavid du Colombier  */
3207dd7cddfSDavid du Colombier void
3217dd7cddfSDavid du Colombier dnpurge(void)
3227dd7cddfSDavid du Colombier {
3237dd7cddfSDavid du Colombier 	DN *dp;
324a4285193SDavid du Colombier 	RR *rp, *srp;
3257dd7cddfSDavid du Colombier 	int i;
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier 	lock(&dnlock);
3287dd7cddfSDavid du Colombier 
3297dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
3307dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
331a4285193SDavid du Colombier 			srp = rp = dp->rr;
3327dd7cddfSDavid du Colombier 			dp->rr = nil;
3337dd7cddfSDavid du Colombier 			for(; rp != nil; rp = rp->next)
3347dd7cddfSDavid du Colombier 				rp->cached = 0;
335a4285193SDavid du Colombier 			rrfreelist(srp);
3367dd7cddfSDavid du Colombier 		}
3377dd7cddfSDavid du Colombier 
3387dd7cddfSDavid du Colombier 	unlock(&dnlock);
3397dd7cddfSDavid du Colombier }
3407dd7cddfSDavid du Colombier 
341d2fd7a44SDavid du Colombier /*
342d2fd7a44SDavid du Colombier  *  delete rp from *l, free rp.
343d2fd7a44SDavid du Colombier  *  call with dnlock held.
344d2fd7a44SDavid du Colombier  */
345225077b0SDavid du Colombier static void
346225077b0SDavid du Colombier rrdelete(RR **l, RR *rp)
347225077b0SDavid du Colombier {
348225077b0SDavid du Colombier 	*l = rp->next;
349225077b0SDavid du Colombier 	rp->cached = 0;		/* avoid blowing an assertion in rrfree */
350225077b0SDavid du Colombier 	rrfree(rp);
351225077b0SDavid du Colombier }
352225077b0SDavid du Colombier 
3537dd7cddfSDavid du Colombier /*
354d2fd7a44SDavid du Colombier  *  check the age of resource records, free any that have timed out.
355d2fd7a44SDavid du Colombier  *  call with dnlock held.
3563e12c5d1SDavid du Colombier  */
3573e12c5d1SDavid du Colombier void
3583e12c5d1SDavid du Colombier dnage(DN *dp)
3593e12c5d1SDavid du Colombier {
3603e12c5d1SDavid du Colombier 	RR **l;
3613e12c5d1SDavid du Colombier 	RR *rp, *next;
3627dd7cddfSDavid du Colombier 	ulong diff;
3633e12c5d1SDavid du Colombier 
3647dd7cddfSDavid du Colombier 	diff = now - dp->referenced;
3656dc4800dSDavid du Colombier 	if(diff < Reserved || dp->keep)
3667dd7cddfSDavid du Colombier 		return;
3677dd7cddfSDavid du Colombier 
3683e12c5d1SDavid du Colombier 	l = &dp->rr;
3693e12c5d1SDavid du Colombier 	for(rp = dp->rr; rp; rp = next){
3707dd7cddfSDavid du Colombier 		assert(rp->magic == RRmagic && rp->cached);
3713e12c5d1SDavid du Colombier 		next = rp->next;
372225077b0SDavid du Colombier 		if(!rp->db && (rp->expire < now || diff > dnvars.oldest))
373225077b0SDavid du Colombier 			rrdelete(l, rp);
374225077b0SDavid du Colombier 		else
3753e12c5d1SDavid du Colombier 			l = &rp->next;
3763e12c5d1SDavid du Colombier 	}
3773e12c5d1SDavid du Colombier }
3783e12c5d1SDavid du Colombier 
3796dc4800dSDavid du Colombier #define MARK(dp)	{ if (dp) (dp)->keep = 1; }
380a41547ffSDavid du Colombier 
381410ea80bSDavid du Colombier /* mark a domain name and those in its RRs as never to be aged */
382a41547ffSDavid du Colombier void
383410ea80bSDavid du Colombier dnagenever(DN *dp, int dolock)
384a41547ffSDavid du Colombier {
385a41547ffSDavid du Colombier 	RR *rp;
386a41547ffSDavid du Colombier 
387410ea80bSDavid du Colombier 	if (dolock)
388a41547ffSDavid du Colombier 		lock(&dnlock);
389a41547ffSDavid du Colombier 
390410ea80bSDavid du Colombier 	/* mark all referenced domain names */
391410ea80bSDavid du Colombier 	MARK(dp);
392a41547ffSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
393a41547ffSDavid du Colombier 		MARK(rp->owner);
394410ea80bSDavid du Colombier 		if(rp->negative){
395410ea80bSDavid du Colombier 			MARK(rp->negsoaowner);
396410ea80bSDavid du Colombier 			continue;
397410ea80bSDavid du Colombier 		}
398a41547ffSDavid du Colombier 		switch(rp->type){
399410ea80bSDavid du Colombier 		case Thinfo:
400410ea80bSDavid du Colombier 			MARK(rp->cpu);
401410ea80bSDavid du Colombier 			MARK(rp->os);
402410ea80bSDavid du Colombier 			break;
403410ea80bSDavid du Colombier 		case Ttxt:
404410ea80bSDavid du Colombier 			break;
405410ea80bSDavid du Colombier 		case Tcname:
406410ea80bSDavid du Colombier 		case Tmb:
407410ea80bSDavid du Colombier 		case Tmd:
408410ea80bSDavid du Colombier 		case Tmf:
409a41547ffSDavid du Colombier 		case Tns:
410410ea80bSDavid du Colombier 		case Tmx:
411410ea80bSDavid du Colombier 		case Tsrv:
412a41547ffSDavid du Colombier 			MARK(rp->host);
413a41547ffSDavid du Colombier 			break;
414410ea80bSDavid du Colombier 		case Tmg:
415410ea80bSDavid du Colombier 		case Tmr:
416410ea80bSDavid du Colombier 			MARK(rp->mb);
417410ea80bSDavid du Colombier 			break;
418410ea80bSDavid du Colombier 		case Tminfo:
419410ea80bSDavid du Colombier 			MARK(rp->rmb);
420410ea80bSDavid du Colombier 			MARK(rp->mb);
421410ea80bSDavid du Colombier 			break;
422410ea80bSDavid du Colombier 		case Trp:
423410ea80bSDavid du Colombier 			MARK(rp->rmb);
424410ea80bSDavid du Colombier 			MARK(rp->rp);
425410ea80bSDavid du Colombier 			break;
426410ea80bSDavid du Colombier 		case Ta:
427410ea80bSDavid du Colombier 		case Taaaa:
428410ea80bSDavid du Colombier 			MARK(rp->ip);
429410ea80bSDavid du Colombier 			break;
430410ea80bSDavid du Colombier 		case Tptr:
431410ea80bSDavid du Colombier 			MARK(rp->ptr);
432410ea80bSDavid du Colombier 			break;
433410ea80bSDavid du Colombier 		case Tsoa:
434410ea80bSDavid du Colombier 			MARK(rp->host);
435410ea80bSDavid du Colombier 			MARK(rp->rmb);
436410ea80bSDavid du Colombier 			break;
437a41547ffSDavid du Colombier 		}
438a41547ffSDavid du Colombier 	}
439410ea80bSDavid du Colombier 
440410ea80bSDavid du Colombier 	if (dolock)
441410ea80bSDavid du Colombier 		unlock(&dnlock);
4426dc4800dSDavid du Colombier }
443a41547ffSDavid du Colombier 
444410ea80bSDavid du Colombier /* mark all current domain names as never to be aged */
445410ea80bSDavid du Colombier void
446410ea80bSDavid du Colombier dnageallnever(void)
447410ea80bSDavid du Colombier {
448410ea80bSDavid du Colombier 	int i;
449410ea80bSDavid du Colombier 	DN *dp;
450410ea80bSDavid du Colombier 
451410ea80bSDavid du Colombier 	lock(&dnlock);
452410ea80bSDavid du Colombier 
453410ea80bSDavid du Colombier 	/* mark all referenced domain names */
454410ea80bSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
455410ea80bSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next)
456410ea80bSDavid du Colombier 			dnagenever(dp, 0);
457410ea80bSDavid du Colombier 
458a41547ffSDavid du Colombier 	unlock(&dnlock);
459a41547ffSDavid du Colombier 
460a41547ffSDavid du Colombier 	dnslog("%ld initial domain names; target is %ld", dnvars.names, target);
461a41547ffSDavid du Colombier 	if(dnvars.names >= target)
462a41547ffSDavid du Colombier 		dnslog("more initial domain names (%ld) than target (%ld)",
463a41547ffSDavid du Colombier 			dnvars.names, target);
464a41547ffSDavid du Colombier }
465a41547ffSDavid du Colombier 
4666dc4800dSDavid du Colombier #define REF(dp)	{ if (dp) (dp)->refs++; }
4676dc4800dSDavid du Colombier 
4687dd7cddfSDavid du Colombier /*
4697dd7cddfSDavid du Colombier  *  periodicly sweep for old records and remove unreferenced domain names
4707dd7cddfSDavid du Colombier  *
4717dd7cddfSDavid du Colombier  *  only called when all other threads are locked out
4727dd7cddfSDavid du Colombier  */
4737dd7cddfSDavid du Colombier void
4747dd7cddfSDavid du Colombier dnageall(int doit)
4757dd7cddfSDavid du Colombier {
4767dd7cddfSDavid du Colombier 	DN *dp, **l;
477225077b0SDavid du Colombier 	int i;
4787dd7cddfSDavid du Colombier 	RR *rp;
4797dd7cddfSDavid du Colombier 	static ulong nextage;
4807dd7cddfSDavid du Colombier 
4814f8f669cSDavid du Colombier 	if(dnvars.names < target || (now < nextage && !doit)){
4827dd7cddfSDavid du Colombier 		dnvars.oldest = maxage;
4837dd7cddfSDavid du Colombier 		return;
4847dd7cddfSDavid du Colombier 	}
4857dd7cddfSDavid du Colombier 
4864f8f669cSDavid du Colombier 	if(dnvars.names >= target) {
4873cbadd90SDavid du Colombier 		dnslog("more names (%lud) than target (%lud)", dnvars.names,
4883cbadd90SDavid du Colombier 			target);
4897dd7cddfSDavid du Colombier 		dnvars.oldest /= 2;
49081730632SDavid du Colombier 		if (dnvars.oldest < Minage)
49181730632SDavid du Colombier 			dnvars.oldest = Minage;		/* don't be silly */
4924f8f669cSDavid du Colombier 	}
493f46c709fSDavid du Colombier 	if (agefreq > dnvars.oldest / 2)
494f46c709fSDavid du Colombier 		nextage = now + dnvars.oldest / 2;
495f46c709fSDavid du Colombier 	else
496f46c709fSDavid du Colombier 		nextage = now + agefreq;
4977dd7cddfSDavid du Colombier 
4987dd7cddfSDavid du Colombier 	lock(&dnlock);
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier 	/* time out all old entries (and set refs to 0) */
5017dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
5027dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
5037dd7cddfSDavid du Colombier 			dp->refs = 0;
5047dd7cddfSDavid du Colombier 			dnage(dp);
5057dd7cddfSDavid du Colombier 		}
5067dd7cddfSDavid du Colombier 
5077dd7cddfSDavid du Colombier 	/* mark all referenced domain names */
5087dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
5097dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next)
5107dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next){
5117dd7cddfSDavid du Colombier 				REF(rp->owner);
5127dd7cddfSDavid du Colombier 				if(rp->negative){
5137dd7cddfSDavid du Colombier 					REF(rp->negsoaowner);
5147dd7cddfSDavid du Colombier 					continue;
5157dd7cddfSDavid du Colombier 				}
5167dd7cddfSDavid du Colombier 				switch(rp->type){
5177dd7cddfSDavid du Colombier 				case Thinfo:
5187dd7cddfSDavid du Colombier 					REF(rp->cpu);
5197dd7cddfSDavid du Colombier 					REF(rp->os);
5207dd7cddfSDavid du Colombier 					break;
5217dd7cddfSDavid du Colombier 				case Ttxt:
5227dd7cddfSDavid du Colombier 					break;
5237dd7cddfSDavid du Colombier 				case Tcname:
5247dd7cddfSDavid du Colombier 				case Tmb:
5257dd7cddfSDavid du Colombier 				case Tmd:
5267dd7cddfSDavid du Colombier 				case Tmf:
5277dd7cddfSDavid du Colombier 				case Tns:
5284f8f669cSDavid du Colombier 				case Tmx:
529225077b0SDavid du Colombier 				case Tsrv:
5307dd7cddfSDavid du Colombier 					REF(rp->host);
5317dd7cddfSDavid du Colombier 					break;
5327dd7cddfSDavid du Colombier 				case Tmg:
5337dd7cddfSDavid du Colombier 				case Tmr:
5347dd7cddfSDavid du Colombier 					REF(rp->mb);
5357dd7cddfSDavid du Colombier 					break;
5367dd7cddfSDavid du Colombier 				case Tminfo:
5377dd7cddfSDavid du Colombier 					REF(rp->rmb);
5387dd7cddfSDavid du Colombier 					REF(rp->mb);
5397dd7cddfSDavid du Colombier 					break;
5407dd7cddfSDavid du Colombier 				case Trp:
5417dd7cddfSDavid du Colombier 					REF(rp->rmb);
54260845620SDavid du Colombier 					REF(rp->rp);
5437dd7cddfSDavid du Colombier 					break;
5447dd7cddfSDavid du Colombier 				case Ta:
5455d459b5aSDavid du Colombier 				case Taaaa:
5467dd7cddfSDavid du Colombier 					REF(rp->ip);
5477dd7cddfSDavid du Colombier 					break;
5487dd7cddfSDavid du Colombier 				case Tptr:
5497dd7cddfSDavid du Colombier 					REF(rp->ptr);
5507dd7cddfSDavid du Colombier 					break;
5517dd7cddfSDavid du Colombier 				case Tsoa:
5527dd7cddfSDavid du Colombier 					REF(rp->host);
5537dd7cddfSDavid du Colombier 					REF(rp->rmb);
5547dd7cddfSDavid du Colombier 					break;
5557dd7cddfSDavid du Colombier 				}
5567dd7cddfSDavid du Colombier 			}
5577dd7cddfSDavid du Colombier 
5587dd7cddfSDavid du Colombier 	/* sweep and remove unreferenced domain names */
5597dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++){
5607dd7cddfSDavid du Colombier 		l = &ht[i];
5617dd7cddfSDavid du Colombier 		for(dp = *l; dp; dp = *l){
562a41547ffSDavid du Colombier 			if(dp->rr == 0 && dp->refs == 0 && !dp->keep){
56334f77ae3SDavid du Colombier 				assert(dp->magic == DNmagic);
5647dd7cddfSDavid du Colombier 				*l = dp->next;
5654f8f669cSDavid du Colombier 
5667dd7cddfSDavid du Colombier 				if(dp->name)
5677dd7cddfSDavid du Colombier 					free(dp->name);
56834f77ae3SDavid du Colombier 				dp->magic = ~dp->magic;
5697dd7cddfSDavid du Colombier 				dnvars.names--;
5704f8f669cSDavid du Colombier 				memset(dp, 0, sizeof *dp); /* cause trouble */
5717dd7cddfSDavid du Colombier 				free(dp);
5724f8f669cSDavid du Colombier 
5737dd7cddfSDavid du Colombier 				continue;
5747dd7cddfSDavid du Colombier 			}
5757dd7cddfSDavid du Colombier 			l = &dp->next;
5767dd7cddfSDavid du Colombier 		}
5777dd7cddfSDavid du Colombier 	}
5787dd7cddfSDavid du Colombier 
5797dd7cddfSDavid du Colombier 	unlock(&dnlock);
5807dd7cddfSDavid du Colombier }
5817dd7cddfSDavid du Colombier 
5827dd7cddfSDavid du Colombier /*
5837dd7cddfSDavid du Colombier  *  timeout all database records (used when rereading db)
5847dd7cddfSDavid du Colombier  */
5857dd7cddfSDavid du Colombier void
5867dd7cddfSDavid du Colombier dnagedb(void)
5877dd7cddfSDavid du Colombier {
5887dd7cddfSDavid du Colombier 	DN *dp;
5897dd7cddfSDavid du Colombier 	int i;
5907dd7cddfSDavid du Colombier 	RR *rp;
5917dd7cddfSDavid du Colombier 
5927dd7cddfSDavid du Colombier 	lock(&dnlock);
5937dd7cddfSDavid du Colombier 
5947dd7cddfSDavid du Colombier 	/* time out all database entries */
5957dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
596410ea80bSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next) {
597410ea80bSDavid du Colombier 			dp->keep = 0;
5987dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next)
5997dd7cddfSDavid du Colombier 				if(rp->db)
6007dd7cddfSDavid du Colombier 					rp->expire = 0;
601410ea80bSDavid du Colombier 		}
6027dd7cddfSDavid du Colombier 
6037dd7cddfSDavid du Colombier 	unlock(&dnlock);
6047dd7cddfSDavid du Colombier }
6057dd7cddfSDavid du Colombier 
6067dd7cddfSDavid du Colombier /*
6074f8f669cSDavid du Colombier  *  mark all local db records about my area as authoritative,
6084f8f669cSDavid du Colombier  *  time out any others
6097dd7cddfSDavid du Colombier  */
6107dd7cddfSDavid du Colombier void
6117dd7cddfSDavid du Colombier dnauthdb(void)
6127dd7cddfSDavid du Colombier {
6136b0d5c8bSDavid du Colombier 	int i;
6144f8f669cSDavid du Colombier 	ulong minttl;
6156b0d5c8bSDavid du Colombier 	Area *area;
6164f8f669cSDavid du Colombier 	DN *dp;
6177dd7cddfSDavid du Colombier 	RR *rp;
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier 	lock(&dnlock);
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier 	/* time out all database entries */
6227dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
6237dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
6247dd7cddfSDavid du Colombier 			area = inmyarea(dp->name);
6257dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next)
6267dd7cddfSDavid du Colombier 				if(rp->db){
6277dd7cddfSDavid du Colombier 					if(area){
6284f8f669cSDavid du Colombier 						minttl = area->soarr->soa->minttl;
6294f8f669cSDavid du Colombier 						if(rp->ttl < minttl)
6304f8f669cSDavid du Colombier 							rp->ttl = minttl;
6317dd7cddfSDavid du Colombier 						rp->auth = 1;
6327dd7cddfSDavid du Colombier 					}
6337dd7cddfSDavid du Colombier 					if(rp->expire == 0){
6347dd7cddfSDavid du Colombier 						rp->db = 0;
6357dd7cddfSDavid du Colombier 						dp->referenced = now-Reserved-1;
6367dd7cddfSDavid du Colombier 					}
6377dd7cddfSDavid du Colombier 				}
6387dd7cddfSDavid du Colombier 		}
6397dd7cddfSDavid du Colombier 
6407dd7cddfSDavid du Colombier 	unlock(&dnlock);
6417dd7cddfSDavid du Colombier }
6427dd7cddfSDavid du Colombier 
6437dd7cddfSDavid du Colombier /*
6447dd7cddfSDavid du Colombier  *  keep track of other processes to know if we can
6457dd7cddfSDavid du Colombier  *  garbage collect.  block while garbage collecting.
6467dd7cddfSDavid du Colombier  */
6477dd7cddfSDavid du Colombier int
648b4b9fc2fSDavid du Colombier getactivity(Request *req, int recursive)
6497dd7cddfSDavid du Colombier {
6507dd7cddfSDavid du Colombier 	int rv;
6517dd7cddfSDavid du Colombier 
6524f8f669cSDavid du Colombier 	if(traceactivity)
6534f8f669cSDavid du Colombier 		dnslog("get: %d active by pid %d from %p",
6544f8f669cSDavid du Colombier 			dnvars.active, getpid(), getcallerpc(&req));
6557dd7cddfSDavid du Colombier 	lock(&dnvars);
656b4b9fc2fSDavid du Colombier 	/*
657b4b9fc2fSDavid du Colombier 	 * can't block here if we're already holding one
658b4b9fc2fSDavid du Colombier 	 * of the dnvars.active (recursive).  will deadlock.
659b4b9fc2fSDavid du Colombier 	 */
660b4b9fc2fSDavid du Colombier 	while(!recursive && dnvars.mutex){
6617dd7cddfSDavid du Colombier 		unlock(&dnvars);
662d6d99297SDavid du Colombier 		sleep(100);			/* tune; was 200 */
6637dd7cddfSDavid du Colombier 		lock(&dnvars);
6647dd7cddfSDavid du Colombier 	}
6657dd7cddfSDavid du Colombier 	rv = ++dnvars.active;
6664f8f669cSDavid du Colombier 	now = time(nil);
667a41547ffSDavid du Colombier 	nowns = nsec();
6687dd7cddfSDavid du Colombier 	req->id = ++dnvars.id;
6697dd7cddfSDavid du Colombier 	unlock(&dnvars);
6707dd7cddfSDavid du Colombier 
6717dd7cddfSDavid du Colombier 	return rv;
6727dd7cddfSDavid du Colombier }
6737dd7cddfSDavid du Colombier void
674b4b9fc2fSDavid du Colombier putactivity(int recursive)
6757dd7cddfSDavid du Colombier {
6767dd7cddfSDavid du Colombier 	static ulong lastclean;
6777dd7cddfSDavid du Colombier 
6784f8f669cSDavid du Colombier 	if(traceactivity)
6794f8f669cSDavid du Colombier 		dnslog("put: %d active by pid %d",
6804f8f669cSDavid du Colombier 			dnvars.active, getpid());
6817dd7cddfSDavid du Colombier 	lock(&dnvars);
6827dd7cddfSDavid du Colombier 	dnvars.active--;
6834f8f669cSDavid du Colombier 	assert(dnvars.active >= 0); /* "dnvars.active %d", dnvars.active */
6847dd7cddfSDavid du Colombier 
6857dd7cddfSDavid du Colombier 	/*
6867dd7cddfSDavid du Colombier 	 *  clean out old entries and check for new db periodicly
687b4b9fc2fSDavid du Colombier 	 *  can't block here if being called to let go a "recursive" lock
688b4b9fc2fSDavid du Colombier 	 *  or we'll deadlock waiting for ourselves to give up the dnvars.active.
6897dd7cddfSDavid du Colombier 	 */
6904f8f669cSDavid du Colombier 	if (recursive || dnvars.mutex ||
6914f8f669cSDavid du Colombier 	    (needrefresh == 0 && dnvars.active > 0)){
6927dd7cddfSDavid du Colombier 		unlock(&dnvars);
6937dd7cddfSDavid du Colombier 		return;
6947dd7cddfSDavid du Colombier 	}
6957dd7cddfSDavid du Colombier 
6967dd7cddfSDavid du Colombier 	/* wait till we're alone */
6977dd7cddfSDavid du Colombier 	dnvars.mutex = 1;
6987dd7cddfSDavid du Colombier 	while(dnvars.active > 0){
6997dd7cddfSDavid du Colombier 		unlock(&dnvars);
700d6d99297SDavid du Colombier 		sleep(100);		/* tune; was 100 */
7017dd7cddfSDavid du Colombier 		lock(&dnvars);
7027dd7cddfSDavid du Colombier 	}
7037dd7cddfSDavid du Colombier 	unlock(&dnvars);
7047dd7cddfSDavid du Colombier 
7057dd7cddfSDavid du Colombier 	db2cache(needrefresh);
7067dd7cddfSDavid du Colombier 	dnageall(0);
7077dd7cddfSDavid du Colombier 
7087dd7cddfSDavid du Colombier 	/* let others back in */
7097dd7cddfSDavid du Colombier 	lastclean = now;
7107dd7cddfSDavid du Colombier 	needrefresh = 0;
7117dd7cddfSDavid du Colombier 	dnvars.mutex = 0;
7127dd7cddfSDavid du Colombier }
7137dd7cddfSDavid du Colombier 
714d2fd7a44SDavid du Colombier int
715d2fd7a44SDavid du Colombier rrlistlen(RR *rp)
716d2fd7a44SDavid du Colombier {
717d2fd7a44SDavid du Colombier 	int n;
718d2fd7a44SDavid du Colombier 
719d2fd7a44SDavid du Colombier 	n = 0;
720d2fd7a44SDavid du Colombier 	for(; rp; rp = rp->next)
721d2fd7a44SDavid du Colombier 		++n;
722d2fd7a44SDavid du Colombier 	return n;
723d2fd7a44SDavid du Colombier }
724d2fd7a44SDavid du Colombier 
7253e12c5d1SDavid du Colombier /*
7266dc4800dSDavid du Colombier  *  Attach a single resource record to a domain name (new->owner).
7273e12c5d1SDavid du Colombier  *	- Avoid duplicates with already present RR's
7283e12c5d1SDavid du Colombier  *	- Chain all RR's of the same type adjacent to one another
7293e12c5d1SDavid du Colombier  *	- chain authoritative RR's ahead of non-authoritative ones
7306dc4800dSDavid du Colombier  *	- remove any expired RR's
731225077b0SDavid du Colombier  *  If new is a stale duplicate, rrfree it.
7326dc4800dSDavid du Colombier  *  Must be called with dnlock held.
7333e12c5d1SDavid du Colombier  */
7343e12c5d1SDavid du Colombier static void
7353e12c5d1SDavid du Colombier rrattach1(RR *new, int auth)
7363e12c5d1SDavid du Colombier {
7373e12c5d1SDavid du Colombier 	RR **l;
7383e12c5d1SDavid du Colombier 	RR *rp;
7393e12c5d1SDavid du Colombier 	DN *dp;
7403e12c5d1SDavid du Colombier 
7417dd7cddfSDavid du Colombier 	assert(new->magic == RRmagic && !new->cached);
7427dd7cddfSDavid du Colombier 
7434f8f669cSDavid du Colombier //	dnslog("rrattach1: %s", new->owner->name);
744e9b54818SDavid du Colombier 	if(!new->db) {
745e9b54818SDavid du Colombier 		/*
746e9b54818SDavid du Colombier 		 * try not to let responses expire before we
747e9b54818SDavid du Colombier 		 * can use them to complete this query, by extending
748e464c1a8SDavid du Colombier 		 * past (or nearly past) expiration time.
749e9b54818SDavid du Colombier 		 */
750e464c1a8SDavid du Colombier 		new->expire = new->ttl > now + Min? new->ttl: now + 10*Min;
751e9b54818SDavid du Colombier 	} else
7527dd7cddfSDavid du Colombier 		new->expire = now + Year;
7533e12c5d1SDavid du Colombier 	dp = new->owner;
7547dd7cddfSDavid du Colombier 	assert(dp->magic == DNmagic);
7557dd7cddfSDavid du Colombier 	new->auth |= auth;
7563e12c5d1SDavid du Colombier 	new->next = 0;
7573e12c5d1SDavid du Colombier 
7583e12c5d1SDavid du Colombier 	/*
7593ff48bf5SDavid du Colombier 	 *  find first rr of the right type
7603e12c5d1SDavid du Colombier 	 */
7613e12c5d1SDavid du Colombier 	l = &dp->rr;
7627dd7cddfSDavid du Colombier 	for(rp = *l; rp; rp = *l){
7637dd7cddfSDavid du Colombier 		assert(rp->magic == RRmagic && rp->cached);
7643e12c5d1SDavid du Colombier 		if(rp->type == new->type)
7653e12c5d1SDavid du Colombier 			break;
7663e12c5d1SDavid du Colombier 		l = &rp->next;
7673e12c5d1SDavid du Colombier 	}
7683e12c5d1SDavid du Colombier 
7693e12c5d1SDavid du Colombier 	/*
7707dd7cddfSDavid du Colombier 	 *  negative entries replace positive entries
7717dd7cddfSDavid du Colombier 	 *  positive entries replace negative entries
7727dd7cddfSDavid du Colombier 	 *  newer entries replace older entries with the same fields
773225077b0SDavid du Colombier 	 *
774225077b0SDavid du Colombier 	 *  look farther ahead than just the next entry when looking
775225077b0SDavid du Colombier 	 *  for duplicates; RRs of a given type can have different rdata
776225077b0SDavid du Colombier 	 *  fields (e.g. multiple NS servers).
7773e12c5d1SDavid du Colombier 	 */
778225077b0SDavid du Colombier 	while ((rp = *l) != nil){
7797dd7cddfSDavid du Colombier 		assert(rp->magic == RRmagic && rp->cached);
7807dd7cddfSDavid du Colombier 		if(rp->type != new->type)
7813e12c5d1SDavid du Colombier 			break;
7827dd7cddfSDavid du Colombier 
7837dd7cddfSDavid du Colombier 		if(rp->db == new->db && rp->auth == new->auth){
7847dd7cddfSDavid du Colombier 			/* negative drives out positive and vice versa */
7857dd7cddfSDavid du Colombier 			if(rp->negative != new->negative) {
786225077b0SDavid du Colombier 				rrdelete(l, rp);
787225077b0SDavid du Colombier 				continue;		/* *l == rp->next */
7883e12c5d1SDavid du Colombier 			}
7897dd7cddfSDavid du Colombier 			/* all things equal, pick the newer one */
790225077b0SDavid du Colombier 			else if(rp->arg0 == new->arg0 && rp->arg1 == new->arg1){
7917dd7cddfSDavid du Colombier 				/* new drives out old */
792225077b0SDavid du Colombier 				if (new->ttl <= rp->ttl &&
793225077b0SDavid du Colombier 				    new->expire <= rp->expire) {
7943e12c5d1SDavid du Colombier 					rrfree(new);
7953e12c5d1SDavid du Colombier 					return;
7963e12c5d1SDavid du Colombier 				}
797225077b0SDavid du Colombier 				rrdelete(l, rp);
798225077b0SDavid du Colombier 				continue;		/* *l == rp->next */
7997dd7cddfSDavid du Colombier 			}
800225077b0SDavid du Colombier 			/*
801225077b0SDavid du Colombier 			 *  Hack for pointer records.  This makes sure
8023ff48bf5SDavid du Colombier 			 *  the ordering in the list reflects the ordering
8033ff48bf5SDavid du Colombier 			 *  received or read from the database
8043ff48bf5SDavid du Colombier 			 */
805225077b0SDavid du Colombier 			else if(rp->type == Tptr &&
806225077b0SDavid du Colombier 			    !rp->negative && !new->negative &&
807225077b0SDavid du Colombier 			    rp->ptr->ordinal > new->ptr->ordinal)
8083ff48bf5SDavid du Colombier 				break;
8093ff48bf5SDavid du Colombier 		}
8103e12c5d1SDavid du Colombier 		l = &rp->next;
8113e12c5d1SDavid du Colombier 	}
8123e12c5d1SDavid du Colombier 
813530fef66SDavid du Colombier 	if (rronlist(new, rp)) {
8144f927735SDavid du Colombier 		/* should not happen; duplicates were processed above */
815530fef66SDavid du Colombier 		dnslog("adding duplicate %R to list of %R; aborting", new, rp);
8164f927735SDavid du Colombier 		abort();
8174f927735SDavid du Colombier 	}
8183e12c5d1SDavid du Colombier 	/*
8193e12c5d1SDavid du Colombier 	 *  add to chain
8203e12c5d1SDavid du Colombier 	 */
8217dd7cddfSDavid du Colombier 	new->cached = 1;
822530fef66SDavid du Colombier 	new->next = rp;
8233e12c5d1SDavid du Colombier 	*l = new;
8243e12c5d1SDavid du Colombier }
8253e12c5d1SDavid du Colombier 
8263e12c5d1SDavid du Colombier /*
8273e12c5d1SDavid du Colombier  *  Attach a list of resource records to a domain name.
828225077b0SDavid du Colombier  *  May rrfree any stale duplicate RRs; dismembers the list.
829225077b0SDavid du Colombier  *  Upon return, every RR in the list will have been rrfree-d
830225077b0SDavid du Colombier  *  or attached to its domain name.
8316dc4800dSDavid du Colombier  *  See rrattach1 for properties preserved.
8323e12c5d1SDavid du Colombier  */
8333e12c5d1SDavid du Colombier void
8343e12c5d1SDavid du Colombier rrattach(RR *rp, int auth)
8353e12c5d1SDavid du Colombier {
8363e12c5d1SDavid du Colombier 	RR *next;
837d2fd7a44SDavid du Colombier 	DN *dp;
8383e12c5d1SDavid du Colombier 
839bd389b36SDavid du Colombier 	lock(&dnlock);
8403e12c5d1SDavid du Colombier 	for(; rp; rp = next){
8413e12c5d1SDavid du Colombier 		next = rp->next;
8424f8f669cSDavid du Colombier 		rp->next = nil;
843d2fd7a44SDavid du Colombier 		dp = rp->owner;
8447dd7cddfSDavid du Colombier 
8457dd7cddfSDavid du Colombier 		/* avoid any outside spoofing */
8464f8f669cSDavid du Colombier //		dnslog("rrattach: %s", rp->owner->name);
8474f8f669cSDavid du Colombier 		if(cfg.cachedb && !rp->db && inmyarea(rp->owner->name))
8487dd7cddfSDavid du Colombier 			rrfree(rp);
849d2fd7a44SDavid du Colombier 		else {
850530fef66SDavid du Colombier 			/* ameliorate the memory leak */
851530fef66SDavid du Colombier 			if (0 && rrlistlen(dp->rr) > 50 && !dp->keep) {
852530fef66SDavid du Colombier 				dnslog("rrattach(%s): rr list too long; "
853530fef66SDavid du Colombier 					"freeing it", dp->name);
854530fef66SDavid du Colombier 				rrfreelist(dp->rr);
855530fef66SDavid du Colombier 				dp->rr = nil;
856530fef66SDavid du Colombier 			} else
857530fef66SDavid du Colombier 				USED(dp);
8583e12c5d1SDavid du Colombier 			rrattach1(rp, auth);
859d2fd7a44SDavid du Colombier 		}
8603e12c5d1SDavid du Colombier 	}
861bd389b36SDavid du Colombier 	unlock(&dnlock);
8623e12c5d1SDavid du Colombier }
8633e12c5d1SDavid du Colombier 
864530fef66SDavid du Colombier /* should be called with dnlock held */
8654f8f669cSDavid du Colombier RR**
8667dd7cddfSDavid du Colombier rrcopy(RR *rp, RR **last)
8677dd7cddfSDavid du Colombier {
8684f8f669cSDavid du Colombier 	Cert *cert;
8694f8f669cSDavid du Colombier 	Key *key;
8704f8f669cSDavid du Colombier 	Null *null;
8717dd7cddfSDavid du Colombier 	RR *nrp;
8727dd7cddfSDavid du Colombier 	SOA *soa;
8739a747e4fSDavid du Colombier 	Sig *sig;
87460845620SDavid du Colombier 	Txt *t, *nt, **l;
8757dd7cddfSDavid du Colombier 
8767dd7cddfSDavid du Colombier 	nrp = rralloc(rp->type);
877a41547ffSDavid du Colombier 	setmalloctag(nrp, getcallerpc(&rp));
8789a747e4fSDavid du Colombier 	switch(rp->type){
87960845620SDavid du Colombier 	case Ttxt:
88060845620SDavid du Colombier 		*nrp = *rp;
88160845620SDavid du Colombier 		l = &nrp->txt;
88260845620SDavid du Colombier 		*l = nil;
88360845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next){
88460845620SDavid du Colombier 			nt = emalloc(sizeof(*nt));
88560845620SDavid du Colombier 			nt->p = estrdup(t->p);
88660845620SDavid du Colombier 			nt->next = nil;
88760845620SDavid du Colombier 			*l = nt;
88860845620SDavid du Colombier 			l = &nt->next;
88960845620SDavid du Colombier 		}
89060845620SDavid du Colombier 		break;
8919a747e4fSDavid du Colombier 	case Tsoa:
8927dd7cddfSDavid du Colombier 		soa = nrp->soa;
8937dd7cddfSDavid du Colombier 		*nrp = *rp;
8947dd7cddfSDavid du Colombier 		nrp->soa = soa;
8957dd7cddfSDavid du Colombier 		*nrp->soa = *rp->soa;
896dc5a79c1SDavid du Colombier 		nrp->soa->slaves = copyserverlist(rp->soa->slaves);
8979a747e4fSDavid du Colombier 		break;
8984f8f669cSDavid du Colombier 	case Tsrv:
8994f8f669cSDavid du Colombier 		*nrp = *rp;
900fd87a217SDavid du Colombier 		nrp->srv = emalloc(sizeof *nrp->srv);
9014f8f669cSDavid du Colombier 		*nrp->srv = *rp->srv;
9024f8f669cSDavid du Colombier 		break;
9039a747e4fSDavid du Colombier 	case Tkey:
9049a747e4fSDavid du Colombier 		key = nrp->key;
9059a747e4fSDavid du Colombier 		*nrp = *rp;
9069a747e4fSDavid du Colombier 		nrp->key = key;
9079a747e4fSDavid du Colombier 		*key = *rp->key;
9089a747e4fSDavid du Colombier 		key->data = emalloc(key->dlen);
9099a747e4fSDavid du Colombier 		memmove(key->data, rp->key->data, rp->key->dlen);
9109a747e4fSDavid du Colombier 		break;
9119a747e4fSDavid du Colombier 	case Tsig:
9129a747e4fSDavid du Colombier 		sig = nrp->sig;
9139a747e4fSDavid du Colombier 		*nrp = *rp;
9149a747e4fSDavid du Colombier 		nrp->sig = sig;
9159a747e4fSDavid du Colombier 		*sig = *rp->sig;
9169a747e4fSDavid du Colombier 		sig->data = emalloc(sig->dlen);
9179a747e4fSDavid du Colombier 		memmove(sig->data, rp->sig->data, rp->sig->dlen);
9189a747e4fSDavid du Colombier 		break;
9199a747e4fSDavid du Colombier 	case Tcert:
9209a747e4fSDavid du Colombier 		cert = nrp->cert;
9219a747e4fSDavid du Colombier 		*nrp = *rp;
9229a747e4fSDavid du Colombier 		nrp->cert = cert;
9239a747e4fSDavid du Colombier 		*cert = *rp->cert;
9249a747e4fSDavid du Colombier 		cert->data = emalloc(cert->dlen);
9259a747e4fSDavid du Colombier 		memmove(cert->data, rp->cert->data, rp->cert->dlen);
9269a747e4fSDavid du Colombier 		break;
9279a747e4fSDavid du Colombier 	case Tnull:
9289a747e4fSDavid du Colombier 		null = nrp->null;
9299a747e4fSDavid du Colombier 		*nrp = *rp;
9309a747e4fSDavid du Colombier 		nrp->null = null;
9319a747e4fSDavid du Colombier 		*null = *rp->null;
9329a747e4fSDavid du Colombier 		null->data = emalloc(null->dlen);
9339a747e4fSDavid du Colombier 		memmove(null->data, rp->null->data, rp->null->dlen);
9349a747e4fSDavid du Colombier 		break;
9359a747e4fSDavid du Colombier 	default:
9369a747e4fSDavid du Colombier 		*nrp = *rp;
9379a747e4fSDavid du Colombier 		break;
9387dd7cddfSDavid du Colombier 	}
9397dd7cddfSDavid du Colombier 	nrp->cached = 0;
9407dd7cddfSDavid du Colombier 	nrp->next = 0;
9417dd7cddfSDavid du Colombier 	*last = nrp;
9427dd7cddfSDavid du Colombier 	return &nrp->next;
9437dd7cddfSDavid du Colombier }
9447dd7cddfSDavid du Colombier 
9453e12c5d1SDavid du Colombier /*
9463e12c5d1SDavid du Colombier  *  lookup a resource record of a particular type and
9477dd7cddfSDavid du Colombier  *  class attached to a domain name.  Return copies.
9487dd7cddfSDavid du Colombier  *
9497dd7cddfSDavid du Colombier  *  Priority ordering is:
9507dd7cddfSDavid du Colombier  *	db authoritative
9517dd7cddfSDavid du Colombier  *	not timed out network authoritative
9527dd7cddfSDavid du Colombier  *	not timed out network unauthoritative
9537dd7cddfSDavid du Colombier  *	unauthoritative db
9547dd7cddfSDavid du Colombier  *
95580ee5cbfSDavid du Colombier  *  if flag NOneg is set, don't return negative cached entries.
9567dd7cddfSDavid du Colombier  *  return nothing instead.
9573e12c5d1SDavid du Colombier  */
9583e12c5d1SDavid du Colombier RR*
9597dd7cddfSDavid du Colombier rrlookup(DN *dp, int type, int flag)
9603e12c5d1SDavid du Colombier {
9617dd7cddfSDavid du Colombier 	RR *rp, *first, **last;
9623e12c5d1SDavid du Colombier 
9637dd7cddfSDavid du Colombier 	assert(dp->magic == DNmagic);
9647dd7cddfSDavid du Colombier 
9657dd7cddfSDavid du Colombier 	first = 0;
9667dd7cddfSDavid du Colombier 	last = &first;
9677dd7cddfSDavid du Colombier 	lock(&dnlock);
9687dd7cddfSDavid du Colombier 
9697dd7cddfSDavid du Colombier 	/* try for an authoritative db entry */
9703e12c5d1SDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
9717dd7cddfSDavid du Colombier 		assert(rp->magic == RRmagic && rp->cached);
9727dd7cddfSDavid du Colombier 		if(rp->db)
9737dd7cddfSDavid du Colombier 		if(rp->auth)
974a41547ffSDavid du Colombier 		if(tsame(type, rp->type)) {
9754e5f5f32SDavid du Colombier 			last = rrcopy(rp, last);
976a41547ffSDavid du Colombier 			// setmalloctag(*last, getcallerpc(&dp));
977a41547ffSDavid du Colombier 		}
9783e12c5d1SDavid du Colombier 	}
9797dd7cddfSDavid du Colombier 	if(first)
9807dd7cddfSDavid du Colombier 		goto out;
9817dd7cddfSDavid du Colombier 
9824f8f669cSDavid du Colombier 	/* try for a living authoritative network entry */
9837dd7cddfSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
9847dd7cddfSDavid du Colombier 		if(!rp->db)
9857dd7cddfSDavid du Colombier 		if(rp->auth)
9867dd7cddfSDavid du Colombier 		if(rp->ttl + 60 > now)
9877dd7cddfSDavid du Colombier 		if(tsame(type, rp->type)){
9887dd7cddfSDavid du Colombier 			if(flag == NOneg && rp->negative)
9897dd7cddfSDavid du Colombier 				goto out;
9907dd7cddfSDavid du Colombier 			last = rrcopy(rp, last);
9917dd7cddfSDavid du Colombier 		}
9927dd7cddfSDavid du Colombier 	}
9937dd7cddfSDavid du Colombier 	if(first)
9947dd7cddfSDavid du Colombier 		goto out;
9957dd7cddfSDavid du Colombier 
9964f8f669cSDavid du Colombier 	/* try for a living unauthoritative network entry */
9977dd7cddfSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
9987dd7cddfSDavid du Colombier 		if(!rp->db)
9997dd7cddfSDavid du Colombier 		if(rp->ttl + 60 > now)
10007dd7cddfSDavid du Colombier 		if(tsame(type, rp->type)){
10017dd7cddfSDavid du Colombier 			if(flag == NOneg && rp->negative)
10027dd7cddfSDavid du Colombier 				goto out;
10034e5f5f32SDavid du Colombier 			last = rrcopy(rp, last);
10047dd7cddfSDavid du Colombier 		}
10057dd7cddfSDavid du Colombier 	}
10067dd7cddfSDavid du Colombier 	if(first)
10077dd7cddfSDavid du Colombier 		goto out;
10087dd7cddfSDavid du Colombier 
10097dd7cddfSDavid du Colombier 	/* try for an unauthoritative db entry */
10107dd7cddfSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
10117dd7cddfSDavid du Colombier 		if(rp->db)
10127dd7cddfSDavid du Colombier 		if(tsame(type, rp->type))
10137dd7cddfSDavid du Colombier 			last = rrcopy(rp, last);
10147dd7cddfSDavid du Colombier 	}
10157dd7cddfSDavid du Colombier 	if(first)
10167dd7cddfSDavid du Colombier 		goto out;
10177dd7cddfSDavid du Colombier 
10187dd7cddfSDavid du Colombier 	/* otherwise, settle for anything we got (except for negative caches) */
10194f8f669cSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next)
10207dd7cddfSDavid du Colombier 		if(tsame(type, rp->type)){
10217dd7cddfSDavid du Colombier 			if(rp->negative)
10227dd7cddfSDavid du Colombier 				goto out;
10237dd7cddfSDavid du Colombier 			last = rrcopy(rp, last);
10247dd7cddfSDavid du Colombier 		}
10257dd7cddfSDavid du Colombier 
10267dd7cddfSDavid du Colombier out:
10277dd7cddfSDavid du Colombier 	unlock(&dnlock);
10287dd7cddfSDavid du Colombier 	unique(first);
10294f8f669cSDavid du Colombier //	dnslog("rrlookup(%s) -> %#p\t# in-core only", dp->name, first);
1030a41547ffSDavid du Colombier //	if (first)
1031a41547ffSDavid du Colombier //		setmalloctag(first, getcallerpc(&dp));
10327dd7cddfSDavid du Colombier 	return first;
10333e12c5d1SDavid du Colombier }
10343e12c5d1SDavid du Colombier 
10353e12c5d1SDavid du Colombier /*
10363e12c5d1SDavid du Colombier  *  convert an ascii RR type name to its integer representation
10373e12c5d1SDavid du Colombier  */
10383e12c5d1SDavid du Colombier int
10393e12c5d1SDavid du Colombier rrtype(char *atype)
10403e12c5d1SDavid du Colombier {
10413e12c5d1SDavid du Colombier 	int i;
10423e12c5d1SDavid du Colombier 
1043219b2ee8SDavid du Colombier 	for(i = 0; i <= Tall; i++)
10443e12c5d1SDavid du Colombier 		if(rrtname[i] && strcmp(rrtname[i], atype) == 0)
10453e12c5d1SDavid du Colombier 			return i;
10467dd7cddfSDavid du Colombier 
10474f8f669cSDavid du Colombier 	/* make any a synonym for all */
10487dd7cddfSDavid du Colombier 	if(strcmp(atype, "any") == 0)
10497dd7cddfSDavid du Colombier 		return Tall;
1050*d9924332SDavid du Colombier 	else if(isascii(atype[0]) && isdigit(atype[0]))
10513e12c5d1SDavid du Colombier 		return atoi(atype);
1052*d9924332SDavid du Colombier 	else
1053*d9924332SDavid du Colombier 		return -1;
10543e12c5d1SDavid du Colombier }
10553e12c5d1SDavid du Colombier 
10563e12c5d1SDavid du Colombier /*
10575d459b5aSDavid du Colombier  *  return 0 if not a supported rr type
10585d459b5aSDavid du Colombier  */
10595d459b5aSDavid du Colombier int
10605d459b5aSDavid du Colombier rrsupported(int type)
10615d459b5aSDavid du Colombier {
10625d459b5aSDavid du Colombier 	if(type < 0 || type >Tall)
10635d459b5aSDavid du Colombier 		return 0;
10644f8f669cSDavid du Colombier 	return rrtname[type] != nil;
10655d459b5aSDavid du Colombier }
10665d459b5aSDavid du Colombier 
10675d459b5aSDavid du Colombier /*
1068219b2ee8SDavid du Colombier  *  compare 2 types
1069219b2ee8SDavid du Colombier  */
1070219b2ee8SDavid du Colombier int
1071219b2ee8SDavid du Colombier tsame(int t1, int t2)
1072219b2ee8SDavid du Colombier {
1073219b2ee8SDavid du Colombier 	return t1 == t2 || t1 == Tall;
1074219b2ee8SDavid du Colombier }
1075219b2ee8SDavid du Colombier 
1076219b2ee8SDavid du Colombier /*
10777dd7cddfSDavid du Colombier  *  Add resource records to a list, duplicate them if they are cached
1078530fef66SDavid du Colombier  *  RR's since these are shared.  should be called with dnlock held
1079530fef66SDavid du Colombier  *  to avoid racing down the start chain.
10803e12c5d1SDavid du Colombier  */
10813e12c5d1SDavid du Colombier RR*
10827dd7cddfSDavid du Colombier rrcat(RR **start, RR *rp)
10833e12c5d1SDavid du Colombier {
1084225077b0SDavid du Colombier 	RR *olp, *nlp;
10853e12c5d1SDavid du Colombier 	RR **last;
10863e12c5d1SDavid du Colombier 
1087225077b0SDavid du Colombier 	/* check for duplicates */
1088225077b0SDavid du Colombier 	for (olp = *start; 0 && olp; olp = olp->next)
1089225077b0SDavid du Colombier 		for (nlp = rp; nlp; nlp = nlp->next)
1090225077b0SDavid du Colombier 			if (rrsame(nlp, olp))
1091225077b0SDavid du Colombier 				dnslog("rrcat: duplicate RR: %R", nlp);
1092225077b0SDavid du Colombier 	USED(olp);
1093225077b0SDavid du Colombier 
10943e12c5d1SDavid du Colombier 	last = start;
10954f8f669cSDavid du Colombier 	while(*last != nil)
10963e12c5d1SDavid du Colombier 		last = &(*last)->next;
10973e12c5d1SDavid du Colombier 
10987dd7cddfSDavid du Colombier 	*last = rp;
10997dd7cddfSDavid du Colombier 	return *start;
11003e12c5d1SDavid du Colombier }
11013e12c5d1SDavid du Colombier 
11027dd7cddfSDavid du Colombier /*
11037dd7cddfSDavid du Colombier  *  remove negative cache rr's from an rr list
11047dd7cddfSDavid du Colombier  */
11057dd7cddfSDavid du Colombier RR*
11067dd7cddfSDavid du Colombier rrremneg(RR **l)
11077dd7cddfSDavid du Colombier {
11087dd7cddfSDavid du Colombier 	RR **nl, *rp;
11097dd7cddfSDavid du Colombier 	RR *first;
11107dd7cddfSDavid du Colombier 
11117dd7cddfSDavid du Colombier 	first = nil;
11127dd7cddfSDavid du Colombier 	nl = &first;
11137dd7cddfSDavid du Colombier 	while(*l != nil){
11147dd7cddfSDavid du Colombier 		rp = *l;
11157dd7cddfSDavid du Colombier 		if(rp->negative){
11167dd7cddfSDavid du Colombier 			*l = rp->next;
11177dd7cddfSDavid du Colombier 			*nl = rp;
11187dd7cddfSDavid du Colombier 			nl = &rp->next;
11197dd7cddfSDavid du Colombier 			*nl = nil;
11207dd7cddfSDavid du Colombier 		} else
112180ee5cbfSDavid du Colombier 			l = &rp->next;
11227dd7cddfSDavid du Colombier 	}
11237dd7cddfSDavid du Colombier 
11247dd7cddfSDavid du Colombier 	return first;
11257dd7cddfSDavid du Colombier }
11267dd7cddfSDavid du Colombier 
11277dd7cddfSDavid du Colombier /*
11287dd7cddfSDavid du Colombier  *  remove rr's of a particular type from an rr list
11297dd7cddfSDavid du Colombier  */
11307dd7cddfSDavid du Colombier RR*
11317dd7cddfSDavid du Colombier rrremtype(RR **l, int type)
11327dd7cddfSDavid du Colombier {
11334f8f669cSDavid du Colombier 	RR *first, *rp;
11344f8f669cSDavid du Colombier 	RR **nl;
11357dd7cddfSDavid du Colombier 
11367dd7cddfSDavid du Colombier 	first = nil;
11377dd7cddfSDavid du Colombier 	nl = &first;
11387dd7cddfSDavid du Colombier 	while(*l != nil){
11397dd7cddfSDavid du Colombier 		rp = *l;
11407dd7cddfSDavid du Colombier 		if(rp->type == type){
11417dd7cddfSDavid du Colombier 			*l = rp->next;
11427dd7cddfSDavid du Colombier 			*nl = rp;
11437dd7cddfSDavid du Colombier 			nl = &rp->next;
11447dd7cddfSDavid du Colombier 			*nl = nil;
11457dd7cddfSDavid du Colombier 		} else
11467dd7cddfSDavid du Colombier 			l = &(*l)->next;
11477dd7cddfSDavid du Colombier 	}
11487dd7cddfSDavid du Colombier 
11497dd7cddfSDavid du Colombier 	return first;
11503e12c5d1SDavid du Colombier }
11513e12c5d1SDavid du Colombier 
11524f8f669cSDavid du Colombier static char *
11534f8f669cSDavid du Colombier dnname(DN *dn)
11544f8f669cSDavid du Colombier {
11554f8f669cSDavid du Colombier 	return dn? dn->name: "<null>";
11564f8f669cSDavid du Colombier }
11574f8f669cSDavid du Colombier 
11583e12c5d1SDavid du Colombier /*
11593e12c5d1SDavid du Colombier  *  print conversion for rr records
11603e12c5d1SDavid du Colombier  */
11613e12c5d1SDavid du Colombier int
11629a747e4fSDavid du Colombier rrfmt(Fmt *f)
11633e12c5d1SDavid du Colombier {
11646b0d5c8bSDavid du Colombier 	int rv;
11654f8f669cSDavid du Colombier 	char *strp;
11666b0d5c8bSDavid du Colombier 	char buf[Domlen];
11674f8f669cSDavid du Colombier 	Fmt fstr;
11684f8f669cSDavid du Colombier 	RR *rp;
1169dc5a79c1SDavid du Colombier 	Server *s;
11704f8f669cSDavid du Colombier 	SOA *soa;
11714f8f669cSDavid du Colombier 	Srv *srv;
117260845620SDavid du Colombier 	Txt *t;
11733e12c5d1SDavid du Colombier 
11749a747e4fSDavid du Colombier 	fmtstrinit(&fstr);
11759a747e4fSDavid du Colombier 
11769a747e4fSDavid du Colombier 	rp = va_arg(f->args, RR*);
11774f8f669cSDavid du Colombier 	if(rp == nil){
11789a747e4fSDavid du Colombier 		fmtprint(&fstr, "<null>");
1179219b2ee8SDavid du Colombier 		goto out;
1180219b2ee8SDavid du Colombier 	}
1181219b2ee8SDavid du Colombier 
11824f8f669cSDavid du Colombier 	fmtprint(&fstr, "%s %s", dnname(rp->owner),
11839a747e4fSDavid du Colombier 		rrname(rp->type, buf, sizeof buf));
11847dd7cddfSDavid du Colombier 
11857dd7cddfSDavid du Colombier 	if(rp->negative){
11869a747e4fSDavid du Colombier 		fmtprint(&fstr, "\tnegative - rcode %d", rp->negrcode);
11877dd7cddfSDavid du Colombier 		goto out;
11887dd7cddfSDavid du Colombier 	}
11893e12c5d1SDavid du Colombier 
11903e12c5d1SDavid du Colombier 	switch(rp->type){
11913e12c5d1SDavid du Colombier 	case Thinfo:
11924f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s", dnname(rp->cpu), dnname(rp->os));
11933e12c5d1SDavid du Colombier 		break;
11943e12c5d1SDavid du Colombier 	case Tcname:
11953e12c5d1SDavid du Colombier 	case Tmb:
11963e12c5d1SDavid du Colombier 	case Tmd:
11973e12c5d1SDavid du Colombier 	case Tmf:
11983e12c5d1SDavid du Colombier 	case Tns:
11994f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->host));
12003e12c5d1SDavid du Colombier 		break;
12013e12c5d1SDavid du Colombier 	case Tmg:
12023e12c5d1SDavid du Colombier 	case Tmr:
12034f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->mb));
12043e12c5d1SDavid du Colombier 		break;
12053e12c5d1SDavid du Colombier 	case Tminfo:
12064f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s", dnname(rp->mb), dnname(rp->rmb));
12073e12c5d1SDavid du Colombier 		break;
12083e12c5d1SDavid du Colombier 	case Tmx:
12094f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%lud %s", rp->pref, dnname(rp->host));
12103e12c5d1SDavid du Colombier 		break;
12113e12c5d1SDavid du Colombier 	case Ta:
12125d459b5aSDavid du Colombier 	case Taaaa:
12134f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->ip));
12143e12c5d1SDavid du Colombier 		break;
12153e12c5d1SDavid du Colombier 	case Tptr:
12164f8f669cSDavid du Colombier //		fmtprint(&fstr, "\t%s(%lud)", dnname(rp->ptr),
12174f8f669cSDavid du Colombier //			rp->ptr? rp->ptr->ordinal: "<null>");
12184f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->ptr));
12193e12c5d1SDavid du Colombier 		break;
12203e12c5d1SDavid du Colombier 	case Tsoa:
12214f8f669cSDavid du Colombier 		soa = rp->soa;
12224f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s %lud %lud %lud %lud %lud",
12234f8f669cSDavid du Colombier 			dnname(rp->host), dnname(rp->rmb),
12244f8f669cSDavid du Colombier 			(soa? soa->serial: 0),
12254f8f669cSDavid du Colombier 			(soa? soa->refresh: 0), (soa? soa->retry: 0),
12264f8f669cSDavid du Colombier 			(soa? soa->expire: 0), (soa? soa->minttl: 0));
12274f8f669cSDavid du Colombier 		if (soa)
12284f8f669cSDavid du Colombier 			for(s = soa->slaves; s != nil; s = s->next)
1229dc5a79c1SDavid du Colombier 				fmtprint(&fstr, " %s", s->name);
12303e12c5d1SDavid du Colombier 		break;
12314f8f669cSDavid du Colombier 	case Tsrv:
12324f8f669cSDavid du Colombier 		srv = rp->srv;
12334f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%ud %ud %ud %s",
12344f8f669cSDavid du Colombier 			(srv? srv->pri: 0), (srv? srv->weight: 0),
1235225077b0SDavid du Colombier 			rp->port, dnname(rp->host));
12364f8f669cSDavid du Colombier 		break;
12379a747e4fSDavid du Colombier 	case Tnull:
12384f8f669cSDavid du Colombier 		if (rp->null == nil)
12394f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t<null>");
12404f8f669cSDavid du Colombier 		else
12414f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t%.*H", rp->null->dlen,
12424f8f669cSDavid du Colombier 				rp->null->data);
12439a747e4fSDavid du Colombier 		break;
12447dd7cddfSDavid du Colombier 	case Ttxt:
124560845620SDavid du Colombier 		fmtprint(&fstr, "\t");
124660845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next)
124760845620SDavid du Colombier 			fmtprint(&fstr, "%s", t->p);
12487dd7cddfSDavid du Colombier 		break;
12497dd7cddfSDavid du Colombier 	case Trp:
12504f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s", dnname(rp->rmb), dnname(rp->rp));
12517dd7cddfSDavid du Colombier 		break;
12527dd7cddfSDavid du Colombier 	case Tkey:
12534f8f669cSDavid du Colombier 		if (rp->key == nil)
12544f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t<null> <null> <null>");
12554f8f669cSDavid du Colombier 		else
12564f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t%d %d %d", rp->key->flags,
12574f8f669cSDavid du Colombier 				rp->key->proto, rp->key->alg);
12587dd7cddfSDavid du Colombier 		break;
12597dd7cddfSDavid du Colombier 	case Tsig:
12604f8f669cSDavid du Colombier 		if (rp->sig == nil)
12614f8f669cSDavid du Colombier 			fmtprint(&fstr,
12624f8f669cSDavid du Colombier 		   "\t<null> <null> <null> <null> <null> <null> <null> <null>");
12634f8f669cSDavid du Colombier 		else
12649a747e4fSDavid du Colombier 			fmtprint(&fstr, "\t%d %d %d %lud %lud %lud %d %s",
12654f8f669cSDavid du Colombier 				rp->sig->type, rp->sig->alg, rp->sig->labels,
12664f8f669cSDavid du Colombier 				rp->sig->ttl, rp->sig->exp, rp->sig->incep,
12674f8f669cSDavid du Colombier 				rp->sig->tag, dnname(rp->sig->signer));
12687dd7cddfSDavid du Colombier 		break;
12697dd7cddfSDavid du Colombier 	case Tcert:
12704f8f669cSDavid du Colombier 		if (rp->cert == nil)
12714f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t<null> <null> <null>");
12724f8f669cSDavid du Colombier 		else
12739a747e4fSDavid du Colombier 			fmtprint(&fstr, "\t%d %d %d",
12744f8f669cSDavid du Colombier 				rp->cert->type, rp->cert->tag, rp->cert->alg);
12753e12c5d1SDavid du Colombier 		break;
12763e12c5d1SDavid du Colombier 	}
1277219b2ee8SDavid du Colombier out:
12789a747e4fSDavid du Colombier 	strp = fmtstrflush(&fstr);
12799a747e4fSDavid du Colombier 	rv = fmtstrcpy(f, strp);
12809a747e4fSDavid du Colombier 	free(strp);
12819a747e4fSDavid du Colombier 	return rv;
12823e12c5d1SDavid du Colombier }
12833e12c5d1SDavid du Colombier 
12843e12c5d1SDavid du Colombier /*
12857dd7cddfSDavid du Colombier  *  print conversion for rr records in attribute value form
12867dd7cddfSDavid du Colombier  */
12877dd7cddfSDavid du Colombier int
12889a747e4fSDavid du Colombier rravfmt(Fmt *f)
12897dd7cddfSDavid du Colombier {
12904f8f669cSDavid du Colombier 	int rv, quote;
12919a747e4fSDavid du Colombier 	char *strp;
12929a747e4fSDavid du Colombier 	Fmt fstr;
12934f8f669cSDavid du Colombier 	RR *rp;
1294dc5a79c1SDavid du Colombier 	Server *s;
12954f8f669cSDavid du Colombier 	SOA *soa;
12964f8f669cSDavid du Colombier 	Srv *srv;
129760845620SDavid du Colombier 	Txt *t;
12987dd7cddfSDavid du Colombier 
12999a747e4fSDavid du Colombier 	fmtstrinit(&fstr);
13009a747e4fSDavid du Colombier 
13019a747e4fSDavid du Colombier 	rp = va_arg(f->args, RR*);
13024f8f669cSDavid du Colombier 	if(rp == nil){
13039a747e4fSDavid du Colombier 		fmtprint(&fstr, "<null>");
13047dd7cddfSDavid du Colombier 		goto out;
13057dd7cddfSDavid du Colombier 	}
13067dd7cddfSDavid du Colombier 
13077dd7cddfSDavid du Colombier 	if(rp->type == Tptr)
13084f8f669cSDavid du Colombier 		fmtprint(&fstr, "ptr=%s", dnname(rp->owner));
13097dd7cddfSDavid du Colombier 	else
13104f8f669cSDavid du Colombier 		fmtprint(&fstr, "dom=%s", dnname(rp->owner));
13117dd7cddfSDavid du Colombier 
13127dd7cddfSDavid du Colombier 	switch(rp->type){
13137dd7cddfSDavid du Colombier 	case Thinfo:
13144f8f669cSDavid du Colombier 		fmtprint(&fstr, " cpu=%s os=%s",
13154f8f669cSDavid du Colombier 			dnname(rp->cpu), dnname(rp->os));
13167dd7cddfSDavid du Colombier 		break;
13177dd7cddfSDavid du Colombier 	case Tcname:
13184f8f669cSDavid du Colombier 		fmtprint(&fstr, " cname=%s", dnname(rp->host));
13197dd7cddfSDavid du Colombier 		break;
13207dd7cddfSDavid du Colombier 	case Tmb:
13217dd7cddfSDavid du Colombier 	case Tmd:
13227dd7cddfSDavid du Colombier 	case Tmf:
13234f8f669cSDavid du Colombier 		fmtprint(&fstr, " mbox=%s", dnname(rp->host));
13247dd7cddfSDavid du Colombier 		break;
13257dd7cddfSDavid du Colombier 	case Tns:
13264f8f669cSDavid du Colombier 		fmtprint(&fstr,  " ns=%s", dnname(rp->host));
13277dd7cddfSDavid du Colombier 		break;
13287dd7cddfSDavid du Colombier 	case Tmg:
13297dd7cddfSDavid du Colombier 	case Tmr:
13304f8f669cSDavid du Colombier 		fmtprint(&fstr, " mbox=%s", dnname(rp->mb));
13317dd7cddfSDavid du Colombier 		break;
13327dd7cddfSDavid du Colombier 	case Tminfo:
13334f8f669cSDavid du Colombier 		fmtprint(&fstr, " mbox=%s mbox=%s",
13344f8f669cSDavid du Colombier 			dnname(rp->mb), dnname(rp->rmb));
13357dd7cddfSDavid du Colombier 		break;
13367dd7cddfSDavid du Colombier 	case Tmx:
13374f8f669cSDavid du Colombier 		fmtprint(&fstr, " pref=%lud mx=%s", rp->pref, dnname(rp->host));
13387dd7cddfSDavid du Colombier 		break;
13397dd7cddfSDavid du Colombier 	case Ta:
13405d459b5aSDavid du Colombier 	case Taaaa:
13414f8f669cSDavid du Colombier 		fmtprint(&fstr, " ip=%s", dnname(rp->ip));
13427dd7cddfSDavid du Colombier 		break;
13437dd7cddfSDavid du Colombier 	case Tptr:
13444f8f669cSDavid du Colombier 		fmtprint(&fstr, " dom=%s", dnname(rp->ptr));
13457dd7cddfSDavid du Colombier 		break;
13467dd7cddfSDavid du Colombier 	case Tsoa:
13474f8f669cSDavid du Colombier 		soa = rp->soa;
13484f8f669cSDavid du Colombier 		fmtprint(&fstr,
13494f8f669cSDavid du Colombier " ns=%s mbox=%s serial=%lud refresh=%lud retry=%lud expire=%lud ttl=%lud",
13504f8f669cSDavid du Colombier 			dnname(rp->host), dnname(rp->rmb),
13514f8f669cSDavid du Colombier 			(soa? soa->serial: 0),
13524f8f669cSDavid du Colombier 			(soa? soa->refresh: 0), (soa? soa->retry: 0),
13534f8f669cSDavid du Colombier 			(soa? soa->expire: 0), (soa? soa->minttl: 0));
13544f8f669cSDavid du Colombier 		for(s = soa->slaves; s != nil; s = s->next)
1355dc5a79c1SDavid du Colombier 			fmtprint(&fstr, " dnsslave=%s", s->name);
13567dd7cddfSDavid du Colombier 		break;
13574f8f669cSDavid du Colombier 	case Tsrv:
13584f8f669cSDavid du Colombier 		srv = rp->srv;
13594f8f669cSDavid du Colombier 		fmtprint(&fstr, " pri=%ud weight=%ud port=%ud target=%s",
13604f8f669cSDavid du Colombier 			(srv? srv->pri: 0), (srv? srv->weight: 0),
1361225077b0SDavid du Colombier 			rp->port, dnname(rp->host));
13624f8f669cSDavid du Colombier 		break;
13639a747e4fSDavid du Colombier 	case Tnull:
13644f8f669cSDavid du Colombier 		if (rp->null == nil)
13654f8f669cSDavid du Colombier 			fmtprint(&fstr, " null=<null>");
13664f8f669cSDavid du Colombier 		else
13674f8f669cSDavid du Colombier 			fmtprint(&fstr, " null=%.*H", rp->null->dlen,
13684f8f669cSDavid du Colombier 				rp->null->data);
13699a747e4fSDavid du Colombier 		break;
13707dd7cddfSDavid du Colombier 	case Ttxt:
137160845620SDavid du Colombier 		fmtprint(&fstr, " txt=");
137260845620SDavid du Colombier 		quote = 0;
137360845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next)
137460845620SDavid du Colombier 			if(strchr(t->p, ' '))
137560845620SDavid du Colombier 				quote = 1;
137660845620SDavid du Colombier 		if(quote)
137760845620SDavid du Colombier 			fmtprint(&fstr, "\"");
137860845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next)
137960845620SDavid du Colombier 			fmtprint(&fstr, "%s", t->p);
138060845620SDavid du Colombier 		if(quote)
138160845620SDavid du Colombier 			fmtprint(&fstr, "\"");
13827dd7cddfSDavid du Colombier 		break;
13837dd7cddfSDavid du Colombier 	case Trp:
13844f8f669cSDavid du Colombier 		fmtprint(&fstr, " rp=%s txt=%s",
13854f8f669cSDavid du Colombier 			dnname(rp->rmb), dnname(rp->rp));
13867dd7cddfSDavid du Colombier 		break;
13877dd7cddfSDavid du Colombier 	case Tkey:
13884f8f669cSDavid du Colombier 		if (rp->key == nil)
13894f8f669cSDavid du Colombier 			fmtprint(&fstr, " flags=<null> proto=<null> alg=<null>");
13904f8f669cSDavid du Colombier 		else
13919a747e4fSDavid du Colombier 			fmtprint(&fstr, " flags=%d proto=%d alg=%d",
13927dd7cddfSDavid du Colombier 				rp->key->flags, rp->key->proto, rp->key->alg);
13937dd7cddfSDavid du Colombier 		break;
13947dd7cddfSDavid du Colombier 	case Tsig:
13954f8f669cSDavid du Colombier 		if (rp->sig == nil)
13964f8f669cSDavid du Colombier 			fmtprint(&fstr,
13974f8f669cSDavid du Colombier " type=<null> alg=<null> labels=<null> ttl=<null> exp=<null> incep=<null> tag=<null> signer=<null>");
13984f8f669cSDavid du Colombier 		else
13994f8f669cSDavid du Colombier 			fmtprint(&fstr,
14004f8f669cSDavid du Colombier " type=%d alg=%d labels=%d ttl=%lud exp=%lud incep=%lud tag=%d signer=%s",
14014f8f669cSDavid du Colombier 				rp->sig->type, rp->sig->alg, rp->sig->labels,
14024f8f669cSDavid du Colombier 				rp->sig->ttl, rp->sig->exp, rp->sig->incep,
14034f8f669cSDavid du Colombier 				rp->sig->tag, dnname(rp->sig->signer));
14047dd7cddfSDavid du Colombier 		break;
14057dd7cddfSDavid du Colombier 	case Tcert:
14064f8f669cSDavid du Colombier 		if (rp->cert == nil)
14074f8f669cSDavid du Colombier 			fmtprint(&fstr, " type=<null> tag=<null> alg=<null>");
14084f8f669cSDavid du Colombier 		else
14099a747e4fSDavid du Colombier 			fmtprint(&fstr, " type=%d tag=%d alg=%d",
14104f8f669cSDavid du Colombier 				rp->cert->type, rp->cert->tag, rp->cert->alg);
14117dd7cddfSDavid du Colombier 		break;
14127dd7cddfSDavid du Colombier 	}
14137dd7cddfSDavid du Colombier out:
14149a747e4fSDavid du Colombier 	strp = fmtstrflush(&fstr);
14159a747e4fSDavid du Colombier 	rv = fmtstrcpy(f, strp);
14169a747e4fSDavid du Colombier 	free(strp);
14179a747e4fSDavid du Colombier 	return rv;
14183e12c5d1SDavid du Colombier }
14197dd7cddfSDavid du Colombier 
14207dd7cddfSDavid du Colombier void
14217dd7cddfSDavid du Colombier warning(char *fmt, ...)
14227dd7cddfSDavid du Colombier {
14234f8f669cSDavid du Colombier 	char dnserr[256];
14247dd7cddfSDavid du Colombier 	va_list arg;
14257dd7cddfSDavid du Colombier 
14267dd7cddfSDavid du Colombier 	va_start(arg, fmt);
14279a747e4fSDavid du Colombier 	vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
14287dd7cddfSDavid du Colombier 	va_end(arg);
14294f8f669cSDavid du Colombier 	syslog(1, logfile, dnserr);		/* on console too */
14304f8f669cSDavid du Colombier }
14314f8f669cSDavid du Colombier 
14324f8f669cSDavid du Colombier void
14334f8f669cSDavid du Colombier dnslog(char *fmt, ...)
14344f8f669cSDavid du Colombier {
14354f8f669cSDavid du Colombier 	char dnserr[256];
14364f8f669cSDavid du Colombier 	va_list arg;
14374f8f669cSDavid du Colombier 
14384f8f669cSDavid du Colombier 	va_start(arg, fmt);
14394f8f669cSDavid du Colombier 	vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
14404f8f669cSDavid du Colombier 	va_end(arg);
14414f8f669cSDavid du Colombier 	syslog(0, logfile, dnserr);
14424f8f669cSDavid du Colombier }
14434f8f669cSDavid du Colombier 
14444f8f669cSDavid du Colombier /*
14454f8f669cSDavid du Colombier  * based on libthread's threadsetname, but drags in less library code.
14464f8f669cSDavid du Colombier  * actually just sets the arguments displayed.
14474f8f669cSDavid du Colombier  */
14484f8f669cSDavid du Colombier void
14494f8f669cSDavid du Colombier procsetname(char *fmt, ...)
14504f8f669cSDavid du Colombier {
14514f8f669cSDavid du Colombier 	int fd;
14524f8f669cSDavid du Colombier 	char *cmdname;
14534f8f669cSDavid du Colombier 	char buf[128];
14544f8f669cSDavid du Colombier 	va_list arg;
14554f8f669cSDavid du Colombier 
14564f8f669cSDavid du Colombier 	va_start(arg, fmt);
14574f8f669cSDavid du Colombier 	cmdname = vsmprint(fmt, arg);
14584f8f669cSDavid du Colombier 	va_end(arg);
14594f8f669cSDavid du Colombier 	if (cmdname == nil)
14604f8f669cSDavid du Colombier 		return;
14614f8f669cSDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/args", getpid());
14624f8f669cSDavid du Colombier 	if((fd = open(buf, OWRITE)) >= 0){
14634f8f669cSDavid du Colombier 		write(fd, cmdname, strlen(cmdname)+1);
14644f8f669cSDavid du Colombier 		close(fd);
14654f8f669cSDavid du Colombier 	}
14664f8f669cSDavid du Colombier 	free(cmdname);
14677dd7cddfSDavid du Colombier }
14687dd7cddfSDavid du Colombier 
14697dd7cddfSDavid du Colombier /*
14707dd7cddfSDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
14717dd7cddfSDavid du Colombier  *  another
14727dd7cddfSDavid du Colombier  */
14737dd7cddfSDavid du Colombier void
14747dd7cddfSDavid du Colombier slave(Request *req)
14757dd7cddfSDavid du Colombier {
1476a41547ffSDavid du Colombier 	int ppid, procs;
14777dd7cddfSDavid du Colombier 
14787dd7cddfSDavid du Colombier 	if(req->isslave)
14797dd7cddfSDavid du Colombier 		return;		/* we're already a slave process */
14807dd7cddfSDavid du Colombier 
1481b4b9fc2fSDavid du Colombier 	/*
1482b4b9fc2fSDavid du Colombier 	 * These calls to putactivity cannot block.
1483b4b9fc2fSDavid du Colombier 	 * After getactivity(), the current process is counted
1484b4b9fc2fSDavid du Colombier 	 * twice in dnvars.active (one will pass to the child).
1485b4b9fc2fSDavid du Colombier 	 * If putactivity tries to wait for dnvars.active == 0,
1486b4b9fc2fSDavid du Colombier 	 * it will never happen.
1487b4b9fc2fSDavid du Colombier 	 */
1488b4b9fc2fSDavid du Colombier 
14897dd7cddfSDavid du Colombier 	/* limit parallelism */
1490a41547ffSDavid du Colombier 	procs = getactivity(req, 1);
1491a41547ffSDavid du Colombier 	if (procs > stats.slavehiwat)
1492a41547ffSDavid du Colombier 		stats.slavehiwat = procs;
1493a41547ffSDavid du Colombier 	if(procs > Maxactive){
14944f8f669cSDavid du Colombier 		if(traceactivity)
14954f8f669cSDavid du Colombier 			dnslog("[%d] too much activity", getpid());
1496b4b9fc2fSDavid du Colombier 		putactivity(1);
14977dd7cddfSDavid du Colombier 		return;
14987dd7cddfSDavid du Colombier 	}
14997dd7cddfSDavid du Colombier 
1500c73252aeSDavid du Colombier 	/*
1501c73252aeSDavid du Colombier 	 * parent returns to main loop, child does the work.
1502c73252aeSDavid du Colombier 	 * don't change note group.
1503c73252aeSDavid du Colombier 	 */
1504b4b9fc2fSDavid du Colombier 	ppid = getpid();
1505c73252aeSDavid du Colombier 	switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
15067dd7cddfSDavid du Colombier 	case -1:
1507b4b9fc2fSDavid du Colombier 		putactivity(1);
15087dd7cddfSDavid du Colombier 		break;
15097dd7cddfSDavid du Colombier 	case 0:
15104f8f669cSDavid du Colombier 		procsetname("request slave of pid %d", ppid);
15114f8f669cSDavid du Colombier  		if(traceactivity)
1512a41547ffSDavid du Colombier 			dnslog("[%d] take activity from %d", getpid(), ppid);
15134f8f669cSDavid du Colombier 		req->isslave = 1;	/* why not `= getpid()'? */
15147dd7cddfSDavid du Colombier 		break;
15157dd7cddfSDavid du Colombier 	default:
15164f8f669cSDavid du Colombier 		/*
15174f8f669cSDavid du Colombier 		 * this relies on rfork producing separate, initially-identical
15184f8f669cSDavid du Colombier 		 * stacks, thus giving us two copies of `req', one in each
15194f8f669cSDavid du Colombier 		 * process.
15204f8f669cSDavid du Colombier 		 */
15216aaebd7dSDavid du Colombier 		alarm(0);
15227dd7cddfSDavid du Colombier 		longjmp(req->mret, 1);
15237dd7cddfSDavid du Colombier 	}
15247dd7cddfSDavid du Colombier }
15257dd7cddfSDavid du Colombier 
15267dd7cddfSDavid du Colombier /*
15277dd7cddfSDavid du Colombier  *  chasing down double free's
15287dd7cddfSDavid du Colombier  */
15297dd7cddfSDavid du Colombier void
15307dd7cddfSDavid du Colombier dncheck(void *p, int dolock)
15317dd7cddfSDavid du Colombier {
15327dd7cddfSDavid du Colombier 	int i;
15337dd7cddfSDavid du Colombier 	DN *dp;
15347dd7cddfSDavid du Colombier 	RR *rp;
15357dd7cddfSDavid du Colombier 
15367dd7cddfSDavid du Colombier 	if(p != nil){
15377dd7cddfSDavid du Colombier 		dp = p;
15387dd7cddfSDavid du Colombier 		assert(dp->magic == DNmagic);
15397dd7cddfSDavid du Colombier 	}
15407dd7cddfSDavid du Colombier 
15417dd7cddfSDavid du Colombier 	if(!testing)
15427dd7cddfSDavid du Colombier 		return;
15437dd7cddfSDavid du Colombier 
15447dd7cddfSDavid du Colombier 	if(dolock)
15457dd7cddfSDavid du Colombier 		lock(&dnlock);
15469a747e4fSDavid du Colombier 	poolcheck(mainmem);
15477dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
15487dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
15497dd7cddfSDavid du Colombier 			assert(dp != p);
15507dd7cddfSDavid du Colombier 			assert(dp->magic == DNmagic);
15517dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next){
15527dd7cddfSDavid du Colombier 				assert(rp->magic == RRmagic);
15537dd7cddfSDavid du Colombier 				assert(rp->cached);
15547dd7cddfSDavid du Colombier 				assert(rp->owner == dp);
1555225077b0SDavid du Colombier 				/* also check for duplicate rrs */
15564f927735SDavid du Colombier 				if (dolock && rronlist(rp, rp->next)) {
15574f927735SDavid du Colombier 					dnslog("%R duplicates its next chain "
15584f927735SDavid du Colombier 						"(%R); aborting", rp, rp->next);
15594f927735SDavid du Colombier 					abort();
15604f927735SDavid du Colombier 				}
15617dd7cddfSDavid du Colombier 			}
15627dd7cddfSDavid du Colombier 		}
15637dd7cddfSDavid du Colombier 	if(dolock)
15647dd7cddfSDavid du Colombier 		unlock(&dnlock);
15657dd7cddfSDavid du Colombier }
15667dd7cddfSDavid du Colombier 
15677dd7cddfSDavid du Colombier static int
15687dd7cddfSDavid du Colombier rrequiv(RR *r1, RR *r2)
15697dd7cddfSDavid du Colombier {
15707dd7cddfSDavid du Colombier 	return r1->owner == r2->owner
15717dd7cddfSDavid du Colombier 		&& r1->type == r2->type
15727dd7cddfSDavid du Colombier 		&& r1->arg0 == r2->arg0
1573225077b0SDavid du Colombier 		&& r1->arg1 == r2->arg1;
15747dd7cddfSDavid du Colombier }
15757dd7cddfSDavid du Colombier 
15767dd7cddfSDavid du Colombier void
15777dd7cddfSDavid du Colombier unique(RR *rp)
15787dd7cddfSDavid du Colombier {
15797dd7cddfSDavid du Colombier 	RR **l, *nrp;
15807dd7cddfSDavid du Colombier 
15817dd7cddfSDavid du Colombier 	for(; rp; rp = rp->next){
15827dd7cddfSDavid du Colombier 		l = &rp->next;
15834f8f669cSDavid du Colombier 		for(nrp = *l; nrp; nrp = *l)
15847dd7cddfSDavid du Colombier 			if(rrequiv(rp, nrp)){
15857dd7cddfSDavid du Colombier 				*l = nrp->next;
15867dd7cddfSDavid du Colombier 				rrfree(nrp);
15877dd7cddfSDavid du Colombier 			} else
15887dd7cddfSDavid du Colombier 				l = &nrp->next;
15897dd7cddfSDavid du Colombier 	}
15907dd7cddfSDavid du Colombier }
15917dd7cddfSDavid du Colombier 
15927dd7cddfSDavid du Colombier /*
15937dd7cddfSDavid du Colombier  *  true if second domain is subsumed by the first
15947dd7cddfSDavid du Colombier  */
15957dd7cddfSDavid du Colombier int
15967dd7cddfSDavid du Colombier subsume(char *higher, char *lower)
15977dd7cddfSDavid du Colombier {
15987dd7cddfSDavid du Colombier 	int hn, ln;
15997dd7cddfSDavid du Colombier 
16007dd7cddfSDavid du Colombier 	ln = strlen(lower);
16017dd7cddfSDavid du Colombier 	hn = strlen(higher);
16024f8f669cSDavid du Colombier 	if (ln < hn || cistrcmp(lower + ln - hn, higher) != 0 ||
16034f8f669cSDavid du Colombier 	    ln > hn && hn != 0 && lower[ln - hn - 1] != '.')
16047dd7cddfSDavid du Colombier 		return 0;
16057dd7cddfSDavid du Colombier 	return 1;
16067dd7cddfSDavid du Colombier }
16077dd7cddfSDavid du Colombier 
16087dd7cddfSDavid du Colombier /*
16097dd7cddfSDavid du Colombier  *  randomize the order we return items to provide some
16105d459b5aSDavid du Colombier  *  load balancing for servers.
16115d459b5aSDavid du Colombier  *
16125d459b5aSDavid du Colombier  *  only randomize the first class of entries
16137dd7cddfSDavid du Colombier  */
16147dd7cddfSDavid du Colombier RR*
16157dd7cddfSDavid du Colombier randomize(RR *rp)
16167dd7cddfSDavid du Colombier {
16175d459b5aSDavid du Colombier 	RR *first, *last, *x, *base;
16187dd7cddfSDavid du Colombier 	ulong n;
16197dd7cddfSDavid du Colombier 
16207dd7cddfSDavid du Colombier 	if(rp == nil || rp->next == nil)
16217dd7cddfSDavid du Colombier 		return rp;
16227dd7cddfSDavid du Colombier 
16233cbadd90SDavid du Colombier 	/* just randomize addresses, mx's and ns's */
16247dd7cddfSDavid du Colombier 	for(x = rp; x; x = x->next)
1625adb31a62SDavid du Colombier 		if(x->type != Ta && x->type != Taaaa &&
1626adb31a62SDavid du Colombier 		    x->type != Tmx && x->type != Tns)
16277dd7cddfSDavid du Colombier 			return rp;
16287dd7cddfSDavid du Colombier 
16295d459b5aSDavid du Colombier 	base = rp;
16305d459b5aSDavid du Colombier 
16317dd7cddfSDavid du Colombier 	n = rand();
16327dd7cddfSDavid du Colombier 	last = first = nil;
16337dd7cddfSDavid du Colombier 	while(rp != nil){
16345d459b5aSDavid du Colombier 		/* stop randomizing if we've moved past our class */
16355d459b5aSDavid du Colombier 		if(base->auth != rp->auth || base->db != rp->db){
16365d459b5aSDavid du Colombier 			last->next = rp;
16375d459b5aSDavid du Colombier 			break;
16385d459b5aSDavid du Colombier 		}
16395d459b5aSDavid du Colombier 
16407dd7cddfSDavid du Colombier 		/* unchain */
16417dd7cddfSDavid du Colombier 		x = rp;
16427dd7cddfSDavid du Colombier 		rp = x->next;
16437dd7cddfSDavid du Colombier 		x->next = nil;
16447dd7cddfSDavid du Colombier 
1645225077b0SDavid du Colombier 		if(n&1){
16467dd7cddfSDavid du Colombier 			/* add to tail */
16477dd7cddfSDavid du Colombier 			if(last == nil)
16487dd7cddfSDavid du Colombier 				first = x;
16497dd7cddfSDavid du Colombier 			else
16507dd7cddfSDavid du Colombier 				last->next = x;
16517dd7cddfSDavid du Colombier 			last = x;
16527dd7cddfSDavid du Colombier 		} else {
16537dd7cddfSDavid du Colombier 			/* add to head */
16547dd7cddfSDavid du Colombier 			if(last == nil)
16557dd7cddfSDavid du Colombier 				last = x;
16567dd7cddfSDavid du Colombier 			x->next = first;
16577dd7cddfSDavid du Colombier 			first = x;
16587dd7cddfSDavid du Colombier 		}
16597dd7cddfSDavid du Colombier 
16607dd7cddfSDavid du Colombier 		/* reroll the dice */
16617dd7cddfSDavid du Colombier 		n >>= 1;
16627dd7cddfSDavid du Colombier 	}
16633cbadd90SDavid du Colombier 
16647dd7cddfSDavid du Colombier 	return first;
16657dd7cddfSDavid du Colombier }
166659cc4ca5SDavid du Colombier 
16679a747e4fSDavid du Colombier static int
16689a747e4fSDavid du Colombier sencodefmt(Fmt *f)
166959cc4ca5SDavid du Colombier {
16704f8f669cSDavid du Colombier 	int i, len, ilen, rv;
16714f8f669cSDavid du Colombier 	char *out, *buf;
16729a747e4fSDavid du Colombier 	uchar *b;
16734f8f669cSDavid du Colombier 	char obuf[64];		/* rsc optimization */
167459cc4ca5SDavid du Colombier 
16759a747e4fSDavid du Colombier 	if(!(f->flags&FmtPrec) || f->prec < 1)
16769a747e4fSDavid du Colombier 		goto error;
16779a747e4fSDavid du Colombier 
16789a747e4fSDavid du Colombier 	b = va_arg(f->args, uchar*);
16799a747e4fSDavid du Colombier 	if(b == nil)
16809a747e4fSDavid du Colombier 		goto error;
16819a747e4fSDavid du Colombier 
16829a747e4fSDavid du Colombier 	/* if it's a printable, go for it */
16839a747e4fSDavid du Colombier 	len = f->prec;
16849a747e4fSDavid du Colombier 	for(i = 0; i < len; i++)
16859a747e4fSDavid du Colombier 		if(!isprint(b[i]))
16869a747e4fSDavid du Colombier 			break;
16879a747e4fSDavid du Colombier 	if(i == len){
16889a747e4fSDavid du Colombier 		if(len >= sizeof obuf)
16899a747e4fSDavid du Colombier 			len = sizeof(obuf)-1;
16909a747e4fSDavid du Colombier 		memmove(obuf, b, len);
16919a747e4fSDavid du Colombier 		obuf[len] = 0;
16929a747e4fSDavid du Colombier 		fmtstrcpy(f, obuf);
16939a747e4fSDavid du Colombier 		return 0;
169459cc4ca5SDavid du Colombier 	}
169559cc4ca5SDavid du Colombier 
16969a747e4fSDavid du Colombier 	ilen = f->prec;
16979a747e4fSDavid du Colombier 	f->prec = 0;
16989a747e4fSDavid du Colombier 	f->flags &= ~FmtPrec;
16999a747e4fSDavid du Colombier 	switch(f->r){
17009a747e4fSDavid du Colombier 	case '<':
17019a747e4fSDavid du Colombier 		len = (8*ilen+4)/5 + 3;
17029a747e4fSDavid du Colombier 		break;
17039a747e4fSDavid du Colombier 	case '[':
17049a747e4fSDavid du Colombier 		len = (8*ilen+5)/6 + 4;
17059a747e4fSDavid du Colombier 		break;
17069a747e4fSDavid du Colombier 	case 'H':
17079a747e4fSDavid du Colombier 		len = 2*ilen + 1;
17089a747e4fSDavid du Colombier 		break;
17099a747e4fSDavid du Colombier 	default:
17109a747e4fSDavid du Colombier 		goto error;
17119a747e4fSDavid du Colombier 	}
171259cc4ca5SDavid du Colombier 
17139a747e4fSDavid du Colombier 	if(len > sizeof(obuf)){
17149a747e4fSDavid du Colombier 		buf = malloc(len);
17159a747e4fSDavid du Colombier 		if(buf == nil)
17169a747e4fSDavid du Colombier 			goto error;
17179a747e4fSDavid du Colombier 	} else
17189a747e4fSDavid du Colombier 		buf = obuf;
17199a747e4fSDavid du Colombier 
17204f8f669cSDavid du Colombier 	/* convert */
17219a747e4fSDavid du Colombier 	out = buf;
17229a747e4fSDavid du Colombier 	switch(f->r){
17239a747e4fSDavid du Colombier 	case '<':
17249a747e4fSDavid du Colombier 		rv = enc32(out, len, b, ilen);
17259a747e4fSDavid du Colombier 		break;
17269a747e4fSDavid du Colombier 	case '[':
17279a747e4fSDavid du Colombier 		rv = enc64(out, len, b, ilen);
17289a747e4fSDavid du Colombier 		break;
17299a747e4fSDavid du Colombier 	case 'H':
17309a747e4fSDavid du Colombier 		rv = enc16(out, len, b, ilen);
17319a747e4fSDavid du Colombier 		break;
17329a747e4fSDavid du Colombier 	default:
17339a747e4fSDavid du Colombier 		rv = -1;
17349a747e4fSDavid du Colombier 		break;
17359a747e4fSDavid du Colombier 	}
17369a747e4fSDavid du Colombier 	if(rv < 0)
17379a747e4fSDavid du Colombier 		goto error;
17389a747e4fSDavid du Colombier 
17399a747e4fSDavid du Colombier 	fmtstrcpy(f, buf);
17409a747e4fSDavid du Colombier 	if(buf != obuf)
17419a747e4fSDavid du Colombier 		free(buf);
17429a747e4fSDavid du Colombier 	return 0;
17439a747e4fSDavid du Colombier 
17449a747e4fSDavid du Colombier error:
17459a747e4fSDavid du Colombier 	return fmtstrcpy(f, "<encodefmt>");
17469a747e4fSDavid du Colombier }
17479a747e4fSDavid du Colombier 
17489a747e4fSDavid du Colombier void*
17499a747e4fSDavid du Colombier emalloc(int size)
17509a747e4fSDavid du Colombier {
17519a747e4fSDavid du Colombier 	char *x;
17529a747e4fSDavid du Colombier 
17539a747e4fSDavid du Colombier 	x = mallocz(size, 1);
17549a747e4fSDavid du Colombier 	if(x == nil)
17559a747e4fSDavid du Colombier 		abort();
175634f77ae3SDavid du Colombier 	setmalloctag(x, getcallerpc(&size));
17579a747e4fSDavid du Colombier 	return x;
17589a747e4fSDavid du Colombier }
17599a747e4fSDavid du Colombier 
17609a747e4fSDavid du Colombier char*
17619a747e4fSDavid du Colombier estrdup(char *s)
17629a747e4fSDavid du Colombier {
17639a747e4fSDavid du Colombier 	int size;
17649a747e4fSDavid du Colombier 	char *p;
17659a747e4fSDavid du Colombier 
17669a747e4fSDavid du Colombier 	size = strlen(s)+1;
17679a747e4fSDavid du Colombier 	p = mallocz(size, 0);
17689a747e4fSDavid du Colombier 	if(p == nil)
17699a747e4fSDavid du Colombier 		abort();
17709a747e4fSDavid du Colombier 	memmove(p, s, size);
177134f77ae3SDavid du Colombier 	setmalloctag(p, getcallerpc(&s));
17729a747e4fSDavid du Colombier 	return p;
177359cc4ca5SDavid du Colombier }
17743ff48bf5SDavid du Colombier 
17753ff48bf5SDavid du Colombier /*
17763ff48bf5SDavid du Colombier  *  create a pointer record
17773ff48bf5SDavid du Colombier  */
17783ff48bf5SDavid du Colombier static RR*
17793ff48bf5SDavid du Colombier mkptr(DN *dp, char *ptr, ulong ttl)
17803ff48bf5SDavid du Colombier {
17813ff48bf5SDavid du Colombier 	DN *ipdp;
17823ff48bf5SDavid du Colombier 	RR *rp;
17833ff48bf5SDavid du Colombier 
17843ff48bf5SDavid du Colombier 	ipdp = dnlookup(ptr, Cin, 1);
17853ff48bf5SDavid du Colombier 
17863ff48bf5SDavid du Colombier 	rp = rralloc(Tptr);
17873ff48bf5SDavid du Colombier 	rp->ptr = dp;
17883ff48bf5SDavid du Colombier 	rp->owner = ipdp;
17893ff48bf5SDavid du Colombier 	rp->db = 1;
17903ff48bf5SDavid du Colombier 	if(ttl)
17913ff48bf5SDavid du Colombier 		rp->ttl = ttl;
17923ff48bf5SDavid du Colombier 	return rp;
17933ff48bf5SDavid du Colombier }
17943ff48bf5SDavid du Colombier 
179553874d13SDavid du Colombier void	bytes2nibbles(uchar *nibbles, uchar *bytes, int nbytes);
179653874d13SDavid du Colombier 
17973ff48bf5SDavid du Colombier /*
17983ff48bf5SDavid du Colombier  *  look for all ip addresses in this network and make
17993ff48bf5SDavid du Colombier  *  pointer records for them.
18003ff48bf5SDavid du Colombier  */
18013ff48bf5SDavid du Colombier void
180253874d13SDavid du Colombier dnptr(uchar *net, uchar *mask, char *dom, int forwtype, int subdoms, int ttl)
18033ff48bf5SDavid du Colombier {
180453874d13SDavid du Colombier 	int i, j, len;
18054f8f669cSDavid du Colombier 	char *p, *e;
18064f8f669cSDavid du Colombier 	char ptr[Domlen];
180753874d13SDavid du Colombier 	uchar *ipp;
18084f8f669cSDavid du Colombier 	uchar ip[IPaddrlen], nnet[IPaddrlen];
180953874d13SDavid du Colombier 	uchar nibip[IPaddrlen*2];
18103ff48bf5SDavid du Colombier 	DN *dp;
18113ff48bf5SDavid du Colombier 	RR *rp, *nrp, *first, **l;
18123ff48bf5SDavid du Colombier 
18133ff48bf5SDavid du Colombier 	l = &first;
18143ff48bf5SDavid du Colombier 	first = nil;
18154f8f669cSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
18164f8f669cSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next)
18173ff48bf5SDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next){
181853874d13SDavid du Colombier 				if(rp->type != forwtype || rp->negative)
18193ff48bf5SDavid du Colombier 					continue;
18203ff48bf5SDavid du Colombier 				parseip(ip, rp->ip->name);
18213ff48bf5SDavid du Colombier 				maskip(ip, mask, nnet);
18223ff48bf5SDavid du Colombier 				if(ipcmp(net, nnet) != 0)
18233ff48bf5SDavid du Colombier 					continue;
182453874d13SDavid du Colombier 
182553874d13SDavid du Colombier 				ipp = ip;
182653874d13SDavid du Colombier 				len = IPaddrlen;
182753874d13SDavid du Colombier 				if (forwtype == Taaaa) {
182853874d13SDavid du Colombier 					bytes2nibbles(nibip, ip, IPaddrlen);
182953874d13SDavid du Colombier 					ipp = nibip;
183053874d13SDavid du Colombier 					len = 2*IPaddrlen;
183153874d13SDavid du Colombier 				}
183253874d13SDavid du Colombier 
18333ff48bf5SDavid du Colombier 				p = ptr;
18343ff48bf5SDavid du Colombier 				e = ptr+sizeof(ptr);
183553874d13SDavid du Colombier 				for(j = len - 1; j >= len - subdoms; j--)
183653874d13SDavid du Colombier 					p = seprint(p, e, (forwtype == Ta?
183753874d13SDavid du Colombier 						"%d.": "%x."), ipp[j]);
18383ff48bf5SDavid du Colombier 				seprint(p, e, "%s", dom);
183953874d13SDavid du Colombier 
18403ff48bf5SDavid du Colombier 				nrp = mkptr(dp, ptr, ttl);
18413ff48bf5SDavid du Colombier 				*l = nrp;
18423ff48bf5SDavid du Colombier 				l = &nrp->next;
18433ff48bf5SDavid du Colombier 			}
18443ff48bf5SDavid du Colombier 
18453ff48bf5SDavid du Colombier 	for(rp = first; rp != nil; rp = nrp){
18463ff48bf5SDavid du Colombier 		nrp = rp->next;
18473ff48bf5SDavid du Colombier 		rp->next = nil;
18486dc4800dSDavid du Colombier 		rrattach(rp, Authoritative);
18493ff48bf5SDavid du Colombier 	}
18503ff48bf5SDavid du Colombier }
1851dc5a79c1SDavid du Colombier 
1852dc5a79c1SDavid du Colombier void
1853dc5a79c1SDavid du Colombier addserver(Server **l, char *name)
1854dc5a79c1SDavid du Colombier {
1855dc5a79c1SDavid du Colombier 	Server *s;
1856dc5a79c1SDavid du Colombier 
1857dc5a79c1SDavid du Colombier 	while(*l)
1858dc5a79c1SDavid du Colombier 		l = &(*l)->next;
1859dc5a79c1SDavid du Colombier 	s = malloc(sizeof(Server)+strlen(name)+1);
1860dc5a79c1SDavid du Colombier 	if(s == nil)
1861dc5a79c1SDavid du Colombier 		return;
1862dc5a79c1SDavid du Colombier 	s->name = (char*)(s+1);
1863dc5a79c1SDavid du Colombier 	strcpy(s->name, name);
1864dc5a79c1SDavid du Colombier 	s->next = nil;
1865dc5a79c1SDavid du Colombier 	*l = s;
1866dc5a79c1SDavid du Colombier }
1867dc5a79c1SDavid du Colombier 
1868dc5a79c1SDavid du Colombier Server*
1869dc5a79c1SDavid du Colombier copyserverlist(Server *s)
1870dc5a79c1SDavid du Colombier {
1871dc5a79c1SDavid du Colombier 	Server *ns;
1872dc5a79c1SDavid du Colombier 
1873dc5a79c1SDavid du Colombier 	for(ns = nil; s != nil; s = s->next)
1874dc5a79c1SDavid du Colombier 		addserver(&ns, s->name);
1875dc5a79c1SDavid du Colombier 	return ns;
1876dc5a79c1SDavid du Colombier }
1877b751ae26SDavid du Colombier 
1878b751ae26SDavid du Colombier 
1879b751ae26SDavid du Colombier /* from here down is copied to ip/snoopy/dns.c periodically to update it */
1880b751ae26SDavid du Colombier 
1881b751ae26SDavid du Colombier /*
1882b751ae26SDavid du Colombier  *  convert an integer RR type to it's ascii name
1883b751ae26SDavid du Colombier  */
1884b751ae26SDavid du Colombier char*
1885b751ae26SDavid du Colombier rrname(int type, char *buf, int len)
1886b751ae26SDavid du Colombier {
1887b751ae26SDavid du Colombier 	char *t;
1888b751ae26SDavid du Colombier 
1889b751ae26SDavid du Colombier 	t = nil;
1890b751ae26SDavid du Colombier 	if(type >= 0 && type <= Tall)
1891b751ae26SDavid du Colombier 		t = rrtname[type];
1892b751ae26SDavid du Colombier 	if(t==nil){
1893b751ae26SDavid du Colombier 		snprint(buf, len, "%d", type);
1894b751ae26SDavid du Colombier 		t = buf;
1895b751ae26SDavid du Colombier 	}
1896b751ae26SDavid du Colombier 	return t;
1897b751ae26SDavid du Colombier }
1898b751ae26SDavid du Colombier 
1899b751ae26SDavid du Colombier /*
1900b751ae26SDavid du Colombier  *  free a list of resource records and any related structs
1901b751ae26SDavid du Colombier  */
1902b751ae26SDavid du Colombier void
1903b751ae26SDavid du Colombier rrfreelist(RR *rp)
1904b751ae26SDavid du Colombier {
1905b751ae26SDavid du Colombier 	RR *next;
1906b751ae26SDavid du Colombier 
1907b751ae26SDavid du Colombier 	for(; rp; rp = next){
1908b751ae26SDavid du Colombier 		next = rp->next;
1909b751ae26SDavid du Colombier 		rrfree(rp);
1910b751ae26SDavid du Colombier 	}
1911b751ae26SDavid du Colombier }
1912b751ae26SDavid du Colombier 
1913b751ae26SDavid du Colombier void
1914b751ae26SDavid du Colombier freeserverlist(Server *s)
1915b751ae26SDavid du Colombier {
1916b751ae26SDavid du Colombier 	Server *next;
1917b751ae26SDavid du Colombier 
1918b751ae26SDavid du Colombier 	for(; s != nil; s = next){
1919b751ae26SDavid du Colombier 		next = s->next;
1920b751ae26SDavid du Colombier 		free(s);
1921b751ae26SDavid du Colombier 	}
1922b751ae26SDavid du Colombier }
1923b751ae26SDavid du Colombier 
1924b751ae26SDavid du Colombier /*
1925b751ae26SDavid du Colombier  *  allocate a resource record of a given type
1926b751ae26SDavid du Colombier  */
1927b751ae26SDavid du Colombier RR*
1928b751ae26SDavid du Colombier rralloc(int type)
1929b751ae26SDavid du Colombier {
1930b751ae26SDavid du Colombier 	RR *rp;
1931b751ae26SDavid du Colombier 
1932b751ae26SDavid du Colombier 	rp = emalloc(sizeof(*rp));
1933b751ae26SDavid du Colombier 	rp->magic = RRmagic;
1934b751ae26SDavid du Colombier 	rp->pc = getcallerpc(&type);
1935b751ae26SDavid du Colombier 	rp->type = type;
1936fd87a217SDavid du Colombier 	if (rp->type != type)
1937fd87a217SDavid du Colombier 		dnslog("rralloc: bogus type %d", type);
1938b751ae26SDavid du Colombier 	setmalloctag(rp, rp->pc);
1939b751ae26SDavid du Colombier 	switch(type){
1940b751ae26SDavid du Colombier 	case Tsoa:
1941b751ae26SDavid du Colombier 		rp->soa = emalloc(sizeof(*rp->soa));
1942b751ae26SDavid du Colombier 		rp->soa->slaves = nil;
1943b751ae26SDavid du Colombier 		setmalloctag(rp->soa, rp->pc);
1944b751ae26SDavid du Colombier 		break;
1945b751ae26SDavid du Colombier 	case Tsrv:
1946b751ae26SDavid du Colombier 		rp->srv = emalloc(sizeof(*rp->srv));
1947b751ae26SDavid du Colombier 		setmalloctag(rp->srv, rp->pc);
1948b751ae26SDavid du Colombier 		break;
1949b751ae26SDavid du Colombier 	case Tkey:
1950b751ae26SDavid du Colombier 		rp->key = emalloc(sizeof(*rp->key));
1951b751ae26SDavid du Colombier 		setmalloctag(rp->key, rp->pc);
1952b751ae26SDavid du Colombier 		break;
1953b751ae26SDavid du Colombier 	case Tcert:
1954b751ae26SDavid du Colombier 		rp->cert = emalloc(sizeof(*rp->cert));
1955b751ae26SDavid du Colombier 		setmalloctag(rp->cert, rp->pc);
1956b751ae26SDavid du Colombier 		break;
1957b751ae26SDavid du Colombier 	case Tsig:
1958b751ae26SDavid du Colombier 		rp->sig = emalloc(sizeof(*rp->sig));
1959b751ae26SDavid du Colombier 		setmalloctag(rp->sig, rp->pc);
1960b751ae26SDavid du Colombier 		break;
1961b751ae26SDavid du Colombier 	case Tnull:
1962b751ae26SDavid du Colombier 		rp->null = emalloc(sizeof(*rp->null));
1963b751ae26SDavid du Colombier 		setmalloctag(rp->null, rp->pc);
1964b751ae26SDavid du Colombier 		break;
1965b751ae26SDavid du Colombier 	}
1966b751ae26SDavid du Colombier 	rp->ttl = 0;
1967b751ae26SDavid du Colombier 	rp->expire = 0;
1968b751ae26SDavid du Colombier 	rp->next = 0;
1969b751ae26SDavid du Colombier 	return rp;
1970b751ae26SDavid du Colombier }
1971b751ae26SDavid du Colombier 
1972b751ae26SDavid du Colombier /*
1973b751ae26SDavid du Colombier  *  free a resource record and any related structs
1974b751ae26SDavid du Colombier  */
1975b751ae26SDavid du Colombier void
1976b751ae26SDavid du Colombier rrfree(RR *rp)
1977b751ae26SDavid du Colombier {
1978b751ae26SDavid du Colombier 	DN *dp;
1979b751ae26SDavid du Colombier 	RR *nrp;
1980b751ae26SDavid du Colombier 	Txt *t;
1981b751ae26SDavid du Colombier 
1982530fef66SDavid du Colombier 	assert(rp->magic == RRmagic);
1983b751ae26SDavid du Colombier 	assert(!rp->cached);
1984b751ae26SDavid du Colombier 
1985b751ae26SDavid du Colombier 	dp = rp->owner;
1986b751ae26SDavid du Colombier 	if(dp){
1987b751ae26SDavid du Colombier 		assert(dp->magic == DNmagic);
1988b751ae26SDavid du Colombier 		for(nrp = dp->rr; nrp; nrp = nrp->next)
1989b751ae26SDavid du Colombier 			assert(nrp != rp);	/* "rrfree of live rr" */
1990b751ae26SDavid du Colombier 	}
1991b751ae26SDavid du Colombier 
1992b751ae26SDavid du Colombier 	switch(rp->type){
1993b751ae26SDavid du Colombier 	case Tsoa:
1994b751ae26SDavid du Colombier 		freeserverlist(rp->soa->slaves);
1995b751ae26SDavid du Colombier 		memset(rp->soa, 0, sizeof *rp->soa);	/* cause trouble */
1996b751ae26SDavid du Colombier 		free(rp->soa);
1997b751ae26SDavid du Colombier 		break;
1998b751ae26SDavid du Colombier 	case Tsrv:
1999b751ae26SDavid du Colombier 		memset(rp->srv, 0, sizeof *rp->srv);	/* cause trouble */
2000b751ae26SDavid du Colombier 		free(rp->srv);
2001b751ae26SDavid du Colombier 		break;
2002b751ae26SDavid du Colombier 	case Tkey:
2003b751ae26SDavid du Colombier 		free(rp->key->data);
2004b751ae26SDavid du Colombier 		memset(rp->key, 0, sizeof *rp->key);	/* cause trouble */
2005b751ae26SDavid du Colombier 		free(rp->key);
2006b751ae26SDavid du Colombier 		break;
2007b751ae26SDavid du Colombier 	case Tcert:
2008b751ae26SDavid du Colombier 		free(rp->cert->data);
2009b751ae26SDavid du Colombier 		memset(rp->cert, 0, sizeof *rp->cert);	/* cause trouble */
2010b751ae26SDavid du Colombier 		free(rp->cert);
2011b751ae26SDavid du Colombier 		break;
2012b751ae26SDavid du Colombier 	case Tsig:
2013b751ae26SDavid du Colombier 		free(rp->sig->data);
2014b751ae26SDavid du Colombier 		memset(rp->sig, 0, sizeof *rp->sig);	/* cause trouble */
2015b751ae26SDavid du Colombier 		free(rp->sig);
2016b751ae26SDavid du Colombier 		break;
2017b751ae26SDavid du Colombier 	case Tnull:
2018b751ae26SDavid du Colombier 		free(rp->null->data);
2019b751ae26SDavid du Colombier 		memset(rp->null, 0, sizeof *rp->null);	/* cause trouble */
2020b751ae26SDavid du Colombier 		free(rp->null);
2021b751ae26SDavid du Colombier 		break;
2022b751ae26SDavid du Colombier 	case Ttxt:
2023b751ae26SDavid du Colombier 		while(rp->txt != nil){
2024b751ae26SDavid du Colombier 			t = rp->txt;
2025b751ae26SDavid du Colombier 			rp->txt = t->next;
2026b751ae26SDavid du Colombier 			free(t->p);
2027b751ae26SDavid du Colombier 			memset(t, 0, sizeof *t);	/* cause trouble */
2028b751ae26SDavid du Colombier 			free(t);
2029b751ae26SDavid du Colombier 		}
2030b751ae26SDavid du Colombier 		break;
2031b751ae26SDavid du Colombier 	}
2032b751ae26SDavid du Colombier 
2033b751ae26SDavid du Colombier 	rp->magic = ~rp->magic;
2034b751ae26SDavid du Colombier 	memset(rp, 0, sizeof *rp);		/* cause trouble */
2035b751ae26SDavid du Colombier 	free(rp);
2036b751ae26SDavid du Colombier }
2037