xref: /plan9/sys/src/cmd/ndb/dn.c (revision 03da95d6cdcd1b850b1d3ca9f9d67f0363db0d22)
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  *
13409a7d08SDavid du Colombier  *  aging corrupts the cache, so raise the trigger to avoid it.
1421abd8f2SDavid du Colombier  */
1521abd8f2SDavid du Colombier enum {
161a8a6b0dSDavid du Colombier 	Deftarget	= 1<<30,	/* effectively disable aging */
171a8a6b0dSDavid du Colombier 	Minage		= 1<<30,
181a8a6b0dSDavid du Colombier 	Defagefreq	= 1<<30,	/* age names this often (seconds) */
191a8a6b0dSDavid du Colombier 
201a8a6b0dSDavid du Colombier 	/* these settings will trigger frequent aging */
211a8a6b0dSDavid du Colombier //	Deftarget	= 4000,
221a8a6b0dSDavid du Colombier //	Minage		=  5*60,
231a8a6b0dSDavid du Colombier //	Defagefreq	= 15*60,	/* age names this often (seconds) */
24409a7d08SDavid du Colombier 
25409a7d08SDavid du Colombier 	Restartmins	= 0,
26409a7d08SDavid du Colombier //	Restartmins	= 600,
2781730632SDavid du Colombier };
2881730632SDavid du Colombier 
293e12c5d1SDavid du Colombier /*
303e12c5d1SDavid du Colombier  *  Hash table for domain names.  The hash is based only on the
313e12c5d1SDavid du Colombier  *  first element of the domain name.
323e12c5d1SDavid du Colombier  */
337dd7cddfSDavid du Colombier DN *ht[HTLEN];
343e12c5d1SDavid du Colombier 
354f8f669cSDavid du Colombier static struct {
367dd7cddfSDavid du Colombier 	Lock;
377dd7cddfSDavid du Colombier 	ulong	names;		/* names allocated */
387dd7cddfSDavid du Colombier 	ulong	oldest;		/* longest we'll leave a name around */
397dd7cddfSDavid du Colombier 	int	active;
407dd7cddfSDavid du Colombier 	int	mutex;
414f8f669cSDavid du Colombier 	ushort	id;		/* same size as in packet */
427dd7cddfSDavid du Colombier } dnvars;
433e12c5d1SDavid du Colombier 
443e12c5d1SDavid du Colombier /* names of RR types */
453e12c5d1SDavid du Colombier char *rrtname[] =
463e12c5d1SDavid du Colombier {
473e12c5d1SDavid du Colombier [Ta]		"ip",
483e12c5d1SDavid du Colombier [Tns]		"ns",
493e12c5d1SDavid du Colombier [Tmd]		"md",
503e12c5d1SDavid du Colombier [Tmf]		"mf",
513e12c5d1SDavid du Colombier [Tcname]	"cname",
523e12c5d1SDavid du Colombier [Tsoa]		"soa",
533e12c5d1SDavid du Colombier [Tmb]		"mb",
543e12c5d1SDavid du Colombier [Tmg]		"mg",
553e12c5d1SDavid du Colombier [Tmr]		"mr",
563e12c5d1SDavid du Colombier [Tnull]		"null",
573e12c5d1SDavid du Colombier [Twks]		"wks",
583e12c5d1SDavid du Colombier [Tptr]		"ptr",
593e12c5d1SDavid du Colombier [Thinfo]	"hinfo",
603e12c5d1SDavid du Colombier [Tminfo]	"minfo",
613e12c5d1SDavid du Colombier [Tmx]		"mx",
623e12c5d1SDavid du Colombier [Ttxt]		"txt",
637dd7cddfSDavid du Colombier [Trp]		"rp",
64ab3dc52fSDavid du Colombier [Tafsdb]	"afsdb",
65ab3dc52fSDavid du Colombier [Tx25]		"x.25",
66ab3dc52fSDavid du Colombier [Tisdn]		"isdn",
67ab3dc52fSDavid du Colombier [Trt]		"rt",
68ab3dc52fSDavid du Colombier [Tnsap]		"nsap",
69ab3dc52fSDavid du Colombier [Tnsapptr]	"nsap-ptr",
707dd7cddfSDavid du Colombier [Tsig]		"sig",
71ab3dc52fSDavid du Colombier [Tkey]		"key",
72ab3dc52fSDavid du Colombier [Tpx]		"px",
73ab3dc52fSDavid du Colombier [Tgpos]		"gpos",
745d459b5aSDavid du Colombier [Taaaa]		"ipv6",
75ab3dc52fSDavid du Colombier [Tloc]		"loc",
76ab3dc52fSDavid du Colombier [Tnxt]		"nxt",
77ab3dc52fSDavid du Colombier [Teid]		"eid",
78ab3dc52fSDavid du Colombier [Tnimloc]	"nimrod",
79ab3dc52fSDavid du Colombier [Tsrv]		"srv",
80ab3dc52fSDavid du Colombier [Tatma]		"atma",
81ab3dc52fSDavid du Colombier [Tnaptr]	"naptr",
82ab3dc52fSDavid du Colombier [Tkx]		"kx",
83ab3dc52fSDavid du Colombier [Tcert]		"cert",
84ab3dc52fSDavid du Colombier [Ta6]		"a6",
85ab3dc52fSDavid du Colombier [Tdname]	"dname",
86ab3dc52fSDavid du Colombier [Tsink]		"sink",
87ab3dc52fSDavid du Colombier [Topt]		"opt",
88ab3dc52fSDavid du Colombier [Tapl]		"apl",
89ab3dc52fSDavid du Colombier [Tds]		"ds",
90ab3dc52fSDavid du Colombier [Tsshfp]	"sshfp",
91ab3dc52fSDavid du Colombier [Tipseckey]	"ipseckey",
92ab3dc52fSDavid du Colombier [Trrsig]	"rrsig",
93ab3dc52fSDavid du Colombier [Tnsec]		"nsec",
94ab3dc52fSDavid du Colombier [Tdnskey]	"dnskey",
95ab3dc52fSDavid du Colombier [Tspf]		"spf",
96ab3dc52fSDavid du Colombier [Tuinfo]	"uinfo",
97ab3dc52fSDavid du Colombier [Tuid]		"uid",
98ab3dc52fSDavid du Colombier [Tgid]		"gid",
99ab3dc52fSDavid du Colombier [Tunspec]	"unspec",
100ab3dc52fSDavid du Colombier [Ttkey]		"tkey",
101ab3dc52fSDavid du Colombier [Ttsig]		"tsig",
1027dd7cddfSDavid du Colombier [Tixfr]		"ixfr",
1037dd7cddfSDavid du Colombier [Taxfr]		"axfr",
104ab3dc52fSDavid du Colombier [Tmailb]	"mailb",
105ab3dc52fSDavid du Colombier [Tmaila]	"maila",
106219b2ee8SDavid du Colombier [Tall]		"all",
1073e12c5d1SDavid du Colombier 		0,
1083e12c5d1SDavid du Colombier };
1093e12c5d1SDavid du Colombier 
1103e12c5d1SDavid du Colombier /* names of response codes */
111271b8d73SDavid du Colombier char *rname[Rmask+1] =
1123e12c5d1SDavid du Colombier {
1133e12c5d1SDavid du Colombier [Rok]			"ok",
1143e12c5d1SDavid du Colombier [Rformat]		"format error",
1153e12c5d1SDavid du Colombier [Rserver]		"server failure",
1163e12c5d1SDavid du Colombier [Rname]			"bad name",
1173e12c5d1SDavid du Colombier [Runimplimented]	"unimplemented",
1183e12c5d1SDavid du Colombier [Rrefused]		"we don't like you",
119ab3dc52fSDavid du Colombier [Ryxdomain]		"name should not exist",
120ab3dc52fSDavid du Colombier [Ryxrrset]		"rr set should not exist",
121ab3dc52fSDavid du Colombier [Rnxrrset]		"rr set should exist",
122ab3dc52fSDavid du Colombier [Rnotauth]		"not authorative",
123ab3dc52fSDavid du Colombier [Rnotzone]		"not in zone",
124ab3dc52fSDavid du Colombier [Rbadvers]		"bad opt version",
125ab3dc52fSDavid du Colombier /* [Rbadsig]		"bad signature", */
126ab3dc52fSDavid du Colombier [Rbadkey]		"bad key",
127ab3dc52fSDavid du Colombier [Rbadtime]		"bad signature time",
128ab3dc52fSDavid du Colombier [Rbadmode]		"bad mode",
129ab3dc52fSDavid du Colombier [Rbadname]		"duplicate key name",
130ab3dc52fSDavid du Colombier [Rbadalg]		"bad algorithm",
1313e12c5d1SDavid du Colombier };
1324f8f669cSDavid du Colombier unsigned nrname = nelem(rname);
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier /* names of op codes */
1353e12c5d1SDavid du Colombier char *opname[] =
1363e12c5d1SDavid du Colombier {
1373e12c5d1SDavid du Colombier [Oquery]	"query",
138ab3dc52fSDavid du Colombier [Oinverse]	"inverse query (retired)",
1393e12c5d1SDavid du Colombier [Ostatus]	"status",
140ab3dc52fSDavid du Colombier [Oupdate]	"update",
1413e12c5d1SDavid du Colombier };
1423e12c5d1SDavid du Colombier 
14321abd8f2SDavid du Colombier ulong target = Deftarget;
14427acba7cSDavid du Colombier ulong start;
145bd389b36SDavid du Colombier Lock	dnlock;
1463e12c5d1SDavid du Colombier 
147f46c709fSDavid du Colombier static ulong agefreq = Defagefreq;
148f46c709fSDavid du Colombier 
149225077b0SDavid du Colombier static int rrequiv(RR *r1, RR *r2);
1509a747e4fSDavid du Colombier static int sencodefmt(Fmt*);
15159cc4ca5SDavid du Colombier 
152254fe3d3SDavid du Colombier static void
ding(void *,char * msg)153254fe3d3SDavid du Colombier ding(void*, char *msg)
154254fe3d3SDavid du Colombier {
155254fe3d3SDavid du Colombier 	if(strstr(msg, "alarm") != nil) {
156254fe3d3SDavid du Colombier 		stats.alarms++;
157254fe3d3SDavid du Colombier 		noted(NCONT);		/* resume with system call error */
158254fe3d3SDavid du Colombier 	} else
159254fe3d3SDavid du Colombier 		noted(NDFLT);		/* die */
160254fe3d3SDavid du Colombier }
161254fe3d3SDavid du Colombier 
1623e12c5d1SDavid du Colombier void
dninit(void)1633e12c5d1SDavid du Colombier dninit(void)
1643e12c5d1SDavid du Colombier {
1659a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
1669a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
1679a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
1689a747e4fSDavid du Colombier 	fmtinstall('R', rrfmt);
1699a747e4fSDavid du Colombier 	fmtinstall('Q', rravfmt);
1709a747e4fSDavid du Colombier 	fmtinstall('H', sencodefmt);
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	dnvars.oldest = maxage;
1737dd7cddfSDavid du Colombier 	dnvars.names = 0;
1744f8f669cSDavid du Colombier 	dnvars.id = truerand();	/* don't start with same id every time */
175254fe3d3SDavid du Colombier 
176254fe3d3SDavid du Colombier 	notify(ding);
1773e12c5d1SDavid du Colombier }
1783e12c5d1SDavid du Colombier 
1793e12c5d1SDavid du Colombier /*
1803e12c5d1SDavid du Colombier  *  hash for a domain name
1813e12c5d1SDavid du Colombier  */
1823e12c5d1SDavid du Colombier static ulong
dnhash(char * name)1833e12c5d1SDavid du Colombier dnhash(char *name)
1843e12c5d1SDavid du Colombier {
1853e12c5d1SDavid du Colombier 	ulong hash;
1863e12c5d1SDavid du Colombier 	uchar *val = (uchar*)name;
1873e12c5d1SDavid du Colombier 
1887dd7cddfSDavid du Colombier 	for(hash = 0; *val; val++)
1894f8f669cSDavid du Colombier 		hash = hash*13 + tolower(*val)-'a';
1903e12c5d1SDavid du Colombier 	return hash % HTLEN;
1913e12c5d1SDavid du Colombier }
1923e12c5d1SDavid du Colombier 
1933e12c5d1SDavid du Colombier /*
1943e12c5d1SDavid du Colombier  *  lookup a symbol.  if enter is not zero and the name is
1953e12c5d1SDavid du Colombier  *  not found, create it.
1963e12c5d1SDavid du Colombier  */
1973e12c5d1SDavid du Colombier DN*
dnlookup(char * name,int class,int enter)1983e12c5d1SDavid du Colombier dnlookup(char *name, int class, int enter)
1993e12c5d1SDavid du Colombier {
2003e12c5d1SDavid du Colombier 	DN **l;
2013e12c5d1SDavid du Colombier 	DN *dp;
2023e12c5d1SDavid du Colombier 
2033ff48bf5SDavid du Colombier 	l = &ht[dnhash(name)];
204bd389b36SDavid du Colombier 	lock(&dnlock);
2053e12c5d1SDavid du Colombier 	for(dp = *l; dp; dp = dp->next) {
2067dd7cddfSDavid du Colombier 		assert(dp->magic == DNmagic);
2073ff48bf5SDavid du Colombier 		if(dp->class == class && cistrcmp(dp->name, name) == 0){
2087dd7cddfSDavid du Colombier 			dp->referenced = now;
209bd389b36SDavid du Colombier 			unlock(&dnlock);
2103e12c5d1SDavid du Colombier 			return dp;
2113e12c5d1SDavid du Colombier 		}
2123e12c5d1SDavid du Colombier 		l = &dp->next;
2133e12c5d1SDavid du Colombier 	}
2144f8f669cSDavid du Colombier 
2154f8f669cSDavid du Colombier 	if(!enter){
216bd389b36SDavid du Colombier 		unlock(&dnlock);
2173e12c5d1SDavid du Colombier 		return 0;
2183e12c5d1SDavid du Colombier 	}
2197dd7cddfSDavid du Colombier 	dnvars.names++;
2209a747e4fSDavid du Colombier 	dp = emalloc(sizeof(*dp));
2217dd7cddfSDavid du Colombier 	dp->magic = DNmagic;
2229a747e4fSDavid du Colombier 	dp->name = estrdup(name);
2234f8f669cSDavid du Colombier 	assert(dp->name != nil);
2243e12c5d1SDavid du Colombier 	dp->class = class;
2253e12c5d1SDavid du Colombier 	dp->rr = 0;
2267dd7cddfSDavid du Colombier 	dp->referenced = now;
227530fef66SDavid du Colombier 	/* add new DN to tail of the hash list.  *l points to last next ptr. */
228530fef66SDavid du Colombier 	dp->next = nil;
2293e12c5d1SDavid du Colombier 	*l = dp;
230bd389b36SDavid du Colombier 	unlock(&dnlock);
2317dd7cddfSDavid du Colombier 
2323e12c5d1SDavid du Colombier 	return dp;
2333e12c5d1SDavid du Colombier }
2343e12c5d1SDavid du Colombier 
235225077b0SDavid du Colombier static int
rrsame(RR * rr1,RR * rr2)236225077b0SDavid du Colombier rrsame(RR *rr1, RR *rr2)
237225077b0SDavid du Colombier {
238225077b0SDavid du Colombier 	return rr1 == rr2 || rr2 && rrequiv(rr1, rr2) &&
239225077b0SDavid du Colombier 		rr1->db == rr2->db && rr1->auth == rr2->auth;
240225077b0SDavid du Colombier }
241225077b0SDavid du Colombier 
242225077b0SDavid du Colombier static int
rronlist(RR * rp,RR * lp)243225077b0SDavid du Colombier rronlist(RR *rp, RR *lp)
244225077b0SDavid du Colombier {
245225077b0SDavid du Colombier 	for(; lp; lp = lp->next)
2464f927735SDavid du Colombier 		if (rrsame(lp, rp))
247225077b0SDavid du Colombier 			return 1;
248225077b0SDavid du Colombier 	return 0;
249225077b0SDavid du Colombier }
250225077b0SDavid du Colombier 
2513e12c5d1SDavid du Colombier /*
2524f927735SDavid du Colombier  * dump the stats
253219b2ee8SDavid du Colombier  */
254219b2ee8SDavid du Colombier void
dnstats(char * file)2554f927735SDavid du Colombier dnstats(char *file)
256219b2ee8SDavid du Colombier {
257219b2ee8SDavid du Colombier 	int i, fd;
258219b2ee8SDavid du Colombier 
25921abd8f2SDavid du Colombier 	fd = create(file, OWRITE, 0666);
260219b2ee8SDavid du Colombier 	if(fd < 0)
261219b2ee8SDavid du Colombier 		return;
262a41547ffSDavid du Colombier 
263a41547ffSDavid du Colombier 	qlock(&stats);
2644f927735SDavid du Colombier 	fprint(fd, "# system %s\n", sysname());
265f46c709fSDavid du Colombier 	fprint(fd, "# slave procs high-water mark\t%lud\n", stats.slavehiwat);
266f46c709fSDavid du Colombier 	fprint(fd, "# queries received by 9p\t%lud\n", stats.qrecvd9p);
267f46c709fSDavid du Colombier 	fprint(fd, "# queries received by udp\t%lud\n", stats.qrecvdudp);
268f46c709fSDavid du Colombier 	fprint(fd, "# queries answered from memory\t%lud\n", stats.answinmem);
269f46c709fSDavid du Colombier 	fprint(fd, "# queries sent by udp\t%lud\n", stats.qsent);
270a41547ffSDavid du Colombier 	for (i = 0; i < nelem(stats.under10ths); i++)
271a41547ffSDavid du Colombier 		if (stats.under10ths[i] || i == nelem(stats.under10ths) - 1)
272f46c709fSDavid du Colombier 			fprint(fd, "# responses arriving within %.1f s.\t%lud\n",
273a41547ffSDavid du Colombier 				(double)(i+1)/10, stats.under10ths[i]);
274f46c709fSDavid du Colombier 	fprint(fd, "\n# queries sent & timed-out\t%lud\n", stats.tmout);
275f46c709fSDavid du Colombier 	fprint(fd, "# cname queries timed-out\t%lud\n", stats.tmoutcname);
276f46c709fSDavid du Colombier 	fprint(fd, "# ipv6  queries timed-out\t%lud\n", stats.tmoutv6);
277f46c709fSDavid du Colombier 	fprint(fd, "\n# negative answers received\t%lud\n", stats.negans);
2780319257bSDavid du Colombier 	fprint(fd, "# negative answers w Rserver set\t%lud\n", stats.negserver);
2790319257bSDavid du Colombier 	fprint(fd, "# negative answers w bad delegation\t%lud\n",
2800319257bSDavid du Colombier 		stats.negbaddeleg);
2810319257bSDavid du Colombier 	fprint(fd, "# negative answers w bad delegation & no answers\t%lud\n",
2820319257bSDavid du Colombier 		stats.negbdnoans);
2830319257bSDavid du Colombier 	fprint(fd, "# negative answers w no Rname set\t%lud\n", stats.negnorname);
284f46c709fSDavid du Colombier 	fprint(fd, "# negative answers cached\t%lud\n", stats.negcached);
285a41547ffSDavid du Colombier 	qunlock(&stats);
286a41547ffSDavid du Colombier 
287219b2ee8SDavid du Colombier 	lock(&dnlock);
2886d8e4566SDavid du Colombier 	fprint(fd, "\n# domain names %lud target %lud\n", dnvars.names, target);
2894f927735SDavid du Colombier 	unlock(&dnlock);
2904f927735SDavid du Colombier 	close(fd);
2914f927735SDavid du Colombier }
2924f927735SDavid du Colombier 
2934f927735SDavid du Colombier /*
2944f927735SDavid du Colombier  *  dump the cache
2954f927735SDavid du Colombier  */
2964f927735SDavid du Colombier void
dndump(char * file)2974f927735SDavid du Colombier dndump(char *file)
2984f927735SDavid du Colombier {
2994f927735SDavid du Colombier 	int i, fd;
3004f927735SDavid du Colombier 	DN *dp;
3014f927735SDavid du Colombier 	RR *rp;
3024f927735SDavid du Colombier 
3034f927735SDavid du Colombier 	fd = create(file, OWRITE, 0666);
3044f927735SDavid du Colombier 	if(fd < 0)
3054f927735SDavid du Colombier 		return;
3064f927735SDavid du Colombier 
3074f927735SDavid du Colombier 	lock(&dnlock);
3084f8f669cSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
309219b2ee8SDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
310219b2ee8SDavid du Colombier 			fprint(fd, "%s\n", dp->name);
311225077b0SDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next) {
3126d8e4566SDavid du Colombier 				fprint(fd, "\t%R %c%c %lud/%lud\n",
3134f8f669cSDavid du Colombier 					rp, rp->auth? 'A': 'U',
3147dd7cddfSDavid du Colombier 					rp->db? 'D': 'N', rp->expire, rp->ttl);
315225077b0SDavid du Colombier 				if (rronlist(rp, rp->next))
316225077b0SDavid du Colombier 					fprint(fd, "*** duplicate:\n");
317225077b0SDavid du Colombier 			}
318219b2ee8SDavid du Colombier 		}
319219b2ee8SDavid du Colombier 	unlock(&dnlock);
320219b2ee8SDavid du Colombier 	close(fd);
321219b2ee8SDavid du Colombier }
322219b2ee8SDavid du Colombier 
323219b2ee8SDavid du Colombier /*
3247dd7cddfSDavid du Colombier  *  purge all records
3257dd7cddfSDavid du Colombier  */
3267dd7cddfSDavid du Colombier void
dnpurge(void)3277dd7cddfSDavid du Colombier dnpurge(void)
3287dd7cddfSDavid du Colombier {
3297dd7cddfSDavid du Colombier 	DN *dp;
330a4285193SDavid du Colombier 	RR *rp, *srp;
3317dd7cddfSDavid du Colombier 	int i;
3327dd7cddfSDavid du Colombier 
3337dd7cddfSDavid du Colombier 	lock(&dnlock);
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
3367dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
337a4285193SDavid du Colombier 			srp = rp = dp->rr;
3387dd7cddfSDavid du Colombier 			dp->rr = nil;
3397dd7cddfSDavid du Colombier 			for(; rp != nil; rp = rp->next)
3407dd7cddfSDavid du Colombier 				rp->cached = 0;
341a4285193SDavid du Colombier 			rrfreelist(srp);
3427dd7cddfSDavid du Colombier 		}
3437dd7cddfSDavid du Colombier 
3447dd7cddfSDavid du Colombier 	unlock(&dnlock);
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier 
347d2fd7a44SDavid du Colombier /*
3484faf7596SDavid du Colombier  *  delete head of *l and free the old head.
349d2fd7a44SDavid du Colombier  *  call with dnlock held.
350d2fd7a44SDavid du Colombier  */
351225077b0SDavid du Colombier static void
rrdelhead(RR ** l)3524faf7596SDavid du Colombier rrdelhead(RR **l)
353225077b0SDavid du Colombier {
3544faf7596SDavid du Colombier 	RR *rp;
3554faf7596SDavid du Colombier 
3564faf7596SDavid du Colombier 	if (canlock(&dnlock))
3574faf7596SDavid du Colombier 		abort();	/* rrdelhead called with dnlock not held */
3584faf7596SDavid du Colombier 	rp = *l;
3594faf7596SDavid du Colombier 	if(rp == nil)
3604faf7596SDavid du Colombier 		return;
3614faf7596SDavid du Colombier 	*l = rp->next;		/* unlink head */
362225077b0SDavid du Colombier 	rp->cached = 0;		/* avoid blowing an assertion in rrfree */
363225077b0SDavid du Colombier 	rrfree(rp);
364225077b0SDavid du Colombier }
365225077b0SDavid du Colombier 
3667dd7cddfSDavid du Colombier /*
367d2fd7a44SDavid du Colombier  *  check the age of resource records, free any that have timed out.
368d2fd7a44SDavid du Colombier  *  call with dnlock held.
3693e12c5d1SDavid du Colombier  */
3703e12c5d1SDavid du Colombier void
dnage(DN * dp)3713e12c5d1SDavid du Colombier dnage(DN *dp)
3723e12c5d1SDavid du Colombier {
3733e12c5d1SDavid du Colombier 	RR **l;
3743e12c5d1SDavid du Colombier 	RR *rp, *next;
3757dd7cddfSDavid du Colombier 	ulong diff;
3763e12c5d1SDavid du Colombier 
3774faf7596SDavid du Colombier 	if (canlock(&dnlock))
3784faf7596SDavid du Colombier 		abort();	/* dnage called with dnlock not held */
3797dd7cddfSDavid du Colombier 	diff = now - dp->referenced;
3806dc4800dSDavid du Colombier 	if(diff < Reserved || dp->keep)
3817dd7cddfSDavid du Colombier 		return;
3827dd7cddfSDavid du Colombier 
3833e12c5d1SDavid du Colombier 	l = &dp->rr;
3843e12c5d1SDavid du Colombier 	for(rp = dp->rr; rp; rp = next){
385*03da95d6SDavid du Colombier 		assert(rp->magic == RRmagic);
386*03da95d6SDavid du Colombier 		assert(rp->cached);
3873e12c5d1SDavid du Colombier 		next = rp->next;
388225077b0SDavid du Colombier 		if(!rp->db && (rp->expire < now || diff > dnvars.oldest))
3894faf7596SDavid du Colombier 			rrdelhead(l); /* rp == *l before; *l == rp->next after */
390225077b0SDavid du Colombier 		else
3913e12c5d1SDavid du Colombier 			l = &rp->next;
3923e12c5d1SDavid du Colombier 	}
3933e12c5d1SDavid du Colombier }
3943e12c5d1SDavid du Colombier 
3956dc4800dSDavid du Colombier #define MARK(dp)	{ if (dp) (dp)->keep = 1; }
396a41547ffSDavid du Colombier 
397410ea80bSDavid du Colombier /* mark a domain name and those in its RRs as never to be aged */
398a41547ffSDavid du Colombier void
dnagenever(DN * dp,int dolock)399410ea80bSDavid du Colombier dnagenever(DN *dp, int dolock)
400a41547ffSDavid du Colombier {
401a41547ffSDavid du Colombier 	RR *rp;
402a41547ffSDavid du Colombier 
403410ea80bSDavid du Colombier 	if (dolock)
404a41547ffSDavid du Colombier 		lock(&dnlock);
405a41547ffSDavid du Colombier 
406410ea80bSDavid du Colombier 	/* mark all referenced domain names */
407410ea80bSDavid du Colombier 	MARK(dp);
408a41547ffSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
409a41547ffSDavid du Colombier 		MARK(rp->owner);
410410ea80bSDavid du Colombier 		if(rp->negative){
411410ea80bSDavid du Colombier 			MARK(rp->negsoaowner);
412410ea80bSDavid du Colombier 			continue;
413410ea80bSDavid du Colombier 		}
414a41547ffSDavid du Colombier 		switch(rp->type){
415410ea80bSDavid du Colombier 		case Thinfo:
416410ea80bSDavid du Colombier 			MARK(rp->cpu);
417410ea80bSDavid du Colombier 			MARK(rp->os);
418410ea80bSDavid du Colombier 			break;
419410ea80bSDavid du Colombier 		case Ttxt:
420410ea80bSDavid du Colombier 			break;
421410ea80bSDavid du Colombier 		case Tcname:
422410ea80bSDavid du Colombier 		case Tmb:
423410ea80bSDavid du Colombier 		case Tmd:
424410ea80bSDavid du Colombier 		case Tmf:
425a41547ffSDavid du Colombier 		case Tns:
426410ea80bSDavid du Colombier 		case Tmx:
427410ea80bSDavid du Colombier 		case Tsrv:
428a41547ffSDavid du Colombier 			MARK(rp->host);
429a41547ffSDavid du Colombier 			break;
430410ea80bSDavid du Colombier 		case Tmg:
431410ea80bSDavid du Colombier 		case Tmr:
432410ea80bSDavid du Colombier 			MARK(rp->mb);
433410ea80bSDavid du Colombier 			break;
434410ea80bSDavid du Colombier 		case Tminfo:
435410ea80bSDavid du Colombier 			MARK(rp->rmb);
436410ea80bSDavid du Colombier 			MARK(rp->mb);
437410ea80bSDavid du Colombier 			break;
438410ea80bSDavid du Colombier 		case Trp:
439410ea80bSDavid du Colombier 			MARK(rp->rmb);
440410ea80bSDavid du Colombier 			MARK(rp->rp);
441410ea80bSDavid du Colombier 			break;
442410ea80bSDavid du Colombier 		case Ta:
443410ea80bSDavid du Colombier 		case Taaaa:
444410ea80bSDavid du Colombier 			MARK(rp->ip);
445410ea80bSDavid du Colombier 			break;
446410ea80bSDavid du Colombier 		case Tptr:
447410ea80bSDavid du Colombier 			MARK(rp->ptr);
448410ea80bSDavid du Colombier 			break;
449410ea80bSDavid du Colombier 		case Tsoa:
450410ea80bSDavid du Colombier 			MARK(rp->host);
451410ea80bSDavid du Colombier 			MARK(rp->rmb);
452410ea80bSDavid du Colombier 			break;
453a41547ffSDavid du Colombier 		}
454a41547ffSDavid du Colombier 	}
455410ea80bSDavid du Colombier 
456410ea80bSDavid du Colombier 	if (dolock)
457410ea80bSDavid du Colombier 		unlock(&dnlock);
4586dc4800dSDavid du Colombier }
459a41547ffSDavid du Colombier 
460410ea80bSDavid du Colombier /* mark all current domain names as never to be aged */
461410ea80bSDavid du Colombier void
dnageallnever(void)462410ea80bSDavid du Colombier dnageallnever(void)
463410ea80bSDavid du Colombier {
464410ea80bSDavid du Colombier 	int i;
465410ea80bSDavid du Colombier 	DN *dp;
466410ea80bSDavid du Colombier 
467410ea80bSDavid du Colombier 	lock(&dnlock);
468410ea80bSDavid du Colombier 
469410ea80bSDavid du Colombier 	/* mark all referenced domain names */
470410ea80bSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
471410ea80bSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next)
472410ea80bSDavid du Colombier 			dnagenever(dp, 0);
473410ea80bSDavid du Colombier 
474a41547ffSDavid du Colombier 	unlock(&dnlock);
475a41547ffSDavid du Colombier 
476a41547ffSDavid du Colombier 	dnslog("%ld initial domain names; target is %ld", dnvars.names, target);
477a41547ffSDavid du Colombier 	if(dnvars.names >= target)
478a41547ffSDavid du Colombier 		dnslog("more initial domain names (%ld) than target (%ld)",
479a41547ffSDavid du Colombier 			dnvars.names, target);
480a41547ffSDavid du Colombier }
481a41547ffSDavid du Colombier 
4826dc4800dSDavid du Colombier #define REF(dp)	{ if (dp) (dp)->refs++; }
4836dc4800dSDavid du Colombier 
4847dd7cddfSDavid du Colombier /*
4857dd7cddfSDavid du Colombier  *  periodicly sweep for old records and remove unreferenced domain names
4867dd7cddfSDavid du Colombier  *
4877dd7cddfSDavid du Colombier  *  only called when all other threads are locked out
4887dd7cddfSDavid du Colombier  */
4897dd7cddfSDavid du Colombier void
dnageall(int doit)4907dd7cddfSDavid du Colombier dnageall(int doit)
4917dd7cddfSDavid du Colombier {
4927dd7cddfSDavid du Colombier 	DN *dp, **l;
493225077b0SDavid du Colombier 	int i;
4947dd7cddfSDavid du Colombier 	RR *rp;
4957dd7cddfSDavid du Colombier 	static ulong nextage;
4967dd7cddfSDavid du Colombier 
4974f8f669cSDavid du Colombier 	if(dnvars.names < target || (now < nextage && !doit)){
4987dd7cddfSDavid du Colombier 		dnvars.oldest = maxage;
4997dd7cddfSDavid du Colombier 		return;
5007dd7cddfSDavid du Colombier 	}
5017dd7cddfSDavid du Colombier 
5024f8f669cSDavid du Colombier 	if(dnvars.names >= target) {
5033cbadd90SDavid du Colombier 		dnslog("more names (%lud) than target (%lud)", dnvars.names,
5043cbadd90SDavid du Colombier 			target);
5057dd7cddfSDavid du Colombier 		dnvars.oldest /= 2;
50681730632SDavid du Colombier 		if (dnvars.oldest < Minage)
50781730632SDavid du Colombier 			dnvars.oldest = Minage;		/* don't be silly */
5084f8f669cSDavid du Colombier 	}
509f46c709fSDavid du Colombier 	if (agefreq > dnvars.oldest / 2)
510f46c709fSDavid du Colombier 		nextage = now + dnvars.oldest / 2;
511f46c709fSDavid du Colombier 	else
512f46c709fSDavid du Colombier 		nextage = now + agefreq;
5137dd7cddfSDavid du Colombier 
5147dd7cddfSDavid du Colombier 	lock(&dnlock);
5157dd7cddfSDavid du Colombier 
5167dd7cddfSDavid du Colombier 	/* time out all old entries (and set refs to 0) */
5177dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
5187dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
5197dd7cddfSDavid du Colombier 			dp->refs = 0;
5207dd7cddfSDavid du Colombier 			dnage(dp);
5217dd7cddfSDavid du Colombier 		}
5227dd7cddfSDavid du Colombier 
5237dd7cddfSDavid du Colombier 	/* mark all referenced domain names */
5247dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
5257dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next)
5267dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next){
5277dd7cddfSDavid du Colombier 				REF(rp->owner);
5287dd7cddfSDavid du Colombier 				if(rp->negative){
5297dd7cddfSDavid du Colombier 					REF(rp->negsoaowner);
5307dd7cddfSDavid du Colombier 					continue;
5317dd7cddfSDavid du Colombier 				}
5327dd7cddfSDavid du Colombier 				switch(rp->type){
5337dd7cddfSDavid du Colombier 				case Thinfo:
5347dd7cddfSDavid du Colombier 					REF(rp->cpu);
5357dd7cddfSDavid du Colombier 					REF(rp->os);
5367dd7cddfSDavid du Colombier 					break;
5377dd7cddfSDavid du Colombier 				case Ttxt:
5387dd7cddfSDavid du Colombier 					break;
5397dd7cddfSDavid du Colombier 				case Tcname:
5407dd7cddfSDavid du Colombier 				case Tmb:
5417dd7cddfSDavid du Colombier 				case Tmd:
5427dd7cddfSDavid du Colombier 				case Tmf:
5437dd7cddfSDavid du Colombier 				case Tns:
5444f8f669cSDavid du Colombier 				case Tmx:
545225077b0SDavid du Colombier 				case Tsrv:
5467dd7cddfSDavid du Colombier 					REF(rp->host);
5477dd7cddfSDavid du Colombier 					break;
5487dd7cddfSDavid du Colombier 				case Tmg:
5497dd7cddfSDavid du Colombier 				case Tmr:
5507dd7cddfSDavid du Colombier 					REF(rp->mb);
5517dd7cddfSDavid du Colombier 					break;
5527dd7cddfSDavid du Colombier 				case Tminfo:
5537dd7cddfSDavid du Colombier 					REF(rp->rmb);
5547dd7cddfSDavid du Colombier 					REF(rp->mb);
5557dd7cddfSDavid du Colombier 					break;
5567dd7cddfSDavid du Colombier 				case Trp:
5577dd7cddfSDavid du Colombier 					REF(rp->rmb);
55860845620SDavid du Colombier 					REF(rp->rp);
5597dd7cddfSDavid du Colombier 					break;
5607dd7cddfSDavid du Colombier 				case Ta:
5615d459b5aSDavid du Colombier 				case Taaaa:
5627dd7cddfSDavid du Colombier 					REF(rp->ip);
5637dd7cddfSDavid du Colombier 					break;
5647dd7cddfSDavid du Colombier 				case Tptr:
5657dd7cddfSDavid du Colombier 					REF(rp->ptr);
5667dd7cddfSDavid du Colombier 					break;
5677dd7cddfSDavid du Colombier 				case Tsoa:
5687dd7cddfSDavid du Colombier 					REF(rp->host);
5697dd7cddfSDavid du Colombier 					REF(rp->rmb);
5707dd7cddfSDavid du Colombier 					break;
5717dd7cddfSDavid du Colombier 				}
5727dd7cddfSDavid du Colombier 			}
5737dd7cddfSDavid du Colombier 
5747dd7cddfSDavid du Colombier 	/* sweep and remove unreferenced domain names */
5757dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++){
5767dd7cddfSDavid du Colombier 		l = &ht[i];
5777dd7cddfSDavid du Colombier 		for(dp = *l; dp; dp = *l){
578a41547ffSDavid du Colombier 			if(dp->rr == 0 && dp->refs == 0 && !dp->keep){
57934f77ae3SDavid du Colombier 				assert(dp->magic == DNmagic);
5807dd7cddfSDavid du Colombier 				*l = dp->next;
5814f8f669cSDavid du Colombier 
5827dd7cddfSDavid du Colombier 				if(dp->name)
5837dd7cddfSDavid du Colombier 					free(dp->name);
58434f77ae3SDavid du Colombier 				dp->magic = ~dp->magic;
5857dd7cddfSDavid du Colombier 				dnvars.names--;
5864f8f669cSDavid du Colombier 				memset(dp, 0, sizeof *dp); /* cause trouble */
5877dd7cddfSDavid du Colombier 				free(dp);
5884f8f669cSDavid du Colombier 
5897dd7cddfSDavid du Colombier 				continue;
5907dd7cddfSDavid du Colombier 			}
5917dd7cddfSDavid du Colombier 			l = &dp->next;
5927dd7cddfSDavid du Colombier 		}
5937dd7cddfSDavid du Colombier 	}
5947dd7cddfSDavid du Colombier 
5957dd7cddfSDavid du Colombier 	unlock(&dnlock);
5967dd7cddfSDavid du Colombier }
5977dd7cddfSDavid du Colombier 
5987dd7cddfSDavid du Colombier /*
5997dd7cddfSDavid du Colombier  *  timeout all database records (used when rereading db)
6007dd7cddfSDavid du Colombier  */
6017dd7cddfSDavid du Colombier void
dnagedb(void)6027dd7cddfSDavid du Colombier dnagedb(void)
6037dd7cddfSDavid du Colombier {
6047dd7cddfSDavid du Colombier 	DN *dp;
6057dd7cddfSDavid du Colombier 	int i;
6067dd7cddfSDavid du Colombier 	RR *rp;
6077dd7cddfSDavid du Colombier 
6087dd7cddfSDavid du Colombier 	lock(&dnlock);
6097dd7cddfSDavid du Colombier 
6107dd7cddfSDavid du Colombier 	/* time out all database entries */
6117dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
612410ea80bSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next) {
613410ea80bSDavid du Colombier 			dp->keep = 0;
6147dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next)
6157dd7cddfSDavid du Colombier 				if(rp->db)
6167dd7cddfSDavid du Colombier 					rp->expire = 0;
617410ea80bSDavid du Colombier 		}
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier 	unlock(&dnlock);
6207dd7cddfSDavid du Colombier }
6217dd7cddfSDavid du Colombier 
6227dd7cddfSDavid du Colombier /*
6234f8f669cSDavid du Colombier  *  mark all local db records about my area as authoritative,
6244f8f669cSDavid du Colombier  *  time out any others
6257dd7cddfSDavid du Colombier  */
6267dd7cddfSDavid du Colombier void
dnauthdb(void)6277dd7cddfSDavid du Colombier dnauthdb(void)
6287dd7cddfSDavid du Colombier {
6296b0d5c8bSDavid du Colombier 	int i;
6304f8f669cSDavid du Colombier 	ulong minttl;
6316b0d5c8bSDavid du Colombier 	Area *area;
6324f8f669cSDavid du Colombier 	DN *dp;
6337dd7cddfSDavid du Colombier 	RR *rp;
6347dd7cddfSDavid du Colombier 
6357dd7cddfSDavid du Colombier 	lock(&dnlock);
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier 	/* time out all database entries */
6387dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
6397dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
6407dd7cddfSDavid du Colombier 			area = inmyarea(dp->name);
6417dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next)
6427dd7cddfSDavid du Colombier 				if(rp->db){
6437dd7cddfSDavid du Colombier 					if(area){
6444f8f669cSDavid du Colombier 						minttl = area->soarr->soa->minttl;
6454f8f669cSDavid du Colombier 						if(rp->ttl < minttl)
6464f8f669cSDavid du Colombier 							rp->ttl = minttl;
6477dd7cddfSDavid du Colombier 						rp->auth = 1;
6487dd7cddfSDavid du Colombier 					}
6497dd7cddfSDavid du Colombier 					if(rp->expire == 0){
6507dd7cddfSDavid du Colombier 						rp->db = 0;
6517dd7cddfSDavid du Colombier 						dp->referenced = now-Reserved-1;
6527dd7cddfSDavid du Colombier 					}
6537dd7cddfSDavid du Colombier 				}
6547dd7cddfSDavid du Colombier 		}
6557dd7cddfSDavid du Colombier 
6567dd7cddfSDavid du Colombier 	unlock(&dnlock);
6577dd7cddfSDavid du Colombier }
6587dd7cddfSDavid du Colombier 
6597dd7cddfSDavid du Colombier /*
6607dd7cddfSDavid du Colombier  *  keep track of other processes to know if we can
6617dd7cddfSDavid du Colombier  *  garbage collect.  block while garbage collecting.
6627dd7cddfSDavid du Colombier  */
6637dd7cddfSDavid du Colombier int
getactivity(Request * req,int recursive)664b4b9fc2fSDavid du Colombier getactivity(Request *req, int recursive)
6657dd7cddfSDavid du Colombier {
6667dd7cddfSDavid du Colombier 	int rv;
6677dd7cddfSDavid du Colombier 
6684f8f669cSDavid du Colombier 	if(traceactivity)
6694f8f669cSDavid du Colombier 		dnslog("get: %d active by pid %d from %p",
6704f8f669cSDavid du Colombier 			dnvars.active, getpid(), getcallerpc(&req));
6717dd7cddfSDavid du Colombier 	lock(&dnvars);
672b4b9fc2fSDavid du Colombier 	/*
673b4b9fc2fSDavid du Colombier 	 * can't block here if we're already holding one
674b4b9fc2fSDavid du Colombier 	 * of the dnvars.active (recursive).  will deadlock.
675b4b9fc2fSDavid du Colombier 	 */
676b4b9fc2fSDavid du Colombier 	while(!recursive && dnvars.mutex){
6777dd7cddfSDavid du Colombier 		unlock(&dnvars);
678d6d99297SDavid du Colombier 		sleep(100);			/* tune; was 200 */
6797dd7cddfSDavid du Colombier 		lock(&dnvars);
6807dd7cddfSDavid du Colombier 	}
6817dd7cddfSDavid du Colombier 	rv = ++dnvars.active;
6824f8f669cSDavid du Colombier 	now = time(nil);
683a41547ffSDavid du Colombier 	nowns = nsec();
6847dd7cddfSDavid du Colombier 	req->id = ++dnvars.id;
6857dd7cddfSDavid du Colombier 	unlock(&dnvars);
6867dd7cddfSDavid du Colombier 
6877dd7cddfSDavid du Colombier 	return rv;
6887dd7cddfSDavid du Colombier }
6897dd7cddfSDavid du Colombier void
putactivity(int recursive)690b4b9fc2fSDavid du Colombier putactivity(int recursive)
6917dd7cddfSDavid du Colombier {
6927dd7cddfSDavid du Colombier 	static ulong lastclean;
6937dd7cddfSDavid du Colombier 
6944f8f669cSDavid du Colombier 	if(traceactivity)
6954f8f669cSDavid du Colombier 		dnslog("put: %d active by pid %d",
6964f8f669cSDavid du Colombier 			dnvars.active, getpid());
6977dd7cddfSDavid du Colombier 	lock(&dnvars);
6987dd7cddfSDavid du Colombier 	dnvars.active--;
6994f8f669cSDavid du Colombier 	assert(dnvars.active >= 0); /* "dnvars.active %d", dnvars.active */
7007dd7cddfSDavid du Colombier 
7017dd7cddfSDavid du Colombier 	/*
7027dd7cddfSDavid du Colombier 	 *  clean out old entries and check for new db periodicly
703b4b9fc2fSDavid du Colombier 	 *  can't block here if being called to let go a "recursive" lock
704b4b9fc2fSDavid du Colombier 	 *  or we'll deadlock waiting for ourselves to give up the dnvars.active.
7057dd7cddfSDavid du Colombier 	 */
7064f8f669cSDavid du Colombier 	if (recursive || dnvars.mutex ||
7074f8f669cSDavid du Colombier 	    (needrefresh == 0 && dnvars.active > 0)){
7087dd7cddfSDavid du Colombier 		unlock(&dnvars);
7097dd7cddfSDavid du Colombier 		return;
7107dd7cddfSDavid du Colombier 	}
7117dd7cddfSDavid du Colombier 
7127dd7cddfSDavid du Colombier 	/* wait till we're alone */
7137dd7cddfSDavid du Colombier 	dnvars.mutex = 1;
7147dd7cddfSDavid du Colombier 	while(dnvars.active > 0){
7157dd7cddfSDavid du Colombier 		unlock(&dnvars);
716d6d99297SDavid du Colombier 		sleep(100);		/* tune; was 100 */
7177dd7cddfSDavid du Colombier 		lock(&dnvars);
7187dd7cddfSDavid du Colombier 	}
7197dd7cddfSDavid du Colombier 	unlock(&dnvars);
7207dd7cddfSDavid du Colombier 
7217dd7cddfSDavid du Colombier 	db2cache(needrefresh);
72227acba7cSDavid du Colombier 
72327acba7cSDavid du Colombier 	/* if we've been running for long enough, restart */
72427acba7cSDavid du Colombier 	if(start == 0)
72527acba7cSDavid du Colombier 		start = time(nil);
726409a7d08SDavid du Colombier 	if(Restartmins > 0 && time(nil) - start > Restartmins*60){
72727acba7cSDavid du Colombier 		dnslog("killing all dns procs for timed restart");
72827acba7cSDavid du Colombier 		postnote(PNGROUP, getpid(), "die");
72927acba7cSDavid du Colombier 		dnvars.mutex = 0;
73027acba7cSDavid du Colombier 		exits("restart");
73127acba7cSDavid du Colombier 	}
73227acba7cSDavid du Colombier 
7337dd7cddfSDavid du Colombier 	dnageall(0);
7347dd7cddfSDavid du Colombier 
7357dd7cddfSDavid du Colombier 	/* let others back in */
7367dd7cddfSDavid du Colombier 	lastclean = now;
7377dd7cddfSDavid du Colombier 	needrefresh = 0;
7387dd7cddfSDavid du Colombier 	dnvars.mutex = 0;
7397dd7cddfSDavid du Colombier }
7407dd7cddfSDavid du Colombier 
741d2fd7a44SDavid du Colombier int
rrlistlen(RR * rp)742d2fd7a44SDavid du Colombier rrlistlen(RR *rp)
743d2fd7a44SDavid du Colombier {
744d2fd7a44SDavid du Colombier 	int n;
745d2fd7a44SDavid du Colombier 
746d2fd7a44SDavid du Colombier 	n = 0;
747d2fd7a44SDavid du Colombier 	for(; rp; rp = rp->next)
748d2fd7a44SDavid du Colombier 		++n;
749d2fd7a44SDavid du Colombier 	return n;
750d2fd7a44SDavid du Colombier }
751d2fd7a44SDavid du Colombier 
7523e12c5d1SDavid du Colombier /*
7536dc4800dSDavid du Colombier  *  Attach a single resource record to a domain name (new->owner).
7543e12c5d1SDavid du Colombier  *	- Avoid duplicates with already present RR's
7553e12c5d1SDavid du Colombier  *	- Chain all RR's of the same type adjacent to one another
7563e12c5d1SDavid du Colombier  *	- chain authoritative RR's ahead of non-authoritative ones
7576dc4800dSDavid du Colombier  *	- remove any expired RR's
758225077b0SDavid du Colombier  *  If new is a stale duplicate, rrfree it.
7596dc4800dSDavid du Colombier  *  Must be called with dnlock held.
7603e12c5d1SDavid du Colombier  */
7613e12c5d1SDavid du Colombier static void
rrattach1(RR * new,int auth)7623e12c5d1SDavid du Colombier rrattach1(RR *new, int auth)
7633e12c5d1SDavid du Colombier {
7643e12c5d1SDavid du Colombier 	RR **l;
7653e12c5d1SDavid du Colombier 	RR *rp;
7663e12c5d1SDavid du Colombier 	DN *dp;
7673e12c5d1SDavid du Colombier 
768*03da95d6SDavid du Colombier 	assert(new->magic == RRmagic);
769*03da95d6SDavid du Colombier 	assert(!new->cached);
7707dd7cddfSDavid du Colombier 
7714f8f669cSDavid du Colombier //	dnslog("rrattach1: %s", new->owner->name);
772e9b54818SDavid du Colombier 	if(!new->db) {
773e9b54818SDavid du Colombier 		/*
774e9b54818SDavid du Colombier 		 * try not to let responses expire before we
775e9b54818SDavid du Colombier 		 * can use them to complete this query, by extending
776e464c1a8SDavid du Colombier 		 * past (or nearly past) expiration time.
777e9b54818SDavid du Colombier 		 */
778e464c1a8SDavid du Colombier 		new->expire = new->ttl > now + Min? new->ttl: now + 10*Min;
779e9b54818SDavid du Colombier 	} else
7807dd7cddfSDavid du Colombier 		new->expire = now + Year;
7813e12c5d1SDavid du Colombier 	dp = new->owner;
7827dd7cddfSDavid du Colombier 	assert(dp->magic == DNmagic);
7837dd7cddfSDavid du Colombier 	new->auth |= auth;
7843e12c5d1SDavid du Colombier 	new->next = 0;
7853e12c5d1SDavid du Colombier 
7863e12c5d1SDavid du Colombier 	/*
7873ff48bf5SDavid du Colombier 	 *  find first rr of the right type
7883e12c5d1SDavid du Colombier 	 */
7893e12c5d1SDavid du Colombier 	l = &dp->rr;
7907dd7cddfSDavid du Colombier 	for(rp = *l; rp; rp = *l){
791*03da95d6SDavid du Colombier 		assert(rp->magic == RRmagic);
792*03da95d6SDavid du Colombier 		assert(rp->cached);
7933e12c5d1SDavid du Colombier 		if(rp->type == new->type)
7943e12c5d1SDavid du Colombier 			break;
7953e12c5d1SDavid du Colombier 		l = &rp->next;
7963e12c5d1SDavid du Colombier 	}
7973e12c5d1SDavid du Colombier 
7983e12c5d1SDavid du Colombier 	/*
7997dd7cddfSDavid du Colombier 	 *  negative entries replace positive entries
8007dd7cddfSDavid du Colombier 	 *  positive entries replace negative entries
8017dd7cddfSDavid du Colombier 	 *  newer entries replace older entries with the same fields
802225077b0SDavid du Colombier 	 *
803225077b0SDavid du Colombier 	 *  look farther ahead than just the next entry when looking
804225077b0SDavid du Colombier 	 *  for duplicates; RRs of a given type can have different rdata
805225077b0SDavid du Colombier 	 *  fields (e.g. multiple NS servers).
8063e12c5d1SDavid du Colombier 	 */
807225077b0SDavid du Colombier 	while ((rp = *l) != nil){
808*03da95d6SDavid du Colombier 		assert(rp->magic == RRmagic);
809*03da95d6SDavid du Colombier 		assert(rp->cached);
8107dd7cddfSDavid du Colombier 		if(rp->type != new->type)
8113e12c5d1SDavid du Colombier 			break;
8127dd7cddfSDavid du Colombier 
8137dd7cddfSDavid du Colombier 		if(rp->db == new->db && rp->auth == new->auth){
8147dd7cddfSDavid du Colombier 			/* negative drives out positive and vice versa */
8157dd7cddfSDavid du Colombier 			if(rp->negative != new->negative) {
8164faf7596SDavid du Colombier 				/* rp == *l before; *l == rp->next after */
8174faf7596SDavid du Colombier 				rrdelhead(l);
8184faf7596SDavid du Colombier 				continue;
8193e12c5d1SDavid du Colombier 			}
8207dd7cddfSDavid du Colombier 			/* all things equal, pick the newer one */
821225077b0SDavid du Colombier 			else if(rp->arg0 == new->arg0 && rp->arg1 == new->arg1){
8227dd7cddfSDavid du Colombier 				/* new drives out old */
823225077b0SDavid du Colombier 				if (new->ttl <= rp->ttl &&
824225077b0SDavid du Colombier 				    new->expire <= rp->expire) {
8253e12c5d1SDavid du Colombier 					rrfree(new);
8263e12c5d1SDavid du Colombier 					return;
8273e12c5d1SDavid du Colombier 				}
8284faf7596SDavid du Colombier 				/* rp == *l before; *l == rp->next after */
8294faf7596SDavid du Colombier 				rrdelhead(l);
8304faf7596SDavid du Colombier 				continue;
8317dd7cddfSDavid du Colombier 			}
832225077b0SDavid du Colombier 			/*
833225077b0SDavid du Colombier 			 *  Hack for pointer records.  This makes sure
8343ff48bf5SDavid du Colombier 			 *  the ordering in the list reflects the ordering
8353ff48bf5SDavid du Colombier 			 *  received or read from the database
8363ff48bf5SDavid du Colombier 			 */
837225077b0SDavid du Colombier 			else if(rp->type == Tptr &&
838225077b0SDavid du Colombier 			    !rp->negative && !new->negative &&
839225077b0SDavid du Colombier 			    rp->ptr->ordinal > new->ptr->ordinal)
8403ff48bf5SDavid du Colombier 				break;
8413ff48bf5SDavid du Colombier 		}
8423e12c5d1SDavid du Colombier 		l = &rp->next;
8433e12c5d1SDavid du Colombier 	}
8443e12c5d1SDavid du Colombier 
845530fef66SDavid du Colombier 	if (rronlist(new, rp)) {
8464f927735SDavid du Colombier 		/* should not happen; duplicates were processed above */
847530fef66SDavid du Colombier 		dnslog("adding duplicate %R to list of %R; aborting", new, rp);
8484f927735SDavid du Colombier 		abort();
8494f927735SDavid du Colombier 	}
8503e12c5d1SDavid du Colombier 	/*
8513e12c5d1SDavid du Colombier 	 *  add to chain
8523e12c5d1SDavid du Colombier 	 */
8537dd7cddfSDavid du Colombier 	new->cached = 1;
854530fef66SDavid du Colombier 	new->next = rp;
8553e12c5d1SDavid du Colombier 	*l = new;
8563e12c5d1SDavid du Colombier }
8573e12c5d1SDavid du Colombier 
8583e12c5d1SDavid du Colombier /*
8593e12c5d1SDavid du Colombier  *  Attach a list of resource records to a domain name.
860225077b0SDavid du Colombier  *  May rrfree any stale duplicate RRs; dismembers the list.
861225077b0SDavid du Colombier  *  Upon return, every RR in the list will have been rrfree-d
862225077b0SDavid du Colombier  *  or attached to its domain name.
8636dc4800dSDavid du Colombier  *  See rrattach1 for properties preserved.
8643e12c5d1SDavid du Colombier  */
8653e12c5d1SDavid du Colombier void
rrattach(RR * rp,int auth)8663e12c5d1SDavid du Colombier rrattach(RR *rp, int auth)
8673e12c5d1SDavid du Colombier {
868e6d9d902SDavid du Colombier 	RR *next, *tp;
869d2fd7a44SDavid du Colombier 	DN *dp;
8703e12c5d1SDavid du Colombier 
871bd389b36SDavid du Colombier 	lock(&dnlock);
8723e12c5d1SDavid du Colombier 	for(; rp; rp = next){
8733e12c5d1SDavid du Colombier 		next = rp->next;
8744f8f669cSDavid du Colombier 		rp->next = nil;
875d2fd7a44SDavid du Colombier 		dp = rp->owner;
8767dd7cddfSDavid du Colombier 
8774f8f669cSDavid du Colombier //		dnslog("rrattach: %s", rp->owner->name);
878c3617180SDavid du Colombier 		/* avoid any outside spoofing; leave keepers alone */
879c3617180SDavid du Colombier 		if(cfg.cachedb && !rp->db && inmyarea(rp->owner->name)
880c3617180SDavid du Colombier //		    || dp->keep			/* TODO: make this work */
881c3617180SDavid du Colombier 		    )
8827dd7cddfSDavid du Colombier 			rrfree(rp);
883d2fd7a44SDavid du Colombier 		else {
8844faf7596SDavid du Colombier 			/* ameliorate the memory leak (someday delete this) */
885530fef66SDavid du Colombier 			if (0 && rrlistlen(dp->rr) > 50 && !dp->keep) {
886530fef66SDavid du Colombier 				dnslog("rrattach(%s): rr list too long; "
887530fef66SDavid du Colombier 					"freeing it", dp->name);
888e6d9d902SDavid du Colombier 				tp = dp->rr;
889530fef66SDavid du Colombier 				dp->rr = nil;
890e6d9d902SDavid du Colombier 				rrfreelist(tp);
891530fef66SDavid du Colombier 			} else
892530fef66SDavid du Colombier 				USED(dp);
8933e12c5d1SDavid du Colombier 			rrattach1(rp, auth);
894d2fd7a44SDavid du Colombier 		}
8953e12c5d1SDavid du Colombier 	}
896bd389b36SDavid du Colombier 	unlock(&dnlock);
8973e12c5d1SDavid du Colombier }
8983e12c5d1SDavid du Colombier 
899530fef66SDavid du Colombier /* should be called with dnlock held */
9004f8f669cSDavid du Colombier RR**
rrcopy(RR * rp,RR ** last)9017dd7cddfSDavid du Colombier rrcopy(RR *rp, RR **last)
9027dd7cddfSDavid du Colombier {
9034f8f669cSDavid du Colombier 	Cert *cert;
9044f8f669cSDavid du Colombier 	Key *key;
9054f8f669cSDavid du Colombier 	Null *null;
9067dd7cddfSDavid du Colombier 	RR *nrp;
9077dd7cddfSDavid du Colombier 	SOA *soa;
9089a747e4fSDavid du Colombier 	Sig *sig;
90960845620SDavid du Colombier 	Txt *t, *nt, **l;
9107dd7cddfSDavid du Colombier 
9114faf7596SDavid du Colombier 	if (canlock(&dnlock))
9124faf7596SDavid du Colombier 		abort();	/* rrcopy called with dnlock not held */
9137dd7cddfSDavid du Colombier 	nrp = rralloc(rp->type);
914a41547ffSDavid du Colombier 	setmalloctag(nrp, getcallerpc(&rp));
9159a747e4fSDavid du Colombier 	switch(rp->type){
91660845620SDavid du Colombier 	case Ttxt:
91760845620SDavid du Colombier 		*nrp = *rp;
91860845620SDavid du Colombier 		l = &nrp->txt;
91960845620SDavid du Colombier 		*l = nil;
92060845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next){
92160845620SDavid du Colombier 			nt = emalloc(sizeof(*nt));
92260845620SDavid du Colombier 			nt->p = estrdup(t->p);
92360845620SDavid du Colombier 			nt->next = nil;
92460845620SDavid du Colombier 			*l = nt;
92560845620SDavid du Colombier 			l = &nt->next;
92660845620SDavid du Colombier 		}
92760845620SDavid du Colombier 		break;
9289a747e4fSDavid du Colombier 	case Tsoa:
9297dd7cddfSDavid du Colombier 		soa = nrp->soa;
9307dd7cddfSDavid du Colombier 		*nrp = *rp;
9317dd7cddfSDavid du Colombier 		nrp->soa = soa;
9327dd7cddfSDavid du Colombier 		*nrp->soa = *rp->soa;
933dc5a79c1SDavid du Colombier 		nrp->soa->slaves = copyserverlist(rp->soa->slaves);
9349a747e4fSDavid du Colombier 		break;
9354f8f669cSDavid du Colombier 	case Tsrv:
9364f8f669cSDavid du Colombier 		*nrp = *rp;
937fd87a217SDavid du Colombier 		nrp->srv = emalloc(sizeof *nrp->srv);
9384f8f669cSDavid du Colombier 		*nrp->srv = *rp->srv;
9394f8f669cSDavid du Colombier 		break;
9409a747e4fSDavid du Colombier 	case Tkey:
9419a747e4fSDavid du Colombier 		key = nrp->key;
9429a747e4fSDavid du Colombier 		*nrp = *rp;
9439a747e4fSDavid du Colombier 		nrp->key = key;
9449a747e4fSDavid du Colombier 		*key = *rp->key;
9459a747e4fSDavid du Colombier 		key->data = emalloc(key->dlen);
9469a747e4fSDavid du Colombier 		memmove(key->data, rp->key->data, rp->key->dlen);
9479a747e4fSDavid du Colombier 		break;
9489a747e4fSDavid du Colombier 	case Tsig:
9499a747e4fSDavid du Colombier 		sig = nrp->sig;
9509a747e4fSDavid du Colombier 		*nrp = *rp;
9519a747e4fSDavid du Colombier 		nrp->sig = sig;
9529a747e4fSDavid du Colombier 		*sig = *rp->sig;
9539a747e4fSDavid du Colombier 		sig->data = emalloc(sig->dlen);
9549a747e4fSDavid du Colombier 		memmove(sig->data, rp->sig->data, rp->sig->dlen);
9559a747e4fSDavid du Colombier 		break;
9569a747e4fSDavid du Colombier 	case Tcert:
9579a747e4fSDavid du Colombier 		cert = nrp->cert;
9589a747e4fSDavid du Colombier 		*nrp = *rp;
9599a747e4fSDavid du Colombier 		nrp->cert = cert;
9609a747e4fSDavid du Colombier 		*cert = *rp->cert;
9619a747e4fSDavid du Colombier 		cert->data = emalloc(cert->dlen);
9629a747e4fSDavid du Colombier 		memmove(cert->data, rp->cert->data, rp->cert->dlen);
9639a747e4fSDavid du Colombier 		break;
9649a747e4fSDavid du Colombier 	case Tnull:
9659a747e4fSDavid du Colombier 		null = nrp->null;
9669a747e4fSDavid du Colombier 		*nrp = *rp;
9679a747e4fSDavid du Colombier 		nrp->null = null;
9689a747e4fSDavid du Colombier 		*null = *rp->null;
9699a747e4fSDavid du Colombier 		null->data = emalloc(null->dlen);
9709a747e4fSDavid du Colombier 		memmove(null->data, rp->null->data, rp->null->dlen);
9719a747e4fSDavid du Colombier 		break;
9729a747e4fSDavid du Colombier 	default:
9739a747e4fSDavid du Colombier 		*nrp = *rp;
9749a747e4fSDavid du Colombier 		break;
9757dd7cddfSDavid du Colombier 	}
9767dd7cddfSDavid du Colombier 	nrp->cached = 0;
9777dd7cddfSDavid du Colombier 	nrp->next = 0;
9787dd7cddfSDavid du Colombier 	*last = nrp;
9797dd7cddfSDavid du Colombier 	return &nrp->next;
9807dd7cddfSDavid du Colombier }
9817dd7cddfSDavid du Colombier 
9823e12c5d1SDavid du Colombier /*
9833e12c5d1SDavid du Colombier  *  lookup a resource record of a particular type and
9847dd7cddfSDavid du Colombier  *  class attached to a domain name.  Return copies.
9857dd7cddfSDavid du Colombier  *
9867dd7cddfSDavid du Colombier  *  Priority ordering is:
9877dd7cddfSDavid du Colombier  *	db authoritative
9887dd7cddfSDavid du Colombier  *	not timed out network authoritative
9897dd7cddfSDavid du Colombier  *	not timed out network unauthoritative
9907dd7cddfSDavid du Colombier  *	unauthoritative db
9917dd7cddfSDavid du Colombier  *
99280ee5cbfSDavid du Colombier  *  if flag NOneg is set, don't return negative cached entries.
9937dd7cddfSDavid du Colombier  *  return nothing instead.
9943e12c5d1SDavid du Colombier  */
9953e12c5d1SDavid du Colombier RR*
rrlookup(DN * dp,int type,int flag)9967dd7cddfSDavid du Colombier rrlookup(DN *dp, int type, int flag)
9973e12c5d1SDavid du Colombier {
9987dd7cddfSDavid du Colombier 	RR *rp, *first, **last;
9993e12c5d1SDavid du Colombier 
10007dd7cddfSDavid du Colombier 	assert(dp->magic == DNmagic);
10017dd7cddfSDavid du Colombier 
10027dd7cddfSDavid du Colombier 	first = 0;
10037dd7cddfSDavid du Colombier 	last = &first;
10047dd7cddfSDavid du Colombier 	lock(&dnlock);
10057dd7cddfSDavid du Colombier 
10067dd7cddfSDavid du Colombier 	/* try for an authoritative db entry */
10073e12c5d1SDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
100898813beeSDavid du Colombier 		assert(rp->magic == RRmagic);
100998813beeSDavid du Colombier 		assert(rp->cached);
10107dd7cddfSDavid du Colombier 		if(rp->db)
10117dd7cddfSDavid du Colombier 		if(rp->auth)
1012a41547ffSDavid du Colombier 		if(tsame(type, rp->type)) {
10134e5f5f32SDavid du Colombier 			last = rrcopy(rp, last);
1014a41547ffSDavid du Colombier 			// setmalloctag(*last, getcallerpc(&dp));
1015a41547ffSDavid du Colombier 		}
10163e12c5d1SDavid du Colombier 	}
10177dd7cddfSDavid du Colombier 	if(first)
10187dd7cddfSDavid du Colombier 		goto out;
10197dd7cddfSDavid du Colombier 
10204f8f669cSDavid du Colombier 	/* try for a living authoritative network entry */
10217dd7cddfSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
10227dd7cddfSDavid du Colombier 		if(!rp->db)
10237dd7cddfSDavid du Colombier 		if(rp->auth)
10247dd7cddfSDavid du Colombier 		if(rp->ttl + 60 > now)
10257dd7cddfSDavid du Colombier 		if(tsame(type, rp->type)){
10267dd7cddfSDavid du Colombier 			if(flag == NOneg && rp->negative)
10277dd7cddfSDavid du Colombier 				goto out;
10287dd7cddfSDavid du Colombier 			last = rrcopy(rp, last);
10297dd7cddfSDavid du Colombier 		}
10307dd7cddfSDavid du Colombier 	}
10317dd7cddfSDavid du Colombier 	if(first)
10327dd7cddfSDavid du Colombier 		goto out;
10337dd7cddfSDavid du Colombier 
10344f8f669cSDavid du Colombier 	/* try for a living unauthoritative network entry */
10357dd7cddfSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
10367dd7cddfSDavid du Colombier 		if(!rp->db)
10377dd7cddfSDavid du Colombier 		if(rp->ttl + 60 > now)
10387dd7cddfSDavid du Colombier 		if(tsame(type, rp->type)){
10397dd7cddfSDavid du Colombier 			if(flag == NOneg && rp->negative)
10407dd7cddfSDavid du Colombier 				goto out;
10414e5f5f32SDavid du Colombier 			last = rrcopy(rp, last);
10427dd7cddfSDavid du Colombier 		}
10437dd7cddfSDavid du Colombier 	}
10447dd7cddfSDavid du Colombier 	if(first)
10457dd7cddfSDavid du Colombier 		goto out;
10467dd7cddfSDavid du Colombier 
10477dd7cddfSDavid du Colombier 	/* try for an unauthoritative db entry */
10487dd7cddfSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next){
10497dd7cddfSDavid du Colombier 		if(rp->db)
10507dd7cddfSDavid du Colombier 		if(tsame(type, rp->type))
10517dd7cddfSDavid du Colombier 			last = rrcopy(rp, last);
10527dd7cddfSDavid du Colombier 	}
10537dd7cddfSDavid du Colombier 	if(first)
10547dd7cddfSDavid du Colombier 		goto out;
10557dd7cddfSDavid du Colombier 
10567dd7cddfSDavid du Colombier 	/* otherwise, settle for anything we got (except for negative caches) */
10574f8f669cSDavid du Colombier 	for(rp = dp->rr; rp; rp = rp->next)
10587dd7cddfSDavid du Colombier 		if(tsame(type, rp->type)){
10597dd7cddfSDavid du Colombier 			if(rp->negative)
10607dd7cddfSDavid du Colombier 				goto out;
10617dd7cddfSDavid du Colombier 			last = rrcopy(rp, last);
10627dd7cddfSDavid du Colombier 		}
10637dd7cddfSDavid du Colombier 
10647dd7cddfSDavid du Colombier out:
10657dd7cddfSDavid du Colombier 	unique(first);
1066c3617180SDavid du Colombier 	unlock(&dnlock);
10674f8f669cSDavid du Colombier //	dnslog("rrlookup(%s) -> %#p\t# in-core only", dp->name, first);
1068a41547ffSDavid du Colombier //	if (first)
1069a41547ffSDavid du Colombier //		setmalloctag(first, getcallerpc(&dp));
10707dd7cddfSDavid du Colombier 	return first;
10713e12c5d1SDavid du Colombier }
10723e12c5d1SDavid du Colombier 
10733e12c5d1SDavid du Colombier /*
10743e12c5d1SDavid du Colombier  *  convert an ascii RR type name to its integer representation
10753e12c5d1SDavid du Colombier  */
10763e12c5d1SDavid du Colombier int
rrtype(char * atype)10773e12c5d1SDavid du Colombier rrtype(char *atype)
10783e12c5d1SDavid du Colombier {
10793e12c5d1SDavid du Colombier 	int i;
10803e12c5d1SDavid du Colombier 
1081219b2ee8SDavid du Colombier 	for(i = 0; i <= Tall; i++)
10823e12c5d1SDavid du Colombier 		if(rrtname[i] && strcmp(rrtname[i], atype) == 0)
10833e12c5d1SDavid du Colombier 			return i;
10847dd7cddfSDavid du Colombier 
10854f8f669cSDavid du Colombier 	/* make any a synonym for all */
10867dd7cddfSDavid du Colombier 	if(strcmp(atype, "any") == 0)
10877dd7cddfSDavid du Colombier 		return Tall;
1088d9924332SDavid du Colombier 	else if(isascii(atype[0]) && isdigit(atype[0]))
10893e12c5d1SDavid du Colombier 		return atoi(atype);
1090d9924332SDavid du Colombier 	else
1091d9924332SDavid du Colombier 		return -1;
10923e12c5d1SDavid du Colombier }
10933e12c5d1SDavid du Colombier 
10943e12c5d1SDavid du Colombier /*
10955d459b5aSDavid du Colombier  *  return 0 if not a supported rr type
10965d459b5aSDavid du Colombier  */
10975d459b5aSDavid du Colombier int
rrsupported(int type)10985d459b5aSDavid du Colombier rrsupported(int type)
10995d459b5aSDavid du Colombier {
11005d459b5aSDavid du Colombier 	if(type < 0 || type >Tall)
11015d459b5aSDavid du Colombier 		return 0;
11024f8f669cSDavid du Colombier 	return rrtname[type] != nil;
11035d459b5aSDavid du Colombier }
11045d459b5aSDavid du Colombier 
11055d459b5aSDavid du Colombier /*
1106219b2ee8SDavid du Colombier  *  compare 2 types
1107219b2ee8SDavid du Colombier  */
1108219b2ee8SDavid du Colombier int
tsame(int t1,int t2)1109219b2ee8SDavid du Colombier tsame(int t1, int t2)
1110219b2ee8SDavid du Colombier {
1111219b2ee8SDavid du Colombier 	return t1 == t2 || t1 == Tall;
1112219b2ee8SDavid du Colombier }
1113219b2ee8SDavid du Colombier 
1114219b2ee8SDavid du Colombier /*
11157dd7cddfSDavid du Colombier  *  Add resource records to a list, duplicate them if they are cached
1116530fef66SDavid du Colombier  *  RR's since these are shared.  should be called with dnlock held
1117530fef66SDavid du Colombier  *  to avoid racing down the start chain.
11183e12c5d1SDavid du Colombier  */
11193e12c5d1SDavid du Colombier RR*
rrcat(RR ** start,RR * rp)11207dd7cddfSDavid du Colombier rrcat(RR **start, RR *rp)
11213e12c5d1SDavid du Colombier {
1122225077b0SDavid du Colombier 	RR *olp, *nlp;
11233e12c5d1SDavid du Colombier 	RR **last;
11243e12c5d1SDavid du Colombier 
11254faf7596SDavid du Colombier 	if (canlock(&dnlock))
11264faf7596SDavid du Colombier 		abort();	/* rrcat called with dnlock not held */
1127225077b0SDavid du Colombier 	/* check for duplicates */
1128225077b0SDavid du Colombier 	for (olp = *start; 0 && olp; olp = olp->next)
1129225077b0SDavid du Colombier 		for (nlp = rp; nlp; nlp = nlp->next)
1130225077b0SDavid du Colombier 			if (rrsame(nlp, olp))
1131225077b0SDavid du Colombier 				dnslog("rrcat: duplicate RR: %R", nlp);
1132225077b0SDavid du Colombier 	USED(olp);
1133225077b0SDavid du Colombier 
11343e12c5d1SDavid du Colombier 	last = start;
11354f8f669cSDavid du Colombier 	while(*last != nil)
11363e12c5d1SDavid du Colombier 		last = &(*last)->next;
11373e12c5d1SDavid du Colombier 
11387dd7cddfSDavid du Colombier 	*last = rp;
11397dd7cddfSDavid du Colombier 	return *start;
11403e12c5d1SDavid du Colombier }
11413e12c5d1SDavid du Colombier 
11427dd7cddfSDavid du Colombier /*
11437dd7cddfSDavid du Colombier  *  remove negative cache rr's from an rr list
11447dd7cddfSDavid du Colombier  */
11457dd7cddfSDavid du Colombier RR*
rrremneg(RR ** l)11467dd7cddfSDavid du Colombier rrremneg(RR **l)
11477dd7cddfSDavid du Colombier {
11487dd7cddfSDavid du Colombier 	RR **nl, *rp;
11497dd7cddfSDavid du Colombier 	RR *first;
11507dd7cddfSDavid du Colombier 
115159f7772cSDavid du Colombier 	if (canlock(&dnlock))
115259f7772cSDavid du Colombier 		abort();	/* rrremneg called with dnlock not held */
11537dd7cddfSDavid du Colombier 	first = nil;
11547dd7cddfSDavid du Colombier 	nl = &first;
11557dd7cddfSDavid du Colombier 	while(*l != nil){
11567dd7cddfSDavid du Colombier 		rp = *l;
11577dd7cddfSDavid du Colombier 		if(rp->negative){
11587dd7cddfSDavid du Colombier 			*l = rp->next;
11597dd7cddfSDavid du Colombier 			*nl = rp;
11607dd7cddfSDavid du Colombier 			nl = &rp->next;
11617dd7cddfSDavid du Colombier 			*nl = nil;
11627dd7cddfSDavid du Colombier 		} else
116380ee5cbfSDavid du Colombier 			l = &rp->next;
11647dd7cddfSDavid du Colombier 	}
11657dd7cddfSDavid du Colombier 
11667dd7cddfSDavid du Colombier 	return first;
11677dd7cddfSDavid du Colombier }
11687dd7cddfSDavid du Colombier 
11697dd7cddfSDavid du Colombier /*
11707dd7cddfSDavid du Colombier  *  remove rr's of a particular type from an rr list
11717dd7cddfSDavid du Colombier  */
11727dd7cddfSDavid du Colombier RR*
rrremtype(RR ** l,int type)11737dd7cddfSDavid du Colombier rrremtype(RR **l, int type)
11747dd7cddfSDavid du Colombier {
11754f8f669cSDavid du Colombier 	RR *first, *rp;
11764f8f669cSDavid du Colombier 	RR **nl;
11777dd7cddfSDavid du Colombier 
11787dd7cddfSDavid du Colombier 	first = nil;
11797dd7cddfSDavid du Colombier 	nl = &first;
11807dd7cddfSDavid du Colombier 	while(*l != nil){
11817dd7cddfSDavid du Colombier 		rp = *l;
11827dd7cddfSDavid du Colombier 		if(rp->type == type){
11837dd7cddfSDavid du Colombier 			*l = rp->next;
11847dd7cddfSDavid du Colombier 			*nl = rp;
11857dd7cddfSDavid du Colombier 			nl = &rp->next;
11867dd7cddfSDavid du Colombier 			*nl = nil;
11877dd7cddfSDavid du Colombier 		} else
11887dd7cddfSDavid du Colombier 			l = &(*l)->next;
11897dd7cddfSDavid du Colombier 	}
11907dd7cddfSDavid du Colombier 
11917dd7cddfSDavid du Colombier 	return first;
11923e12c5d1SDavid du Colombier }
11933e12c5d1SDavid du Colombier 
11944f8f669cSDavid du Colombier static char *
dnname(DN * dn)11954f8f669cSDavid du Colombier dnname(DN *dn)
11964f8f669cSDavid du Colombier {
11974f8f669cSDavid du Colombier 	return dn? dn->name: "<null>";
11984f8f669cSDavid du Colombier }
11994f8f669cSDavid du Colombier 
12003e12c5d1SDavid du Colombier /*
12013e12c5d1SDavid du Colombier  *  print conversion for rr records
12023e12c5d1SDavid du Colombier  */
12033e12c5d1SDavid du Colombier int
rrfmt(Fmt * f)12049a747e4fSDavid du Colombier rrfmt(Fmt *f)
12053e12c5d1SDavid du Colombier {
12066b0d5c8bSDavid du Colombier 	int rv;
12074f8f669cSDavid du Colombier 	char *strp;
12086b0d5c8bSDavid du Colombier 	char buf[Domlen];
12094f8f669cSDavid du Colombier 	Fmt fstr;
12104f8f669cSDavid du Colombier 	RR *rp;
1211dc5a79c1SDavid du Colombier 	Server *s;
12124f8f669cSDavid du Colombier 	SOA *soa;
12134f8f669cSDavid du Colombier 	Srv *srv;
121460845620SDavid du Colombier 	Txt *t;
12153e12c5d1SDavid du Colombier 
12169a747e4fSDavid du Colombier 	fmtstrinit(&fstr);
12179a747e4fSDavid du Colombier 
12189a747e4fSDavid du Colombier 	rp = va_arg(f->args, RR*);
12194f8f669cSDavid du Colombier 	if(rp == nil){
12209a747e4fSDavid du Colombier 		fmtprint(&fstr, "<null>");
1221219b2ee8SDavid du Colombier 		goto out;
1222219b2ee8SDavid du Colombier 	}
1223219b2ee8SDavid du Colombier 
12244f8f669cSDavid du Colombier 	fmtprint(&fstr, "%s %s", dnname(rp->owner),
12259a747e4fSDavid du Colombier 		rrname(rp->type, buf, sizeof buf));
12267dd7cddfSDavid du Colombier 
12277dd7cddfSDavid du Colombier 	if(rp->negative){
12289a747e4fSDavid du Colombier 		fmtprint(&fstr, "\tnegative - rcode %d", rp->negrcode);
12297dd7cddfSDavid du Colombier 		goto out;
12307dd7cddfSDavid du Colombier 	}
12313e12c5d1SDavid du Colombier 
12323e12c5d1SDavid du Colombier 	switch(rp->type){
12333e12c5d1SDavid du Colombier 	case Thinfo:
12344f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s", dnname(rp->cpu), dnname(rp->os));
12353e12c5d1SDavid du Colombier 		break;
12363e12c5d1SDavid du Colombier 	case Tcname:
12373e12c5d1SDavid du Colombier 	case Tmb:
12383e12c5d1SDavid du Colombier 	case Tmd:
12393e12c5d1SDavid du Colombier 	case Tmf:
12403e12c5d1SDavid du Colombier 	case Tns:
12414f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->host));
12423e12c5d1SDavid du Colombier 		break;
12433e12c5d1SDavid du Colombier 	case Tmg:
12443e12c5d1SDavid du Colombier 	case Tmr:
12454f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->mb));
12463e12c5d1SDavid du Colombier 		break;
12473e12c5d1SDavid du Colombier 	case Tminfo:
12484f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s", dnname(rp->mb), dnname(rp->rmb));
12493e12c5d1SDavid du Colombier 		break;
12503e12c5d1SDavid du Colombier 	case Tmx:
12514f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%lud %s", rp->pref, dnname(rp->host));
12523e12c5d1SDavid du Colombier 		break;
12533e12c5d1SDavid du Colombier 	case Ta:
12545d459b5aSDavid du Colombier 	case Taaaa:
12554f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->ip));
12563e12c5d1SDavid du Colombier 		break;
12573e12c5d1SDavid du Colombier 	case Tptr:
12584f8f669cSDavid du Colombier //		fmtprint(&fstr, "\t%s(%lud)", dnname(rp->ptr),
12594f8f669cSDavid du Colombier //			rp->ptr? rp->ptr->ordinal: "<null>");
12604f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s", dnname(rp->ptr));
12613e12c5d1SDavid du Colombier 		break;
12623e12c5d1SDavid du Colombier 	case Tsoa:
12634f8f669cSDavid du Colombier 		soa = rp->soa;
12644f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s %lud %lud %lud %lud %lud",
12654f8f669cSDavid du Colombier 			dnname(rp->host), dnname(rp->rmb),
12664f8f669cSDavid du Colombier 			(soa? soa->serial: 0),
12674f8f669cSDavid du Colombier 			(soa? soa->refresh: 0), (soa? soa->retry: 0),
12684f8f669cSDavid du Colombier 			(soa? soa->expire: 0), (soa? soa->minttl: 0));
12694f8f669cSDavid du Colombier 		if (soa)
12704f8f669cSDavid du Colombier 			for(s = soa->slaves; s != nil; s = s->next)
1271dc5a79c1SDavid du Colombier 				fmtprint(&fstr, " %s", s->name);
12723e12c5d1SDavid du Colombier 		break;
12734f8f669cSDavid du Colombier 	case Tsrv:
12744f8f669cSDavid du Colombier 		srv = rp->srv;
12754f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%ud %ud %ud %s",
12764f8f669cSDavid du Colombier 			(srv? srv->pri: 0), (srv? srv->weight: 0),
1277225077b0SDavid du Colombier 			rp->port, dnname(rp->host));
12784f8f669cSDavid du Colombier 		break;
12799a747e4fSDavid du Colombier 	case Tnull:
12804f8f669cSDavid du Colombier 		if (rp->null == nil)
12814f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t<null>");
12824f8f669cSDavid du Colombier 		else
12834f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t%.*H", rp->null->dlen,
12844f8f669cSDavid du Colombier 				rp->null->data);
12859a747e4fSDavid du Colombier 		break;
12867dd7cddfSDavid du Colombier 	case Ttxt:
128760845620SDavid du Colombier 		fmtprint(&fstr, "\t");
128860845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next)
128960845620SDavid du Colombier 			fmtprint(&fstr, "%s", t->p);
12907dd7cddfSDavid du Colombier 		break;
12917dd7cddfSDavid du Colombier 	case Trp:
12924f8f669cSDavid du Colombier 		fmtprint(&fstr, "\t%s %s", dnname(rp->rmb), dnname(rp->rp));
12937dd7cddfSDavid du Colombier 		break;
12947dd7cddfSDavid du Colombier 	case Tkey:
12954f8f669cSDavid du Colombier 		if (rp->key == nil)
12964f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t<null> <null> <null>");
12974f8f669cSDavid du Colombier 		else
12984f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t%d %d %d", rp->key->flags,
12994f8f669cSDavid du Colombier 				rp->key->proto, rp->key->alg);
13007dd7cddfSDavid du Colombier 		break;
13017dd7cddfSDavid du Colombier 	case Tsig:
13024f8f669cSDavid du Colombier 		if (rp->sig == nil)
13034f8f669cSDavid du Colombier 			fmtprint(&fstr,
13044f8f669cSDavid du Colombier 		   "\t<null> <null> <null> <null> <null> <null> <null> <null>");
13054f8f669cSDavid du Colombier 		else
13069a747e4fSDavid du Colombier 			fmtprint(&fstr, "\t%d %d %d %lud %lud %lud %d %s",
13074f8f669cSDavid du Colombier 				rp->sig->type, rp->sig->alg, rp->sig->labels,
13084f8f669cSDavid du Colombier 				rp->sig->ttl, rp->sig->exp, rp->sig->incep,
13094f8f669cSDavid du Colombier 				rp->sig->tag, dnname(rp->sig->signer));
13107dd7cddfSDavid du Colombier 		break;
13117dd7cddfSDavid du Colombier 	case Tcert:
13124f8f669cSDavid du Colombier 		if (rp->cert == nil)
13134f8f669cSDavid du Colombier 			fmtprint(&fstr, "\t<null> <null> <null>");
13144f8f669cSDavid du Colombier 		else
13159a747e4fSDavid du Colombier 			fmtprint(&fstr, "\t%d %d %d",
13164f8f669cSDavid du Colombier 				rp->cert->type, rp->cert->tag, rp->cert->alg);
13173e12c5d1SDavid du Colombier 		break;
13183e12c5d1SDavid du Colombier 	}
1319219b2ee8SDavid du Colombier out:
13209a747e4fSDavid du Colombier 	strp = fmtstrflush(&fstr);
13219a747e4fSDavid du Colombier 	rv = fmtstrcpy(f, strp);
13229a747e4fSDavid du Colombier 	free(strp);
13239a747e4fSDavid du Colombier 	return rv;
13243e12c5d1SDavid du Colombier }
13253e12c5d1SDavid du Colombier 
13263e12c5d1SDavid du Colombier /*
13277dd7cddfSDavid du Colombier  *  print conversion for rr records in attribute value form
13287dd7cddfSDavid du Colombier  */
13297dd7cddfSDavid du Colombier int
rravfmt(Fmt * f)13309a747e4fSDavid du Colombier rravfmt(Fmt *f)
13317dd7cddfSDavid du Colombier {
13324f8f669cSDavid du Colombier 	int rv, quote;
13339a747e4fSDavid du Colombier 	char *strp;
13349a747e4fSDavid du Colombier 	Fmt fstr;
13354f8f669cSDavid du Colombier 	RR *rp;
1336dc5a79c1SDavid du Colombier 	Server *s;
13374f8f669cSDavid du Colombier 	SOA *soa;
13384f8f669cSDavid du Colombier 	Srv *srv;
133960845620SDavid du Colombier 	Txt *t;
13407dd7cddfSDavid du Colombier 
13419a747e4fSDavid du Colombier 	fmtstrinit(&fstr);
13429a747e4fSDavid du Colombier 
13439a747e4fSDavid du Colombier 	rp = va_arg(f->args, RR*);
13444f8f669cSDavid du Colombier 	if(rp == nil){
13459a747e4fSDavid du Colombier 		fmtprint(&fstr, "<null>");
13467dd7cddfSDavid du Colombier 		goto out;
13477dd7cddfSDavid du Colombier 	}
13487dd7cddfSDavid du Colombier 
13497dd7cddfSDavid du Colombier 	if(rp->type == Tptr)
13504f8f669cSDavid du Colombier 		fmtprint(&fstr, "ptr=%s", dnname(rp->owner));
13517dd7cddfSDavid du Colombier 	else
13524f8f669cSDavid du Colombier 		fmtprint(&fstr, "dom=%s", dnname(rp->owner));
13537dd7cddfSDavid du Colombier 
13547dd7cddfSDavid du Colombier 	switch(rp->type){
13557dd7cddfSDavid du Colombier 	case Thinfo:
13564f8f669cSDavid du Colombier 		fmtprint(&fstr, " cpu=%s os=%s",
13574f8f669cSDavid du Colombier 			dnname(rp->cpu), dnname(rp->os));
13587dd7cddfSDavid du Colombier 		break;
13597dd7cddfSDavid du Colombier 	case Tcname:
13604f8f669cSDavid du Colombier 		fmtprint(&fstr, " cname=%s", dnname(rp->host));
13617dd7cddfSDavid du Colombier 		break;
13627dd7cddfSDavid du Colombier 	case Tmb:
13637dd7cddfSDavid du Colombier 	case Tmd:
13647dd7cddfSDavid du Colombier 	case Tmf:
13654f8f669cSDavid du Colombier 		fmtprint(&fstr, " mbox=%s", dnname(rp->host));
13667dd7cddfSDavid du Colombier 		break;
13677dd7cddfSDavid du Colombier 	case Tns:
13684f8f669cSDavid du Colombier 		fmtprint(&fstr,  " ns=%s", dnname(rp->host));
13697dd7cddfSDavid du Colombier 		break;
13707dd7cddfSDavid du Colombier 	case Tmg:
13717dd7cddfSDavid du Colombier 	case Tmr:
13724f8f669cSDavid du Colombier 		fmtprint(&fstr, " mbox=%s", dnname(rp->mb));
13737dd7cddfSDavid du Colombier 		break;
13747dd7cddfSDavid du Colombier 	case Tminfo:
13754f8f669cSDavid du Colombier 		fmtprint(&fstr, " mbox=%s mbox=%s",
13764f8f669cSDavid du Colombier 			dnname(rp->mb), dnname(rp->rmb));
13777dd7cddfSDavid du Colombier 		break;
13787dd7cddfSDavid du Colombier 	case Tmx:
13794f8f669cSDavid du Colombier 		fmtprint(&fstr, " pref=%lud mx=%s", rp->pref, dnname(rp->host));
13807dd7cddfSDavid du Colombier 		break;
13817dd7cddfSDavid du Colombier 	case Ta:
13825d459b5aSDavid du Colombier 	case Taaaa:
13834f8f669cSDavid du Colombier 		fmtprint(&fstr, " ip=%s", dnname(rp->ip));
13847dd7cddfSDavid du Colombier 		break;
13857dd7cddfSDavid du Colombier 	case Tptr:
13864f8f669cSDavid du Colombier 		fmtprint(&fstr, " dom=%s", dnname(rp->ptr));
13877dd7cddfSDavid du Colombier 		break;
13887dd7cddfSDavid du Colombier 	case Tsoa:
13894f8f669cSDavid du Colombier 		soa = rp->soa;
13904f8f669cSDavid du Colombier 		fmtprint(&fstr,
13914f8f669cSDavid du Colombier " ns=%s mbox=%s serial=%lud refresh=%lud retry=%lud expire=%lud ttl=%lud",
13924f8f669cSDavid du Colombier 			dnname(rp->host), dnname(rp->rmb),
13934f8f669cSDavid du Colombier 			(soa? soa->serial: 0),
13944f8f669cSDavid du Colombier 			(soa? soa->refresh: 0), (soa? soa->retry: 0),
13954f8f669cSDavid du Colombier 			(soa? soa->expire: 0), (soa? soa->minttl: 0));
13964f8f669cSDavid du Colombier 		for(s = soa->slaves; s != nil; s = s->next)
1397dc5a79c1SDavid du Colombier 			fmtprint(&fstr, " dnsslave=%s", s->name);
13987dd7cddfSDavid du Colombier 		break;
13994f8f669cSDavid du Colombier 	case Tsrv:
14004f8f669cSDavid du Colombier 		srv = rp->srv;
14014f8f669cSDavid du Colombier 		fmtprint(&fstr, " pri=%ud weight=%ud port=%ud target=%s",
14024f8f669cSDavid du Colombier 			(srv? srv->pri: 0), (srv? srv->weight: 0),
1403225077b0SDavid du Colombier 			rp->port, dnname(rp->host));
14044f8f669cSDavid du Colombier 		break;
14059a747e4fSDavid du Colombier 	case Tnull:
14064f8f669cSDavid du Colombier 		if (rp->null == nil)
14074f8f669cSDavid du Colombier 			fmtprint(&fstr, " null=<null>");
14084f8f669cSDavid du Colombier 		else
14094f8f669cSDavid du Colombier 			fmtprint(&fstr, " null=%.*H", rp->null->dlen,
14104f8f669cSDavid du Colombier 				rp->null->data);
14119a747e4fSDavid du Colombier 		break;
14127dd7cddfSDavid du Colombier 	case Ttxt:
141360845620SDavid du Colombier 		fmtprint(&fstr, " txt=");
141460845620SDavid du Colombier 		quote = 0;
141560845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next)
141660845620SDavid du Colombier 			if(strchr(t->p, ' '))
141760845620SDavid du Colombier 				quote = 1;
141860845620SDavid du Colombier 		if(quote)
141960845620SDavid du Colombier 			fmtprint(&fstr, "\"");
142060845620SDavid du Colombier 		for(t = rp->txt; t != nil; t = t->next)
142160845620SDavid du Colombier 			fmtprint(&fstr, "%s", t->p);
142260845620SDavid du Colombier 		if(quote)
142360845620SDavid du Colombier 			fmtprint(&fstr, "\"");
14247dd7cddfSDavid du Colombier 		break;
14257dd7cddfSDavid du Colombier 	case Trp:
14264f8f669cSDavid du Colombier 		fmtprint(&fstr, " rp=%s txt=%s",
14274f8f669cSDavid du Colombier 			dnname(rp->rmb), dnname(rp->rp));
14287dd7cddfSDavid du Colombier 		break;
14297dd7cddfSDavid du Colombier 	case Tkey:
14304f8f669cSDavid du Colombier 		if (rp->key == nil)
14314f8f669cSDavid du Colombier 			fmtprint(&fstr, " flags=<null> proto=<null> alg=<null>");
14324f8f669cSDavid du Colombier 		else
14339a747e4fSDavid du Colombier 			fmtprint(&fstr, " flags=%d proto=%d alg=%d",
14347dd7cddfSDavid du Colombier 				rp->key->flags, rp->key->proto, rp->key->alg);
14357dd7cddfSDavid du Colombier 		break;
14367dd7cddfSDavid du Colombier 	case Tsig:
14374f8f669cSDavid du Colombier 		if (rp->sig == nil)
14384f8f669cSDavid du Colombier 			fmtprint(&fstr,
14394f8f669cSDavid du Colombier " type=<null> alg=<null> labels=<null> ttl=<null> exp=<null> incep=<null> tag=<null> signer=<null>");
14404f8f669cSDavid du Colombier 		else
14414f8f669cSDavid du Colombier 			fmtprint(&fstr,
14424f8f669cSDavid du Colombier " type=%d alg=%d labels=%d ttl=%lud exp=%lud incep=%lud tag=%d signer=%s",
14434f8f669cSDavid du Colombier 				rp->sig->type, rp->sig->alg, rp->sig->labels,
14444f8f669cSDavid du Colombier 				rp->sig->ttl, rp->sig->exp, rp->sig->incep,
14454f8f669cSDavid du Colombier 				rp->sig->tag, dnname(rp->sig->signer));
14467dd7cddfSDavid du Colombier 		break;
14477dd7cddfSDavid du Colombier 	case Tcert:
14484f8f669cSDavid du Colombier 		if (rp->cert == nil)
14494f8f669cSDavid du Colombier 			fmtprint(&fstr, " type=<null> tag=<null> alg=<null>");
14504f8f669cSDavid du Colombier 		else
14519a747e4fSDavid du Colombier 			fmtprint(&fstr, " type=%d tag=%d alg=%d",
14524f8f669cSDavid du Colombier 				rp->cert->type, rp->cert->tag, rp->cert->alg);
14537dd7cddfSDavid du Colombier 		break;
14547dd7cddfSDavid du Colombier 	}
14557dd7cddfSDavid du Colombier out:
14569a747e4fSDavid du Colombier 	strp = fmtstrflush(&fstr);
14579a747e4fSDavid du Colombier 	rv = fmtstrcpy(f, strp);
14589a747e4fSDavid du Colombier 	free(strp);
14599a747e4fSDavid du Colombier 	return rv;
14603e12c5d1SDavid du Colombier }
14617dd7cddfSDavid du Colombier 
14627dd7cddfSDavid du Colombier void
warning(char * fmt,...)14637dd7cddfSDavid du Colombier warning(char *fmt, ...)
14647dd7cddfSDavid du Colombier {
14654f8f669cSDavid du Colombier 	char dnserr[256];
14667dd7cddfSDavid du Colombier 	va_list arg;
14677dd7cddfSDavid du Colombier 
14687dd7cddfSDavid du Colombier 	va_start(arg, fmt);
14699a747e4fSDavid du Colombier 	vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
14707dd7cddfSDavid du Colombier 	va_end(arg);
14714f8f669cSDavid du Colombier 	syslog(1, logfile, dnserr);		/* on console too */
14724f8f669cSDavid du Colombier }
14734f8f669cSDavid du Colombier 
14744f8f669cSDavid du Colombier void
dnslog(char * fmt,...)14754f8f669cSDavid du Colombier dnslog(char *fmt, ...)
14764f8f669cSDavid du Colombier {
14774f8f669cSDavid du Colombier 	char dnserr[256];
14784f8f669cSDavid du Colombier 	va_list arg;
14794f8f669cSDavid du Colombier 
14804f8f669cSDavid du Colombier 	va_start(arg, fmt);
14814f8f669cSDavid du Colombier 	vseprint(dnserr, dnserr+sizeof(dnserr), fmt, arg);
14824f8f669cSDavid du Colombier 	va_end(arg);
14834f8f669cSDavid du Colombier 	syslog(0, logfile, dnserr);
14844f8f669cSDavid du Colombier }
14854f8f669cSDavid du Colombier 
14864f8f669cSDavid du Colombier /*
14874f8f669cSDavid du Colombier  * based on libthread's threadsetname, but drags in less library code.
14884f8f669cSDavid du Colombier  * actually just sets the arguments displayed.
14894f8f669cSDavid du Colombier  */
14904f8f669cSDavid du Colombier void
procsetname(char * fmt,...)14914f8f669cSDavid du Colombier procsetname(char *fmt, ...)
14924f8f669cSDavid du Colombier {
14934f8f669cSDavid du Colombier 	int fd;
14944f8f669cSDavid du Colombier 	char *cmdname;
14954f8f669cSDavid du Colombier 	char buf[128];
14964f8f669cSDavid du Colombier 	va_list arg;
14974f8f669cSDavid du Colombier 
14984f8f669cSDavid du Colombier 	va_start(arg, fmt);
14994f8f669cSDavid du Colombier 	cmdname = vsmprint(fmt, arg);
15004f8f669cSDavid du Colombier 	va_end(arg);
15014f8f669cSDavid du Colombier 	if (cmdname == nil)
15024f8f669cSDavid du Colombier 		return;
15034f8f669cSDavid du Colombier 	snprint(buf, sizeof buf, "#p/%d/args", getpid());
15044f8f669cSDavid du Colombier 	if((fd = open(buf, OWRITE)) >= 0){
15054f8f669cSDavid du Colombier 		write(fd, cmdname, strlen(cmdname)+1);
15064f8f669cSDavid du Colombier 		close(fd);
15074f8f669cSDavid du Colombier 	}
15084f8f669cSDavid du Colombier 	free(cmdname);
15097dd7cddfSDavid du Colombier }
15107dd7cddfSDavid du Colombier 
15117dd7cddfSDavid du Colombier /*
15127dd7cddfSDavid du Colombier  *  create a slave process to handle a request to avoid one request blocking
15137dd7cddfSDavid du Colombier  *  another
15147dd7cddfSDavid du Colombier  */
15157dd7cddfSDavid du Colombier void
slave(Request * req)15167dd7cddfSDavid du Colombier slave(Request *req)
15177dd7cddfSDavid du Colombier {
1518a41547ffSDavid du Colombier 	int ppid, procs;
15197dd7cddfSDavid du Colombier 
15207dd7cddfSDavid du Colombier 	if(req->isslave)
15217dd7cddfSDavid du Colombier 		return;		/* we're already a slave process */
15227dd7cddfSDavid du Colombier 
1523b4b9fc2fSDavid du Colombier 	/*
1524b4b9fc2fSDavid du Colombier 	 * These calls to putactivity cannot block.
1525b4b9fc2fSDavid du Colombier 	 * After getactivity(), the current process is counted
1526b4b9fc2fSDavid du Colombier 	 * twice in dnvars.active (one will pass to the child).
1527b4b9fc2fSDavid du Colombier 	 * If putactivity tries to wait for dnvars.active == 0,
1528b4b9fc2fSDavid du Colombier 	 * it will never happen.
1529b4b9fc2fSDavid du Colombier 	 */
1530b4b9fc2fSDavid du Colombier 
15317dd7cddfSDavid du Colombier 	/* limit parallelism */
1532a41547ffSDavid du Colombier 	procs = getactivity(req, 1);
1533a41547ffSDavid du Colombier 	if (procs > stats.slavehiwat)
1534a41547ffSDavid du Colombier 		stats.slavehiwat = procs;
1535a41547ffSDavid du Colombier 	if(procs > Maxactive){
15364f8f669cSDavid du Colombier 		if(traceactivity)
15374f8f669cSDavid du Colombier 			dnslog("[%d] too much activity", getpid());
1538b4b9fc2fSDavid du Colombier 		putactivity(1);
15397dd7cddfSDavid du Colombier 		return;
15407dd7cddfSDavid du Colombier 	}
15417dd7cddfSDavid du Colombier 
1542c73252aeSDavid du Colombier 	/*
1543c73252aeSDavid du Colombier 	 * parent returns to main loop, child does the work.
1544c73252aeSDavid du Colombier 	 * don't change note group.
1545c73252aeSDavid du Colombier 	 */
1546b4b9fc2fSDavid du Colombier 	ppid = getpid();
1547c73252aeSDavid du Colombier 	switch(rfork(RFPROC|RFMEM|RFNOWAIT)){
15487dd7cddfSDavid du Colombier 	case -1:
1549b4b9fc2fSDavid du Colombier 		putactivity(1);
15507dd7cddfSDavid du Colombier 		break;
15517dd7cddfSDavid du Colombier 	case 0:
15524f8f669cSDavid du Colombier 		procsetname("request slave of pid %d", ppid);
15534f8f669cSDavid du Colombier  		if(traceactivity)
1554a41547ffSDavid du Colombier 			dnslog("[%d] take activity from %d", getpid(), ppid);
15554f8f669cSDavid du Colombier 		req->isslave = 1;	/* why not `= getpid()'? */
15567dd7cddfSDavid du Colombier 		break;
15577dd7cddfSDavid du Colombier 	default:
15584f8f669cSDavid du Colombier 		/*
15594f8f669cSDavid du Colombier 		 * this relies on rfork producing separate, initially-identical
15604f8f669cSDavid du Colombier 		 * stacks, thus giving us two copies of `req', one in each
15614f8f669cSDavid du Colombier 		 * process.
15624f8f669cSDavid du Colombier 		 */
15636aaebd7dSDavid du Colombier 		alarm(0);
15647dd7cddfSDavid du Colombier 		longjmp(req->mret, 1);
15657dd7cddfSDavid du Colombier 	}
15667dd7cddfSDavid du Colombier }
15677dd7cddfSDavid du Colombier 
15687dd7cddfSDavid du Colombier /*
15697dd7cddfSDavid du Colombier  *  chasing down double free's
15707dd7cddfSDavid du Colombier  */
15717dd7cddfSDavid du Colombier void
dncheck(void * p,int dolock)15727dd7cddfSDavid du Colombier dncheck(void *p, int dolock)
15737dd7cddfSDavid du Colombier {
15747dd7cddfSDavid du Colombier 	int i;
15757dd7cddfSDavid du Colombier 	DN *dp;
15767dd7cddfSDavid du Colombier 	RR *rp;
15777dd7cddfSDavid du Colombier 
15787dd7cddfSDavid du Colombier 	if(p != nil){
15797dd7cddfSDavid du Colombier 		dp = p;
15807dd7cddfSDavid du Colombier 		assert(dp->magic == DNmagic);
15817dd7cddfSDavid du Colombier 	}
15827dd7cddfSDavid du Colombier 
15837dd7cddfSDavid du Colombier 	if(!testing)
15847dd7cddfSDavid du Colombier 		return;
15857dd7cddfSDavid du Colombier 
15867dd7cddfSDavid du Colombier 	if(dolock)
15877dd7cddfSDavid du Colombier 		lock(&dnlock);
15889a747e4fSDavid du Colombier 	poolcheck(mainmem);
15897dd7cddfSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
15907dd7cddfSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next){
15917dd7cddfSDavid du Colombier 			assert(dp != p);
15927dd7cddfSDavid du Colombier 			assert(dp->magic == DNmagic);
15937dd7cddfSDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next){
15947dd7cddfSDavid du Colombier 				assert(rp->magic == RRmagic);
15957dd7cddfSDavid du Colombier 				assert(rp->cached);
15967dd7cddfSDavid du Colombier 				assert(rp->owner == dp);
1597225077b0SDavid du Colombier 				/* also check for duplicate rrs */
15984f927735SDavid du Colombier 				if (dolock && rronlist(rp, rp->next)) {
15994f927735SDavid du Colombier 					dnslog("%R duplicates its next chain "
16004f927735SDavid du Colombier 						"(%R); aborting", rp, rp->next);
16014f927735SDavid du Colombier 					abort();
16024f927735SDavid du Colombier 				}
16037dd7cddfSDavid du Colombier 			}
16047dd7cddfSDavid du Colombier 		}
16057dd7cddfSDavid du Colombier 	if(dolock)
16067dd7cddfSDavid du Colombier 		unlock(&dnlock);
16077dd7cddfSDavid du Colombier }
16087dd7cddfSDavid du Colombier 
16097dd7cddfSDavid du Colombier static int
rrequiv(RR * r1,RR * r2)16107dd7cddfSDavid du Colombier rrequiv(RR *r1, RR *r2)
16117dd7cddfSDavid du Colombier {
16127dd7cddfSDavid du Colombier 	return r1->owner == r2->owner
16137dd7cddfSDavid du Colombier 		&& r1->type == r2->type
16147dd7cddfSDavid du Colombier 		&& r1->arg0 == r2->arg0
1615225077b0SDavid du Colombier 		&& r1->arg1 == r2->arg1;
16167dd7cddfSDavid du Colombier }
16177dd7cddfSDavid du Colombier 
1618c3617180SDavid du Colombier /* called with dnlock held */
16197dd7cddfSDavid du Colombier void
unique(RR * rp)16207dd7cddfSDavid du Colombier unique(RR *rp)
16217dd7cddfSDavid du Colombier {
16227dd7cddfSDavid du Colombier 	RR **l, *nrp;
16237dd7cddfSDavid du Colombier 
16247dd7cddfSDavid du Colombier 	for(; rp; rp = rp->next){
16257dd7cddfSDavid du Colombier 		l = &rp->next;
16264f8f669cSDavid du Colombier 		for(nrp = *l; nrp; nrp = *l)
16277dd7cddfSDavid du Colombier 			if(rrequiv(rp, nrp)){
16287dd7cddfSDavid du Colombier 				*l = nrp->next;
16297dd7cddfSDavid du Colombier 				rrfree(nrp);
16307dd7cddfSDavid du Colombier 			} else
16317dd7cddfSDavid du Colombier 				l = &nrp->next;
16327dd7cddfSDavid du Colombier 	}
16337dd7cddfSDavid du Colombier }
16347dd7cddfSDavid du Colombier 
16357dd7cddfSDavid du Colombier /*
16367dd7cddfSDavid du Colombier  *  true if second domain is subsumed by the first
16377dd7cddfSDavid du Colombier  */
16387dd7cddfSDavid du Colombier int
subsume(char * higher,char * lower)16397dd7cddfSDavid du Colombier subsume(char *higher, char *lower)
16407dd7cddfSDavid du Colombier {
16417dd7cddfSDavid du Colombier 	int hn, ln;
16427dd7cddfSDavid du Colombier 
16437dd7cddfSDavid du Colombier 	ln = strlen(lower);
16447dd7cddfSDavid du Colombier 	hn = strlen(higher);
16454f8f669cSDavid du Colombier 	if (ln < hn || cistrcmp(lower + ln - hn, higher) != 0 ||
16464f8f669cSDavid du Colombier 	    ln > hn && hn != 0 && lower[ln - hn - 1] != '.')
16477dd7cddfSDavid du Colombier 		return 0;
16487dd7cddfSDavid du Colombier 	return 1;
16497dd7cddfSDavid du Colombier }
16507dd7cddfSDavid du Colombier 
16517dd7cddfSDavid du Colombier /*
16527dd7cddfSDavid du Colombier  *  randomize the order we return items to provide some
16535d459b5aSDavid du Colombier  *  load balancing for servers.
16545d459b5aSDavid du Colombier  *
16555d459b5aSDavid du Colombier  *  only randomize the first class of entries
16567dd7cddfSDavid du Colombier  */
16577dd7cddfSDavid du Colombier RR*
randomize(RR * rp)16587dd7cddfSDavid du Colombier randomize(RR *rp)
16597dd7cddfSDavid du Colombier {
16605d459b5aSDavid du Colombier 	RR *first, *last, *x, *base;
16617dd7cddfSDavid du Colombier 	ulong n;
16627dd7cddfSDavid du Colombier 
16637dd7cddfSDavid du Colombier 	if(rp == nil || rp->next == nil)
16647dd7cddfSDavid du Colombier 		return rp;
16657dd7cddfSDavid du Colombier 
16663cbadd90SDavid du Colombier 	/* just randomize addresses, mx's and ns's */
16677dd7cddfSDavid du Colombier 	for(x = rp; x; x = x->next)
1668adb31a62SDavid du Colombier 		if(x->type != Ta && x->type != Taaaa &&
1669adb31a62SDavid du Colombier 		    x->type != Tmx && x->type != Tns)
16707dd7cddfSDavid du Colombier 			return rp;
16717dd7cddfSDavid du Colombier 
16725d459b5aSDavid du Colombier 	base = rp;
16735d459b5aSDavid du Colombier 
16747dd7cddfSDavid du Colombier 	n = rand();
16757dd7cddfSDavid du Colombier 	last = first = nil;
16767dd7cddfSDavid du Colombier 	while(rp != nil){
16775d459b5aSDavid du Colombier 		/* stop randomizing if we've moved past our class */
16785d459b5aSDavid du Colombier 		if(base->auth != rp->auth || base->db != rp->db){
16795d459b5aSDavid du Colombier 			last->next = rp;
16805d459b5aSDavid du Colombier 			break;
16815d459b5aSDavid du Colombier 		}
16825d459b5aSDavid du Colombier 
16837dd7cddfSDavid du Colombier 		/* unchain */
16847dd7cddfSDavid du Colombier 		x = rp;
16857dd7cddfSDavid du Colombier 		rp = x->next;
16867dd7cddfSDavid du Colombier 		x->next = nil;
16877dd7cddfSDavid du Colombier 
1688225077b0SDavid du Colombier 		if(n&1){
16897dd7cddfSDavid du Colombier 			/* add to tail */
16907dd7cddfSDavid du Colombier 			if(last == nil)
16917dd7cddfSDavid du Colombier 				first = x;
16927dd7cddfSDavid du Colombier 			else
16937dd7cddfSDavid du Colombier 				last->next = x;
16947dd7cddfSDavid du Colombier 			last = x;
16957dd7cddfSDavid du Colombier 		} else {
16967dd7cddfSDavid du Colombier 			/* add to head */
16977dd7cddfSDavid du Colombier 			if(last == nil)
16987dd7cddfSDavid du Colombier 				last = x;
16997dd7cddfSDavid du Colombier 			x->next = first;
17007dd7cddfSDavid du Colombier 			first = x;
17017dd7cddfSDavid du Colombier 		}
17027dd7cddfSDavid du Colombier 
17037dd7cddfSDavid du Colombier 		/* reroll the dice */
17047dd7cddfSDavid du Colombier 		n >>= 1;
17057dd7cddfSDavid du Colombier 	}
17063cbadd90SDavid du Colombier 
17077dd7cddfSDavid du Colombier 	return first;
17087dd7cddfSDavid du Colombier }
170959cc4ca5SDavid du Colombier 
17109a747e4fSDavid du Colombier static int
sencodefmt(Fmt * f)17119a747e4fSDavid du Colombier sencodefmt(Fmt *f)
171259cc4ca5SDavid du Colombier {
17134f8f669cSDavid du Colombier 	int i, len, ilen, rv;
17144f8f669cSDavid du Colombier 	char *out, *buf;
17159a747e4fSDavid du Colombier 	uchar *b;
17164f8f669cSDavid du Colombier 	char obuf[64];		/* rsc optimization */
171759cc4ca5SDavid du Colombier 
17189a747e4fSDavid du Colombier 	if(!(f->flags&FmtPrec) || f->prec < 1)
17199a747e4fSDavid du Colombier 		goto error;
17209a747e4fSDavid du Colombier 
17219a747e4fSDavid du Colombier 	b = va_arg(f->args, uchar*);
17229a747e4fSDavid du Colombier 	if(b == nil)
17239a747e4fSDavid du Colombier 		goto error;
17249a747e4fSDavid du Colombier 
17259a747e4fSDavid du Colombier 	/* if it's a printable, go for it */
17269a747e4fSDavid du Colombier 	len = f->prec;
17279a747e4fSDavid du Colombier 	for(i = 0; i < len; i++)
17289a747e4fSDavid du Colombier 		if(!isprint(b[i]))
17299a747e4fSDavid du Colombier 			break;
17309a747e4fSDavid du Colombier 	if(i == len){
17319a747e4fSDavid du Colombier 		if(len >= sizeof obuf)
17329a747e4fSDavid du Colombier 			len = sizeof(obuf)-1;
17339a747e4fSDavid du Colombier 		memmove(obuf, b, len);
17349a747e4fSDavid du Colombier 		obuf[len] = 0;
17359a747e4fSDavid du Colombier 		fmtstrcpy(f, obuf);
17369a747e4fSDavid du Colombier 		return 0;
173759cc4ca5SDavid du Colombier 	}
173859cc4ca5SDavid du Colombier 
17399a747e4fSDavid du Colombier 	ilen = f->prec;
17409a747e4fSDavid du Colombier 	f->prec = 0;
17419a747e4fSDavid du Colombier 	f->flags &= ~FmtPrec;
17429a747e4fSDavid du Colombier 	switch(f->r){
17439a747e4fSDavid du Colombier 	case '<':
17449a747e4fSDavid du Colombier 		len = (8*ilen+4)/5 + 3;
17459a747e4fSDavid du Colombier 		break;
17469a747e4fSDavid du Colombier 	case '[':
17479a747e4fSDavid du Colombier 		len = (8*ilen+5)/6 + 4;
17489a747e4fSDavid du Colombier 		break;
17499a747e4fSDavid du Colombier 	case 'H':
17509a747e4fSDavid du Colombier 		len = 2*ilen + 1;
17519a747e4fSDavid du Colombier 		break;
17529a747e4fSDavid du Colombier 	default:
17539a747e4fSDavid du Colombier 		goto error;
17549a747e4fSDavid du Colombier 	}
175559cc4ca5SDavid du Colombier 
17569a747e4fSDavid du Colombier 	if(len > sizeof(obuf)){
17579a747e4fSDavid du Colombier 		buf = malloc(len);
17589a747e4fSDavid du Colombier 		if(buf == nil)
17599a747e4fSDavid du Colombier 			goto error;
17609a747e4fSDavid du Colombier 	} else
17619a747e4fSDavid du Colombier 		buf = obuf;
17629a747e4fSDavid du Colombier 
17634f8f669cSDavid du Colombier 	/* convert */
17649a747e4fSDavid du Colombier 	out = buf;
17659a747e4fSDavid du Colombier 	switch(f->r){
17669a747e4fSDavid du Colombier 	case '<':
17679a747e4fSDavid du Colombier 		rv = enc32(out, len, b, ilen);
17689a747e4fSDavid du Colombier 		break;
17699a747e4fSDavid du Colombier 	case '[':
17709a747e4fSDavid du Colombier 		rv = enc64(out, len, b, ilen);
17719a747e4fSDavid du Colombier 		break;
17729a747e4fSDavid du Colombier 	case 'H':
17739a747e4fSDavid du Colombier 		rv = enc16(out, len, b, ilen);
17749a747e4fSDavid du Colombier 		break;
17759a747e4fSDavid du Colombier 	default:
17769a747e4fSDavid du Colombier 		rv = -1;
17779a747e4fSDavid du Colombier 		break;
17789a747e4fSDavid du Colombier 	}
17799a747e4fSDavid du Colombier 	if(rv < 0)
17809a747e4fSDavid du Colombier 		goto error;
17819a747e4fSDavid du Colombier 
17829a747e4fSDavid du Colombier 	fmtstrcpy(f, buf);
17839a747e4fSDavid du Colombier 	if(buf != obuf)
17849a747e4fSDavid du Colombier 		free(buf);
17859a747e4fSDavid du Colombier 	return 0;
17869a747e4fSDavid du Colombier 
17879a747e4fSDavid du Colombier error:
17889a747e4fSDavid du Colombier 	return fmtstrcpy(f, "<encodefmt>");
17899a747e4fSDavid du Colombier }
17909a747e4fSDavid du Colombier 
17919a747e4fSDavid du Colombier void*
emalloc(int size)17929a747e4fSDavid du Colombier emalloc(int size)
17939a747e4fSDavid du Colombier {
17949a747e4fSDavid du Colombier 	char *x;
17959a747e4fSDavid du Colombier 
17969a747e4fSDavid du Colombier 	x = mallocz(size, 1);
17979a747e4fSDavid du Colombier 	if(x == nil)
17989a747e4fSDavid du Colombier 		abort();
179934f77ae3SDavid du Colombier 	setmalloctag(x, getcallerpc(&size));
18009a747e4fSDavid du Colombier 	return x;
18019a747e4fSDavid du Colombier }
18029a747e4fSDavid du Colombier 
18039a747e4fSDavid du Colombier char*
estrdup(char * s)18049a747e4fSDavid du Colombier estrdup(char *s)
18059a747e4fSDavid du Colombier {
18069a747e4fSDavid du Colombier 	int size;
18079a747e4fSDavid du Colombier 	char *p;
18089a747e4fSDavid du Colombier 
18099a747e4fSDavid du Colombier 	size = strlen(s)+1;
18109a747e4fSDavid du Colombier 	p = mallocz(size, 0);
18119a747e4fSDavid du Colombier 	if(p == nil)
18129a747e4fSDavid du Colombier 		abort();
18139a747e4fSDavid du Colombier 	memmove(p, s, size);
181434f77ae3SDavid du Colombier 	setmalloctag(p, getcallerpc(&s));
18159a747e4fSDavid du Colombier 	return p;
181659cc4ca5SDavid du Colombier }
18173ff48bf5SDavid du Colombier 
18183ff48bf5SDavid du Colombier /*
18193ff48bf5SDavid du Colombier  *  create a pointer record
18203ff48bf5SDavid du Colombier  */
18213ff48bf5SDavid du Colombier static RR*
mkptr(DN * dp,char * ptr,ulong ttl)18223ff48bf5SDavid du Colombier mkptr(DN *dp, char *ptr, ulong ttl)
18233ff48bf5SDavid du Colombier {
18243ff48bf5SDavid du Colombier 	DN *ipdp;
18253ff48bf5SDavid du Colombier 	RR *rp;
18263ff48bf5SDavid du Colombier 
18273ff48bf5SDavid du Colombier 	ipdp = dnlookup(ptr, Cin, 1);
18283ff48bf5SDavid du Colombier 
18293ff48bf5SDavid du Colombier 	rp = rralloc(Tptr);
18303ff48bf5SDavid du Colombier 	rp->ptr = dp;
18313ff48bf5SDavid du Colombier 	rp->owner = ipdp;
18323ff48bf5SDavid du Colombier 	rp->db = 1;
18333ff48bf5SDavid du Colombier 	if(ttl)
18343ff48bf5SDavid du Colombier 		rp->ttl = ttl;
18353ff48bf5SDavid du Colombier 	return rp;
18363ff48bf5SDavid du Colombier }
18373ff48bf5SDavid du Colombier 
183853874d13SDavid du Colombier void	bytes2nibbles(uchar *nibbles, uchar *bytes, int nbytes);
183953874d13SDavid du Colombier 
18403ff48bf5SDavid du Colombier /*
18413ff48bf5SDavid du Colombier  *  look for all ip addresses in this network and make
18423ff48bf5SDavid du Colombier  *  pointer records for them.
18433ff48bf5SDavid du Colombier  */
18443ff48bf5SDavid du Colombier void
dnptr(uchar * net,uchar * mask,char * dom,int forwtype,int subdoms,int ttl)184553874d13SDavid du Colombier dnptr(uchar *net, uchar *mask, char *dom, int forwtype, int subdoms, int ttl)
18463ff48bf5SDavid du Colombier {
184753874d13SDavid du Colombier 	int i, j, len;
18484f8f669cSDavid du Colombier 	char *p, *e;
18494f8f669cSDavid du Colombier 	char ptr[Domlen];
185053874d13SDavid du Colombier 	uchar *ipp;
18514f8f669cSDavid du Colombier 	uchar ip[IPaddrlen], nnet[IPaddrlen];
185253874d13SDavid du Colombier 	uchar nibip[IPaddrlen*2];
18533ff48bf5SDavid du Colombier 	DN *dp;
18543ff48bf5SDavid du Colombier 	RR *rp, *nrp, *first, **l;
18553ff48bf5SDavid du Colombier 
18563ff48bf5SDavid du Colombier 	l = &first;
18573ff48bf5SDavid du Colombier 	first = nil;
18584f8f669cSDavid du Colombier 	for(i = 0; i < HTLEN; i++)
18594f8f669cSDavid du Colombier 		for(dp = ht[i]; dp; dp = dp->next)
18603ff48bf5SDavid du Colombier 			for(rp = dp->rr; rp; rp = rp->next){
186153874d13SDavid du Colombier 				if(rp->type != forwtype || rp->negative)
18623ff48bf5SDavid du Colombier 					continue;
18633ff48bf5SDavid du Colombier 				parseip(ip, rp->ip->name);
18643ff48bf5SDavid du Colombier 				maskip(ip, mask, nnet);
18653ff48bf5SDavid du Colombier 				if(ipcmp(net, nnet) != 0)
18663ff48bf5SDavid du Colombier 					continue;
186753874d13SDavid du Colombier 
186853874d13SDavid du Colombier 				ipp = ip;
186953874d13SDavid du Colombier 				len = IPaddrlen;
187053874d13SDavid du Colombier 				if (forwtype == Taaaa) {
187153874d13SDavid du Colombier 					bytes2nibbles(nibip, ip, IPaddrlen);
187253874d13SDavid du Colombier 					ipp = nibip;
187353874d13SDavid du Colombier 					len = 2*IPaddrlen;
187453874d13SDavid du Colombier 				}
187553874d13SDavid du Colombier 
18763ff48bf5SDavid du Colombier 				p = ptr;
18773ff48bf5SDavid du Colombier 				e = ptr+sizeof(ptr);
187853874d13SDavid du Colombier 				for(j = len - 1; j >= len - subdoms; j--)
187953874d13SDavid du Colombier 					p = seprint(p, e, (forwtype == Ta?
188053874d13SDavid du Colombier 						"%d.": "%x."), ipp[j]);
18813ff48bf5SDavid du Colombier 				seprint(p, e, "%s", dom);
188253874d13SDavid du Colombier 
18833ff48bf5SDavid du Colombier 				nrp = mkptr(dp, ptr, ttl);
18843ff48bf5SDavid du Colombier 				*l = nrp;
18853ff48bf5SDavid du Colombier 				l = &nrp->next;
18863ff48bf5SDavid du Colombier 			}
18873ff48bf5SDavid du Colombier 
18883ff48bf5SDavid du Colombier 	for(rp = first; rp != nil; rp = nrp){
18893ff48bf5SDavid du Colombier 		nrp = rp->next;
18903ff48bf5SDavid du Colombier 		rp->next = nil;
18916dc4800dSDavid du Colombier 		rrattach(rp, Authoritative);
18923ff48bf5SDavid du Colombier 	}
18933ff48bf5SDavid du Colombier }
1894dc5a79c1SDavid du Colombier 
1895dc5a79c1SDavid du Colombier void
addserver(Server ** l,char * name)1896dc5a79c1SDavid du Colombier addserver(Server **l, char *name)
1897dc5a79c1SDavid du Colombier {
1898dc5a79c1SDavid du Colombier 	Server *s;
1899dc5a79c1SDavid du Colombier 
1900dc5a79c1SDavid du Colombier 	while(*l)
1901dc5a79c1SDavid du Colombier 		l = &(*l)->next;
1902dc5a79c1SDavid du Colombier 	s = malloc(sizeof(Server)+strlen(name)+1);
1903dc5a79c1SDavid du Colombier 	if(s == nil)
1904dc5a79c1SDavid du Colombier 		return;
1905dc5a79c1SDavid du Colombier 	s->name = (char*)(s+1);
1906dc5a79c1SDavid du Colombier 	strcpy(s->name, name);
1907dc5a79c1SDavid du Colombier 	s->next = nil;
1908dc5a79c1SDavid du Colombier 	*l = s;
1909dc5a79c1SDavid du Colombier }
1910dc5a79c1SDavid du Colombier 
1911dc5a79c1SDavid du Colombier Server*
copyserverlist(Server * s)1912dc5a79c1SDavid du Colombier copyserverlist(Server *s)
1913dc5a79c1SDavid du Colombier {
1914dc5a79c1SDavid du Colombier 	Server *ns;
1915dc5a79c1SDavid du Colombier 
1916dc5a79c1SDavid du Colombier 	for(ns = nil; s != nil; s = s->next)
1917dc5a79c1SDavid du Colombier 		addserver(&ns, s->name);
1918dc5a79c1SDavid du Colombier 	return ns;
1919dc5a79c1SDavid du Colombier }
1920b751ae26SDavid du Colombier 
1921b751ae26SDavid du Colombier 
1922b751ae26SDavid du Colombier /* from here down is copied to ip/snoopy/dns.c periodically to update it */
1923b751ae26SDavid du Colombier 
1924b751ae26SDavid du Colombier /*
1925b751ae26SDavid du Colombier  *  convert an integer RR type to it's ascii name
1926b751ae26SDavid du Colombier  */
1927b751ae26SDavid du Colombier char*
rrname(int type,char * buf,int len)1928b751ae26SDavid du Colombier rrname(int type, char *buf, int len)
1929b751ae26SDavid du Colombier {
1930b751ae26SDavid du Colombier 	char *t;
1931b751ae26SDavid du Colombier 
1932b751ae26SDavid du Colombier 	t = nil;
1933b751ae26SDavid du Colombier 	if(type >= 0 && type <= Tall)
1934b751ae26SDavid du Colombier 		t = rrtname[type];
1935b751ae26SDavid du Colombier 	if(t==nil){
1936b751ae26SDavid du Colombier 		snprint(buf, len, "%d", type);
1937b751ae26SDavid du Colombier 		t = buf;
1938b751ae26SDavid du Colombier 	}
1939b751ae26SDavid du Colombier 	return t;
1940b751ae26SDavid du Colombier }
1941b751ae26SDavid du Colombier 
1942b751ae26SDavid du Colombier /*
1943b751ae26SDavid du Colombier  *  free a list of resource records and any related structs
1944b751ae26SDavid du Colombier  */
1945b751ae26SDavid du Colombier void
rrfreelist(RR * rp)1946b751ae26SDavid du Colombier rrfreelist(RR *rp)
1947b751ae26SDavid du Colombier {
1948b751ae26SDavid du Colombier 	RR *next;
1949b751ae26SDavid du Colombier 
1950b751ae26SDavid du Colombier 	for(; rp; rp = next){
1951b751ae26SDavid du Colombier 		next = rp->next;
1952b751ae26SDavid du Colombier 		rrfree(rp);
1953b751ae26SDavid du Colombier 	}
1954b751ae26SDavid du Colombier }
1955b751ae26SDavid du Colombier 
1956b751ae26SDavid du Colombier void
freeserverlist(Server * s)1957b751ae26SDavid du Colombier freeserverlist(Server *s)
1958b751ae26SDavid du Colombier {
1959b751ae26SDavid du Colombier 	Server *next;
1960b751ae26SDavid du Colombier 
1961b751ae26SDavid du Colombier 	for(; s != nil; s = next){
1962b751ae26SDavid du Colombier 		next = s->next;
1963b751ae26SDavid du Colombier 		free(s);
1964b751ae26SDavid du Colombier 	}
1965b751ae26SDavid du Colombier }
1966b751ae26SDavid du Colombier 
1967b751ae26SDavid du Colombier /*
1968b751ae26SDavid du Colombier  *  allocate a resource record of a given type
1969b751ae26SDavid du Colombier  */
1970b751ae26SDavid du Colombier RR*
rralloc(int type)1971b751ae26SDavid du Colombier rralloc(int type)
1972b751ae26SDavid du Colombier {
1973b751ae26SDavid du Colombier 	RR *rp;
1974b751ae26SDavid du Colombier 
1975b751ae26SDavid du Colombier 	rp = emalloc(sizeof(*rp));
1976b751ae26SDavid du Colombier 	rp->magic = RRmagic;
1977b751ae26SDavid du Colombier 	rp->pc = getcallerpc(&type);
1978b751ae26SDavid du Colombier 	rp->type = type;
1979fd87a217SDavid du Colombier 	if (rp->type != type)
1980fd87a217SDavid du Colombier 		dnslog("rralloc: bogus type %d", type);
1981b751ae26SDavid du Colombier 	setmalloctag(rp, rp->pc);
1982b751ae26SDavid du Colombier 	switch(type){
1983b751ae26SDavid du Colombier 	case Tsoa:
1984b751ae26SDavid du Colombier 		rp->soa = emalloc(sizeof(*rp->soa));
1985b751ae26SDavid du Colombier 		rp->soa->slaves = nil;
1986b751ae26SDavid du Colombier 		setmalloctag(rp->soa, rp->pc);
1987b751ae26SDavid du Colombier 		break;
1988b751ae26SDavid du Colombier 	case Tsrv:
1989b751ae26SDavid du Colombier 		rp->srv = emalloc(sizeof(*rp->srv));
1990b751ae26SDavid du Colombier 		setmalloctag(rp->srv, rp->pc);
1991b751ae26SDavid du Colombier 		break;
1992b751ae26SDavid du Colombier 	case Tkey:
1993b751ae26SDavid du Colombier 		rp->key = emalloc(sizeof(*rp->key));
1994b751ae26SDavid du Colombier 		setmalloctag(rp->key, rp->pc);
1995b751ae26SDavid du Colombier 		break;
1996b751ae26SDavid du Colombier 	case Tcert:
1997b751ae26SDavid du Colombier 		rp->cert = emalloc(sizeof(*rp->cert));
1998b751ae26SDavid du Colombier 		setmalloctag(rp->cert, rp->pc);
1999b751ae26SDavid du Colombier 		break;
2000b751ae26SDavid du Colombier 	case Tsig:
2001b751ae26SDavid du Colombier 		rp->sig = emalloc(sizeof(*rp->sig));
2002b751ae26SDavid du Colombier 		setmalloctag(rp->sig, rp->pc);
2003b751ae26SDavid du Colombier 		break;
2004b751ae26SDavid du Colombier 	case Tnull:
2005b751ae26SDavid du Colombier 		rp->null = emalloc(sizeof(*rp->null));
2006b751ae26SDavid du Colombier 		setmalloctag(rp->null, rp->pc);
2007b751ae26SDavid du Colombier 		break;
2008b751ae26SDavid du Colombier 	}
2009b751ae26SDavid du Colombier 	rp->ttl = 0;
2010b751ae26SDavid du Colombier 	rp->expire = 0;
2011b751ae26SDavid du Colombier 	rp->next = 0;
2012b751ae26SDavid du Colombier 	return rp;
2013b751ae26SDavid du Colombier }
2014b751ae26SDavid du Colombier 
2015b751ae26SDavid du Colombier /*
2016b751ae26SDavid du Colombier  *  free a resource record and any related structs
2017b751ae26SDavid du Colombier  */
2018b751ae26SDavid du Colombier void
rrfree(RR * rp)2019b751ae26SDavid du Colombier rrfree(RR *rp)
2020b751ae26SDavid du Colombier {
2021b751ae26SDavid du Colombier 	DN *dp;
2022b751ae26SDavid du Colombier 	RR *nrp;
2023b751ae26SDavid du Colombier 	Txt *t;
2024b751ae26SDavid du Colombier 
2025530fef66SDavid du Colombier 	assert(rp->magic == RRmagic);
2026b751ae26SDavid du Colombier 	assert(!rp->cached);
2027b751ae26SDavid du Colombier 
202827acba7cSDavid du Colombier 	/* our callers often hold dnlock.  it's needed to examine dp safely. */
2029b751ae26SDavid du Colombier 	dp = rp->owner;
2030b751ae26SDavid du Colombier 	if(dp){
203127acba7cSDavid du Colombier 		/* if someone else holds dnlock, skip the sanity check. */
203227acba7cSDavid du Colombier 		if (canlock(&dnlock)) {
2033b751ae26SDavid du Colombier 			assert(dp->magic == DNmagic);
2034b751ae26SDavid du Colombier 			for(nrp = dp->rr; nrp; nrp = nrp->next)
2035b751ae26SDavid du Colombier 				assert(nrp != rp);   /* "rrfree of live rr" */
203627acba7cSDavid du Colombier 			unlock(&dnlock);
203727acba7cSDavid du Colombier 		}
2038b751ae26SDavid du Colombier 	}
2039b751ae26SDavid du Colombier 
2040b751ae26SDavid du Colombier 	switch(rp->type){
2041b751ae26SDavid du Colombier 	case Tsoa:
2042b751ae26SDavid du Colombier 		freeserverlist(rp->soa->slaves);
2043b751ae26SDavid du Colombier 		memset(rp->soa, 0, sizeof *rp->soa);	/* cause trouble */
2044b751ae26SDavid du Colombier 		free(rp->soa);
2045b751ae26SDavid du Colombier 		break;
2046b751ae26SDavid du Colombier 	case Tsrv:
2047b751ae26SDavid du Colombier 		memset(rp->srv, 0, sizeof *rp->srv);	/* cause trouble */
2048b751ae26SDavid du Colombier 		free(rp->srv);
2049b751ae26SDavid du Colombier 		break;
2050b751ae26SDavid du Colombier 	case Tkey:
2051b751ae26SDavid du Colombier 		free(rp->key->data);
2052b751ae26SDavid du Colombier 		memset(rp->key, 0, sizeof *rp->key);	/* cause trouble */
2053b751ae26SDavid du Colombier 		free(rp->key);
2054b751ae26SDavid du Colombier 		break;
2055b751ae26SDavid du Colombier 	case Tcert:
2056b751ae26SDavid du Colombier 		free(rp->cert->data);
2057b751ae26SDavid du Colombier 		memset(rp->cert, 0, sizeof *rp->cert);	/* cause trouble */
2058b751ae26SDavid du Colombier 		free(rp->cert);
2059b751ae26SDavid du Colombier 		break;
2060b751ae26SDavid du Colombier 	case Tsig:
2061b751ae26SDavid du Colombier 		free(rp->sig->data);
2062b751ae26SDavid du Colombier 		memset(rp->sig, 0, sizeof *rp->sig);	/* cause trouble */
2063b751ae26SDavid du Colombier 		free(rp->sig);
2064b751ae26SDavid du Colombier 		break;
2065b751ae26SDavid du Colombier 	case Tnull:
2066b751ae26SDavid du Colombier 		free(rp->null->data);
2067b751ae26SDavid du Colombier 		memset(rp->null, 0, sizeof *rp->null);	/* cause trouble */
2068b751ae26SDavid du Colombier 		free(rp->null);
2069b751ae26SDavid du Colombier 		break;
2070b751ae26SDavid du Colombier 	case Ttxt:
2071b751ae26SDavid du Colombier 		while(rp->txt != nil){
2072b751ae26SDavid du Colombier 			t = rp->txt;
2073b751ae26SDavid du Colombier 			rp->txt = t->next;
2074b751ae26SDavid du Colombier 			free(t->p);
2075b751ae26SDavid du Colombier 			memset(t, 0, sizeof *t);	/* cause trouble */
2076b751ae26SDavid du Colombier 			free(t);
2077b751ae26SDavid du Colombier 		}
2078b751ae26SDavid du Colombier 		break;
2079b751ae26SDavid du Colombier 	}
2080b751ae26SDavid du Colombier 
2081b751ae26SDavid du Colombier 	rp->magic = ~rp->magic;
2082b751ae26SDavid du Colombier 	memset(rp, 0, sizeof *rp);		/* cause trouble */
2083b751ae26SDavid du Colombier 	free(rp);
2084b751ae26SDavid du Colombier }
2085