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:
parent
122868b378
commit
1fefe14725
|
@ -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,33 +409,6 @@ static unsigned int ipv4_synproxy_hook(void *priv,
|
||||||
return NF_ACCEPT;
|
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 = {
|
static struct nf_hook_ops ipv4_synproxy_ops[] __read_mostly = {
|
||||||
{
|
{
|
||||||
.hook = ipv4_synproxy_hook,
|
.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;
|
int err;
|
||||||
|
|
||||||
err = nf_register_hooks(ipv4_synproxy_ops,
|
if (e->ip.proto != IPPROTO_TCP ||
|
||||||
ARRAY_SIZE(ipv4_synproxy_ops));
|
e->ip.invflags & XT_INV_PROTO)
|
||||||
if (err < 0)
|
return -EINVAL;
|
||||||
goto err1;
|
|
||||||
|
|
||||||
err = xt_register_target(&synproxy_tg4_reg);
|
err = nf_ct_netns_get(par->net, par->family);
|
||||||
if (err < 0)
|
if (err)
|
||||||
goto err2;
|
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:
|
snet->hook_ref4++;
|
||||||
nf_unregister_hooks(ipv4_synproxy_ops, ARRAY_SIZE(ipv4_synproxy_ops));
|
|
||||||
err1:
|
|
||||||
return err;
|
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)
|
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,34 +430,6 @@ static unsigned int ipv6_synproxy_hook(void *priv,
|
||||||
return NF_ACCEPT;
|
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 = {
|
static struct nf_hook_ops ipv6_synproxy_ops[] __read_mostly = {
|
||||||
{
|
{
|
||||||
.hook = ipv6_synproxy_hook,
|
.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;
|
int err;
|
||||||
|
|
||||||
err = nf_register_hooks(ipv6_synproxy_ops,
|
if (!(e->ipv6.flags & IP6T_F_PROTO) ||
|
||||||
ARRAY_SIZE(ipv6_synproxy_ops));
|
e->ipv6.proto != IPPROTO_TCP ||
|
||||||
if (err < 0)
|
e->ipv6.invflags & XT_INV_PROTO)
|
||||||
goto err1;
|
return -EINVAL;
|
||||||
|
|
||||||
err = xt_register_target(&synproxy_tg6_reg);
|
err = nf_ct_netns_get(par->net, par->family);
|
||||||
if (err < 0)
|
if (err)
|
||||||
goto err2;
|
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:
|
snet->hook_ref6++;
|
||||||
nf_unregister_hooks(ipv6_synproxy_ops, ARRAY_SIZE(ipv6_synproxy_ops));
|
|
||||||
err1:
|
|
||||||
return err;
|
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)
|
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);
|
||||||
|
|
Loading…
Reference in New Issue