diff options
| -rw-r--r-- | include/net/netfilter/nf_tables.h | 3 | ||||
| -rw-r--r-- | include/net/netfilter/nft_masq.h | 3 | ||||
| -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 |
10 files changed, 165 insertions, 41 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 3d7292392fac..845c596bf594 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
| @@ -530,6 +530,9 @@ enum nft_chain_type { | |||
| 530 | NFT_CHAIN_T_MAX | 530 | NFT_CHAIN_T_MAX |
| 531 | }; | 531 | }; |
| 532 | 532 | ||
| 533 | int nft_chain_validate_dependency(const struct nft_chain *chain, | ||
| 534 | enum nft_chain_type type); | ||
| 535 | |||
| 533 | struct nft_stats { | 536 | struct nft_stats { |
| 534 | u64 bytes; | 537 | u64 bytes; |
| 535 | u64 pkts; | 538 | u64 pkts; |
diff --git a/include/net/netfilter/nft_masq.h b/include/net/netfilter/nft_masq.h index c72729f954f4..e2a518b60e19 100644 --- a/include/net/netfilter/nft_masq.h +++ b/include/net/netfilter/nft_masq.h | |||
| @@ -13,4 +13,7 @@ int nft_masq_init(const struct nft_ctx *ctx, | |||
| 13 | 13 | ||
| 14 | int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr); | 14 | int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr); |
| 15 | 15 | ||
| 16 | int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, | ||
| 17 | const struct nft_data **data); | ||
| 18 | |||
| 16 | #endif /* _NFT_MASQ_H_ */ | 19 | #endif /* _NFT_MASQ_H_ */ |
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 = { |
