xref: /plan9/sys/src/cmd/ndb/dn.c (revision 1a8a6b0d994d08a990732c4fe0c170c664ab1e2c)
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 {
17*1a8a6b0dSDavid du Colombier 	Deftarget	= 1<<30,	/* effectively disable aging */
18*1a8a6b0dSDavid du Colombier 	Minage		= 1<<30,
19*1a8a6b0dSDavid du Colombier 	Defagefreq	= 1<<30,	/* age names this often (seconds) */
20*1a8a6b0dSDavid du Colombier 
21*1a8a6b0dSDavid du Colombier 	/* these settings will trigger frequent aging */
22*1a8a6b0dSDavid du Colombier //	Deftarget	= 4000,
23*1a8a6b0dSDavid du Colombier //	Minage		=  5*60,
24*1a8a6b0dSDavid du Colombier //	Defagefreq	= 15*60,	/* age names this often (seconds) */
2581730632SDavid du Colombier };
2681730632SDavid du Colombier 
273e12c5d1SDavid du Colombier /*
283e12c5d1SDavid du Colombier  *  Hash table for domain names.  The hash is based only on the
293e12c5d1SDavid du Colombier  *  first element of the domain name.
303e12c5d1SDavid du Colombier  */
317dd7cddfSDavid du Colombier DN *ht[HTLEN];
323e12c5d1SDavid du Colombier 
334f8f669cSDavid du Colombier static struct {
347dd7cddfSDavid du Colombier 	Lock;
357dd7cddfSDavid du Colombier 	ulong	names;		/* names allocated */
367dd7cddfSDavid du Colombier 	ulong	oldest;		/* longest we'll leave a name around */
377dd7cddfSDavid du Colombier 	int	active;
387dd7cddfSDavid du Colombier 	int	mutex;
394f8f669cSDavid du Colombier 	ushort	id;		/* same size as in packet */
407dd7cddfSDavid du Colombier } dnvars;
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier /* names of RR types */
433e12c5d1SDavid du Colombier char *rrtname[] =
443e12c5d1SDavid du Colombier {
453e12c5d1SDavid du Colombier [Ta]		"ip",
463e12c5d1SDavid du Colombier [Tns]		"ns",
473e12c5d1SDavid du Colombier [Tmd]		"md",
483e12c5d1SDavid du Colombier [Tmf]		"mf",
493e12c5d1SDavid du Colombier [Tcname]	"cname",
503e12c5d1SDavid du Colombier [Tsoa]		"soa",
513e12c5d1SDavid du Colombier [Tmb]		"mb",
523e12c5d1SDavid du Colombier [Tmg]		"mg",
533e12c5d1SDavid du Colombier [Tmr]		"mr",
543e12c5d1SDavid du Colombier [Tnull]		"null",
553e12c5d1SDavid du Colombier [Twks]		"wks",
563e12c5d1SDavid du Colombier [Tptr]		"ptr",
573e12c5d1SDavid du Colombier [Thinfo]	"hinfo",
583e12c5d1SDavid du Colombier [Tminfo]	"minfo",
593e12c5d1SDavid du Colombier [Tmx]		"mx",
603e12c5d1SDavid du Colombier [Ttxt]		"txt",
617dd7cddfSDavid du Colombier [Trp]		"rp",
62ab3dc52fSDavid du Colombier [Tafsdb]	"afsdb",
63ab3dc52fSDavid du Colombier [Tx25]		"x.25",
64ab3dc52fSDavid du Colombier [Tisdn]		"isdn",
65ab3dc52fSDavid du Colombier [Trt]		"rt",
66ab3dc52fSDavid du Colombier [Tnsap]		"nsap",
67ab3dc52fSDavid du Colombier [Tnsapptr]	"nsap-ptr",
687dd7cddfSDavid du Colombier [Tsig]		"sig",
69ab3dc52fSDavid du Colombier [Tkey]		"key",
70ab3dc52fSDavid du Colombier [Tpx]		"px",
71ab3dc52fSDavid du Colombier [Tgpos]		"gpos",
725d459b5aSDavid du Colombier [Taaaa]		"ipv6",
73ab3dc52fSDavid du Colombier [Tloc]		"loc",
74ab3dc52fSDavid du Colombier [Tnxt]		"nxt",
75ab3dc52fSDavid du Colombier [Teid]		"eid",
76ab3dc52fSDavid du Colombier [Tnimloc]	"nimrod",
77ab3dc52fSDavid du Colombier [Tsrv]		"srv",
78ab3dc52fSDavid du Colombier [Tatma]		"atma",
79ab3dc52fSDavid du Colombier [Tnaptr]	"naptr",
80ab3dc52fSDavid du Colombier [Tkx]		"kx",
81ab3dc52fSDavid du Colombier [Tcert]		"cert",
82ab3dc52fSDavid du Colombier [Ta6]		"a6",
83ab3dc52fSDavid du Colombier [Tdname]	"dname",
84ab3dc52fSDavid du Colombier [Tsink]		"sink",
85ab3dc52fSDavid du Colombier [Topt]		"opt",
86ab3dc52fSDavid du Colombier [Tapl]		"apl",
87ab3dc52fSDavid du Colombier [Tds]		"ds",
88ab3dc52fSDavid du Colombier [Tsshfp]	"sshfp",
89ab3dc52fSDavid du Colombier [Tipseckey]	"ipseckey",
90ab3dc52fSDavid du Colombier [Trrsig]	"rrsig",
91ab3dc52fSDavid du Colombier [Tnsec]		"nsec",
92ab3dc52fSDavid du Colombier [Tdnskey]	"dnskey",
93ab3dc52fSDavid du Colombier [Tspf]		"spf",
94ab3dc52fSDavid du Colombier [Tuinfo]	"uinfo",
95ab3dc52fSDavid du Colombier [Tuid]		"uid",
96ab3dc52fSDavid du Colombier [Tgid]		"gid",
97ab3dc52fSDavid du Colombier [Tunspec]	"unspec",
98ab3dc52fSDavid du Colombier [Ttkey]		"tkey",
99ab3dc52fSDavid du Colombier [Ttsig]		"tsig",
1007dd7cddfSDavid du Colombier [Tixfr]		"ixfr",
1017dd7cddfSDavid du Colombier [Taxfr]		"axfr",
102ab3dc52fSDavid du Colombier [Tmailb]	"mailb",
103ab3dc52fSDavid du Colombier [Tmaila]	"maila",
104219b2ee8SDavid du Colombier [Tall]		"all",
1053e12c5d1SDavid du Colombier 		0,
1063e12c5d1SDavid du Colombier };
1073e12c5d1SDavid du Colombier 
1083e12c5d1SDavid du Colombier /* names of response codes */
109271b8d73SDavid du Colombier char *rname[Rmask+1] =
1103e12c5d1SDavid du Colombier {
1113e12c5d1SDavid du Colombier [Rok]			"ok",
1123e12c5d1SDavid du Colombier [Rformat]		"format error",
1133e12c5d1SDavid du Colombier [Rserver]		"server failure",
1143e12c5d1SDavid du Colombier [Rname]			"bad name",
1153e12c5d1SDavid du Colombier [Runimplimented]	"unimplemented",
1163e12c5d1SDavid du Colombier [Rrefused]		"we don't like you",
117ab3dc52fSDavid du Colombier [Ryxdomain]		"name should not exist",
118ab3dc52fSDavid du Colombier [Ryxrrset]		"rr set should not exist",
119ab3dc52fSDavid du Colombier [Rnxrrset]		"rr set should exist",
120ab3dc52fSDavid du Colombier [Rnotauth]		"not authorative",
121ab3dc52fSDavid du Colombier [Rnotzone]		"not in zone",
122ab3dc52fSDavid du Colombier [Rbadvers]		"bad opt version",
123ab3dc52fSDavid du Colombier /* [Rbadsig]		"bad signature", */
124ab3dc52fSDavid du Colombier [Rbadkey]		"bad key",
125ab3dc52fSDavid du Colombier [Rbadtime]		"bad signature time",
126ab3dc52fSDavid du Colombier [Rbadmode]		"bad mode",
127ab3dc52fSDavid du Colombier [Rbadname]		"duplicate key name",
128ab3dc52fSDavid du Colombier [Rbadalg]		"bad algorithm",
1293e12c5d1SDavid du Colombier };
1304f8f669cSDavid du Colombier unsigned nrname = nelem(rname);
1313e12c5d1SDavid du Colombier 
1323e12c5d1SDavid du Colombier /* names of op codes */
1333e12c5d1SDavid du Colombier char *opname[] =
1343e12c5d1SDavid du Colombier {
1353e12c5d1SDavid du Colombier [Oquery]	"query",
136ab3dc52fSDavid du Colombier [Oinverse]	"inverse query (retired)",
1373e12c5d1SDavid du Colombier [Ostatus]	"status",
138ab3dc52fSDavid du Colombier [Oupdate]	"update",
1393e12c5d1SDavid du Colombier };
1403e12c5d1SDavid du Colombier 
14121abd8f2SDavid du Colombier ulong target = Deftarget;
142bd389b36SDavid du Colombier Lock	dnlock;
1433e12c5d1SDavid du Colombier 
144f46c709fSDavid du Colombier static ulong agefreq = Defagefreq;
145f46c709fSDavid du Colombier 
146225077b0SDavid du Colombier static int rrequiv(RR *r1, RR *r2);
1479a747e4fSDavid du Colombier static int sencodefmt(Fmt*);
14859cc4ca5SDavid du Colombier 
149254fe3d3SDavid du Colombier static void
150254fe3d3SDavid du Colombier ding(void*, char *msg)
151254fe3d3SDavid du Colombier {
152254fe3d3SDavid du Colombier 	if(strstr(msg, "alarm") != nil) {
153254fe3d3SDavid du Colombier 		stats.alarms++;
154254fe3d3SDavid du Colombier 		noted(NCONT);		/* resume with system call error */
155254fe3d3SDavid du Colombier 	} else
156254fe3d3SDavid du Colombier 		noted(NDFLT);		/* die */
157254fe3d3SDavid du Colombier }
158254fe3d3SDavid du Colombier 
1593e12c5d1SDavid du Colombier void
1603e12c5d1SDavid du Colombier dninit(void)
1613e12c5d1SDavid du Colombier {
1629a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
1639a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
1649a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
1659a747e4fSDavid du Colombier 	fmtinstall('R', rrfmt);
1669a747e4fSDavid du Colombier 	fmtinstall('Q', rravfmt);
1679a747e4fSDavid du Colombier 	fmtinstall('H', sencodefmt);
1687dd7cddfSDavid du Colombier 
1697dd7cddfSDavid du Colombier 	dnvars.oldest = maxage;
1707dd7cddfSDavid du Colombier 	dnvars.names = 0;
1714f8f669cSDavid du Colombier 	dnvars.id = truerand();	/* don't start with same id every time */
172254fe3d3SDavid du Colombier 
173254fe3d3SDavid du Colombier 	notify(ding);
1743e12c5d1SDavid du Colombier }
1753e12c5d1SDavid du Colombier 
1763e12c5d1SDavid du Colombier /*
1773e12c5d1SDavid du Colombier  *  hash for a domain name
1783e12c5d1SDavid du Colombier  */
1793e12c5d1SDavid du Colombier static ulong
1803e12c5d1SDavid du Colombier dnhash(char *name)
1813e12c5d1SDavid du Colombier {
1823e12c5d1SDavid du Colombier 	ulong hash;
1833e12c5d1SDavid du Colombier 	uchar *val = (uchar*)name;
1843e12c5d1SDavid du Colombier 
1857dd7cddfSDavid du Colombier 	for(hash = 0; *val; val++)
1864f8f669cSDavid du Colombier 		hash = hash*13 + tolower(*val)-'a';
1873e12c5d1SDavid du Colombier 	return hash % HTLEN;
1883e12c5d1SDavid du Colombier }
1893e12c5d1SDavid du Colombier 
1903e12c5d1SDavid du Colombier /*
1913e12c5d1SDavid du Colombier  *  lookup a symbol.  if enter is not zero and the name is
1923e12c5d1SDavid du Colombier  *  not found, create it.
1933e12c5d1SDavid du Colombier  */
1943e12c5d1SDavid du Colombier DN*
1953e12c5d1SDavid du Colombier dnlookup(char *name, int class, int enter)
1963e12c5d1SDavid du Colombier {
1973e12c5d1SDavid du Colombier 	DN **l;
1983e12c5d1SDavid du Colombier 	DN *dp;
1993e12c5d1SDavid du Colombier 
2003ff48bf5SDavid du Colombier 	l = &ht[dnhash(name)];
201bd389b36SDavid du Colombier 	lock(&dnlock);
2023e12c5d1SDavid du Colombier 	for(dp = *l; dp; dp = dp->next) {
2037dd7cddfSDavid du Colombier 		assert(dp->magic == DNmagic);
2043ff48bf5SDavid du Colombier 		if(dp->class == class && cistrcmp(dp->name, name) == 0){
2057dd7cddfSDavid du Colombier 			dp->referenced = now;
206bd389b36SDavid du Colombier 			unlock(&dnlock);
2073e12c5d1SDavid du Colombier 			return dp;
2083e12c5d1SDavid du Colombier 		}
2093e12c5d1SDavid du Colombier 		l = &dp->next;
2103e12c5d1SDavid du Colombier 	}
2114f8f669cSDavid du Colombier 
2124f8f669cSDavid du Colombier 	if(!enter){
213bd389b36SDavid du Colombier 		unlock(&dnlock);
2143e12c5d1SDavid du Colombier 		return 0;
2153e12c5d1SDavid du Colombier 	}
2167dd7cddfSDavid du Colombier 	dnvars.names++;
2179a747e4fSDavid du Colombier 	dp = emalloc(sizeof(*dp));
2187dd7cddfSDavid du Colombier 	dp->magic = DNmagic;
2199a747e4fSDavid du Colombier 	dp->name = estrdup(name);
2204f8f669cSDavid du Colombier 	assert(dp->name != nil);
2213e12c5d1SDavid du Colombier 	dp->class = class;
2223e12c5d1SDavid du Colombier 	dp->rr = 0;
2237dd7cddfSDavid du Colombier 	dp->referenced = now;
224530fef66SDavid du Colombier 	/* add new DN to tail of the hash list.  *l points to last next ptr. */
225530fef66SDavid du Colombier 	dp->next = nil;
2263e12c5d1SDavid du Colombier 	*l = dp;
227bd389b36SDavid du Colombier 	unlock(&dnlock);
2287dd7cddfSDavid du Colombier 
2293e12c5d1SDavid du Colombier 	return dp;
2303e12c5d1SDavid du Colombier }
2313e12c5d1SDavid du Colombier 
232225077b0SDavid du Colombier static int
233225077b0SDavid du Colombier rrsame(RR *rr1, RR *rr2)
234225077b0SDavid du Colombier {
235225077b0SDavid du Colombier 	return rr1 == rr2 || rr2 && rrequiv(rr1, rr2) &&
236225077b0SDavid du Colombier 		rr1->db == rr2->db && rr1->auth == rr2->auth;
237225077b0SDavid du Colombier }
238225077b0SDavid du Colombier 
239225077b0SDavid du Colombier static int
240225077b0SDavid du Colombier rronlist(RR *rp, RR *lp)
241225077b0SDavid du Colombier {
242225077b0SDavid du Colombier 	for(; lp; lp = lp->next)
2434f927735SDavid du Colombier 		if (rrsame(lp, rp))
244225077b0SDavid du Colombier 			return 1;
245225077b0SDavid du Colombier 	return 0;
246225077b0SDavid du Colombier }
247225077b0SDavid du Colombier 
2483e12c5d1SDavid du Colombier /*
2494f927735SDavid du Colombier  * dump the stats
250219b2ee8SDavid du Colombier  */
251219b2ee8SDavid du Colombier void
2524f927735SDavid du Colombier dnstats(char *file)
253219b2ee8SDavid du Colombier {
254219b2ee8SDavid du Colombier 	int i, fd;
255219b2ee8SDavid du Colombier 
25621abd8f2SDavid du Colombier 	fd = create(file, OWRITE, 0666);
257219b2ee8SDavid du Colombier 	if(fd < 0)
258219b2ee8SDavid du Colombier 		return;
259a41547ffSDavid du Colombier 
260a41547ffSDavid du Colombier 	qlock(&stats);
2614f927735SDavid du Colombier 	fprint(fd, "# system %s\n", sysname());
262f46c709fSDavid du Colombier 	fprint(fd, "# slave procs high-water mark\t%lud\n", stats.slavehiwat);
263f46c709fSDavid du Colombier 	fprint(fd, "# queries received by 9p\t%lud\n", stats.qrecvd9p);
264f46c709fSDavid du Colombier 	fprint(fd, "# queries received by udp\t%lud\n", stats.qrecvdudp);
265f46c709fSDavid du Colombier 	fprint(fd, "# queries answered from memory\t%lud\n", stats.answinmem);
266f46c709fSDavid du Colombier 	fprint(fd, "# queries sent by udp\t%lud\n", stats.qsent);
267a41547ffSDavid du Colombier 	for (i = 0; i < nelem(stats.under10ths); i++)
268a41547ffSDavid du Colombier 		if (stats.under10ths[i] || i == nelem(stats.under10ths) - 1)
269f46c709fSDavid du Colombier 			fprint(fd, "# responses arriving within %.1f s.\t%lud\n",
270a41547ffSDavid du Colombier 				(double)(i+1)/10, stats.under10ths[i]);
271f46c709fSDavid du Colombier 	fprint(fd, "\n# queries sent & timed-out\t%lud\n", stats.tmout);
272f46c709fSDavid du Colombier 	fprint(fd, "# cname queries timed-out\t%lud\n", stats.tmoutcname);
273f46c709fSDavid du Colombier 	fprint(fd, "# ipv6  queries timed-out\t%lud\n", stats.tmoutv6);
274f46c709fSDavid du Colombier 	fprint(fd, "\n# negative answers received\t%lud\n", stats.negans);
2750319257bSDavid du Colombier 	fprint(fd, "# negative answers w Rserver set\t%lud\n", stats.negserver);
2760319257bSDavid du Colombier 	fprint(fd, "# negative answers w bad delegation\t%lud\n",
2770319257bSDavid du Colombier 		stats.negbaddeleg);
2780319257bSDavid du Colombier 	fprint(fd, "# negative answers w bad delegation & no answers\t%lud\n",
2790319257bSDavid du Colombier 		stats.negbdnoans);
2800319257bSDavid du Colombier 	fprint(fd, "# negative answers w no Rname set\t%lud\n", stats.negnorname);
281f46c709fSDavid du Colombier 	fprint(fd, "# negative answers cached\t%lud\n", stats.negcached);
282a41547ffSDavid du Colombier 	qunlock(&stats);
283a41547ffSDavid du Colombier 
284219b2ee8SDavid du Colombier 	lock(&dnlock);
2856d8e4566SDavid du Colombier 	fprint(fd, "\n# domain names %lud target %lud\n", dnvars.names, target);
2864f927735SDavid du Colombier 	unlock(&dnlock);
2874f927735SDavid du Colombier 	close(fd);
2884f927735SDavid du Colombier }
2894f927735SDavid du Colombier 
2904f927735SDavid du Colombier /*
2914f927735SDavid du Colombier  *  dump the cache
2924f927735SDavid du Colombier  */
2934f927735SDavid du Colombier void
2944f927735SDavid du Colombier dndump(char *file)
2954f927735SDavid du Colombier {
2964f927735SDavid du Colombier 	int i, fd;
2974f927735SDavid du Colombier 	DN *dp;
2984f927735SDavid du Colombier 	RR *rp;
2994f927735SDavid du Colombier 
3004f927735SDavid du Colombier 	fd = create(file, OWRITE, 0666);
3014f927735SDavid du Colombier 	if(fd < 0)
3024f927735SDavid du Colombier 		return;
3034f927735SDavid du Colombier 
3044f927735SDavid du Colombier 	lock(&dnlock);
3054f8f669cSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
306219b2ee8SDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
307219b2ee8SDavid du Colombier 			fprint(fd, "%s\n", dp->name);
308225077b0SDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next) {
3096d8e4566SDavid du Colombier 				fprint(fd, "\t%R %c%c %lud/%lud\n",
3104f8f669cSDavid du Colombier 					rp, rp->auth? 'A': 'U',
3117dd7cddfSDavid du Colombier 					rp->db? 'D': 'N', rp->expire, rp->ttl);
312225077b0SDavid du Colombier 				if (rronlist(rp, rp->next))
313225077b0SDavid du Colombier 					fprint(fd, "*** duplicate:\n");
314225077b0SDavid du Colombier 			}
315219b2ee8SDavid du Colombier 		}
316219b2ee8SDavid du Colombier 	unlock(&dnlock);
317219b2ee8SDavid du Colombier 	close(fd);
318219b2ee8SDavid du Colombier }
319219b2ee8SDavid du Colombier 
320219b2ee8SDavid du Colombier /*
3217dd7cddfSDavid du Colombier  *  purge all records
3227dd7cddfSDavid du Colombier  */
3237dd7cddfSDavid du Colombier void
3247dd7cddfSDavid du Colombier dnpurge(void)
3257dd7cddfSDavid du Colombier {
3267dd7cddfSDavid du Colombier 	DN *dp;
327a4285193SDavid du Colombier 	RR *rp, *srp;
3287dd7cddfSDavid du Colombier 	int i;
3297dd7cddfSDavid du Colombier 
3307dd7cddfSDavid du Colombier 	lock(&dnlock);
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
3337dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
334a4285193SDavid du Colombier 			srp = rp = dp->rr;
3357dd7cddfSDavid du Colombier 			dp->rr = nil;
3367dd7cddfSDavid du Colombier 			for(; rp != nil; rp = rp->next)
3377dd7cddfSDavid du Colombier 				rp->cached = 0;
338a4285193SDavid du Colombier 			rrfreelist(srp);
3397dd7cddfSDavid du Colombier 		}
3407dd7cddfSDavid du Colombier 
3417dd7cddfSDavid du Colombier 	unlock(&dnlock);
3427dd7cddfSDavid du Colombier }
3437dd7cddfSDavid du Colombier 
344d2fd7a44SDavid du Colombier /*
345d2fd7a44SDavid du Colombier  *  delete rp from *l, free rp.
346d2fd7a44SDavid du Colombier  *  call with dnlock held.
347d2fd7a44SDavid du Colombier  */
348225077b0SDavid du Colombier static void
349225077b0SDavid du Colombier rrdelete(RR **l, RR *rp)
350225077b0SDavid du Colombier {
351225077b0SDavid du Colombier 	*l = rp->next;
352225077b0SDavid du Colombier 	rp->cached = 0;		/* avoid blowing an assertion in rrfree */
353225077b0SDavid du Colombier 	rrfree(rp);
354225077b0SDavid du Colombier }
355225077b0SDavid du Colombier 
3567dd7cddfSDavid du Colombier /*
357d2fd7a44SDavid du Colombier  *  check the age of resource records, free any that have timed out.
358d2fd7a44SDavid du Colombier  *  call with dnlock held.
3593e12c5d1SDavid du Colombier  */
3603e12c5d1SDavid du Colombier void
3613e12c5d1SDavid du Colombier dnage(DN *dp)
3623e12c5d1SDavid du Colombier {
3633e12c5d1SDavid du Colombier 	RR **l;
3643e12c5d1SDavid du Colombier 	RR *rp, *next;
3657dd7cddfSDavid du Colombier 	ulong diff;
3663e12c5d1SDavid du Colombier 
3677dd7cddfSDavid du Colombier 	diff = now - dp->referenced;
3686dc4800dSDavid du Colombier 	if(diff < Reserved || dp->keep)
3697dd7cddfSDavid du Colombier 		return;
3707dd7cddfSDavid du Colombier 
3713e12c5d1SDavid du Colombier 	l = &dp->rr;
3723e12c5d1SDavid du Colombier 	for(rp = dp->rr; rp; rp = next){
3737dd7cddfSDavid du Colombier 		assert(rp->magic == RRmagic && rp->cached);
3743e12c5d1SDavid du Colombier 		next = rp->next;
375225077b0SDavid du Colombier 		if(!rp->db && (rp->expire < now || diff > dnvars.oldest))
376225077b0SDavid du Colombier 			rrdelete(l, rp);
377225077b0SDavid du Colombier 		else
3783e12c5d1SDavid du Colombier 			l = &rp->next;
3793e12c5d1SDavid du Colombier 	}
3803e12c5d1SDavid du Colombier }
3813e12c5d1SDavid du Colombier 
3826dc4800dSDavid du Colombier #define MARK(dp)	{ if (dp) (dp)->keep = 1; }
383a41547ffSDavid du Colombier 
384410ea80bSDavid du Colombier /* mark a domain name and those in its RRs as never to be aged */
385a41547ffSDavid du Colombier void
386410ea80bSDavid du Colombier dnagenever(DN *dp, int dolock)
387a41547ffSDavid du Colombier {
388a41547ffSDavid du Colombier 	RR *rp;
389a41547ffSDavid du Colombier 
390410ea80bSDavid du Colombier 	if (dolock)
391a41547ffSDavid du Colombier 		lock(&dnlock);
392a41547ffSDavid du Colombier 
393410ea80bSDavid du Colombier 	/* mark all referenced domain names */
394410ea80bSDavid du Colombier 	MARK(dp);
395a41547ffSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
396a41547ffSDavid du Colombier 		MARK(rp->owner);
397410ea80bSDavid du Colombier 		if(rp->negative){
398410ea80bSDavid du Colombier 			MARK(rp->negsoaowner);
399410ea80bSDavid du Colombier 			continue;
400410ea80bSDavid du Colombier 		}
401a41547ffSDavid du Colombier 		switch(rp->type){
402410ea80bSDavid du Colombier 		case Thinfo:
403410ea80bSDavid du Colombier 			MARK(rp->cpu);
404410ea80bSDavid du Colombier 			MARK(rp->os);
405410ea80bSDavid du Colombier 			break;
406410ea80bSDavid du Colombier 		case Ttxt:
407410ea80bSDavid du Colombier 			break;
408410ea80bSDavid du Colombier 		case Tcname:
409410ea80bSDavid du Colombier 		case Tmb:
410410ea80bSDavid du Colombier 		case Tmd:
411410ea80bSDavid du Colombier 		case Tmf:
412a41547ffSDavid du Colombier 		case Tns:
413410ea80bSDavid du Colombier 		case Tmx:
414410ea80bSDavid du Colombier 		case Tsrv:
415a41547ffSDavid du Colombier 			MARK(rp->host);
416a41547ffSDavid du Colombier 			break;
417410ea80bSDavid du Colombier 		case Tmg:
418410ea80bSDavid du Colombier 		case Tmr:
419410ea80bSDavid du Colombier 			MARK(rp->mb);
420410ea80bSDavid du Colombier 			break;
421410ea80bSDavid du Colombier 		case Tminfo:
422410ea80bSDavid du Colombier 			MARK(rp->rmb);
423410ea80bSDavid du Colombier 			MARK(rp->mb);
424410ea80bSDavid du Colombier 			break;
425410ea80bSDavid du Colombier 		case Trp:
426410ea80bSDavid du Colombier 			MARK(rp->rmb);
427410ea80bSDavid du Colombier 			MARK(rp->rp);
428410ea80bSDavid du Colombier 			break;
429410ea80bSDavid du Colombier 		case Ta:
430410ea80bSDavid du Colombier 		case Taaaa:
431410ea80bSDavid du Colombier 			MARK(rp->ip);
432410ea80bSDavid du Colombier 			break;
433410ea80bSDavid du Colombier 		case Tptr:
434410ea80bSDavid du Colombier 			MARK(rp->ptr);
435410ea80bSDavid du Colombier 			break;
436410ea80bSDavid du Colombier 		case Tsoa:
437410ea80bSDavid du Colombier 			MARK(rp->host);
438410ea80bSDavid du Colombier 			MARK(rp->rmb);
439410ea80bSDavid du Colombier 			break;
440a41547ffSDavid du Colombier 		}
441a41547ffSDavid du Colombier 	}
442410ea80bSDavid du Colombier 
443410ea80bSDavid du Colombier 	if (dolock)
444410ea80bSDavid du Colombier 		unlock(&dnlock);
4456dc4800dSDavid du Colombier }
446a41547ffSDavid du Colombier 
447410ea80bSDavid du Colombier /* mark all current domain names as never to be aged */
448410ea80bSDavid du Colombier void
449410ea80bSDavid du Colombier dnageallnever(void)
450410ea80bSDavid du Colombier {
451410ea80bSDavid du Colombier 	int i;
452410ea80bSDavid du Colombier 	DN *dp;
453410ea80bSDavid du Colombier 
454410ea80bSDavid du Colombier 	lock(&dnlock);
455410ea80bSDavid du Colombier 
456410ea80bSDavid du Colombier 	/* mark all referenced domain names */
457410ea80bSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
458410ea80bSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next)
459410ea80bSDavid du Colombier 			dnagenever(dp, 0);
460410ea80bSDavid du Colombier 
461a41547ffSDavid du Colombier 	unlock(&dnlock);
462a41547ffSDavid du Colombier 
463a41547ffSDavid du Colombier 	dnslog("%ld initial domain names; target is %ld", dnvars.names, target);
464a41547ffSDavid du Colombier 	if(dnvars.names >= target)
465a41547ffSDavid du Colombier 		dnslog("more initial domain names (%ld) than target (%ld)",
466a41547ffSDavid du Colombier 			dnvars.names, target);
467a41547ffSDavid du Colombier }
468a41547ffSDavid du Colombier 
4696dc4800dSDavid du Colombier #define REF(dp)	{ if (dp) (dp)->refs++; }
4706dc4800dSDavid du Colombier 
4717dd7cddfSDavid du Colombier /*
4727dd7cddfSDavid du Colombier  *  periodicly sweep for old records and remove unreferenced domain names
4737dd7cddfSDavid du Colombier  *
4747dd7cddfSDavid du Colombier  *  only called when all other threads are locked out
4757dd7cddfSDavid du Colombier  */
4767dd7cddfSDavid du Colombier void
4777dd7cddfSDavid du Colombier dnageall(int doit)
4787dd7cddfSDavid du Colombier {
4797dd7cddfSDavid du Colombier 	DN *dp, **l;
480225077b0SDavid du Colombier 	int i;
4817dd7cddfSDavid du Colombier 	RR *rp;
4827dd7cddfSDavid du Colombier 	static ulong nextage;
4837dd7cddfSDavid du Colombier 
4844f8f669cSDavid du Colombier 	if(dnvars.names < target || (now < nextage && !doit)){
4857dd7cddfSDavid du Colombier 		dnvars.oldest = maxage;
4867dd7cddfSDavid du Colombier 		return;
4877dd7cddfSDavid du Colombier 	}
4887dd7cddfSDavid du Colombier 
4894f8f669cSDavid du Colombier 	if(dnvars.names >= target) {
4903cbadd90SDavid du Colombier 		dnslog("more names (%lud) than target (%lud)", dnvars.names,
4913cbadd90SDavid du Colombier 			target);
4927dd7cddfSDavid du Colombier 		dnvars.oldest /= 2;
49381730632SDavid du Colombier 		if (dnvars.oldest < Minage)
49481730632SDavid du Colombier 			dnvars.oldest = Minage;		/* don't be silly */
4954f8f669cSDavid du Colombier 	}
496f46c709fSDavid du Colombier 	if (agefreq > dnvars.oldest / 2)
497f46c709fSDavid du Colombier 		nextage = now + dnvars.oldest / 2;
498f46c709fSDavid du Colombier 	else
499f46c709fSDavid du Colombier 		nextage = now + agefreq;
5007dd7cddfSDavid du Colombier 
5017dd7cddfSDavid du Colombier 	lock(&dnlock);
5027dd7cddfSDavid du Colombier 
5037dd7cddfSDavid du Colombier 	/* time out all old entries (and set refs to 0) */
5047dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
5057dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
5067dd7cddfSDavid du Colombier 			dp->refs = 0;
5077dd7cddfSDavid du Colombier 			dnage(dp);
5087dd7cddfSDavid du Colombier 		}
5097dd7cddfSDavid du Colombier 
5107dd7cddfSDavid du Colombier 	/* mark all referenced domain names */
5117dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
5127dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next)
5137dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next){
5147dd7cddfSDavid du Colombier 				REF(rp->owner);
5157dd7cddfSDavid du Colombier 				if(rp->negative){
5167dd7cddfSDavid du Colombier 					REF(rp->negsoaowner);
5177dd7cddfSDavid du Colombier 					continue;
5187dd7cddfSDavid du Colombier 				}
5197dd7cddfSDavid du Colombier 				switch(rp->type){
5207dd7cddfSDavid du Colombier 				case Thinfo:
5217dd7cddfSDavid du Colombier 					REF(rp->cpu);
5227dd7cddfSDavid du Colombier 					REF(rp->os);
5237dd7cddfSDavid du Colombier 					break;
5247dd7cddfSDavid du Colombier 				case Ttxt:
5257dd7cddfSDavid du Colombier 					break;
5267dd7cddfSDavid du Colombier 				case Tcname:
5277dd7cddfSDavid du Colombier 				case Tmb:
5287dd7cddfSDavid du Colombier 				case Tmd:
5297dd7cddfSDavid du Colombier 				case Tmf:
5307dd7cddfSDavid du Colombier 				case Tns:
5314f8f669cSDavid du Colombier 				case Tmx:
532225077b0SDavid du Colombier 				case Tsrv:
5337dd7cddfSDavid du Colombier 					REF(rp->host);
5347dd7cddfSDavid du Colombier 					break;
5357dd7cddfSDavid du Colombier 				case Tmg:
5367dd7cddfSDavid du Colombier 				case Tmr:
5377dd7cddfSDavid du Colombier 					REF(rp->mb);
5387dd7cddfSDavid du Colombier 					break;
5397dd7cddfSDavid du Colombier 				case Tminfo:
5407dd7cddfSDavid du Colombier 					REF(rp->rmb);
5417dd7cddfSDavid du Colombier 					REF(rp->mb);
5427dd7cddfSDavid du Colombier 					break;
5437dd7cddfSDavid du Colombier 				case Trp:
5447dd7cddfSDavid du Colombier 					REF(rp->rmb);
54560845620SDavid du Colombier 					REF(rp->rp);
5467dd7cddfSDavid du Colombier 					break;
5477dd7cddfSDavid du Colombier 				case Ta:
5485d459b5aSDavid du Colombier 				case Taaaa:
5497dd7cddfSDavid du Colombier 					REF(rp->ip);
5507dd7cddfSDavid du Colombier 					break;
5517dd7cddfSDavid du Colombier 				case Tptr:
5527dd7cddfSDavid du Colombier 					REF(rp->ptr);
5537dd7cddfSDavid du Colombier 					break;
5547dd7cddfSDavid du Colombier 				case Tsoa:
5557dd7cddfSDavid du Colombier 					REF(rp->host);
5567dd7cddfSDavid du Colombier 					REF(rp->rmb);
5577dd7cddfSDavid du Colombier 					break;
5587dd7cddfSDavid du Colombier 				}
5597dd7cddfSDavid du Colombier 			}
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier 	/* sweep and remove unreferenced domain names */
5627dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++){
5637dd7cddfSDavid du Colombier 		l = &ht[i];
5647dd7cddfSDavid du Colombier 		for(dp = *l; dp; dp = *l){
565a41547ffSDavid du Colombier 			if(dp->rr == 0 && dp->refs == 0 && !dp->keep){
56634f77ae3SDavid du Colombier 				assert(dp->magic == DNmagic);
5677dd7cddfSDavid du Colombier 				*l = dp->next;
5684f8f669cSDavid du Colombier 
5697dd7cddfSDavid du Colombier 				if(dp->name)
5707dd7cddfSDavid du Colombier 					free(dp->name);
57134f77ae3SDavid du Colombier 				dp->magic = ~dp->magic;
5727dd7cddfSDavid du Colombier 				dnvars.names--;
5734f8f669cSDavid du Colombier 				memset(dp, 0, sizeof *dp); /* cause trouble */
5747dd7cddfSDavid du Colombier 				free(dp);
5754f8f669cSDavid du Colombier 
5767dd7cddfSDavid du Colombier 				continue;
5777dd7cddfSDavid du Colombier 			}
5787dd7cddfSDavid du Colombier 			l = &dp->next;
5797dd7cddfSDavid du Colombier 		}
5807dd7cddfSDavid du Colombier 	}
5817dd7cddfSDavid du Colombier 
5827dd7cddfSDavid du Colombier 	unlock(&dnlock);
5837dd7cddfSDavid du Colombier }
5847dd7cddfSDavid du Colombier 
5857dd7cddfSDavid du Colombier /*
5867dd7cddfSDavid du Colombier  *  timeout all database records (used when rereading db)
5877dd7cddfSDavid du Colombier  */
5887dd7cddfSDavid du Colombier void
5897dd7cddfSDavid du Colombier dnagedb(void)
5907dd7cddfSDavid du Colombier {
5917dd7cddfSDavid du Colombier 	DN *dp;
5927dd7cddfSDavid du Colombier 	int i;
5937dd7cddfSDavid du Colombier 	RR *rp;
5947dd7cddfSDavid du Colombier 
5957dd7cddfSDavid du Colombier 	lock(&dnlock);
5967dd7cddfSDavid du Colombier 
5977dd7cddfSDavid du Colombier 	/* time out all database entries */
5987dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
599410ea80bSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next) {
600410ea80bSDavid du Colombier 			dp->keep = 0;
6017dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next)
6027dd7cddfSDavid du Colombier 				if(rp->db)
6037dd7cddfSDavid du Colombier 					rp->expire = 0;
604410ea80bSDavid du Colombier 		}
6057dd7cddfSDavid du Colombier 
6067dd7cddfSDavid du Colombier 	unlock(&dnlock);
6077dd7cddfSDavid du Colombier }
6087dd7cddfSDavid du Colombier 
6097dd7cddfSDavid du Colombier /*
6104f8f669cSDavid du Colombier  *  mark all local db records about my area as authoritative,
6114f8f669cSDavid du Colombier  *  time out any others
6127dd7cddfSDavid du Colombier  */
6137dd7cddfSDavid du Colombier void
6147dd7cddfSDavid du Colombier dnauthdb(void)
6157dd7cddfSDavid du Colombier {
6166b0d5c8bSDavid du Colombier 	int i;
6174f8f669cSDavid du Colombier 	ulong minttl;
6186b0d5c8bSDavid du Colombier 	Area *area;
6194f8f669cSDavid du Colombier 	DN *dp;
6207dd7cddfSDavid du Colombier 	RR *rp;
6217dd7cddfSDavid du Colombier 
6227dd7cddfSDavid du Colombier 	lock(&dnlock);
6237dd7cddfSDavid du Colombier 
6247dd7cddfSDavid du Colombier 	/* time out all database entries */
6257dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
6267dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
6277dd7cddfSDavid du Colombier 			area = inmyarea(dp->name);
6287dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next)
6297dd7cddfSDavid du Colombier 				if(rp->db){
6307dd7cddfSDavid du Colombier 					if(area){
6314f8f669cSDavid du Colombier 						minttl = area->soarr->soa->minttl;
6324f8f669cSDavid du Colombier 						if(rp->ttl < minttl)
6334f8f669cSDavid du Colombier 							rp->ttl = minttl;
6347dd7cddfSDavid du Colombier 						rp->auth = 1;
6357dd7cddfSDavid du Colombier 					}
6367dd7cddfSDavid du Colombier 					if(rp->expire == 0){
6377dd7cddfSDavid du Colombier 						rp->db = 0;
6387dd7cddfSDavid du Colombier 						dp->referenced = now-Reserved-1;
6397dd7cddfSDavid du Colombier 					}
6407dd7cddfSDavid du Colombier 				}
6417dd7cddfSDavid du Colombier 		}
6427dd7cddfSDavid du Colombier 
6437dd7cddfSDavid du Colombier 	unlock(&dnlock);
6447dd7cddfSDavid du Colombier }
6457dd7cddfSDavid du Colombier 
6467dd7cddfSDavid du Colombier /*
6477dd7cddfSDavid du Colombier  *  keep track of other processes to know if we can
6487dd7cddfSDavid du Colombier  *  garbage collect.  block while garbage collecting.
6497dd7cddfSDavid du Colombier  */
6507dd7cddfSDavid du Colombier int
651b4b9fc2fSDavid du Colombier getactivity(Request *req, int recursive)
6527dd7cddfSDavid du Colombier {
6537dd7cddfSDavid du Colombier 	int rv;
6547dd7cddfSDavid du Colombier 
6554f8f669cSDavid du Colombier 	if(traceactivity)
6564f8f669cSDavid du Colombier 		dnslog("get: %d active by pid %d from %p",
6574f8f669cSDavid du Colombier 			dnvars.active, getpid(), getcallerpc(&req));
6587dd7cddfSDavid du Colombier 	lock(&dnvars);
659b4b9fc2fSDavid du Colombier 	/*
660b4b9fc2fSDavid du Colombier 	 * can't block here if we're already holding one
661b4b9fc2fSDavid du Colombier 	 * of the dnvars.active (recursive).  will deadlock.
662b4b9fc2fSDavid du Colombier 	 */
663b4b9fc2fSDavid du Colombier 	while(!recursive && dnvars.mutex){
6647dd7cddfSDavid du Colombier 		unlock(&dnvars);
665d6d99297SDavid du Colombier 		sleep(100);			/* tune; was 200 */
6667dd7cddfSDavid du Colombier 		lock(&dnvars);
6677dd7cddfSDavid du Colombier 	}
6687dd7cddfSDavid du Colombier 	rv = ++dnvars.active;
6694f8f669cSDavid du Colombier 	now = time(nil);
670a41547ffSDavid du Colombier 	nowns = nsec();
6717dd7cddfSDavid du Colombier 	req->id = ++dnvars.id;
6727dd7cddfSDavid du Colombier 	unlock(&dnvars);
6737dd7cddfSDavid du Colombier 
6747dd7cddfSDavid du Colombier 	return rv;
6757dd7cddfSDavid du Colombier }
6767dd7cddfSDavid du Colombier void
677b4b9fc2fSDavid du Colombier putactivity(int recursive)
6787dd7cddfSDavid du Colombier {
6797dd7cddfSDavid du Colombier 	static ulong lastclean;
6807dd7cddfSDavid du Colombier 
6814f8f669cSDavid du Colombier 	if(traceactivity)
6824f8f669cSDavid du Colombier 		dnslog("put: %d active by pid %d",
6834f8f669cSDavid du Colombier 			dnvars.active, getpid());
6847dd7cddfSDavid du Colombier 	lock(&dnvars);
6857dd7cddfSDavid du Colombier 	dnvars.active--;
6864f8f669cSDavid du Colombier 	assert(dnvars.active >= 0); /* "dnvars.active %d", dnvars.active */
6877dd7cddfSDavid du Colombier 
6887dd7cddfSDavid du Colombier 	/*
6897dd7cddfSDavid du Colombier 	 *  clean out old entries and check for new db periodicly
690b4b9fc2fSDavid du Colombier 	 *  can't block here if being called to let go a "recursive" lock
691b4b9fc2fSDavid du Colombier 	 *  or we'll deadlock waiting for ourselves to give up the dnvars.active.
6927dd7cddfSDavid du Colombier 	 */
6934f8f669cSDavid du Colombier 	if (recursive || dnvars.mutex ||
6944f8f669cSDavid du Colombier 	    (needrefresh == 0 && dnvars.active > 0)){
6957dd7cddfSDavid du Colombier 		unlock(&dnvars);
6967dd7cddfSDavid du Colombier 		return;
6977dd7cddfSDavid du Colombier 	}
6987dd7cddfSDavid du Colombier 
6997dd7cddfSDavid du Colombier 	/* wait till we're alone */
7007dd7cddfSDavid du Colombier 	dnvars.mutex = 1;
7017dd7cddfSDavid du Colombier 	while(dnvars.active > 0){
7027dd7cddfSDavid du Colombier 		unlock(&dnvars);
703d6d99297SDavid du Colombier 		sleep(100);		/* tune; was 100 */
7047dd7cddfSDavid du Colombier 		lock(&dnvars);
7057dd7cddfSDavid du Colombier 	}
7067dd7cddfSDavid du Colombier 	unlock(&dnvars);
7077dd7cddfSDavid du Colombier 
7087dd7cddfSDavid du Colombier 	db2cache(needrefresh);
7097dd7cddfSDavid du Colombier 	dnageall(0);
7107dd7cddfSDavid du Colombier 
7117dd7cddfSDavid du Colombier 	/* let others back in */
7127dd7cddfSDavid du Colombier 	lastclean = now;
7137dd7cddfSDavid du Colombier 	needrefresh = 0;
7147dd7cddfSDavid du Colombier 	dnvars.mutex = 0;
7157dd7cddfSDavid du Colombier }
7167dd7cddfSDavid du Colombier 
717d2fd7a44SDavid du Colombier int
718d2fd7a44SDavid du Colombier rrlistlen(RR *rp)
719d2fd7a44SDavid du Colombier {
720d2fd7a44SDavid du Colombier 	int n;
721d2fd7a44SDavid du Colombier 
722d2fd7a44SDavid du Colombier 	n = 0;
723d2fd7a44SDavid du Colombier 	for(; rp; rp = rp->next)
724d2fd7a44SDavid du Colombier 		++n;
725d2fd7a44SDavid du Colombier 	return n;
726d2fd7a44SDavid du Colombier }
727d2fd7a44SDavid du Colombier 
7283e12c5d1SDavid du Colombier /*
7296dc4800dSDavid du Colombier  *  Attach a single resource record to a domain name (new->owner).
7303e12c5d1SDavid du Colombier  *	- Avoid duplicates with already present RR's
7313e12c5d1SDavid du Colombier  *	- Chain all RR's of the same type adjacent to one another
7323e12c5d1SDavid du Colombier  *	- chain authoritative RR's ahead of non-authoritative ones
7336dc4800dSDavid du Colombier  *	- remove any expired RR's
734225077b0SDavid du Colombier  *  If new is a stale duplicate, rrfree it.
7356dc4800dSDavid du Colombier  *  Must be called with dnlock held.
7363e12c5d1SDavid du Colombier  */
7373e12c5d1SDavid du Colombier static void
7383e12c5d1SDavid du Colombier rrattach1(RR *new, int auth)
7393e12c5d1SDavid du Colombier {
7403e12c5d1SDavid du Colombier 	RR **l;
7413e12c5d1SDavid du Colombier 	RR *rp;
7423e12c5d1SDavid du Colombier 	DN *dp;
7433e12c5d1SDavid du Colombier 
7447dd7cddfSDavid du Colombier 	assert(new->magic == RRmagic && !new->cached);
7457dd7cddfSDavid du Colombier 
7464f8f669cSDavid du Colombier //	dnslog("rrattach1: %s", new->owner->name);
747e9b54818SDavid du Colombier 	if(!new->db) {
748e9b54818SDavid du Colombier 		/*
749e9b54818SDavid du Colombier 		 * try not to let responses expire before we
750e9b54818SDavid du Colombier 		 * can use them to complete this query, by extending
751e464c1a8SDavid du Colombier 		 * past (or nearly past) expiration time.
752e9b54818SDavid du Colombier 		 */
753e464c1a8SDavid du Colombier 		new->expire = new->ttl > now + Min? new->ttl: now + 10*Min;
754e9b54818SDavid du Colombier 	} else
7557dd7cddfSDavid du Colombier 		new->expire = now + Year;
7563e12c5d1SDavid du Colombier 	dp = new->owner;
7577dd7cddfSDavid du Colombier 	assert(dp->magic == DNmagic);
7587dd7cddfSDavid du Colombier 	new->auth |= auth;
7593e12c5d1SDavid du Colombier 	new->next = 0;
7603e12c5d1SDavid du Colombier 
7613e12c5d1SDavid du Colombier 	/*
7623ff48bf5SDavid du Colombier 	 *  find first rr of the right type
7633e12c5d1SDavid du Colombier 	 */
7643e12c5d1SDavid du Colombier 	l = &dp->rr;
7657dd7cddfSDavid du Colombier 	for(rp = *l; rp; rp = *l){
7667dd7cddfSDavid du Colombier 		assert(rp->magic == RRmagic && rp->cached);
7673e12c5d1SDavid du Colombier 		if(rp->type == new->type)
7683e12c5d1SDavid du Colombier 			break;
7693e12c5d1SDavid du Colombier 		l = &rp->next;
7703e12c5d1SDavid du Colombier 	}
7713e12c5d1SDavid du Colombier 
7723e12c5d1SDavid du Colombier 	/*
7737dd7cddfSDavid du Colombier 	 *  negative entries replace positive entries
7747dd7cddfSDavid du Colombier 	 *  positive entries replace negative entries
7757dd7cddfSDavid du Colombier 	 *  newer entries replace older entries with the same fields
776225077b0SDavid du Colombier 	 *
777225077b0SDavid du Colombier 	 *  look farther ahead than just the next entry when looking
778225077b0SDavid du Colombier 	 *  for duplicates; RRs of a given type can have different rdata
779225077b0SDavid du Colombier 	 *  fields (e.g. multiple NS servers).
7803e12c5d1SDavid du Colombier 	 */
781225077b0SDavid du Colombier 	while ((rp = *l) != nil){
7827dd7cddfSDavid du Colombier 		assert(rp->magic == RRmagic && rp->cached);
7837dd7cddfSDavid du Colombier 		if(rp->type != new->type)
7843e12c5d1SDavid du Colombier 			break;
7857dd7cddfSDavid du Colombier 
7867dd7cddfSDavid du Colombier 		if(rp->db == new->db && rp->auth == new->auth){
7877dd7cddfSDavid du Colombier 			/* negative drives out positive and vice versa */
7887dd7cddfSDavid du Colombier 			if(rp->negative != new->negative) {
789225077b0SDavid du Colombier 				rrdelete(l, rp);
790225077b0SDavid du Colombier 				continue;		/* *l == rp->next */
7913e12c5d1SDavid du Colombier 			}
7927dd7cddfSDavid du Colombier 			/* all things equal, pick the newer one */
793225077b0SDavid du Colombier 			else if(rp->arg0 == new->arg0 && rp->arg1 == new->arg1){
7947dd7cddfSDavid du Colombier 				/* new drives out old */
795225077b0SDavid du Colombier 				if (new->ttl <= rp->ttl &&
796225077b0SDavid du Colombier 				    new->expire <= rp->expire) {
7973e12c5d1SDavid du Colombier 					rrfree(new);
7983e12c5d1SDavid du Colombier 					return;
7993e12c5d1SDavid du Colombier 				}
800225077b0SDavid du Colombier 				rrdelete(l, rp);
801225077b0SDavid du Colombier 				continue;		/* *l == rp->next */
8027dd7cddfSDavid du Colombier 			}
803225077b0SDavid du Colombier 			/*
804225077b0SDavid du Colombier 			 *  Hack for pointer records.  This makes sure
8053ff48bf5SDavid du Colombier 			 *  the ordering in the list reflects the ordering
8063ff48bf5SDavid du Colombier 			 *  received or read from the database
8073ff48bf5SDavid du Colombier 			 */
808225077b0SDavid du Colombier 			else if(rp->type == Tptr &&
809225077b0SDavid du Colombier 			    !rp->negative && !new->negative &&
810225077b0SDavid du Colombier 			    rp->ptr->ordinal > new->ptr->ordinal)
8113ff48bf5SDavid du Colombier 				break;
8123ff48bf5SDavid du Colombier 		}
8133e12c5d1SDavid du Colombier 		l = &rp->next;
8143e12c5d1SDavid du Colombier 	}
8153e12c5d1SDavid du Colombier 
816530fef66SDavid du Colombier 	if (rronlist(new, rp)) {
8174f927735SDavid du Colombier 		/* should not happen; duplicates were processed above */
818530fef66SDavid du Colombier 		dnslog("adding duplicate %R to list of %R; aborting", new, rp);
8194f927735SDavid du Colombier 		abort();
8204f927735SDavid du Colombier 	}
8213e12c5d1SDavid du Colombier 	/*
8223e12c5d1SDavid du Colombier 	 *  add to chain
8233e12c5d1SDavid du Colombier 	 */
8247dd7cddfSDavid du Colombier 	new->cached = 1;
825530fef66SDavid du Colombier 	new->next = rp;
8263e12c5d1SDavid du Colombier 	*l = new;
8273e12c5d1SDavid du Colombier }
8283e12c5d1SDavid du Colombier 
8293e12c5d1SDavid du Colombier /*
8303e12c5d1SDavid du Colombier  *  Attach a list of resource records to a domain name.
831225077b0SDavid du Colombier  *  May rrfree any stale duplicate RRs; dismembers the list.
832225077b0SDavid du Colombier  *  Upon return, every RR in the list will have been rrfree-d
833225077b0SDavid du Colombier  *  or attached to its domain name.
8346dc4800dSDavid du Colombier  *  See rrattach1 for properties preserved.
8353e12c5d1SDavid du Colombier  */
8363e12c5d1SDavid du Colombier void
8373e12c5d1SDavid du Colombier rrattach(RR *rp, int auth)
8383e12c5d1SDavid du Colombier {
8393e12c5d1SDavid du Colombier 	RR *next;
840d2fd7a44SDavid du Colombier 	DN *dp;
8413e12c5d1SDavid du Colombier 
842bd389b36SDavid du Colombier 	lock(&dnlock);
8433e12c5d1SDavid du Colombier 	for(; rp; rp = next){
8443e12c5d1SDavid du Colombier 		next = rp->next;
8454f8f669cSDavid du Colombier 		rp->next = nil;
846d2fd7a44SDavid du Colombier 		dp = rp->owner;
8477dd7cddfSDavid du Colombier 
8487dd7cddfSDavid du Colombier 		/* avoid any outside spoofing */
8494f8f669cSDavid du Colombier //		dnslog("rrattach: %s", rp->owner->name);
8504f8f669cSDavid du Colombier 		if(cfg.cachedb && !rp->db && inmyarea(rp->owner->name))
8517dd7cddfSDavid du Colombier 			rrfree(rp);
852d2fd7a44SDavid du Colombier 		else {
853530fef66SDavid du Colombier 			/* ameliorate the memory leak */
854530fef66SDavid du Colombier 			if (0 && rrlistlen(dp->rr) > 50 && !dp->keep) {
855530fef66SDavid du Colombier 				dnslog("rrattach(%s): rr list too long; "
856530fef66SDavid du Colombier 					"freeing it", dp->name);
857530fef66SDavid du Colombier 				rrfreelist(dp->rr);
858530fef66SDavid du Colombier 				dp->rr = nil;
859530fef66SDavid du Colombier 			} else
860530fef66SDavid du Colombier 				USED(dp);
8613e12c5d1SDavid du Colombier 			rrattach1(rp, auth);
862d2fd7a44SDavid du Colombier 		}
8633e12c5d1SDavid du Colombier 	}
864bd389b36SDavid du Colombier 	unlock(&dnlock);
8653e12c5d1SDavid du Colombier }
8663e12c5d1SDavid du Colombier 
867530fef66SDavid du Colombier /* should be called with dnlock held */
8684f8f669cSDavid du Colombier RR**
8697dd7cddfSDavid du Colombier rrcopy(RR *rp, RR **last)
8707dd7cddfSDavid du Colombier {
8714f8f669cSDavid du Colombier 	Cert *cert;
8724f8f669cSDavid du Colombier 	Key *key;
8734f8f669cSDavid du Colombier 	Null *null;
8747dd7cddfSDavid du Colombier 	RR *nrp;
8757dd7cddfSDavid du Colombier 	SOA *soa;
8769a747e4fSDavid du Colombier 	Sig *sig;
87760845620SDavid du Colombier 	Txt *t, *nt, **l;
8787dd7cddfSDavid du Colombier 
8797dd7cddfSDavid du Colombier 	nrp = rralloc(rp->type);
880a41547ffSDavid du Colombier 	setmalloctag(nrp, getcallerpc(&rp));
8819a747e4fSDavid du Colombier 	switch(rp->type){
88260845620SDavid du Colombier 	case Ttxt:
88360845620SDavid du Colombier 		*nrp = *rp;
88460845620SDavid du Colombier 		l = &nrp->txt;
88560845620SDavid du Colombier 		*l = nil;
88660845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next){
88760845620SDavid du Colombier 			nt = emalloc(sizeof(*nt));
88860845620SDavid du Colombier 			nt->p = estrdup(t->p);
88960845620SDavid du Colombier 			nt->next = nil;
89060845620SDavid du Colombier 			*l = nt;
89160845620SDavid du Colombier 			l = &nt->next;
89260845620SDavid du Colombier 		}
89360845620SDavid du Colombier 		break;
8949a747e4fSDavid du Colombier 	case Tsoa:
8957dd7cddfSDavid du Colombier 		soa = nrp->soa;
8967dd7cddfSDavid du Colombier 		*nrp = *rp;
8977dd7cddfSDavid du Colombier 		nrp->soa = soa;
8987dd7cddfSDavid du Colombier 		*nrp->soa = *rp->soa;
899dc5a79c1SDavid du Colombier 		nrp->soa->slaves = copyserverlist(rp->soa->slaves);
9009a747e4fSDavid du Colombier 		break;
9014f8f669cSDavid du Colombier 	case Tsrv:
9024f8f669cSDavid du Colombier 		*nrp = *rp;
903fd87a217SDavid du Colombier 		nrp->srv = emalloc(sizeof *nrp->srv);
9044f8f669cSDavid du Colombier 		*nrp->srv = *rp->srv;
9054f8f669cSDavid du Colombier 		break;
9069a747e4fSDavid du Colombier 	case Tkey:
9079a747e4fSDavid du Colombier 		key = nrp->key;
9089a747e4fSDavid du Colombier 		*nrp = *rp;
9099a747e4fSDavid du Colombier 		nrp->key = key;
9109a747e4fSDavid du Colombier 		*key = *rp->key;
9119a747e4fSDavid du Colombier 		key->data = emalloc(key->dlen);
9129a747e4fSDavid du Colombier 		memmove(key->data, rp->key->data, rp->key->dlen);
9139a747e4fSDavid du Colombier 		break;
9149a747e4fSDavid du Colombier 	case Tsig:
9159a747e4fSDavid du Colombier 		sig = nrp->sig;
9169a747e4fSDavid du Colombier 		*nrp = *rp;
9179a747e4fSDavid du Colombier 		nrp->sig = sig;
9189a747e4fSDavid du Colombier 		*sig = *rp->sig;
9199a747e4fSDavid du Colombier 		sig->data = emalloc(sig->dlen);
9209a747e4fSDavid du Colombier 		memmove(sig->data, rp->sig->data, rp->sig->dlen);
9219a747e4fSDavid du Colombier 		break;
9229a747e4fSDavid du Colombier 	case Tcert:
9239a747e4fSDavid du Colombier 		cert = nrp->cert;
9249a747e4fSDavid du Colombier 		*nrp = *rp;
9259a747e4fSDavid du Colombier 		nrp->cert = cert;
9269a747e4fSDavid du Colombier 		*cert = *rp->cert;
9279a747e4fSDavid du Colombier 		cert->data = emalloc(cert->dlen);
9289a747e4fSDavid du Colombier 		memmove(cert->data, rp->cert->data, rp->cert->dlen);
9299a747e4fSDavid du Colombier 		break;
9309a747e4fSDavid du Colombier 	case Tnull:
9319a747e4fSDavid du Colombier 		null = nrp->null;
9329a747e4fSDavid du Colombier 		*nrp = *rp;
9339a747e4fSDavid du Colombier 		nrp->null = null;
9349a747e4fSDavid du Colombier 		*null = *rp->null;
9359a747e4fSDavid du Colombier 		null->data = emalloc(null->dlen);
9369a747e4fSDavid du Colombier 		memmove(null->data, rp->null->data, rp->null->dlen);
9379a747e4fSDavid du Colombier 		break;
9389a747e4fSDavid du Colombier 	default:
9399a747e4fSDavid du Colombier 		*nrp = *rp;
9409a747e4fSDavid du Colombier 		break;
9417dd7cddfSDavid du Colombier 	}
9427dd7cddfSDavid du Colombier 	nrp->cached = 0;
9437dd7cddfSDavid du Colombier 	nrp->next = 0;
9447dd7cddfSDavid du Colombier 	*last = nrp;
9457dd7cddfSDavid du Colombier 	return &nrp->next;
9467dd7cddfSDavid du Colombier }
9477dd7cddfSDavid du Colombier 
9483e12c5d1SDavid du Colombier /*
9493e12c5d1SDavid du Colombier  *  lookup a resource record of a particular type and
9507dd7cddfSDavid du Colombier  *  class attached to a domain name.  Return copies.
9517dd7cddfSDavid du Colombier  *
9527dd7cddfSDavid du Colombier  *  Priority ordering is:
9537dd7cddfSDavid du Colombier  *	db authoritative
9547dd7cddfSDavid du Colombier  *	not timed out network authoritative
9557dd7cddfSDavid du Colombier  *	not timed out network unauthoritative
9567dd7cddfSDavid du Colombier  *	unauthoritative db
9577dd7cddfSDavid du Colombier  *
95880ee5cbfSDavid du Colombier  *  if flag NOneg is set, don't return negative cached entries.
9597dd7cddfSDavid du Colombier  *  return nothing instead.
9603e12c5d1SDavid du Colombier  */
9613e12c5d1SDavid du Colombier RR*
9627dd7cddfSDavid du Colombier rrlookup(DN *dp, int type, int flag)
9633e12c5d1SDavid du Colombier {
9647dd7cddfSDavid du Colombier 	RR *rp, *first, **last;
9653e12c5d1SDavid du Colombier 
9667dd7cddfSDavid du Colombier 	assert(dp->magic == DNmagic);
9677dd7cddfSDavid du Colombier 
9687dd7cddfSDavid du Colombier 	first = 0;
9697dd7cddfSDavid du Colombier 	last = &first;
9707dd7cddfSDavid du Colombier 	lock(&dnlock);
9717dd7cddfSDavid du Colombier 
9727dd7cddfSDavid du Colombier 	/* try for an authoritative db entry */
9733e12c5d1SDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
9747dd7cddfSDavid du Colombier 		assert(rp->magic == RRmagic && rp->cached);
9757dd7cddfSDavid du Colombier 		if(rp->db)
9767dd7cddfSDavid du Colombier 		if(rp->auth)
977a41547ffSDavid du Colombier 		if(tsame(type, rp->type)) {
9784e5f5f32SDavid du Colombier 			last = rrcopy(rp, last);
979a41547ffSDavid du Colombier 			// setmalloctag(*last, getcallerpc(&dp));
980a41547ffSDavid du Colombier 		}
9813e12c5d1SDavid du Colombier 	}
9827dd7cddfSDavid du Colombier 	if(first)
9837dd7cddfSDavid du Colombier 		goto out;
9847dd7cddfSDavid du Colombier 
9854f8f669cSDavid du Colombier 	/* try for a living authoritative network entry */
9867dd7cddfSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
9877dd7cddfSDavid du Colombier 		if(!rp->db)
9887dd7cddfSDavid du Colombier 		if(rp->auth)
9897dd7cddfSDavid du Colombier 		if(rp->ttl + 60 > now)
9907dd7cddfSDavid du Colombier 		if(tsame(type, rp->type)){
9917dd7cddfSDavid du Colombier 			if(flag == NOneg && rp->negative)
9927dd7cddfSDavid du Colombier 				goto out;
9937dd7cddfSDavid du Colombier 			last = rrcopy(rp, last);
9947dd7cddfSDavid du Colombier 		}
9957dd7cddfSDavid du Colombier 	}
9967dd7cddfSDavid du Colombier 	if(first)
9977dd7cddfSDavid du Colombier 		goto out;
9987dd7cddfSDavid du Colombier 
9994f8f669cSDavid du Colombier 	/* try for a living unauthoritative network entry */
10007dd7cddfSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
10017dd7cddfSDavid du Colombier 		if(!rp->db)
10027dd7cddfSDavid du Colombier 		if(rp->ttl + 60 > now)
10037dd7cddfSDavid du Colombier 		if(tsame(type, rp->type)){
10047dd7cddfSDavid du Colombier 			if(flag == NOneg && rp->negative)
10057dd7cddfSDavid du Colombier 				goto out;
10064e5f5f32SDavid du Colombier 			last = rrcopy(rp, last);
10077dd7cddfSDavid du Colombier 		}
10087dd7cddfSDavid du Colombier 	}
10097dd7cddfSDavid du Colombier 	if(first)
10107dd7cddfSDavid du Colombier 		goto out;
10117dd7cddfSDavid du Colombier 
10127dd7cddfSDavid du Colombier 	/* try for an unauthoritative db entry */
10137dd7cddfSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
10147dd7cddfSDavid du Colombier 		if(rp->db)
10157dd7cddfSDavid du Colombier 		if(tsame(type, rp->type))
10167dd7cddfSDavid du Colombier 			last = rrcopy(rp, last);
10177dd7cddfSDavid du Colombier 	}
10187dd7cddfSDavid du Colombier 	if(first)
10197dd7cddfSDavid du Colombier 		goto out;
10207dd7cddfSDavid du Colombier 
10217dd7cddfSDavid du Colombier 	/* otherwise, settle for anything we got (except for negative caches) */
10224f8f669cSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next)
10237dd7cddfSDavid du Colombier 		if(tsame(type, rp->type)){
10247dd7cddfSDavid du Colombier 			if(rp->negative)
10257dd7cddfSDavid du Colombier 				goto out;
10267dd7cddfSDavid du Colombier 			last = rrcopy(rp, last);
10277dd7cddfSDavid du Colombier 		}
10287dd7cddfSDavid du Colombier 
10297dd7cddfSDavid du Colombier out:
10307dd7cddfSDavid du Colombier 	unlock(&dnlock);
10317dd7cddfSDavid du Colombier 	unique(first);
10324f8f669cSDavid du Colombier //	dnslog("rrlookup(%s) -> %#p\t# in-core only", dp->name, first);
1033a41547ffSDavid du Colombier //	if (first)
1034a41547ffSDavid du Colombier //		setmalloctag(first, getcallerpc(&dp));
10357dd7cddfSDavid du Colombier 	return first;
10363e12c5d1SDavid du Colombier }
10373e12c5d1SDavid du Colombier 
10383e12c5d1SDavid du Colombier /*
10393e12c5d1SDavid du Colombier  *  convert an ascii RR type name to its integer representation
10403e12c5d1SDavid du Colombier  */
10413e12c5d1SDavid du Colombier int
10423e12c5d1SDavid du Colombier rrtype(char *atype)
10433e12c5d1SDavid du Colombier {
10443e12c5d1SDavid du Colombier 	int i;
10453e12c5d1SDavid du Colombier 
1046219b2ee8SDavid du Colombier 	for(i = 0; i <= Tall; i++)
10473e12c5d1SDavid du Colombier 		if(rrtname[i] && strcmp(rrtname[i], atype) == 0)
10483e12c5d1SDavid du Colombier 			return i;
10497dd7cddfSDavid du Colombier 
10504f8f669cSDavid du Colombier 	/* make any a synonym for all */
10517dd7cddfSDavid du Colombier 	if(strcmp(atype, "any") == 0)
10527dd7cddfSDavid du Colombier 		return Tall;
1053d9924332SDavid du Colombier 	else if(isascii(atype[0]) && isdigit(atype[0]))
10543e12c5d1SDavid du Colombier 		return atoi(atype);
1055d9924332SDavid du Colombier 	else
1056d9924332SDavid du Colombier 		return -1;
10573e12c5d1SDavid du Colombier }
10583e12c5d1SDavid du Colombier 
10593e12c5d1SDavid du Colombier /*
10605d459b5aSDavid du Colombier  *  return 0 if not a supported rr type
10615d459b5aSDavid du Colombier  */
10625d459b5aSDavid du Colombier int
10635d459b5aSDavid du Colombier rrsupported(int type)
10645d459b5aSDavid du Colombier {
10655d459b5aSDavid du Colombier 	if(type < 0 || type >Tall)
10665d459b5aSDavid du Colombier 		return 0;
10674f8f669cSDavid du Colombier 	return rrtname[type] != nil;
10685d459b5aSDavid du Colombier }
10695d459b5aSDavid du Colombier 
10705d459b5aSDavid du Colombier /*
1071219b2ee8SDavid du Colombier  *  compare 2 types
1072219b2ee8SDavid du Colombier  */
1073219b2ee8SDavid du Colombier int
1074219b2ee8SDavid du Colombier tsame(int t1, int t2)
1075219b2ee8SDavid du Colombier {
1076219b2ee8SDavid du Colombier 	return t1 == t2 || t1 == Tall;
1077219b2ee8SDavid du Colombier }
1078219b2ee8SDavid du Colombier 
1079219b2ee8SDavid du Colombier /*
10807dd7cddfSDavid du Colombier  *  Add resource records to a list, duplicate them if they are cached
1081530fef66SDavid du Colombier  *  RR's since these are shared.  should be called with dnlock held
1082530fef66SDavid du Colombier  *  to avoid racing down the start chain.
10833e12c5d1SDavid du Colombier  */
10843e12c5d1SDavid du Colombier RR*
10857dd7cddfSDavid du Colombier rrcat(RR **start, RR *rp)
10863e12c5d1SDavid du Colombier {
1087225077b0SDavid du Colombier 	RR *olp, *nlp;
10883e12c5d1SDavid du Colombier 	RR **last;
10893e12c5d1SDavid du Colombier 
1090225077b0SDavid du Colombier 	/* check for duplicates */
1091225077b0SDavid du Colombier 	for (olp = *start; 0 && olp; olp = olp->next)
1092225077b0SDavid du Colombier 		for (nlp = rp; nlp; nlp = nlp->next)
1093225077b0SDavid du Colombier 			if (rrsame(nlp, olp))
1094225077b0SDavid du Colombier 				dnslog("rrcat: duplicate RR: %R", nlp);
1095225077b0SDavid du Colombier 	USED(olp);
1096225077b0SDavid du Colombier 
10973e12c5d1SDavid du Colombier 	last = start;
10984f8f669cSDavid du Colombier 	while(*last != nil)
10993e12c5d1SDavid du Colombier 		last = &(*last)->next;
11003e12c5d1SDavid du Colombier 
11017dd7cddfSDavid du Colombier 	*last = rp;
11027dd7cddfSDavid du Colombier 	return *start;
11033e12c5d1SDavid du Colombier }
11043e12c5d1SDavid du Colombier 
11057dd7cddfSDavid du Colombier /*
11067dd7cddfSDavid du Colombier  *  remove negative cache rr's from an rr list
11077dd7cddfSDavid du Colombier  */
11087dd7cddfSDavid du Colombier RR*
11097dd7cddfSDavid du Colombier rrremneg(RR **l)
11107dd7cddfSDavid du Colombier {
11117dd7cddfSDavid du Colombier 	RR **nl, *rp;
11127dd7cddfSDavid du Colombier 	RR *first;
11137dd7cddfSDavid du Colombier 
11147dd7cddfSDavid du Colombier 	first = nil;
11157dd7cddfSDavid du Colombier 	nl = &first;
11167dd7cddfSDavid du Colombier 	while(*l != nil){
11177dd7cddfSDavid du Colombier 		rp = *l;
11187dd7cddfSDavid du Colombier 		if(rp->negative){
11197dd7cddfSDavid du Colombier 			*l = rp->next;
11207dd7cddfSDavid du Colombier 			*nl = rp;
11217dd7cddfSDavid du Colombier 			nl = &rp->next;
11227dd7cddfSDavid du Colombier 			*nl = nil;
11237dd7cddfSDavid du Colombier 		} else
112480ee5cbfSDavid du Colombier 			l = &rp->next;
11257dd7cddfSDavid du Colombier 	}
11267dd7cddfSDavid du Colombier 
11277dd7cddfSDavid du Colombier 	return first;
11287dd7cddfSDavid du Colombier }
11297dd7cddfSDavid du Colombier 
11307dd7cddfSDavid du Colombier /*
11317dd7cddfSDavid du Colombier  *  remove rr's of a particular type from an rr list
11327dd7cddfSDavid du Colombier  */
11337dd7cddfSDavid du Colombier RR*
11347dd7cddfSDavid du Colombier rrremtype(RR **l, int type)
11357dd7cddfSDavid du Colombier {
11364f8f669cSDavid du Colombier 	RR *first, *rp;
11374f8f669cSDavid du Colombier 	RR **nl;
11387dd7cddfSDavid du Colombier 
11397dd7cddfSDavid du Colombier 	first = nil;
11407dd7cddfSDavid du Colombier 	nl = &first;
11417dd7cddfSDavid du Colombier 	while(*l != nil){
11427dd7cddfSDavid du Colombier 		rp = *l;
11437dd7cddfSDavid du Colombier 		if(rp->type == type){
11447dd7cddfSDavid du Colombier 			*l = rp->next;
11457dd7cddfSDavid du Colombier 			*nl = rp;
11467dd7cddfSDavid du Colombier 			nl = &rp->next;
11477dd7cddfSDavid du Colombier 			*nl = nil;
11487dd7cddfSDavid du Colombier 		} else
11497dd7cddfSDavid du Colombier 			l = &(*l)->next;
11507dd7cddfSDavid du Colombier 	}
11517dd7cddfSDavid du Colombier 
11527dd7cddfSDavid du Colombier 	return first;
11533e12c5d1SDavid du Colombier }
11543e12c5d1SDavid du Colombier 
11554f8f669cSDavid du Colombier static char *
11564f8f669cSDavid du Colombier dnname(DN *dn)
11574f8f669cSDavid du Colombier {
11584f8f669cSDavid du Colombier 	return dn? dn->name: "<null>";
11594f8f669cSDavid du Colombier }
11604f8f669cSDavid du Colombier 
11613e12c5d1SDavid du Colombier /*
11623e12c5d1SDavid du Colombier  *  print conversion for rr records
11633e12c5d1SDavid du Colombier  */
11643e12c5d1SDavid du Colombier int
11659a747e4fSDavid du Colombier rrfmt(Fmt *f)
11663e12c5d1SDavid du Colombier {
11676b0d5c8bSDavid du Colombier 	int rv;
11684f8f669cSDavid du Colombier 	char *strp;
11696b0d5c8bSDavid du Colombier 	char buf[Domlen];
11704f8f669cSDavid du Colombier 	Fmt fstr;
11714f8f669cSDavid du Colombier 	RR *rp;
1172dc5a79c1SDavid du Colombier 	Server *s;
11734f8f669cSDavid du Colombier 	SOA *soa;
11744f8f669cSDavid du Colombier 	Srv *srv;
117560845620SDavid du Colombier 	Txt *t;
11763e12c5d1SDavid du Colombier 
11779a747e4fSDavid du Colombier 	fmtstrinit(&fstr);
11789a747e4fSDavid du Colombier 
11799a747e4fSDavid du Colombier 	rp = va_arg(f->args, RR*);
11804f8f669cSDavid du Colombier 	if(rp == nil){
11819a747e4fSDavid du Colombier 		fmtprint(&fstr, "<null>");
1182219b2ee8SDavid du Colombier 		goto out;
1183219b2ee8SDavid du Colombier 	}
1184219b2ee8SDavid du Colombier 
11854f8f669cSDavid du Colombier 	fmtprint(&fstr, "%s %s", dnname(rp->owner),
11869a747e4fSDavid du Colombier 		rrname(rp->type, buf, sizeof buf));
11877dd7cddfSDavid du Colombier 
11887dd7cddfSDavid du Colombier 	if(rp->negative){
11899a747e4fSDavid du Colombier 		fmtprint(&fstr, "\tnegative - rcode %d", rp->negrcode);
11907dd7cddfSDavid du Colombier 		goto out;
11917dd7cddfSDavid du Colombier 	}
11923e12c5d1SDavid du Colombier 
11933e12c5d1SDavid du Colombier 	switch(rp->type){
11943e12c5d1SDavid du Colombier 	case Thinfo:
11954f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s", dnname(rp->cpu), dnname(rp->os));
11963e12c5d1SDavid du Colombier 		break;
11973e12c5d1SDavid du Colombier 	case Tcname:
11983e12c5d1SDavid du Colombier 	case Tmb:
11993e12c5d1SDavid du Colombier 	case Tmd:
12003e12c5d1SDavid du Colombier 	case Tmf:
12013e12c5d1SDavid du Colombier 	case Tns:
12024f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->host));
12033e12c5d1SDavid du Colombier 		break;
12043e12c5d1SDavid du Colombier 	case Tmg:
12053e12c5d1SDavid du Colombier 	case Tmr:
12064f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->mb));
12073e12c5d1SDavid du Colombier 		break;
12083e12c5d1SDavid du Colombier 	case Tminfo:
12094f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s", dnname(rp->mb), dnname(rp->rmb));
12103e12c5d1SDavid du Colombier 		break;
12113e12c5d1SDavid du Colombier 	case Tmx:
12124f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%lud %s", rp->pref, dnname(rp->host));
12133e12c5d1SDavid du Colombier 		break;
12143e12c5d1SDavid du Colombier 	case Ta:
12155d459b5aSDavid du Colombier 	case Taaaa:
12164f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->ip));
12173e12c5d1SDavid du Colombier 		break;
12183e12c5d1SDavid du Colombier 	case Tptr:
12194f8f669cSDavid du Colombier //		fmtprint(&fstr, "\t%s(%lud)", dnname(rp->ptr),
12204f8f669cSDavid du Colombier //			rp->ptr? rp->ptr->ordinal: "<null>");
12214f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->ptr));
12223e12c5d1SDavid du Colombier 		break;
12233e12c5d1SDavid du Colombier 	case Tsoa:
12244f8f669cSDavid du Colombier 		soa = rp->soa;
12254f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s %lud %lud %lud %lud %lud",
12264f8f669cSDavid du Colombier 			dnname(rp->host), dnname(rp->rmb),
12274f8f669cSDavid du Colombier 			(soa? soa->serial: 0),
12284f8f669cSDavid du Colombier 			(soa? soa->refresh: 0), (soa? soa->retry: 0),
12294f8f669cSDavid du Colombier 			(soa? soa->expire: 0), (soa? soa->minttl: 0));
12304f8f669cSDavid du Colombier 		if (soa)
12314f8f669cSDavid du Colombier 			for(s = soa->slaves; s != nil; s = s->next)
1232dc5a79c1SDavid du Colombier 				fmtprint(&fstr, " %s", s->name);
12333e12c5d1SDavid du Colombier 		break;
12344f8f669cSDavid du Colombier 	case Tsrv:
12354f8f669cSDavid du Colombier 		srv = rp->srv;
12364f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%ud %ud %ud %s",
12374f8f669cSDavid du Colombier 			(srv? srv->pri: 0), (srv? srv->weight: 0),
1238225077b0SDavid du Colombier 			rp->port, dnname(rp->host));
12394f8f669cSDavid du Colombier 		break;
12409a747e4fSDavid du Colombier 	case Tnull:
12414f8f669cSDavid du Colombier 		if (rp->null == nil)
12424f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t<null>");
12434f8f669cSDavid du Colombier 		else
12444f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t%.*H", rp->null->dlen,
12454f8f669cSDavid du Colombier 				rp->null->data);
12469a747e4fSDavid du Colombier 		break;
12477dd7cddfSDavid du Colombier 	case Ttxt:
124860845620SDavid du Colombier 		fmtprint(&fstr, "\t");
124960845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next)
125060845620SDavid du Colombier 			fmtprint(&fstr, "%s", t->p);
12517dd7cddfSDavid du Colombier 		break;
12527dd7cddfSDavid du Colombier 	case Trp:
12534f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s", dnname(rp->rmb), dnname(rp->rp));
12547dd7cddfSDavid du Colombier 		break;
12557dd7cddfSDavid du Colombier 	case Tkey:
12564f8f669cSDavid du Colombier 		if (rp->key == nil)
12574f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t<null> <null> <null>");
12584f8f669cSDavid du Colombier 		else
12594f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t%d %d %d", rp->key->flags,
12604f8f669cSDavid du Colombier 				rp->key->proto, rp->key->alg);
12617dd7cddfSDavid du Colombier 		break;
12627dd7cddfSDavid du Colombier 	case Tsig:
12634f8f669cSDavid du Colombier 		if (rp->sig == nil)
12644f8f669cSDavid du Colombier 			fmtprint(&fstr,
12654f8f669cSDavid du Colombier 		   "\t<null> <null> <null> <null> <null> <null> <null> <null>");
12664f8f669cSDavid du Colombier 		else
12679a747e4fSDavid du Colombier 			fmtprint(&fstr, "\t%d %d %d %lud %lud %lud %d %s",
12684f8f669cSDavid du Colombier 				rp->sig->type, rp->sig->alg, rp->sig->labels,
12694f8f669cSDavid du Colombier 				rp->sig->ttl, rp->sig->exp, rp->sig->incep,
12704f8f669cSDavid du Colombier 				rp->sig->tag, dnname(rp->sig->signer));
12717dd7cddfSDavid du Colombier 		break;
12727dd7cddfSDavid du Colombier 	case Tcert:
12734f8f669cSDavid du Colombier 		if (rp->cert == nil)
12744f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t<null> <null> <null>");
12754f8f669cSDavid du Colombier 		else
12769a747e4fSDavid du Colombier 			fmtprint(&fstr, "\t%d %d %d",
12774f8f669cSDavid du Colombier 				rp->cert->type, rp->cert->tag, rp->cert->alg);
12783e12c5d1SDavid du Colombier 		break;
12793e12c5d1SDavid du Colombier 	}
1280219b2ee8SDavid du Colombier out:
12819a747e4fSDavid du Colombier 	strp = fmtstrflush(&fstr);
12829a747e4fSDavid du Colombier 	rv = fmtstrcpy(f, strp);
12839a747e4fSDavid du Colombier 	free(strp);
12849a747e4fSDavid du Colombier 	return rv;
12853e12c5d1SDavid du Colombier }
12863e12c5d1SDavid du Colombier 
12873e12c5d1SDavid du Colombier /*
12887dd7cddfSDavid du Colombier  *  print conversion for rr records in attribute value form
12897dd7cddfSDavid du Colombier  */
12907dd7cddfSDavid du Colombier int
12919a747e4fSDavid du Colombier rravfmt(Fmt *f)
12927dd7cddfSDavid du Colombier {
12934f8f669cSDavid du Colombier 	int rv, quote;
12949a747e4fSDavid du Colombier 	char *strp;
12959a747e4fSDavid du Colombier 	Fmt fstr;
12964f8f669cSDavid du Colombier 	RR *rp;
1297dc5a79c1SDavid du Colombier 	Server *s;
12984f8f669cSDavid du Colombier 	SOA *soa;
12994f8f669cSDavid du Colombier 	Srv *srv;
130060845620SDavid du Colombier 	Txt *t;
13017dd7cddfSDavid du Colombier 
13029a747e4fSDavid du Colombier 	fmtstrinit(&fstr);
13039a747e4fSDavid du Colombier 
13049a747e4fSDavid du Colombier 	rp = va_arg(f->args, RR*);
13054f8f669cSDavid du Colombier 	if(rp == nil){
13069a747e4fSDavid du Colombier 		fmtprint(&fstr, "<null>");
13077dd7cddfSDavid du Colombier 		goto out;
13087dd7cddfSDavid du Colombier 	}
13097dd7cddfSDavid du Colombier 
13107dd7cddfSDavid du Colombier 	if(rp->type == Tptr)
13114f8f669cSDavid du Colombier 		fmtprint(&fstr, "ptr=%s", dnname(rp->owner));
13127dd7cddfSDavid du Colombier 	else
13134f8f669cSDavid du Colombier 		fmtprint(&fstr, "dom=%s", dnname(rp->owner));
13147dd7cddfSDavid du Colombier 
13157dd7cddfSDavid du Colombier 	switch(rp->type){
13167dd7cddfSDavid du Colombier 	case Thinfo:
13174f8f669cSDavid du Colombier 		fmtprint(&fstr, " cpu=%s os=%s",
13184f8f669cSDavid du Colombier 			dnname(rp->cpu), dnname(rp->os));
13197dd7cddfSDavid du Colombier 		break;
13207dd7cddfSDavid du Colombier 	case Tcname:
13214f8f669cSDavid du Colombier 		fmtprint(&fstr, " cname=%s", dnname(rp->host));
13227dd7cddfSDavid du Colombier 		break;
13237dd7cddfSDavid du Colombier 	case Tmb:
13247dd7cddfSDavid du Colombier 	case Tmd:
13257dd7cddfSDavid du Colombier 	case Tmf:
13264f8f669cSDavid du Colombier 		fmtprint(&fstr, " mbox=%s", dnname(rp->host));
13277dd7cddfSDavid du Colombier 		break;
13287dd7cddfSDavid du Colombier 	case Tns:
13294f8f669cSDavid du Colombier 		fmtprint(&fstr,  " ns=%s", dnname(rp->host));
13307dd7cddfSDavid du Colombier 		break;
13317dd7cddfSDavid du Colombier 	case Tmg:
13327dd7cddfSDavid du Colombier 	case Tmr:
13334f8f669cSDavid du Colombier 		fmtprint(&fstr, " mbox=%s", dnname(rp->mb));
13347dd7cddfSDavid du Colombier 		break;
13357dd7cddfSDavid du Colombier 	case Tminfo:
13364f8f669cSDavid du Colombier 		fmtprint(&fstr, " mbox=%s mbox=%s",
13374f8f669cSDavid du Colombier 			dnname(rp->mb), dnname(rp->rmb));
13387dd7cddfSDavid du Colombier 		break;
13397dd7cddfSDavid du Colombier 	case Tmx:
13404f8f669cSDavid du Colombier 		fmtprint(&fstr, " pref=%lud mx=%s", rp->pref, dnname(rp->host));
13417dd7cddfSDavid du Colombier 		break;
13427dd7cddfSDavid du Colombier 	case Ta:
13435d459b5aSDavid du Colombier 	case Taaaa:
13444f8f669cSDavid du Colombier 		fmtprint(&fstr, " ip=%s", dnname(rp->ip));
13457dd7cddfSDavid du Colombier 		break;
13467dd7cddfSDavid du Colombier 	case Tptr:
13474f8f669cSDavid du Colombier 		fmtprint(&fstr, " dom=%s", dnname(rp->ptr));
13487dd7cddfSDavid du Colombier 		break;
13497dd7cddfSDavid du Colombier 	case Tsoa:
13504f8f669cSDavid du Colombier 		soa = rp->soa;
13514f8f669cSDavid du Colombier 		fmtprint(&fstr,
13524f8f669cSDavid du Colombier " ns=%s mbox=%s serial=%lud refresh=%lud retry=%lud expire=%lud ttl=%lud",
13534f8f669cSDavid du Colombier 			dnname(rp->host), dnname(rp->rmb),
13544f8f669cSDavid du Colombier 			(soa? soa->serial: 0),
13554f8f669cSDavid du Colombier 			(soa? soa->refresh: 0), (soa? soa->retry: 0),
13564f8f669cSDavid du Colombier 			(soa? soa->expire: 0), (soa? soa->minttl: 0));
13574f8f669cSDavid du Colombier 		for(s = soa->slaves; s != nil; s = s->next)
1358dc5a79c1SDavid du Colombier 			fmtprint(&fstr, " dnsslave=%s", s->name);
13597dd7cddfSDavid du Colombier 		break;
13604f8f669cSDavid du Colombier 	case Tsrv:
13614f8f669cSDavid du Colombier 		srv = rp->srv;
13624f8f669cSDavid du Colombier 		fmtprint(&fstr, " pri=%ud weight=%ud port=%ud target=%s",
13634f8f669cSDavid du Colombier 			(srv? srv->pri: 0), (srv? srv->weight: 0),
1364225077b0SDavid du Colombier 			rp->port, dnname(rp->host));
13654f8f669cSDavid du Colombier 		break;
13669a747e4fSDavid du Colombier 	case Tnull:
13674f8f669cSDavid du Colombier 		if (rp->null == nil)
13684f8f669cSDavid du Colombier 			fmtprint(&fstr, " null=<null>");
13694f8f669cSDavid du Colombier 		else
13704f8f669cSDavid du Colombier 			fmtprint(&fstr, " null=%.*H", rp->null->dlen,
13714f8f669cSDavid du Colombier 				rp->null->data);
13729a747e4fSDavid du Colombier 		break;
13737dd7cddfSDavid du Colombier 	case Ttxt:
137460845620SDavid du Colombier 		fmtprint(&fstr, " txt=");
137560845620SDavid du Colombier 		quote = 0;
137660845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next)
137760845620SDavid du Colombier 			if(strchr(t->p, ' '))
137860845620SDavid du Colombier 				quote = 1;
137960845620SDavid du Colombier 		if(quote)
138060845620SDavid du Colombier 			fmtprint(&fstr, "\"");
138160845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next)
138260845620SDavid du Colombier 			fmtprint(&fstr, "%s", t->p);
138360845620SDavid du Colombier 		if(quote)
138460845620SDavid du Colombier 			fmtprint(&fstr, "\"");
13857dd7cddfSDavid du Colombier 		break;
13867dd7cddfSDavid du Colombier 	case Trp:
13874f8f669cSDavid du Colombier 		fmtprint(&fstr, " rp=%s txt=%s",
13884f8f669cSDavid du Colombier 			dnname(rp->rmb), dnname(rp->rp));
13897dd7cddfSDavid du Colombier 		break;
13907dd7cddfSDavid du Colombier 	case Tkey:
13914f8f669cSDavid du Colombier 		if (rp->key == nil)
13924f8f669cSDavid du Colombier 			fmtprint(&fstr, " flags=<null> proto=<null> alg=<null>");
13934f8f669cSDavid du Colombier 		else
13949a747e4fSDavid du Colombier 			fmtprint(&fstr, " flags=%d proto=%d alg=%d",
13957dd7cddfSDavid du Colombier 				rp->key->flags, rp->key->proto, rp->key->alg);
13967dd7cddfSDavid du Colombier 		break;
13977dd7cddfSDavid du Colombier 	case Tsig:
13984f8f669cSDavid du Colombier 		if (rp->sig == nil)
13994f8f669cSDavid du Colombier 			fmtprint(&fstr,
14004f8f669cSDavid du Colombier " type=<null> alg=<null> labels=<null> ttl=<null> exp=<null> incep=<null> tag=<null> signer=<null>");
14014f8f669cSDavid du Colombier 		else
14024f8f669cSDavid du Colombier 			fmtprint(&fstr,
14034f8f669cSDavid du Colombier " type=%d alg=%d labels=%d ttl=%lud exp=%lud incep=%lud tag=%d signer=%s",
14044f8f669cSDavid du Colombier 				rp->sig->type, rp->sig->alg, rp->sig->labels,
14054f8f669cSDavid du Colombier 				rp->sig->ttl, rp->sig->exp, rp->sig->incep,
14064f8f669cSDavid du Colombier 				rp->sig->tag, dnname(rp->sig->signer));
14077dd7cddfSDavid du Colombier 		break;
14087dd7cddfSDavid du Colombier 	case Tcert:
14094f8f669cSDavid du Colombier 		if (rp->cert == nil)
14104f8f669cSDavid du Colombier 			fmtprint(&fstr, " type=<null> tag=<null> alg=<null>");
14114f8f669cSDavid du Colombier 		else
14129a747e4fSDavid du Colombier 			fmtprint(&fstr, " type=%d tag=%d alg=%d",
14134f8f669cSDavid du Colombier 				rp->cert->type, rp->cert->tag, rp->cert->alg);
14147dd7cddfSDavid du Colombier 		break;
14157dd7cddfSDavid du Colombier 	}
14167dd7cddfSDavid du Colombier out:
14179a747e4fSDavid du Colombier 	strp = fmtstrflush(&fstr);
14189a747e4fSDavid du Colombier 	rv = fmtstrcpy(f, strp);
14199a747e4fSDavid du Colombier 	free(strp);
14209a747e4fSDavid du Colombier 	return rv;
14213e12c5d1SDavid du Colombier }
14227dd7cddfSDavid du Colombier 
14237dd7cddfSDavid du Colombier void
14247dd7cddfSDavid du Colombier warning(char *fmt, ...)
14257dd7cddfSDavid du Colombier {
14264f8f669cSDavid du Colombier 	char dnserr[256];
14277dd7cddfSDavid du Colombier 	va_list arg;
14287dd7cddfSDavid du Colombier 
14297dd7cddfSDavid du Colombier 	va_start(arg, fmt);
14309a747e4fSDavid du Colombier 	vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
14317dd7cddfSDavid du Colombier 	va_end(arg);
14324f8f669cSDavid du Colombier 	syslog(1, logfile, dnserr);		/* on console too */
14334f8f669cSDavid du Colombier }
14344f8f669cSDavid du Colombier 
14354f8f669cSDavid du Colombier void
14364f8f669cSDavid du Colombier dnslog(char *fmt, ...)
14374f8f669cSDavid du Colombier {
14384f8f669cSDavid du Colombier 	char dnserr[256];
14394f8f669cSDavid du Colombier 	va_list arg;
14404f8f669cSDavid du Colombier 
14414f8f669cSDavid du Colombier 	va_start(arg, fmt);
14424f8f669cSDavid du Colombier 	vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
14434f8f669cSDavid du Colombier 	va_end(arg);
14444f8f669cSDavid du Colombier 	syslog(0, logfile, dnserr);
14454f8f669cSDavid du Colombier }
14464f8f669cSDavid du Colombier 
14474f8f669cSDavid du Colombier /*
14484f8f669cSDavid du Colombier  * based on libthread's threadsetname, but drags in less library code.
14494f8f669cSDavid du Colombier  * actually just sets the arguments displayed.
14504f8f669cSDavid du Colombier  */
14514f8f669cSDavid du Colombier void
14524f8f669cSDavid du Colombier procsetname(char *fmt, ...)
14534f8f669cSDavid du Colombier {
14544f8f669cSDavid du Colombier 	int fd;
14554f8f669cSDavid du Colombier 	char *cmdname;
14564f8f669cSDavid du Colombier 	char buf[128];
14574f8f669cSDavid du Colombier 	va_list arg;
14584f8f669cSDavid du Colombier 
14594f8f669cSDavid du Colombier 	va_start(arg, fmt);
14604f8f669cSDavid du Colombier 	cmdname = vsmprint(fmt, arg);
14614f8f669cSDavid du Colombier 	va_end(arg);
14624f8f669cSDavid du Colombier 	if (cmdname == nil)
14634f8f669cSDavid du Colombier 		return;
14644f8f669cSDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/args", getpid());
14654f8f669cSDavid du Colombier 	if((fd = open(buf, OWRITE)) >= 0){
14664f8f669cSDavid du Colombier 		write(fd, cmdname, strlen(cmdname)+1);
14674f8f669cSDavid du Colombier 		close(fd);
14684f8f669cSDavid du Colombier 	}
14694f8f669cSDavid du Colombier 	free(cmdname);
14707dd7cddfSDavid du Colombier }
14717dd7cddfSDavid du Colombier 
14727dd7cddfSDavid du Colombier /*
14737dd7cddfSDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
14747dd7cddfSDavid du Colombier  *  another
14757dd7cddfSDavid du Colombier  */
14767dd7cddfSDavid du Colombier void
14777dd7cddfSDavid du Colombier slave(Request *req)
14787dd7cddfSDavid du Colombier {
1479a41547ffSDavid du Colombier 	int ppid, procs;
14807dd7cddfSDavid du Colombier 
14817dd7cddfSDavid du Colombier 	if(req->isslave)
14827dd7cddfSDavid du Colombier 		return;		/* we're already a slave process */
14837dd7cddfSDavid du Colombier 
1484b4b9fc2fSDavid du Colombier 	/*
1485b4b9fc2fSDavid du Colombier 	 * These calls to putactivity cannot block.
1486b4b9fc2fSDavid du Colombier 	 * After getactivity(), the current process is counted
1487b4b9fc2fSDavid du Colombier 	 * twice in dnvars.active (one will pass to the child).
1488b4b9fc2fSDavid du Colombier 	 * If putactivity tries to wait for dnvars.active == 0,
1489b4b9fc2fSDavid du Colombier 	 * it will never happen.
1490b4b9fc2fSDavid du Colombier 	 */
1491b4b9fc2fSDavid du Colombier 
14927dd7cddfSDavid du Colombier 	/* limit parallelism */
1493a41547ffSDavid du Colombier 	procs = getactivity(req, 1);
1494a41547ffSDavid du Colombier 	if (procs > stats.slavehiwat)
1495a41547ffSDavid du Colombier 		stats.slavehiwat = procs;
1496a41547ffSDavid du Colombier 	if(procs > Maxactive){
14974f8f669cSDavid du Colombier 		if(traceactivity)
14984f8f669cSDavid du Colombier 			dnslog("[%d] too much activity", getpid());
1499b4b9fc2fSDavid du Colombier 		putactivity(1);
15007dd7cddfSDavid du Colombier 		return;
15017dd7cddfSDavid du Colombier 	}
15027dd7cddfSDavid du Colombier 
1503c73252aeSDavid du Colombier 	/*
1504c73252aeSDavid du Colombier 	 * parent returns to main loop, child does the work.
1505c73252aeSDavid du Colombier 	 * don't change note group.
1506c73252aeSDavid du Colombier 	 */
1507b4b9fc2fSDavid du Colombier 	ppid = getpid();
1508c73252aeSDavid du Colombier 	switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
15097dd7cddfSDavid du Colombier 	case -1:
1510b4b9fc2fSDavid du Colombier 		putactivity(1);
15117dd7cddfSDavid du Colombier 		break;
15127dd7cddfSDavid du Colombier 	case 0:
15134f8f669cSDavid du Colombier 		procsetname("request slave of pid %d", ppid);
15144f8f669cSDavid du Colombier  		if(traceactivity)
1515a41547ffSDavid du Colombier 			dnslog("[%d] take activity from %d", getpid(), ppid);
15164f8f669cSDavid du Colombier 		req->isslave = 1;	/* why not `= getpid()'? */
15177dd7cddfSDavid du Colombier 		break;
15187dd7cddfSDavid du Colombier 	default:
15194f8f669cSDavid du Colombier 		/*
15204f8f669cSDavid du Colombier 		 * this relies on rfork producing separate, initially-identical
15214f8f669cSDavid du Colombier 		 * stacks, thus giving us two copies of `req', one in each
15224f8f669cSDavid du Colombier 		 * process.
15234f8f669cSDavid du Colombier 		 */
15246aaebd7dSDavid du Colombier 		alarm(0);
15257dd7cddfSDavid du Colombier 		longjmp(req->mret, 1);
15267dd7cddfSDavid du Colombier 	}
15277dd7cddfSDavid du Colombier }
15287dd7cddfSDavid du Colombier 
15297dd7cddfSDavid du Colombier /*
15307dd7cddfSDavid du Colombier  *  chasing down double free's
15317dd7cddfSDavid du Colombier  */
15327dd7cddfSDavid du Colombier void
15337dd7cddfSDavid du Colombier dncheck(void *p, int dolock)
15347dd7cddfSDavid du Colombier {
15357dd7cddfSDavid du Colombier 	int i;
15367dd7cddfSDavid du Colombier 	DN *dp;
15377dd7cddfSDavid du Colombier 	RR *rp;
15387dd7cddfSDavid du Colombier 
15397dd7cddfSDavid du Colombier 	if(p != nil){
15407dd7cddfSDavid du Colombier 		dp = p;
15417dd7cddfSDavid du Colombier 		assert(dp->magic == DNmagic);
15427dd7cddfSDavid du Colombier 	}
15437dd7cddfSDavid du Colombier 
15447dd7cddfSDavid du Colombier 	if(!testing)
15457dd7cddfSDavid du Colombier 		return;
15467dd7cddfSDavid du Colombier 
15477dd7cddfSDavid du Colombier 	if(dolock)
15487dd7cddfSDavid du Colombier 		lock(&dnlock);
15499a747e4fSDavid du Colombier 	poolcheck(mainmem);
15507dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
15517dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
15527dd7cddfSDavid du Colombier 			assert(dp != p);
15537dd7cddfSDavid du Colombier 			assert(dp->magic == DNmagic);
15547dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next){
15557dd7cddfSDavid du Colombier 				assert(rp->magic == RRmagic);
15567dd7cddfSDavid du Colombier 				assert(rp->cached);
15577dd7cddfSDavid du Colombier 				assert(rp->owner == dp);
1558225077b0SDavid du Colombier 				/* also check for duplicate rrs */
15594f927735SDavid du Colombier 				if (dolock && rronlist(rp, rp->next)) {
15604f927735SDavid du Colombier 					dnslog("%R duplicates its next chain "
15614f927735SDavid du Colombier 						"(%R); aborting", rp, rp->next);
15624f927735SDavid du Colombier 					abort();
15634f927735SDavid du Colombier 				}
15647dd7cddfSDavid du Colombier 			}
15657dd7cddfSDavid du Colombier 		}
15667dd7cddfSDavid du Colombier 	if(dolock)
15677dd7cddfSDavid du Colombier 		unlock(&dnlock);
15687dd7cddfSDavid du Colombier }
15697dd7cddfSDavid du Colombier 
15707dd7cddfSDavid du Colombier static int
15717dd7cddfSDavid du Colombier rrequiv(RR *r1, RR *r2)
15727dd7cddfSDavid du Colombier {
15737dd7cddfSDavid du Colombier 	return r1->owner == r2->owner
15747dd7cddfSDavid du Colombier 		&& r1->type == r2->type
15757dd7cddfSDavid du Colombier 		&& r1->arg0 == r2->arg0
1576225077b0SDavid du Colombier 		&& r1->arg1 == r2->arg1;
15777dd7cddfSDavid du Colombier }
15787dd7cddfSDavid du Colombier 
15797dd7cddfSDavid du Colombier void
15807dd7cddfSDavid du Colombier unique(RR *rp)
15817dd7cddfSDavid du Colombier {
15827dd7cddfSDavid du Colombier 	RR **l, *nrp;
15837dd7cddfSDavid du Colombier 
15847dd7cddfSDavid du Colombier 	for(; rp; rp = rp->next){
15857dd7cddfSDavid du Colombier 		l = &rp->next;
15864f8f669cSDavid du Colombier 		for(nrp = *l; nrp; nrp = *l)
15877dd7cddfSDavid du Colombier 			if(rrequiv(rp, nrp)){
15887dd7cddfSDavid du Colombier 				*l = nrp->next;
15897dd7cddfSDavid du Colombier 				rrfree(nrp);
15907dd7cddfSDavid du Colombier 			} else
15917dd7cddfSDavid du Colombier 				l = &nrp->next;
15927dd7cddfSDavid du Colombier 	}
15937dd7cddfSDavid du Colombier }
15947dd7cddfSDavid du Colombier 
15957dd7cddfSDavid du Colombier /*
15967dd7cddfSDavid du Colombier  *  true if second domain is subsumed by the first
15977dd7cddfSDavid du Colombier  */
15987dd7cddfSDavid du Colombier int
15997dd7cddfSDavid du Colombier subsume(char *higher, char *lower)
16007dd7cddfSDavid du Colombier {
16017dd7cddfSDavid du Colombier 	int hn, ln;
16027dd7cddfSDavid du Colombier 
16037dd7cddfSDavid du Colombier 	ln = strlen(lower);
16047dd7cddfSDavid du Colombier 	hn = strlen(higher);
16054f8f669cSDavid du Colombier 	if (ln < hn || cistrcmp(lower + ln - hn, higher) != 0 ||
16064f8f669cSDavid du Colombier 	    ln > hn && hn != 0 && lower[ln - hn - 1] != '.')
16077dd7cddfSDavid du Colombier 		return 0;
16087dd7cddfSDavid du Colombier 	return 1;
16097dd7cddfSDavid du Colombier }
16107dd7cddfSDavid du Colombier 
16117dd7cddfSDavid du Colombier /*
16127dd7cddfSDavid du Colombier  *  randomize the order we return items to provide some
16135d459b5aSDavid du Colombier  *  load balancing for servers.
16145d459b5aSDavid du Colombier  *
16155d459b5aSDavid du Colombier  *  only randomize the first class of entries
16167dd7cddfSDavid du Colombier  */
16177dd7cddfSDavid du Colombier RR*
16187dd7cddfSDavid du Colombier randomize(RR *rp)
16197dd7cddfSDavid du Colombier {
16205d459b5aSDavid du Colombier 	RR *first, *last, *x, *base;
16217dd7cddfSDavid du Colombier 	ulong n;
16227dd7cddfSDavid du Colombier 
16237dd7cddfSDavid du Colombier 	if(rp == nil || rp->next == nil)
16247dd7cddfSDavid du Colombier 		return rp;
16257dd7cddfSDavid du Colombier 
16263cbadd90SDavid du Colombier 	/* just randomize addresses, mx's and ns's */
16277dd7cddfSDavid du Colombier 	for(x = rp; x; x = x->next)
1628adb31a62SDavid du Colombier 		if(x->type != Ta && x->type != Taaaa &&
1629adb31a62SDavid du Colombier 		    x->type != Tmx && x->type != Tns)
16307dd7cddfSDavid du Colombier 			return rp;
16317dd7cddfSDavid du Colombier 
16325d459b5aSDavid du Colombier 	base = rp;
16335d459b5aSDavid du Colombier 
16347dd7cddfSDavid du Colombier 	n = rand();
16357dd7cddfSDavid du Colombier 	last = first = nil;
16367dd7cddfSDavid du Colombier 	while(rp != nil){
16375d459b5aSDavid du Colombier 		/* stop randomizing if we've moved past our class */
16385d459b5aSDavid du Colombier 		if(base->auth != rp->auth || base->db != rp->db){
16395d459b5aSDavid du Colombier 			last->next = rp;
16405d459b5aSDavid du Colombier 			break;
16415d459b5aSDavid du Colombier 		}
16425d459b5aSDavid du Colombier 
16437dd7cddfSDavid du Colombier 		/* unchain */
16447dd7cddfSDavid du Colombier 		x = rp;
16457dd7cddfSDavid du Colombier 		rp = x->next;
16467dd7cddfSDavid du Colombier 		x->next = nil;
16477dd7cddfSDavid du Colombier 
1648225077b0SDavid du Colombier 		if(n&1){
16497dd7cddfSDavid du Colombier 			/* add to tail */
16507dd7cddfSDavid du Colombier 			if(last == nil)
16517dd7cddfSDavid du Colombier 				first = x;
16527dd7cddfSDavid du Colombier 			else
16537dd7cddfSDavid du Colombier 				last->next = x;
16547dd7cddfSDavid du Colombier 			last = x;
16557dd7cddfSDavid du Colombier 		} else {
16567dd7cddfSDavid du Colombier 			/* add to head */
16577dd7cddfSDavid du Colombier 			if(last == nil)
16587dd7cddfSDavid du Colombier 				last = x;
16597dd7cddfSDavid du Colombier 			x->next = first;
16607dd7cddfSDavid du Colombier 			first = x;
16617dd7cddfSDavid du Colombier 		}
16627dd7cddfSDavid du Colombier 
16637dd7cddfSDavid du Colombier 		/* reroll the dice */
16647dd7cddfSDavid du Colombier 		n >>= 1;
16657dd7cddfSDavid du Colombier 	}
16663cbadd90SDavid du Colombier 
16677dd7cddfSDavid du Colombier 	return first;
16687dd7cddfSDavid du Colombier }
166959cc4ca5SDavid du Colombier 
16709a747e4fSDavid du Colombier static int
16719a747e4fSDavid du Colombier sencodefmt(Fmt *f)
167259cc4ca5SDavid du Colombier {
16734f8f669cSDavid du Colombier 	int i, len, ilen, rv;
16744f8f669cSDavid du Colombier 	char *out, *buf;
16759a747e4fSDavid du Colombier 	uchar *b;
16764f8f669cSDavid du Colombier 	char obuf[64];		/* rsc optimization */
167759cc4ca5SDavid du Colombier 
16789a747e4fSDavid du Colombier 	if(!(f->flags&FmtPrec) || f->prec < 1)
16799a747e4fSDavid du Colombier 		goto error;
16809a747e4fSDavid du Colombier 
16819a747e4fSDavid du Colombier 	b = va_arg(f->args, uchar*);
16829a747e4fSDavid du Colombier 	if(b == nil)
16839a747e4fSDavid du Colombier 		goto error;
16849a747e4fSDavid du Colombier 
16859a747e4fSDavid du Colombier 	/* if it's a printable, go for it */
16869a747e4fSDavid du Colombier 	len = f->prec;
16879a747e4fSDavid du Colombier 	for(i = 0; i < len; i++)
16889a747e4fSDavid du Colombier 		if(!isprint(b[i]))
16899a747e4fSDavid du Colombier 			break;
16909a747e4fSDavid du Colombier 	if(i == len){
16919a747e4fSDavid du Colombier 		if(len >= sizeof obuf)
16929a747e4fSDavid du Colombier 			len = sizeof(obuf)-1;
16939a747e4fSDavid du Colombier 		memmove(obuf, b, len);
16949a747e4fSDavid du Colombier 		obuf[len] = 0;
16959a747e4fSDavid du Colombier 		fmtstrcpy(f, obuf);
16969a747e4fSDavid du Colombier 		return 0;
169759cc4ca5SDavid du Colombier 	}
169859cc4ca5SDavid du Colombier 
16999a747e4fSDavid du Colombier 	ilen = f->prec;
17009a747e4fSDavid du Colombier 	f->prec = 0;
17019a747e4fSDavid du Colombier 	f->flags &= ~FmtPrec;
17029a747e4fSDavid du Colombier 	switch(f->r){
17039a747e4fSDavid du Colombier 	case '<':
17049a747e4fSDavid du Colombier 		len = (8*ilen+4)/5 + 3;
17059a747e4fSDavid du Colombier 		break;
17069a747e4fSDavid du Colombier 	case '[':
17079a747e4fSDavid du Colombier 		len = (8*ilen+5)/6 + 4;
17089a747e4fSDavid du Colombier 		break;
17099a747e4fSDavid du Colombier 	case 'H':
17109a747e4fSDavid du Colombier 		len = 2*ilen + 1;
17119a747e4fSDavid du Colombier 		break;
17129a747e4fSDavid du Colombier 	default:
17139a747e4fSDavid du Colombier 		goto error;
17149a747e4fSDavid du Colombier 	}
171559cc4ca5SDavid du Colombier 
17169a747e4fSDavid du Colombier 	if(len > sizeof(obuf)){
17179a747e4fSDavid du Colombier 		buf = malloc(len);
17189a747e4fSDavid du Colombier 		if(buf == nil)
17199a747e4fSDavid du Colombier 			goto error;
17209a747e4fSDavid du Colombier 	} else
17219a747e4fSDavid du Colombier 		buf = obuf;
17229a747e4fSDavid du Colombier 
17234f8f669cSDavid du Colombier 	/* convert */
17249a747e4fSDavid du Colombier 	out = buf;
17259a747e4fSDavid du Colombier 	switch(f->r){
17269a747e4fSDavid du Colombier 	case '<':
17279a747e4fSDavid du Colombier 		rv = enc32(out, len, b, ilen);
17289a747e4fSDavid du Colombier 		break;
17299a747e4fSDavid du Colombier 	case '[':
17309a747e4fSDavid du Colombier 		rv = enc64(out, len, b, ilen);
17319a747e4fSDavid du Colombier 		break;
17329a747e4fSDavid du Colombier 	case 'H':
17339a747e4fSDavid du Colombier 		rv = enc16(out, len, b, ilen);
17349a747e4fSDavid du Colombier 		break;
17359a747e4fSDavid du Colombier 	default:
17369a747e4fSDavid du Colombier 		rv = -1;
17379a747e4fSDavid du Colombier 		break;
17389a747e4fSDavid du Colombier 	}
17399a747e4fSDavid du Colombier 	if(rv < 0)
17409a747e4fSDavid du Colombier 		goto error;
17419a747e4fSDavid du Colombier 
17429a747e4fSDavid du Colombier 	fmtstrcpy(f, buf);
17439a747e4fSDavid du Colombier 	if(buf != obuf)
17449a747e4fSDavid du Colombier 		free(buf);
17459a747e4fSDavid du Colombier 	return 0;
17469a747e4fSDavid du Colombier 
17479a747e4fSDavid du Colombier error:
17489a747e4fSDavid du Colombier 	return fmtstrcpy(f, "<encodefmt>");
17499a747e4fSDavid du Colombier }
17509a747e4fSDavid du Colombier 
17519a747e4fSDavid du Colombier void*
17529a747e4fSDavid du Colombier emalloc(int size)
17539a747e4fSDavid du Colombier {
17549a747e4fSDavid du Colombier 	char *x;
17559a747e4fSDavid du Colombier 
17569a747e4fSDavid du Colombier 	x = mallocz(size, 1);
17579a747e4fSDavid du Colombier 	if(x == nil)
17589a747e4fSDavid du Colombier 		abort();
175934f77ae3SDavid du Colombier 	setmalloctag(x, getcallerpc(&size));
17609a747e4fSDavid du Colombier 	return x;
17619a747e4fSDavid du Colombier }
17629a747e4fSDavid du Colombier 
17639a747e4fSDavid du Colombier char*
17649a747e4fSDavid du Colombier estrdup(char *s)
17659a747e4fSDavid du Colombier {
17669a747e4fSDavid du Colombier 	int size;
17679a747e4fSDavid du Colombier 	char *p;
17689a747e4fSDavid du Colombier 
17699a747e4fSDavid du Colombier 	size = strlen(s)+1;
17709a747e4fSDavid du Colombier 	p = mallocz(size, 0);
17719a747e4fSDavid du Colombier 	if(p == nil)
17729a747e4fSDavid du Colombier 		abort();
17739a747e4fSDavid du Colombier 	memmove(p, s, size);
177434f77ae3SDavid du Colombier 	setmalloctag(p, getcallerpc(&s));
17759a747e4fSDavid du Colombier 	return p;
177659cc4ca5SDavid du Colombier }
17773ff48bf5SDavid du Colombier 
17783ff48bf5SDavid du Colombier /*
17793ff48bf5SDavid du Colombier  *  create a pointer record
17803ff48bf5SDavid du Colombier  */
17813ff48bf5SDavid du Colombier static RR*
17823ff48bf5SDavid du Colombier mkptr(DN *dp, char *ptr, ulong ttl)
17833ff48bf5SDavid du Colombier {
17843ff48bf5SDavid du Colombier 	DN *ipdp;
17853ff48bf5SDavid du Colombier 	RR *rp;
17863ff48bf5SDavid du Colombier 
17873ff48bf5SDavid du Colombier 	ipdp = dnlookup(ptr, Cin, 1);
17883ff48bf5SDavid du Colombier 
17893ff48bf5SDavid du Colombier 	rp = rralloc(Tptr);
17903ff48bf5SDavid du Colombier 	rp->ptr = dp;
17913ff48bf5SDavid du Colombier 	rp->owner = ipdp;
17923ff48bf5SDavid du Colombier 	rp->db = 1;
17933ff48bf5SDavid du Colombier 	if(ttl)
17943ff48bf5SDavid du Colombier 		rp->ttl = ttl;
17953ff48bf5SDavid du Colombier 	return rp;
17963ff48bf5SDavid du Colombier }
17973ff48bf5SDavid du Colombier 
179853874d13SDavid du Colombier void	bytes2nibbles(uchar *nibbles, uchar *bytes, int nbytes);
179953874d13SDavid du Colombier 
18003ff48bf5SDavid du Colombier /*
18013ff48bf5SDavid du Colombier  *  look for all ip addresses in this network and make
18023ff48bf5SDavid du Colombier  *  pointer records for them.
18033ff48bf5SDavid du Colombier  */
18043ff48bf5SDavid du Colombier void
180553874d13SDavid du Colombier dnptr(uchar *net, uchar *mask, char *dom, int forwtype, int subdoms, int ttl)
18063ff48bf5SDavid du Colombier {
180753874d13SDavid du Colombier 	int i, j, len;
18084f8f669cSDavid du Colombier 	char *p, *e;
18094f8f669cSDavid du Colombier 	char ptr[Domlen];
181053874d13SDavid du Colombier 	uchar *ipp;
18114f8f669cSDavid du Colombier 	uchar ip[IPaddrlen], nnet[IPaddrlen];
181253874d13SDavid du Colombier 	uchar nibip[IPaddrlen*2];
18133ff48bf5SDavid du Colombier 	DN *dp;
18143ff48bf5SDavid du Colombier 	RR *rp, *nrp, *first, **l;
18153ff48bf5SDavid du Colombier 
18163ff48bf5SDavid du Colombier 	l = &first;
18173ff48bf5SDavid du Colombier 	first = nil;
18184f8f669cSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
18194f8f669cSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next)
18203ff48bf5SDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next){
182153874d13SDavid du Colombier 				if(rp->type != forwtype || rp->negative)
18223ff48bf5SDavid du Colombier 					continue;
18233ff48bf5SDavid du Colombier 				parseip(ip, rp->ip->name);
18243ff48bf5SDavid du Colombier 				maskip(ip, mask, nnet);
18253ff48bf5SDavid du Colombier 				if(ipcmp(net, nnet) != 0)
18263ff48bf5SDavid du Colombier 					continue;
182753874d13SDavid du Colombier 
182853874d13SDavid du Colombier 				ipp = ip;
182953874d13SDavid du Colombier 				len = IPaddrlen;
183053874d13SDavid du Colombier 				if (forwtype == Taaaa) {
183153874d13SDavid du Colombier 					bytes2nibbles(nibip, ip, IPaddrlen);
183253874d13SDavid du Colombier 					ipp = nibip;
183353874d13SDavid du Colombier 					len = 2*IPaddrlen;
183453874d13SDavid du Colombier 				}
183553874d13SDavid du Colombier 
18363ff48bf5SDavid du Colombier 				p = ptr;
18373ff48bf5SDavid du Colombier 				e = ptr+sizeof(ptr);
183853874d13SDavid du Colombier 				for(j = len - 1; j >= len - subdoms; j--)
183953874d13SDavid du Colombier 					p = seprint(p, e, (forwtype == Ta?
184053874d13SDavid du Colombier 						"%d.": "%x."), ipp[j]);
18413ff48bf5SDavid du Colombier 				seprint(p, e, "%s", dom);
184253874d13SDavid du Colombier 
18433ff48bf5SDavid du Colombier 				nrp = mkptr(dp, ptr, ttl);
18443ff48bf5SDavid du Colombier 				*l = nrp;
18453ff48bf5SDavid du Colombier 				l = &nrp->next;
18463ff48bf5SDavid du Colombier 			}
18473ff48bf5SDavid du Colombier 
18483ff48bf5SDavid du Colombier 	for(rp = first; rp != nil; rp = nrp){
18493ff48bf5SDavid du Colombier 		nrp = rp->next;
18503ff48bf5SDavid du Colombier 		rp->next = nil;
18516dc4800dSDavid du Colombier 		rrattach(rp, Authoritative);
18523ff48bf5SDavid du Colombier 	}
18533ff48bf5SDavid du Colombier }
1854dc5a79c1SDavid du Colombier 
1855dc5a79c1SDavid du Colombier void
1856dc5a79c1SDavid du Colombier addserver(Server **l, char *name)
1857dc5a79c1SDavid du Colombier {
1858dc5a79c1SDavid du Colombier 	Server *s;
1859dc5a79c1SDavid du Colombier 
1860dc5a79c1SDavid du Colombier 	while(*l)
1861dc5a79c1SDavid du Colombier 		l = &(*l)->next;
1862dc5a79c1SDavid du Colombier 	s = malloc(sizeof(Server)+strlen(name)+1);
1863dc5a79c1SDavid du Colombier 	if(s == nil)
1864dc5a79c1SDavid du Colombier 		return;
1865dc5a79c1SDavid du Colombier 	s->name = (char*)(s+1);
1866dc5a79c1SDavid du Colombier 	strcpy(s->name, name);
1867dc5a79c1SDavid du Colombier 	s->next = nil;
1868dc5a79c1SDavid du Colombier 	*l = s;
1869dc5a79c1SDavid du Colombier }
1870dc5a79c1SDavid du Colombier 
1871dc5a79c1SDavid du Colombier Server*
1872dc5a79c1SDavid du Colombier copyserverlist(Server *s)
1873dc5a79c1SDavid du Colombier {
1874dc5a79c1SDavid du Colombier 	Server *ns;
1875dc5a79c1SDavid du Colombier 
1876dc5a79c1SDavid du Colombier 	for(ns = nil; s != nil; s = s->next)
1877dc5a79c1SDavid du Colombier 		addserver(&ns, s->name);
1878dc5a79c1SDavid du Colombier 	return ns;
1879dc5a79c1SDavid du Colombier }
1880b751ae26SDavid du Colombier 
1881b751ae26SDavid du Colombier 
1882b751ae26SDavid du Colombier /* from here down is copied to ip/snoopy/dns.c periodically to update it */
1883b751ae26SDavid du Colombier 
1884b751ae26SDavid du Colombier /*
1885b751ae26SDavid du Colombier  *  convert an integer RR type to it's ascii name
1886b751ae26SDavid du Colombier  */
1887b751ae26SDavid du Colombier char*
1888b751ae26SDavid du Colombier rrname(int type, char *buf, int len)
1889b751ae26SDavid du Colombier {
1890b751ae26SDavid du Colombier 	char *t;
1891b751ae26SDavid du Colombier 
1892b751ae26SDavid du Colombier 	t = nil;
1893b751ae26SDavid du Colombier 	if(type >= 0 && type <= Tall)
1894b751ae26SDavid du Colombier 		t = rrtname[type];
1895b751ae26SDavid du Colombier 	if(t==nil){
1896b751ae26SDavid du Colombier 		snprint(buf, len, "%d", type);
1897b751ae26SDavid du Colombier 		t = buf;
1898b751ae26SDavid du Colombier 	}
1899b751ae26SDavid du Colombier 	return t;
1900b751ae26SDavid du Colombier }
1901b751ae26SDavid du Colombier 
1902b751ae26SDavid du Colombier /*
1903b751ae26SDavid du Colombier  *  free a list of resource records and any related structs
1904b751ae26SDavid du Colombier  */
1905b751ae26SDavid du Colombier void
1906b751ae26SDavid du Colombier rrfreelist(RR *rp)
1907b751ae26SDavid du Colombier {
1908b751ae26SDavid du Colombier 	RR *next;
1909b751ae26SDavid du Colombier 
1910b751ae26SDavid du Colombier 	for(; rp; rp = next){
1911b751ae26SDavid du Colombier 		next = rp->next;
1912b751ae26SDavid du Colombier 		rrfree(rp);
1913b751ae26SDavid du Colombier 	}
1914b751ae26SDavid du Colombier }
1915b751ae26SDavid du Colombier 
1916b751ae26SDavid du Colombier void
1917b751ae26SDavid du Colombier freeserverlist(Server *s)
1918b751ae26SDavid du Colombier {
1919b751ae26SDavid du Colombier 	Server *next;
1920b751ae26SDavid du Colombier 
1921b751ae26SDavid du Colombier 	for(; s != nil; s = next){
1922b751ae26SDavid du Colombier 		next = s->next;
1923b751ae26SDavid du Colombier 		free(s);
1924b751ae26SDavid du Colombier 	}
1925b751ae26SDavid du Colombier }
1926b751ae26SDavid du Colombier 
1927b751ae26SDavid du Colombier /*
1928b751ae26SDavid du Colombier  *  allocate a resource record of a given type
1929b751ae26SDavid du Colombier  */
1930b751ae26SDavid du Colombier RR*
1931b751ae26SDavid du Colombier rralloc(int type)
1932b751ae26SDavid du Colombier {
1933b751ae26SDavid du Colombier 	RR *rp;
1934b751ae26SDavid du Colombier 
1935b751ae26SDavid du Colombier 	rp = emalloc(sizeof(*rp));
1936b751ae26SDavid du Colombier 	rp->magic = RRmagic;
1937b751ae26SDavid du Colombier 	rp->pc = getcallerpc(&type);
1938b751ae26SDavid du Colombier 	rp->type = type;
1939fd87a217SDavid du Colombier 	if (rp->type != type)
1940fd87a217SDavid du Colombier 		dnslog("rralloc: bogus type %d", type);
1941b751ae26SDavid du Colombier 	setmalloctag(rp, rp->pc);
1942b751ae26SDavid du Colombier 	switch(type){
1943b751ae26SDavid du Colombier 	case Tsoa:
1944b751ae26SDavid du Colombier 		rp->soa = emalloc(sizeof(*rp->soa));
1945b751ae26SDavid du Colombier 		rp->soa->slaves = nil;
1946b751ae26SDavid du Colombier 		setmalloctag(rp->soa, rp->pc);
1947b751ae26SDavid du Colombier 		break;
1948b751ae26SDavid du Colombier 	case Tsrv:
1949b751ae26SDavid du Colombier 		rp->srv = emalloc(sizeof(*rp->srv));
1950b751ae26SDavid du Colombier 		setmalloctag(rp->srv, rp->pc);
1951b751ae26SDavid du Colombier 		break;
1952b751ae26SDavid du Colombier 	case Tkey:
1953b751ae26SDavid du Colombier 		rp->key = emalloc(sizeof(*rp->key));
1954b751ae26SDavid du Colombier 		setmalloctag(rp->key, rp->pc);
1955b751ae26SDavid du Colombier 		break;
1956b751ae26SDavid du Colombier 	case Tcert:
1957b751ae26SDavid du Colombier 		rp->cert = emalloc(sizeof(*rp->cert));
1958b751ae26SDavid du Colombier 		setmalloctag(rp->cert, rp->pc);
1959b751ae26SDavid du Colombier 		break;
1960b751ae26SDavid du Colombier 	case Tsig:
1961b751ae26SDavid du Colombier 		rp->sig = emalloc(sizeof(*rp->sig));
1962b751ae26SDavid du Colombier 		setmalloctag(rp->sig, rp->pc);
1963b751ae26SDavid du Colombier 		break;
1964b751ae26SDavid du Colombier 	case Tnull:
1965b751ae26SDavid du Colombier 		rp->null = emalloc(sizeof(*rp->null));
1966b751ae26SDavid du Colombier 		setmalloctag(rp->null, rp->pc);
1967b751ae26SDavid du Colombier 		break;
1968b751ae26SDavid du Colombier 	}
1969b751ae26SDavid du Colombier 	rp->ttl = 0;
1970b751ae26SDavid du Colombier 	rp->expire = 0;
1971b751ae26SDavid du Colombier 	rp->next = 0;
1972b751ae26SDavid du Colombier 	return rp;
1973b751ae26SDavid du Colombier }
1974b751ae26SDavid du Colombier 
1975b751ae26SDavid du Colombier /*
1976b751ae26SDavid du Colombier  *  free a resource record and any related structs
1977b751ae26SDavid du Colombier  */
1978b751ae26SDavid du Colombier void
1979b751ae26SDavid du Colombier rrfree(RR *rp)
1980b751ae26SDavid du Colombier {
1981b751ae26SDavid du Colombier 	DN *dp;
1982b751ae26SDavid du Colombier 	RR *nrp;
1983b751ae26SDavid du Colombier 	Txt *t;
1984b751ae26SDavid du Colombier 
1985530fef66SDavid du Colombier 	assert(rp->magic == RRmagic);
1986b751ae26SDavid du Colombier 	assert(!rp->cached);
1987b751ae26SDavid du Colombier 
1988b751ae26SDavid du Colombier 	dp = rp->owner;
1989b751ae26SDavid du Colombier 	if(dp){
1990b751ae26SDavid du Colombier 		assert(dp->magic == DNmagic);
1991b751ae26SDavid du Colombier 		for(nrp = dp->rr; nrp; nrp = nrp->next)
1992b751ae26SDavid du Colombier 			assert(nrp != rp);	/* "rrfree of live rr" */
1993b751ae26SDavid du Colombier 	}
1994b751ae26SDavid du Colombier 
1995b751ae26SDavid du Colombier 	switch(rp->type){
1996b751ae26SDavid du Colombier 	case Tsoa:
1997b751ae26SDavid du Colombier 		freeserverlist(rp->soa->slaves);
1998b751ae26SDavid du Colombier 		memset(rp->soa, 0, sizeof *rp->soa);	/* cause trouble */
1999b751ae26SDavid du Colombier 		free(rp->soa);
2000b751ae26SDavid du Colombier 		break;
2001b751ae26SDavid du Colombier 	case Tsrv:
2002b751ae26SDavid du Colombier 		memset(rp->srv, 0, sizeof *rp->srv);	/* cause trouble */
2003b751ae26SDavid du Colombier 		free(rp->srv);
2004b751ae26SDavid du Colombier 		break;
2005b751ae26SDavid du Colombier 	case Tkey:
2006b751ae26SDavid du Colombier 		free(rp->key->data);
2007b751ae26SDavid du Colombier 		memset(rp->key, 0, sizeof *rp->key);	/* cause trouble */
2008b751ae26SDavid du Colombier 		free(rp->key);
2009b751ae26SDavid du Colombier 		break;
2010b751ae26SDavid du Colombier 	case Tcert:
2011b751ae26SDavid du Colombier 		free(rp->cert->data);
2012b751ae26SDavid du Colombier 		memset(rp->cert, 0, sizeof *rp->cert);	/* cause trouble */
2013b751ae26SDavid du Colombier 		free(rp->cert);
2014b751ae26SDavid du Colombier 		break;
2015b751ae26SDavid du Colombier 	case Tsig:
2016b751ae26SDavid du Colombier 		free(rp->sig->data);
2017b751ae26SDavid du Colombier 		memset(rp->sig, 0, sizeof *rp->sig);	/* cause trouble */
2018b751ae26SDavid du Colombier 		free(rp->sig);
2019b751ae26SDavid du Colombier 		break;
2020b751ae26SDavid du Colombier 	case Tnull:
2021b751ae26SDavid du Colombier 		free(rp->null->data);
2022b751ae26SDavid du Colombier 		memset(rp->null, 0, sizeof *rp->null);	/* cause trouble */
2023b751ae26SDavid du Colombier 		free(rp->null);
2024b751ae26SDavid du Colombier 		break;
2025b751ae26SDavid du Colombier 	case Ttxt:
2026b751ae26SDavid du Colombier 		while(rp->txt != nil){
2027b751ae26SDavid du Colombier 			t = rp->txt;
2028b751ae26SDavid du Colombier 			rp->txt = t->next;
2029b751ae26SDavid du Colombier 			free(t->p);
2030b751ae26SDavid du Colombier 			memset(t, 0, sizeof *t);	/* cause trouble */
2031b751ae26SDavid du Colombier 			free(t);
2032b751ae26SDavid du Colombier 		}
2033b751ae26SDavid du Colombier 		break;
2034b751ae26SDavid du Colombier 	}
2035b751ae26SDavid du Colombier 
2036b751ae26SDavid du Colombier 	rp->magic = ~rp->magic;
2037b751ae26SDavid du Colombier 	memset(rp, 0, sizeof *rp);		/* cause trouble */
2038b751ae26SDavid du Colombier 	free(rp);
2039b751ae26SDavid du Colombier }
2040