diff options
Diffstat (limited to 'iptables/nft-ipv6.c')
-rw-r--r-- | iptables/nft-ipv6.c | 155 |
1 files changed, 39 insertions, 116 deletions
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 05d65fbb..b184f8af 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -25,28 +25,13 @@ #include "nft.h" #include "nft-shared.h" -static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, - struct iptables_command_state *cs) +static int nft_ipv6_add(struct nft_handle *h, struct nft_rule_ctx *ctx, + struct nftnl_rule *r, struct iptables_command_state *cs) { struct xtables_rule_match *matchp; uint32_t op; int ret; - if (cs->fw6.ipv6.iniface[0] != '\0') { - op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN); - add_iniface(h, r, cs->fw6.ipv6.iniface, op); - } - - if (cs->fw6.ipv6.outiface[0] != '\0') { - op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT); - add_outiface(h, r, cs->fw6.ipv6.outiface, op); - } - - if (cs->fw6.ipv6.proto != 0) { - op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO); - add_l4proto(h, r, cs->fw6.ipv6.proto, op); - } - if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src) || !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) || (cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) { @@ -56,6 +41,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk, sizeof(struct in6_addr), op); } + if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst) || !IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) || (cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) { @@ -65,10 +51,26 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk, sizeof(struct in6_addr), op); } + + if (cs->fw6.ipv6.iniface[0] != '\0') { + op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_IN); + add_iface(h, r, cs->fw6.ipv6.iniface, NFT_META_IIFNAME, op); + } + + if (cs->fw6.ipv6.outiface[0] != '\0') { + op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_VIA_OUT); + add_iface(h, r, cs->fw6.ipv6.outiface, NFT_META_OIFNAME, op); + } + + if (cs->fw6.ipv6.proto != 0) { + op = nft_invflags2cmp(cs->fw6.ipv6.invflags, XT_INV_PROTO); + add_l4proto(h, r, cs->fw6.ipv6.proto, op); + } + add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO); for (matchp = cs->matches; matchp; matchp = matchp->next) { - ret = add_match(h, r, matchp->match->m); + ret = add_match(h, ctx, r, matchp->match->m); if (ret < 0) return ret; } @@ -104,80 +106,6 @@ static bool nft_ipv6_is_same(const struct iptables_command_state *a, b->fw6.ipv6.outiface_mask); } -static void nft_ipv6_parse_meta(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - switch (reg->meta_dreg.key) { - case NFT_META_L4PROTO: - cs->fw6.ipv6.proto = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); - if (nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP) == NFT_CMP_NEQ) - cs->fw6.ipv6.invflags |= XT_INV_PROTO; - return; - default: - break; - } - - parse_meta(ctx, e, reg->meta_dreg.key, cs->fw6.ipv6.iniface, - cs->fw6.ipv6.iniface_mask, cs->fw6.ipv6.outiface, - cs->fw6.ipv6.outiface_mask, &cs->fw6.ipv6.invflags); -} - -static void parse_mask_ipv6(const struct nft_xt_ctx_reg *reg, - struct in6_addr *mask) -{ - memcpy(mask, reg->bitwise.mask, sizeof(struct in6_addr)); -} - -static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, - const struct nft_xt_ctx_reg *reg, - struct nftnl_expr *e, - struct iptables_command_state *cs) -{ - struct in6_addr addr; - uint8_t proto; - bool inv; - - switch (reg->payload.offset) { - case offsetof(struct ip6_hdr, ip6_src): - get_cmp_data(e, &addr, sizeof(addr), &inv); - memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr)); - if (reg->bitwise.set) - parse_mask_ipv6(reg, &cs->fw6.ipv6.smsk); - else - memset(&cs->fw6.ipv6.smsk, 0xff, - min(reg->payload.len, sizeof(struct in6_addr))); - - if (inv) - cs->fw6.ipv6.invflags |= IP6T_INV_SRCIP; - break; - case offsetof(struct ip6_hdr, ip6_dst): - get_cmp_data(e, &addr, sizeof(addr), &inv); - memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr)); - if (reg->bitwise.set) - parse_mask_ipv6(reg, &cs->fw6.ipv6.dmsk); - else - memset(&cs->fw6.ipv6.dmsk, 0xff, - min(reg->payload.len, sizeof(struct in6_addr))); - - if (inv) - cs->fw6.ipv6.invflags |= IP6T_INV_DSTIP; - break; - case offsetof(struct ip6_hdr, ip6_nxt): - get_cmp_data(e, &proto, sizeof(proto), &inv); - cs->fw6.ipv6.proto = proto; - if (inv) - cs->fw6.ipv6.invflags |= IP6T_INV_PROTO; - case offsetof(struct ip6_hdr, ip6_hlim): - nft_parse_hl(ctx, e, cs); - break; - default: - DEBUGP("unknown payload offset %d\n", ctx->payload.offset); - break; - } -} - static void nft_ipv6_set_goto_flag(struct iptables_command_state *cs) { cs->fw6.ipv6.flags |= IP6T_F_GOTO; @@ -208,7 +136,7 @@ static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); - nft_clear_iptables_command_state(&cs); + xtables_clear_iptables_command_state(&cs); } static void nft_ipv6_save_rule(const struct iptables_command_state *cs, @@ -219,8 +147,7 @@ static void nft_ipv6_save_rule(const struct iptables_command_state *cs, save_ipv6_addr('d', &cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk, cs->fw6.ipv6.invflags & IP6T_INV_DSTIP); - save_rule_details(cs->fw6.ipv6.iniface, cs->fw6.ipv6.iniface_mask, - cs->fw6.ipv6.outiface, cs->fw6.ipv6.outiface_mask, + save_rule_details(cs->fw6.ipv6.iniface, cs->fw6.ipv6.outiface, cs->fw6.ipv6.proto, 0, cs->fw6.ipv6.invflags); save_matches_and_target(cs, cs->fw6.ipv6.flags & IP6T_F_GOTO, @@ -257,6 +184,7 @@ static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr, static int nft_ipv6_xlate(const struct iptables_command_state *cs, struct xt_xlate *xl) { + uint16_t proto = cs->fw6.ipv6.proto; const char *comment; int ret; @@ -265,23 +193,16 @@ static int nft_ipv6_xlate(const struct iptables_command_state *cs, xlate_ifname(xl, "oifname", cs->fw6.ipv6.outiface, cs->fw6.ipv6.invflags & IP6T_INV_VIA_OUT); - if (cs->fw6.ipv6.proto != 0) { - const struct protoent *pent = - getprotobynumber(cs->fw6.ipv6.proto); - char protonum[sizeof("65535")]; - const char *name = protonum; - - snprintf(protonum, sizeof(protonum), "%u", - cs->fw6.ipv6.proto); - - if (!pent || !xlate_find_match(cs, pent->p_name)) { - if (pent) - name = pent->p_name; - xt_xlate_add(xl, "meta l4proto %s%s ", - cs->fw6.ipv6.invflags & IP6T_INV_PROTO ? - "!= " : "", name); - } + if (proto != 0 && !xlate_find_protomatch(cs, proto)) { + const char *pname = proto_to_name(proto, 0); + xt_xlate_add(xl, "meta l4proto"); + if (cs->fw6.ipv6.invflags & IP6T_INV_PROTO) + xt_xlate_add(xl, " !="); + if (pname) + xt_xlate_add(xl, "%s", pname); + else + xt_xlate_add(xl, "%hu", proto); } xlate_ipv6_addr("ip6 saddr", &cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk, @@ -326,7 +247,7 @@ nft_ipv6_add_entry(struct nft_handle *h, &args->d.mask.v6[j], sizeof(struct in6_addr)); if (append) { ret = nft_cmd_rule_append(h, chain, table, - cs, NULL, verbose); + cs, verbose); } else { ret = nft_cmd_rule_insert(h, chain, table, cs, rulenum, verbose); @@ -407,20 +328,22 @@ nft_ipv6_replace_entry(struct nft_handle *h, struct nft_family_ops nft_family_ops_ipv6 = { .add = nft_ipv6_add, .is_same = nft_ipv6_is_same, - .parse_meta = nft_ipv6_parse_meta, - .parse_payload = nft_ipv6_parse_payload, .set_goto_flag = nft_ipv6_set_goto_flag, .print_header = print_header, .print_rule = nft_ipv6_print_rule, .save_rule = nft_ipv6_save_rule, .save_chain = nft_ipv46_save_chain, + .rule_parse = &nft_ruleparse_ops_ipv6, .cmd_parse = { .proto_parse = ipv6_proto_parse, .post_parse = ipv6_post_parse, + .option_name = ip46t_option_name, + .option_invert = ip46t_option_invert, + .command_default = command_default, + .print_help = xtables_printhelp, }, - .parse_target = nft_ipv46_parse_target, .rule_to_cs = nft_rule_to_iptables_command_state, - .clear_cs = nft_clear_iptables_command_state, + .clear_cs = xtables_clear_iptables_command_state, .xlate = nft_ipv6_xlate, .add_entry = nft_ipv6_add_entry, .delete_entry = nft_ipv6_delete_entry, |