diff options
author | David S. Miller <davem@davemloft.net> | 2014-10-20 11:57:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-10-20 11:57:47 -0400 |
commit | ce8ec4896749783bd6cdc457e6012cfc18e09c8b (patch) | |
tree | 3d58d88f4e4030ddf0f926ac2ef52c3ee2c9f65a /net | |
parent | 95ff88688781db2f64042e69bd499e518bbb36e5 (diff) | |
parent | 1e2d56a5d33a7e1fcd21ed3859f52596d02708b0 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says:
====================
netfilter fixes for net
The following patchset contains netfilter fixes for your net tree,
they are:
1) Fix missing MODULE_LICENSE() in the new nf_reject_ipv{4,6} modules.
2) Restrict nat and masq expressions to the nat chain type. Otherwise,
users may crash their kernel if they attach a nat/masq rule to a non
nat chain.
3) Fix hook validation in nft_compat when non-base chains are used.
Basically, initialize hook_mask to zero.
4) Make sure you use match/targets in nft_compat from the right chain
type. The existing validation relies on the table name which can be
avoided by
5) Better netlink attribute validation in nft_nat. This expression has
to reject the configuration when no address and proto configurations
are specified.
6) Interpret NFTA_NAT_REG_*_MAX if only if NFTA_NAT_REG_*_MIN is set.
Yet another sanity check to reject incorrect configurations from
userspace.
7) Conditional NAT attribute dumping depending on the existing
configuration.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/nf_reject_ipv4.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/nft_masq_ipv4.c | 1 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_reject_ipv6.c | 4 | ||||
-rw-r--r-- | net/ipv6/netfilter/nft_masq_ipv6.c | 1 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 14 | ||||
-rw-r--r-- | net/netfilter/nft_compat.c | 79 | ||||
-rw-r--r-- | net/netfilter/nft_masq.c | 12 | ||||
-rw-r--r-- | net/netfilter/nft_nat.c | 86 |
8 files changed, 159 insertions, 41 deletions
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c index b023b4eb1a96..92b303dbd5fc 100644 --- a/net/ipv4/netfilter/nf_reject_ipv4.c +++ b/net/ipv4/netfilter/nf_reject_ipv4.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/module.h> | ||
9 | #include <net/ip.h> | 10 | #include <net/ip.h> |
10 | #include <net/tcp.h> | 11 | #include <net/tcp.h> |
11 | #include <net/route.h> | 12 | #include <net/route.h> |
@@ -125,3 +126,5 @@ void nf_send_reset(struct sk_buff *oldskb, int hook) | |||
125 | kfree_skb(nskb); | 126 | kfree_skb(nskb); |
126 | } | 127 | } |
127 | EXPORT_SYMBOL_GPL(nf_send_reset); | 128 | EXPORT_SYMBOL_GPL(nf_send_reset); |
129 | |||
130 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv4/netfilter/nft_masq_ipv4.c b/net/ipv4/netfilter/nft_masq_ipv4.c index 1c636d6b5b50..c1023c445920 100644 --- a/net/ipv4/netfilter/nft_masq_ipv4.c +++ b/net/ipv4/netfilter/nft_masq_ipv4.c | |||
@@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv4_ops = { | |||
39 | .eval = nft_masq_ipv4_eval, | 39 | .eval = nft_masq_ipv4_eval, |
40 | .init = nft_masq_init, | 40 | .init = nft_masq_init, |
41 | .dump = nft_masq_dump, | 41 | .dump = nft_masq_dump, |
42 | .validate = nft_masq_validate, | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | static struct nft_expr_type nft_masq_ipv4_type __read_mostly = { | 45 | static struct nft_expr_type nft_masq_ipv4_type __read_mostly = { |
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index 5f5f0438d74d..20d9defc6c59 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c | |||
@@ -5,6 +5,8 @@ | |||
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | |||
9 | #include <linux/module.h> | ||
8 | #include <net/ipv6.h> | 10 | #include <net/ipv6.h> |
9 | #include <net/ip6_route.h> | 11 | #include <net/ip6_route.h> |
10 | #include <net/ip6_fib.h> | 12 | #include <net/ip6_fib.h> |
@@ -161,3 +163,5 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) | |||
161 | ip6_local_out(nskb); | 163 | ip6_local_out(nskb); |
162 | } | 164 | } |
163 | EXPORT_SYMBOL_GPL(nf_send_reset6); | 165 | EXPORT_SYMBOL_GPL(nf_send_reset6); |
166 | |||
167 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv6/netfilter/nft_masq_ipv6.c b/net/ipv6/netfilter/nft_masq_ipv6.c index 556262f40761..8a7ac685076d 100644 --- a/net/ipv6/netfilter/nft_masq_ipv6.c +++ b/net/ipv6/netfilter/nft_masq_ipv6.c | |||
@@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv6_ops = { | |||
39 | .eval = nft_masq_ipv6_eval, | 39 | .eval = nft_masq_ipv6_eval, |
40 | .init = nft_masq_init, | 40 | .init = nft_masq_init, |
41 | .dump = nft_masq_dump, | 41 | .dump = nft_masq_dump, |
42 | .validate = nft_masq_validate, | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | static struct nft_expr_type nft_masq_ipv6_type __read_mostly = { | 45 | static struct nft_expr_type nft_masq_ipv6_type __read_mostly = { |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 556a0dfa4abc..65eb2a1160d5 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -3744,6 +3744,20 @@ static const struct nfnetlink_subsystem nf_tables_subsys = { | |||
3744 | .abort = nf_tables_abort, | 3744 | .abort = nf_tables_abort, |
3745 | }; | 3745 | }; |
3746 | 3746 | ||
3747 | int nft_chain_validate_dependency(const struct nft_chain *chain, | ||
3748 | enum nft_chain_type type) | ||
3749 | { | ||
3750 | const struct nft_base_chain *basechain; | ||
3751 | |||
3752 | if (chain->flags & NFT_BASE_CHAIN) { | ||
3753 | basechain = nft_base_chain(chain); | ||
3754 | if (basechain->type->type != type) | ||
3755 | return -EOPNOTSUPP; | ||
3756 | } | ||
3757 | return 0; | ||
3758 | } | ||
3759 | EXPORT_SYMBOL_GPL(nft_chain_validate_dependency); | ||
3760 | |||
3747 | /* | 3761 | /* |
3748 | * Loop detection - walk through the ruleset beginning at the destination chain | 3762 | * Loop detection - walk through the ruleset beginning at the destination chain |
3749 | * of a new jump until either the source chain is reached (loop) or all | 3763 | * of a new jump until either the source chain is reached (loop) or all |
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 7e2683c8a44a..0480f57a4eb6 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
@@ -19,9 +19,52 @@ | |||
19 | #include <linux/netfilter/x_tables.h> | 19 | #include <linux/netfilter/x_tables.h> |
20 | #include <linux/netfilter_ipv4/ip_tables.h> | 20 | #include <linux/netfilter_ipv4/ip_tables.h> |
21 | #include <linux/netfilter_ipv6/ip6_tables.h> | 21 | #include <linux/netfilter_ipv6/ip6_tables.h> |
22 | #include <asm/uaccess.h> /* for set_fs */ | ||
23 | #include <net/netfilter/nf_tables.h> | 22 | #include <net/netfilter/nf_tables.h> |
24 | 23 | ||
24 | static const struct { | ||
25 | const char *name; | ||
26 | u8 type; | ||
27 | } table_to_chaintype[] = { | ||
28 | { "filter", NFT_CHAIN_T_DEFAULT }, | ||
29 | { "raw", NFT_CHAIN_T_DEFAULT }, | ||
30 | { "security", NFT_CHAIN_T_DEFAULT }, | ||
31 | { "mangle", NFT_CHAIN_T_ROUTE }, | ||
32 | { "nat", NFT_CHAIN_T_NAT }, | ||
33 | { }, | ||
34 | }; | ||
35 | |||
36 | static int nft_compat_table_to_chaintype(const char *table) | ||
37 | { | ||
38 | int i; | ||
39 | |||
40 | for (i = 0; table_to_chaintype[i].name != NULL; i++) { | ||
41 | if (strcmp(table_to_chaintype[i].name, table) == 0) | ||
42 | return table_to_chaintype[i].type; | ||
43 | } | ||
44 | |||
45 | return -1; | ||
46 | } | ||
47 | |||
48 | static int nft_compat_chain_validate_dependency(const char *tablename, | ||
49 | const struct nft_chain *chain) | ||
50 | { | ||
51 | enum nft_chain_type type; | ||
52 | const struct nft_base_chain *basechain; | ||
53 | |||
54 | if (!tablename || !(chain->flags & NFT_BASE_CHAIN)) | ||
55 | return 0; | ||
56 | |||
57 | type = nft_compat_table_to_chaintype(tablename); | ||
58 | if (type < 0) | ||
59 | return -EINVAL; | ||
60 | |||
61 | basechain = nft_base_chain(chain); | ||
62 | if (basechain->type->type != type) | ||
63 | return -EINVAL; | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
25 | union nft_entry { | 68 | union nft_entry { |
26 | struct ipt_entry e4; | 69 | struct ipt_entry e4; |
27 | struct ip6t_entry e6; | 70 | struct ip6t_entry e6; |
@@ -95,6 +138,8 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par, | |||
95 | const struct nf_hook_ops *ops = &basechain->ops[0]; | 138 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
96 | 139 | ||
97 | par->hook_mask = 1 << ops->hooknum; | 140 | par->hook_mask = 1 << ops->hooknum; |
141 | } else { | ||
142 | par->hook_mask = 0; | ||
98 | } | 143 | } |
99 | par->family = ctx->afi->family; | 144 | par->family = ctx->afi->family; |
100 | } | 145 | } |
@@ -151,6 +196,10 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
151 | union nft_entry e = {}; | 196 | union nft_entry e = {}; |
152 | int ret; | 197 | int ret; |
153 | 198 | ||
199 | ret = nft_compat_chain_validate_dependency(target->table, ctx->chain); | ||
200 | if (ret < 0) | ||
201 | goto err; | ||
202 | |||
154 | target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info); | 203 | target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info); |
155 | 204 | ||
156 | if (ctx->nla[NFTA_RULE_COMPAT]) { | 205 | if (ctx->nla[NFTA_RULE_COMPAT]) { |
@@ -216,6 +265,7 @@ static int nft_target_validate(const struct nft_ctx *ctx, | |||
216 | { | 265 | { |
217 | struct xt_target *target = expr->ops->data; | 266 | struct xt_target *target = expr->ops->data; |
218 | unsigned int hook_mask = 0; | 267 | unsigned int hook_mask = 0; |
268 | int ret; | ||
219 | 269 | ||
220 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 270 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
221 | const struct nft_base_chain *basechain = | 271 | const struct nft_base_chain *basechain = |
@@ -223,11 +273,13 @@ static int nft_target_validate(const struct nft_ctx *ctx, | |||
223 | const struct nf_hook_ops *ops = &basechain->ops[0]; | 273 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
224 | 274 | ||
225 | hook_mask = 1 << ops->hooknum; | 275 | hook_mask = 1 << ops->hooknum; |
226 | if (hook_mask & target->hooks) | 276 | if (!(hook_mask & target->hooks)) |
227 | return 0; | 277 | return -EINVAL; |
228 | 278 | ||
229 | /* This target is being called from an invalid chain */ | 279 | ret = nft_compat_chain_validate_dependency(target->table, |
230 | return -EINVAL; | 280 | ctx->chain); |
281 | if (ret < 0) | ||
282 | return ret; | ||
231 | } | 283 | } |
232 | return 0; | 284 | return 0; |
233 | } | 285 | } |
@@ -293,6 +345,8 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, | |||
293 | const struct nf_hook_ops *ops = &basechain->ops[0]; | 345 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
294 | 346 | ||
295 | par->hook_mask = 1 << ops->hooknum; | 347 | par->hook_mask = 1 << ops->hooknum; |
348 | } else { | ||
349 | par->hook_mask = 0; | ||
296 | } | 350 | } |
297 | par->family = ctx->afi->family; | 351 | par->family = ctx->afi->family; |
298 | } | 352 | } |
@@ -320,6 +374,10 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
320 | union nft_entry e = {}; | 374 | union nft_entry e = {}; |
321 | int ret; | 375 | int ret; |
322 | 376 | ||
377 | ret = nft_compat_chain_validate_dependency(match->name, ctx->chain); | ||
378 | if (ret < 0) | ||
379 | goto err; | ||
380 | |||
323 | match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info); | 381 | match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info); |
324 | 382 | ||
325 | if (ctx->nla[NFTA_RULE_COMPAT]) { | 383 | if (ctx->nla[NFTA_RULE_COMPAT]) { |
@@ -379,6 +437,7 @@ static int nft_match_validate(const struct nft_ctx *ctx, | |||
379 | { | 437 | { |
380 | struct xt_match *match = expr->ops->data; | 438 | struct xt_match *match = expr->ops->data; |
381 | unsigned int hook_mask = 0; | 439 | unsigned int hook_mask = 0; |
440 | int ret; | ||
382 | 441 | ||
383 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 442 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
384 | const struct nft_base_chain *basechain = | 443 | const struct nft_base_chain *basechain = |
@@ -386,11 +445,13 @@ static int nft_match_validate(const struct nft_ctx *ctx, | |||
386 | const struct nf_hook_ops *ops = &basechain->ops[0]; | 445 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
387 | 446 | ||
388 | hook_mask = 1 << ops->hooknum; | 447 | hook_mask = 1 << ops->hooknum; |
389 | if (hook_mask & match->hooks) | 448 | if (!(hook_mask & match->hooks)) |
390 | return 0; | 449 | return -EINVAL; |
391 | 450 | ||
392 | /* This match is being called from an invalid chain */ | 451 | ret = nft_compat_chain_validate_dependency(match->name, |
393 | return -EINVAL; | 452 | ctx->chain); |
453 | if (ret < 0) | ||
454 | return ret; | ||
394 | } | 455 | } |
395 | return 0; | 456 | return 0; |
396 | } | 457 | } |
diff --git a/net/netfilter/nft_masq.c b/net/netfilter/nft_masq.c index 6637bab00567..d1ffd5eb3a9b 100644 --- a/net/netfilter/nft_masq.c +++ b/net/netfilter/nft_masq.c | |||
@@ -26,6 +26,11 @@ int nft_masq_init(const struct nft_ctx *ctx, | |||
26 | const struct nlattr * const tb[]) | 26 | const struct nlattr * const tb[]) |
27 | { | 27 | { |
28 | struct nft_masq *priv = nft_expr_priv(expr); | 28 | struct nft_masq *priv = nft_expr_priv(expr); |
29 | int err; | ||
30 | |||
31 | err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); | ||
32 | if (err < 0) | ||
33 | return err; | ||
29 | 34 | ||
30 | if (tb[NFTA_MASQ_FLAGS] == NULL) | 35 | if (tb[NFTA_MASQ_FLAGS] == NULL) |
31 | return 0; | 36 | return 0; |
@@ -55,5 +60,12 @@ nla_put_failure: | |||
55 | } | 60 | } |
56 | EXPORT_SYMBOL_GPL(nft_masq_dump); | 61 | EXPORT_SYMBOL_GPL(nft_masq_dump); |
57 | 62 | ||
63 | int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, | ||
64 | const struct nft_data **data) | ||
65 | { | ||
66 | return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); | ||
67 | } | ||
68 | EXPORT_SYMBOL_GPL(nft_masq_validate); | ||
69 | |||
58 | MODULE_LICENSE("GPL"); | 70 | MODULE_LICENSE("GPL"); |
59 | MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); | 71 | MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); |
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index 799550b476fb..afe2b0b45ec4 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c | |||
@@ -95,7 +95,13 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
95 | u32 family; | 95 | u32 family; |
96 | int err; | 96 | int err; |
97 | 97 | ||
98 | if (tb[NFTA_NAT_TYPE] == NULL) | 98 | err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); |
99 | if (err < 0) | ||
100 | return err; | ||
101 | |||
102 | if (tb[NFTA_NAT_TYPE] == NULL || | ||
103 | (tb[NFTA_NAT_REG_ADDR_MIN] == NULL && | ||
104 | tb[NFTA_NAT_REG_PROTO_MIN] == NULL)) | ||
99 | return -EINVAL; | 105 | return -EINVAL; |
100 | 106 | ||
101 | switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) { | 107 | switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) { |
@@ -120,38 +126,44 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
120 | priv->family = family; | 126 | priv->family = family; |
121 | 127 | ||
122 | if (tb[NFTA_NAT_REG_ADDR_MIN]) { | 128 | if (tb[NFTA_NAT_REG_ADDR_MIN]) { |
123 | priv->sreg_addr_min = ntohl(nla_get_be32( | 129 | priv->sreg_addr_min = |
124 | tb[NFTA_NAT_REG_ADDR_MIN])); | 130 | ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN])); |
131 | |||
125 | err = nft_validate_input_register(priv->sreg_addr_min); | 132 | err = nft_validate_input_register(priv->sreg_addr_min); |
126 | if (err < 0) | 133 | if (err < 0) |
127 | return err; | 134 | return err; |
128 | } | ||
129 | 135 | ||
130 | if (tb[NFTA_NAT_REG_ADDR_MAX]) { | 136 | if (tb[NFTA_NAT_REG_ADDR_MAX]) { |
131 | priv->sreg_addr_max = ntohl(nla_get_be32( | 137 | priv->sreg_addr_max = |
132 | tb[NFTA_NAT_REG_ADDR_MAX])); | 138 | ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MAX])); |
133 | err = nft_validate_input_register(priv->sreg_addr_max); | 139 | |
134 | if (err < 0) | 140 | err = nft_validate_input_register(priv->sreg_addr_max); |
135 | return err; | 141 | if (err < 0) |
136 | } else | 142 | return err; |
137 | priv->sreg_addr_max = priv->sreg_addr_min; | 143 | } else { |
144 | priv->sreg_addr_max = priv->sreg_addr_min; | ||
145 | } | ||
146 | } | ||
138 | 147 | ||
139 | if (tb[NFTA_NAT_REG_PROTO_MIN]) { | 148 | if (tb[NFTA_NAT_REG_PROTO_MIN]) { |
140 | priv->sreg_proto_min = ntohl(nla_get_be32( | 149 | priv->sreg_proto_min = |
141 | tb[NFTA_NAT_REG_PROTO_MIN])); | 150 | ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MIN])); |
151 | |||
142 | err = nft_validate_input_register(priv->sreg_proto_min); | 152 | err = nft_validate_input_register(priv->sreg_proto_min); |
143 | if (err < 0) | 153 | if (err < 0) |
144 | return err; | 154 | return err; |
145 | } | ||
146 | 155 | ||
147 | if (tb[NFTA_NAT_REG_PROTO_MAX]) { | 156 | if (tb[NFTA_NAT_REG_PROTO_MAX]) { |
148 | priv->sreg_proto_max = ntohl(nla_get_be32( | 157 | priv->sreg_proto_max = |
149 | tb[NFTA_NAT_REG_PROTO_MAX])); | 158 | ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MAX])); |
150 | err = nft_validate_input_register(priv->sreg_proto_max); | 159 | |
151 | if (err < 0) | 160 | err = nft_validate_input_register(priv->sreg_proto_max); |
152 | return err; | 161 | if (err < 0) |
153 | } else | 162 | return err; |
154 | priv->sreg_proto_max = priv->sreg_proto_min; | 163 | } else { |
164 | priv->sreg_proto_max = priv->sreg_proto_min; | ||
165 | } | ||
166 | } | ||
155 | 167 | ||
156 | if (tb[NFTA_NAT_FLAGS]) { | 168 | if (tb[NFTA_NAT_FLAGS]) { |
157 | priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS])); | 169 | priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS])); |
@@ -179,17 +191,19 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr) | |||
179 | 191 | ||
180 | if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family))) | 192 | if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family))) |
181 | goto nla_put_failure; | 193 | goto nla_put_failure; |
182 | if (nla_put_be32(skb, | 194 | |
183 | NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min))) | 195 | if (priv->sreg_addr_min) { |
184 | goto nla_put_failure; | 196 | if (nla_put_be32(skb, NFTA_NAT_REG_ADDR_MIN, |
185 | if (nla_put_be32(skb, | 197 | htonl(priv->sreg_addr_min)) || |
186 | NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max))) | 198 | nla_put_be32(skb, NFTA_NAT_REG_ADDR_MAX, |
187 | goto nla_put_failure; | 199 | htonl(priv->sreg_addr_max))) |
200 | goto nla_put_failure; | ||
201 | } | ||
202 | |||
188 | if (priv->sreg_proto_min) { | 203 | if (priv->sreg_proto_min) { |
189 | if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MIN, | 204 | if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MIN, |
190 | htonl(priv->sreg_proto_min))) | 205 | htonl(priv->sreg_proto_min)) || |
191 | goto nla_put_failure; | 206 | nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX, |
192 | if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX, | ||
193 | htonl(priv->sreg_proto_max))) | 207 | htonl(priv->sreg_proto_max))) |
194 | goto nla_put_failure; | 208 | goto nla_put_failure; |
195 | } | 209 | } |
@@ -205,6 +219,13 @@ nla_put_failure: | |||
205 | return -1; | 219 | return -1; |
206 | } | 220 | } |
207 | 221 | ||
222 | static int nft_nat_validate(const struct nft_ctx *ctx, | ||
223 | const struct nft_expr *expr, | ||
224 | const struct nft_data **data) | ||
225 | { | ||
226 | return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); | ||
227 | } | ||
228 | |||
208 | static struct nft_expr_type nft_nat_type; | 229 | static struct nft_expr_type nft_nat_type; |
209 | static const struct nft_expr_ops nft_nat_ops = { | 230 | static const struct nft_expr_ops nft_nat_ops = { |
210 | .type = &nft_nat_type, | 231 | .type = &nft_nat_type, |
@@ -212,6 +233,7 @@ static const struct nft_expr_ops nft_nat_ops = { | |||
212 | .eval = nft_nat_eval, | 233 | .eval = nft_nat_eval, |
213 | .init = nft_nat_init, | 234 | .init = nft_nat_init, |
214 | .dump = nft_nat_dump, | 235 | .dump = nft_nat_dump, |
236 | .validate = nft_nat_validate, | ||
215 | }; | 237 | }; |
216 | 238 | ||
217 | static struct nft_expr_type nft_nat_type __read_mostly = { | 239 | static struct nft_expr_type nft_nat_type __read_mostly = { |