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
11typedef struct {
12	int c;
13	int e;
14	int n;
15	int p;
16	int s;
17} mc_t;
18
19
20static char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" };
21static int count = 0;
22
23int intcmp(const void *, const void *);
24static void indent(FILE *, int);
25static void printeq(FILE *, char *, int, int, int);
26static void printipeq(FILE *, char *, int, int, int);
27static void addrule(FILE *, frentry_t *);
28static void printhooks(FILE *, int, int, frgroup_t *);
29static void emitheader(frgroup_t *, u_int, u_int);
30static void emitGroup(int, int, void *, frentry_t *, char *,
31			   u_int, u_int);
32static void emittail(void);
33static 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
54static	FILE	*cfile = NULL;
55
56/*
57 * This is called once per filter rule being loaded to emit data structures
58 * required.
59 */
60void
61printc(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
157static frgroup_t *groups = NULL;
158
159
160static void
161addrule(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, "\
203static 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
240int
241intcmp(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
252static void
253indent(FILE *fp, int in)
254{
255	for (; in; in--)
256		fputc('\t', fp);
257}
258
259static void
260printeq(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 */
274static void
275printipeq(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
286void
287emit(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
336static void
337emitheader(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\
355extern frentry_t *ipfrule_match_in_%s(fr_info_t *, u_32_t *));\n\
356extern 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\
366extern int ipfrule_add_in_%s(void));\n\
367extern int ipfrule_remove_in_%s(void));\n", grp->fg_name, grp->fg_name);
368		}
369	}
370	if (outcount) {
371		fprintf(fph, "\n\
372extern frentry_t *ipfrule_match_out_%s(fr_info_t *, u_32_t *));\n\
373extern 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\
383extern int ipfrule_add_out_%s(void));\n\
384extern int ipfrule_remove_out_%s(void));\n",
385				grp->fg_name, grp->fg_name);
386		}
387	}
388}
389
390static void
391emittail(void)
392{
393	frgroup_t *g;
394
395	fprintf(cfile, "\n\
396int 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\
412int 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
428static void
429emitGroup(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		 * 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
943void
944printC(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 */
966static void
967printCgroup(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
1213static void
1214printhooks(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\
1241int 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\
1312int 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