diff --git a/HISTORY b/HISTORY index 1e38f231..536397f4 100644 --- a/HISTORY +++ b/HISTORY @@ -1,3 +1,9 @@ +0.12.8: + Fix some easy to cause crashes. + Remove some obsolete code that caused long compilation times. + Prevents inclusion of the root filesystem path directly. + Test that the example programs compile. + 0.12.7: Supports iptables-restore output format. Supports IPv6 names. diff --git a/Makefile.am b/Makefile.am index e51d50cf..ca762eef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,7 @@ filtergen_SOURCES = \ resolver.c \ icmpent.c -filtergen_LDADD = @GETOPT_LIBS@ +filtergen_LDADD = @GETOPT_LIBS@ @LIBPROFILER@ headers = filter.h util.h ast.h resolver.h icmpent.h diff --git a/configure.ac b/configure.ac index 6c67b599..8ab7d558 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ(2.50) -AC_INIT(filtergen, 0.12.7, jaq@spacepants.org) +AC_INIT(filtergen, 0.12.8, jaq@spacepants.org) AC_CONFIG_AUX_DIR(.) AC_CONFIG_SRCDIR(filtergen.c) @@ -43,6 +43,22 @@ if test "x$HAVE_GETOPT" = xyes ; then AC_SUBST(GETOPT_LIBS) fi +# Google profiler +AC_MSG_CHECKING([whether to enable profiler]) +AC_ARG_WITH([profiler], + [AS_HELP_STRING([--with-profiler],[enable support for profiler [default=no]])], + [with_profiler=$withval], + [with_profiler=no] +) +AC_MSG_RESULT([$with_profiler]) + +if test "x${with_profiler}" = "xyes"; then + AC_CHECK_LIB([profiler], [ProfilerStart], + [AC_SUBST([LIBPROFILER], ["-lprofiler"])], + [AC_MSG_FAILURE([check for profiler failed. Have you installed google-perftools-devel?])], + ) +fi + dnl ----------------- dnl set warning level dnl ----------------- diff --git a/examples/icmp.filter b/examples/icmp similarity index 100% rename from examples/icmp.filter rename to examples/icmp diff --git a/fg-cisco.c b/fg-cisco.c index b1877772..258b071d 100644 --- a/fg-cisco.c +++ b/fg-cisco.c @@ -71,8 +71,8 @@ static int cb_cisco_rule(const struct filterent *ent, APP(rule_r, "IN"); break; default: - fprintf(stderr, "unknown direction\n"); - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } /* target */ @@ -91,7 +91,8 @@ static int cb_cisco_rule(const struct filterent *ent, APPS(rule_r, "deny"); break; default: - abort(); + fprintf(stderr, "invalid target: %d\n", ent->target); + return -1; } /* protocol */ @@ -147,6 +148,5 @@ int fg_cisco(struct filter *filter, int flags) { "can generate broken rulesets."); filter_nogroup(filter); filter_unroll(&filter); - filter_apply_flags(filter, flags); return filtergen_cprod(filter, &cb_cisco, &misc); } diff --git a/fg-ipchains.c b/fg-ipchains.c index 277fb6c2..3ef26709 100644 --- a/fg-ipchains.c +++ b/fg-ipchains.c @@ -103,8 +103,8 @@ static int cb_ipchains_rule(const struct filterent *ent, forrevchain = strdup("forward"); break; default: - fprintf(stderr, "unknown direction\n"); - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } if (ent->iface && strcmp(ent->iface, "*")) { @@ -187,7 +187,8 @@ static int cb_ipchains_rule(const struct filterent *ent, forrevtarget = strdup("forw_out"); break; default: - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } break; case DROP: @@ -221,11 +222,13 @@ static int cb_ipchains_rule(const struct filterent *ent, forrevtarget = strdup("forward"); break; default: - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } break; default: - abort(); + fprintf(stderr, "invalid target: %d\n", ent->target); + return -1; } if (ent->oneway) @@ -266,7 +269,6 @@ int fg_ipchains(struct filter *filter, int flags) { }; filter_unroll(&filter); - filter_apply_flags(filter, flags); if (!(flags & FF_NOSKEL)) { oputs("for f in INPUT OUTPUT FORWARD; do " IPCHAINS " -P $f DENY; done"); oputs(IPCHAINS " -F; " IPCHAINS " -X"); @@ -300,8 +302,8 @@ int flush_ipchains(enum filtertype policy) { ostr = strdup("REJECT"); break; default: - fprintf(stderr, "invalid filtertype %d\n", policy); - abort(); + fprintf(stderr, "invalid filtertype: %d\n", policy); + return -1; } oprintf("for f in $CHAINS; do " IPCHAINS " -P $f %s; done\n", ostr); oputs(IPCHAINS " -F; " IPCHAINS " -X"); diff --git a/fg-ipfilter.c b/fg-ipfilter.c index f4f13cc8..0911b328 100644 --- a/fg-ipfilter.c +++ b/fg-ipfilter.c @@ -80,7 +80,8 @@ static int cb_ipfilter_rule(const struct filterent *ent, APP(rule, "block return-icmp-as-dest(port-unr)"); break; default: - abort(); + fprintf(stderr, "invalid target: %d\n", ent->target); + return -1; } /* in or out? */ @@ -92,8 +93,8 @@ static int cb_ipfilter_rule(const struct filterent *ent, APPS(rule, "out"); break; default: - fprintf(stderr, "unknown direction\n"); - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } if (ESET(ent, LOG)) @@ -136,6 +137,5 @@ int fg_ipfilter(struct filter *filter, int flags) { filter_nogroup(filter); filter_unroll(&filter); - filter_apply_flags(filter, flags); return filtergen_cprod(filter, &cb_ipfilter, &misc); } diff --git a/fg-iptables.c b/fg-iptables.c index 7049a758..00b5d7c0 100644 --- a/fg-iptables.c +++ b/fg-iptables.c @@ -157,8 +157,8 @@ static int cb_iptables_rule_common(const struct filterent *ent, } break; default: - fprintf(stderr, "unknown direction: %d\n", ent->direction); - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } /* state and reverse rules here */ @@ -280,7 +280,8 @@ static int cb_iptables_rule_common(const struct filterent *ent, nattarget = strdup("REDIRECT"); break; default: - abort(); + fprintf(stderr, "invalid target: %d\n", target); + return -1; } } @@ -297,7 +298,8 @@ static int cb_iptables_rule_common(const struct filterent *ent, forrevtarget = strdup("FORW_OUT"); break; default: - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } break; case DROP: @@ -324,11 +326,13 @@ static int cb_iptables_rule_common(const struct filterent *ent, forrevtarget = strdup("FORWARD"); break; default: - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } break; default: - abort(); + fprintf(stderr, "invalid target: %d\n", target); + return -1; } if ((misc->flags & FF_LSTATE) && (target != T_REJECT)) @@ -397,7 +401,6 @@ static int fg_iptables_common(struct filter *filter, int flags, const int nchains = 3; filter_unroll(&filter); - filter_apply_flags(filter, flags); if (!(flags & FF_NOSKEL)) { oputs("CHAINS=\"INPUT OUTPUT FORWARD\""); @@ -481,7 +484,7 @@ static int flush_iptables_common(enum filtertype policy, sa_family_t family, break; default: fprintf(stderr, "invalid filtertype %d\n", policy); - abort(); + return -1; } oprintf("for f in $CHAINS; do %s -P $f %s; done\n", iptables, ostr); oprintf("%s -F; %s -X\n", iptables, iptables); diff --git a/fg-iptrestore.c b/fg-iptrestore.c index 8da07e32..6e094e9a 100644 --- a/fg-iptrestore.c +++ b/fg-iptrestore.c @@ -154,8 +154,8 @@ static int cb_iptrestore_rule_common(const struct filterent *ent, } break; default: - fprintf(stderr, "unknown direction\n"); - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } /* state and reverse rules here */ @@ -276,7 +276,8 @@ static int cb_iptrestore_rule_common(const struct filterent *ent, nattarget = strdup("REDIRECT"); break; default: - abort(); + fprintf(stderr, "invalid target: %d\n", target); + return -1; } } @@ -293,7 +294,8 @@ static int cb_iptrestore_rule_common(const struct filterent *ent, forrevtarget = strdup("FORW_OUT"); break; default: - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } break; case DROP: @@ -320,11 +322,13 @@ static int cb_iptrestore_rule_common(const struct filterent *ent, forrevtarget = strdup("FORWARD"); break; default: - abort(); + fprintf(stderr, "invalid direction: %d\n", ent->direction); + return -1; } break; default: - abort(); + fprintf(stderr, "invalid target: %d\n", target); + return -1; } if ((misc->flags & FF_LSTATE) && (target != T_REJECT)) @@ -403,7 +407,6 @@ static int fg_iptrestore_common(struct filter *filter, int flags, const int nchains = 3; filter_unroll(&filter); - filter_apply_flags(filter, flags); if (!(flags & FF_NOSKEL)) { oprintf("%s <type) { - /* Structural things */ - case F_SIBLIST: - for (s = f->u.sib; s; s = s->next) - filter_apply_flags(s, flags); - break; - case F_SUBGROUP: - filter_apply_flags(f->u.sub.list, flags); - break; - case F_NEG: - filter_apply_flags(f->u.neg, flags); - break; - /* Real things */ - case F_SPORT: - case F_DPORT: - if (flags & FF_LOOKUP) { - struct port_spec *p = &f->u.ports; - if (p->min == -1) { - fprintf(stderr, "warning: couldn't lookup service \"%s\"\n", p->minstr); - break; - } - free(p->minstr); - p->minstr = int_to_str_dup(p->min); - if (p->maxstr) { - if (p->max == -1) { - fprintf(stderr, "warning: couldn't lookup service \"%s\"\n", - p->minstr); - break; - } - free(p->maxstr); - p->maxstr = int_to_str_dup(p->max); - } - } - break; - case F_SOURCE: - case F_DEST: - if (flags & FF_LOOKUP) { - struct addr_spec *a = &f->u.addrs; - struct addrinfo hints; - struct addrinfo *info = NULL; - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = a->family; - if (getaddrinfo(a->addrstr, NULL, &hints, &info) == 0) { - free(a->addrstr); - a->addrstr = malloc(NI_MAXHOST + 1); - if (getnameinfo(info->ai_addr, info->ai_addrlen, a->addrstr, NI_MAXHOST, - NULL, 0, NI_NUMERICHOST)) { - fprintf(stderr, "warning: can't stringify IP: %s\n", strerror(errno)); - } - freeaddrinfo(info); - } else { - fprintf(stderr, "warning: can't lookup name \"%s\"\n", a->addrstr); - } - } - break; - default: - break; - } - filter_apply_flags(f->child, flags); - filter_apply_flags(f->next, flags); -} diff --git a/filter.h b/filter.h index 96965b92..104694a7 100644 --- a/filter.h +++ b/filter.h @@ -145,7 +145,6 @@ struct filter *new_filter_oneway(void); void filter_unroll(struct filter **f); void filter_nogroup(struct filter *f); void filter_noneg(struct filter **f); -void filter_apply_flags(struct filter *f, long flags); /* from generated lexer and parer in filterlex.l */ int filter_fopen(const char *filename); @@ -215,10 +214,8 @@ enum flags { FF_LSTATE = (1 << 1), /* lightweight state matching */ FF_LOCAL = (1 << 2), /* assume packets are local only */ FF_ROUTE = (1 << 3), /* assume packets are forwarded */ - FF_LOOKUP = (1 << 4), /* translate host and service names into IP addresses - and port numbers */ + FF_NORESOLVE = (1 << 4), /* don't resolve hostnames, ports, or services */ FF_FLUSH = (1 << 5), /* just flush the ruleset instead */ - FF_NORESOLVE = (1 << 6), /* don't resolve hostnames, ports, or services */ }; /* filtergen.c */ diff --git a/filtergen.c b/filtergen.c index 3a253363..8018972f 100644 --- a/filtergen.c +++ b/filtergen.c @@ -234,6 +234,7 @@ int main(int argc, char **argv) { for (ft = filter_types; ft->name; ft++) if (!strcmp(ftn, ft->name)) break; + free(ftn); if (!ft->name) { fprintf(stderr, "%s: target filter unrecognised: %s\n", progname, ftn); usage(progname); @@ -293,6 +294,9 @@ int main(int argc, char **argv) { unlink(ofn); return 1; } + if (ofn) { + free(ofn); + } fprintf(stderr, "generated %d rules\n", l); return 0; } diff --git a/gen.c b/gen.c index 65c80691..3897b99d 100644 --- a/gen.c +++ b/gen.c @@ -117,7 +117,7 @@ int __fg_applyone(struct filterent *e, const struct filter *f, fg_callback *cb, fprintf( stderr, "backend doesn't support grouping, but hasn't removed groups\n"); - abort(); + return -1; } e->target = f->type; e->subgroup = f->u.sub.name; @@ -167,7 +167,8 @@ int __fg_applyone(struct filterent *e, const struct filter *f, fg_callback *cb, return __fg_applylist(e, f->u.sib, cb, misc); default: - abort(); + fprintf(stderr, "invalid filter type %d\n", f->type); + return -1; } if (f->negate) diff --git a/glue.c b/glue.c index abe120a9..1b0c85ac 100644 --- a/glue.c +++ b/glue.c @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include "filter.h" #include "ast.h" @@ -75,18 +76,23 @@ struct filter *convert_subrule_list(struct subrule_list_s *n, printf("error: no content in subrule_list\n"); } + free(n); return res; } struct filter *convert_compound_specifier(struct compound_specifier_s *r, struct filtergen_opts *o) { - struct filter *res = NULL; + struct filter *res = NULL, *sub = NULL; eprint("converting compound_specifier\n"); if (r->list) { - res = new_filter_sibs(convert_subrule_list(r->list, o)); + sub = convert_subrule_list(r->list, o); + if (sub) { + res = new_filter_sibs(sub); + } } + free(r); return res; } @@ -99,7 +105,7 @@ struct filter *convert_direction_argument(struct direction_argument_s *n, } else { printf("error: no direction argument contents\n"); } - + free(n); return res; } @@ -123,9 +129,10 @@ convert_direction_argument_list(struct direction_argument_list_s *n, int type) { printf("warning: convert_direction_argument_list returned NULL\n"); } } else { - res = convert_direction_argument(n->arg, type); + if (n->arg) + res = convert_direction_argument(n->arg, type); } - + free(n); return res; } @@ -152,7 +159,7 @@ struct filter *convert_direction(struct direction_specifier_s *n) { } else { printf("error: no direction argument list\n"); } - + free(n); return res; } @@ -177,7 +184,7 @@ struct filter *convert_host_argument(struct host_argument_s *n, int type, } else { printf("error: no host part\n"); } - + free(n); return res; } @@ -201,9 +208,10 @@ struct filter *convert_host_argument_list(struct host_argument_list_s *n, printf("warning: convert_host_argument_list returned NULL\n"); } } else { - res = convert_host_argument(n->arg, type, o); + if (n->arg) + res = convert_host_argument(n->arg, type, o); } - + free(n); return res; } @@ -231,7 +239,7 @@ struct filter *convert_host_specifier(struct host_specifier_s *n, } else { printf("error: no host argument list\n"); } - + free(n); return res; } @@ -245,7 +253,7 @@ struct filter *convert_protocol_argument(struct protocol_argument_s *n) { } else { printf("error: no protocol argument contents\n"); } - + free(n); return res; } @@ -269,9 +277,10 @@ convert_protocol_argument_list(struct protocol_argument_list_s *n) { printf("warning: convert_protocol_argument_list returned NULL\n"); } } else { - res = convert_protocol_argument(n->arg); + if (n->arg) + res = convert_protocol_argument(n->arg); } - + free(n); return res; } @@ -285,7 +294,7 @@ struct filter *convert_protocol_specifier(struct protocol_specifier_s *n) { } else { printf("error: no protocol argument list\n"); } - + free(n); return res; } @@ -309,7 +318,7 @@ struct filter *convert_port_argument(struct port_argument_s *n, int type) { } else { printf("error: no port argument contents\n"); } - + free(n); return res; } @@ -333,9 +342,10 @@ struct filter *convert_port_argument_list(struct port_argument_list_s *n, printf("warning: convert_port_argument_list returned NULL\n"); } } else { - res = convert_port_argument(n->arg, type); + if (n->arg) + res = convert_port_argument(n->arg, type); } - + free(n); return res; } @@ -362,7 +372,7 @@ struct filter *convert_port_specifier(struct port_specifier_s *n) { } else { printf("error: no port argument list\n"); } - + free(n); return res; } @@ -376,7 +386,7 @@ struct filter *convert_icmptype_argument(struct icmptype_argument_s *n) { } else { printf("error: no icmptype argument contents\n"); } - + free(n); return res; } @@ -400,9 +410,10 @@ convert_icmptype_argument_list(struct icmptype_argument_list_s *n) { printf("warning: convert_icmptype_argument_list returned NULL\n"); } } else { - res = convert_icmptype_argument(n->arg); + if (n->arg) + res = convert_icmptype_argument(n->arg); } - + free(n); return res; } @@ -416,7 +427,7 @@ struct filter *convert_icmptype_specifier(struct icmptype_specifier_s *n) { } else { printf("error: no icmptype argument list\n"); } - + free(n); return res; } @@ -442,7 +453,7 @@ struct filter *convert_option_specifier(struct option_specifier_s *n) { printf("error: incorrect option type encountered\n"); break; } - + free(n); return res; } @@ -466,12 +477,13 @@ struct filter *convert_chaingroup_specifier(struct chaingroup_specifier_s *n, if (n->list) { sub = convert_subrule_list(n->list, o); - - res = new_filter_subgroup(name, sub); + if (sub) { + res = new_filter_subgroup(name, sub); + } } else { printf("error: no list in chaingroup\n"); } - + free(n); return res; } @@ -527,9 +539,10 @@ struct filter *convert_specifier(struct specifier_s *r, res = convert_option_specifier(r->option); } else if (r->chaingroup) { res = convert_chaingroup_specifier(r->chaingroup, o); - } else + } else { printf("error: no specifiers\n"); - + } + free(r); return res; } @@ -549,6 +562,7 @@ struct filter *convert_negated_specifier(struct negated_specifier_s *r, res = spec; } } + free(r); return res; } @@ -572,9 +586,10 @@ struct filter *convert_specifier_list(struct specifier_list_s *n, printf("warning: convert_specifier_list returned NULL\n"); } } else { - res = convert_negated_specifier(n->spec, o); + if (n->spec) + res = convert_negated_specifier(n->spec, o); } - + free(n); return res; } @@ -585,6 +600,7 @@ struct filter *convert_rule(struct rule_s *r, struct filtergen_opts *o) { if (r->list) res = convert_specifier_list(r->list, o); + free(r); return res; } @@ -610,7 +626,7 @@ struct filter *convert_rule_list(struct rule_list_s *n, res = convert_rule(n->rule, o); } } - + free(n); return res; } @@ -619,8 +635,10 @@ struct filter *convert(struct ast_s *ast, struct filtergen_opts *o) { eprint("converting ast\n"); - if (ast->list) + if (ast->list) { res = convert_rule_list(ast->list, o); +} + return res; } diff --git a/scanner.l b/scanner.l index 3f81242c..a11bfac0 100644 --- a/scanner.l +++ b/scanner.l @@ -21,6 +21,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -39,10 +40,11 @@ struct inc_stack_s { }; struct inc_stack_s inc_stack[MAXINCLUDES] = { { .state = 0, .filename = NULL, .lineno = 1 } }; +static const char kStandardInput[] = "(standard input)"; int inc_stackptr = 0; long int lineno(); -char * filename(); +const char * filename(); static void scan_err(const char * fmt, ...) __attribute__((format(printf, 1, 2))); void include_file(const char *); %} @@ -127,8 +129,12 @@ text return TOK_TEXT; [ \t]* /* eat whitespace after include */ [^ \t\n;]+ { /* include file name */ char * name = strdup(yytext); - include_file(name); - free(name); + if (name == NULL) { + scan_err("warning: internal error trying to alloc for include of %s: %s", yytext, strerror(errno)); + } else { + include_file(name); + free(name); + } BEGIN(INITIAL); } @@ -151,18 +157,18 @@ long int lineno(void) { return inc_stack[inc_stackptr].lineno; } -/* FIXME: make this return an immutable string */ -char *filename(void) { +const char *filename(void) { return inc_stack[inc_stackptr].filename ? inc_stack[inc_stackptr].filename - : strdup("(standard input)"); + : kStandardInput; } static void scan_err(const char *fmt, ...) { va_list args; va_start(args, fmt); - if (inc_stackptr >= 0) + if (inc_stackptr >= 0) { fprintf(stderr, "%s:%ld: ", filename(), lineno()); + } vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); } @@ -227,13 +233,23 @@ void include_file(const char *name) { } } else { if (S_ISDIR(st.st_mode)) { + char *b = strdup(name); + char *base = basename(b); + + if (strcmp("/", base) == 0) { + scan_err("warning: cannot include / path; skipping"); + free(b); + return; + } + free(b); + if ((n = scandir(name, &namelist, NULL, alphasort)) < 0) { scan_err("warning: scandir failed on %s: %s", name, strerror(errno)); } else { while (n--) { /* FIXME: assumes d_name */ if (namelist[n]->d_name[0] == '.') { - free(namelist[n]); + free(namelist[n]); continue; } if (asprintf(&fn, "%s/%s", name, namelist[n]->d_name) < 0) { @@ -245,7 +261,7 @@ void include_file(const char *name) { include_file(fn); free(fn); } - free(namelist[n]); + free(namelist[n]); } free(namelist); } diff --git a/t/Makefile.am b/t/Makefile.am index debf28a3..324413f7 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -68,7 +68,10 @@ TESTS = t_01_ccomment \ t_68_noop \ t_69_includeemptynoop \ t_70_includesemicolon \ - t_71_includeglob + t_71_includeglob \ + t_72_noincluderoot \ + check_examples + check_PROGRAMS = scan parse emit convert factorise diff --git a/t/check_examples b/t/check_examples new file mode 100755 index 00000000..3f3d6adc --- /dev/null +++ b/t/check_examples @@ -0,0 +1,11 @@ +#!/bin/sh -ex + +TEST="that the example programs all compile" + +testdir=`dirname $0` +. $testdir/testlib + +for t in $here/../examples/*.filter; do + echo Checking $t + $here/../filtergen -R -c -t iptables $t +done diff --git a/t/t_72_noincluderoot b/t/t_72_noincluderoot new file mode 100755 index 00000000..17536cd7 --- /dev/null +++ b/t/t_72_noincluderoot @@ -0,0 +1,27 @@ +#!/bin/sh -x + +TEST="that include paths don't start at root" + +testdir=`dirname $0` +. $testdir/testlib + +cat >$work/in < $work/out 2>&1 +if test $? -ne 0 ; then fail ; fi + +test "x$srcdir" = "x" && cat $work/out + +cat >$work/good <