diff -ruN iptables-1.3.8.0debian1/iptables/include/linux/netfilter/xt_timeout.h iptables-patch/iptables/include/linux/netfilter/xt_timeout.h
--- iptables-1.3.8.0debian1/iptables/include/linux/netfilter/xt_timeout.h	1970-01-01 01:00:00.000000000 +0100
+++ iptables-patch/iptables/include/linux/netfilter/xt_timeout.h	2008-01-27 01:27:24.000000000 +0100
@@ -0,0 +1,10 @@
+#ifndef _XT_TIMEOUT_H
+#define _XT_TIMEOUT_H
+
+struct xt_timeout_info {
+	struct timespec match_from;
+	struct timespec match_upto;
+	int invert;
+};
+
+#endif /*_XT_TIMEOUT_H*/
diff -ruN iptables-1.3.8.0debian1/iptables/iptables.c iptables-patch/iptables/iptables.c
--- iptables-1.3.8.0debian1/iptables/iptables.c	2007-04-30 01:03:30.000000000 +0200
+++ iptables-patch/iptables/iptables.c	2008-01-27 01:47:01.000000000 +0100
@@ -80,9 +80,10 @@
 #define CMD_DELETE_CHAIN	0x0200U
 #define CMD_SET_POLICY		0x0400U
 #define CMD_RENAME_CHAIN	0x0800U
+#define CMD_CLEAN		0x1000U
 #define NUMBER_OF_CMD	13
 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
-				 'N', 'X', 'P', 'E' };
+				 'N', 'X', 'P', 'E', 'C' };
 
 #define OPTION_OFFSET 256
 
@@ -114,6 +115,7 @@
 	{ "new-chain", 1, 0,  'N' },
 	{ "delete-chain", 2, 0,  'X' },
 	{ "rename-chain", 1, 0,  'E' },
+	{ "clean", 2, 0,  'C' },
 	{ "policy", 1, 0,  'P' },
 	{ "source", 1, 0, 's' },
 	{ "destination", 1, 0,  'd' },
@@ -171,7 +173,8 @@
 /*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
 /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
 /*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x','x'}
+/*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x','x'},
+/*CLEAN*/     {'x','x','x','x','x',' ','x','x','x','x','x','x'}
 };
 
 static int inverse_for_options[NUMBER_OF_OPT] =
@@ -418,7 +421,7 @@
 "       %s -[RI] chain rulenum rule-specification [options]\n"
 "       %s -D chain rulenum [options]\n"
 "       %s -[LFZ] [chain] [options]\n"
-"       %s -[NX] chain\n"
+"       %s -[NXC] chain\n"
 "       %s -E old-chain-name new-chain-name\n"
 "       %s -P chain target [options]\n"
 "       %s -h (print this help information)\n\n",
@@ -448,6 +451,7 @@
 "  --rename-chain\n"
 "            -E old-chain new-chain\n"
 "				Change chain name, (moving any references)\n"
+"            -C [chain]		Clean a chain (remove rules that do not match anymore)\n"
 
 "Options:\n"
 "  --proto	-p [!] proto	protocol: by number or name, eg. `tcp'\n"
@@ -1733,6 +1737,19 @@
 	return iptc_delete_chain(chain, handle);
 }
 
+int
+clean_chain(const ipt_chainlabel chain, int verbose,
+	     iptc_handle_t *handle)
+{
+	if (!chain)
+		return for_each_chain(clean_chain, verbose, 1, handle);
+
+	if (verbose)
+	        fprintf(stdout, "Cleaning chain `%s'\n", chain);
+
+	return iptc_delete_entries(chain, handle);
+}
+
 static int
 list_entries(const ipt_chainlabel chain, int verbose, int numeric,
 	     int expanded, int linenumbers, iptc_handle_t *handle)
