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