From cdc78b1d6bd7b48ec05d78fc6e6cd98473f40357 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Mon, 19 Aug 2013 15:04:02 +0300 Subject: nft: convert rule into a command state structure This helps to reduce the code complexity to have one single common path for printing, saving and looking up for the rule. Signed-off-by: Tomasz Bursztyka Signed-off-by: Pablo Neira Ayuso --- iptables/nft-shared.c | 272 ++++++++++++++++++++++++++------------------------ 1 file changed, 142 insertions(+), 130 deletions(-) (limited to 'iptables/nft-shared.c') diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index dd4766b0..ad5e80ea 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -281,57 +281,60 @@ void parse_meta(struct nft_rule_expr *e, uint8_t key, char *iniface, } } -const char *nft_parse_target(struct nft_rule *r, const void **targinfo, - size_t *target_len) +static void +nft_parse_target(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter, + struct iptables_command_state *cs) { - struct nft_rule_expr_iter *iter; - struct nft_rule_expr *expr; - const char *targname = NULL; + size_t tg_len; + const char *targname = nft_rule_expr_get_str(e, NFT_EXPR_TG_NAME); + const void *targinfo = nft_rule_expr_get(e, NFT_EXPR_TG_INFO, &tg_len); + struct xtables_target *target; + struct xt_entry_target *t; - iter = nft_rule_expr_iter_create(r); - if (iter == NULL) - return NULL; + target = xtables_find_target(targname, XTF_TRY_LOAD); + if (target == NULL) + return; - expr = nft_rule_expr_iter_next(iter); - while (expr != NULL) { - const char *name = - nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME); + t = calloc(1, sizeof(struct xt_entry_target) + tg_len); + if (t == NULL) { + fprintf(stderr, "OOM"); + exit(EXIT_FAILURE); + } + memcpy(&t->data, targinfo, tg_len); + t->u.target_size = tg_len + XT_ALIGN(sizeof(struct xt_entry_target)); + t->u.user.revision = nft_rule_expr_get_u32(e, NFT_EXPR_TG_REV); + strcpy(t->u.user.name, target->name); - if (strcmp(name, "target") == 0) { - targname = nft_rule_expr_get_str(expr, - NFT_EXPR_TG_NAME); - *targinfo = nft_rule_expr_get(expr, NFT_EXPR_TG_INFO, - target_len); - break; - } else if (strcmp(name, "immediate") == 0) { - uint32_t verdict = - nft_rule_expr_get_u32(expr, NFT_EXPR_IMM_VERDICT); - - switch(verdict) { - case NF_ACCEPT: - targname = "ACCEPT"; - break; - case NF_DROP: - targname = "DROP"; - break; - case NFT_RETURN: - targname = "RETURN"; - break; - case NFT_GOTO: - targname = nft_rule_expr_get_str(expr, - NFT_EXPR_IMM_CHAIN); - break; - case NFT_JUMP: - targname = nft_rule_expr_get_str(expr, - NFT_EXPR_IMM_CHAIN); - break; - } - } - expr = nft_rule_expr_iter_next(iter); + target->t = t; + cs->target = target; +} + +static void +nft_parse_match(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter, + struct iptables_command_state *cs) +{ + size_t mt_len; + const char *mt_name = nft_rule_expr_get_str(e, NFT_EXPR_MT_NAME); + const void *mt_info = nft_rule_expr_get(e, NFT_EXPR_MT_INFO, &mt_len); + struct xtables_match *match; + struct xt_entry_match *m; + + match = xtables_find_match(mt_name, XTF_TRY_LOAD, &cs->matches); + if (match == NULL) + return; + + m = calloc(1, sizeof(struct xt_entry_match) + mt_len); + if (m == NULL) { + fprintf(stderr, "OOM"); + exit(EXIT_FAILURE); } - nft_rule_expr_iter_destroy(iter); - return targname; + memcpy(&m->data, mt_info, mt_len); + m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match)); + m->u.user.revision = nft_rule_expr_get_u32(e, NFT_EXPR_TG_REV); + strcpy(m->u.user.name, match->name); + + match->m = m; } void print_proto(uint16_t proto, int invert) @@ -460,101 +463,30 @@ void nft_rule_to_iptables_command_state(struct nft_rule *r, const char *name = nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME); - if (strcmp(name, "counter") == 0) { + if (strcmp(name, "counter") == 0) nft_parse_counter(expr, iter, &cs->counters); - } else if (strcmp(name, "payload") == 0) { + else if (strcmp(name, "payload") == 0) nft_parse_payload(expr, iter, family, cs); - } else if (strcmp(name, "meta") == 0) { + else if (strcmp(name, "meta") == 0) nft_parse_meta(expr, iter, family, cs); - } else if (strcmp(name, "immediate") == 0) { + else if (strcmp(name, "immediate") == 0) nft_parse_immediate(expr, iter, family, cs); - } + else if (strcmp(name, "match") == 0) + nft_parse_match(expr, iter, cs); + else if (strcmp(name, "target") == 0) + nft_parse_target(expr, iter, cs); expr = nft_rule_expr_iter_next(iter); } nft_rule_expr_iter_destroy(iter); -} - -static void -print_match(struct nft_rule_expr *expr, int numeric) -{ - size_t len; - const char *match_name = nft_rule_expr_get_str(expr, NFT_EXPR_MT_NAME); - const void *match_info = nft_rule_expr_get(expr, NFT_EXPR_MT_INFO, &len); - const struct xtables_match *match = - xtables_find_match(match_name, XTF_TRY_LOAD, NULL); - struct xt_entry_match *m = - calloc(1, sizeof(struct xt_entry_match) + len); - - /* emulate struct xt_entry_match since ->print needs it */ - memcpy((void *)&m->data, match_info, len); - - if (match) { - if (match->print) - /* FIXME missing first parameter */ - match->print(NULL, m, numeric); - else - printf("%s ", match_name); - } else { - if (match_name[0]) - printf("UNKNOWN match `%s' ", match_name); - } - - free(m); -} - -int print_matches(struct nft_rule *r, int format) -{ - struct nft_rule_expr_iter *iter; - struct nft_rule_expr *expr; - - iter = nft_rule_expr_iter_create(r); - if (iter == NULL) - return -ENOMEM; - - expr = nft_rule_expr_iter_next(iter); - while (expr != NULL) { - const char *name = - nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME); - - if (strcmp(name, "match") == 0) - print_match(expr, format & FMT_NUMERIC); - - expr = nft_rule_expr_iter_next(iter); - } - nft_rule_expr_iter_destroy(iter); - - return 0; -} - -int print_target(const char *targname, const void *targinfo, - size_t target_len, int format) -{ - struct xtables_target *target; - struct xt_entry_target *t; - - if (targname == NULL) - return 0; - - t = calloc(1, sizeof(struct xt_entry_target) + target_len); - if (t == NULL) - return -ENOMEM; - - /* emulate struct xt_entry_target since ->print needs it */ - memcpy((void *)&t->data, targinfo, target_len); - - target = xtables_find_target(targname, XTF_TRY_LOAD); - if (target) { - if (target->print) - /* FIXME missing first parameter */ - target->print(NULL, t, format & FMT_NUMERIC); - } else if (target_len > 0) - printf("[%ld bytes of unknown target data] ", target_len); - free(t); - - return 0; + if (cs->target != NULL) + cs->jumpto = cs->target->name; + else if (cs->jumpto != NULL) + cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); + else + cs->jumpto = ""; } void print_num(uint64_t number, unsigned int format) @@ -646,6 +578,86 @@ void print_firewall_details(const struct iptables_command_state *cs, } } +static void +print_iface(char letter, const char *iface, const unsigned char *mask, int inv) +{ + unsigned int i; + + if (mask[0] == 0) + return; + + printf("%s-%c ", inv ? "! " : "", letter); + + for (i = 0; i < IFNAMSIZ; i++) { + if (mask[i] != 0) { + if (iface[i] != '\0') + printf("%c", iface[i]); + } else { + if (iface[i-1] != '\0') + printf("+"); + break; + } + } + + printf(" "); +} + +void save_firewall_details(const struct iptables_command_state *cs, + uint8_t invflags, uint16_t proto, + const char *iniface, + unsigned const char *iniface_mask, + const char *outiface, + unsigned const char *outiface_mask, + unsigned int format) +{ + if (!(format & FMT_NOCOUNTS)) { + printf("-c "); + print_num(cs->counters.pcnt, format); + print_num(cs->counters.bcnt, format); + } + + if (iniface != NULL) { + print_iface('i', iniface, iniface_mask, + invflags & IPT_INV_VIA_IN); + } + if (outiface != NULL) { + print_iface('o', outiface, outiface_mask, + invflags & IPT_INV_VIA_OUT); + } + + if (proto > 0) { + const struct protoent *pent = getprotobynumber(proto); + + if (invflags & XT_INV_PROTO) + printf("! "); + + if (pent) + printf("-p %s ", pent->p_name); + else + printf("-p %u ", proto); + } +} + +void print_matches_and_target(struct iptables_command_state *cs, + unsigned int format) +{ + struct xtables_rule_match *matchp; + + for (matchp = cs->matches; matchp; matchp = matchp->next) { + if (matchp->match->print != NULL) { + matchp->match->print(NULL, matchp->match->m, + format & FMT_NUMERIC); + } + } + + if (cs->target != NULL) { + if (cs->target->print != NULL) { + cs->target->print(NULL, cs->target->t, + format & FMT_NUMERIC); + } + } +} + struct nft_family_ops *nft_family_ops_lookup(int family) { switch (family) { -- cgit v1.2.3