@@ -1985,7 +2002,7 @@
 	opterr = 0;
 
 	while ((c = getopt_long(argc, argv,
-	   "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
+	   "-A:D:R:I:L::M:F::Z::N:X::E:C::P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
 					   opts, NULL)) != -1) {
 		switch (c) {
 			/*
@@ -2095,6 +2112,15 @@
 					    cmd2char(CMD_RENAME_CHAIN));
 			break;
 
+		case 'C':
+			add_command(&command, CMD_CLEAN, CMD_NONE,
+					invert);
+			if (optarg) chain = optarg;
+			else if (optind < argc && argv[optind][0] != '-'
+					&& argv[optind][0] != '!')
+				chain = argv[optind++];
+			break;
+
 		case 'P':
 			add_command(&command, CMD_SET_POLICY, CMD_NONE,
 				    invert);
@@ -2594,6 +2620,9 @@
 	case CMD_SET_POLICY:
 		ret = iptc_set_policy(chain, policy, NULL, handle);
 		break;
+	case CMD_CLEAN:
+		ret = clean_chain(chain, options&OPT_VERBOSE, handle);
+		break;
 	default:
 		/* We should never reach this... */
 		exit_tryhelp(2);
diff -ruN iptables-1.3.8.0debian1/iptables/libiptc/libip4tc.c iptables-patch/iptables/libiptc/libip4tc.c
--- iptables-1.3.8.0debian1/iptables/libiptc/libip4tc.c	2007-01-23 13:49:53.000000000 +0100
+++ iptables-patch/iptables/libiptc/libip4tc.c	2008-01-26 19:23:00.000000000 +0100
@@ -77,6 +77,7 @@
 #define TC_REPLACE_ENTRY	iptc_replace_entry
 #define TC_APPEND_ENTRY		iptc_append_entry
 #define TC_DELETE_ENTRY		iptc_delete_entry
+#define TC_DELETE_ENTRIES	iptc_delete_entries
 #define TC_DELETE_NUM_ENTRY	iptc_delete_num_entry
 #define TC_CHECK_PACKET		iptc_check_packet
 #define TC_FLUSH_ENTRIES	iptc_flush_entries
diff -ruN iptables-1.3.8.0debian1/iptables/libiptc/libip6tc.c iptables-patch/iptables/libiptc/libip6tc.c
--- iptables-1.3.8.0debian1/iptables/libiptc/libip6tc.c	2007-01-23 13:49:53.000000000 +0100
+++ iptables-patch/iptables/libiptc/libip6tc.c	2008-01-27 01:49:42.000000000 +0100
@@ -72,6 +72,7 @@
 #define TC_REPLACE_ENTRY	ip6tc_replace_entry
 #define TC_APPEND_ENTRY		ip6tc_append_entry
 #define TC_DELETE_ENTRY		ip6tc_delete_entry
+#define TC_DELETE_ENTRIES	ip6tc_delete_entries
 #define TC_DELETE_NUM_ENTRY	ip6tc_delete_num_entry
 #define TC_CHECK_PACKET		ip6tc_check_packet
 #define TC_FLUSH_ENTRIES	ip6tc_flush_entries
diff -ruN iptables-1.3.8.0debian1/iptables/libiptc/libiptc.c iptables-patch/iptables/libiptc/libiptc.c
--- iptables-1.3.8.0debian1/iptables/libiptc/libiptc.c	2007-01-23 13:49:53.000000000 +0100
+++ iptables-patch/iptables/libiptc/libiptc.c	2008-01-27 15:15:43.000000000 +0100
@@ -27,6 +27,11 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 
+#include <sys/time.h>
+#include <time.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter/xt_timeout.h>
 #include "linux_list.h"
 
 //#define IPTC_DEBUG2 1
@@ -1561,6 +1566,79 @@
 	return 0;
 }
 
+#ifdef _XT_TIMEOUT_H
+/* this should go out some way */
+static inline int
+match_too_late(const STRUCT_ENTRY_MATCH *a, int *flags, struct timespec *now)
+{
+	struct xt_timeout_info *info = (struct xt_recent_info *)a->data;
+
+	if (strcmp(a->u.user.name, "timeout") != 0)
+		return 0; /* 0 = match */
+
+	*flags = 1;
+
+	if (info->invert)
+		return 0; /* will necessary be valid some time */
+
+	if (now->tv_sec > info->match_upto.tv_sec)
+		return 1;
+	return now->tv_nsec > info->match_upto.tv_nsec;
+}
+
+/* Delete all rules that will never match anymore . */
+int
+TC_DELETE_ENTRIES(const IPT_CHAINLABEL chain,
+		TC_HANDLE_T *handle)
+{
+	struct chain_head *c;
+	struct rule_head *i, *r;
+	struct timeval now;
+	struct timespec nowspec;
+
+	iptc_fn = TC_DELETE_ENTRIES;
+	if (!(c = iptcc_find_label(chain, *handle))) {
+		errno = ENOENT;
+		return 0;
+	}
+
+	gettimeofday(&now, NULL);
+	nowspec.tv_sec = now.tv_sec;
+	nowspec.tv_nsec = now.tv_usec * 1000;
+
+	list_for_each_entry_safe(i, r, &c->rules, list) {
+		int flags = 0;
+		STRUCT_ENTRY *a = i->entry;
+		if(!IPT_MATCH_ITERATE(a, match_too_late, &flags, &nowspec))
+			continue;
+		if(flags == 0)
+			continue;
+
+		/* If we are about to delete the rule that is the
+		 * current iterator, move rule iterator back.  next
+		 * pointer will then point to real next node */
+		if (i == (*handle)->rule_iterator_cur) {
+			(*handle)->rule_iterator_cur = 
+				list_entry((*handle)->rule_iterator_cur->list.prev,
+					   struct rule_head, list);
+		}
+
+		c->num_rules--;
+		iptcc_delete_rule(i);
+		set_changed(*handle);
+	}
+
+	return 1;
+}
+#else
+int
+TC_DELETE_ENTRIES(const IPT_CHAINLABEL chain,
+		                TC_HANDLE_T *handle)
+{
+	return 1;
+}
+
+#endif
 
 /* Delete the rule in position `rulenum' in `chain'. */
 int

