Re: [RFC] generic CONNTRACK target

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Pablo Neira Ayuso wrote:
> Attached an untested RFC patch [...]

I forgot to attach the patch...

-- 
"Los honestos son inadaptados sociales" -- Les Luthiers
[RFC] Introduce the generic conntrack target

This patch implements the generic CONNTRACK target which merges
CONNMARK, CONNSECMARK, NOTRACK and TIMEOUT into a single target. Also,
This patch introduces the volatile events marking to make ctnetlink ignore
certain events.

Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>

Index: net-2.6.git/include/linux/netfilter/nf_conntrack_common.h
===================================================================
--- net-2.6.git.orig/include/linux/netfilter/nf_conntrack_common.h	2008-01-02 03:43:36.000000000 +0100
+++ net-2.6.git/include/linux/netfilter/nf_conntrack_common.h	2008-01-02 04:54:29.000000000 +0100
@@ -73,6 +73,10 @@ enum ip_conntrack_status {
 	/* Connection has fixed timeout. */
 	IPS_FIXED_TIMEOUT_BIT = 10,
 	IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
+
+	/* Connection has a manually configured timeout. */
+	IPS_MANUAL_TIMEOUT_BIT = 11,
+	IPS_MANUAL_TIMEOUT = (1 << IPS_MANUAL_TIMEOUT_BIT),
 };
 
 /* Connection tracking event bits */
@@ -137,6 +141,10 @@ enum ip_conntrack_events
 	/* Secmark is set */
 	IPCT_SECMARK_BIT = 14,
 	IPCT_SECMARK = (1 << IPCT_SECMARK_BIT),
+
+	/* These events has been set as volatile (via iptables) */
+	IPCT_VOLATILE_BIT = 15,
+	IPCT_VOLATILE = (1 << IPCT_VOLATILE_BIT),
 };
 
 enum ip_conntrack_expect_events {
Index: net-2.6.git/include/net/netfilter/nf_conntrack.h
===================================================================
--- net-2.6.git.orig/include/net/netfilter/nf_conntrack.h	2008-01-02 03:43:36.000000000 +0100
+++ net-2.6.git/include/net/netfilter/nf_conntrack.h	2008-01-02 03:47:52.000000000 +0100
@@ -88,6 +88,10 @@ struct nf_conn_help {
 	unsigned int expecting;
 };
 
+/* nf_conn feature for manual timeouts via iptables */
+struct nf_conn_timeout {
+	u_int32_t       timeout;
+};
 
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
Index: net-2.6.git/include/net/netfilter/nf_conntrack_extend.h
===================================================================
--- net-2.6.git.orig/include/net/netfilter/nf_conntrack_extend.h	2008-01-02 03:43:36.000000000 +0100
+++ net-2.6.git/include/net/netfilter/nf_conntrack_extend.h	2008-01-02 03:48:45.000000000 +0100
@@ -7,11 +7,13 @@ enum nf_ct_ext_id
 {
 	NF_CT_EXT_HELPER,
 	NF_CT_EXT_NAT,
+	NF_CT_EXT_TIMEOUT,
 	NF_CT_EXT_NUM,
 };
 
 #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help
 #define NF_CT_EXT_NAT_TYPE struct nf_conn_nat
+#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
 
 /* Extensions: optional stuff which isn't permanently in struct. */
 struct nf_ct_ext {
@@ -82,4 +84,10 @@ struct nf_ct_ext_type
 
 int nf_ct_extend_register(struct nf_ct_ext_type *type);
 void nf_ct_extend_unregister(struct nf_ct_ext_type *type);
+
+static inline struct nf_conn_timeout *nfct_timeout(const struct nf_conn *ct)
+{
+	return nf_ct_ext_find(ct, NF_CT_EXT_TIMEOUT);
+}
+
 #endif /* _NF_CONNTRACK_EXTEND_H */
Index: net-2.6.git/net/netfilter/Kconfig
===================================================================
--- net-2.6.git.orig/net/netfilter/Kconfig	2008-01-02 03:43:36.000000000 +0100
+++ net-2.6.git/net/netfilter/Kconfig	2008-01-02 05:00:44.000000000 +0100
@@ -420,6 +420,30 @@ config NETFILTER_XT_TARGET_CONNSECMARK
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_TARGET_CONNTRACK
+	tristate '"CONNTRACK" target support'
+	depends on NETFILTER_XTABLES
+	depends on NF_CONNTRACK
+	default m if NETFILTER_ADVANCED=n
+	help
+	  The generic CONNTRACK target:
+	  a) allows you to manipulate the connection mark value. Similar
+	  to the MARK target, but affects the connection mark value rather
+	  than the packet mark value.
+	  b) allows you to copy security markings from packets to connections,
+	  and restores security markings from connections to packets (if the
+	  packets are not already marked).  This would normally be used in
+	  conjunction with the SECMARK target.
+	  c) allows you to alter the timeout of specific sessions in the
+	  conntrack/NAT subsystem.  Specific conntracks can be given longer
+	  or shorter timeouts than the global defaults.
+	  d) allows a select rule to specify which packets *not* to enter
+	  the conntrack/NAT subsystem with all the consequences (no ICMP error
+	  tracking, no protocol helpers for the selected packets).
+	  e) allows you to skip ctnetlink events delivery
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_TARGET_TCPMSS
 	tristate '"TCPMSS" target support'
 	depends on NETFILTER_XTABLES && (IPV6 || IPV6=n)
