xref: /netbsd-src/external/bsd/ipf/dist/tools/ipfcomp.c (revision 07967fb18af5b87d2d477c5b3e1e438bf0c293fb)
1 /*	$NetBSD: ipfcomp.c,v 1.5 2018/02/04 08:19:42 mrg Exp $	*/
2 
3 /*
4  * Copyright (C) 2012 by Darren Reed.
5  *
6  * See the IPFILTER.LICENCE file for details on licencing.
7  */
8 #if !defined(lint)
9 static __attribute__((__used__)) const char sccsid[] = "@(#)ip_fil.c	2.41 6/5/96 (C) 1993-2000 Darren Reed";
10 static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ipfcomp.c,v 1.1.1.2 2012/07/22 13:44:53 darrenr";
11 #endif
12 
13 #include "ipf.h"
14 
15 
16 typedef struct {
17 	int c;
18 	int e;
19 	int n;
20 	int p;
21 	int s;
22 } mc_t;
23 
24 
25 static char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" };
26 static int count = 0;
27 
28 int intcmp __P((const void *, const void *));
29 static void indent __P((FILE *, int));
30 static void printeq __P((FILE *, char *, int, int, int));
31 static void printipeq __P((FILE *, char *, int, int, int));
32 static void addrule __P((FILE *, frentry_t *));
33 static void printhooks __P((FILE *, int, int, frgroup_t *));
34 static void emitheader __P((frgroup_t *, u_int, u_int));
35 static void emitGroup __P((int, int, void *, frentry_t *, char *,
36 			   u_int, u_int));
37 static void emittail __P((void));
38 static void printCgroup __P((int, frentry_t *, mc_t *, char *));
39 
40 #define	FRC_IFN	0
41 #define	FRC_V	1
42 #define	FRC_P	2
43 #define	FRC_FL	3
44 #define	FRC_TOS	4
45 #define	FRC_TTL	5
46 #define	FRC_SRC	6
47 #define	FRC_DST	7
48 #define	FRC_TCP	8
49 #define	FRC_SP	9
50 #define	FRC_DP	10
51 #define	FRC_OPT	11
52 #define	FRC_SEC	12
53 #define	FRC_ATH	13
54 #define	FRC_ICT	14
55 #define	FRC_ICC	15
56 #define	FRC_MAX	16
57 
58 
59 static	FILE	*cfile = NULL;
60 
61 /*
62  * This is called once per filter rule being loaded to emit data structures
63  * required.
64  */
printc(fr)65 void printc(fr)
66 	frentry_t *fr;
67 {
68 	u_long *ulp;
69 	char *and;
70 	FILE *fp;
71 	int i;
72 
73 	if (fr->fr_family == 6)
74 		return;
75 	if ((fr->fr_type != FR_T_IPF) && (fr->fr_type != FR_T_NONE))
76 		return;
77 	if ((fr->fr_type == FR_T_IPF) &&
78 	    ((fr->fr_datype != FRI_NORMAL) || (fr->fr_satype != FRI_NORMAL)))
79 		return;
80 
81 	if (cfile == NULL)
82 		cfile = fopen("ip_rules.c", "w");
83 	if (cfile == NULL)
84 		return;
85 	fp = cfile;
86 	if (count == 0) {
87 		fprintf(fp, "/*\n");
88  		fprintf(fp, "* Copyright (C) 2012 by Darren Reed.\n");
89  		fprintf(fp, "*\n");
90  		fprintf(fp, "* Redistribution and use in source and binary forms are permitted\n");
91  		fprintf(fp, "* provided that this notice is preserved and due credit is given\n");
92  		fprintf(fp, "* to the original author and the contributors.\n");
93  		fprintf(fp, "*/\n\n");
94 
95 		fprintf(fp, "#include <sys/param.h>\n");
96 		fprintf(fp, "#include <sys/types.h>\n");
97 		fprintf(fp, "#include <sys/time.h>\n");
98 		fprintf(fp, "#include <sys/socket.h>\n");
99 		fprintf(fp, "#if (__FreeBSD_version >= 40000)\n");
100 		fprintf(fp, "# if defined(_KERNEL)\n");
101 		fprintf(fp, "#  include <sys/libkern.h>\n");
102 		fprintf(fp, "# else\n");
103 		fprintf(fp, "#  include <sys/unistd.h>\n");
104 		fprintf(fp, "# endif\n");
105 		fprintf(fp, "#endif\n");
106 		fprintf(fp, "#if (__NetBSD_Version__ >= 399000000)\n");
107 		fprintf(fp, "#else\n");
108 		fprintf(fp, "# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n");
109 		fprintf(fp, "#  include <sys/systm.h>\n");
110 		fprintf(fp, "# endif\n");
111 		fprintf(fp, "#endif\n");
112 		fprintf(fp, "#include <sys/errno.h>\n");
113 		fprintf(fp, "#include <sys/param.h>\n");
114 		fprintf(fp,
115 "#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n");
116 		fprintf(fp, "# include <sys/mbuf.h>\n");
117 		fprintf(fp, "#endif\n");
118 		fprintf(fp,
119 "#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n");
120 		fprintf(fp, "# include <sys/sockio.h>\n");
121 		fprintf(fp, "#else\n");
122 		fprintf(fp, "# include <sys/ioctl.h>\n");
123 		fprintf(fp, "#endif /* FreeBSD */\n");
124 		fprintf(fp, "#include <net/if.h>\n");
125 		fprintf(fp, "#include <netinet/in.h>\n");
126 		fprintf(fp, "#include <netinet/in_systm.h>\n");
127 		fprintf(fp, "#include <netinet/ip.h>\n");
128 		fprintf(fp, "#include <netinet/tcp.h>\n");
129 		fprintf(fp, "#include \"netinet/ip_compat.h\"\n");
130 		fprintf(fp, "#include \"netinet/ip_fil.h\"\n\n");
131 		fprintf(fp, "#include \"netinet/ip_rules.h\"\n\n");
132 		fprintf(fp, "#ifndef _KERNEL\n");
133 		fprintf(fp, "# include <string.h>\n");
134 		fprintf(fp, "#endif /* _KERNEL */\n");
135 		fprintf(fp, "\n");
136 		fprintf(fp, "#ifdef IPFILTER_COMPILED\n");
137 		fprintf(fp, "\n");
138 		fprintf(fp, "extern ipf_main_softc_t ipfmain;\n");
139 		fprintf(fp, "\n");
140 	}
141 
142 	addrule(fp, fr);
143 	fr->fr_type |= FR_T_BUILTIN;
144 	and = "";
145 	fr->fr_ref = 1;
146 	i = sizeof(*fr);
147 	if (i & -(1 - sizeof(*ulp)))
148 		i += sizeof(u_long);
149 	for (i /= sizeof(u_long), ulp = (u_long *)fr; i > 0; i--) {
150 		fprintf(fp, "%s%#lx", and, *ulp++);
151 		and = ", ";
152 	}
153 	fprintf(fp, "\n};\n");
154 	fr->fr_type &= ~FR_T_BUILTIN;
155 
156 	count++;
157 
158 	fflush(fp);
159 }
160 
161 
162 static frgroup_t *groups = NULL;
163 
164 
addrule(fp,fr)165 static void addrule(fp, fr)
166 	FILE *fp;
167 	frentry_t *fr;
168 {
169 	frentry_t *f, **fpp;
170 	frgroup_t *g;
171 	u_long *ulp;
172 	char *ghead;
173 	char *gname;
174 	char *and;
175 	int i;
176 
177 	f = (frentry_t *)malloc(sizeof(*f));
178 	bcopy((char *)fr, (char *)f, sizeof(*fr));
179 	if (fr->fr_ipf) {
180 		f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf));
181 		bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf,
182 		      sizeof(*fr->fr_ipf));
183 	}
184 
185 	f->fr_next = NULL;
186 	gname = FR_NAME(fr, fr_group);
187 
188 	for (g = groups; g != NULL; g = g->fg_next)
189 		if ((strncmp(g->fg_name, gname, FR_GROUPLEN) == 0) &&
190 		    (g->fg_flags == (f->fr_flags & FR_INOUT)))
191 			break;
192 
193 	if (g == NULL) {
194 		g = (frgroup_t *)calloc(1, sizeof(*g));
195 		g->fg_next = groups;
196 		groups = g;
197 		g->fg_head = f;
198 		strncpy(g->fg_name, gname, FR_GROUPLEN);
199 		g->fg_ref = 0;
200 		g->fg_flags = f->fr_flags & FR_INOUT;
201 	}
202 
203 	for (fpp = &g->fg_start; *fpp != NULL; )
204 		fpp = &((*fpp)->fr_next);
205 	*fpp = f;
206 
207 	if (fr->fr_dsize > 0) {
208 		fprintf(fp, "\
209 static u_long ipf%s_rule_data_%s_%u[] = {\n",
210 			f->fr_flags & FR_INQUE ? "in" : "out",
211 			g->fg_name, g->fg_ref);
212 		and = "";
213 		i = fr->fr_dsize;
214 		ulp = fr->fr_data;
215 		for (i /= sizeof(u_long); i > 0; i--) {
216 			fprintf(fp, "%s%#lx", and, *ulp++);
217 			and = ", ";
218 		}
219 		fprintf(fp, "\n};\n");
220 	}
221 
222 	fprintf(fp, "\nstatic u_long %s_rule_%s_%d[] = {\n",
223 		f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref);
224 
225 	g->fg_ref++;
226 
227 	if (f->fr_grhead != -1) {
228 		ghead = FR_NAME(f, fr_grhead);
229 		for (g = groups; g != NULL; g = g->fg_next)
230 			if ((strncmp(g->fg_name, ghead, FR_GROUPLEN) == 0) &&
231 			    g->fg_flags == (f->fr_flags & FR_INOUT))
232 				break;
233 		if (g == NULL) {
234 			g = (frgroup_t *)calloc(1, sizeof(*g));
235 			g->fg_next = groups;
236 			groups = g;
237 			g->fg_head = f;
238 			strncpy(g->fg_name, ghead, FR_GROUPLEN);
239 			g->fg_ref = 0;
240 			g->fg_flags = f->fr_flags & FR_INOUT;
241 		}
242 	}
243 }
244 
245 
intcmp(c1,c2)246 int intcmp(c1, c2)
247 	const void *c1, *c2;
248 {
249 	const mc_t *i1 = (const mc_t *)c1, *i2 = (const mc_t *)c2;
250 
251 	if (i1->n == i2->n) {
252 		return i1->c - i2->c;
253 	}
254 	return i2->n - i1->n;
255 }
256 
257 
indent(fp,in)258 static void indent(fp, in)
259 	FILE *fp;
260 	int in;
261 {
262 	for (; in; in--)
263 		fputc('\t', fp);
264 }
265 
printeq(fp,var,m,max,v)266 static void printeq(fp, var, m, max, v)
267 	FILE *fp;
268 	char *var;
269 	int m, max, v;
270 {
271 	if (m == max)
272 		fprintf(fp, "%s == %#x) {\n", var, v);
273 	else
274 		fprintf(fp, "(%s & %#x) == %#x) {\n", var, m, v);
275 }
276 
277 /*
278  * Parameters: var - IP# being compared
279  *             fl - 0 for positive match, 1 for negative match
280  *             m - netmask
281  *             v - required address
282  */
printipeq(fp,var,fl,m,v)283 static void printipeq(fp, var, fl, m, v)
284 	FILE *fp;
285 	char *var;
286 	int fl, m, v;
287 {
288 	if (m == 0xffffffff)
289 		fprintf(fp, "%s ", var);
290 	else
291 		fprintf(fp, "(%s & %#x) ", var, m);
292 	fprintf(fp, "%c", fl ? '!' : '=');
293 	fprintf(fp, "= %#x) {\n", v);
294 }
295 
296 
emit(num,dir,v,fr)297 void emit(num, dir, v, fr)
298 	int num, dir;
299 	void *v;
300 	frentry_t *fr;
301 {
302 	u_int incnt, outcnt;
303 	frgroup_t *g;
304 	frentry_t *f;
305 
306 	for (g = groups; g != NULL; g = g->fg_next) {
307 		if (dir == 0 || dir == -1) {
308 			if ((g->fg_flags & FR_INQUE) == 0)
309 				continue;
310 			for (incnt = 0, f = g->fg_start; f != NULL;
311 			     f = f->fr_next)
312 				incnt++;
313 			emitGroup(num, dir, v, fr, g->fg_name, incnt, 0);
314 		}
315 		if (dir == 1 || dir == -1) {
316 			if ((g->fg_flags & FR_OUTQUE) == 0)
317 				continue;
318 			for (outcnt = 0, f = g->fg_start; f != NULL;
319 			     f = f->fr_next)
320 				outcnt++;
321 			emitGroup(num, dir, v, fr, g->fg_name, 0, outcnt);
322 		}
323 	}
324 
325 	if (num == -1 && dir == -1) {
326 		for (g = groups; g != NULL; g = g->fg_next) {
327 			if ((g->fg_flags & FR_INQUE) != 0) {
328 				for (incnt = 0, f = g->fg_start; f != NULL;
329 				     f = f->fr_next)
330 					incnt++;
331 				if (incnt > 0)
332 					emitheader(g, incnt, 0);
333 			}
334 			if ((g->fg_flags & FR_OUTQUE) != 0) {
335 				for (outcnt = 0, f = g->fg_start; f != NULL;
336 				     f = f->fr_next)
337 					outcnt++;
338 				if (outcnt > 0)
339 					emitheader(g, 0, outcnt);
340 			}
341 		}
342 		emittail();
343 		fprintf(cfile, "#endif /* IPFILTER_COMPILED */\n");
344 	}
345 
346 }
347 
348 
emitheader(grp,incount,outcount)349 static void emitheader(grp, incount, outcount)
350 	frgroup_t *grp;
351 	u_int incount, outcount;
352 {
353 	static FILE *fph = NULL;
354 	frgroup_t *g;
355 
356 	if (fph == NULL) {
357 		fph = fopen("ip_rules.h", "w");
358 		if (fph == NULL)
359 			return;
360 
361 		fprintf(fph, "extern int ipfrule_add __P((void));\n");
362 		fprintf(fph, "extern int ipfrule_remove __P((void));\n");
363 	}
364 
365 	printhooks(cfile, incount, outcount, grp);
366 
367 	if (incount) {
368 		fprintf(fph, "\n\
369 extern frentry_t *ipfrule_match_in_%s __P((fr_info_t *, u_32_t *));\n\
370 extern frentry_t *ipf_rules_in_%s[%d];\n",
371 			grp->fg_name, grp->fg_name, incount);
372 
373 		for (g = groups; g != grp; g = g->fg_next)
374 			if ((strncmp(g->fg_name, grp->fg_name,
375 				     FR_GROUPLEN) == 0) &&
376 			    g->fg_flags == grp->fg_flags)
377 				break;
378 		if (g == grp) {
379 			fprintf(fph, "\n\
380 extern int ipfrule_add_in_%s __P((void));\n\
381 extern int ipfrule_remove_in_%s __P((void));\n", grp->fg_name, grp->fg_name);
382 		}
383 	}
384 	if (outcount) {
385 		fprintf(fph, "\n\
386 extern frentry_t *ipfrule_match_out_%s __P((fr_info_t *, u_32_t *));\n\
387 extern frentry_t *ipf_rules_out_%s[%d];\n",
388 			grp->fg_name, grp->fg_name, outcount);
389 
390 		for (g = groups; g != grp; g = g->fg_next)
391 			if ((strncmp(g->fg_name, grp->fg_name,
392 				     FR_GROUPLEN) == 0) &&
393 			    g->fg_flags == grp->fg_flags)
394 				break;
395 		if (g == grp) {
396 			fprintf(fph, "\n\
397 extern int ipfrule_add_out_%s __P((void));\n\
398 extern int ipfrule_remove_out_%s __P((void));\n",
399 				grp->fg_name, grp->fg_name);
400 		}
401 	}
402 }
403 
emittail()404 static void emittail()
405 {
406 	frgroup_t *g;
407 
408 	fprintf(cfile, "\n\
409 int ipfrule_add()\n\
410 {\n\
411 	int err;\n\
412 \n");
413 	for (g = groups; g != NULL; g = g->fg_next)
414 		fprintf(cfile, "\
415 	err = ipfrule_add_%s_%s();\n\
416 	if (err != 0)\n\
417 		return err;\n",
418 			(g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name);
419 	fprintf(cfile, "\
420 	return 0;\n");
421 	fprintf(cfile, "}\n\
422 \n");
423 
424 	fprintf(cfile, "\n\
425 int ipfrule_remove()\n\
426 {\n\
427 	int err;\n\
428 \n");
429 	for (g = groups; g != NULL; g = g->fg_next)
430 		fprintf(cfile, "\
431 	err = ipfrule_remove_%s_%s();\n\
432 	if (err != 0)\n\
433 		return err;\n",
434 			(g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name);
435 	fprintf(cfile, "\
436 	return 0;\n");
437 	fprintf(cfile, "}\n");
438 }
439 
440 
emitGroup(num,dir,v,fr,group,incount,outcount)441 static void emitGroup(num, dir, v, fr, group, incount, outcount)
442 	int num, dir;
443 	void *v;
444 	frentry_t *fr;
445 	char *group;
446 	u_int incount, outcount;
447 {
448 	static FILE *fp = NULL;
449 	static int header[2] = { 0, 0 };
450 	static char egroup[FR_GROUPLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
451 	static int openfunc = 0;
452 	static mc_t *n = NULL;
453 	static int sin = 0;
454 	frentry_t *f;
455 	frgroup_t *g;
456 	fripf_t *ipf;
457 	int i, in, j;
458 	mc_t *m = v;
459 
460 	if (fp == NULL)
461 		fp = cfile;
462 	if (fp == NULL)
463 		return;
464 	if (strncmp(egroup, group, FR_GROUPLEN)) {
465 		for (sin--; sin > 0; sin--) {
466 			indent(fp, sin);
467 			fprintf(fp, "}\n");
468 		}
469 		if (openfunc == 1) {
470 			fprintf(fp, "\treturn fr;\n}\n");
471 			openfunc = 0;
472 			if (n != NULL) {
473 				free(n);
474 				n = NULL;
475 			}
476 		}
477 		sin = 0;
478 		header[0] = 0;
479 		header[1] = 0;
480 		strncpy(egroup, group, FR_GROUPLEN);
481 	} else if (openfunc == 1 && num < 0) {
482 		if (n != NULL) {
483 			free(n);
484 			n = NULL;
485 		}
486 		for (sin--; sin > 0; sin--) {
487 			indent(fp, sin);
488 			fprintf(fp, "}\n");
489 		}
490 		if (openfunc == 1) {
491 			fprintf(fp, "\treturn fr;\n}\n");
492 			openfunc = 0;
493 		}
494 	}
495 
496 	if (dir == -1)
497 		return;
498 
499 	for (g = groups; g != NULL; g = g->fg_next) {
500 		if (dir == 0 && (g->fg_flags & FR_INQUE) == 0)
501 			continue;
502 		else if (dir == 1 && (g->fg_flags & FR_OUTQUE) == 0)
503 			continue;
504 		if (strncmp(g->fg_name, group, FR_GROUPLEN) != 0)
505 			continue;
506 		break;
507 	}
508 
509 	/*
510 	 * Output the array of pointers to rules for this group.
511 	 */
512 	if (g != NULL && num == -2 && dir == 0 && header[0] == 0 &&
513 	    incount != 0) {
514 		fprintf(fp, "\nfrentry_t *ipf_rules_in_%s[%d] = {",
515 			group, incount);
516 		for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
517 			if ((f->fr_flags & FR_INQUE) == 0)
518 				continue;
519 			if ((i & 1) == 0) {
520 				fprintf(fp, "\n\t");
521 			}
522 			fprintf(fp, "(frentry_t *)&in_rule_%s_%d",
523 				FR_NAME(f, fr_group), i);
524 			if (i + 1 < incount)
525 				fprintf(fp, ", ");
526 			i++;
527 		}
528 		fprintf(fp, "\n};\n");
529 	}
530 
531 	if (g != NULL && num == -2 && dir == 1 && header[0] == 0 &&
532 	    outcount != 0) {
533 		fprintf(fp, "\nfrentry_t *ipf_rules_out_%s[%d] = {",
534 			group, outcount);
535 		for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
536 			if ((f->fr_flags & FR_OUTQUE) == 0)
537 				continue;
538 			if ((i & 1) == 0) {
539 				fprintf(fp, "\n\t");
540 			}
541 			fprintf(fp, "(frentry_t *)&out_rule_%s_%d",
542 				FR_NAME(f, fr_group), i);
543 			if (i + 1 < outcount)
544 				fprintf(fp, ", ");
545 			i++;
546 		}
547 		fprintf(fp, "\n};\n");
548 		fp = NULL;
549 	}
550 
551 	if (num < 0)
552 		return;
553 
554 	in = 0;
555 	ipf = fr->fr_ipf;
556 
557 	/*
558 	 * If the function header has not been printed then print it now.
559 	 */
560 	if (g != NULL && header[dir] == 0) {
561 		int pdst = 0, psrc = 0;
562 
563 		openfunc = 1;
564 		fprintf(fp, "\nfrentry_t *ipfrule_match_%s_%s(fin, passp)\n",
565 			(dir == 0) ? "in" : "out", group);
566 		fprintf(fp, "fr_info_t *fin;\n");
567 		fprintf(fp, "u_32_t *passp;\n");
568 		fprintf(fp, "{\n");
569 		fprintf(fp, "\tfrentry_t *fr = NULL;\n");
570 
571 		/*
572 		 * Print out any variables that need to be declared.
573 		 */
574 		for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
575 			if (incount + outcount > m[FRC_SRC].e + 1)
576 				psrc = 1;
577 			if (incount + outcount > m[FRC_DST].e + 1)
578 				pdst = 1;
579 		}
580 		if (psrc == 1)
581 			fprintf(fp, "\tu_32_t src = ntohl(%s);\n",
582 				"fin->fin_fi.fi_saddr");
583 		if (pdst == 1)
584 			fprintf(fp, "\tu_32_t dst = ntohl(%s);\n",
585 				"fin->fin_fi.fi_daddr");
586 	}
587 
588 	for (i = 0; i < FRC_MAX; i++) {
589 		switch(m[i].c)
590 		{
591 		case FRC_IFN :
592 			if (fr->fr_ifnames[0] != -1)
593 				m[i].s = 1;
594 			break;
595 		case FRC_V :
596 			if (ipf != NULL && ipf->fri_mip.fi_v != 0)
597 				m[i].s = 1;
598 			break;
599 		case FRC_FL :
600 			if (ipf != NULL && ipf->fri_mip.fi_flx != 0)
601 				m[i].s = 1;
602 			break;
603 		case FRC_P :
604 			if (ipf != NULL && ipf->fri_mip.fi_p != 0)
605 				m[i].s = 1;
606 			break;
607 		case FRC_TTL :
608 			if (ipf != NULL && ipf->fri_mip.fi_ttl != 0)
609 				m[i].s = 1;
610 			break;
611 		case FRC_TOS :
612 			if (ipf != NULL && ipf->fri_mip.fi_tos != 0)
613 				m[i].s = 1;
614 			break;
615 		case FRC_TCP :
616 			if (ipf == NULL)
617 				break;
618 			if ((ipf->fri_ip.fi_p == IPPROTO_TCP) &&
619 			    fr->fr_tcpfm != 0)
620 				m[i].s = 1;
621 			break;
622 		case FRC_SP :
623 			if (ipf == NULL)
624 				break;
625 			if (fr->fr_scmp == FR_INRANGE)
626 				m[i].s = 1;
627 			else if (fr->fr_scmp == FR_OUTRANGE)
628 				m[i].s = 1;
629 			else if (fr->fr_scmp != 0)
630 				m[i].s = 1;
631 			break;
632 		case FRC_DP :
633 			if (ipf == NULL)
634 				break;
635 			if (fr->fr_dcmp == FR_INRANGE)
636 				m[i].s = 1;
637 			else if (fr->fr_dcmp == FR_OUTRANGE)
638 				m[i].s = 1;
639 			else if (fr->fr_dcmp != 0)
640 				m[i].s = 1;
641 			break;
642 		case FRC_SRC :
643 			if (ipf == NULL)
644 				break;
645 			if (fr->fr_satype == FRI_LOOKUP) {
646 				;
647 			} else if ((fr->fr_smask != 0) ||
648 				   (fr->fr_flags & FR_NOTSRCIP) != 0)
649 				m[i].s = 1;
650 			break;
651 		case FRC_DST :
652 			if (ipf == NULL)
653 				break;
654 			if (fr->fr_datype == FRI_LOOKUP) {
655 				;
656 			} else if ((fr->fr_dmask != 0) ||
657 				   (fr->fr_flags & FR_NOTDSTIP) != 0)
658 				m[i].s = 1;
659 			break;
660 		case FRC_OPT :
661 			if (ipf == NULL)
662 				break;
663 			if (fr->fr_optmask != 0)
664 				m[i].s = 1;
665 			break;
666 		case FRC_SEC :
667 			if (ipf == NULL)
668 				break;
669 			if (fr->fr_secmask != 0)
670 				m[i].s = 1;
671 			break;
672 		case FRC_ATH :
673 			if (ipf == NULL)
674 				break;
675 			if (fr->fr_authmask != 0)
676 				m[i].s = 1;
677 			break;
678 		case FRC_ICT :
679 			if (ipf == NULL)
680 				break;
681 			if ((fr->fr_icmpm & 0xff00) != 0)
682 				m[i].s = 1;
683 			break;
684 		case FRC_ICC :
685 			if (ipf == NULL)
686 				break;
687 			if ((fr->fr_icmpm & 0xff) != 0)
688 				m[i].s = 1;
689 			break;
690 		}
691 	}
692 
693 	if (!header[dir]) {
694 		fprintf(fp, "\n");
695 		header[dir] = 1;
696 		sin = 0;
697 	}
698 
699 	qsort(m, FRC_MAX, sizeof(mc_t), intcmp);
700 
701 	if (n) {
702 		/*
703 		 * Calculate the indentation interval upto the last common
704 		 * common comparison being made.
705 		 */
706 		for (i = 0, in = 1; i < FRC_MAX; i++) {
707 			if (n[i].c != m[i].c)
708 				break;
709 			if (n[i].s != m[i].s)
710 				break;
711 			if (n[i].s) {
712 				if (n[i].n && (n[i].n > n[i].e)) {
713 					m[i].p++;
714 					in += m[i].p;
715 					break;
716 				}
717 				if (n[i].e > 0) {
718 					in++;
719 				} else
720 					break;
721 			}
722 		}
723 		if (sin != in) {
724 			for (j = sin - 1; j >= in; j--) {
725 				indent(fp, j);
726 				fprintf(fp, "}\n");
727 			}
728 		}
729 	} else {
730 		in = 1;
731 		i = 0;
732 	}
733 
734 	/*
735 	 * print out C code that implements a filter rule.
736 	 */
737 	for (; i < FRC_MAX; i++) {
738 		switch(m[i].c)
739 		{
740 		case FRC_IFN :
741 			if (m[i].s) {
742 				indent(fp, in);
743 				fprintf(fp, "if (fin->fin_ifp == ");
744 				fprintf(fp, "ipf_rules_%s_%s[%d]->fr_ifa) {\n",
745 					dir ? "out" : "in", group, num);
746 				in++;
747 			}
748 			break;
749 		case FRC_V :
750 			if (m[i].s) {
751 				indent(fp, in);
752 				fprintf(fp, "if (fin->fin_v == %d) {\n",
753 					ipf->fri_ip.fi_v);
754 				in++;
755 			}
756 			break;
757 		case FRC_FL :
758 			if (m[i].s) {
759 				indent(fp, in);
760 				fprintf(fp, "if (");
761 				printeq(fp, "fin->fin_flx",
762 				        ipf->fri_mip.fi_flx, 0xf,
763 					ipf->fri_ip.fi_flx);
764 				in++;
765 			}
766 			break;
767 		case FRC_P :
768 			if (m[i].s) {
769 				indent(fp, in);
770 				fprintf(fp, "if (fin->fin_p == %d) {\n",
771 					ipf->fri_ip.fi_p);
772 				in++;
773 			}
774 			break;
775 		case FRC_TTL :
776 			if (m[i].s) {
777 				indent(fp, in);
778 				fprintf(fp, "if (");
779 				printeq(fp, "fin->fin_ttl",
780 					ipf->fri_mip.fi_ttl, 0xff,
781 					ipf->fri_ip.fi_ttl);
782 				in++;
783 			}
784 			break;
785 		case FRC_TOS :
786 			if (m[i].s) {
787 				indent(fp, in);
788 				fprintf(fp, "if (fin->fin_tos");
789 				printeq(fp, "fin->fin_tos",
790 					ipf->fri_mip.fi_tos, 0xff,
791 					ipf->fri_ip.fi_tos);
792 				in++;
793 			}
794 			break;
795 		case FRC_TCP :
796 			if (m[i].s) {
797 				indent(fp, in);
798 				fprintf(fp, "if (");
799 				printeq(fp, "fin->fin_tcpf", fr->fr_tcpfm,
800 					0xff, fr->fr_tcpf);
801 				in++;
802 			}
803 			break;
804 		case FRC_SP :
805 			if (!m[i].s)
806 				break;
807 			if (fr->fr_scmp == FR_INRANGE) {
808 				indent(fp, in);
809 				fprintf(fp, "if ((fin->fin_data[0] > %d) && ",
810 					fr->fr_sport);
811 				fprintf(fp, "(fin->fin_data[0] < %d)",
812 					fr->fr_stop);
813 				fprintf(fp, ") {\n");
814 				in++;
815 			} else if (fr->fr_scmp == FR_OUTRANGE) {
816 				indent(fp, in);
817 				fprintf(fp, "if ((fin->fin_data[0] < %d) || ",
818 					fr->fr_sport);
819 				fprintf(fp, "(fin->fin_data[0] > %d)",
820 					fr->fr_stop);
821 				fprintf(fp, ") {\n");
822 				in++;
823 			} else if (fr->fr_scmp) {
824 				indent(fp, in);
825 				fprintf(fp, "if (fin->fin_data[0] %s %d)",
826 					portcmp[fr->fr_scmp], fr->fr_sport);
827 				fprintf(fp, " {\n");
828 				in++;
829 			}
830 			break;
831 		case FRC_DP :
832 			if (!m[i].s)
833 				break;
834 			if (fr->fr_dcmp == FR_INRANGE) {
835 				indent(fp, in);
836 				fprintf(fp, "if ((fin->fin_data[1] > %d) && ",
837 					fr->fr_dport);
838 				fprintf(fp, "(fin->fin_data[1] < %d)",
839 					fr->fr_dtop);
840 				fprintf(fp, ") {\n");
841 				in++;
842 			} else if (fr->fr_dcmp == FR_OUTRANGE) {
843 				indent(fp, in);
844 				fprintf(fp, "if ((fin->fin_data[1] < %d) || ",
845 					fr->fr_dport);
846 				fprintf(fp, "(fin->fin_data[1] > %d)",
847 					fr->fr_dtop);
848 				fprintf(fp, ") {\n");
849 				in++;
850 			} else if (fr->fr_dcmp) {
851 				indent(fp, in);
852 				fprintf(fp, "if (fin->fin_data[1] %s %d)",
853 					portcmp[fr->fr_dcmp], fr->fr_dport);
854 				fprintf(fp, " {\n");
855 				in++;
856 			}
857 			break;
858 		case FRC_SRC :
859 			if (!m[i].s)
860 				break;
861 			if (fr->fr_satype == FRI_LOOKUP) {
862 				;
863 			} else if ((fr->fr_smask != 0) ||
864 				   (fr->fr_flags & FR_NOTSRCIP) != 0) {
865 				indent(fp, in);
866 				fprintf(fp, "if (");
867 				printipeq(fp, "src",
868 					  fr->fr_flags & FR_NOTSRCIP,
869 					  fr->fr_smask, fr->fr_saddr);
870 				in++;
871 			}
872 			break;
873 		case FRC_DST :
874 			if (!m[i].s)
875 				break;
876 			if (fr->fr_datype == FRI_LOOKUP) {
877 				;
878 			} else if ((fr->fr_dmask != 0) ||
879 				   (fr->fr_flags & FR_NOTDSTIP) != 0) {
880 				indent(fp, in);
881 				fprintf(fp, "if (");
882 				printipeq(fp, "dst",
883 					  fr->fr_flags & FR_NOTDSTIP,
884 					  fr->fr_dmask, fr->fr_daddr);
885 				in++;
886 			}
887 			break;
888 		case FRC_OPT :
889 			if (m[i].s) {
890 				indent(fp, in);
891 				fprintf(fp, "if (");
892 				printeq(fp, "fin->fin_fi.fi_optmsk",
893 					fr->fr_optmask, 0xffffffff,
894 				        fr->fr_optbits);
895 				in++;
896 			}
897 			break;
898 		case FRC_SEC :
899 			if (m[i].s) {
900 				indent(fp, in);
901 				fprintf(fp, "if (");
902 				printeq(fp, "fin->fin_fi.fi_secmsk",
903 					fr->fr_secmask, 0xffff,
904 					fr->fr_secbits);
905 				in++;
906 			}
907 			break;
908 		case FRC_ATH :
909 			if (m[i].s) {
910 				indent(fp, in);
911 				fprintf(fp, "if (");
912 				printeq(fp, "fin->fin_fi.fi_authmsk",
913 					fr->fr_authmask, 0xffff,
914 					fr->fr_authbits);
915 				in++;
916 			}
917 			break;
918 		case FRC_ICT :
919 			if (m[i].s) {
920 				indent(fp, in);
921 				fprintf(fp, "if (");
922 				printeq(fp, "fin->fin_data[0]",
923 					fr->fr_icmpm & 0xff00, 0xffff,
924 					fr->fr_icmp & 0xff00);
925 				in++;
926 			}
927 			break;
928 		case FRC_ICC :
929 			if (m[i].s) {
930 				indent(fp, in);
931 				fprintf(fp, "if (");
932 				printeq(fp, "fin->fin_data[0]",
933 					fr->fr_icmpm & 0xff, 0xffff,
934 					fr->fr_icmp & 0xff);
935 				in++;
936 			}
937 			break;
938 		}
939 
940 	}
941 
942 	indent(fp, in);
943 	if (fr->fr_flags & FR_QUICK) {
944 		fprintf(fp, "return (frentry_t *)&%s_rule_%s_%d;\n",
945 			fr->fr_flags & FR_INQUE ? "in" : "out",
946 			FR_NAME(fr, fr_group), num);
947 	} else {
948 		fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n",
949 			fr->fr_flags & FR_INQUE ? "in" : "out",
950 			FR_NAME(fr, fr_group), num);
951 	}
952 	if (n == NULL)
953 		n = (mc_t *)malloc(sizeof(*n) * FRC_MAX);
954 	bcopy((char *)m, (char *)n, sizeof(*n) * FRC_MAX);
955 	sin = in;
956 }
957 
958 
printC(dir)959 void printC(dir)
960 	int dir;
961 {
962 	static mc_t *m = NULL;
963 	frgroup_t *g;
964 
965 	if (m == NULL)
966 		m = (mc_t *)calloc(1, sizeof(*m) * FRC_MAX);
967 
968 	for (g = groups; g != NULL; g = g->fg_next) {
969 		if ((dir == 0) && ((g->fg_flags & FR_INQUE) != 0))
970 			printCgroup(dir, g->fg_start, m, g->fg_name);
971 		if ((dir == 1) && ((g->fg_flags & FR_OUTQUE) != 0))
972 			printCgroup(dir, g->fg_start, m, g->fg_name);
973 	}
974 
975 	emit(-1, dir, m, NULL);
976 }
977 
978 
979 /*
980  * Now print out code to implement all of the rules.
981  */
printCgroup(dir,top,m,group)982 static void printCgroup(dir, top, m, group)
983 	int dir;
984 	frentry_t *top;
985 	mc_t *m;
986 	char *group;
987 {
988 	frentry_t *fr, *fr1;
989 	int i, n, rn;
990 	u_int count;
991 
992 	for (count = 0, fr1 = top; fr1 != NULL; fr1 = fr1->fr_next) {
993 		if ((dir == 0) && ((fr1->fr_flags & FR_INQUE) != 0))
994 			count++;
995 		else if ((dir == 1) && ((fr1->fr_flags & FR_OUTQUE) != 0))
996 			count++;
997 	}
998 
999 	if (dir == 0)
1000 		emitGroup(-2, dir, m, fr1, group, count, 0);
1001 	else if (dir == 1)
1002 		emitGroup(-2, dir, m, fr1, group, 0, count);
1003 
1004 	/*
1005 	 * Before printing each rule, check to see how many of its fields are
1006 	 * matched by subsequent rules.
1007 	 */
1008 	for (fr1 = top, rn = 0; fr1 != NULL; fr1 = fr1->fr_next, rn++) {
1009 		if (!dir && !(fr1->fr_flags & FR_INQUE))
1010 			continue;
1011 		if (dir && !(fr1->fr_flags & FR_OUTQUE))
1012 			continue;
1013 		n = 0xfffffff;
1014 
1015 		for (i = 0; i < FRC_MAX; i++)
1016 			m[i].e = 0;
1017 		qsort(m, FRC_MAX, sizeof(mc_t), intcmp);
1018 
1019 		for (i = 0; i < FRC_MAX; i++) {
1020 			m[i].c = i;
1021 			m[i].e = 0;
1022 			m[i].n = 0;
1023 			m[i].s = 0;
1024 		}
1025 
1026 		for (fr = fr1->fr_next; fr; fr = fr->fr_next) {
1027 			if (!dir && !(fr->fr_flags & FR_INQUE))
1028 				continue;
1029 			if (dir && !(fr->fr_flags & FR_OUTQUE))
1030 				continue;
1031 
1032 			if ((n & 0x0001) &&
1033 			    !strcmp(fr1->fr_names + fr1->fr_ifnames[0],
1034 				    fr->fr_names + fr->fr_ifnames[0])) {
1035 				m[FRC_IFN].e++;
1036 				m[FRC_IFN].n++;
1037 			} else
1038 				n &= ~0x0001;
1039 
1040 			if ((n & 0x0002) && (fr1->fr_family == fr->fr_family)) {
1041 				m[FRC_V].e++;
1042 				m[FRC_V].n++;
1043 			} else
1044 				n &= ~0x0002;
1045 
1046 			if ((n & 0x0004) &&
1047 			    (fr->fr_type == fr1->fr_type) &&
1048 			    (fr->fr_type == FR_T_IPF) &&
1049 			    (fr1->fr_mip.fi_flx == fr->fr_mip.fi_flx) &&
1050 			    (fr1->fr_ip.fi_flx == fr->fr_ip.fi_flx)) {
1051 				m[FRC_FL].e++;
1052 				m[FRC_FL].n++;
1053 			} else
1054 				n &= ~0x0004;
1055 
1056 			if ((n & 0x0008) &&
1057 			    (fr->fr_type == fr1->fr_type) &&
1058 			    (fr->fr_type == FR_T_IPF) &&
1059 			    (fr1->fr_proto == fr->fr_proto)) {
1060 				m[FRC_P].e++;
1061 				m[FRC_P].n++;
1062 			} else
1063 				n &= ~0x0008;
1064 
1065 			if ((n & 0x0010) &&
1066 			    (fr->fr_type == fr1->fr_type) &&
1067 			    (fr->fr_type == FR_T_IPF) &&
1068 			    (fr1->fr_ttl == fr->fr_ttl)) {
1069 				m[FRC_TTL].e++;
1070 				m[FRC_TTL].n++;
1071 			} else
1072 				n &= ~0x0010;
1073 
1074 			if ((n & 0x0020) &&
1075 			    (fr->fr_type == fr1->fr_type) &&
1076 			    (fr->fr_type == FR_T_IPF) &&
1077 			    (fr1->fr_tos == fr->fr_tos)) {
1078 				m[FRC_TOS].e++;
1079 				m[FRC_TOS].n++;
1080 			} else
1081 				n &= ~0x0020;
1082 
1083 			if ((n & 0x0040) &&
1084 			    (fr->fr_type == fr1->fr_type) &&
1085 			    (fr->fr_type == FR_T_IPF) &&
1086 			    ((fr1->fr_tcpfm == fr->fr_tcpfm) &&
1087 			    (fr1->fr_tcpf == fr->fr_tcpf))) {
1088 				m[FRC_TCP].e++;
1089 				m[FRC_TCP].n++;
1090 			} else
1091 				n &= ~0x0040;
1092 
1093 			if ((n & 0x0080) &&
1094 			    (fr->fr_type == fr1->fr_type) &&
1095 			    (fr->fr_type == FR_T_IPF) &&
1096 			    ((fr1->fr_scmp == fr->fr_scmp) &&
1097 			     (fr1->fr_stop == fr->fr_stop) &&
1098 			     (fr1->fr_sport == fr->fr_sport))) {
1099 				m[FRC_SP].e++;
1100 				m[FRC_SP].n++;
1101 			} else
1102 				n &= ~0x0080;
1103 
1104 			if ((n & 0x0100) &&
1105 			    (fr->fr_type == fr1->fr_type) &&
1106 			    (fr->fr_type == FR_T_IPF) &&
1107 			    ((fr1->fr_dcmp == fr->fr_dcmp) &&
1108 			     (fr1->fr_dtop == fr->fr_dtop) &&
1109 			     (fr1->fr_dport == fr->fr_dport))) {
1110 				m[FRC_DP].e++;
1111 				m[FRC_DP].n++;
1112 			} else
1113 				n &= ~0x0100;
1114 
1115 			if ((n & 0x0200) &&
1116 			    (fr->fr_type == fr1->fr_type) &&
1117 			    (fr->fr_type == FR_T_IPF) &&
1118 			    ((fr1->fr_satype == FRI_LOOKUP) &&
1119 			    (fr->fr_satype == FRI_LOOKUP) &&
1120 			    (fr1->fr_srcnum == fr->fr_srcnum))) {
1121 				m[FRC_SRC].e++;
1122 				m[FRC_SRC].n++;
1123 			} else if ((n & 0x0200) &&
1124 				   (fr->fr_type == fr1->fr_type) &&
1125 				   (fr->fr_type == FR_T_IPF) &&
1126 				   (((fr1->fr_flags & FR_NOTSRCIP) ==
1127 				    (fr->fr_flags & FR_NOTSRCIP)))) {
1128 					if ((fr1->fr_smask == fr->fr_smask) &&
1129 					    (fr1->fr_saddr == fr->fr_saddr))
1130 						m[FRC_SRC].e++;
1131 					else
1132 						n &= ~0x0200;
1133 					if (fr1->fr_smask &&
1134 					    (fr1->fr_saddr & fr1->fr_smask) ==
1135 					    (fr->fr_saddr & fr1->fr_smask)) {
1136 						m[FRC_SRC].n++;
1137 						n |= 0x0200;
1138 					}
1139 			} else {
1140 				n &= ~0x0200;
1141 			}
1142 
1143 			if ((n & 0x0400) &&
1144 			    (fr->fr_type == fr1->fr_type) &&
1145 			    (fr->fr_type == FR_T_IPF) &&
1146 			    ((fr1->fr_datype == FRI_LOOKUP) &&
1147 			    (fr->fr_datype == FRI_LOOKUP) &&
1148 			    (fr1->fr_dstnum == fr->fr_dstnum))) {
1149 				m[FRC_DST].e++;
1150 				m[FRC_DST].n++;
1151 			} else if ((n & 0x0400) &&
1152 				   (fr->fr_type == fr1->fr_type) &&
1153 				   (fr->fr_type == FR_T_IPF) &&
1154 				   (((fr1->fr_flags & FR_NOTDSTIP) ==
1155 				    (fr->fr_flags & FR_NOTDSTIP)))) {
1156 					if ((fr1->fr_dmask == fr->fr_dmask) &&
1157 					    (fr1->fr_daddr == fr->fr_daddr))
1158 						m[FRC_DST].e++;
1159 					else
1160 						n &= ~0x0400;
1161 					if (fr1->fr_dmask &&
1162 					    (fr1->fr_daddr & fr1->fr_dmask) ==
1163 					    (fr->fr_daddr & fr1->fr_dmask)) {
1164 						m[FRC_DST].n++;
1165 						n |= 0x0400;
1166 					}
1167 			} else {
1168 				n &= ~0x0400;
1169 			}
1170 
1171 			if ((n & 0x0800) &&
1172 			    (fr->fr_type == fr1->fr_type) &&
1173 			    (fr->fr_type == FR_T_IPF) &&
1174 			    (fr1->fr_optmask == fr->fr_optmask) &&
1175 			    (fr1->fr_optbits == fr->fr_optbits)) {
1176 				m[FRC_OPT].e++;
1177 				m[FRC_OPT].n++;
1178 			} else
1179 				n &= ~0x0800;
1180 
1181 			if ((n & 0x1000) &&
1182 			    (fr->fr_type == fr1->fr_type) &&
1183 			    (fr->fr_type == FR_T_IPF) &&
1184 			    (fr1->fr_secmask == fr->fr_secmask) &&
1185 			    (fr1->fr_secbits == fr->fr_secbits)) {
1186 				m[FRC_SEC].e++;
1187 				m[FRC_SEC].n++;
1188 			} else
1189 				n &= ~0x1000;
1190 
1191 			if ((n & 0x10000) &&
1192 			    (fr->fr_type == fr1->fr_type) &&
1193 			    (fr->fr_type == FR_T_IPF) &&
1194 			    (fr1->fr_authmask == fr->fr_authmask) &&
1195 			    (fr1->fr_authbits == fr->fr_authbits)) {
1196 				m[FRC_ATH].e++;
1197 				m[FRC_ATH].n++;
1198 			} else
1199 				n &= ~0x10000;
1200 
1201 			if ((n & 0x20000) &&
1202 			    (fr->fr_type == fr1->fr_type) &&
1203 			    (fr->fr_type == FR_T_IPF) &&
1204 			    ((fr1->fr_icmpm & 0xff00) ==
1205 			     (fr->fr_icmpm & 0xff00)) &&
1206 			    ((fr1->fr_icmp & 0xff00) ==
1207 			     (fr->fr_icmp & 0xff00))) {
1208 				m[FRC_ICT].e++;
1209 				m[FRC_ICT].n++;
1210 			} else
1211 				n &= ~0x20000;
1212 
1213 			if ((n & 0x40000) &&
1214 			    (fr->fr_type == fr1->fr_type) &&
1215 			    (fr->fr_type == FR_T_IPF) &&
1216 			    ((fr1->fr_icmpm & 0xff) == (fr->fr_icmpm & 0xff)) &&
1217 			    ((fr1->fr_icmp & 0xff) == (fr->fr_icmp & 0xff))) {
1218 				m[FRC_ICC].e++;
1219 				m[FRC_ICC].n++;
1220 			} else
1221 				n &= ~0x40000;
1222 		}
1223 		/*msort(m);*/
1224 
1225 		if (dir == 0)
1226 			emitGroup(rn, dir, m, fr1, group, count, 0);
1227 		else if (dir == 1)
1228 			emitGroup(rn, dir, m, fr1, group, 0, count);
1229 	}
1230 }
1231 
printhooks(fp,in,out,grp)1232 static void printhooks(fp, in, out, grp)
1233 	FILE *fp;
1234 	int in;
1235 	int out;
1236 	frgroup_t *grp;
1237 {
1238 	frentry_t *fr;
1239 	char *group;
1240 	int dogrp, i;
1241 	char *instr;
1242 
1243 	group = grp->fg_name;
1244 	dogrp = 0;
1245 
1246 	if (in && out) {
1247 		fprintf(stderr,
1248 			"printhooks called with both in and out set\n");
1249 		exit(1);
1250 	}
1251 
1252 	if (in) {
1253 		instr = "in";
1254 	} else if (out) {
1255 		instr = "out";
1256 	} else {
1257 		instr = "???";
1258 	}
1259 	fprintf(fp, "static frentry_t ipfrule_%s_%s;\n", instr, group);
1260 
1261 	fprintf(fp, "\
1262 \n\
1263 int ipfrule_add_%s_%s()\n", instr, group);
1264 	fprintf(fp, "\
1265 {\n\
1266 	int i, j, err = 0, max;\n\
1267 	frentry_t *fp;\n");
1268 
1269 	if (dogrp)
1270 		fprintf(fp, "\
1271 	frgroup_t *fg;\n");
1272 
1273 	fprintf(fp, "\n");
1274 
1275 	for (i = 0, fr = grp->fg_start; fr != NULL; i++, fr = fr->fr_next)
1276 		if (fr->fr_dsize > 0) {
1277 			fprintf(fp, "\
1278 	ipf_rules_%s_%s[%d]->fr_data = &ipf%s_rule_data_%s_%u;\n",
1279 				instr, grp->fg_name, i,
1280 				instr, grp->fg_name, i);
1281 		}
1282 	fprintf(fp, "\
1283 	max = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *);\n\
1284 	for (i = 0; i < max; i++) {\n\
1285 		fp = ipf_rules_%s_%s[i];\n\
1286 		fp->fr_next = NULL;\n", instr, group, instr, group);
1287 
1288 	fprintf(fp, "\
1289 		for (j = i + 1; j < max; j++)\n\
1290 			if (strncmp(fp->fr_names + fp->fr_group,\n\
1291 				    ipf_rules_%s_%s[j]->fr_names +\n\
1292 				    ipf_rules_%s_%s[j]->fr_group,\n\
1293 				    FR_GROUPLEN) == 0) {\n\
1294 				if (ipf_rules_%s_%s[j] != NULL)\n\
1295 					ipf_rules_%s_%s[j]->fr_pnext =\n\
1296 					    &fp->fr_next;\n\
1297 				fp->fr_pnext = &ipf_rules_%s_%s[j];\n\
1298 				fp->fr_next = ipf_rules_%s_%s[j];\n\
1299 				break;\n\
1300 			}\n", instr, group, instr, group, instr, group,
1301 			      instr, group, instr, group, instr, group);
1302 	if (dogrp)
1303 		fprintf(fp, "\
1304 \n\
1305 		if (fp->fr_grhead != -1) {\n\
1306 			fg = fr_addgroup(fp->fr_names + fp->fr_grhead,\n\
1307 					 fp, FR_INQUE, IPL_LOGIPF, 0);\n\
1308 			if (fg != NULL)\n\
1309 				fp->fr_grp = &fg->fg_start;\n\
1310 		}\n");
1311 	fprintf(fp, "\
1312 	}\n\
1313 \n\
1314 	fp = &ipfrule_%s_%s;\n", instr, group);
1315 		fprintf(fp, "\
1316 	bzero((char *)fp, sizeof(*fp));\n\
1317 	fp->fr_type = FR_T_CALLFUNC_BUILTIN;\n\
1318 	fp->fr_flags = FR_%sQUE|FR_NOMATCH;\n\
1319 	fp->fr_data = (void *)ipf_rules_%s_%s[0];\n",
1320 		(in != 0) ? "IN" : "OUT", instr, group);
1321 	fprintf(fp, "\
1322 	fp->fr_dsize = sizeof(ipf_rules_%s_%s[0]);\n",
1323 		instr, group);
1324 
1325 	fprintf(fp, "\
1326 	fp->fr_family = AF_INET;\n\
1327 	fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\
1328 	err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,\n\
1329 			ipfmain.ipf_active, 0);\n",
1330 			instr, group);
1331 	fprintf(fp, "\treturn err;\n}\n");
1332 
1333 	fprintf(fp, "\n\n\
1334 int ipfrule_remove_%s_%s()\n", instr, group);
1335 	fprintf(fp, "\
1336 {\n\
1337 	int err = 0, i;\n\
1338 	frentry_t *fp;\n\
1339 \n\
1340 	/*\n\
1341 	 * Try to remove the %sbound rule.\n", instr);
1342 
1343 	fprintf(fp, "\
1344 	 */\n\
1345 	if (ipfrule_%s_%s.fr_ref > 0) {\n", instr, group);
1346 
1347 	fprintf(fp, "\
1348 		err = EBUSY;\n\
1349 	} else {\n");
1350 
1351 	fprintf(fp, "\
1352 		i = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *) - 1;\n\
1353 		for (; i >= 0; i--) {\n\
1354 			fp = ipf_rules_%s_%s[i];\n\
1355 			if (fp->fr_ref > 1) {\n\
1356 				err = EBUSY;\n\
1357 				break;\n\
1358 			}\n\
1359 		}\n\
1360 	}\n\
1361 	if (err == 0)\n\
1362 		err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,\n\
1363 				(caddr_t)&ipfrule_%s_%s,\n\
1364 				ipfmain.ipf_active, 0);\n",
1365 		instr, group, instr, group, instr, group);
1366 	fprintf(fp, "\
1367 	if (err)\n\
1368 		return err;\n\
1369 \n\n");
1370 
1371 	fprintf(fp, "\treturn err;\n}\n");
1372 }
1373