diff options
author | darrenr <darrenr@FreeBSD.org> | 2005-04-25 17:31:50 +0000 |
---|---|---|
committer | darrenr <darrenr@FreeBSD.org> | 2005-04-25 17:31:50 +0000 |
commit | d438802dcb3e270d6fcc65f075c808c64853a7c2 (patch) | |
tree | e2e1c7115044e6dfc86ff65598566fa32e5f7421 /contrib/ipfilter/tools/ipfcomp.c | |
parent | 590450fec65a8e72a8965117398bc8f14938b4a8 (diff) | |
download | FreeBSD-src-d438802dcb3e270d6fcc65f075c808c64853a7c2.zip FreeBSD-src-d438802dcb3e270d6fcc65f075c808c64853a7c2.tar.gz |
import ipfilter 4.1.8 into the vendor branch
Diffstat (limited to 'contrib/ipfilter/tools/ipfcomp.c')
-rw-r--r-- | contrib/ipfilter/tools/ipfcomp.c | 1347 |
1 files changed, 1347 insertions, 0 deletions
diff --git a/contrib/ipfilter/tools/ipfcomp.c b/contrib/ipfilter/tools/ipfcomp.c new file mode 100644 index 0000000..262e909 --- /dev/null +++ b/contrib/ipfilter/tools/ipfcomp.c @@ -0,0 +1,1347 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipfcomp.c,v 1.24.2.2 2004/04/28 10:34:44 darrenr Exp"; +#endif + +#include "ipf.h" + + +typedef struct { + int c; + int e; + int n; + int p; + int s; +} mc_t; + + +static char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" }; +static int count = 0; + +int intcmp __P((const void *, const void *)); +static void indent __P((FILE *, int)); +static void printeq __P((FILE *, char *, int, int, int)); +static void printipeq __P((FILE *, char *, int, int, int)); +static void addrule __P((FILE *, frentry_t *)); +static void printhooks __P((FILE *, int, int, frgroup_t *)); +static void emitheader __P((frgroup_t *, u_int, u_int)); +static void emitGroup __P((int, int, void *, frentry_t *, char *, + u_int, u_int)); +static void emittail __P((void)); +static void printCgroup __P((int, frentry_t *, mc_t *, char *)); + +#define FRC_IFN 0 +#define FRC_V 1 +#define FRC_P 2 +#define FRC_FL 3 +#define FRC_TOS 4 +#define FRC_TTL 5 +#define FRC_SRC 6 +#define FRC_DST 7 +#define FRC_TCP 8 +#define FRC_SP 9 +#define FRC_DP 10 +#define FRC_OPT 11 +#define FRC_SEC 12 +#define FRC_ATH 13 +#define FRC_ICT 14 +#define FRC_ICC 15 +#define FRC_MAX 16 + + +static FILE *cfile = NULL; + +/* + * This is called once per filter rule being loaded to emit data structures + * required. + */ +void printc(fr) +frentry_t *fr; +{ + fripf_t *ipf; + u_long *ulp; + char *and; + FILE *fp; + int i; + + if (fr->fr_v != 4) + return; + if ((fr->fr_type != FR_T_IPF) && (fr->fr_type != FR_T_NONE)) + return; + if ((fr->fr_type == FR_T_IPF) && + ((fr->fr_datype != FRI_NORMAL) || (fr->fr_satype != FRI_NORMAL))) + return; + ipf = fr->fr_ipf; + + if (cfile == NULL) + cfile = fopen("ip_rules.c", "w"); + if (cfile == NULL) + return; + fp = cfile; + if (count == 0) { + fprintf(fp, "/*\n"); + fprintf(fp, "* Copyright (C) 1993-2000 by Darren Reed.\n"); + fprintf(fp, "*\n"); + fprintf(fp, "* Redistribution and use in source and binary forms are permitted\n"); + fprintf(fp, "* provided that this notice is preserved and due credit is given\n"); + fprintf(fp, "* to the original author and the contributors.\n"); + fprintf(fp, "*/\n\n"); + + fprintf(fp, "#include <sys/types.h>\n"); + fprintf(fp, "#include <sys/time.h>\n"); + fprintf(fp, "#include <sys/socket.h>\n"); + fprintf(fp, "#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n"); + fprintf(fp, "# include <sys/systm.h>\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, "#include <sys/errno.h>\n"); + fprintf(fp, "#include <sys/param.h>\n"); + fprintf(fp, +"#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n"); + fprintf(fp, "# include <sys/mbuf.h>\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, +"#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n"); + fprintf(fp, "# include <sys/sockio.h>\n"); + fprintf(fp, "#else\n"); + fprintf(fp, "# include <sys/ioctl.h>\n"); + fprintf(fp, "#endif /* FreeBSD */\n"); + fprintf(fp, "#include <net/if.h>\n"); + fprintf(fp, "#include <netinet/in.h>\n"); + fprintf(fp, "#include <netinet/in_systm.h>\n"); + fprintf(fp, "#include <netinet/ip.h>\n"); + fprintf(fp, "#include <netinet/tcp.h>\n"); + fprintf(fp, "#include \"netinet/ip_compat.h\"\n"); + fprintf(fp, "#include \"netinet/ip_fil.h\"\n\n"); + fprintf(fp, "#include \"netinet/ip_rules.h\"\n\n"); + fprintf(fp, "#ifndef _KERNEL\n"); + fprintf(fp, "# include <string.h>\n"); + fprintf(fp, "#endif /* _KERNEL */\n"); + fprintf(fp, "\n"); + fprintf(fp, "#ifdef IPFILTER_COMPILED\n"); + } + + addrule(fp, fr); + fr->fr_type |= FR_T_BUILTIN; + and = ""; + fr->fr_ref = 1; + i = sizeof(*fr); + if (i & -(1 - sizeof(*ulp))) + i += sizeof(u_long); + for (i /= sizeof(u_long), ulp = (u_long *)fr; i > 0; i--) { + fprintf(fp, "%s%#lx", and, *ulp++); + and = ", "; + } + fprintf(fp, "\n};\n"); + fr->fr_type &= ~FR_T_BUILTIN; + + count++; + + fflush(fp); +} + + +static frgroup_t *groups = NULL; + + +static void addrule(fp, fr) +FILE *fp; +frentry_t *fr; +{ + frentry_t *f, **fpp; + frgroup_t *g; + u_long *ulp; + char *and; + int i; + + f = (frentry_t *)malloc(sizeof(*f)); + bcopy((char *)fr, (char *)f, sizeof(*fr)); + if (fr->fr_ipf) { + f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf)); + bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf, + sizeof(*fr->fr_ipf)); + } + + f->fr_next = NULL; + for (g = groups; g != NULL; g = g->fg_next) + if ((strncmp(g->fg_name, f->fr_group, FR_GROUPLEN) == 0) && + (g->fg_flags == (f->fr_flags & FR_INOUT))) + break; + + if (g == NULL) { + g = (frgroup_t *)calloc(1, sizeof(*g)); + g->fg_next = groups; + groups = g; + g->fg_head = f; + bcopy(f->fr_group, g->fg_name, FR_GROUPLEN); + g->fg_ref = 0; + g->fg_flags = f->fr_flags & FR_INOUT; + } + + for (fpp = &g->fg_start; *fpp != NULL; ) + fpp = &((*fpp)->fr_next); + *fpp = f; + + if (fr->fr_dsize > 0) { + fprintf(fp, "\ +static u_long ipf%s_rule_data_%s_%u[] = {\n", + f->fr_flags & FR_INQUE ? "in" : "out", + g->fg_name, g->fg_ref); + and = ""; + i = fr->fr_dsize; + ulp = fr->fr_data; + for (i /= sizeof(u_long); i > 0; i--) { + fprintf(fp, "%s%#lx", and, *ulp++); + and = ", "; + } + fprintf(fp, "\n};\n"); + } + + fprintf(fp, "\nstatic u_long %s_rule_%s_%d[] = {\n", + f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref); + + g->fg_ref++; + + if (f->fr_grhead != 0) { + for (g = groups; g != NULL; g = g->fg_next) + if ((strncmp(g->fg_name, f->fr_grhead, + FR_GROUPLEN) == 0) && + g->fg_flags == (f->fr_flags & FR_INOUT)) + break; + if (g == NULL) { + g = (frgroup_t *)calloc(1, sizeof(*g)); + g->fg_next = groups; + groups = g; + g->fg_head = f; + bcopy(f->fr_grhead, g->fg_name, FR_GROUPLEN); + g->fg_ref = 0; + g->fg_flags = f->fr_flags & FR_INOUT; + } + } +} + + +int intcmp(c1, c2) +const void *c1, *c2; +{ + const mc_t *i1 = (const mc_t *)c1, *i2 = (const mc_t *)c2; + + if (i1->n == i2->n) { + return i1->c - i2->c; + } + return i2->n - i1->n; +} + + +static void indent(fp, in) +FILE *fp; +int in; +{ + for (; in; in--) + fputc('\t', fp); +} + +static void printeq(fp, var, m, max, v) +FILE *fp; +char *var; +int m, max, v; +{ + if (m == max) + fprintf(fp, "%s == %#x) {\n", var, v); + else + fprintf(fp, "(%s & %#x) == %#x) {\n", var, m, v); +} + +/* + * Parameters: var - IP# being compared + * fl - 0 for positive match, 1 for negative match + * m - netmask + * v - required address + */ +static void printipeq(fp, var, fl, m, v) +FILE *fp; +char *var; +int fl, m, v; +{ + if (m == 0xffffffff) + fprintf(fp, "%s ", var); + else + fprintf(fp, "(%s & %#x) ", var, m); + fprintf(fp, "%c", fl ? '!' : '='); + fprintf(fp, "= %#x) {\n", v); +} + + +void emit(num, dir, v, fr) +int num, dir; +void *v; +frentry_t *fr; +{ + u_int incnt, outcnt; + frgroup_t *g; + frentry_t *f; + + for (g = groups; g != NULL; g = g->fg_next) { + if (dir == 0 || dir == -1) { + if ((g->fg_flags & FR_INQUE) == 0) + continue; + for (incnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + incnt++; + emitGroup(num, dir, v, fr, g->fg_name, incnt, 0); + } + if (dir == 1 || dir == -1) { + if ((g->fg_flags & FR_OUTQUE) == 0) + continue; + for (outcnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + outcnt++; + emitGroup(num, dir, v, fr, g->fg_name, 0, outcnt); + } + } + + if (num == -1 && dir == -1) { + for (g = groups; g != NULL; g = g->fg_next) { + if ((g->fg_flags & FR_INQUE) != 0) { + for (incnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + incnt++; + if (incnt > 0) + emitheader(g, incnt, 0); + } + if ((g->fg_flags & FR_OUTQUE) != 0) { + for (outcnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + outcnt++; + if (outcnt > 0) + emitheader(g, 0, outcnt); + } + } + emittail(); + fprintf(cfile, "#endif /* IPFILTER_COMPILED */\n"); + } + +} + + +static void emitheader(grp, incount, outcount) +frgroup_t *grp; +u_int incount, outcount; +{ + static FILE *fph = NULL; + frgroup_t *g; + + if (fph == NULL) { + fph = fopen("ip_rules.h", "w"); + if (fph == NULL) + return; + + fprintf(fph, "extern int ipfrule_add __P((void));\n"); + fprintf(fph, "extern int ipfrule_remove __P((void));\n"); + } + + printhooks(cfile, incount, outcount, grp); + + if (incount) { + fprintf(fph, "\n\ +extern frentry_t *ipfrule_match_in_%s __P((fr_info_t *, u_32_t *));\n\ +extern frentry_t *ipf_rules_in_%s[%d];\n", + grp->fg_name, grp->fg_name, incount); + + for (g = groups; g != grp; g = g->fg_next) + if ((strncmp(g->fg_name, grp->fg_name, + FR_GROUPLEN) == 0) && + g->fg_flags == grp->fg_flags) + break; + if (g == grp) { + fprintf(fph, "\n\ +extern int ipfrule_add_in_%s __P((void));\n\ +extern int ipfrule_remove_in_%s __P((void));\n", grp->fg_name, grp->fg_name); + } + } + if (outcount) { + fprintf(fph, "\n\ +extern frentry_t *ipfrule_match_out_%s __P((fr_info_t *, u_32_t *));\n\ +extern frentry_t *ipf_rules_out_%s[%d];\n", + grp->fg_name, grp->fg_name, outcount); + + for (g = groups; g != g; g = g->fg_next) + if ((strncmp(g->fg_name, grp->fg_name, + FR_GROUPLEN) == 0) && + g->fg_flags == grp->fg_flags) + break; + if (g == grp) { + fprintf(fph, "\n\ +extern int ipfrule_add_out_%s __P((void));\n\ +extern int ipfrule_remove_out_%s __P((void));\n", + grp->fg_name, grp->fg_name); + } + } +} + +static void emittail() +{ + frgroup_t *g; + + fprintf(cfile, "\n\ +int ipfrule_add()\n\ +{\n\ + int err;\n\ +\n"); + for (g = groups; g != NULL; g = g->fg_next) + fprintf(cfile, "\ + err = ipfrule_add_%s_%s();\n\ + if (err != 0)\n\ + return err;\n", + (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); + fprintf(cfile, "\ + return 0;\n"); + fprintf(cfile, "}\n\ +\n"); + + fprintf(cfile, "\n\ +int ipfrule_remove()\n\ +{\n\ + int err;\n\ +\n"); + for (g = groups; g != NULL; g = g->fg_next) + fprintf(cfile, "\ + err = ipfrule_remove_%s_%s();\n\ + if (err != 0)\n\ + return err;\n", + (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); + fprintf(cfile, "\ + return 0;\n"); + fprintf(cfile, "}\n"); +} + + +static void emitGroup(num, dir, v, fr, group, incount, outcount) +int num, dir; +void *v; +frentry_t *fr; +char *group; +u_int incount, outcount; +{ + static FILE *fp = NULL; + static int header[2] = { 0, 0 }; + static char egroup[FR_GROUPLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + static int openfunc = 0; + static mc_t *n = NULL; + static int sin = 0; + frentry_t *f; + frgroup_t *g; + fripf_t *ipf; + int i, in, j; + mc_t *m = v; + + if (fp == NULL) + fp = cfile; + if (fp == NULL) + return; + if (strncmp(egroup, group, FR_GROUPLEN)) { + for (sin--; sin > 0; sin--) { + indent(fp, sin); + fprintf(fp, "}\n"); + } + if (openfunc == 1) { + fprintf(fp, "\treturn fr;\n}\n"); + openfunc = 0; + if (n != NULL) { + free(n); + n = NULL; + } + } + sin = 0; + header[0] = 0; + header[1] = 0; + strncpy(egroup, group, FR_GROUPLEN); + } else if (openfunc == 1 && num < 0) { + if (n != NULL) { + free(n); + n = NULL; + } + for (sin--; sin > 0; sin--) { + indent(fp, sin); + fprintf(fp, "}\n"); + } + if (openfunc == 1) { + fprintf(fp, "\treturn fr;\n}\n"); + openfunc = 0; + } + } + + if (dir == -1) + return; + + for (g = groups; g != NULL; g = g->fg_next) { + if (dir == 0 && (g->fg_flags & FR_INQUE) == 0) + continue; + else if (dir == 1 && (g->fg_flags & FR_OUTQUE) == 0) + continue; + if (strncmp(g->fg_name, group, FR_GROUPLEN) != 0) + continue; + break; + } + + /* + * Output the array of pointers to rules for this group. + */ + if (num == -2 && dir == 0 && header[0] == 0 && incount != 0) { + fprintf(fp, "\nfrentry_t *ipf_rules_in_%s[%d] = {", + group, incount); + for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { + if ((f->fr_flags & FR_INQUE) == 0) + continue; + if ((i & 1) == 0) { + fprintf(fp, "\n\t"); + } + fprintf(fp, + "(frentry_t *)&in_rule_%s_%d", + f->fr_group, i); + if (i + 1 < incount) + fprintf(fp, ", "); + i++; + } + fprintf(fp, "\n};\n"); + } + + if (num == -2 && dir == 1 && header[1] == 0 && outcount != 0) { + fprintf(fp, "\nfrentry_t *ipf_rules_out_%s[%d] = {", + group, outcount); + for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { + if ((f->fr_flags & FR_OUTQUE) == 0) + continue; + if ((i & 1) == 0) { + fprintf(fp, "\n\t"); + } + fprintf(fp, + "(frentry_t *)&out_rule_%s_%d", + f->fr_group, i); + if (i + 1 < outcount) + fprintf(fp, ", "); + i++; + } + fprintf(fp, "\n};\n"); + fp = NULL; + } + + if (num < 0) + return; + + in = 0; + ipf = fr->fr_ipf; + + /* + * If the function header has not been printed then print it now. + */ + if (header[dir] == 0) { + int pdst = 0, psrc = 0; + + openfunc = 1; + fprintf(fp, "\nfrentry_t *ipfrule_match_%s_%s(fin, passp)\n", + (dir == 0) ? "in" : "out", group); + fprintf(fp, "fr_info_t *fin;\n"); + fprintf(fp, "u_32_t *passp;\n"); + fprintf(fp, "{\n"); + fprintf(fp, "\tfrentry_t *fr = NULL;\n"); + + /* + * Print out any variables that need to be declared. + */ + for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { + if (incount + outcount > m[FRC_SRC].e + 1) + psrc = 1; + if (incount + outcount > m[FRC_DST].e + 1) + pdst = 1; + } + if (psrc == 1) + fprintf(fp, "\tu_32_t src = ntohl(%s);\n", + "fin->fin_fi.fi_saddr"); + if (pdst == 1) + fprintf(fp, "\tu_32_t dst = ntohl(%s);\n", + "fin->fin_fi.fi_daddr"); + } + + for (i = 0; i < FRC_MAX; i++) { + switch(m[i].c) + { + case FRC_IFN : + if (*fr->fr_ifname) + m[i].s = 1; + break; + case FRC_V : + if (ipf != NULL && ipf->fri_mip.fi_v != 0) + m[i].s = 1; + break; + case FRC_FL : + if (ipf != NULL && ipf->fri_mip.fi_flx != 0) + m[i].s = 1; + break; + case FRC_P : + if (ipf != NULL && ipf->fri_mip.fi_p != 0) + m[i].s = 1; + break; + case FRC_TTL : + if (ipf != NULL && ipf->fri_mip.fi_ttl != 0) + m[i].s = 1; + break; + case FRC_TOS : + if (ipf != NULL && ipf->fri_mip.fi_tos != 0) + m[i].s = 1; + break; + case FRC_TCP : + if (ipf == NULL) + break; + if ((ipf->fri_ip.fi_p == IPPROTO_TCP) && + fr->fr_tcpfm != 0) + m[i].s = 1; + break; + case FRC_SP : + if (ipf == NULL) + break; + if (fr->fr_scmp == FR_INRANGE) + m[i].s = 1; + else if (fr->fr_scmp == FR_OUTRANGE) + m[i].s = 1; + else if (fr->fr_scmp != 0) + m[i].s = 1; + break; + case FRC_DP : + if (ipf == NULL) + break; + if (fr->fr_dcmp == FR_INRANGE) + m[i].s = 1; + else if (fr->fr_dcmp == FR_OUTRANGE) + m[i].s = 1; + else if (fr->fr_dcmp != 0) + m[i].s = 1; + break; + case FRC_SRC : + if (ipf == NULL) + break; + if (fr->fr_satype == FRI_LOOKUP) { + ; + } else if ((fr->fr_smask != 0) || + (fr->fr_flags & FR_NOTSRCIP) != 0) + m[i].s = 1; + break; + case FRC_DST : + if (ipf == NULL) + break; + if (fr->fr_datype == FRI_LOOKUP) { + ; + } else if ((fr->fr_dmask != 0) || + (fr->fr_flags & FR_NOTDSTIP) != 0) + m[i].s = 1; + break; + case FRC_OPT : + if (ipf == NULL) + break; + if (fr->fr_optmask != 0) + m[i].s = 1; + break; + case FRC_SEC : + if (ipf == NULL) + break; + if (fr->fr_secmask != 0) + m[i].s = 1; + break; + case FRC_ATH : + if (ipf == NULL) + break; + if (fr->fr_authmask != 0) + m[i].s = 1; + break; + case FRC_ICT : + if (ipf == NULL) + break; + if ((fr->fr_icmpm & 0xff00) != 0) + m[i].s = 1; + break; + case FRC_ICC : + if (ipf == NULL) + break; + if ((fr->fr_icmpm & 0xff) != 0) + m[i].s = 1; + break; + } + } + + if (!header[dir]) { + fprintf(fp, "\n"); + header[dir] = 1; + sin = 0; + } + + qsort(m, FRC_MAX, sizeof(mc_t), intcmp); + + if (n) { + /* + * Calculate the indentation interval upto the last common + * common comparison being made. + */ + for (i = 0, in = 1; i < FRC_MAX; i++) { + if (n[i].c != m[i].c) + break; + if (n[i].s != m[i].s) + break; + if (n[i].s) { + if (n[i].n && (n[i].n > n[i].e)) { + m[i].p++; + in += m[i].p; + break; + } + if (n[i].e > 0) { + in++; + } else + break; + } + } + if (sin != in) { + for (j = sin - 1; j >= in; j--) { + indent(fp, j); + fprintf(fp, "}\n"); + } + } + } else { + in = 1; + i = 0; + } + + /* + * print out C code that implements a filter rule. + */ + for (; i < FRC_MAX; i++) { + switch(m[i].c) + { + case FRC_IFN : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_ifp == "); + fprintf(fp, "ipf_rules_%s_%s[%d]->fr_ifa) {\n", + dir ? "out" : "in", group, num); + in++; + } + break; + case FRC_V : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_v == %d) {\n", + ipf->fri_ip.fi_v); + in++; + } + break; + case FRC_FL : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_flx", + ipf->fri_mip.fi_flx, 0xf, + ipf->fri_ip.fi_flx); + in++; + } + break; + case FRC_P : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_p == %d) {\n", + ipf->fri_ip.fi_p); + in++; + } + break; + case FRC_TTL : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_ttl", + ipf->fri_mip.fi_ttl, 0xff, + ipf->fri_ip.fi_ttl); + in++; + } + break; + case FRC_TOS : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_tos"); + printeq(fp, "fin->fin_tos", + ipf->fri_mip.fi_tos, 0xff, + ipf->fri_ip.fi_tos); + in++; + } + break; + case FRC_TCP : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_tcpf", fr->fr_tcpfm, + 0xff, fr->fr_tcpf); + in++; + } + break; + case FRC_SP : + if (!m[i].s) + break; + if (fr->fr_scmp == FR_INRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[0] > %d) && ", + fr->fr_sport); + fprintf(fp, "(fin->fin_data[0] < %d)", + fr->fr_stop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_scmp == FR_OUTRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[0] < %d) || ", + fr->fr_sport); + fprintf(fp, "(fin->fin_data[0] > %d)", + fr->fr_stop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_scmp) { + indent(fp, in); + fprintf(fp, "if (fin->fin_data[0] %s %d)", + portcmp[fr->fr_scmp], fr->fr_sport); + fprintf(fp, " {\n"); + in++; + } + break; + case FRC_DP : + if (!m[i].s) + break; + if (fr->fr_dcmp == FR_INRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[1] > %d) && ", + fr->fr_dport); + fprintf(fp, "(fin->fin_data[1] < %d)", + fr->fr_dtop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_dcmp == FR_OUTRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[1] < %d) || ", + fr->fr_dport); + fprintf(fp, "(fin->fin_data[1] > %d)", + fr->fr_dtop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_dcmp) { + indent(fp, in); + fprintf(fp, "if (fin->fin_data[1] %s %d)", + portcmp[fr->fr_dcmp], fr->fr_dport); + fprintf(fp, " {\n"); + in++; + } + break; + case FRC_SRC : + if (!m[i].s) + break; + if (fr->fr_satype == FRI_LOOKUP) { + ; + } else if ((fr->fr_smask != 0) || + (fr->fr_flags & FR_NOTSRCIP) != 0) { + indent(fp, in); + fprintf(fp, "if ("); + printipeq(fp, "src", + fr->fr_flags & FR_NOTSRCIP, + fr->fr_smask, fr->fr_saddr); + in++; + } + break; + case FRC_DST : + if (!m[i].s) + break; + if (fr->fr_datype == FRI_LOOKUP) { + ; + } else if ((fr->fr_dmask != 0) || + (fr->fr_flags & FR_NOTDSTIP) != 0) { + indent(fp, in); + fprintf(fp, "if ("); + printipeq(fp, "dst", + fr->fr_flags & FR_NOTDSTIP, + fr->fr_dmask, fr->fr_daddr); + in++; + } + break; + case FRC_OPT : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_fi.fi_optmsk", + fr->fr_optmask, 0xffffffff, + fr->fr_optbits); + in++; + } + break; + case FRC_SEC : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_fi.fi_secmsk", + fr->fr_secmask, 0xffff, + fr->fr_secbits); + in++; + } + break; + case FRC_ATH : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_fi.fi_authmsk", + fr->fr_authmask, 0xffff, + fr->fr_authbits); + in++; + } + break; + case FRC_ICT : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_data[0]", + fr->fr_icmpm & 0xff00, 0xffff, + fr->fr_icmp & 0xff00); + in++; + } + break; + case FRC_ICC : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_data[0]", + fr->fr_icmpm & 0xff, 0xffff, + fr->fr_icmp & 0xff); + in++; + } + break; + } + + } + + indent(fp, in); + if (fr->fr_flags & FR_QUICK) { + fprintf(fp, "return (frentry_t *)&%s_rule_%s_%d;\n", + fr->fr_flags & FR_INQUE ? "in" : "out", + fr->fr_group, num); + } else { + fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n", + fr->fr_flags & FR_INQUE ? "in" : "out", + fr->fr_group, num); + } + if (n == NULL) + n = (mc_t *)malloc(sizeof(*n) * FRC_MAX); + bcopy((char *)m, (char *)n, sizeof(*n) * FRC_MAX); + sin = in; +} + + +void printC(dir) +int dir; +{ + static mc_t *m = NULL; + frgroup_t *g; + + if (m == NULL) + m = (mc_t *)calloc(1, sizeof(*m) * FRC_MAX); + + for (g = groups; g != NULL; g = g->fg_next) { + if ((dir == 0) && ((g->fg_flags & FR_INQUE) != 0)) + printCgroup(dir, g->fg_start, m, g->fg_name); + if ((dir == 1) && ((g->fg_flags & FR_OUTQUE) != 0)) + printCgroup(dir, g->fg_start, m, g->fg_name); + } + + emit(-1, dir, m, NULL); +} + + +/* + * Now print out code to implement all of the rules. + */ +static void printCgroup(dir, top, m, group) +int dir; +frentry_t *top; +mc_t *m; +char *group; +{ + frentry_t *fr, *fr1; + int i, n, rn; + u_int count; + + for (count = 0, fr1 = top; fr1 != NULL; fr1 = fr1->fr_next) { + if ((dir == 0) && ((fr1->fr_flags & FR_INQUE) != 0)) + count++; + else if ((dir == 1) && ((fr1->fr_flags & FR_OUTQUE) != 0)) + count++; + } + + if (dir == 0) + emitGroup(-2, dir, m, fr1, group, count, 0); + else if (dir == 1) + emitGroup(-2, dir, m, fr1, group, 0, count); + + /* + * Before printing each rule, check to see how many of its fields are + * matched by subsequent rules. + */ + for (fr1 = top, rn = 0; fr1 != NULL; fr1 = fr1->fr_next, rn++) { + if (!dir && !(fr1->fr_flags & FR_INQUE)) + continue; + if (dir && !(fr1->fr_flags & FR_OUTQUE)) + continue; + n = 0xfffffff; + + for (i = 0; i < FRC_MAX; i++) + m[i].e = 0; + qsort(m, FRC_MAX, sizeof(mc_t), intcmp); + + for (i = 0; i < FRC_MAX; i++) { + m[i].c = i; + m[i].e = 0; + m[i].n = 0; + m[i].s = 0; + } + + for (fr = fr1->fr_next; fr; fr = fr->fr_next) { + if (!dir && !(fr->fr_flags & FR_INQUE)) + continue; + if (dir && !(fr->fr_flags & FR_OUTQUE)) + continue; + + if ((n & 0x0001) && + !strcmp(fr1->fr_ifname, fr->fr_ifname)) { + m[FRC_IFN].e++; + m[FRC_IFN].n++; + } else + n &= ~0x0001; + + if ((n & 0x0002) && (fr1->fr_v == fr->fr_v)) { + m[FRC_V].e++; + m[FRC_V].n++; + } else + n &= ~0x0002; + + if ((n & 0x0004) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_mip.fi_flx == fr->fr_mip.fi_flx) && + (fr1->fr_ip.fi_flx == fr->fr_ip.fi_flx)) { + m[FRC_FL].e++; + m[FRC_FL].n++; + } else + n &= ~0x0004; + + if ((n & 0x0008) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_proto == fr->fr_proto)) { + m[FRC_P].e++; + m[FRC_P].n++; + } else + n &= ~0x0008; + + if ((n & 0x0010) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_ttl == fr->fr_ttl)) { + m[FRC_TTL].e++; + m[FRC_TTL].n++; + } else + n &= ~0x0010; + + if ((n & 0x0020) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_tos == fr->fr_tos)) { + m[FRC_TOS].e++; + m[FRC_TOS].n++; + } else + n &= ~0x0020; + + if ((n & 0x0040) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_tcpfm == fr->fr_tcpfm) && + (fr1->fr_tcpf == fr->fr_tcpf))) { + m[FRC_TCP].e++; + m[FRC_TCP].n++; + } else + n &= ~0x0040; + + if ((n & 0x0080) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_scmp == fr->fr_scmp) && + (fr1->fr_stop == fr->fr_stop) && + (fr1->fr_sport == fr->fr_sport))) { + m[FRC_SP].e++; + m[FRC_SP].n++; + } else + n &= ~0x0080; + + if ((n & 0x0100) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_dcmp == fr->fr_dcmp) && + (fr1->fr_dtop == fr->fr_dtop) && + (fr1->fr_dport == fr->fr_dport))) { + m[FRC_DP].e++; + m[FRC_DP].n++; + } else + n &= ~0x0100; + + if ((n & 0x0200) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_satype == FRI_LOOKUP) && + (fr->fr_satype == FRI_LOOKUP) && + (fr1->fr_srcnum == fr->fr_srcnum))) { + m[FRC_SRC].e++; + m[FRC_SRC].n++; + } else if ((n & 0x0200) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (((fr1->fr_flags & FR_NOTSRCIP) == + (fr->fr_flags & FR_NOTSRCIP)))) { + if ((fr1->fr_smask == fr->fr_smask) && + (fr1->fr_saddr == fr->fr_saddr)) + m[FRC_SRC].e++; + else + n &= ~0x0200; + if (fr1->fr_smask && + (fr1->fr_saddr & fr1->fr_smask) == + (fr->fr_saddr & fr1->fr_smask)) { + m[FRC_SRC].n++; + n |= 0x0200; + } + } else { + n &= ~0x0200; + } + + if ((n & 0x0400) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_datype == FRI_LOOKUP) && + (fr->fr_datype == FRI_LOOKUP) && + (fr1->fr_dstnum == fr->fr_dstnum))) { + m[FRC_DST].e++; + m[FRC_DST].n++; + } else if ((n & 0x0400) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (((fr1->fr_flags & FR_NOTDSTIP) == + (fr->fr_flags & FR_NOTDSTIP)))) { + if ((fr1->fr_dmask == fr->fr_dmask) && + (fr1->fr_daddr == fr->fr_daddr)) + m[FRC_DST].e++; + else + n &= ~0x0400; + if (fr1->fr_dmask && + (fr1->fr_daddr & fr1->fr_dmask) == + (fr->fr_daddr & fr1->fr_dmask)) { + m[FRC_DST].n++; + n |= 0x0400; + } + } else { + n &= ~0x0400; + } + + if ((n & 0x0800) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_optmask == fr->fr_optmask) && + (fr1->fr_optbits == fr->fr_optbits)) { + m[FRC_OPT].e++; + m[FRC_OPT].n++; + } else + n &= ~0x0800; + + if ((n & 0x1000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_secmask == fr->fr_secmask) && + (fr1->fr_secbits == fr->fr_secbits)) { + m[FRC_SEC].e++; + m[FRC_SEC].n++; + } else + n &= ~0x1000; + + if ((n & 0x10000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_authmask == fr->fr_authmask) && + (fr1->fr_authbits == fr->fr_authbits)) { + m[FRC_ATH].e++; + m[FRC_ATH].n++; + } else + n &= ~0x10000; + + if ((n & 0x20000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_icmpm & 0xff00) == + (fr->fr_icmpm & 0xff00)) && + ((fr1->fr_icmp & 0xff00) == + (fr->fr_icmp & 0xff00))) { + m[FRC_ICT].e++; + m[FRC_ICT].n++; + } else + n &= ~0x20000; + + if ((n & 0x40000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_icmpm & 0xff) == (fr->fr_icmpm & 0xff)) && + ((fr1->fr_icmp & 0xff) == (fr->fr_icmp & 0xff))) { + m[FRC_ICC].e++; + m[FRC_ICC].n++; + } else + n &= ~0x40000; + } + /*msort(m);*/ + + if (dir == 0) + emitGroup(rn, dir, m, fr1, group, count, 0); + else if (dir == 1) + emitGroup(rn, dir, m, fr1, group, 0, count); + } +} + +static void printhooks(fp, in, out, grp) +FILE *fp; +int in; +int out; +frgroup_t *grp; +{ + frentry_t *fr; + char *group; + int dogrp, i; + char *instr; + + group = grp->fg_name; + dogrp = 0; + + if (in && out) { + fprintf(stderr, + "printhooks called with both in and out set\n"); + exit(1); + } + + if (in) { + instr = "in"; + } else if (out) { + instr = "out"; + } else { + instr = "???"; + } + fprintf(fp, "static frentry_t ipfrule_%s_%s;\n", instr, group); + + fprintf(fp, "\ +\n\ +int ipfrule_add_%s_%s()\n", instr, group); + fprintf(fp, "\ +{\n\ + int i, j, err = 0, max;\n\ + frentry_t *fp;\n"); + + if (dogrp) + fprintf(fp, "\ + frgroup_t *fg;\n"); + + fprintf(fp, "\n"); + + for (i = 0, fr = grp->fg_start; fr != NULL; i++, fr = fr->fr_next) + if (fr->fr_dsize > 0) { + fprintf(fp, "\ + ipf_rules_%s_%s[%d]->fr_data = &ipf%s_rule_data_%s_%u;\n", + instr, grp->fg_name, i, + instr, grp->fg_name, i); + } + fprintf(fp, "\ + max = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *);\n\ + for (i = 0; i < max; i++) {\n\ + fp = ipf_rules_%s_%s[i];\n\ + fp->fr_next = NULL;\n", instr, group, instr, group); + + fprintf(fp, "\ + for (j = i + 1; j < max; j++)\n\ + if (strncmp(fp->fr_group,\n\ + ipf_rules_%s_%s[j]->fr_group,\n\ + FR_GROUPLEN) == 0) {\n\ + fp->fr_next = ipf_rules_%s_%s[j];\n\ + break;\n\ + }\n", instr, group, instr, group); + if (dogrp) + fprintf(fp, "\ +\n\ + if (fp->fr_grhead != 0) {\n\ + fg = fr_addgroup(fp->fr_grhead, fp, FR_INQUE,\n\ + IPL_LOGIPF, 0);\n\ + if (fg != NULL)\n\ + fp->fr_grp = &fg->fg_start;\n\ + }\n"); + fprintf(fp, "\ + }\n\ +\n\ + fp = &ipfrule_%s_%s;\n", instr, group); + fprintf(fp, "\ + bzero((char *)fp, sizeof(*fp));\n\ + fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;\n\ + fp->fr_flags = FR_%sQUE|FR_NOMATCH;\n\ + fp->fr_data = (void *)ipf_rules_%s_%s[0];\n", + (in != 0) ? "IN" : "OUT", instr, group); + fprintf(fp, "\ + fp->fr_dsize = sizeof(ipf_rules_%s_%s[0]);\n", + instr, group); + + fprintf(fp, "\ + fp->fr_v = 4;\n\ + fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\ + err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);\n", + instr, group); + fprintf(fp, "\treturn err;\n}\n"); + + fprintf(fp, "\n\n\ +int ipfrule_remove_%s_%s()\n", instr, group); + fprintf(fp, "\ +{\n\ + int err = 0, i;\n\ + frentry_t *fp;\n\ +\n\ + /*\n\ + * Try to remove the %sbound rule.\n", instr); + + fprintf(fp, "\ + */\n\ + if (ipfrule_%s_%s.fr_ref > 0) {\n", instr, group); + + fprintf(fp, "\ + err = EBUSY;\n\ + } else {\n"); + + fprintf(fp, "\ + i = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *) - 1;\n\ + for (; i >= 0; i--) {\n\ + fp = ipf_rules_%s_%s[i];\n\ + if (fp->fr_ref > 1) {\n\ + err = EBUSY;\n\ + break;\n\ + }\n\ + }\n\ + }\n\ + if (err == 0)\n\ + err = frrequest(IPL_LOGIPF, SIOCDELFR,\n\ + (caddr_t)&ipfrule_%s_%s, fr_active, 0);\n", + instr, group, instr, group, instr, group); + fprintf(fp, "\ + if (err)\n\ + return err;\n\ +\n\n"); + + fprintf(fp, "\treturn err;\n}\n"); +} |