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

netfilter: synproxy: only register hooks when needed

Defer registration of the synproxy hooks until the first SYNPROXY rule is
added.  Also means we only register hooks in namespaces that need it.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 122868b3
...@@ -52,6 +52,8 @@ struct synproxy_stats { ...@@ -52,6 +52,8 @@ struct synproxy_stats {
struct synproxy_net { struct synproxy_net {
struct nf_conn *tmpl; struct nf_conn *tmpl;
struct synproxy_stats __percpu *stats; struct synproxy_stats __percpu *stats;
unsigned int hook_ref4;
unsigned int hook_ref6;
}; };
extern unsigned int synproxy_net_id; extern unsigned int synproxy_net_id;
......
...@@ -409,19 +409,56 @@ static unsigned int ipv4_synproxy_hook(void *priv, ...@@ -409,19 +409,56 @@ static unsigned int ipv4_synproxy_hook(void *priv,
return NF_ACCEPT; return NF_ACCEPT;
} }
static struct nf_hook_ops ipv4_synproxy_ops[] __read_mostly = {
{
.hook = ipv4_synproxy_hook,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
},
{
.hook = ipv4_synproxy_hook,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
},
};
static int synproxy_tg4_check(const struct xt_tgchk_param *par) static int synproxy_tg4_check(const struct xt_tgchk_param *par)
{ {
struct synproxy_net *snet = synproxy_pernet(par->net);
const struct ipt_entry *e = par->entryinfo; const struct ipt_entry *e = par->entryinfo;
int err;
if (e->ip.proto != IPPROTO_TCP || if (e->ip.proto != IPPROTO_TCP ||
e->ip.invflags & XT_INV_PROTO) e->ip.invflags & XT_INV_PROTO)
return -EINVAL; return -EINVAL;
return nf_ct_netns_get(par->net, par->family); err = nf_ct_netns_get(par->net, par->family);
if (err)
return err;
if (snet->hook_ref4 == 0) {
err = nf_register_net_hooks(par->net, ipv4_synproxy_ops,
ARRAY_SIZE(ipv4_synproxy_ops));
if (err) {
nf_ct_netns_put(par->net, par->family);
return err;
}
}
snet->hook_ref4++;
return err;
} }
static void synproxy_tg4_destroy(const struct xt_tgdtor_param *par) static void synproxy_tg4_destroy(const struct xt_tgdtor_param *par)
{ {
struct synproxy_net *snet = synproxy_pernet(par->net);
snet->hook_ref4--;
if (snet->hook_ref4 == 0)
nf_unregister_net_hooks(par->net, ipv4_synproxy_ops,
ARRAY_SIZE(ipv4_synproxy_ops));
nf_ct_netns_put(par->net, par->family); nf_ct_netns_put(par->net, par->family);
} }
...@@ -436,46 +473,14 @@ static struct xt_target synproxy_tg4_reg __read_mostly = { ...@@ -436,46 +473,14 @@ static struct xt_target synproxy_tg4_reg __read_mostly = {
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
static struct nf_hook_ops ipv4_synproxy_ops[] __read_mostly = {
{
.hook = ipv4_synproxy_hook,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
},
{
.hook = ipv4_synproxy_hook,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
},
};
static int __init synproxy_tg4_init(void) static int __init synproxy_tg4_init(void)
{ {
int err; return xt_register_target(&synproxy_tg4_reg);
err = nf_register_hooks(ipv4_synproxy_ops,
ARRAY_SIZE(ipv4_synproxy_ops));
if (err < 0)
goto err1;
err = xt_register_target(&synproxy_tg4_reg);
if (err < 0)
goto err2;
return 0;
err2:
nf_unregister_hooks(ipv4_synproxy_ops, ARRAY_SIZE(ipv4_synproxy_ops));
err1:
return err;
} }
static void __exit synproxy_tg4_exit(void) static void __exit synproxy_tg4_exit(void)
{ {
xt_unregister_target(&synproxy_tg4_reg); xt_unregister_target(&synproxy_tg4_reg);
nf_unregister_hooks(ipv4_synproxy_ops, ARRAY_SIZE(ipv4_synproxy_ops));
} }
module_init(synproxy_tg4_init); module_init(synproxy_tg4_init);
......
...@@ -430,20 +430,57 @@ static unsigned int ipv6_synproxy_hook(void *priv, ...@@ -430,20 +430,57 @@ static unsigned int ipv6_synproxy_hook(void *priv,
return NF_ACCEPT; return NF_ACCEPT;
} }
static struct nf_hook_ops ipv6_synproxy_ops[] __read_mostly = {
{
.hook = ipv6_synproxy_hook,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
},
{
.hook = ipv6_synproxy_hook,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
},
};
static int synproxy_tg6_check(const struct xt_tgchk_param *par) static int synproxy_tg6_check(const struct xt_tgchk_param *par)
{ {
struct synproxy_net *snet = synproxy_pernet(par->net);
const struct ip6t_entry *e = par->entryinfo; const struct ip6t_entry *e = par->entryinfo;
int err;
if (!(e->ipv6.flags & IP6T_F_PROTO) || if (!(e->ipv6.flags & IP6T_F_PROTO) ||
e->ipv6.proto != IPPROTO_TCP || e->ipv6.proto != IPPROTO_TCP ||
e->ipv6.invflags & XT_INV_PROTO) e->ipv6.invflags & XT_INV_PROTO)
return -EINVAL; return -EINVAL;
return nf_ct_netns_get(par->net, par->family); err = nf_ct_netns_get(par->net, par->family);
if (err)
return err;
if (snet->hook_ref6 == 0) {
err = nf_register_net_hooks(par->net, ipv6_synproxy_ops,
ARRAY_SIZE(ipv6_synproxy_ops));
if (err) {
nf_ct_netns_put(par->net, par->family);
return err;
}
}
snet->hook_ref6++;
return err;
} }
static void synproxy_tg6_destroy(const struct xt_tgdtor_param *par) static void synproxy_tg6_destroy(const struct xt_tgdtor_param *par)
{ {
struct synproxy_net *snet = synproxy_pernet(par->net);
snet->hook_ref6--;
if (snet->hook_ref6 == 0)
nf_unregister_net_hooks(par->net, ipv6_synproxy_ops,
ARRAY_SIZE(ipv6_synproxy_ops));
nf_ct_netns_put(par->net, par->family); nf_ct_netns_put(par->net, par->family);
} }
...@@ -458,46 +495,14 @@ static struct xt_target synproxy_tg6_reg __read_mostly = { ...@@ -458,46 +495,14 @@ static struct xt_target synproxy_tg6_reg __read_mostly = {
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
static struct nf_hook_ops ipv6_synproxy_ops[] __read_mostly = {
{
.hook = ipv6_synproxy_hook,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
},
{
.hook = ipv6_synproxy_hook,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
},
};
static int __init synproxy_tg6_init(void) static int __init synproxy_tg6_init(void)
{ {
int err; return xt_register_target(&synproxy_tg6_reg);
err = nf_register_hooks(ipv6_synproxy_ops,
ARRAY_SIZE(ipv6_synproxy_ops));
if (err < 0)
goto err1;
err = xt_register_target(&synproxy_tg6_reg);
if (err < 0)
goto err2;
return 0;
err2:
nf_unregister_hooks(ipv6_synproxy_ops, ARRAY_SIZE(ipv6_synproxy_ops));
err1:
return err;
} }
static void __exit synproxy_tg6_exit(void) static void __exit synproxy_tg6_exit(void)
{ {
xt_unregister_target(&synproxy_tg6_reg); xt_unregister_target(&synproxy_tg6_reg);
nf_unregister_hooks(ipv6_synproxy_ops, ARRAY_SIZE(ipv6_synproxy_ops));
} }
module_init(synproxy_tg6_init); module_init(synproxy_tg6_init);
......
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