Complete masquerading support by allowing port range selection.
Unified · Split
| @@ -2,7 +2,9 @@ · 1 unmodified line | |||
| 2 | #define _NFT_MASQ_H_ | 2 | #define _NFT_MASQ_H_ |
| 3 | 3 | ||
| 4 | struct nft_masq { | 4 | struct nft_masq { |
| 5 | u32 flags; | 5 | u32 flags; |
| 6 | enum nft_registers sreg_proto_min:8; | ||
| 7 | enum nft_registers sreg_proto_max:8; | ||
| 6 | }; | 8 | }; |
| 7 | 9 | ||
| 8 | extern const struct nla_policy nft_masq_policy[]; | 10 | extern const struct nla_policy nft_masq_policy[]; |
| @@ -951,10 +951,14 @@ enum nft_nat_attributes { · 950 unmodified lines | |||
| 951 | * enum nft_masq_attributes - nf_tables masquerade expression attributes | 951 | * enum nft_masq_attributes - nf_tables masquerade expression attributes |
| 952 | * | 952 | * |
| 953 | * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) | 953 | * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) |
| 954 | * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) | ||
| 955 | * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) | ||
| 954 | */ | 956 | */ |
| 955 | enum nft_masq_attributes { | 957 | enum nft_masq_attributes { |
| 956 | NFTA_MASQ_UNSPEC, | 958 | NFTA_MASQ_UNSPEC, |
| 957 | NFTA_MASQ_FLAGS, | 959 | NFTA_MASQ_FLAGS, |
| 960 | NFTA_MASQ_REG_PROTO_MIN, | ||
| 961 | NFTA_MASQ_REG_PROTO_MAX, | ||
| 958 | __NFTA_MASQ_MAX | 962 | __NFTA_MASQ_MAX |
| 959 | }; | 963 | }; |
| 960 | #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) | 964 | #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) |
| @@ -25,7 +25,12 @@ static void nft_masq_ipv4_eval(const struct nft_expr *expr, · 24 unmodified lines | |||
| 25 | 25 | ||
| 26 | memset(&range, 0, sizeof(range)); | 26 | memset(&range, 0, sizeof(range)); |
| 27 | range.flags = priv->flags; | 27 | range.flags = priv->flags; |
| 28 | 28 | if (priv->sreg_proto_min) { | |
| 29 | range.min_proto.all = | ||
| 30 | *(__be16 *)®s->data[priv->sreg_proto_min]; | ||
| 31 | range.max_proto.all = | ||
| 32 | *(__be16 *)®s->data[priv->sreg_proto_max]; | ||
| 33 | } | ||
| 29 | regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->hook, | 34 | regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->hook, |
| 30 | &range, pkt->out); | 35 | &range, pkt->out); |
| 31 | } | 36 | } |
| @@ -26,7 +26,12 @@ static void nft_masq_ipv6_eval(const struct nft_expr *expr, · 25 unmodified lines | |||
| 26 | 26 | ||
| 27 | memset(&range, 0, sizeof(range)); | 27 | memset(&range, 0, sizeof(range)); |
| 28 | range.flags = priv->flags; | 28 | range.flags = priv->flags; |
| 29 | 29 | if (priv->sreg_proto_min) { | |
| 30 | range.min_proto.all = | ||
| 31 | *(__be16 *)®s->data[priv->sreg_proto_min]; | ||
| 32 | range.max_proto.all = | ||
| 33 | *(__be16 *)®s->data[priv->sreg_proto_max]; | ||
| 34 | } | ||
| 30 | regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out); | 35 | regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out); |
| 31 | } | 36 | } |
| 32 | 37 | ||
| @@ -17,7 +17,9 @@ · 16 unmodified lines | |||
| 17 | #include <net/netfilter/nft_masq.h> | 17 | #include <net/netfilter/nft_masq.h> |
| 18 | 18 | ||
| 19 | const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { | 19 | const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { |
| 20 | [NFTA_MASQ_FLAGS] = { .type = NLA_U32 }, | 20 | [NFTA_MASQ_FLAGS] = { .type = NLA_U32 }, |
| 21 | [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, | ||
| 22 | [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, | ||
| 21 | }; | 23 | }; |
| 22 | EXPORT_SYMBOL_GPL(nft_masq_policy); | 24 | EXPORT_SYMBOL_GPL(nft_masq_policy); |
| 23 | 25 | ||
| @@ -40,6 +42,7 @@ int nft_masq_init(const struct nft_ctx *ctx, · 16 unmodified lines | |||
| 40 | const struct nft_expr *expr, | 42 | const struct nft_expr *expr, |
| 41 | const struct nlattr * const tb[]) | 43 | const struct nlattr * const tb[]) |
| 42 | { | 44 | { |
| 45 | u32 plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all); | ||
| 43 | struct nft_masq *priv = nft_expr_priv(expr); | 46 | struct nft_masq *priv = nft_expr_priv(expr); |
| 44 | int err; | 47 | int err; |
| 45 | 48 | ||
| @@ -47,12 +50,32 @@ int nft_masq_init(const struct nft_ctx *ctx, · 1 unmodified line | |||
| 47 | if (err) | 50 | if (err) |
| 48 | return err; | 51 | return err; |
| 49 | 52 | ||
| 50 | if (tb[NFTA_MASQ_FLAGS] == NULL) | 53 | if (tb[NFTA_MASQ_FLAGS]) { |
| 51 | return 0; | 54 | priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); |
| 52 | 55 | if (priv->flags & ~NF_NAT_RANGE_MASK) | |
| 53 | priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); | 56 | return -EINVAL; |
| 54 | if (priv->flags & ~NF_NAT_RANGE_MASK) | 57 | } |
| 55 | return -EINVAL; | 58 | |
| 59 | if (tb[NFTA_MASQ_REG_PROTO_MIN]) { | ||
| 60 | priv->sreg_proto_min = | ||
| 61 | nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MIN]); | ||
| 62 | |||
| 63 | err = nft_validate_register_load(priv->sreg_proto_min, plen); | ||
| 64 | if (err < 0) | ||
| 65 | return err; | ||
| 66 | |||
| 67 | if (tb[NFTA_MASQ_REG_PROTO_MAX]) { | ||
| 68 | priv->sreg_proto_max = | ||
| 69 | nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MAX]); | ||
| 70 | |||
| 71 | err = nft_validate_register_load(priv->sreg_proto_max, | ||
| 72 | plen); | ||
| 73 | if (err < 0) | ||
| 74 | return err; | ||
| 75 | } else { | ||
| 76 | priv->sreg_proto_max = priv->sreg_proto_min; | ||
| 77 | } | ||
| 78 | } | ||
| 56 | 79 | ||
| 57 | return 0; | 80 | return 0; |
| 58 | } | 81 | } |
| @@ -62,12 +85,18 @@ int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr) · 3 unmodified lines | |||
| 62 | { | 85 | { |
| 63 | const struct nft_masq *priv = nft_expr_priv(expr); | 86 | const struct nft_masq *priv = nft_expr_priv(expr); |
| 64 | 87 | ||
| 65 | if (priv->flags == 0) | 88 | if (priv->flags != 0 && |
| 66 | return 0; | 89 | nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) |
| 67 | |||
| 68 | if (nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) | ||
| 69 | goto nla_put_failure; | 90 | goto nla_put_failure; |
| 70 | 91 | ||
| 92 | if (priv->sreg_proto_min) { | ||
| 93 | if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN, | ||
| 94 | priv->sreg_proto_min) || | ||
| 95 | nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX, | ||
| 96 | priv->sreg_proto_max)) | ||
| 97 | goto nla_put_failure; | ||
| 98 | } | ||
| 99 | |||
| 71 | return 0; | 100 | return 0; |
| 72 | 101 | ||
| 73 | nla_put_failure: | 102 | nla_put_failure: |