Commit a37061a6 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: lift one-nat-hook-only restriction

This reverts commit f92b40a8
("netfilter: core: only allow one nat hook per hook point"), this
limitation is no longer needed.  The nat core now invokes these
functions and makes sure that hook evaluation stops after a mapping is
created and a null binding is created otherwise.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 9971a514
...@@ -67,7 +67,6 @@ struct nf_hook_ops { ...@@ -67,7 +67,6 @@ struct nf_hook_ops {
struct net_device *dev; struct net_device *dev;
void *priv; void *priv;
u_int8_t pf; u_int8_t pf;
bool nat_hook;
unsigned int hooknum; unsigned int hooknum;
/* Hooks are ordered in ascending priority. */ /* Hooks are ordered in ascending priority. */
int priority; int priority;
......
...@@ -138,11 +138,6 @@ nf_hook_entries_grow(const struct nf_hook_entries *old, ...@@ -138,11 +138,6 @@ nf_hook_entries_grow(const struct nf_hook_entries *old,
continue; continue;
} }
if (reg->nat_hook && orig_ops[i]->nat_hook) {
kvfree(new);
return ERR_PTR(-EBUSY);
}
if (inserted || reg->priority > orig_ops[i]->priority) { if (inserted || reg->priority > orig_ops[i]->priority) {
new_ops[nhooks] = (void *)orig_ops[i]; new_ops[nhooks] = (void *)orig_ops[i];
new->hooks[nhooks] = old->hooks[i]; new->hooks[nhooks] = old->hooks[i];
......
...@@ -74,64 +74,12 @@ static void nft_trans_destroy(struct nft_trans *trans) ...@@ -74,64 +74,12 @@ static void nft_trans_destroy(struct nft_trans *trans)
kfree(trans); kfree(trans);
} }
/* removal requests are queued in the commit_list, but not acted upon
* until after all new rules are in place.
*
* Therefore, nf_register_net_hook(net, &nat_hook) runs before pending
* nf_unregister_net_hook().
*
* nf_register_net_hook thus fails if a nat hook is already in place
* even if the conflicting hook is about to be removed.
*
* If collision is detected, search commit_log for DELCHAIN matching
* the new nat hooknum; if we find one collision is temporary:
*
* Either transaction is aborted (new/colliding hook is removed), or
* transaction is committed (old hook is removed).
*/
static bool nf_tables_allow_nat_conflict(const struct net *net,
const struct nf_hook_ops *ops)
{
const struct nft_trans *trans;
bool ret = false;
if (!ops->nat_hook)
return false;
list_for_each_entry(trans, &net->nft.commit_list, list) {
const struct nf_hook_ops *pending_ops;
const struct nft_chain *pending;
if (trans->msg_type != NFT_MSG_NEWCHAIN &&
trans->msg_type != NFT_MSG_DELCHAIN)
continue;
pending = trans->ctx.chain;
if (!nft_is_base_chain(pending))
continue;
pending_ops = &nft_base_chain(pending)->ops;
if (pending_ops->nat_hook &&
pending_ops->pf == ops->pf &&
pending_ops->hooknum == ops->hooknum) {
/* other hook registration already pending? */
if (trans->msg_type == NFT_MSG_NEWCHAIN)
return false;
ret = true;
}
}
return ret;
}
static int nf_tables_register_hook(struct net *net, static int nf_tables_register_hook(struct net *net,
const struct nft_table *table, const struct nft_table *table,
struct nft_chain *chain) struct nft_chain *chain)
{ {
const struct nft_base_chain *basechain; const struct nft_base_chain *basechain;
struct nf_hook_ops *ops; const struct nf_hook_ops *ops;
int ret;
if (table->flags & NFT_TABLE_F_DORMANT || if (table->flags & NFT_TABLE_F_DORMANT ||
!nft_is_base_chain(chain)) !nft_is_base_chain(chain))
...@@ -143,14 +91,7 @@ static int nf_tables_register_hook(struct net *net, ...@@ -143,14 +91,7 @@ static int nf_tables_register_hook(struct net *net,
if (basechain->type->ops_register) if (basechain->type->ops_register)
return basechain->type->ops_register(net, ops); return basechain->type->ops_register(net, ops);
ret = nf_register_net_hook(net, ops); return nf_register_net_hook(net, ops);
if (ret == -EBUSY && nf_tables_allow_nat_conflict(net, ops)) {
ops->nat_hook = false;
ret = nf_register_net_hook(net, ops);
ops->nat_hook = true;
}
return ret;
} }
static void nf_tables_unregister_hook(struct net *net, static void nf_tables_unregister_hook(struct net *net,
...@@ -1418,9 +1359,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, ...@@ -1418,9 +1359,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
ops->hook = hook.type->hooks[ops->hooknum]; ops->hook = hook.type->hooks[ops->hooknum];
ops->dev = hook.dev; ops->dev = hook.dev;
if (basechain->type->type == NFT_CHAIN_T_NAT)
ops->nat_hook = true;
chain->flags |= NFT_BASE_CHAIN; chain->flags |= NFT_BASE_CHAIN;
basechain->policy = policy; basechain->policy = policy;
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment