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