xref: /plan9/sys/src/cmd/ratfs/ctlfiles.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include "ratfs.h"
2*9a747e4fSDavid du Colombier #include <ip.h>
3*9a747e4fSDavid du Colombier 
4*9a747e4fSDavid du Colombier enum {
5*9a747e4fSDavid du Colombier 	ACCEPT = 0,		/* verbs in control file */
6*9a747e4fSDavid du Colombier 	REFUSED,
7*9a747e4fSDavid du Colombier 	DENIED,
8*9a747e4fSDavid du Colombier 	DIALUP,
9*9a747e4fSDavid du Colombier 	BLOCKED,
10*9a747e4fSDavid du Colombier 	DELAY,
11*9a747e4fSDavid du Colombier 	NONE,
12*9a747e4fSDavid du Colombier 
13*9a747e4fSDavid du Colombier 	Subchar	=	'#',	/* character substituted for '/' in file names */
14*9a747e4fSDavid du Colombier };
15*9a747e4fSDavid du Colombier 
16*9a747e4fSDavid du Colombier static	Keyword actions[] = {
17*9a747e4fSDavid du Colombier 	"allow",		ACCEPT,
18*9a747e4fSDavid du Colombier 	"accept",		ACCEPT,
19*9a747e4fSDavid du Colombier 	"block",		BLOCKED,
20*9a747e4fSDavid du Colombier 	"deny",			DENIED,
21*9a747e4fSDavid du Colombier 	"dial",			DIALUP,
22*9a747e4fSDavid du Colombier 	"relay",		DELAY,
23*9a747e4fSDavid du Colombier 	"delay",		DELAY,
24*9a747e4fSDavid du Colombier 	0,			NONE,
25*9a747e4fSDavid du Colombier };
26*9a747e4fSDavid du Colombier 
27*9a747e4fSDavid du Colombier static void	acctinsert(Node*, char*);
28*9a747e4fSDavid du Colombier static char*	getline(Biobuf*);
29*9a747e4fSDavid du Colombier static void	ipinsert(Node*, char*);
30*9a747e4fSDavid du Colombier static void	ipsort(void);
31*9a747e4fSDavid du Colombier 
32*9a747e4fSDavid du Colombier /*
33*9a747e4fSDavid du Colombier  *	Input the configuration file
34*9a747e4fSDavid du Colombier  *	Currently we only process the "ournets"
35*9a747e4fSDavid du Colombier  *	specification.
36*9a747e4fSDavid du Colombier  */
37*9a747e4fSDavid du Colombier void
getconf(void)38*9a747e4fSDavid du Colombier getconf(void)
39*9a747e4fSDavid du Colombier {
40*9a747e4fSDavid du Colombier 	Biobuf *bp;
41*9a747e4fSDavid du Colombier 	char *cp;
42*9a747e4fSDavid du Colombier 	Node *np, *dir, **l;
43*9a747e4fSDavid du Colombier 
44*9a747e4fSDavid du Colombier 	if(debugfd >= 0)
45*9a747e4fSDavid du Colombier 		fprint(debugfd, "loading %s\n", conffile);
46*9a747e4fSDavid du Colombier 
47*9a747e4fSDavid du Colombier 	bp = Bopen(conffile, OREAD);
48*9a747e4fSDavid du Colombier 	if(bp == 0)
49*9a747e4fSDavid du Colombier 		return;
50*9a747e4fSDavid du Colombier 
51*9a747e4fSDavid du Colombier 	dir = finddir(Trusted);
52*9a747e4fSDavid du Colombier 	if(dir == 0)
53*9a747e4fSDavid du Colombier 		return;
54*9a747e4fSDavid du Colombier 
55*9a747e4fSDavid du Colombier 	/*
56*9a747e4fSDavid du Colombier 	 * if this isn't the first time, purge permanent entries
57*9a747e4fSDavid du Colombier 	 */
58*9a747e4fSDavid du Colombier 	trustedqid = Qtrustedfile;
59*9a747e4fSDavid du Colombier 	if(lastconftime){
60*9a747e4fSDavid du Colombier 		l = &dir->children;
61*9a747e4fSDavid du Colombier 		for(np = dir->children; np; np = *l){
62*9a747e4fSDavid du Colombier 			if(np->d.type == Trustedperm){
63*9a747e4fSDavid du Colombier 				*l = np->sibs;
64*9a747e4fSDavid du Colombier 				free(np);
65*9a747e4fSDavid du Colombier 			} else {
66*9a747e4fSDavid du Colombier 				np->d.qid.path = trustedqid++;
67*9a747e4fSDavid du Colombier 				l = &np->sibs;
68*9a747e4fSDavid du Colombier 			}
69*9a747e4fSDavid du Colombier 		}
70*9a747e4fSDavid du Colombier 		dir->count = 0;
71*9a747e4fSDavid du Colombier 	}
72*9a747e4fSDavid du Colombier 
73*9a747e4fSDavid du Colombier 	for(;;){
74*9a747e4fSDavid du Colombier 		cp = getline(bp);
75*9a747e4fSDavid du Colombier 		if(cp == 0)
76*9a747e4fSDavid du Colombier 			break;
77*9a747e4fSDavid du Colombier 		if (strcmp(cp, "ournets") == 0){
78*9a747e4fSDavid du Colombier 			for(cp += strlen(cp)+1; cp && *cp; cp += strlen(cp)+1){
79*9a747e4fSDavid du Colombier 				np = newnode(dir, cp, Trustedperm, 0111, trustedqid++);
80*9a747e4fSDavid du Colombier 				cidrparse(&np->ip, cp);
81*9a747e4fSDavid du Colombier 				subslash(cp);
82*9a747e4fSDavid du Colombier 				np->d.name = atom(cp);
83*9a747e4fSDavid du Colombier 			}
84*9a747e4fSDavid du Colombier 		}
85*9a747e4fSDavid du Colombier 	}
86*9a747e4fSDavid du Colombier 	Bterm(bp);
87*9a747e4fSDavid du Colombier 	lastconftime = time(0);
88*9a747e4fSDavid du Colombier }
89*9a747e4fSDavid du Colombier 
90*9a747e4fSDavid du Colombier /*
91*9a747e4fSDavid du Colombier  *	Reload the control file, if necessary
92*9a747e4fSDavid du Colombier  */
93*9a747e4fSDavid du Colombier void
reload(void)94*9a747e4fSDavid du Colombier reload(void)
95*9a747e4fSDavid du Colombier {
96*9a747e4fSDavid du Colombier 	int type, action;
97*9a747e4fSDavid du Colombier 	Biobuf *bp;
98*9a747e4fSDavid du Colombier 	char *cp;
99*9a747e4fSDavid du Colombier 	Node *np, *dir;
100*9a747e4fSDavid du Colombier 
101*9a747e4fSDavid du Colombier 	if(debugfd >= 0)
102*9a747e4fSDavid du Colombier 		fprint(debugfd,"loading %s\n", ctlfile);
103*9a747e4fSDavid du Colombier 
104*9a747e4fSDavid du Colombier 	bp = Bopen(ctlfile, OREAD);
105*9a747e4fSDavid du Colombier 	if(bp == 0)
106*9a747e4fSDavid du Colombier 		return;
107*9a747e4fSDavid du Colombier 
108*9a747e4fSDavid du Colombier 	if(lastctltime){
109*9a747e4fSDavid du Colombier 		for(dir = root->children; dir; dir = dir->sibs){
110*9a747e4fSDavid du Colombier 			if (dir->d.type != Addrdir)
111*9a747e4fSDavid du Colombier 				continue;
112*9a747e4fSDavid du Colombier 			for(np = dir->children; np; np = np->sibs)
113*9a747e4fSDavid du Colombier 				np->count = 0;
114*9a747e4fSDavid du Colombier 		}
115*9a747e4fSDavid du Colombier 	}
116*9a747e4fSDavid du Colombier 
117*9a747e4fSDavid du Colombier 	for(;;){
118*9a747e4fSDavid du Colombier 		cp = getline(bp);
119*9a747e4fSDavid du Colombier 		if(cp == 0)
120*9a747e4fSDavid du Colombier 			break;
121*9a747e4fSDavid du Colombier 		type = *cp;
122*9a747e4fSDavid du Colombier 		if(type == '*'){
123*9a747e4fSDavid du Colombier 			cp++;
124*9a747e4fSDavid du Colombier 			if(*cp == 0)		/* space before keyword */
125*9a747e4fSDavid du Colombier 				cp++;
126*9a747e4fSDavid du Colombier 		}
127*9a747e4fSDavid du Colombier 		action = findkey(cp, actions);
128*9a747e4fSDavid du Colombier 		if (action == NONE)
129*9a747e4fSDavid du Colombier 			continue;
130*9a747e4fSDavid du Colombier 		if (action == ACCEPT)
131*9a747e4fSDavid du Colombier 			dir = dirwalk("allow", root);
132*9a747e4fSDavid du Colombier 		else
133*9a747e4fSDavid du Colombier 		if (action == DELAY)
134*9a747e4fSDavid du Colombier 			dir = dirwalk("delay", root);
135*9a747e4fSDavid du Colombier 		else
136*9a747e4fSDavid du Colombier 			dir = dirwalk(cp, root);
137*9a747e4fSDavid du Colombier 		if(dir == 0)
138*9a747e4fSDavid du Colombier 			continue;
139*9a747e4fSDavid du Colombier 
140*9a747e4fSDavid du Colombier 		for(cp += strlen(cp)+1; cp && *cp; cp += strlen(cp)+1){
141*9a747e4fSDavid du Colombier 			if(type == '*')
142*9a747e4fSDavid du Colombier 				acctinsert(dir, cp);
143*9a747e4fSDavid du Colombier 			else
144*9a747e4fSDavid du Colombier 				ipinsert(dir, cp);
145*9a747e4fSDavid du Colombier 		}
146*9a747e4fSDavid du Colombier 	}
147*9a747e4fSDavid du Colombier 	Bterm(bp);
148*9a747e4fSDavid du Colombier 	ipsort();
149*9a747e4fSDavid du Colombier 	dummy.d.mtime = dummy.d.atime = lastctltime = time(0);
150*9a747e4fSDavid du Colombier }
151*9a747e4fSDavid du Colombier 
152*9a747e4fSDavid du Colombier /*
153*9a747e4fSDavid du Colombier  * get a canonicalized line: a string of null-terminated lower-case
154*9a747e4fSDavid du Colombier  * tokens with a two null bytes at the end.
155*9a747e4fSDavid du Colombier  */
156*9a747e4fSDavid du Colombier static char*
getline(Biobuf * bp)157*9a747e4fSDavid du Colombier getline(Biobuf *bp)
158*9a747e4fSDavid du Colombier {
159*9a747e4fSDavid du Colombier 	char c, *cp, *p, *q;
160*9a747e4fSDavid du Colombier 	int n;
161*9a747e4fSDavid du Colombier 
162*9a747e4fSDavid du Colombier 	static char *buf;
163*9a747e4fSDavid du Colombier 	static int bufsize;
164*9a747e4fSDavid du Colombier 
165*9a747e4fSDavid du Colombier 	for(;;){
166*9a747e4fSDavid du Colombier 		cp = Brdline(bp, '\n');
167*9a747e4fSDavid du Colombier 		if(cp == 0)
168*9a747e4fSDavid du Colombier 			return 0;
169*9a747e4fSDavid du Colombier 		n = Blinelen(bp);
170*9a747e4fSDavid du Colombier 		cp[n-1] = 0;
171*9a747e4fSDavid du Colombier 		if(buf == 0 || bufsize < n+1){
172*9a747e4fSDavid du Colombier 			bufsize += 512;
173*9a747e4fSDavid du Colombier 			if(bufsize < n+1)
174*9a747e4fSDavid du Colombier 				bufsize = n+1;
175*9a747e4fSDavid du Colombier 			buf = realloc(buf, bufsize);
176*9a747e4fSDavid du Colombier 			if(buf == 0)
177*9a747e4fSDavid du Colombier 				break;
178*9a747e4fSDavid du Colombier 		}
179*9a747e4fSDavid du Colombier 		q = buf;
180*9a747e4fSDavid du Colombier 		for (p = cp; *p; p++){
181*9a747e4fSDavid du Colombier 			c = *p;
182*9a747e4fSDavid du Colombier 			if(c == '\\' && p[1])	/* we don't allow \<newline> */
183*9a747e4fSDavid du Colombier 				c = *++p;
184*9a747e4fSDavid du Colombier 			else
185*9a747e4fSDavid du Colombier 			if(c == '#')
186*9a747e4fSDavid du Colombier 				break;
187*9a747e4fSDavid du Colombier 			else
188*9a747e4fSDavid du Colombier 			if(c == ' ' || c == '\t' || c == ',')
189*9a747e4fSDavid du Colombier 				if(q == buf || q[-1] == 0)
190*9a747e4fSDavid du Colombier 					continue;
191*9a747e4fSDavid du Colombier 				else
192*9a747e4fSDavid du Colombier 					c = 0;
193*9a747e4fSDavid du Colombier 			*q++ = tolower(c);
194*9a747e4fSDavid du Colombier 		}
195*9a747e4fSDavid du Colombier 		if(q != buf){
196*9a747e4fSDavid du Colombier 			if(q[-1])
197*9a747e4fSDavid du Colombier 				*q++ = 0;
198*9a747e4fSDavid du Colombier 			*q = 0;
199*9a747e4fSDavid du Colombier 			break;
200*9a747e4fSDavid du Colombier 		}
201*9a747e4fSDavid du Colombier 	}
202*9a747e4fSDavid du Colombier 	return buf;
203*9a747e4fSDavid du Colombier }
204*9a747e4fSDavid du Colombier 
205*9a747e4fSDavid du Colombier /*
206*9a747e4fSDavid du Colombier  *	Match a keyword
207*9a747e4fSDavid du Colombier  */
208*9a747e4fSDavid du Colombier int
findkey(char * val,Keyword * p)209*9a747e4fSDavid du Colombier findkey(char *val, Keyword *p)
210*9a747e4fSDavid du Colombier {
211*9a747e4fSDavid du Colombier 
212*9a747e4fSDavid du Colombier 	for(; p->name; p++)
213*9a747e4fSDavid du Colombier 		if(strcmp(val, p->name) == 0)
214*9a747e4fSDavid du Colombier 				break;
215*9a747e4fSDavid du Colombier 	return p->code;
216*9a747e4fSDavid du Colombier }
217*9a747e4fSDavid du Colombier 
218*9a747e4fSDavid du Colombier /*
219*9a747e4fSDavid du Colombier  *	parse a cidr specification in either IP/mask or IP#mask format
220*9a747e4fSDavid du Colombier  */
221*9a747e4fSDavid du Colombier void
cidrparse(Cidraddr * cidr,char * cp)222*9a747e4fSDavid du Colombier cidrparse(Cidraddr *cidr, char *cp)
223*9a747e4fSDavid du Colombier {
224*9a747e4fSDavid du Colombier 
225*9a747e4fSDavid du Colombier 	char *p, *slash;
226*9a747e4fSDavid du Colombier 	int c;
227*9a747e4fSDavid du Colombier 	ulong a, m;
228*9a747e4fSDavid du Colombier 	uchar addr[IPv4addrlen];
229*9a747e4fSDavid du Colombier 	uchar mask[IPv4addrlen];
230*9a747e4fSDavid du Colombier 	char buf[64];
231*9a747e4fSDavid du Colombier 
232*9a747e4fSDavid du Colombier 	/*
233*9a747e4fSDavid du Colombier 	 * find '/' or '#' character in the cidr specification
234*9a747e4fSDavid du Colombier 	 */
235*9a747e4fSDavid du Colombier 	slash = 0;
236*9a747e4fSDavid du Colombier 	for(p = buf; p < buf+sizeof(buf)-1 && *cp; p++) {
237*9a747e4fSDavid du Colombier 		c = *cp++;
238*9a747e4fSDavid du Colombier 		switch(c) {
239*9a747e4fSDavid du Colombier 		case Subchar:
240*9a747e4fSDavid du Colombier 			c = '/';
241*9a747e4fSDavid du Colombier 			slash = p;
242*9a747e4fSDavid du Colombier 			break;
243*9a747e4fSDavid du Colombier 		case '/':
244*9a747e4fSDavid du Colombier 			slash = p;
245*9a747e4fSDavid du Colombier 			break;
246*9a747e4fSDavid du Colombier 		default:
247*9a747e4fSDavid du Colombier 			break;
248*9a747e4fSDavid du Colombier 		}
249*9a747e4fSDavid du Colombier 		*p = c;
250*9a747e4fSDavid du Colombier 	}
251*9a747e4fSDavid du Colombier 	*p = 0;
252*9a747e4fSDavid du Colombier 
253*9a747e4fSDavid du Colombier 	v4parsecidr(addr, mask, buf);
254*9a747e4fSDavid du Colombier 	a = nhgetl(addr);
255*9a747e4fSDavid du Colombier 	m = nhgetl(mask);
256*9a747e4fSDavid du Colombier 	/*
257*9a747e4fSDavid du Colombier 	 * if a mask isn't specified, we build a minimal mask
258*9a747e4fSDavid du Colombier 	 * instead of using the default mask for that net.  in this
259*9a747e4fSDavid du Colombier 	 * case we never allow a class A mask (0xff000000).
260*9a747e4fSDavid du Colombier 	 */
261*9a747e4fSDavid du Colombier 	if(slash == 0){
262*9a747e4fSDavid du Colombier 		m = 0xff000000;
263*9a747e4fSDavid du Colombier 		p = buf;
264*9a747e4fSDavid du Colombier 		for(p = strchr(p, '.'); p && p[1]; p = strchr(p+1, '.'))
265*9a747e4fSDavid du Colombier 				m = (m>>8)|0xff000000;
266*9a747e4fSDavid du Colombier 
267*9a747e4fSDavid du Colombier 		/* force at least a class B */
268*9a747e4fSDavid du Colombier 		m |= 0xffff0000;
269*9a747e4fSDavid du Colombier 	}
270*9a747e4fSDavid du Colombier 	cidr->ipaddr = a;
271*9a747e4fSDavid du Colombier 	cidr->mask = m;
272*9a747e4fSDavid du Colombier }
273*9a747e4fSDavid du Colombier 
274*9a747e4fSDavid du Colombier /*
275*9a747e4fSDavid du Colombier  *	Substitute Subchar ('#') for '/'
276*9a747e4fSDavid du Colombier  */
277*9a747e4fSDavid du Colombier char*
subslash(char * os)278*9a747e4fSDavid du Colombier subslash(char *os)
279*9a747e4fSDavid du Colombier {
280*9a747e4fSDavid du Colombier 	char *s;
281*9a747e4fSDavid du Colombier 
282*9a747e4fSDavid du Colombier 	for(s=os; *s; s++)
283*9a747e4fSDavid du Colombier 		if(*s == '/')
284*9a747e4fSDavid du Colombier 			*s = Subchar;
285*9a747e4fSDavid du Colombier 	return os;
286*9a747e4fSDavid du Colombier }
287*9a747e4fSDavid du Colombier 
288*9a747e4fSDavid du Colombier /*
289*9a747e4fSDavid du Colombier  *	Insert an account pseudo-file in a directory
290*9a747e4fSDavid du Colombier  */
291*9a747e4fSDavid du Colombier static void
acctinsert(Node * np,char * cp)292*9a747e4fSDavid du Colombier acctinsert(Node *np, char *cp)
293*9a747e4fSDavid du Colombier {
294*9a747e4fSDavid du Colombier 	int i;
295*9a747e4fSDavid du Colombier 	char *tmp;
296*9a747e4fSDavid du Colombier 	Address *ap;
297*9a747e4fSDavid du Colombier 
298*9a747e4fSDavid du Colombier 	static char *dangerous[] = { "*", "!", "*!", "!*", "*!*", 0 };
299*9a747e4fSDavid du Colombier 
300*9a747e4fSDavid du Colombier 	if(cp == 0 || *cp == 0)
301*9a747e4fSDavid du Colombier 		return;
302*9a747e4fSDavid du Colombier 
303*9a747e4fSDavid du Colombier 	/* rule out dangerous patterns */
304*9a747e4fSDavid du Colombier 	for (i = 0; dangerous[i]; i++)
305*9a747e4fSDavid du Colombier 		if(strcmp(cp, dangerous[i])== 0)
306*9a747e4fSDavid du Colombier 			return;
307*9a747e4fSDavid du Colombier 
308*9a747e4fSDavid du Colombier 	np = dirwalk("account", np);
309*9a747e4fSDavid du Colombier 	if(np == 0)
310*9a747e4fSDavid du Colombier 		return;
311*9a747e4fSDavid du Colombier 
312*9a747e4fSDavid du Colombier 	i = np->count++;
313*9a747e4fSDavid du Colombier 	if(i >= np->allocated){
314*9a747e4fSDavid du Colombier 		np->allocated = np->count;
315*9a747e4fSDavid du Colombier 		np->addrs = realloc(np->addrs, np->allocated*sizeof(Address));
316*9a747e4fSDavid du Colombier 		if(np->addrs == 0)
317*9a747e4fSDavid du Colombier 			fatal("out of memory");
318*9a747e4fSDavid du Colombier 	}
319*9a747e4fSDavid du Colombier 
320*9a747e4fSDavid du Colombier 	ap = &np->addrs[i];			/* new entry on end */
321*9a747e4fSDavid du Colombier 	tmp = strdup(cp);
322*9a747e4fSDavid du Colombier 	if(tmp == nil)
323*9a747e4fSDavid du Colombier 		fatal("out of memory");
324*9a747e4fSDavid du Colombier 	subslash(tmp);
325*9a747e4fSDavid du Colombier 	ap->name = atom(tmp);
326*9a747e4fSDavid du Colombier 	free(tmp);
327*9a747e4fSDavid du Colombier }
328*9a747e4fSDavid du Colombier 
329*9a747e4fSDavid du Colombier /*
330*9a747e4fSDavid du Colombier  *	Insert an IP address pseudo-file in a directory
331*9a747e4fSDavid du Colombier  */
332*9a747e4fSDavid du Colombier static void
ipinsert(Node * np,char * cp)333*9a747e4fSDavid du Colombier ipinsert(Node *np, char *cp)
334*9a747e4fSDavid du Colombier {
335*9a747e4fSDavid du Colombier 	char *tmp;
336*9a747e4fSDavid du Colombier 	int i;
337*9a747e4fSDavid du Colombier 	Address *ap;
338*9a747e4fSDavid du Colombier 	if(cp == 0 || *cp == 0)
339*9a747e4fSDavid du Colombier 		return;
340*9a747e4fSDavid du Colombier 
341*9a747e4fSDavid du Colombier 	np = dirwalk("ip", np);
342*9a747e4fSDavid du Colombier 	if(np == 0)
343*9a747e4fSDavid du Colombier 		return;
344*9a747e4fSDavid du Colombier 
345*9a747e4fSDavid du Colombier 	i = np->count++;
346*9a747e4fSDavid du Colombier 	if(i >= np->allocated){
347*9a747e4fSDavid du Colombier 		np->allocated = np->count;
348*9a747e4fSDavid du Colombier 		np->addrs = realloc(np->addrs, np->allocated*sizeof(Address));
349*9a747e4fSDavid du Colombier 		if(np->addrs == 0)
350*9a747e4fSDavid du Colombier 			fatal("out of memory");
351*9a747e4fSDavid du Colombier 	}
352*9a747e4fSDavid du Colombier 
353*9a747e4fSDavid du Colombier 	ap = &np->addrs[i];				/* new entry on end */
354*9a747e4fSDavid du Colombier 	tmp = strdup(cp);
355*9a747e4fSDavid du Colombier 	if(tmp == nil)
356*9a747e4fSDavid du Colombier 		fatal("out of memory");
357*9a747e4fSDavid du Colombier 	subslash(tmp);
358*9a747e4fSDavid du Colombier 	ap->name = atom(tmp);
359*9a747e4fSDavid du Colombier 	free(tmp);
360*9a747e4fSDavid du Colombier 	cidrparse(&ap->ip, cp);
361*9a747e4fSDavid du Colombier }
362*9a747e4fSDavid du Colombier 
363*9a747e4fSDavid du Colombier int
ipcomp(void * a,void * b)364*9a747e4fSDavid du Colombier ipcomp(void *a, void *b)
365*9a747e4fSDavid du Colombier {
366*9a747e4fSDavid du Colombier 	ulong aip, bip;
367*9a747e4fSDavid du Colombier 
368*9a747e4fSDavid du Colombier 	aip = ((Address*)a)->ip.ipaddr;
369*9a747e4fSDavid du Colombier 	bip = ((Address*)b)->ip.ipaddr;
370*9a747e4fSDavid du Colombier 	if(aip > bip)
371*9a747e4fSDavid du Colombier 		return 1;
372*9a747e4fSDavid du Colombier 	if(aip < bip)
373*9a747e4fSDavid du Colombier 		return -1;
374*9a747e4fSDavid du Colombier 	return 0;
375*9a747e4fSDavid du Colombier }
376*9a747e4fSDavid du Colombier 
377*9a747e4fSDavid du Colombier /*
378*9a747e4fSDavid du Colombier  *	Sort a directory of IP addresses
379*9a747e4fSDavid du Colombier  */
380*9a747e4fSDavid du Colombier static void
ipsort(void)381*9a747e4fSDavid du Colombier ipsort(void)
382*9a747e4fSDavid du Colombier {
383*9a747e4fSDavid du Colombier 	int base;
384*9a747e4fSDavid du Colombier 	Node *dir, *np;
385*9a747e4fSDavid du Colombier 
386*9a747e4fSDavid du Colombier 	base = Qaddrfile;
387*9a747e4fSDavid du Colombier 	for(dir = root->children; dir; dir = dir->sibs){
388*9a747e4fSDavid du Colombier 		if (dir->d.type != Addrdir)
389*9a747e4fSDavid du Colombier 			continue;
390*9a747e4fSDavid du Colombier 		for(np = dir->children; np; np = np->sibs){
391*9a747e4fSDavid du Colombier 			if(np->d.type == IPaddr && np->count && np->addrs)
392*9a747e4fSDavid du Colombier 				qsort(np->addrs, np->count, sizeof(Address), ipcomp);
393*9a747e4fSDavid du Colombier 			np->baseqid = base;
394*9a747e4fSDavid du Colombier 			base += np->count;
395*9a747e4fSDavid du Colombier 		}
396*9a747e4fSDavid du Colombier 	}
397*9a747e4fSDavid du Colombier }
398