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