diff options
author | Phil Sutter <phil@nwl.cc> | 2023-04-21 15:52:14 +0200 |
---|---|---|
committer | Phil Sutter <phil@nwl.cc> | 2023-05-03 19:11:55 +0200 |
commit | 4c923250269f9ef4a7b4235f4dc127b04932a8eb (patch) | |
tree | 9a370a1990ac6c22f7c43e2b630c7bb66ee1edfb /iptables/nft-bridge.c | |
parent | 674e7c0f639f2322dcc7eee67aa9c3d52fa3ee65 (diff) |
nft: ruleparse: Create family-specific source files
Extract the remaining nftnl rule parsing code from
nft-<family>.c sources into dedicated ones to complete the separation.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Diffstat (limited to 'iptables/nft-bridge.c')
-rw-r--r-- | iptables/nft-bridge.c | 392 |
1 files changed, 0 insertions, 392 deletions
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 0c9e1238..f3dfa488 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -231,390 +231,6 @@ 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, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct ebt_entry *fw = &cs->eb; - uint8_t invflags = 0; - char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {}; - - switch (reg->meta_dreg.key) { - case NFT_META_PROTOCOL: - return; - } - - if (parse_meta(ctx, e, reg->meta_dreg.key, iifname, NULL, oifname, NULL, &invflags) < 0) { - ctx->errmsg = "unknown meta key"; - return; - } - - switch (reg->meta_dreg.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: - ctx->errmsg = "unknown bridge meta key"; - break; - } -} - -static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct ebt_entry *fw = &cs->eb; - unsigned char addr[ETH_ALEN]; - unsigned short int ethproto; - uint8_t op; - bool inv; - int i; - - switch (reg->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 (reg->bitwise.set) - memcpy(fw->destmsk, reg->bitwise.mask, ETH_ALEN); - else - memset(&fw->destmsk, 0xff, - min(reg->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 (reg->bitwise.set) - memcpy(fw->sourcemsk, reg->bitwise.mask, ETH_ALEN); - else - memset(&fw->sourcemsk, 0xff, - min(reg->payload.len, ETH_ALEN)); - fw->bitmask |= EBT_ISOURCE; - break; - case offsetof(struct ethhdr, h_proto): - __get_cmp_data(e, ðproto, sizeof(ethproto), &op); - if (ethproto == htons(0x0600)) { - fw->bitmask |= EBT_802_3; - inv = (op == NFT_CMP_GTE); - } else { - fw->ethproto = ethproto; - inv = (op == NFT_CMP_NEQ); - } - if (inv) - fw->invflags |= EBT_IPROTO; - fw->bitmask &= ~EBT_NOPROTO; - break; - default: - DEBUGP("unknown payload offset %d\n", reg->payload.offset); - ctx->errmsg = "unknown payload offset"; - 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(struct nft_xt_ctx *ctx, - enum nft_registers sreg, - uint32_t key_len, - bool *dst, bool *ip) -{ - const struct nft_xt_ctx_reg *reg; - int val, val2 = -1; - - reg = nft_xt_ctx_get_sreg(ctx, sreg); - if (!reg) - return -1; - - if (reg->type != NFT_XT_REG_PAYLOAD) { - ctx->errmsg = "lookup reg is not payload type"; - return -1; - } - - switch (key_len) { - case 12: /* ether + ipv4addr */ - val = lookup_check_ether_payload(reg->payload.base, - reg->payload.offset, - reg->payload.len); - if (val < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - reg->payload.base, reg->payload.offset, - reg->payload.len); - return -1; - } - - sreg = nft_get_next_reg(sreg, ETH_ALEN); - - reg = nft_xt_ctx_get_sreg(ctx, sreg); - if (!reg) { - ctx->errmsg = "next lookup register is invalid"; - return -1; - } - - if (reg->type != NFT_XT_REG_PAYLOAD) { - ctx->errmsg = "next lookup reg is not payload type"; - return -1; - } - - val2 = lookup_check_iphdr_payload(reg->payload.base, - reg->payload.offset, - reg->payload.len); - if (val2 < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - reg->payload.base, reg->payload.offset, - reg->payload.len); - return -1; - } else if (val != val2) { - DEBUGP("mismatching payload match offsets\n"); - return -1; - } - break; - case 6: /* ether */ - val = lookup_check_ether_payload(reg->payload.base, - reg->payload.offset, - reg->payload.len); - if (val < 0) { - DEBUGP("unknown payload base/offset/len %d/%d/%d\n", - reg->payload.base, reg->payload.offset, - reg->payload.len); - return -1; - } - break; - default: - ctx->errmsg = "unsupported lookup key length"; - 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; - - s = set_from_lookup_expr(ctx, e); - if (!s) - xtables_error(OTHER_PROBLEM, - "BUG: lookup expression references unknown set"); - - if (lookup_analyze_payloads(ctx, - nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_SREG), - nftnl_set_get_u32(s, NFTNL_SET_KEY_LEN), - &is_dst, &have_ip)) - return; - - 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->rule_parse->match != NULL) - ctx->h->ops->rule_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"); -} - -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 bool nft_rule_to_ebtables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs) @@ -984,14 +600,6 @@ static int nft_bridge_xlate(const struct iptables_command_state *cs, return ret; } -static struct nft_ruleparse_ops nft_ruleparse_ops_bridge = { - .meta = nft_bridge_parse_meta, - .payload = nft_bridge_parse_payload, - .lookup = nft_bridge_parse_lookup, - .match = nft_bridge_parse_match, - .target = nft_bridge_parse_target, -}; - struct nft_family_ops nft_family_ops_bridge = { .add = nft_bridge_add, .is_same = nft_bridge_is_same, |