From da871de2a6efb576b6378a66222c0871f4282e96 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 9 Oct 2014 15:02:02 +0200 Subject: nft: bootstrap ebtables-compat This patch bootstraps ebtables-compat, the ebtables compatibility software upon nf_tables. [ Original patches: http://patchwork.ozlabs.org/patch/395544/ http://patchwork.ozlabs.org/patch/395545/ http://patchwork.ozlabs.org/patch/395546/ I have also forward port them on top of the current git HEAD, otherwise compilation breaks. This bootstrap is experimental, this still needs more work. --Pablo ] Signed-off-by: Giuseppe Longo Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 558 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 558 insertions(+) create mode 100644 iptables/nft-bridge.c (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c new file mode 100644 index 00000000..66361ee9 --- /dev/null +++ b/iptables/nft-bridge.c @@ -0,0 +1,558 @@ +/* + * (C) 2014 by Giuseppe Longo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "nft-shared.h" +#include "nft.h" + +/* 0: default, print only 2 digits if necessary + * 2: always print 2 digits, a printed mac address + * then always has the same length */ +int ebt_printstyle_mac; + +static void ebt_print_mac(const unsigned char *mac) +{ + if (ebt_printstyle_mac == 2) { + int j; + for (j = 0; j < ETH_ALEN; j++) + printf("%02x%s", mac[j], + (j==ETH_ALEN-1) ? "" : ":"); + } else + printf("%s", ether_ntoa((struct ether_addr *) mac)); +} + +/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */ +static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask) +{ + char hlpmsk[6] = {}; + + if (!memcmp(mac, eb_mac_type_unicast, 6) && + !memcmp(mask, eb_msk_type_unicast, 6)) + printf("Unicast"); + else if (!memcmp(mac, eb_mac_type_multicast, 6) && + !memcmp(mask, eb_msk_type_multicast, 6)) + printf("Multicast"); + else if (!memcmp(mac, eb_mac_type_broadcast, 6) && + !memcmp(mask, eb_msk_type_broadcast, 6)) + printf("Broadcast"); + else if (!memcmp(mac, eb_mac_type_bridge_group, 6) && + !memcmp(mask, eb_msk_type_bridge_group, 6)) + printf("BGA"); + else { + ebt_print_mac(mac); + if (memcmp(mask, hlpmsk, 6)) { + printf("/"); + ebt_print_mac(mask); + } + } +} + +static uint8_t ebt_to_ipt_flags(uint16_t invflags) +{ + uint8_t result = 0; + + if (invflags & EBT_IIN) + result |= IPT_INV_VIA_IN; + + if (invflags & EBT_IOUT) + result |= IPT_INV_VIA_OUT; + + if (invflags & EBT_IPROTO) + result |= IPT_INV_PROTO; + + return result; +} + +static uint16_t ipt_to_ebt_flags(uint8_t invflags) +{ + uint16_t result = 0; + + if (invflags & IPT_INV_VIA_IN) + result |= EBT_IIN; + + if (invflags & IPT_INV_VIA_OUT) + result |= EBT_IOUT; + + if (invflags & IPT_INV_PROTO) + result |= EBT_IPROTO; + + return result; +} + +static void add_logical_iniface(struct nft_rule *r, char *iface, int invflags) +{ + int iface_len; + uint32_t op; + + iface_len = strlen(iface); + + if (invflags & EBT_ILOGICALIN) + op = NFT_CMP_NEQ; + else + op = NFT_CMP_EQ; + + add_meta(r, NFT_META_BRI_IIFNAME); + if (iface[iface_len - 1] == '+') + add_cmp_ptr(r, op, iface, iface_len - 1); + else + add_cmp_ptr(r, op, iface, iface_len + 1); +} + +static void add_logical_outiface(struct nft_rule *r, char *iface, int invflags) +{ + int iface_len; + uint32_t op; + + iface_len = strlen(iface); + + if (invflags & EBT_ILOGICALOUT) + op = NFT_CMP_NEQ; + else + op = NFT_CMP_EQ; + + add_meta(r, NFT_META_BRI_OIFNAME); + if (iface[iface_len - 1] == '+') + add_cmp_ptr(r, op, iface, iface_len - 1); + else + add_cmp_ptr(r, op, iface, iface_len + 1); +} + +static int _add_action(struct nft_rule *r, struct xtables_ebt_entry *fw) +{ + int ret = 0; + + /* If no target at all, add nothing (default to continue) */ + if (fw->target != NULL) { + /* Standard target? */ + if (strcmp(fw->jumpto, XTC_LABEL_ACCEPT) == 0) + ret = add_verdict(r, NF_ACCEPT); + else if (strcmp(fw->jumpto, XTC_LABEL_DROP) == 0) + ret = add_verdict(r, NF_DROP); + else if (strcmp(fw->jumpto, XTC_LABEL_RETURN) == 0) + ret = add_verdict(r, NFT_RETURN); + else + ret = add_target(r, fw->target->t); + } else if (strlen(fw->jumpto) > 0) + /* Not standard, then it's a jump to chain */ + ret = add_jumpto(r, fw->jumpto, NFT_JUMP); + + return ret; +} + +static int nft_bridge_add(struct nft_rule *r, void *data) +{ + struct xtables_ebt_entry *fw = data; + uint8_t flags = ebt_to_ipt_flags(fw->invflags); + char *addr; + + if (fw->in[0] != '\0') + add_iniface(r, fw->in, flags); + + if (fw->out[0] != '\0') + add_outiface(r, fw->out, flags); + + if (fw->logical_in[0] != '\0') + add_logical_iniface(r, fw->logical_in, flags); + + if (fw->logical_out[0] != '\0') + add_logical_outiface(r, fw->logical_out, flags); + + addr = ether_ntoa((struct ether_addr *) fw->sourcemac); + if (strcmp(addr, "0:0:0:0:0:0") != 0) { + add_payload(r, offsetof(struct ethhdr, h_source), 6); + add_cmp_ptr(r, NFT_CMP_EQ, fw->sourcemac, 6); + } + + addr = ether_ntoa((struct ether_addr *) fw->destmac); + if (strcmp(addr, "0:0:0:0:0:0") != 0) { + add_payload(r, offsetof(struct ethhdr, h_dest), 6); + add_cmp_ptr(r, NFT_CMP_EQ, fw->destmac, 6); + } + + if (fw->ethproto != 0) { + add_payload(r, offsetof(struct ethhdr, h_proto), 2); + add_cmp_u16(r, fw->ethproto, NFT_CMP_EQ); + } + + return _add_action(r, fw); +} + +static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, + struct nft_rule_expr *e, void *data) +{ + struct xtables_ebt_entry *fw = data; + uint8_t flags = 0; + int iface = 0; + const void *ifname; + uint32_t len; + + iface = parse_meta(e, ctx->meta.key, fw->in, fw->in_mask, + fw->out, fw->out_mask, &flags); + if (!iface) + goto out; + + switch (ctx->meta.key) { + case NFT_META_BRI_IIFNAME: + ifname = nft_rule_expr_get(e, NFT_EXPR_CMP_DATA, &len); + if (nft_rule_expr_get_u32(e, NFT_EXPR_CMP_OP) == NFT_CMP_NEQ) + flags |= IPT_INV_VIA_IN; + + memcpy(fw->logical_in, ifname, len); + + if (fw->logical_in[len] == '\0') + memset(fw->in_mask, 0xff, len); + else { + fw->logical_in[len] = '+'; + fw->logical_in[len+1] = '\0'; + memset(fw->in_mask, 0xff, len + 1); + } + break; + case NFT_META_BRI_OIFNAME: + ifname = nft_rule_expr_get(e, NFT_EXPR_CMP_DATA, &len); + if (nft_rule_expr_get_u32(e, NFT_EXPR_CMP_OP) == NFT_CMP_NEQ) + flags |= IPT_INV_VIA_OUT; + + memcpy(fw->logical_out, ifname, len); + + if (fw->logical_out[len] == '\0') + memset(fw->out_mask, 0xff, len); + else { + fw->logical_out[len] = '+'; + fw->logical_out[len+1] = '\0'; + memset(fw->out_mask, 0xff, len + 1); + } + break; + default: + break; + } + +out: + fw->invflags |= ipt_to_ebt_flags(flags); +} + +static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, + struct nft_rule_expr *e, void *data) +{ + struct xtables_ebt_entry *fw = data; + unsigned char addr[ETH_ALEN]; + unsigned short int ethproto; + bool inv; + int i; + + switch (ctx->payload.offset) { + case offsetof(struct ethhdr, h_dest): + get_cmp_data(e, addr, sizeof(addr), &inv); + for (i = 0; i < ETH_ALEN; i++) + fw->destmac[i] = addr[i]; + break; + case offsetof(struct ethhdr, h_source): + get_cmp_data(e, addr, sizeof(addr), &inv); + for (i = 0; i < ETH_ALEN; i++) + fw->sourcemac[i] = addr[i]; + break; + case offsetof(struct ethhdr, h_proto): + get_cmp_data(e, ðproto, sizeof(ethproto), &inv); + fw->ethproto = ethproto; + break; + } +} +static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, + void *data) +{ + struct xtables_ebt_entry *fw = data; + + fw->jumpto = jumpto; +} + +static void nft_bridge_parse_target(struct xtables_target *t, void *data) +{ + struct xtables_ebt_entry *fw = data; + + fw->target = t; +} + +void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry *fw) +{ + struct nft_rule_expr_iter *iter; + struct nft_rule_expr *expr; + int family = nft_rule_attr_get_u32(r, NFT_RULE_ATTR_FAMILY); + struct nft_xt_ctx ctx = { + .state.ebfw = fw, + .family = family, + }; + + iter = nft_rule_expr_iter_create(r); + if (iter == 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); + + if (strcmp(name, "counter") == 0) + nft_parse_counter(expr, &fw->counters); + else if (strcmp(name, "payload") == 0) + nft_parse_payload(&ctx, expr); + else if (strcmp(name, "meta") == 0) + nft_parse_meta(&ctx, expr); + else if (strcmp(name, "cmp") == 0) + nft_parse_cmp(&ctx, expr); + else if (strcmp(name, "immediate") == 0) + nft_parse_immediate(&ctx, expr); + else if (strcmp(name, "target") == 0) + nft_parse_target(&ctx, expr); + + expr = nft_rule_expr_iter_next(iter); + } + + nft_rule_expr_iter_destroy(iter); + + if (fw->target != NULL) + fw->jumpto = fw->target->name; + else if (fw->jumpto != NULL) + fw->target = xtables_find_target(fw->jumpto, XTF_TRY_LOAD); + else + fw->jumpto = ""; +} + +static void print_iface(const char *iface) +{ + char *c; + + if ((c = strchr(iface, IF_WILDCARD))) + *c = '+'; + printf("%s ", iface); + if (c) + *c = IF_WILDCARD; +} + +static void nft_bridge_print_header(unsigned int format, const char *chain, + const char *pol, + const struct xt_counters *counters, + bool basechain, uint32_t refs) +{ + /* FIXME: Giuseppe replace this with ebtables format */ + print_header(format, chain, pol, counters, basechain, refs); +} + +static void +nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, + unsigned int format) +{ + struct xtables_ebt_entry fw = {}; + char *addr; + + nft_rule_to_xtables_ebt_entry(r, &fw); + + if (format & FMT_LINENUMBERS) + printf("%d ", num); + + /* Dont print anything about the protocol if no protocol was + * specified, obviously this means any protocol will do. */ + if (fw.ethproto != 0) { + printf("-p "); + if (fw.invflags & EBT_IPROTO) + printf("! "); + if (fw.bitmask & EBT_802_3) + printf("Length "); + else { + struct ethertypeent *ent; + + ent = getethertypebynumber(ntohs(fw.ethproto)); + if (!ent) + printf("0x%x ", ntohs(fw.ethproto)); + else + printf("%s ", ent->e_name); + } + } + + addr = ether_ntoa((struct ether_addr *) fw.sourcemac); + if (strcmp(addr, "0:0:0:0:0:0") != 0) { + printf("-s "); + if (fw.invflags & EBT_ISOURCE) + printf("! "); + ebt_print_mac_and_mask(fw.sourcemac, fw.sourcemsk); + printf(" "); + } + + addr = ether_ntoa((struct ether_addr *) fw.destmac); + if (strcmp(addr, "0:0:0:0:0:0") != 0) { + printf("-d "); + if (fw.invflags & EBT_IDEST) + printf("! "); + ebt_print_mac_and_mask(fw.destmac, fw.destmsk); + printf(" "); + } + + if (fw.in[0] != '\0') { + printf("-i "); + if (fw.invflags & EBT_IIN) + printf("! "); + print_iface(fw.in); + } + + if (fw.logical_in[0] != '\0') { + printf("--logical-in "); + if (fw.invflags & EBT_ILOGICALIN) + printf("! "); + print_iface(fw.logical_in); + } + + if (fw.logical_out[0] != '\0') { + printf("--logical-out "); + if (fw.invflags & EBT_ILOGICALOUT) + printf("! "); + print_iface(fw.logical_out); + } + + if (fw.out[0] != '\0') { + printf("-o "); + if (fw.invflags & EBT_IOUT) + printf("! "); + print_iface(fw.out); + } + + /* old code to adapt + m_l = hlp->m_list; + while (m_l) { + m = ebt_find_match(m_l->m->u.name); + if (!m) + ebt_print_bug("Match not found"); + m->print(hlp, m_l->m); + m_l = m_l->next; + } + w_l = hlp->w_list; + while (w_l) { + w = ebt_find_watcher(w_l->w->u.name); + if (!w) + ebt_print_bug("Watcher not found"); + w->print(hlp, w_l->w); + w_l = w_l->next; + }*/ + printf("-j "); + if (!(format & FMT_NOTARGET)) + printf("%s", fw.jumpto); + + if (fw.target != NULL) { + if (fw.target->print != NULL) { + fw.target->print(&fw, fw.target->t, + format & FMT_NUMERIC); + } + } + + if (!(format & FMT_NONEWLINE)) + fputc('\n', stdout); +} + +static bool nft_bridge_is_same(const void *data_a, + const void *data_b) +{ + const struct xtables_ebt_entry *a = data_a; + const struct xtables_ebt_entry *b = data_b; + int i; + + if (a->ethproto != b->ethproto + /*|| a->flags != b->flags*/ + || a->invflags != b->invflags) { + DEBUGP("different proto/flags/invflags\n"); + return false; + } + + for (i = 0; i < ETH_ALEN; i++) { + if (a->sourcemac[i] != b->sourcemac[i]) { + DEBUGP("different source mac %x, %x (%d)\n", + a->sourcemac[i] & 0xff, b->sourcemac[i] & 0xff, i); + return false; + } + + if (a->destmac[i] != b->destmac[i]) { + DEBUGP("different destination mac %x, %x (%d)\n", + a->destmac[i] & 0xff, b->destmac[i] & 0xff, i); + return false; + } + } + + for (i = 0; i < IFNAMSIZ; i++) { + if (a->logical_in[i] != b->logical_in[i]) { + DEBUGP("different logical iniface %x, %x (%d)\n", + a->logical_in[i] & 0xff, b->logical_in[i] & 0xff, i); + return false; + } + + if (a->logical_out[i] != b->logical_out[i]) { + DEBUGP("different logical outiface %x, %x (%d)\n", + a->logical_out[i] & 0xff, b->logical_out[i] & 0xff, i); + return false; + } + } + + return is_same_interfaces((char *)a->in, + (char *)a->out, + a->in_mask, + a->out_mask, + (char *)b->in, + (char *)b->out, + b->in_mask, + b->out_mask); +} + +static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nft_rule *r, + void *data) +{ + struct xtables_ebt_entry *fw = data; + struct xtables_ebt_entry this = {}; + + nft_rule_to_xtables_ebt_entry(r, &this); + + DEBUGP("comparing with... "); + + if (!ops->is_same(fw, &this)) + return false; + + if (!compare_matches(fw->matches, this.matches)) { + DEBUGP("Different matches\n"); + return false; + } + + if (!compare_targets(fw->target, this.target)) { + DEBUGP("Different target\n"); + return false; + } + + if (strcmp(fw->jumpto, this.jumpto) != 0) { + DEBUGP("Different verdict\n"); + return false; + } + + return true; +} + +struct nft_family_ops nft_family_ops_bridge = { + .add = nft_bridge_add, + .is_same = nft_bridge_is_same, + .print_payload = NULL, + .parse_meta = nft_bridge_parse_meta, + .parse_payload = nft_bridge_parse_payload, + .parse_immediate = nft_bridge_parse_immediate, + .print_header = nft_bridge_print_header, + .print_firewall = nft_bridge_print_firewall, + .post_parse = NULL, + .rule_find = nft_bridge_rule_find, + .parse_target = nft_bridge_parse_target, +}; -- cgit v1.2.3 From 902e92ceedba96d3241fa8ff701c061cd53a197d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 9 Oct 2014 20:11:16 +0200 Subject: ebtables-compat: use ebtables_command_state in bootstrap code And introduce fake ebt_entry. This gets the code in sync in other existing compat tools. This will likely allow to consolidate common infrastructure. This code is still quite experimental. Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 177 +++++++++++++++++++++++++++----------------------- 1 file changed, 96 insertions(+), 81 deletions(-) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 66361ee9..ab97881d 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -18,11 +18,13 @@ #include #include "nft-shared.h" +#include "nft-bridge.h" #include "nft.h" /* 0: default, print only 2 digits if necessary * 2: always print 2 digits, a printed mac address - * then always has the same length */ + * then always has the same length + */ int ebt_printstyle_mac; static void ebt_print_mac(const unsigned char *mac) @@ -132,31 +134,36 @@ static void add_logical_outiface(struct nft_rule *r, char *iface, int invflags) add_cmp_ptr(r, op, iface, iface_len + 1); } -static int _add_action(struct nft_rule *r, struct xtables_ebt_entry *fw) +/* TODO: Use generic add_action() once we convert this to use + * iptables_command_state. + */ +static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs) { int ret = 0; - /* If no target at all, add nothing (default to continue) */ - if (fw->target != NULL) { - /* Standard target? */ - if (strcmp(fw->jumpto, XTC_LABEL_ACCEPT) == 0) - ret = add_verdict(r, NF_ACCEPT); - else if (strcmp(fw->jumpto, XTC_LABEL_DROP) == 0) - ret = add_verdict(r, NF_DROP); - else if (strcmp(fw->jumpto, XTC_LABEL_RETURN) == 0) - ret = add_verdict(r, NFT_RETURN); - else - ret = add_target(r, fw->target->t); - } else if (strlen(fw->jumpto) > 0) + /* If no target at all, add nothing (default to continue) */ + if (cs->target != NULL) { + /* Standard target? */ + if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0) + ret = add_verdict(r, NF_ACCEPT); + else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) + ret = add_verdict(r, NF_DROP); + else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) + ret = add_verdict(r, NFT_RETURN); + else + ret = add_target(r, cs->target->t); + } else if (strlen(cs->jumpto) > 0) { /* Not standard, then it's a jump to chain */ - ret = add_jumpto(r, fw->jumpto, NFT_JUMP); + ret = add_jumpto(r, cs->jumpto, NFT_JUMP); + } - return ret; + return ret; } static int nft_bridge_add(struct nft_rule *r, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; + struct ebt_entry *fw = &cs->fw; uint8_t flags = ebt_to_ipt_flags(fw->invflags); char *addr; @@ -189,13 +196,14 @@ static int nft_bridge_add(struct nft_rule *r, void *data) add_cmp_u16(r, fw->ethproto, NFT_CMP_EQ); } - return _add_action(r, fw); + return _add_action(r, cs); } static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; + struct ebt_entry *fw = &cs->fw; uint8_t flags = 0; int iface = 0; const void *ifname; @@ -214,7 +222,7 @@ static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, memcpy(fw->logical_in, ifname, len); - if (fw->logical_in[len] == '\0') + if (fw->logical_in[len] == '\0') memset(fw->in_mask, 0xff, len); else { fw->logical_in[len] = '+'; @@ -248,7 +256,8 @@ out: static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, struct nft_rule_expr *e, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; + struct ebt_entry *fw = &cs->fw; unsigned char addr[ETH_ALEN]; unsigned short int ethproto; bool inv; @@ -271,28 +280,30 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, break; } } + static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; - fw->jumpto = jumpto; + cs->jumpto = jumpto; } static void nft_bridge_parse_target(struct xtables_target *t, void *data) { - struct xtables_ebt_entry *fw = data; + struct ebtables_command_state *cs = data; - fw->target = t; + cs->target = t; } -void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry *fw) +void nft_rule_to_ebtables_command_state(struct nft_rule *r, + struct ebtables_command_state *cs) { struct nft_rule_expr_iter *iter; struct nft_rule_expr *expr; int family = nft_rule_attr_get_u32(r, NFT_RULE_ATTR_FAMILY); struct nft_xt_ctx ctx = { - .state.ebfw = fw, + .state.cs_eb = cs, .family = family, }; @@ -306,15 +317,19 @@ void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME); if (strcmp(name, "counter") == 0) - nft_parse_counter(expr, &fw->counters); + nft_parse_counter(expr, &cs->counters); else if (strcmp(name, "payload") == 0) nft_parse_payload(&ctx, expr); else if (strcmp(name, "meta") == 0) nft_parse_meta(&ctx, expr); + else if (strcmp(name, "bitwise") == 0) + nft_parse_bitwise(&ctx, expr); else if (strcmp(name, "cmp") == 0) nft_parse_cmp(&ctx, expr); else if (strcmp(name, "immediate") == 0) nft_parse_immediate(&ctx, expr); + else if (strcmp(name, "match") == 0) + nft_parse_match(&ctx, expr); else if (strcmp(name, "target") == 0) nft_parse_target(&ctx, expr); @@ -323,12 +338,12 @@ void nft_rule_to_xtables_ebt_entry(struct nft_rule *r, struct xtables_ebt_entry nft_rule_expr_iter_destroy(iter); - if (fw->target != NULL) - fw->jumpto = fw->target->name; - else if (fw->jumpto != NULL) - fw->target = xtables_find_target(fw->jumpto, XTF_TRY_LOAD); + 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 - fw->jumpto = ""; + cs->jumpto = ""; } static void print_iface(const char *iface) @@ -351,81 +366,80 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, print_header(format, chain, pol, counters, basechain, refs); } -static void -nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, - unsigned int format) +static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, + unsigned int format) { - struct xtables_ebt_entry fw = {}; + struct ebtables_command_state cs = {}; char *addr; - nft_rule_to_xtables_ebt_entry(r, &fw); + nft_rule_to_ebtables_command_state(r, &cs); if (format & FMT_LINENUMBERS) printf("%d ", num); /* Dont print anything about the protocol if no protocol was * specified, obviously this means any protocol will do. */ - if (fw.ethproto != 0) { + if (cs.fw.ethproto != 0) { printf("-p "); - if (fw.invflags & EBT_IPROTO) + if (cs.fw.invflags & EBT_IPROTO) printf("! "); - if (fw.bitmask & EBT_802_3) + if (cs.fw.bitmask & EBT_802_3) printf("Length "); else { struct ethertypeent *ent; - ent = getethertypebynumber(ntohs(fw.ethproto)); + ent = getethertypebynumber(ntohs(cs.fw.ethproto)); if (!ent) - printf("0x%x ", ntohs(fw.ethproto)); + printf("0x%x ", ntohs(cs.fw.ethproto)); else printf("%s ", ent->e_name); } } - addr = ether_ntoa((struct ether_addr *) fw.sourcemac); + addr = ether_ntoa((struct ether_addr *) cs.fw.sourcemac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { printf("-s "); - if (fw.invflags & EBT_ISOURCE) + if (cs.fw.invflags & EBT_ISOURCE) printf("! "); - ebt_print_mac_and_mask(fw.sourcemac, fw.sourcemsk); + ebt_print_mac_and_mask(cs.fw.sourcemac, cs.fw.sourcemsk); printf(" "); } - addr = ether_ntoa((struct ether_addr *) fw.destmac); + addr = ether_ntoa((struct ether_addr *) cs.fw.destmac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { printf("-d "); - if (fw.invflags & EBT_IDEST) + if (cs.fw.invflags & EBT_IDEST) printf("! "); - ebt_print_mac_and_mask(fw.destmac, fw.destmsk); + ebt_print_mac_and_mask(cs.fw.destmac, cs.fw.destmsk); printf(" "); } - if (fw.in[0] != '\0') { + if (cs.fw.in[0] != '\0') { printf("-i "); - if (fw.invflags & EBT_IIN) + if (cs.fw.invflags & EBT_IIN) printf("! "); - print_iface(fw.in); + print_iface(cs.fw.in); } - if (fw.logical_in[0] != '\0') { + if (cs.fw.logical_in[0] != '\0') { printf("--logical-in "); - if (fw.invflags & EBT_ILOGICALIN) + if (cs.fw.invflags & EBT_ILOGICALIN) printf("! "); - print_iface(fw.logical_in); + print_iface(cs.fw.logical_in); } - if (fw.logical_out[0] != '\0') { + if (cs.fw.logical_out[0] != '\0') { printf("--logical-out "); - if (fw.invflags & EBT_ILOGICALOUT) + if (cs.fw.invflags & EBT_ILOGICALOUT) printf("! "); - print_iface(fw.logical_out); + print_iface(cs.fw.logical_out); } - if (fw.out[0] != '\0') { + if (cs.fw.out[0] != '\0') { printf("-o "); - if (fw.invflags & EBT_IOUT) + if (cs.fw.invflags & EBT_IOUT) printf("! "); - print_iface(fw.out); + print_iface(cs.fw.out); } /* old code to adapt @@ -447,12 +461,12 @@ nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, }*/ printf("-j "); if (!(format & FMT_NOTARGET)) - printf("%s", fw.jumpto); + printf("%s", cs.jumpto); - if (fw.target != NULL) { - if (fw.target->print != NULL) { - fw.target->print(&fw, fw.target->t, - format & FMT_NUMERIC); + if (cs.target != NULL) { + if (cs.target->print != NULL) { + cs.target->print(&cs.fw, cs.target->t, + format & FMT_NUMERIC); } } @@ -460,16 +474,15 @@ nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, fputc('\n', stdout); } -static bool nft_bridge_is_same(const void *data_a, - const void *data_b) +static bool nft_bridge_is_same(const void *data_a, const void *data_b) { - const struct xtables_ebt_entry *a = data_a; - const struct xtables_ebt_entry *b = data_b; + const struct ebt_entry *a = data_a; + const struct ebt_entry *b = data_b; int i; - if (a->ethproto != b->ethproto - /*|| a->flags != b->flags*/ - || a->invflags != b->invflags) { + if (a->ethproto != b->ethproto || + /* FIXME: a->flags != b->flags || */ + a->invflags != b->invflags) { DEBUGP("different proto/flags/invflags\n"); return false; } @@ -515,27 +528,27 @@ static bool nft_bridge_is_same(const void *data_a, static bool nft_bridge_rule_find(struct nft_family_ops *ops, struct nft_rule *r, void *data) { - struct xtables_ebt_entry *fw = data; - struct xtables_ebt_entry this = {}; + struct ebtables_command_state *cs = data; + struct ebtables_command_state this = {}; - nft_rule_to_xtables_ebt_entry(r, &this); + nft_rule_to_ebtables_command_state(r, &this); DEBUGP("comparing with... "); - if (!ops->is_same(fw, &this)) + if (!nft_bridge_is_same(cs, &this)) return false; - if (!compare_matches(fw->matches, this.matches)) { + if (!compare_matches(cs->matches, this.matches)) { DEBUGP("Different matches\n"); return false; } - if (!compare_targets(fw->target, this.target)) { + if (!compare_targets(cs->target, this.target)) { DEBUGP("Different target\n"); return false; } - if (strcmp(fw->jumpto, this.jumpto) != 0) { + if (strcmp(cs->jumpto, this.jumpto) != 0) { DEBUGP("Different verdict\n"); return false; } @@ -550,9 +563,11 @@ struct nft_family_ops nft_family_ops_bridge = { .parse_meta = nft_bridge_parse_meta, .parse_payload = nft_bridge_parse_payload, .parse_immediate = nft_bridge_parse_immediate, + .parse_target = nft_bridge_parse_target, .print_header = nft_bridge_print_header, .print_firewall = nft_bridge_print_firewall, + .save_firewall = NULL, + .save_counters = NULL, .post_parse = NULL, .rule_find = nft_bridge_rule_find, - .parse_target = nft_bridge_parse_target, }; -- cgit v1.2.3 From 51e83a4deb4849152a29c160893f0823846d47a0 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Thu, 16 Oct 2014 16:29:51 +0200 Subject: ebtables-compat: fix print_header This prints the header like ebtables. Signed-off-by: Giuseppe Longo Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index ab97881d..0e21b468 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -357,13 +357,17 @@ static void print_iface(const char *iface) *c = IF_WILDCARD; } +static void nft_bridge_print_table_header(const char *tablename) +{ + printf("Bridge table: %s\n\n", tablename); +} + static void nft_bridge_print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, bool basechain, uint32_t refs) { - /* FIXME: Giuseppe replace this with ebtables format */ - print_header(format, chain, pol, counters, basechain, refs); + printf("Bridge chain: %s, entries: %u, policy: %s\n", chain, refs, pol); } static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, @@ -564,6 +568,7 @@ struct nft_family_ops nft_family_ops_bridge = { .parse_payload = nft_bridge_parse_payload, .parse_immediate = nft_bridge_parse_immediate, .parse_target = nft_bridge_parse_target, + .print_table_header = nft_bridge_print_table_header, .print_header = nft_bridge_print_header, .print_firewall = nft_bridge_print_firewall, .save_firewall = NULL, -- cgit v1.2.3 From 04ff786c7a42f3ad16535fa5d7aa20346217917b Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Sat, 8 Nov 2014 22:40:37 +0100 Subject: nft-bridge: fix printing of inverted protocols, addresses Previous to this patch, no '!' is printed in payload comparisions. This patch solves it, so we can print for example inverted protocols: % ebtables-compat -L [...] -p ! 0x800 -j ACCEPT Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 0e21b468..3ed62398 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -268,15 +268,21 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, get_cmp_data(e, addr, sizeof(addr), &inv); for (i = 0; i < ETH_ALEN; i++) fw->destmac[i] = addr[i]; + if (inv) + fw->invflags |= EBT_IDEST; break; case offsetof(struct ethhdr, h_source): get_cmp_data(e, addr, sizeof(addr), &inv); for (i = 0; i < ETH_ALEN; i++) fw->sourcemac[i] = addr[i]; + if (inv) + fw->invflags |= EBT_ISOURCE; break; case offsetof(struct ethhdr, h_proto): get_cmp_data(e, ðproto, sizeof(ethproto), &inv); fw->ethproto = ethproto; + if (inv) + fw->invflags |= EBT_IPROTO; break; } } -- cgit v1.2.3 From 29b5492b339efe4635c18ac9f61873a590139c51 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Wed, 12 Nov 2014 17:10:25 +0100 Subject: nft-bridge: fix inversion of builtin matches This patch fixes inversion of builtin matches by updating the use of add_*() functions and using nft_invflags2cmp() as well. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 67 +++++++++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 42 deletions(-) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 3ed62398..b5aec001 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -64,22 +64,6 @@ static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char } } -static uint8_t ebt_to_ipt_flags(uint16_t invflags) -{ - uint8_t result = 0; - - if (invflags & EBT_IIN) - result |= IPT_INV_VIA_IN; - - if (invflags & EBT_IOUT) - result |= IPT_INV_VIA_OUT; - - if (invflags & EBT_IPROTO) - result |= IPT_INV_PROTO; - - return result; -} - static uint16_t ipt_to_ebt_flags(uint8_t invflags) { uint16_t result = 0; @@ -96,18 +80,12 @@ static uint16_t ipt_to_ebt_flags(uint8_t invflags) return result; } -static void add_logical_iniface(struct nft_rule *r, char *iface, int invflags) +static void add_logical_iniface(struct nft_rule *r, char *iface, uint32_t op) { int iface_len; - uint32_t op; iface_len = strlen(iface); - if (invflags & EBT_ILOGICALIN) - op = NFT_CMP_NEQ; - else - op = NFT_CMP_EQ; - add_meta(r, NFT_META_BRI_IIFNAME); if (iface[iface_len - 1] == '+') add_cmp_ptr(r, op, iface, iface_len - 1); @@ -115,18 +93,12 @@ static void add_logical_iniface(struct nft_rule *r, char *iface, int invflags) add_cmp_ptr(r, op, iface, iface_len + 1); } -static void add_logical_outiface(struct nft_rule *r, char *iface, int invflags) +static void add_logical_outiface(struct nft_rule *r, char *iface, uint32_t op) { int iface_len; - uint32_t op; iface_len = strlen(iface); - if (invflags & EBT_ILOGICALOUT) - op = NFT_CMP_NEQ; - else - op = NFT_CMP_EQ; - add_meta(r, NFT_META_BRI_OIFNAME); if (iface[iface_len - 1] == '+') add_cmp_ptr(r, op, iface, iface_len - 1); @@ -164,36 +136,47 @@ static int nft_bridge_add(struct nft_rule *r, void *data) { struct ebtables_command_state *cs = data; struct ebt_entry *fw = &cs->fw; - uint8_t flags = ebt_to_ipt_flags(fw->invflags); + uint32_t op; char *addr; - if (fw->in[0] != '\0') - add_iniface(r, fw->in, flags); + if (fw->in[0] != '\0') { + op = nft_invflags2cmp(fw->invflags, EBT_IIN); + add_iniface(r, fw->in, op); + } - if (fw->out[0] != '\0') - add_outiface(r, fw->out, flags); + if (fw->out[0] != '\0') { + op = nft_invflags2cmp(fw->invflags, EBT_IOUT); + add_outiface(r, fw->out, op); + } - if (fw->logical_in[0] != '\0') - add_logical_iniface(r, fw->logical_in, flags); + if (fw->logical_in[0] != '\0') { + op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN); + add_logical_iniface(r, fw->logical_in, op); + } - if (fw->logical_out[0] != '\0') - add_logical_outiface(r, fw->logical_out, flags); + if (fw->logical_out[0] != '\0') { + op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT); + add_logical_outiface(r, fw->logical_out, op); + } addr = ether_ntoa((struct ether_addr *) fw->sourcemac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { + op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); add_payload(r, offsetof(struct ethhdr, h_source), 6); - add_cmp_ptr(r, NFT_CMP_EQ, fw->sourcemac, 6); + add_cmp_ptr(r, op, fw->sourcemac, 6); } addr = ether_ntoa((struct ether_addr *) fw->destmac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { + op = nft_invflags2cmp(fw->invflags, EBT_IDEST); add_payload(r, offsetof(struct ethhdr, h_dest), 6); - add_cmp_ptr(r, NFT_CMP_EQ, fw->destmac, 6); + add_cmp_ptr(r, op, fw->destmac, 6); } if (fw->ethproto != 0) { + op = nft_invflags2cmp(fw->invflags, EBT_IPROTO); add_payload(r, offsetof(struct ethhdr, h_proto), 2); - add_cmp_u16(r, fw->ethproto, NFT_CMP_EQ); + add_cmp_u16(r, fw->ethproto, op); } return _add_action(r, cs); -- cgit v1.2.3 From 4a48ec94c233a125a371eced5dc161df557576d9 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 24 Nov 2014 10:52:04 +0100 Subject: iptables: xtables-eb: user-defined chains default policy is always RETURN The RETURN default policy is mandatory in user-defined chains. Builtin chains must have one of ACCEPT or DROP. So, with this patch, ebtables-compat ends with: Command: Result: -L Always RETURN for user-defined chains -P builtin RETURN Policy RETURN only allowed for user defined chains -P builtin ACCEPT|DROP ok -P userdefined RETURN|ACCEPT|DROP Policy XYZ not allowed for user defined chains -N userdefined ok -N userdefined -P RETURN|ACCEPT|DROP Policy XYZ not allowed for user defined chains Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index b5aec001..a1bd9065 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -356,7 +356,8 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, const struct xt_counters *counters, bool basechain, uint32_t refs) { - printf("Bridge chain: %s, entries: %u, policy: %s\n", chain, refs, pol); + printf("Bridge chain: %s, entries: %u, policy: %s\n", + chain, refs, basechain ? pol : "RETURN"); } static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, -- cgit v1.2.3 From 6aa7d1c26d0a3b0c909bbf13aa0ef6b179615433 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Wed, 17 Dec 2014 12:06:56 +0100 Subject: extensions: add ebt 802_3 extension This patch adds the first ebtables extension to ebtables-compat. The original 802_3 code is adapted to the xtables environment. I tried to mimic as much as possible the original ebtables code paths. With this patch, ebtables-compat is able to send the 802_3 match to the kernel, but the kernel-to-userspace path is not tested and should be adjusted in follow-up patches. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index a1bd9065..9772b5fe 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -135,6 +135,7 @@ static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs) static int nft_bridge_add(struct nft_rule *r, void *data) { struct ebtables_command_state *cs = data; + struct xtables_rule_match *matchp; struct ebt_entry *fw = &cs->fw; uint32_t op; char *addr; @@ -179,6 +180,11 @@ static int nft_bridge_add(struct nft_rule *r, void *data) add_cmp_u16(r, fw->ethproto, op); } + for (matchp = cs->matches; matchp; matchp = matchp->next) { + if (add_match(r, matchp->match->m) < 0) + break; + } + return _add_action(r, cs); } -- cgit v1.2.3 From 0e65c922fc0d51a8dff1a779863d4ae559aa9a4a Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Tue, 23 Dec 2014 13:24:26 +0100 Subject: ebtables-compat: fix counter listing With this patch: % sudo ebtables-compat -L --Lc Bridge table: filter Bridge chain: INPUT, entries: 0, policy: ACCEPT -j ACCEPT , pcnt = 123 -- bcnt = 123 Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 9772b5fe..807c4da0 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -470,6 +471,10 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, } } + if (!(format & FMT_NOCOUNTS)) + printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"", + (uint64_t)cs.counters.pcnt, (uint64_t)cs.counters.bcnt); + if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); } -- cgit v1.2.3 From 42cfeee024d0ba0c6b15645f829273ee3dcfa5c6 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Fri, 26 Dec 2014 13:49:52 +0100 Subject: ebtables-compat: fix printing of extension This patch fix printing of ebt extensions: % sudo ebtables-compat -L [...] Bridge chain: FORWARD, entries: 1, policy: ACCEPT --802_3-type 0x0012 -j ACCEPT [...] Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 807c4da0..90bcd63d 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -370,6 +370,7 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, unsigned int format) { + struct xtables_rule_match *matchp; struct ebtables_command_state cs = {}; char *addr; @@ -443,23 +444,13 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, print_iface(cs.fw.out); } - /* old code to adapt - m_l = hlp->m_list; - while (m_l) { - m = ebt_find_match(m_l->m->u.name); - if (!m) - ebt_print_bug("Match not found"); - m->print(hlp, m_l->m); - m_l = m_l->next; + for (matchp = cs.matches; matchp; matchp = matchp->next) { + if (matchp->match->print != NULL) { + matchp->match->print(&cs.fw, matchp->match->m, + format & FMT_NUMERIC); + } } - w_l = hlp->w_list; - while (w_l) { - w = ebt_find_watcher(w_l->w->u.name); - if (!w) - ebt_print_bug("Watcher not found"); - w->print(hlp, w_l->w); - w_l = w_l->next; - }*/ + printf("-j "); if (!(format & FMT_NOTARGET)) printf("%s", cs.jumpto); -- cgit v1.2.3 From bc543af074cf4372162eb330b914d2b0fdb6b6c7 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 5 Jan 2015 15:28:46 +0100 Subject: ebtables-compat: fix segfault in rules w/o target This patch fixes a segfault in rules without target. Now, these two rules are allowed: % ebtables-compat -A FORWARD -p 0x0600 -j CONTINUE % ebtables-compat -A FORWARD -p 0x0600 And both are printed: Bridge chain: FORWARD, entries: 1, policy: ACCEPT -p 0x600 -j CONTINUE Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 90bcd63d..fd9554eb 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -114,6 +114,9 @@ static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs) { int ret = 0; + if (cs->jumpto == NULL || strcmp(cs->jumpto, "CONTINUE") == 0) + return 0; + /* If no target at all, add nothing (default to continue) */ if (cs->target != NULL) { /* Standard target? */ @@ -452,14 +455,16 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, } printf("-j "); - if (!(format & FMT_NOTARGET)) - printf("%s", cs.jumpto); - if (cs.target != NULL) { if (cs.target->print != NULL) { cs.target->print(&cs.fw, cs.target->t, format & FMT_NUMERIC); } + } else { + if (strcmp(cs.jumpto, "") == 0) + printf("CONTINUE"); + else + printf("%s", cs.jumpto); } if (!(format & FMT_NOCOUNTS)) -- cgit v1.2.3 From 457ed5e1231cf433b239fd10ccf3d976805eb4d8 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Tue, 13 Jan 2015 18:36:10 +0100 Subject: ebtables-compat: fix ACCEPT printing by simplifying logic The commit bc543af ("ebtables-compat: fix segfault in rules w/o target") doesn't handle all possible cases of target printing, and ACCEPT is left behind. BTW, the logic of target (-j XXX) printing is a bit weird. This patch simplifies it. I assume: * cs->jumpto is only filled by nft_immediate. * cs->target is only filled by nft_target. So we end with these cases: * nft_immediate contains a 'standard' target (ACCEPT, DROP, CONTINUE, RETURN, chain) Then cs->jumpto contains the target already. We have the rule. * No standard target. If nft_target contains a target, try to load it. * Neither nft_target nor nft_immediate exist. Then, assume CONTINUE. The printing path is then straight forward: either cs.jumpto or cs.target contains the target. As there isn't support for target extensions yet, there is no way to test the nft_target (cs.target) path. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index fd9554eb..9747405e 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -337,12 +337,13 @@ void nft_rule_to_ebtables_command_state(struct nft_rule *r, nft_rule_expr_iter_destroy(iter); - if (cs->target != NULL) - cs->jumpto = cs->target->name; - else if (cs->jumpto != NULL) - cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); + if (cs->jumpto != NULL) + return; + + if (cs->target != NULL && cs->target->name != NULL) + cs->target = xtables_find_target(cs->target->name, XTF_TRY_LOAD); else - cs->jumpto = ""; + cs->jumpto = "CONTINUE"; } static void print_iface(const char *iface) @@ -455,17 +456,11 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, } printf("-j "); - if (cs.target != NULL) { - if (cs.target->print != NULL) { - cs.target->print(&cs.fw, cs.target->t, - format & FMT_NUMERIC); - } - } else { - if (strcmp(cs.jumpto, "") == 0) - printf("CONTINUE"); - else - printf("%s", cs.jumpto); - } + + if (cs.jumpto != NULL) + printf("%s", cs.jumpto); + else if (cs.target != NULL && cs.target->print != NULL) + cs.target->print(&cs.fw, cs.target->t, format & FMT_NUMERIC); if (!(format & FMT_NOCOUNTS)) printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"", -- cgit v1.2.3 From 4143a08819a076507abaee0ee18e291b65e5997c Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:27:41 +0100 Subject: ebtables-compat: add nft rule compat information to bridge rules The compat information is required by some ebtables extensions to properly work. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 9747405e..af67a5af 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -184,6 +184,8 @@ static int nft_bridge_add(struct nft_rule *r, void *data) add_cmp_u16(r, fw->ethproto, op); } + add_compat(r, fw->ethproto, fw->invflags); + for (matchp = cs->matches; matchp; matchp = matchp->next) { if (add_match(r, matchp->match->m) < 0) break; -- cgit v1.2.3 From cd414abfd21dae0288f53669672f057c0630c78a Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:27:57 +0100 Subject: ebtables-compat: include rule counters in ebtables rules Counters are missing in ebtables rules. This patch includes them just before the target, so counters are incremented when the rule is about to take his action. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index af67a5af..3ef13570 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -191,6 +191,9 @@ static int nft_bridge_add(struct nft_rule *r, void *data) break; } + if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) + return -1; + return _add_action(r, cs); } -- cgit v1.2.3 From 8acf8315a44fbee8227433daabb262b6de1e70f6 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 19 Jan 2015 14:28:02 +0100 Subject: ebtables-compat: fix nft payload bases ebtables should use NFT_PAYLOAD_LL_HEADER to fetch basic payload information from packets in the bridge family. Let's allow the add_payload() function to know in which base it should work. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 3ef13570..62aab041 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -167,20 +167,23 @@ static int nft_bridge_add(struct nft_rule *r, void *data) addr = ether_ntoa((struct ether_addr *) fw->sourcemac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); - add_payload(r, offsetof(struct ethhdr, h_source), 6); + add_payload(r, offsetof(struct ethhdr, h_source), 6, + NFT_PAYLOAD_LL_HEADER); add_cmp_ptr(r, op, fw->sourcemac, 6); } addr = ether_ntoa((struct ether_addr *) fw->destmac); if (strcmp(addr, "0:0:0:0:0:0") != 0) { op = nft_invflags2cmp(fw->invflags, EBT_IDEST); - add_payload(r, offsetof(struct ethhdr, h_dest), 6); + add_payload(r, offsetof(struct ethhdr, h_dest), 6, + NFT_PAYLOAD_LL_HEADER); add_cmp_ptr(r, op, fw->destmac, 6); } if (fw->ethproto != 0) { op = nft_invflags2cmp(fw->invflags, EBT_IPROTO); - add_payload(r, offsetof(struct ethhdr, h_proto), 2); + add_payload(r, offsetof(struct ethhdr, h_proto), 2, + NFT_PAYLOAD_LL_HEADER); add_cmp_u16(r, fw->ethproto, op); } -- cgit v1.2.3 From fe97f60e5d2a968638286036db67e3a4e17f095d Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Mon, 9 Feb 2015 13:16:12 +0100 Subject: ebtables-compat: add watchers support ebtables watchers are targets which always return EBT_CONTINUE. Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- iptables/nft-bridge.c | 86 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 9 deletions(-) (limited to 'iptables/nft-bridge.c') diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 62aab041..e3ab667f 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -22,6 +22,21 @@ #include "nft-bridge.h" #include "nft.h" +void ebt_cs_clean(struct ebtables_command_state *cs) +{ + struct ebt_match *m, *nm; + + xtables_rule_matches_free(&cs->matches); + + for (m = cs->match_list; m;) { + nm = m->next; + if (!m->ismatch) + free(m->u.watcher->t); + free(m); + m = nm; + } +} + /* 0: default, print only 2 digits if necessary * 2: always print 2 digits, a printed mac address * then always has the same length @@ -139,7 +154,7 @@ static int _add_action(struct nft_rule *r, struct ebtables_command_state *cs) static int nft_bridge_add(struct nft_rule *r, void *data) { struct ebtables_command_state *cs = data; - struct xtables_rule_match *matchp; + struct ebt_match *iter; struct ebt_entry *fw = &cs->fw; uint32_t op; char *addr; @@ -189,9 +204,14 @@ static int nft_bridge_add(struct nft_rule *r, void *data) add_compat(r, fw->ethproto, fw->invflags); - for (matchp = cs->matches; matchp; matchp = matchp->next) { - if (add_match(r, matchp->match->m) < 0) - break; + for (iter = cs->match_list; iter; iter = iter->next) { + if (iter->ismatch) { + if (add_match(r, iter->u.match->m)) + break; + } else { + if (add_target(r, iter->u.watcher->t)) + break; + } } if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) @@ -296,10 +316,44 @@ static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, cs->jumpto = jumpto; } +static void parse_watcher(void *object, struct ebt_match **match_list, + bool ismatch) +{ + struct ebt_match *m; + + m = calloc(1, sizeof(struct ebt_match)); + if (m == NULL) + xtables_error(OTHER_PROBLEM, "Can't allocate memory"); + + if (ismatch) + m->u.match = object; + else + m->u.watcher = object; + + m->ismatch = ismatch; + if (*match_list == NULL) + *match_list = m; + else + (*match_list)->next = m; +} + +static void nft_bridge_parse_match(struct xtables_match *m, void *data) +{ + struct ebtables_command_state *cs = data; + + parse_watcher(m, &cs->match_list, true); +} + static void nft_bridge_parse_target(struct xtables_target *t, void *data) { struct ebtables_command_state *cs = data; + /* harcoded names :-( */ + if (strcmp(t->name, "log") == 0) { + parse_watcher(t, &cs->match_list, false); + return; + } + cs->target = t; } @@ -382,7 +436,9 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, unsigned int format) { - struct xtables_rule_match *matchp; + struct xtables_match *matchp; + struct xtables_target *watcherp; + struct ebt_match *m; struct ebtables_command_state cs = {}; char *addr; @@ -456,10 +512,19 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, print_iface(cs.fw.out); } - for (matchp = cs.matches; matchp; matchp = matchp->next) { - if (matchp->match->print != NULL) { - matchp->match->print(&cs.fw, matchp->match->m, - format & FMT_NUMERIC); + for (m = cs.match_list; m; m = m->next) { + if (m->ismatch) { + matchp = m->u.match; + if (matchp->print != NULL) { + matchp->print(&cs.fw, matchp->m, + format & FMT_NUMERIC); + } + } else { + watcherp = m->u.watcher; + if (watcherp->print != NULL) { + watcherp->print(&cs.fw, watcherp->t, + format & FMT_NUMERIC); + } } } @@ -476,6 +541,8 @@ static void nft_bridge_print_firewall(struct nft_rule *r, unsigned int num, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); + + ebt_cs_clean(&cs); } static bool nft_bridge_is_same(const void *data_a, const void *data_b) @@ -567,6 +634,7 @@ struct nft_family_ops nft_family_ops_bridge = { .parse_meta = nft_bridge_parse_meta, .parse_payload = nft_bridge_parse_payload, .parse_immediate = nft_bridge_parse_immediate, + .parse_match = nft_bridge_parse_match, .parse_target = nft_bridge_parse_target, .print_table_header = nft_bridge_print_table_header, .print_header = nft_bridge_print_header, -- cgit v1.2.3