[Devel,rh7,3/4] net: Mark conntrack users in xtables

Submitted by Kirill Tkhai on Sept. 6, 2016, 6:31 a.m.

Details

Message ID 147314350299.331.2889428978711666329.stgit@pro
State New
Series "Create conntrack structures only if they are really needed"
Headers show

Commit Message

Kirill Tkhai Sept. 6, 2016, 6:31 a.m.
Allow conntracks to be allocated in case of these
rules are inserted.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 net/ipv4/netfilter/ipt_CLUSTERIP.c   |    4 ++++
 net/ipv4/netfilter/ipt_MASQUERADE.c  |    7 +++++++
 net/ipv4/netfilter/ipt_SYNPROXY.c    |    7 ++++++-
 net/ipv6/netfilter/ip6t_MASQUERADE.c |    7 +++++++
 net/ipv6/netfilter/ip6t_SYNPROXY.c   |    7 ++++++-
 net/netfilter/xt_CONNSECMARK.c       |    3 +++
 net/netfilter/xt_HMARK.c             |    8 ++++++++
 net/netfilter/xt_NETMAP.c            |    8 ++++++++
 net/netfilter/xt_REDIRECT.c          |    9 +++++++++
 net/netfilter/xt_cluster.c           |    7 +++++++
 net/netfilter/xt_connbytes.c         |    3 +++
 net/netfilter/xt_connlabel.c         |    4 +++-
 net/netfilter/xt_connlimit.c         |    3 +++
 net/netfilter/xt_connmark.c          |    4 ++++
 net/netfilter/xt_conntrack.c         |    3 +++
 net/netfilter/xt_helper.c            |    2 ++
 net/netfilter/xt_ipvs.c              |    7 +++++++
 net/netfilter/xt_nat.c               |   18 ++++++++++++++++++
 net/netfilter/xt_socket.c            |   19 +++++++++++++++++++
 net/netfilter/xt_state.c             |    3 +++
 20 files changed, 130 insertions(+), 3 deletions(-)

Patch hide | download patch | download mbox

diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 5798d53..2159f32 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -418,6 +418,8 @@  static int clusterip_tg_check(const struct xt_tgchk_param *par)
 	if (ret < 0)
 		pr_info("cannot load conntrack support for proto=%u\n",
 			par->family);
+	else
+		inc_conntrack_users(par->net);
 	return ret;
 }
 
@@ -426,6 +428,8 @@  static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
 {
 	const struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
 
+	dec_conntrack_users(par->net);
+
 	/* if no more entries are referencing the config, remove it
 	 * from the list and destroy the proc entry */
 	clusterip_config_entry_put(cipinfo->config);
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index da7f02a..1275737 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -41,9 +41,15 @@  static int masquerade_tg_check(const struct xt_tgchk_param *par)
 		pr_debug("bad rangesize %u\n", mr->rangesize);
 		return -EINVAL;
 	}
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
+static void masquerade_tg_destroy(const struct xt_tgdtor_param *par)
+{
+	dec_conntrack_users(par->net);
+}
+
 static unsigned int
 masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
@@ -66,6 +72,7 @@  static struct xt_target masquerade_tg_reg __read_mostly = {
 	.table		= "nat",
 	.hooks		= 1 << NF_INET_POST_ROUTING,
 	.checkentry	= masquerade_tg_check,
+	.destroy	= masquerade_tg_destroy,
 	.me		= THIS_MODULE,
 };
 
