Commit 60a3815d authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: add inet ingress support

This patch adds the NF_INET_INGRESS pseudohook for the NFPROTO_INET
family. This is a mapping this new hook to the existing NFPROTO_NETDEV
and NF_NETDEV_INGRESS hook. The hook does not guarantee that packets are
inet only, users must filter out non-ip traffic explicitly.

This infrastructure makes it easier to support this new hook in nf_tables.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent ddcfa710
...@@ -45,6 +45,7 @@ enum nf_inet_hooks { ...@@ -45,6 +45,7 @@ enum nf_inet_hooks {
NF_INET_FORWARD, NF_INET_FORWARD,
NF_INET_LOCAL_OUT, NF_INET_LOCAL_OUT,
NF_INET_POST_ROUTING, NF_INET_POST_ROUTING,
NF_INET_INGRESS,
NF_INET_NUMHOOKS NF_INET_NUMHOOKS
}; };
......
...@@ -281,6 +281,16 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum, ...@@ -281,6 +281,16 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_bridge) <= hooknum)) if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_bridge) <= hooknum))
return NULL; return NULL;
return net->nf.hooks_bridge + hooknum; return net->nf.hooks_bridge + hooknum;
#endif
#ifdef CONFIG_NETFILTER_INGRESS
case NFPROTO_INET:
if (WARN_ON_ONCE(hooknum != NF_INET_INGRESS))
return NULL;
if (!dev || dev_net(dev) != net) {
WARN_ON_ONCE(1);
return NULL;
}
return &dev->nf_hooks_ingress;
#endif #endif
case NFPROTO_IPV4: case NFPROTO_IPV4:
if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv4) <= hooknum)) if (WARN_ON_ONCE(ARRAY_SIZE(net->nf.hooks_ipv4) <= hooknum))
...@@ -311,22 +321,56 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum, ...@@ -311,22 +321,56 @@ nf_hook_entry_head(struct net *net, int pf, unsigned int hooknum,
return NULL; return NULL;
} }
static int nf_ingress_check(struct net *net, const struct nf_hook_ops *reg,
int hooknum)
{
#ifndef CONFIG_NETFILTER_INGRESS
if (reg->hooknum == hooknum)
return -EOPNOTSUPP;
#endif
if (reg->hooknum != hooknum ||
!reg->dev || dev_net(reg->dev) != net)
return -EINVAL;
return 0;
}
static inline bool nf_ingress_hook(const struct nf_hook_ops *reg, int pf) static inline bool nf_ingress_hook(const struct nf_hook_ops *reg, int pf)
{ {
return pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS; if ((pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) ||
(pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS))
return true;
return false;
} }
static void nf_static_key_inc(const struct nf_hook_ops *reg, int pf) static void nf_static_key_inc(const struct nf_hook_ops *reg, int pf)
{ {
#ifdef CONFIG_JUMP_LABEL #ifdef CONFIG_JUMP_LABEL
static_key_slow_inc(&nf_hooks_needed[pf][reg->hooknum]); int hooknum;
if (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS) {
pf = NFPROTO_NETDEV;
hooknum = NF_NETDEV_INGRESS;
} else {
hooknum = reg->hooknum;
}
static_key_slow_inc(&nf_hooks_needed[pf][hooknum]);
#endif #endif
} }
static void nf_static_key_dec(const struct nf_hook_ops *reg, int pf) static void nf_static_key_dec(const struct nf_hook_ops *reg, int pf)
{ {
#ifdef CONFIG_JUMP_LABEL #ifdef CONFIG_JUMP_LABEL
static_key_slow_dec(&nf_hooks_needed[pf][reg->hooknum]); int hooknum;
if (pf == NFPROTO_INET && reg->hooknum == NF_INET_INGRESS) {
pf = NFPROTO_NETDEV;
hooknum = NF_NETDEV_INGRESS;
} else {
hooknum = reg->hooknum;
}
static_key_slow_dec(&nf_hooks_needed[pf][hooknum]);
#endif #endif
} }
...@@ -335,15 +379,22 @@ static int __nf_register_net_hook(struct net *net, int pf, ...@@ -335,15 +379,22 @@ static int __nf_register_net_hook(struct net *net, int pf,
{ {
struct nf_hook_entries *p, *new_hooks; struct nf_hook_entries *p, *new_hooks;
struct nf_hook_entries __rcu **pp; struct nf_hook_entries __rcu **pp;
int err;
if (pf == NFPROTO_NETDEV) { switch (pf) {
#ifndef CONFIG_NETFILTER_INGRESS case NFPROTO_NETDEV:
if (reg->hooknum == NF_NETDEV_INGRESS) err = nf_ingress_check(net, reg, NF_NETDEV_INGRESS);
return -EOPNOTSUPP; if (err < 0)
#endif return err;
if (reg->hooknum != NF_NETDEV_INGRESS || break;
!reg->dev || dev_net(reg->dev) != net) case NFPROTO_INET:
return -EINVAL; if (reg->hooknum != NF_INET_INGRESS)
break;
err = nf_ingress_check(net, reg, NF_INET_INGRESS);
if (err < 0)
return err;
break;
} }
pp = nf_hook_entry_head(net, pf, reg->hooknum, reg->dev); pp = nf_hook_entry_head(net, pf, reg->hooknum, reg->dev);
...@@ -441,8 +492,12 @@ static void __nf_unregister_net_hook(struct net *net, int pf, ...@@ -441,8 +492,12 @@ static void __nf_unregister_net_hook(struct net *net, int pf,
void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
{ {
if (reg->pf == NFPROTO_INET) { if (reg->pf == NFPROTO_INET) {
__nf_unregister_net_hook(net, NFPROTO_IPV4, reg); if (reg->hooknum == NF_INET_INGRESS) {
__nf_unregister_net_hook(net, NFPROTO_IPV6, reg); __nf_unregister_net_hook(net, NFPROTO_INET, reg);
} else {
__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
__nf_unregister_net_hook(net, NFPROTO_IPV6, reg);
}
} else { } else {
__nf_unregister_net_hook(net, reg->pf, reg); __nf_unregister_net_hook(net, reg->pf, reg);
} }
...@@ -467,14 +522,20 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) ...@@ -467,14 +522,20 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
int err; int err;
if (reg->pf == NFPROTO_INET) { if (reg->pf == NFPROTO_INET) {
err = __nf_register_net_hook(net, NFPROTO_IPV4, reg); if (reg->hooknum == NF_INET_INGRESS) {
if (err < 0) err = __nf_register_net_hook(net, NFPROTO_INET, reg);
return err; if (err < 0)
return err;
err = __nf_register_net_hook(net, NFPROTO_IPV6, reg); } else {
if (err < 0) { err = __nf_register_net_hook(net, NFPROTO_IPV4, reg);
__nf_unregister_net_hook(net, NFPROTO_IPV4, reg); if (err < 0)
return err; return err;
err = __nf_register_net_hook(net, NFPROTO_IPV6, reg);
if (err < 0) {
__nf_unregister_net_hook(net, NFPROTO_IPV4, reg);
return err;
}
} }
} else { } else {
err = __nf_register_net_hook(net, reg->pf, reg); err = __nf_register_net_hook(net, reg->pf, reg);
......
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