diff options
Diffstat (limited to 'iptables/nft-bridge.c')
-rw-r--r-- | iptables/nft-bridge.c | 736 |
1 files changed, 236 insertions, 500 deletions
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 3f85cbbf..922ce983 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -58,135 +58,137 @@ void ebt_cs_clean(struct iptables_command_state *cs) } } -static void ebt_print_mac(const unsigned char *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) { - int j; - - for (j = 0; j < ETH_ALEN; j++) - printf("%02x%s", mac[j], (j==ETH_ALEN-1) ? "" : ":"); + if (xtables_print_well_known_mac_and_mask(mac, mask)) + xtables_print_mac_and_mask(mac, mask); } -static bool mac_all_ones(const unsigned char *mac) +static int add_meta_broute(struct nftnl_rule *r) { - static const char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct nftnl_expr *expr; - return memcmp(mac, hlpmsk, sizeof(hlpmsk)) == 0; -} + expr = nftnl_expr_alloc("immediate"); + if (expr == NULL) + return -1; -/* 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) -{ + nftnl_expr_set_u32(expr, NFTNL_EXPR_IMM_DREG, NFT_REG32_01); + nftnl_expr_set_u8(expr, NFTNL_EXPR_IMM_DATA, 1); + nftnl_rule_add_expr(r, expr); - 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 (!mac_all_ones(mask)) { - printf("/"); - ebt_print_mac(mask); - } - } + expr = nftnl_expr_alloc("meta"); + if (expr == NULL) + return -1; + nftnl_expr_set_u32(expr, NFTNL_EXPR_META_KEY, NFT_META_BRI_BROUTE); + nftnl_expr_set_u32(expr, NFTNL_EXPR_META_SREG, NFT_REG32_01); + + nftnl_rule_add_expr(r, expr); + return 0; } -static void add_logical_iniface(struct nftnl_rule *r, char *iface, uint32_t op) +static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) { - int iface_len; + const char *table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE); - iface_len = strlen(iface); + if (cs->target && + table && strcmp(table, "broute") == 0) { + if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) { + int ret = add_meta_broute(r); - 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); + if (ret) + return ret; + + cs->jumpto = "ACCEPT"; + } + } + + return add_action(r, cs, false); } -static void add_logical_outiface(struct nftnl_rule *r, char *iface, uint32_t op) +static int +nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw, + struct nft_rule_ctx *ctx, struct nftnl_rule *r, + struct xt_entry_match *m) { - int iface_len; + if (!strcmp(m->u.user.name, "802_3") && !(fw->bitmask & EBT_802_3)) + xtables_error(PARAMETER_PROBLEM, + "For 802.3 DSAP/SSAP filtering the protocol must be LENGTH"); - iface_len = strlen(iface); + if (!strcmp(m->u.user.name, "ip") && fw->ethproto != htons(ETH_P_IP)) + xtables_error(PARAMETER_PROBLEM, + "For IP filtering the protocol must be specified as IPv4."); - 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); -} + if (!strcmp(m->u.user.name, "ip6") && fw->ethproto != htons(ETH_P_IPV6)) + xtables_error(PARAMETER_PROBLEM, + "For IPv6 filtering the protocol must be specified as IPv6."); -static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) -{ - return add_action(r, cs, false); + return add_match(h, ctx, r, m); } -static int nft_bridge_add(struct nft_handle *h, - struct nftnl_rule *r, void *data) +static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx, + struct nftnl_rule *r, + struct iptables_command_state *cs) { - struct iptables_command_state *cs = data; struct ebt_match *iter; struct ebt_entry *fw = &cs->eb; uint32_t op; + if (fw->bitmask & EBT_SOURCEMAC) { + op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); + add_addr(h, r, NFT_PAYLOAD_LL_HEADER, + offsetof(struct ethhdr, h_source), + fw->sourcemac, fw->sourcemsk, ETH_ALEN, op); + } + + if (fw->bitmask & EBT_DESTMAC) { + op = nft_invflags2cmp(fw->invflags, EBT_IDEST); + add_addr(h, r, NFT_PAYLOAD_LL_HEADER, + offsetof(struct ethhdr, h_dest), + fw->destmac, fw->destmsk, ETH_ALEN, op); + } + if (fw->in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IIN); - add_iniface(r, fw->in, op); + add_iface(h, r, fw->in, NFT_META_IIFNAME, op); } if (fw->out[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_IOUT); - add_outiface(r, fw->out, op); + add_iface(h, r, fw->out, NFT_META_OIFNAME, op); } if (fw->logical_in[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN); - add_logical_iniface(r, fw->logical_in, op); + add_iface(h, r, fw->logical_in, NFT_META_BRI_IIFNAME, op); } if (fw->logical_out[0] != '\0') { op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT); - add_logical_outiface(r, fw->logical_out, op); - } - - if (fw->bitmask & EBT_ISOURCE) { - op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE); - add_payload(r, offsetof(struct ethhdr, h_source), 6, - NFT_PAYLOAD_LL_HEADER); - if (!mac_all_ones(fw->sourcemsk)) - add_bitwise(r, fw->sourcemsk, 6); - add_cmp_ptr(r, op, fw->sourcemac, 6); - } - - if (fw->bitmask & EBT_IDEST) { - op = nft_invflags2cmp(fw->invflags, EBT_IDEST); - add_payload(r, offsetof(struct ethhdr, h_dest), 6, - NFT_PAYLOAD_LL_HEADER); - if (!mac_all_ones(fw->destmsk)) - add_bitwise(r, fw->destmsk, 6); - add_cmp_ptr(r, op, fw->destmac, 6); + add_iface(h, r, fw->logical_out, NFT_META_BRI_OIFNAME, op); } if ((fw->bitmask & EBT_NOPROTO) == 0) { + uint16_t ethproto = fw->ethproto; + uint8_t reg; + op = nft_invflags2cmp(fw->invflags, EBT_IPROTO); - add_payload(r, offsetof(struct ethhdr, h_proto), 2, - NFT_PAYLOAD_LL_HEADER); - add_cmp_u16(r, fw->ethproto, op); + add_payload(h, r, offsetof(struct ethhdr, h_proto), 2, + NFT_PAYLOAD_LL_HEADER, ®); + + if (fw->bitmask & EBT_802_3) { + op = (op == NFT_CMP_EQ ? NFT_CMP_LT : NFT_CMP_GTE); + ethproto = htons(0x0600); + } + + add_cmp_u16(r, ethproto, op, reg); } add_compat(r, fw->ethproto, fw->invflags & EBT_IPROTO); for (iter = cs->match_list; iter; iter = iter->next) { if (iter->ismatch) { - if (add_match(h, r, iter->u.match->m)) + if (nft_bridge_add_match(h, fw, ctx, r, iter->u.match->m)) break; } else { if (add_target(r, iter->u.watcher->t)) @@ -200,360 +202,18 @@ static int nft_bridge_add(struct nft_handle *h, return _add_action(r, cs); } -static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) -{ - struct iptables_command_state *cs = data; - struct ebt_entry *fw = &cs->eb; - uint8_t invflags = 0; - char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; - - parse_meta(e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags); - - switch (ctx->meta.key) { - case NFT_META_BRI_IIFNAME: - if (invflags & IPT_INV_VIA_IN) - cs->eb.invflags |= EBT_ILOGICALIN; - snprintf(fw->logical_in, sizeof(fw->logical_in), "%s", iifname); - break; - case NFT_META_IIFNAME: - if (invflags & IPT_INV_VIA_IN) - cs->eb.invflags |= EBT_IIN; - snprintf(fw->in, sizeof(fw->in), "%s", iifname); - break; - case NFT_META_BRI_OIFNAME: - if (invflags & IPT_INV_VIA_OUT) - cs->eb.invflags |= EBT_ILOGICALOUT; - snprintf(fw->logical_out, sizeof(fw->logical_out), "%s", oifname); - break; - case NFT_META_OIFNAME: - if (invflags & IPT_INV_VIA_OUT) - cs->eb.invflags |= EBT_IOUT; - snprintf(fw->out, sizeof(fw->out), "%s", oifname); - break; - default: - break; - } -} - -static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) -{ - struct iptables_command_state *cs = data; - struct ebt_entry *fw = &cs->eb; - 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]; - if (inv) - fw->invflags |= EBT_IDEST; - - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - memset(&fw->destmsk, 0xff, ETH_ALEN); - } - fw->bitmask |= 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; - if (ctx->flags & NFT_XT_CTX_BITWISE) { - memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN); - ctx->flags &= ~NFT_XT_CTX_BITWISE; - } else { - memset(&fw->sourcemsk, 0xff, ETH_ALEN); - } - fw->bitmask |= 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; - fw->bitmask &= ~EBT_NOPROTO; - break; - } -} - -static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto, - void *data) -{ - struct iptables_command_state *cs = data; - - cs->jumpto = jumpto; -} - -/* return 0 if saddr, 1 if daddr, -1 on error */ -static int -lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len) -{ - if (base != 0 || len != ETH_ALEN) - return -1; - - switch (offset) { - case offsetof(struct ether_header, ether_dhost): - return 1; - case offsetof(struct ether_header, ether_shost): - return 0; - default: - return -1; - } -} - -/* return 0 if saddr, 1 if daddr, -1 on error */ -static int -lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len) -{ - if (base != 1 || len != 4) - return -1; - - switch (offset) { - case offsetof(struct iphdr, daddr): - return 1; - case offsetof(struct iphdr, saddr): - return 0; - default: - return -1; - } -} - -/* Make sure previous payload expression(s) is/are consistent and extract if - * matching on source or destination address and if matching on MAC and IP or - * only MAC address. */ -static int lookup_analyze_payloads(const struct nft_xt_ctx *ctx, - bool *dst, bool *ip) -{ - int val, val2 = -1; - - if (ctx->flags & NFT_XT_CTX_PREV_PAYLOAD) { - val = lookup_check_ether_payload(ctx->prev_payload.base, - ctx->prev_payload.offset, - ctx->prev_payload.len); - if (val < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->prev_payload.base, ctx->prev_payload.offset, - ctx->prev_payload.len); - return -1; - } - if (!(ctx->flags & NFT_XT_CTX_PAYLOAD)) { - DEBUGP("Previous but no current payload?\n"); - return -1; - } - val2 = lookup_check_iphdr_payload(ctx->payload.base, - ctx->payload.offset, - ctx->payload.len); - if (val2 < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->payload.base, ctx->payload.offset, - ctx->payload.len); - return -1; - } else if (val != val2) { - DEBUGP("mismatching payload match offsets\n"); - return -1; - } - } else if (ctx->flags & NFT_XT_CTX_PAYLOAD) { - val = lookup_check_ether_payload(ctx->payload.base, - ctx->payload.offset, - ctx->payload.len); - if (val < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - ctx->payload.base, ctx->payload.offset, - ctx->payload.len); - return -1; - } - } else { - DEBUGP("unknown LHS of lookup expression\n"); - return -1; - } - - if (dst) - *dst = (val == 1); - if (ip) - *ip = (val2 != -1); - return 0; -} - -static int set_elems_to_among_pairs(struct nft_among_pair *pairs, - const struct nftnl_set *s, int cnt) -{ - struct nftnl_set_elems_iter *iter = nftnl_set_elems_iter_create(s); - struct nftnl_set_elem *elem; - size_t tmpcnt = 0; - const void *data; - uint32_t datalen; - int ret = -1; - - if (!iter) { - fprintf(stderr, "BUG: set elems iter allocation failed\n"); - return ret; - } - - while ((elem = nftnl_set_elems_iter_next(iter))) { - data = nftnl_set_elem_get(elem, NFTNL_SET_ELEM_KEY, &datalen); - if (!data) { - fprintf(stderr, "BUG: set elem without key\n"); - goto err; - } - if (datalen > sizeof(*pairs)) { - fprintf(stderr, "BUG: overlong set elem\n"); - goto err; - } - nft_among_insert_pair(pairs, &tmpcnt, data); - } - ret = 0; -err: - nftnl_set_elems_iter_destroy(iter); - return ret; -} - -static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx, - const struct nftnl_expr *e) -{ - const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET); - struct nftnl_set_list *slist; - - slist = nft_set_list_get(ctx->h, ctx->table, set_name); - if (slist) - return nftnl_set_list_lookup_byname(slist, set_name); - - return NULL; -} - -static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, - struct nftnl_expr *e, void *data) -{ - struct xtables_match *match = NULL; - struct nft_among_data *among_data; - bool is_dst, have_ip, inv; - struct ebt_match *ematch; - struct nftnl_set *s; - size_t poff, size; - uint32_t cnt; - - if (lookup_analyze_payloads(ctx, &is_dst, &have_ip)) - return; - - s = set_from_lookup_expr(ctx, e); - if (!s) - xtables_error(OTHER_PROBLEM, - "BUG: lookup expression references unknown set"); - - cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE); - - for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) { - if (!ematch->ismatch || strcmp(ematch->u.match->name, "among")) - continue; - - match = ematch->u.match; - among_data = (struct nft_among_data *)match->m->data; - - size = cnt + among_data->src.cnt + among_data->dst.cnt; - size *= sizeof(struct nft_among_pair); - - size += XT_ALIGN(sizeof(struct xt_entry_match)) + - sizeof(struct nft_among_data); - - match->m = xtables_realloc(match->m, size); - break; - } - if (!match) { - match = xtables_find_match("among", XTF_TRY_LOAD, - &ctx->cs->matches); - - size = cnt * sizeof(struct nft_among_pair); - size += XT_ALIGN(sizeof(struct xt_entry_match)) + - sizeof(struct nft_among_data); - - match->m = xtables_calloc(1, size); - strcpy(match->m->u.user.name, match->name); - match->m->u.user.revision = match->revision; - xs_init_match(match); - - if (ctx->h->ops->parse_match != NULL) - ctx->h->ops->parse_match(match, ctx->cs); - } - if (!match) - return; - - match->m->u.match_size = size; - - inv = !!(nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_FLAGS) & - NFT_LOOKUP_F_INV); - - among_data = (struct nft_among_data *)match->m->data; - poff = nft_among_prepare_data(among_data, is_dst, cnt, inv, have_ip); - if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt)) - xtables_error(OTHER_PROBLEM, - "ebtables among pair parsing failed"); - - ctx->flags &= ~(NFT_XT_CTX_PAYLOAD | NFT_XT_CTX_PREV_PAYLOAD); -} - -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 iptables_command_state *cs = data; - - parse_watcher(m, &cs->match_list, true); -} - -static void nft_bridge_parse_target(struct xtables_target *t, void *data) -{ - struct iptables_command_state *cs = data; - - /* harcoded names :-( */ - if (strcmp(t->name, "log") == 0 || - strcmp(t->name, "nflog") == 0) { - parse_watcher(t, &cs->match_list, false); - return; - } - - cs->target = t; -} - -static void nft_rule_to_ebtables_command_state(struct nft_handle *h, +static bool nft_rule_to_ebtables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs) { cs->eb.bitmask = EBT_NOPROTO; - nft_rule_to_iptables_command_state(h, r, cs); + return nft_rule_to_iptables_command_state(h, r, cs); } static void print_iface(const char *option, const char *name, bool invert) { if (*name) - printf("%s%s %s ", option, invert ? " !" : "", name); + printf("%s%s %s ", invert ? "! " : "", option, name); } static void nft_bridge_print_table_header(const char *tablename) @@ -564,7 +224,7 @@ static void nft_bridge_print_table_header(const char *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, uint32_t entries) + int refs, uint32_t entries) { printf("Bridge chain: %s, entries: %u, policy: %s\n", chain, entries, pol ?: "RETURN"); @@ -598,9 +258,7 @@ static void print_mac(char option, const unsigned char *mac, const unsigned char *mask, bool invert) { - printf("-%c ", option); - if (invert) - printf("! "); + printf("%s-%c ", invert ? "! " : "", option); ebt_print_mac_and_mask(mac, mask); printf(" "); } @@ -615,12 +273,10 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) if (bitmask & EBT_NOPROTO) return; - printf("-p "); - if (invert) - printf("! "); + printf("%s-p ", invert ? "! " : ""); if (bitmask & EBT_802_3) { - printf("length "); + printf("Length "); return; } @@ -631,11 +287,10 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) printf("%s ", ent->e_name); } -static void nft_bridge_save_rule(const void *data, unsigned int format) +static void __nft_bridge_save_rule(const struct iptables_command_state *cs, + unsigned int format) { - const struct iptables_command_state *cs = data; - - if (cs->eb.ethproto) + if (!(cs->eb.bitmask & EBT_NOPROTO)) print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO, cs->eb.bitmask); if (cs->eb.bitmask & EBT_ISOURCE) @@ -682,16 +337,23 @@ static void nft_bridge_save_rule(const void *data, unsigned int format) fputc('\n', stdout); } +static void nft_bridge_save_rule(const struct iptables_command_state *cs, + unsigned int format) +{ + printf(" "); + __nft_bridge_save_rule(cs, format); +} + static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r, unsigned int num, unsigned int format) { struct iptables_command_state cs = {}; if (format & FMT_LINENUMBERS) - printf("%d ", num); + printf("%d. ", num); nft_rule_to_ebtables_command_state(h, r, &cs); - nft_bridge_save_rule(&cs, format); + __nft_bridge_save_rule(&cs, format); ebt_cs_clean(&cs); } @@ -703,10 +365,11 @@ static void nft_bridge_save_chain(const struct nftnl_chain *c, printf(":%s %s\n", chain, policy ?: "ACCEPT"); } -static bool nft_bridge_is_same(const void *data_a, const void *data_b) +static bool nft_bridge_is_same(const struct iptables_command_state *cs_a, + const struct iptables_command_state *cs_b) { - const struct ebt_entry *a = data_a; - const struct ebt_entry *b = data_b; + const struct ebt_entry *a = &cs_a->eb; + const struct ebt_entry *b = &cs_b->eb; int i; if (a->ethproto != b->ethproto || @@ -747,41 +410,6 @@ static bool nft_bridge_is_same(const void *data_a, const void *data_b) return strcmp(a->in, b->in) == 0 && strcmp(a->out, b->out) == 0; } -static bool nft_bridge_rule_find(struct nft_handle *h, struct nftnl_rule *r, - void *data) -{ - struct iptables_command_state *cs = data; - struct iptables_command_state this = {}; - bool ret = false; - - nft_rule_to_ebtables_command_state(h, r, &this); - - DEBUGP("comparing with... "); - - if (!nft_bridge_is_same(cs, &this)) - goto out; - - if (!compare_matches(cs->matches, this.matches)) { - DEBUGP("Different matches\n"); - goto out; - } - - if (!compare_targets(cs->target, this.target)) { - DEBUGP("Different target\n"); - goto out; - } - - if (cs->jumpto != NULL && strcmp(cs->jumpto, this.jumpto) != 0) { - DEBUGP("Different verdict\n"); - goto out; - } - - ret = true; -out: - h->ops->clear_cs(&this); - return ret; -} - static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xlate *xl) { int ret = 1, numeric = cs->options & OPT_NUMERIC; @@ -793,7 +421,6 @@ static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xl struct xt_xlate_mt_params mt_params = { .ip = (const void *)&cs->eb, .numeric = numeric, - .escape_quotes = false, .match = matchp->m, }; @@ -806,7 +433,6 @@ static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xl struct xt_xlate_tg_params wt_params = { .ip = (const void *)&cs->eb, .numeric = numeric, - .escape_quotes = false, .target = watcherp->t, }; @@ -837,7 +463,6 @@ static int xlate_ebaction(const struct iptables_command_state *cs, struct xt_xla else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) xt_xlate_add(xl, " return"); else if (cs->target->xlate) { - xt_xlate_add(xl, " "); struct xt_xlate_tg_params params = { .ip = (const void *)&cs->eb, .target = cs->target->t, @@ -871,25 +496,23 @@ static void nft_bridge_xlate_mac(struct xt_xlate *xl, const char *type, bool inv xt_xlate_add(xl, "ether %s %s", type, invert ? "!= " : ""); - xlate_mac(xl, mac); - if (memcmp(mask, one_msk, ETH_ALEN)) { int i; - xt_xlate_add(xl, " and "); + xt_xlate_add(xl, "and"); xlate_mac(xl, mask); xt_xlate_add(xl, " == %02x", mac[0] & mask[0]); for (i=1; i < ETH_ALEN; i++) xt_xlate_add(xl, ":%02x", mac[i] & mask[i]); + } else { + xlate_mac(xl, mac); } - - xt_xlate_add(xl, " "); } -static int nft_bridge_xlate(const void *data, struct xt_xlate *xl) +static int nft_bridge_xlate(const struct iptables_command_state *cs, + struct xt_xlate *xl) { - const struct iptables_command_state *cs = data; int ret; xlate_ifname(xl, "iifname", cs->eb.in, @@ -901,7 +524,10 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl) xlate_ifname(xl, "meta obrname", cs->eb.logical_out, cs->eb.invflags & EBT_ILOGICALOUT); - if ((cs->eb.bitmask & EBT_NOPROTO) == 0) { + if (cs->eb.bitmask & EBT_802_3) { + xt_xlate_add(xl, "ether type %s 0x0600 ", + cs->eb.invflags & EBT_IPROTO ? ">=" : "<"); + } else if ((cs->eb.bitmask & EBT_NOPROTO) == 0) { const char *implicit = NULL; switch (ntohs(cs->eb.ethproto)) { @@ -924,9 +550,6 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl) ntohs(cs->eb.ethproto)); } - if (cs->eb.bitmask & EBT_802_3) - return 0; - if (cs->eb.bitmask & EBT_ISOURCE) nft_bridge_xlate_mac(xl, "saddr", cs->eb.invflags & EBT_ISOURCE, cs->eb.sourcemac, cs->eb.sourcemsk); @@ -944,25 +567,138 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl) return ret; } +static const char *nft_bridge_option_name(int option) +{ + switch (option) { + /* ebtables specific ones */ + case OPT_LOGICALIN: return "--logical-in"; + case OPT_LOGICALOUT: return "--logical-out"; + case OPT_LINENUMBERS: return "--Ln"; + case OPT_LIST_C: return "--Lc"; + case OPT_LIST_X: return "--Lx"; + case OPT_LIST_MAC2: return "--Lmac2"; + default: return ip46t_option_name(option); + } +} + +static int nft_bridge_option_invert(int option) +{ + switch (option) { + case OPT_SOURCE: return EBT_ISOURCE; + case OPT_DESTINATION: return EBT_IDEST; + case OPT_PROTOCOL: return EBT_IPROTO; + case OPT_VIANAMEIN: return EBT_IIN; + case OPT_VIANAMEOUT: return EBT_IOUT; + case OPT_LOGICALIN: return EBT_ILOGICALIN; + case OPT_LOGICALOUT: return EBT_ILOGICALOUT; + default: return -1; + } +} + +static void nft_bridge_proto_parse(struct iptables_command_state *cs, + struct xtables_args *args) +{ + char *buffer; + int i; + + cs->eb.bitmask &= ~((unsigned int)EBT_NOPROTO); + + i = strtol(cs->protocol, &buffer, 16); + if (*buffer == '\0' && (i < 0 || i > 0xFFFF)) + xtables_error(PARAMETER_PROBLEM, + "Problem with the specified protocol"); + if (*buffer != '\0') { + struct xt_ethertypeent *ent; + + if (!strcmp(cs->protocol, "length")) { + cs->eb.bitmask |= EBT_802_3; + return; + } + ent = xtables_getethertypebyname(cs->protocol); + if (!ent) + xtables_error(PARAMETER_PROBLEM, + "Problem with the specified Ethernet protocol '%s', perhaps "XT_PATH_ETHERTYPES " is missing", + cs->protocol); + cs->eb.ethproto = ent->e_ethertype; + } else + cs->eb.ethproto = i; + + if (cs->eb.ethproto < 0x0600) + xtables_error(PARAMETER_PROBLEM, + "Sorry, protocols have values above or equal to 0x0600"); +} + +static void nft_bridge_post_parse(int command, + struct iptables_command_state *cs, + struct xtables_args *args) +{ + struct ebt_match *match; + + cs->eb.invflags = args->invflags; + + memcpy(cs->eb.in, args->iniface, IFNAMSIZ); + memcpy(cs->eb.out, args->outiface, IFNAMSIZ); + memcpy(cs->eb.logical_in, args->bri_iniface, IFNAMSIZ); + memcpy(cs->eb.logical_out, args->bri_outiface, IFNAMSIZ); + + cs->counters.pcnt = args->pcnt_cnt; + cs->counters.bcnt = args->bcnt_cnt; + + if (args->shostnetworkmask) { + if (xtables_parse_mac_and_mask(args->shostnetworkmask, + cs->eb.sourcemac, + cs->eb.sourcemsk)) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified source mac '%s'", + args->shostnetworkmask); + cs->eb.bitmask |= EBT_SOURCEMAC; + } + if (args->dhostnetworkmask) { + if (xtables_parse_mac_and_mask(args->dhostnetworkmask, + cs->eb.destmac, + cs->eb.destmsk)) + xtables_error(PARAMETER_PROBLEM, + "Problem with specified destination mac '%s'", + args->dhostnetworkmask); + cs->eb.bitmask |= EBT_DESTMAC; + } + + if ((cs->options & (OPT_LIST_X | OPT_LINENUMBERS)) == + (OPT_LIST_X | OPT_LINENUMBERS)) + xtables_error(PARAMETER_PROBLEM, + "--Lx is not compatible with --Ln"); + + /* So, the extensions can work with the host endian. + * The kernel does not have to do this of course */ + cs->eb.ethproto = htons(cs->eb.ethproto); + + for (match = cs->match_list; match; match = match->next) { + if (match->ismatch) + continue; + + xtables_option_tfcall(match->u.watcher); + } +} + 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, - .parse_lookup = nft_bridge_parse_lookup, - .parse_match = nft_bridge_parse_match, - .parse_target = nft_bridge_parse_target, + .rule_parse = &nft_ruleparse_ops_bridge, + .cmd_parse = { + .proto_parse = nft_bridge_proto_parse, + .post_parse = nft_bridge_post_parse, + .option_name = nft_bridge_option_name, + .option_invert = nft_bridge_option_invert, + .command_default = ebt_command_default, + .print_help = nft_bridge_print_help, + }, .print_table_header = nft_bridge_print_table_header, .print_header = nft_bridge_print_header, .print_rule = nft_bridge_print_rule, .save_rule = nft_bridge_save_rule, - .save_counters = save_counters, .save_chain = nft_bridge_save_chain, - .post_parse = NULL, .rule_to_cs = nft_rule_to_ebtables_command_state, .clear_cs = ebt_cs_clean, - .rule_find = nft_bridge_rule_find, .xlate = nft_bridge_xlate, }; |