diff --git a/net/ipv4/netfilter/ipt_SYNPROXY.c b/net/ipv4/netfilter/ipt_SYNPROXY.c
index f28cd93..36a802e 100644
--- a/net/ipv4/netfilter/ipt_SYNPROXY.c
+++ b/net/ipv4/netfilter/ipt_SYNPROXY.c
@@ -408,16 +408,21 @@  static unsigned int ipv4_synproxy_hook(const struct nf_hook_ops *ops,
 static int synproxy_tg4_check(const struct xt_tgchk_param *par)
 {
 	const struct ipt_entry *e = par->entryinfo;
+	int ret;
 
 	if (e->ip.proto != IPPROTO_TCP ||
 	    e->ip.invflags & XT_INV_PROTO)
 		return -EINVAL;
 
-	return nf_ct_l3proto_try_module_get(par->family);
+	ret = nf_ct_l3proto_try_module_get(par->family);
+	if (ret == 0)
+		inc_conntrack_users(par->net);
+	return ret;
 }
 
 static void synproxy_tg4_destroy(const struct xt_tgdtor_param *par)
 {
+	dec_conntrack_users(par->net);
 	nf_ct_l3proto_module_put(par->family);
 }
 
diff --git a/net/ipv6/netfilter/ip6t_MASQUERADE.c b/net/ipv6/netfilter/ip6t_MASQUERADE.c
index 7f9f45d..b9263c7 100644
--- a/net/ipv6/netfilter/ip6t_MASQUERADE.c
+++ b/net/ipv6/netfilter/ip6t_MASQUERADE.c
@@ -33,13 +33,20 @@  static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
 
 	if (range->flags & NF_NAT_RANGE_MAP_IPS)
 		return -EINVAL;
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
+static void masquerade_tg6_destroy(const struct xt_tgdtor_param *par)
+{
+	dec_conntrack_users(par->net);
+}
+
 static struct xt_target masquerade_tg6_reg __read_mostly = {
 	.name		= "MASQUERADE",
 	.family		= NFPROTO_IPV6,
 	.checkentry	= masquerade_tg6_checkentry,
+	.destroy	= masquerade_tg6_destroy,
 	.target		= masquerade_tg6,
 	.targetsize	= sizeof(struct nf_nat_range),
 	.table		= "nat",
diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c
index 3308621..751f732 100644
--- a/net/ipv6/netfilter/ip6t_SYNPROXY.c
+++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c
@@ -432,17 +432,22 @@  static unsigned int ipv6_synproxy_hook(const struct nf_hook_ops *ops,
 static int synproxy_tg6_check(const struct xt_tgchk_param *par)
 {
 	const struct ip6t_entry *e = par->entryinfo;
+	int ret;
 
 	if (!(e->ipv6.flags & IP6T_F_PROTO) ||
 	    e->ipv6.proto != IPPROTO_TCP ||
 	    e->ipv6.invflags & XT_INV_PROTO)
 		return -EINVAL;
 
-	return nf_ct_l3proto_try_module_get(par->family);
+	ret = nf_ct_l3proto_try_module_get(par->family);
+	if (ret == 0)
+		inc_conntrack_users(par->net);
+	return ret;
 }
 
 static void synproxy_tg6_destroy(const struct xt_tgdtor_param *par)
 {
+	dec_conntrack_users(par->net);
 	nf_ct_l3proto_module_put(par->family);
 }
 
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index e04dc28..e7792a2 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -110,11 +110,14 @@  static int connsecmark_tg_check(const struct xt_tgchk_param *par)
 	if (ret < 0)
 		pr_info("cannot load conntrack support for proto=%u\n",
 			par->family);
+	else
+		inc_conntrack_users(par->net);
 	return ret;
 }
 
 static void connsecmark_tg_destroy(const struct xt_tgdtor_param *par)
 {
+	dec_conntrack_users(par->net);
 	nf_ct_l3proto_module_put(par->family);
 }
 
diff --git a/net/netfilter/xt_HMARK.c b/net/netfilter/xt_HMARK.c
index 73b73f6..02ecc7a 100644
--- a/net/netfilter/xt_HMARK.c
+++ b/net/netfilter/xt_HMARK.c
@@ -334,9 +334,15 @@  static int hmark_tg_check(const struct xt_tgchk_param *par)
 		pr_info("xt_HMARK: spi-set and port-set can't be combined\n");
 		return -EINVAL;
 	}
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
+static void hmark_tg_destroy(const struct xt_tgdtor_param *par)
+{
+	dec_conntrack_users(par->net);
+}
+
 static struct xt_target hmark_tg_reg[] __read_mostly = {
 	{
 		.name		= "HMARK",
@@ -344,6 +350,7 @@  static struct xt_target hmark_tg_reg[] __read_mostly = {
 		.target		= hmark_tg_v4,
 		.targetsize	= sizeof(struct xt_hmark_info),
 		.checkentry	= hmark_tg_check,
+		.destroy	= hmark_tg_destroy,
 		.me		= THIS_MODULE,
 	},
 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
@@ -353,6 +360,7 @@  static struct xt_target hmark_tg_reg[] __read_mostly = {
 		.target		= hmark_tg_v6,
 		.targetsize	= sizeof(struct xt_hmark_info),
 		.checkentry	= hmark_tg_check,
+		.destroy	= hmark_tg_destroy,
 		.me		= THIS_MODULE,
 	},
 #endif
diff --git a/net/netfilter/xt_NETMAP.c b/net/netfilter/xt_NETMAP.c
index b253e07..1b68d4a 100644
--- a/net/netfilter/xt_NETMAP.c
+++ b/net/netfilter/xt_NETMAP.c
@@ -60,6 +60,7 @@  static int netmap_tg6_checkentry(const struct xt_tgchk_param *par)
 
 	if (!(range->flags & NF_NAT_RANGE_MAP_IPS))
 		return -EINVAL;
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
@@ -111,8 +112,13 @@  static int netmap_tg4_check(const struct xt_tgchk_param *par)
 		pr_debug("bad rangesize %u.\n", mr->rangesize);
 		return -EINVAL;
 	}
+	inc_conntrack_users(par->net);
 	return 0;
 }
+static void netmap_tg_destroy(const struct xt_tgdtor_param *par)
+{
+	dec_conntrack_users(par->net);
+}
 
 static struct xt_target netmap_tg_reg[] __read_mostly = {
 	{
@@ -127,6 +133,7 @@  static struct xt_target netmap_tg_reg[] __read_mostly = {
 		              (1 << NF_INET_LOCAL_OUT) |
 		              (1 << NF_INET_LOCAL_IN),
 		.checkentry = netmap_tg6_checkentry,
+		.destroy    = netmap_tg_destroy,
 		.me         = THIS_MODULE,
 	},
 	{
@@ -141,6 +148,7 @@  static struct xt_target netmap_tg_reg[] __read_mostly = {
 		              (1 << NF_INET_LOCAL_OUT) |
 		              (1 << NF_INET_LOCAL_IN),
 		.checkentry = netmap_tg4_check,
+		.destroy    = netmap_tg_destroy,
 		.me         = THIS_MODULE,
 	},
 };
diff --git a/net/netfilter/xt_REDIRECT.c b/net/netfilter/xt_REDIRECT.c
index 22a1030..b4a3691 100644
--- a/net/netfilter/xt_REDIRECT.c
+++ b/net/netfilter/xt_REDIRECT.c
@@ -76,6 +76,7 @@  static int redirect_tg6_checkentry(const struct xt_tgchk_param *par)
 
 	if (range->flags & NF_NAT_RANGE_MAP_IPS)
 		return -EINVAL;
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
@@ -92,6 +93,7 @@  static int redirect_tg4_check(const struct xt_tgchk_param *par)
 		pr_debug("bad rangesize %u.\n", mr->rangesize);
 		return -EINVAL;
 	}
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
@@ -142,6 +144,11 @@  redirect_tg4(struct sk_buff *skb, const struct xt_action_param *par)
 	return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
 }
 
+static void redirect_tg_destroy(const struct xt_tgdtor_param *par)
+{
+	dec_conntrack_users(par->net);
+}
+
 static struct xt_target redirect_tg_reg[] __read_mostly = {
 	{
 		.name       = "REDIRECT",
@@ -150,6 +157,7 @@  static struct xt_target redirect_tg_reg[] __read_mostly = {
 		.table      = "nat",
 		.checkentry = redirect_tg6_checkentry,
 		.target     = redirect_tg6,
+		.destroy    = redirect_tg_destroy,
 		.targetsize = sizeof(struct nf_nat_range),
 		.hooks      = (1 << NF_INET_PRE_ROUTING) |
 		              (1 << NF_INET_LOCAL_OUT),
@@ -162,6 +170,7 @@  static struct xt_target redirect_tg_reg[] __read_mostly = {
 		.table      = "nat",
 		.target     = redirect_tg4,
 		.checkentry = redirect_tg4_check,
+		.destroy    = redirect_tg_destroy,
 		.targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
 		.hooks      = (1 << NF_INET_PRE_ROUTING) |
 		              (1 << NF_INET_LOCAL_OUT),
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c
index f4af1bf..5f462aa 100644
--- a/net/netfilter/xt_cluster.c
+++ b/net/netfilter/xt_cluster.c
@@ -147,14 +147,21 @@  static int xt_cluster_mt_checkentry(const struct xt_mtchk_param *par)
 			"higher than the total number of nodes\n");
 		return -EDOM;
 	}
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
+static void xt_cluster_mt_destroy(const struct xt_mtdtor_param *par)
+{
+	dec_conntrack_users(par->net);
+}
+
 static struct xt_match xt_cluster_match __read_mostly = {
 	.name		= "cluster",
 	.family		= NFPROTO_UNSPEC,
 	.match		= xt_cluster_mt,
 	.checkentry	= xt_cluster_mt_checkentry,
+	.destroy	= xt_cluster_mt_destroy,
 	.matchsize	= sizeof(struct xt_cluster_match_info),
 	.me		= THIS_MODULE,
 };
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index e595e07..15d203a 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -112,6 +112,8 @@  static int connbytes_mt_check(const struct xt_mtchk_param *par)
 	if (ret < 0)
 		pr_info("cannot load conntrack support for proto=%u\n",
 			par->family);
+	else
+		inc_conntrack_users(par->net);
 
 	/*
 	 * This filter cannot function correctly unless connection tracking
@@ -127,6 +129,7 @@  static int connbytes_mt_check(const struct xt_mtchk_param *par)
 
 static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
 {
+	dec_conntrack_users(par->net);
 	nf_ct_l3proto_module_put(par->family);
 }
 
diff --git a/net/netfilter/xt_connlabel.c b/net/netfilter/xt_connlabel.c
index 9f8719d..b5b3bb4 100644
--- a/net/netfilter/xt_connlabel.c
+++ b/net/netfilter/xt_connlabel.c
@@ -57,7 +57,8 @@  static int connlabel_mt_check(const struct xt_mtchk_param *par)
 		pr_info("cannot load conntrack support for proto=%u\n",
 							par->family);
 		return ret;
-	}
+	} else
+		inc_conntrack_users(par->net);
 
 	par->net->ct.labels_used++;
 	words = BITS_TO_LONGS(info->bit+1);
@@ -69,6 +70,7 @@  static int connlabel_mt_check(const struct xt_mtchk_param *par)
 
 static void connlabel_mt_destroy(const struct xt_mtdtor_param *par)
 {
+	dec_conntrack_users(par->net);
 	par->net->ct.labels_used--;
 	if (par->net->ct.labels_used == 0)
 		par->net->ct.label_words = 0;
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c
index 34aa0ba..1f1b928 100644
--- a/net/netfilter/xt_connlimit.c
+++ b/net/netfilter/xt_connlimit.c
@@ -389,6 +389,8 @@  static int connlimit_mt_check(const struct xt_mtchk_param *par)
 	for (i = 0; i < ARRAY_SIZE(info->data->climit_root6); ++i)
 		info->data->climit_root6[i] = RB_ROOT;
 
+	inc_conntrack_users(par->net);
+
 	return 0;
 }
 
@@ -416,6 +418,7 @@  static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
 	const struct xt_connlimit_info *info = par->matchinfo;
 	unsigned int i;
 
+	dec_conntrack_users(par->net);
 	nf_ct_l3proto_module_put(par->family);
 
 	for (i = 0; i < ARRAY_SIZE(info->data->climit_root4); ++i)
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index 3059aa3..2407e75 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -182,6 +182,7 @@  static int connmark_mt_check_v0(const struct xt_mtchk_param *par)
 				    "proto=%u\n", par->family);
 		return -EINVAL;
 	}
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
@@ -207,11 +208,14 @@  static int connmark_mt_check(const struct xt_mtchk_param *par)
 	if (ret < 0)
 		pr_info("cannot load conntrack support for proto=%u\n",
 			par->family);
+	else
+		inc_conntrack_users(par->net);
 	return ret;
 }
 
 static void connmark_mt_destroy(const struct xt_mtdtor_param *par)
 {
+	dec_conntrack_users(par->net);
 	nf_ct_l3proto_module_put(par->family);
 }
 
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 4846430..d8c1e58 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -415,11 +415,14 @@  static int conntrack_mt_check(const struct xt_mtchk_param *par)
 	if (ret < 0)
 		pr_info("cannot load conntrack support for proto=%u\n",
 			par->family);
+	else
+		inc_conntrack_users(par->net);
 	return ret;
 }
 
 static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
 {
+	dec_conntrack_users(par->net);
 	nf_ct_l3proto_module_put(par->family);
 }
 
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
index 9f4ab00..550951e 100644
--- a/net/netfilter/xt_helper.c
+++ b/net/netfilter/xt_helper.c
@@ -66,11 +66,13 @@  static int helper_mt_check(const struct xt_mtchk_param *par)
 		return ret;
 	}
 	info->name[29] = '\0';
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
 static void helper_mt_destroy(const struct xt_mtdtor_param *par)
 {
+	dec_conntrack_users(par->net);
 	nf_ct_l3proto_module_put(par->family);
 }
 
diff --git a/net/netfilter/xt_ipvs.c b/net/netfilter/xt_ipvs.c
index 8d47c37..44c0848 100644
--- a/net/netfilter/xt_ipvs.c
+++ b/net/netfilter/xt_ipvs.c
@@ -161,15 +161,22 @@  static int ipvs_mt_check(const struct xt_mtchk_param *par)
 		return -EINVAL;
 	}
 
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
+static void ipvs_mt_destroy(const struct xt_mtdtor_param *par)
+{
+	dec_conntrack_users(par->net);
+}
+
 static struct xt_match xt_ipvs_mt_reg __read_mostly = {
 	.name       = "ipvs",
 	.revision   = 0,
 	.family     = NFPROTO_UNSPEC,
 	.match      = ipvs_mt,
 	.checkentry = ipvs_mt_check,
+	.destroy    = ipvs_mt_destroy,
 	.matchsize  = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)),
 	.me         = THIS_MODULE,
 };
diff --git a/net/netfilter/xt_nat.c b/net/netfilter/xt_nat.c
index bea7464..d620e01 100644
--- a/net/netfilter/xt_nat.c
+++ b/net/netfilter/xt_nat.c
@@ -23,9 +23,21 @@  static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par)
 			par->target->name);
 		return -EINVAL;
 	}
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
+static int xt_nat_checkentry_v1(const struct xt_tgchk_param *par)
+{
+	inc_conntrack_users(par->net);
+	return 0;
+}
+
+static void xt_nat_tg_destroy(const struct xt_tgdtor_param *par)
+{
+	dec_conntrack_users(par->net);
+}
+
 static void xt_nat_convert_range(struct nf_nat_range *dst,
 				 const struct nf_nat_ipv4_range *src)
 {
@@ -108,6 +120,7 @@  static struct xt_target xt_nat_target_reg[] __read_mostly = {
 		.checkentry	= xt_nat_checkentry_v0,
 		.target		= xt_snat_target_v0,
 		.targetsize	= sizeof(struct nf_nat_ipv4_multi_range_compat),
+		.destroy	= xt_nat_tg_destroy,
 		.family		= NFPROTO_IPV4,
 		.table		= "nat",
 		.hooks		= (1 << NF_INET_POST_ROUTING) |
@@ -120,6 +133,7 @@  static struct xt_target xt_nat_target_reg[] __read_mostly = {
 		.checkentry	= xt_nat_checkentry_v0,
 		.target		= xt_dnat_target_v0,
 		.targetsize	= sizeof(struct nf_nat_ipv4_multi_range_compat),
+		.destroy	= xt_nat_tg_destroy,
 		.family		= NFPROTO_IPV4,
 		.table		= "nat",
 		.hooks		= (1 << NF_INET_PRE_ROUTING) |
@@ -129,8 +143,10 @@  static struct xt_target xt_nat_target_reg[] __read_mostly = {
 	{
 		.name		= "SNAT",
 		.revision	= 1,
+		.checkentry	= xt_nat_checkentry_v1,
 		.target		= xt_snat_target_v1,
 		.targetsize	= sizeof(struct nf_nat_range),
+		.destroy	= xt_nat_tg_destroy,
 		.table		= "nat",
 		.hooks		= (1 << NF_INET_POST_ROUTING) |
 				  (1 << NF_INET_LOCAL_IN),
@@ -139,8 +155,10 @@  static struct xt_target xt_nat_target_reg[] __read_mostly = {
 	{
 		.name		= "DNAT",
 		.revision	= 1,
+		.checkentry	= xt_nat_checkentry_v1,
 		.target		= xt_dnat_target_v1,
 		.targetsize	= sizeof(struct nf_nat_range),
+		.destroy	= xt_nat_tg_destroy,
 		.table		= "nat",
 		.hooks		= (1 << NF_INET_PRE_ROUTING) |
 				  (1 << NF_INET_LOCAL_OUT),
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 1ba6793..f6855c8 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -388,6 +388,12 @@  socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 }
 #endif
 
+static int socket_mt_v0_check(const struct xt_mtchk_param *par)
+{
+	inc_conntrack_users(par->net);
+	return 0;
+}
+
 static int socket_mt_v1_check(const struct xt_mtchk_param *par)
 {
 	const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
@@ -396,6 +402,7 @@  static int socket_mt_v1_check(const struct xt_mtchk_param *par)
 		pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1);
 		return -EINVAL;
 	}
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
@@ -407,15 +414,23 @@  static int socket_mt_v2_check(const struct xt_mtchk_param *par)
 		pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2);
 		return -EINVAL;
 	}
+	inc_conntrack_users(par->net);
 	return 0;
 }
 
+static void socket_mt_destroy(const struct xt_mtdtor_param *par)
+{
+	dec_conntrack_users(par->net);
+}
+
 static struct xt_match socket_mt_reg[] __read_mostly = {
 	{
 		.name		= "socket",
 		.revision	= 0,
 		.family		= NFPROTO_IPV4,
 		.match		= socket_mt4_v0,
+		.checkentry	= socket_mt_v0_check,
+		.destroy	= socket_mt_destroy,
 		.hooks		= (1 << NF_INET_PRE_ROUTING) |
 				  (1 << NF_INET_LOCAL_IN),
 		.me		= THIS_MODULE,
@@ -426,6 +441,7 @@  static struct xt_match socket_mt_reg[] __read_mostly = {
 		.family		= NFPROTO_IPV4,
 		.match		= socket_mt4_v1_v2,
 		.checkentry	= socket_mt_v1_check,
+		.destroy	= socket_mt_destroy,
 		.matchsize	= sizeof(struct xt_socket_mtinfo1),
 		.hooks		= (1 << NF_INET_PRE_ROUTING) |
 				  (1 << NF_INET_LOCAL_IN),
@@ -438,6 +454,7 @@  static struct xt_match socket_mt_reg[] __read_mostly = {
 		.family		= NFPROTO_IPV6,
 		.match		= socket_mt6_v1_v2,
 		.checkentry	= socket_mt_v1_check,
+		.destroy	= socket_mt_destroy,
 		.matchsize	= sizeof(struct xt_socket_mtinfo1),
 		.hooks		= (1 << NF_INET_PRE_ROUTING) |
 				  (1 << NF_INET_LOCAL_IN),
@@ -450,6 +467,7 @@  static struct xt_match socket_mt_reg[] __read_mostly = {
 		.family		= NFPROTO_IPV4,
 		.match		= socket_mt4_v1_v2,
 		.checkentry	= socket_mt_v2_check,
+		.destroy	= socket_mt_destroy,
 		.matchsize	= sizeof(struct xt_socket_mtinfo1),
 		.hooks		= (1 << NF_INET_PRE_ROUTING) |
 				  (1 << NF_INET_LOCAL_IN),
@@ -462,6 +480,7 @@  static struct xt_match socket_mt_reg[] __read_mostly = {
 		.family		= NFPROTO_IPV6,
 		.match		= socket_mt6_v1_v2,
 		.checkentry	= socket_mt_v2_check,
+		.destroy	= socket_mt_destroy,
 		.matchsize	= sizeof(struct xt_socket_mtinfo1),
 		.hooks		= (1 << NF_INET_PRE_ROUTING) |
 				  (1 << NF_INET_LOCAL_IN),
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index a507922..b065bac 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -47,11 +47,14 @@  static int state_mt_check(const struct xt_mtchk_param *par)
 	if (ret < 0)
 		pr_info("cannot load conntrack support for proto=%u\n",
 			par->family);
+	else
+		inc_conntrack_users(par->net);
 	return ret;
 }
 
 static void state_mt_destroy(const struct xt_mtdtor_param *par)
 {
+	dec_conntrack_users(par->net);
 	nf_ct_l3proto_module_put(par->family);
 }