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: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Florian Westphal 2017-04-19 18:14:04 +02:00 committed by Pablo Neira Ayuso
parent 122868b378
commit 1fefe14725
3 changed files with 93 additions and 81 deletions

View File

@ -52,6 +52,8 @@ struct synproxy_stats {
struct synproxy_net {
struct nf_conn *tmpl;
struct synproxy_stats __percpu *stats;
unsigned int hook_ref4;
unsigned int hook_ref6;
};
extern unsigned int synproxy_net_id;

View File

@ -409,33 +409,6 @@ static unsigned int ipv4_synproxy_hook(void *priv,
return NF_ACCEPT;
}
static int synproxy_tg4_check(const struct xt_tgchk_param *par)
{
const struct ipt_entry *e = par->entryinfo;
if (e->ip.proto != IPPROTO_TCP ||
e->ip.invflags & XT_INV_PROTO)
return -EINVAL;
return nf_ct_netns_get(par->net, par->family);
}
static void synproxy_tg4_destroy(const struct xt_tgdtor_param *par)
{
nf_ct_netns_put(par->net, par->family);
}
static struct xt_target synproxy_tg4_reg __read_mostly = {
.name = "SYNPROXY",
.family = NFPROTO_IPV4,
.hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
.target = synproxy_tg4,
.targetsize = sizeof(struct xt_synproxy_info),
.checkentry = synproxy_tg4_check,
.destroy = synproxy_tg4_destroy,
.me = THIS_MODULE,
};
static struct nf_hook_ops ipv4_synproxy_ops[] __read_mostly = {
{
.hook = ipv4_synproxy_hook,
@ -451,31 +424,63 @@ static struct nf_hook_ops ipv4_synproxy_ops[] __read_mostly = {
},
};
static int __init synproxy_tg4_init(void)
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;
int err;
err = nf_register_hooks(ipv4_synproxy_ops,
ARRAY_SIZE(ipv4_synproxy_ops));
if (err < 0)
goto err1;
if (e->ip.proto != IPPROTO_TCP ||
e->ip.invflags & XT_INV_PROTO)
return -EINVAL;
err = xt_register_target(&synproxy_tg4_reg);
if (err < 0)
goto err2;
err = nf_ct_netns_get(par->net, par->family);
if (err)
return err;
return 0;
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;
}
}
err2:
nf_unregister_hooks(ipv4_synproxy_ops, ARRAY_SIZE(ipv4_synproxy_ops));
err1:
snet->hook_ref4++;
return err;
}
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);
}
static struct xt_target synproxy_tg4_reg __read_mostly = {
.name = "SYNPROXY",
.family = NFPROTO_IPV4,
.hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
.target = synproxy_tg4,
.targetsize = sizeof(struct xt_synproxy_info),
.checkentry = synproxy_tg4_check,
.destroy = synproxy_tg4_destroy,
.me = THIS_MODULE,
};
static int __init synproxy_tg4_init(void)
{
return xt_register_target(&synproxy_tg4_reg);
}
static void __exit synproxy_tg4_exit(void)
{
xt_unregister_target(&synproxy_tg4_reg);
nf_unregister_hooks(ipv4_synproxy_ops, ARRAY_SIZE(ipv4_synproxy_ops));
}
module_init(synproxy_tg4_init);

View File

@ -430,34 +430,6 @@ static unsigned int ipv6_synproxy_hook(void *priv,
return NF_ACCEPT;
}
static int synproxy_tg6_check(const struct xt_tgchk_param *par)
{
const struct ip6t_entry *e = par->entryinfo;
if (!(e->ipv6.flags & IP6T_F_PROTO) ||
e->ipv6.proto != IPPROTO_TCP ||
e->ipv6.invflags & XT_INV_PROTO)
return -EINVAL;
return nf_ct_netns_get(par->net, par->family);
}
static void synproxy_tg6_destroy(const struct xt_tgdtor_param *par)
{
nf_ct_netns_put(par->net, par->family);
}
static struct xt_target synproxy_tg6_reg __read_mostly = {
.name = "SYNPROXY",
.family = NFPROTO_IPV6,
.hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
.target = synproxy_tg6,
.targetsize = sizeof(struct xt_synproxy_info),
.checkentry = synproxy_tg6_check,
.destroy = synproxy_tg6_destroy,
.me = THIS_MODULE,
};
static struct nf_hook_ops ipv6_synproxy_ops[] __read_mostly = {
{
.hook = ipv6_synproxy_hook,
@ -473,31 +445,64 @@ static struct nf_hook_ops ipv6_synproxy_ops[] __read_mostly = {
},
};
static int __init synproxy_tg6_init(void)
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;
int err;
err = nf_register_hooks(ipv6_synproxy_ops,
ARRAY_SIZE(ipv6_synproxy_ops));
if (err < 0)
goto err1;
if (!(e->ipv6.flags & IP6T_F_PROTO) ||
e->ipv6.proto != IPPROTO_TCP ||
e->ipv6.invflags & XT_INV_PROTO)
return -EINVAL;
err = xt_register_target(&synproxy_tg6_reg);
if (err < 0)
goto err2;
err = nf_ct_netns_get(par->net, par->family);
if (err)
return err;
return 0;
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;
}
}
err2:
nf_unregister_hooks(ipv6_synproxy_ops, ARRAY_SIZE(ipv6_synproxy_ops));
err1:
snet->hook_ref6++;
return err;
}
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);
}
static struct xt_target synproxy_tg6_reg __read_mostly = {
.name = "SYNPROXY",
.family = NFPROTO_IPV6,
.hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
.target = synproxy_tg6,
.targetsize = sizeof(struct xt_synproxy_info),
.checkentry = synproxy_tg6_check,
.destroy = synproxy_tg6_destroy,
.me = THIS_MODULE,
};
static int __init synproxy_tg6_init(void)
{
return xt_register_target(&synproxy_tg6_reg);
}
static void __exit synproxy_tg6_exit(void)
{
xt_unregister_target(&synproxy_tg6_reg);
nf_unregister_hooks(ipv6_synproxy_ops, ARRAY_SIZE(ipv6_synproxy_ops));
}
module_init(synproxy_tg6_init);