| /* |
| * Copyright (C) 2001-2005 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$"; |
| #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/param.h>\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 (__FreeBSD_version >= 40000)\n"); |
| fprintf(fp, "# if defined(_KERNEL)\n"); |
| fprintf(fp, "# include <sys/libkern.h>\n"); |
| fprintf(fp, "# else\n"); |
| fprintf(fp, "# include <sys/unistd.h>\n"); |
| fprintf(fp, "# endif\n"); |
| fprintf(fp, "#endif\n"); |
| fprintf(fp, "#if (__NetBSD_Version__ >= 399000000)\n"); |
| fprintf(fp, "#else\n"); |
| fprintf(fp, "# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n"); |
| fprintf(fp, "# include <sys/systm.h>\n"); |
| fprintf(fp, "# endif\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 (g != NULL && 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 (g != NULL && num == -2 && dir == 1 && header[0] == 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 (g != NULL && 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 = *group ? 1 : 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"); |
| } |