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