diff options
Diffstat (limited to 'iptables/nft-bridge.c')
-rw-r--r-- | iptables/nft-bridge.c | 639 |
1 files changed, 220 insertions, 419 deletions
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 106bcc72..1623acba 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -46,6 +46,7 @@ void ebt_cs_clean(struct iptables_command_state *cs) free(m); m = nm; } + cs->match_list = NULL; if (cs->target) { free(cs->target->t); @@ -65,42 +66,68 @@ static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char xtables_print_mac_and_mask(mac, mask); } -static void add_logical_iniface(struct nft_handle *h, struct nftnl_rule *r, - char *iface, uint32_t op) +static int add_meta_broute(struct nftnl_rule *r) { - int iface_len; - uint8_t reg; + struct nftnl_expr *expr; - iface_len = strlen(iface); + expr = nftnl_expr_alloc("immediate"); + if (expr == NULL) + return -1; - add_meta(h, r, NFT_META_BRI_IIFNAME, ®); - if (iface[iface_len - 1] == '+') - add_cmp_ptr(r, op, iface, iface_len - 1, reg); - else - add_cmp_ptr(r, op, iface, iface_len + 1, reg); + 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); + + 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_outiface(struct nft_handle *h, 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; - uint8_t reg; + 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(h, r, NFT_META_BRI_OIFNAME, ®); - if (iface[iface_len - 1] == '+') - add_cmp_ptr(r, op, iface, iface_len - 1, reg); - else - add_cmp_ptr(r, op, iface, iface_len + 1, reg); + if (ret) + return ret; + + cs->jumpto = "ACCEPT"; + } + } + + return add_action(r, cs, false); } -static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs) +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) { - return add_action(r, cs, false); + 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"); + + 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."); + + 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."); + + return add_match(h, ctx, r, m); } -static int nft_bridge_add(struct nft_handle *h, +static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx, struct nftnl_rule *r, struct iptables_command_state *cs) { @@ -108,54 +135,61 @@ static int nft_bridge_add(struct nft_handle *h, 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(h, 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(h, 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(h, 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(h, r, fw->logical_out, op); - } - - if (fw->bitmask & EBT_ISOURCE) { - 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_IDEST) { - 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); + 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(h, r, offsetof(struct ethhdr, h_proto), 2, NFT_PAYLOAD_LL_HEADER, ®); - add_cmp_u16(r, fw->ethproto, op, reg); + + 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)) @@ -169,358 +203,15 @@ 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, - struct iptables_command_state *cs) -{ - struct ebt_entry *fw = &cs->eb; - uint8_t invflags = 0; - char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; - - parse_meta(ctx, 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, - struct iptables_command_state *cs) -{ - 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, - min(ctx->payload.len, 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, - min(ctx->payload.len, 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; - } -} - -/* 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); - uint32_t set_id = nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SET_ID); - struct nftnl_set_list *slist; - struct nftnl_set *set; - - slist = nft_set_list_get(ctx->h, ctx->table, set_name); - if (slist) { - set = nftnl_set_list_lookup_byname(slist, set_name); - if (set) - return set; - - set = nft_set_batch_lookup_byid(ctx->h, set_id); - if (set) - return set; - } - - return NULL; -} - -static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx, - struct nftnl_expr *e) -{ - 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 = xtables_calloc(1, sizeof(struct ebt_match)); - - 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, - struct iptables_command_state *cs) -{ - parse_watcher(m, &cs->match_list, true); -} - -static void nft_bridge_parse_target(struct xtables_target *t, - struct iptables_command_state *cs) -{ - /* harcoded names :-( */ - if (strcmp(t->name, "log") == 0 || - strcmp(t->name, "nflog") == 0) { - parse_watcher(t, &cs->match_list, false); - return; - } - - cs->target = t; - cs->jumpto = t->name; -} - -static void nft_rule_to_ebtables_command_state(struct nft_handle *h, - const struct nftnl_rule *r, - struct iptables_command_state *cs) +static void nft_bridge_init_cs(struct iptables_command_state *cs) { cs->eb.bitmask = EBT_NOPROTO; - 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); + if (*name && (strcmp(name, "+") || invert)) + printf("%s%s %s ", invert ? "! " : "", option, name); } static void nft_bridge_print_table_header(const char *tablename) @@ -565,9 +256,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(" "); } @@ -582,12 +271,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; } @@ -601,7 +288,7 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask) static void __nft_bridge_save_rule(const struct iptables_command_state *cs, unsigned int format) { - 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) @@ -661,9 +348,10 @@ static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r, 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_init_cs(&cs); + nft_rule_to_iptables_command_state(h, r, &cs); __nft_bridge_save_rule(&cs, format); ebt_cs_clean(&cs); } @@ -684,9 +372,9 @@ static bool nft_bridge_is_same(const struct iptables_command_state *cs_a, int i; if (a->ethproto != b->ethproto || - /* FIXME: a->flags != b->flags || */ + a->bitmask != b->bitmask || a->invflags != b->invflags) { - DEBUGP("different proto/flags/invflags\n"); + DEBUGP("different proto/bitmask/invflags\n"); return false; } @@ -732,7 +420,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, }; @@ -745,7 +432,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, }; @@ -776,7 +462,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, @@ -810,20 +495,18 @@ 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 struct iptables_command_state *cs, @@ -840,7 +523,10 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, 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)) { @@ -863,9 +549,6 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, 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); @@ -883,21 +566,139 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, 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_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_chain = nft_bridge_save_chain, - .rule_to_cs = nft_rule_to_ebtables_command_state, + .rule_to_cs = nft_rule_to_iptables_command_state, + .init_cs = nft_bridge_init_cs, .clear_cs = ebt_cs_clean, .xlate = nft_bridge_xlate, }; |