From 108d9f6b3af0f70459fb7ccc1dfc5452d3f3646e Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 4 Sep 2013 12:50:19 +0300 Subject: src: Wrap netfilter hooks around human readable strings This allows to use unique, human readable, hook names for the command line and let the user being unaware of the complex netfilter's hook names and there difference depending on the netfilter family. So: add chain foo bar { type route hook NF_INET_LOCAL_IN 0; } becomes: add chain foo bar { type route hook input 0; } It also fixes then the difference in hook values between families. I.e. ARP family has different values for input, forward and output compared to IPv4, IPv6 or bridge. Signed-off-by: Tomasz Bursztyka Signed-off-by: Pablo Neira Ayuso --- src/evaluate.c | 43 ++++++++++++++++++++++++++++++++++ src/parser.y | 21 +++++++++++++---- src/rule.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++----------- src/scanner.l | 6 ----- 4 files changed, 119 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/evaluate.c b/src/evaluate.c index 85c647e5..29fa32bd 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -54,6 +56,8 @@ static int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx, __stmt_binary_error(ctx, &(s1)->location, NULL, fmt, ## args) #define stmt_binary_error(ctx, s1, s2, fmt, args...) \ __stmt_binary_error(ctx, &(s1)->location, &(s2)->location, fmt, ## args) +#define chain_error(ctx, s1, fmt, args...) \ + __stmt_binary_error(ctx, &(s1)->location, NULL, fmt, ## args) static int __fmtstring(3, 4) set_error(struct eval_ctx *ctx, const struct set *set, @@ -1247,10 +1251,49 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule) return 0; } +static uint32_t str2hooknum(uint32_t family, const char *hook) +{ + switch (family) { + case NFPROTO_IPV4: + case NFPROTO_BRIDGE: + case NFPROTO_IPV6: + /* These families have overlapping values for each hook */ + if (!strcmp(hook, "prerouting")) + return NF_INET_PRE_ROUTING; + else if (!strcmp(hook, "input")) + return NF_INET_LOCAL_IN; + else if (!strcmp(hook, "forward")) + return NF_INET_FORWARD; + else if (!strcmp(hook, "postrouting")) + return NF_INET_POST_ROUTING; + else if (!strcmp(hook, "output")) + return NF_INET_LOCAL_OUT; + case NFPROTO_ARP: + if (!strcmp(hook, "input")) + return NF_ARP_IN; + else if (!strcmp(hook, "forward")) + return NF_ARP_FORWARD; + else if (!strcmp(hook, "output")) + return NF_ARP_OUT; + default: + break; + } + + return NF_INET_NUMHOOKS; +} + static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain) { struct rule *rule; + if (chain->flags & CHAIN_F_BASECHAIN) { + chain->hooknum = str2hooknum(chain->handle.family, + chain->hookstr); + if (chain->hooknum == NF_INET_NUMHOOKS) + return chain_error(ctx, chain, "invalid hook %s", + chain->hookstr); + } + list_for_each_entry(rule, &chain->rules, list) { handle_merge(&rule->handle, &chain->handle); if (rule_evaluate(ctx, rule) < 0) diff --git a/src/parser.y b/src/parser.y index f0eb8e32..ec78e7fd 100644 --- a/src/parser.y +++ b/src/parser.y @@ -155,7 +155,6 @@ static void location_update(struct location *loc, struct location *rhs, int n) %token DEFINE "define" %token HOOK "hook" -%token HOOKNUM "hooknum" %token TABLE "table" %token TABLES "tables" %token CHAIN "chain" @@ -550,6 +549,7 @@ add_cmd : TABLE table_spec | CHAIN chain_spec chain_block_alloc '{' chain_block '}' { + $5->location = @5; handle_merge(&$3->handle, &$2); close_scope(state); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &$2, &@$, $5); @@ -667,6 +667,7 @@ table_block : /* empty */ { $$ = $-1; } chain_block_alloc '{' chain_block '}' stmt_seperator { + $4->location = @3; handle_merge(&$4->handle, &$3); handle_free(&$3); close_scope(state); @@ -766,17 +767,27 @@ map_block : /* empty */ { $$ = $-1; } } ; -hook_spec : TYPE STRING HOOK HOOKNUM NUM +hook_spec : TYPE STRING HOOK STRING NUM { $0->type = $2; - $0->hooknum = $4; + $0->hookstr = chain_hookname_lookup($4); + if ($0->hookstr == NULL) { + erec_queue(error(&@4, "unknown hook name %s", $4), + state->msgs); + YYERROR; + } $0->priority = $5; $0->flags |= CHAIN_F_BASECHAIN; } - | TYPE STRING HOOK HOOKNUM DASH NUM + | TYPE STRING HOOK STRING DASH NUM { $0->type = $2; - $0->hooknum = $4; + $0->hookstr = chain_hookname_lookup($4); + if ($0->hookstr == NULL) { + erec_queue(error(&@4, "unknown hook name %s", $4), + state->msgs); + YYERROR; + } $0->priority = -$6; $0->flags |= CHAIN_F_BASECHAIN; } diff --git a/src/rule.c b/src/rule.c index 73054bad..f493cd48 100644 --- a/src/rule.c +++ b/src/rule.c @@ -21,6 +21,7 @@ #include #include +#include void handle_free(struct handle *h) { @@ -189,6 +190,27 @@ struct symbol *symbol_lookup(const struct scope *scope, const char *identifier) return NULL; } +static const char *chain_hookname_str_array[] = { + "prerouting", + "input", + "forward", + "postrouting", + "output", + NULL, +}; + +const char *chain_hookname_lookup(const char *name) +{ + int i; + + for (i = 0; chain_hookname_str_array[i]; i++) { + if (!strcmp(name, chain_hookname_str_array[i])) + return chain_hookname_str_array[i]; + } + + return NULL; +} + struct chain *chain_alloc(const char *name) { struct chain *chain; @@ -228,20 +250,43 @@ struct chain *chain_lookup(const struct table *table, const struct handle *h) return NULL; } -static const char *hooknum2str_array[NF_INET_NUMHOOKS] = { - [NF_INET_PRE_ROUTING] = "NF_INET_PRE_ROUTING", - [NF_INET_LOCAL_IN] = "NF_INET_LOCAL_IN", - [NF_INET_FORWARD] = "NF_INET_FORWARD", - [NF_INET_LOCAL_OUT] = "NF_INET_LOCAL_OUT", - [NF_INET_POST_ROUTING] = "NF_INET_POST_ROUTING", -}; - -static const char *hooknum2str(unsigned int hooknum) -{ - if (hooknum >= NF_INET_NUMHOOKS) - return "UNKNOWN"; +static const char *hooknum2str(unsigned int family, unsigned int hooknum) +{ + switch (family) { + case NFPROTO_IPV4: + case NFPROTO_BRIDGE: + case NFPROTO_IPV6: + switch (hooknum) { + case NF_INET_PRE_ROUTING: + return "prerouting"; + case NF_INET_LOCAL_IN: + return "input"; + case NF_INET_FORWARD: + return "forward"; + case NF_INET_POST_ROUTING: + return "postrouting"; + case NF_INET_LOCAL_OUT: + return "output"; + default: + break; + }; + break; + case NFPROTO_ARP: + switch (hooknum) { + case NF_ARP_IN: + return "input"; + case NF_ARP_FORWARD: + return "forward"; + case NF_ARP_OUT: + return "output"; + default: + break; + } + default: + break; + }; - return hooknum2str_array[hooknum]; + return "unknown"; } static void chain_print(const struct chain *chain) @@ -251,7 +296,8 @@ static void chain_print(const struct chain *chain) printf("\tchain %s {\n", chain->handle.chain); if (chain->flags & CHAIN_F_BASECHAIN) { printf("\t\t type %s hook %s %u;\n", chain->type, - hooknum2str(chain->hooknum), chain->priority); + hooknum2str(chain->handle.family, chain->hooknum), + chain->priority); } list_for_each_entry(rule, &chain->rules, list) { printf("\t\t"); diff --git a/src/scanner.l b/src/scanner.l index 59e0aac7..cee6aa6e 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -212,12 +212,6 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "=>" { return ARROW; } "vmap" { return VMAP; } -"NF_INET_PRE_ROUTING" { yylval->val = NF_INET_PRE_ROUTING; return HOOKNUM; } -"NF_INET_LOCAL_IN" { yylval->val = NF_INET_LOCAL_IN; return HOOKNUM; } -"NF_INET_FORWARD" { yylval->val = NF_INET_FORWARD; return HOOKNUM; } -"NF_INET_LOCAL_OUT" { yylval->val = NF_INET_LOCAL_OUT; return HOOKNUM; } -"NF_INET_POST_ROUTING" { yylval->val = NF_INET_POST_ROUTING; return HOOKNUM; } - "include" { return INCLUDE; } "define" { return DEFINE; } -- cgit v1.2.3