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