Index: net-2.6.git/net/netfilter/Makefile
===================================================================
--- net-2.6.git.orig/net/netfilter/Makefile	2008-01-02 03:43:36.000000000 +0100
+++ net-2.6.git/net/netfilter/Makefile	2008-01-02 03:44:04.000000000 +0100
@@ -41,6 +41,7 @@ obj-$(CONFIG_NETFILTER_XTABLES) += x_tab
 obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_CONNTRACK) += xt_CONNTRACK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
Index: net-2.6.git/net/netfilter/nf_conntrack_core.c
===================================================================
--- net-2.6.git.orig/net/netfilter/nf_conntrack_core.c	2008-01-02 03:43:36.000000000 +0100
+++ net-2.6.git/net/netfilter/nf_conntrack_core.c	2008-01-02 03:44:04.000000000 +0100
@@ -781,6 +781,10 @@ void __nf_ct_refresh_acct(struct nf_conn
 		return;
 	}
 
+	/* This conntrack has a manual timeout set via iptables */
+	if (test_bit(IPS_MANUAL_TIMEOUT_BIT, &ct->status) && nfct_timeout(ct))
+		extra_jiffies = nfct_timeout(ct)->timeout;
+
 	/* If not in hash table, timer will not be active yet */
 	if (!nf_ct_is_confirmed(ct)) {
 		ct->timeout.expires = extra_jiffies;
Index: net-2.6.git/net/netfilter/nf_conntrack_netlink.c
===================================================================
--- net-2.6.git.orig/net/netfilter/nf_conntrack_netlink.c	2008-01-02 03:43:36.000000000 +0100
+++ net-2.6.git/net/netfilter/nf_conntrack_netlink.c	2008-01-02 04:55:38.000000000 +0100
@@ -4,7 +4,7 @@
  * (C) 2001 by Jay Schulist <jschlst@xxxxxxxxx>
  * (C) 2002-2006 by Harald Welte <laforge@xxxxxxxxxxxx>
  * (C) 2003 by Patrick Mchardy <kaber@xxxxxxxxx>
- * (C) 2005-2007 by Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
+ * (C) 2005-2008 by Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
  *
  * Initial connection tracking via netlink development funded and
  * generally made possible by Network Robots, Inc. (www.networkrobots.com)
@@ -427,6 +427,9 @@ static int ctnetlink_conntrack_event(str
 	if (ct == &nf_conntrack_untracked)
 		return NOTIFY_DONE;
 
+	if (events & IPCT_VOLATILE)
+		return NOTIFY_DONE;
+
 	if (events & IPCT_DESTROY) {
 		type = IPCTNL_MSG_CT_DELETE;
 		group = NFNLGRP_CONNTRACK_DESTROY;
Index: net-2.6.git/net/netfilter/xt_CONNTRACK.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ net-2.6.git/net/netfilter/xt_CONNTRACK.c	2008-01-02 05:03:23.000000000 +0100
@@ -0,0 +1,304 @@
+/*
+ * (C) 2008 Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on the following previous works:
+ * 	CONNMARK target:	Henrik Nordstrom <hno@xxxxxxxxxxxxxxx>
+ * 	NOTRACK target:		Jeremy Kerr <jk@xxxxxxxxxx>
+ * 	CONNSECMARK target:	James Morris <jmorris@xxxxxxxxxx>
+ * 	TIMEOUT target:		Phil Oester <kernel@xxxxxxxxxxxx>
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CONNTRACK.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
+
+#define PFX "xt_CONNTRACK: "
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>");
+MODULE_DESCRIPTION("ip[6]tables CONNTRACK module");
+MODULE_ALIAS("ipt_CONNTRACK");
+MODULE_ALIAS("ip6t_CONNTRACK");
+
+#define CT_TG_MASK(x) (x->data_0)
+#define CT_TG_MARK(x) (x->data_1)
+
+static void mark_set(struct sk_buff *skb,
+		     struct nf_conn *ct,
+		     const struct xt_conntrack_tg_info *info)
+{
+	u_int32_t newmark;
+
+	newmark = (ct->mark & ~CT_TG_MASK(info)) | CT_TG_MARK(info);
+	if (newmark != ct->mark) {
+		ct->mark = newmark;
+		nf_conntrack_event_cache(IPCT_MARK, skb);
+	}
+}
+
+static void mark_save(struct sk_buff *skb,
+		      struct nf_conn *ct,
+		      const struct xt_conntrack_tg_info *info)
+{
+	u_int32_t newmark;
+
+	newmark = (ct->mark & ~CT_TG_MASK(info)) |
+		  (skb->mark & CT_TG_MASK(info));
+	if (ct->mark != newmark) {
+		ct->mark = newmark;
+		nf_conntrack_event_cache(IPCT_MARK, skb);
+	}
+}
+
+static void mark_restore(struct sk_buff *skb,
+			 struct nf_conn *ct,
+			 const struct xt_conntrack_tg_info *info)
+{
+	u_int32_t mark, diff;
+
+	mark = skb->mark;
+	diff = (ct->mark ^ mark) & CT_TG_MASK(info);
+	skb->mark = mark ^ diff;
+}
+
+static void secmark_save(struct sk_buff *skb,
+			 struct nf_conn *ct,
+			 const struct xt_conntrack_tg_info *info)
+{
+	if (skb->secmark && !ct->secmark) {
+		ct->secmark = skb->secmark;
+		nf_conntrack_event_cache(IPCT_SECMARK, skb);
+	}
+}
+
+static void secmark_restore(struct sk_buff *skb,
+			    struct nf_conn *ct,
+			    const struct xt_conntrack_tg_info *info)
+{
+	if (!skb->secmark && ct->secmark)
+		skb->secmark = ct->secmark;
+}
+
+static void notrack(struct sk_buff *skb,
+		    struct nf_conn *ct,
+		    const struct xt_conntrack_tg_info *info)
+{
+	/* Previously seen (loopback)? Ignore. */
+	if (skb->nfct != NULL)
+		return;
+
+	/* Attach fake conntrack entry.
+	 * If there is a real ct entry correspondig to this packet,
+	 * it'll hang aroun till timing out. We don't deal with it
+	 * for performance reasons. JK */
+	skb->nfct = &nf_conntrack_untracked.ct_general;
+	skb->nfctinfo = IP_CT_NEW;
+	nf_conntrack_get(skb->nfct);
+}
+
+#define CT_TG_TIMEOUT(x) (x->data_0)
+
+static void manual_timeout(struct sk_buff *skb,
+			   struct nf_conn *ct,
+			   const struct xt_conntrack_tg_info *info)
+{
+	struct nf_conn_timeout *timeout_ext;
+
+	timeout_ext = nfct_timeout(ct);
+	if (!timeout_ext) {
+		timeout_ext = nf_ct_ext_add(ct, NF_CT_EXT_TIMEOUT, GFP_ATOMIC);
+		if (timeout_ext == NULL) {
+			pr_debug("failed to add TIMEOUT extension\n");
+			return;
+		}
+	}
+	timeout_ext->timeout = CT_TG_TIMEOUT(info) * HZ;
+	set_bit(IPS_MANUAL_TIMEOUT_BIT, &ct->status);
+}
+
+static void volatile_events(struct sk_buff *skb,
+				  struct nf_conn *ct,
+				  const struct xt_conntrack_tg_info *info)
+{
+	nf_conntrack_event_cache(IPCT_VOLATILE, skb);
+}
+
+typedef void (*ct_tg_array)(struct sk_buff *skb,
+			    struct nf_conn *ct,
+			    const struct xt_conntrack_tg_info *info);
+
+ct_tg_array conntrack_tg_array[CONNTRACK_TG_MAX] = {
+	[CONNTRACK_TG_MARK_SET]			= mark_set,
+	[CONNTRACK_TG_MARK_SAVE]		= mark_save,
+	[CONNTRACK_TG_MARK_RESTORE]		= mark_restore,
+	[CONNTRACK_TG_SECMARK_SAVE]		= secmark_save,
+	[CONNTRACK_TG_SECMARK_RESTORE]		= secmark_restore,
+	[CONNTRACK_TG_NOTRACK]			= notrack,
+	[CONNTRACK_TG_MANUAL_TIMEOUT]		= manual_timeout,
+	[CONNTRACK_TG_VOLATILE_EVENTS]		= volatile_events,
+};
+
+static unsigned int
+conntrack_tg(struct sk_buff *skb, const struct net_device *in,
+             const struct net_device *out, unsigned int hooknum,
+             const struct xt_target *target, const void *targinfo)
+{
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+	const struct xt_conntrack_tg_info *info = targinfo;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (!ct)
+		return XT_CONTINUE;
+
+	if (ct == &nf_conntrack_untracked)
+		return XT_CONTINUE;
+
+	conntrack_tg_array[info->mode](skb, ct, info);
+
+	return XT_CONTINUE;
+}
+
+static bool
+conntrack_tg_check(const char *tablename, const void *entry,
+                   const struct xt_target *target, void *targinfo,
+                   unsigned int hook_mask)
+{
+	const struct xt_conntrack_tg_info *info = targinfo;
+
+	switch(info->mode) {
+	case CONNTRACK_TG_MARK_SET:
+	case CONNTRACK_TG_MARK_SAVE:
+	case CONNTRACK_TG_MARK_RESTORE:
+	case CONNTRACK_TG_SECMARK_SAVE:
+	case CONNTRACK_TG_SECMARK_RESTORE:
+	case CONNTRACK_TG_MANUAL_TIMEOUT:
+	case CONNTRACK_TG_VOLATILE_EVENTS:
+		if (strcmp(tablename, "mangle") != 0) {
+			printk(KERN_INFO PFX "use mode %hu in table "
+					     "`mangle\'\n", info->mode);
+			return false;
+		}
+		break;
+	case CONNTRACK_TG_NOTRACK:
+		if (strcmp(tablename, "raw") != 0) {
+			printk(KERN_INFO PFX "use mode: %hu in table "
+					     "`raw\'\n", info->mode);
+			return false;
+		}
+		break;
+	default:
+		printk(KERN_INFO PFX "unsupported mode: %hu\n", info->mode);
+		return false;
+	}
+
+	if (nf_ct_l3proto_try_module_get(target->family) < 0) {
+		printk(KERN_WARNING "can't load conntrack support for "
+				    "proto=%u\n", target->family);
+		return false;
+	}
+	return true;
+}
+
+static void
+conntrack_tg_destroy(const struct xt_target *target, void *targinfo)
+{
+	nf_ct_l3proto_module_put(target->family);
+}
+
+static struct xt_target conntrack_tg_mangle_reg[] __read_mostly = {
+	{
+		.name		= "CONNTRACK",
+		.family		= AF_INET,
+		.checkentry	= conntrack_tg_check,
+		.destroy	= conntrack_tg_destroy,
+		.target		= conntrack_tg,
+		.targetsize	= sizeof(struct xt_conntrack_tg_info),
+		.table		= "mangle",
+		.me		= THIS_MODULE,
+	},
+	{
+		.name		= "CONNTRACK",
+		.family		= AF_INET6,
+		.checkentry	= conntrack_tg_check,
+		.destroy	= conntrack_tg_destroy,
+		.target		= conntrack_tg,
+		.targetsize	= sizeof(struct xt_conntrack_tg_info),
+		.table		= "mangle",
+		.me		= THIS_MODULE,
+	},
+};
+
+static struct xt_target conntrack_tg_raw_reg[] __read_mostly = {
+	{
+		.name		= "CONNTRACK",
+		.family		= AF_INET,
+		.checkentry	= conntrack_tg_check,
+		.destroy	= conntrack_tg_destroy,
+		.target		= conntrack_tg,
+		.targetsize	= sizeof(struct xt_conntrack_tg_info),
+		.table		= "raw",
+		.me		= THIS_MODULE,
+	},
+	{
+		.name		= "CONNTRACK",
+		.family		= AF_INET6,
+		.checkentry	= conntrack_tg_check,
+		.destroy	= conntrack_tg_destroy,
+		.target		= conntrack_tg,
+		.targetsize	= sizeof(struct xt_conntrack_tg_info),
+		.table		= "raw",
+		.me		= THIS_MODULE,
+	},
+};
+
+static struct nf_ct_ext_type timeout_extend __read_mostly = {
+	.len		= sizeof(struct nf_conn_timeout),
+	.align		= __alignof__(struct nf_conn_timeout),
+	.id		= NF_CT_EXT_TIMEOUT,
+};
+
+static int __init conntrack_tg_init(void)
+{
+	int ret;
+
+	ret = nf_ct_extend_register(&timeout_extend);
+	if (ret < 0) {
+		printk(KERN_ERR PFX "unable to register extension\n");
+		return ret;
+	}
+
+	ret = xt_register_targets(conntrack_tg_mangle_reg,
+				  ARRAY_SIZE(conntrack_tg_mangle_reg));
+	if (ret < 0)
+		nf_ct_extend_unregister(&timeout_extend);
+
+	ret = xt_register_targets(conntrack_tg_raw_reg,
+				  ARRAY_SIZE(conntrack_tg_raw_reg));
+	if (ret < 0) {
+		nf_ct_extend_unregister(&timeout_extend);
+		xt_unregister_targets(conntrack_tg_mangle_reg,
+				      ARRAY_SIZE(conntrack_tg_mangle_reg));
+	}
+
+	return ret;
+}
+
+static void __exit conntrack_tg_exit(void)
+{
+	nf_ct_extend_unregister(&timeout_extend);
+	xt_unregister_targets(conntrack_tg_mangle_reg,
+			      ARRAY_SIZE(conntrack_tg_mangle_reg));
+	xt_unregister_targets(conntrack_tg_raw_reg,
+			      ARRAY_SIZE(conntrack_tg_raw_reg));
+}
+
+module_init(conntrack_tg_init);
+module_exit(conntrack_tg_exit);
Index: net-2.6.git/include/linux/netfilter/xt_CONNTRACK.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ net-2.6.git/include/linux/netfilter/xt_CONNTRACK.h	2008-01-02 05:03:40.000000000 +0100
@@ -0,0 +1,22 @@
+#ifndef _XT_CONNTRACK_H_target
+#define _XT_CONNTRACK_H_target
+
+enum {
+	CONNTRACK_TG_MARK_SET = 0,
+	CONNTRACK_TG_MARK_SAVE,
+	CONNTRACK_TG_MARK_RESTORE,
+	CONNTRACK_TG_SECMARK_SAVE,
+	CONNTRACK_TG_SECMARK_RESTORE,
+	CONNTRACK_TG_NOTRACK,
+	CONNTRACK_TG_MANUAL_TIMEOUT,
+	CONNTRACK_TG_VOLATILE_EVENTS,
+	CONNTRACK_TG_MAX
+};
+
+struct xt_conntrack_tg_info {
+	u_int32_t mode;
+	u_int32_t data_0;
+	u_int32_t data_1;
+};
+
+#endif /*_XT_CONNTRACK_H_target */

[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux