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