[netfilter-cvslog] r4113 - in trunk/conntrack: . extensions include src

pablo at netfilter.org pablo at netfilter.org
Wed Jul 13 01:24:13 CEST 2005


Author: pablo at netfilter.org
Date: 2005-07-13 01:24:06 +0200 (Wed, 13 Jul 2005)
New Revision: 4113

Modified:
   trunk/conntrack/ChangeLog
   trunk/conntrack/extensions/libct_proto_icmp.c
   trunk/conntrack/extensions/libct_proto_sctp.c
   trunk/conntrack/extensions/libct_proto_tcp.c
   trunk/conntrack/extensions/libct_proto_udp.c
   trunk/conntrack/include/libct_proto.h
   trunk/conntrack/src/conntrack.c
   trunk/conntrack/src/libct.c
   trunk/conntrack/test.sh
Log:
o Use conntrack netlink attributes: Major change
o Kill action setting: Mask based dumping


Modified: trunk/conntrack/ChangeLog
===================================================================
--- trunk/conntrack/ChangeLog	2005-07-12 15:32:18 UTC (rev 4112)
+++ trunk/conntrack/ChangeLog	2005-07-12 23:24:06 UTC (rev 4113)
@@ -1,3 +1,9 @@
+2005-07-12
+<pablo at eurodev.net>
+	o Use conntrack netlink attributes: Major change
+	o Kill action setting: Mask based dumping
+	o Fix ChangeLog
+
 2005-05-23
 <laforge at netfilter.org>
 	o Fixed syntax error (tab/space issue) in help message
@@ -9,12 +15,17 @@
 	o Add SCTP extension
 	o Add support for expect creation
 	o Bump version number to 0.63
-2005-04-25
+
+2005-05-17
 <pablo at eurodev.net>
-	o Added support for mask based event dumping
-	o Added support for mask based event notification
-	o On-demand autoload of ip_conntrack_netlink
+	o Added descriptive error messages.
+	o Fix wrong flags check in [tcp|udp] proto helpers.
 
+2005-05-16
+<pablo at eurodev.net>
+	o Implemented ICMP proto helper
+	o Added help() and final_check() functions for proto helpers.
+
 2005-05-01
 <pablo at eurodev.net>
 	o Created changelog file
@@ -33,12 +44,8 @@
 	o Autoconf stuff for conntrack + some pablo's modifications.
 	o Fixed packet counters formatting (use %llu instead of %lu)
 
-2005-05-16
+2005-04-25
 <pablo at eurodev.net>
-	o Implemented ICMP proto helper
-	o Added help() and final_check() functions for proto helpers.
-
-2005-05-17
-<pablo at eurodev.net>
-	o Added descriptive error messages.
-	o Fix wrong flags check in [tcp|udp] proto helpers.
+	o Added support for mask based event dumping
+	o Added support for mask based event notification
+	o On-demand autoload of ip_conntrack_netlink

Modified: trunk/conntrack/extensions/libct_proto_icmp.c
===================================================================
--- trunk/conntrack/extensions/libct_proto_icmp.c	2005-07-12 15:32:18 UTC (rev 4112)
+++ trunk/conntrack/extensions/libct_proto_icmp.c	2005-07-12 23:24:06 UTC (rev 4113)
@@ -11,8 +11,6 @@
 #include <getopt.h>
 #include <stdlib.h>
 #include <netinet/in.h> /* For htons */
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
 #include "libct_proto.h"
 
 static struct option opts[] = {
@@ -41,27 +39,28 @@
 }
 
 int parse(char c, char *argv[], 
-	   struct ip_conntrack_tuple *orig,
-	   struct ip_conntrack_tuple *reply,
-	   union ip_conntrack_proto *proto,
+	   struct ctnl_tuple *orig,
+	   struct ctnl_tuple *reply,
+	   struct ctnl_tuple *mask,
+	   union ctnl_protoinfo *proto,
 	   unsigned int *flags)
 {
 	switch(c) {
 		case '1':
 			if (optarg) {
-				orig->dst.u.icmp.type = atoi(optarg);
+				orig->l4dst.icmp.type = atoi(optarg);
 				*flags |= ICMP_TYPE;
 			}
 			break;
 		case '2':
 			if (optarg) {
-				orig->dst.u.icmp.code = atoi(optarg);
+				orig->l4dst.icmp.code = atoi(optarg);
 				*flags |= ICMP_CODE;
 			}
 			break;
 		case '3':
 			if (optarg) {
-				reply->src.u.icmp.id = atoi(optarg);
+				orig->l4src.icmp.id = atoi(optarg);
 				*flags |= ICMP_ID;
 			}
 			break;
@@ -69,7 +68,9 @@
 	return 1;
 }
 
-int final_check(unsigned int flags)
+int final_check(unsigned int flags,
+		struct ctnl_tuple *orig,
+		struct ctnl_tuple *reply)
 {
 	if (!(flags & ICMP_TYPE))
 		return 0;
@@ -79,18 +80,18 @@
 	return 1;
 }
 
-void print_tuple(struct ip_conntrack_tuple *t)
+void print_proto(struct ctnl_tuple *t)
 {
-	fprintf(stdout, "type=%d code=%d id=%d ", t->dst.u.icmp.type, 
-				             	 t->dst.u.icmp.code,
-						 t->src.u.icmp.id);
+	fprintf(stdout, "type=%d code=%d id=%d", t->l4dst.icmp.type, 
+				             	 t->l4dst.icmp.code,
+						 t->l4src.icmp.id);
 }
 
 static struct ctproto_handler icmp = {
 	.name 		= "icmp",
 	.protonum	= 1,
-	.parse		= parse,
-	.print_tuple	= print_tuple,
+	.parse_opts	= parse,
+	.print_proto	= print_proto,
 	.final_check	= final_check,
 	.help		= help,
 	.opts		= opts

Modified: trunk/conntrack/extensions/libct_proto_sctp.c
===================================================================
--- trunk/conntrack/extensions/libct_proto_sctp.c	2005-07-12 15:32:18 UTC (rev 4112)
+++ trunk/conntrack/extensions/libct_proto_sctp.c	2005-07-12 23:24:06 UTC (rev 4113)
@@ -1,26 +1,26 @@
 /*
- * (C) 2005 by Harald Welte <lafoorge at netfilter.org>
+ * (C) 2005 by Harald Welte <laforge at netfilter.org>
  *
  *      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
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
  *
  */
 #include <stdio.h>
 #include <getopt.h>
 #include <stdlib.h>
-#include <string.h>
 #include <netinet/in.h> /* For htons */
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_netlink.h>
 #include "libct_proto.h"
+#include "libctnetlink.h"
 
 static struct option opts[] = {
 	{"orig-port-src", 1, 0, '1'},
 	{"orig-port-dst", 1, 0, '2'},
 	{"reply-port-src", 1, 0, '3'},
 	{"reply-port-dst", 1, 0, '4'},
-	{"state", 1, 0, '5'},
+	{"state", 1, 0, '7'},
 	{0, 0, 0, 0}
 };
 
@@ -52,43 +52,44 @@
 	"SHUTDOWN_ACK_SENT",
 };
 
-static void help()
+void help()
 {
 	fprintf(stdout, "--orig-port-src        original source port\n");
 	fprintf(stdout, "--orig-port-dst        original destination port\n");
 	fprintf(stdout, "--reply-port-src       reply source port\n");
 	fprintf(stdout, "--reply-port-dst       reply destination port\n");
-	fprintf(stdout, "--state                SCTP state, eg. ESTABLISHED\n");
+	fprintf(stdout, "--state                SCTP state, fe. ESTABLISHED\n");
 }
 
-static int parse(char c, char *argv[], 
-	   struct ip_conntrack_tuple *orig,
-	   struct ip_conntrack_tuple *reply,
-	   union ip_conntrack_proto *proto,
-	   unsigned int *flags)
+int parse_options(char c, char *argv[], 
+		  struct ctnl_tuple *orig,
+		  struct ctnl_tuple *reply,
+		  struct ctnl_tuple *mask,
+		  union ctnl_protoinfo *proto,
+		  unsigned int *flags)
 {
 	switch(c) {
 		case '1':
 			if (optarg) {
-				orig->src.u.sctp.port = htons(atoi(optarg));
+				orig->l4src.sctp.port = htons(atoi(optarg));
 				*flags |= ORIG_SPORT;
 			}
 			break;
 		case '2':
 			if (optarg) {
-				orig->dst.u.sctp.port = htons(atoi(optarg));
+				orig->l4dst.sctp.port = htons(atoi(optarg));
 				*flags |= ORIG_DPORT;
 			}
 			break;
 		case '3':
 			if (optarg) {
-				reply->src.u.sctp.port = htons(atoi(optarg));
+				reply->l4src.sctp.port = htons(atoi(optarg));
 				*flags |= REPL_SPORT;
 			}
 			break;
 		case '4':
 			if (optarg) {
-				reply->dst.u.sctp.port = htons(atoi(optarg));
+				reply->l4dst.sctp.port = htons(atoi(optarg));
 				*flags |= REPL_DPORT;
 			}
 			break;
@@ -97,7 +98,9 @@
 				int i;
 				for (i=0; i<10; i++) {
 					if (strcmp(optarg, states[i]) == 0) {
-						proto->sctp.state = i;
+						/* FIXME: Add state to
+						 * ctnl_protoinfo
+						proto->sctp.state = i; */
 						break;
 					}
 				}
@@ -111,39 +114,68 @@
 	return 1;
 }
 
-static int final_check(unsigned int flags)
+int final_check(unsigned int flags,
+		struct ctnl_tuple *orig,
+		struct ctnl_tuple *reply)
 {
-	if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT))
+	if ((flags & (ORIG_SPORT|ORIG_DPORT)) 
+	    && !(flags & (REPL_SPORT|REPL_DPORT))) {
+		reply->l4src.sctp.port = orig->l4dst.sctp.port;
+		reply->l4dst.sctp.port = orig->l4src.sctp.port;
 		return 1;
-	else if ((flags & REPL_SPORT) && (flags & REPL_DPORT))
+	} else if (!(flags & (ORIG_SPORT|ORIG_DPORT))
+	            && (flags & (REPL_SPORT|REPL_DPORT))) {
+		orig->l4src.sctp.port = reply->l4dst.sctp.port;
+		orig->l4dst.sctp.port = reply->l4src.sctp.port;
 		return 1;
+	}
+	if ((flags & (ORIG_SPORT|ORIG_DPORT)) 
+	    && ((flags & (REPL_SPORT|REPL_DPORT))))
+		return 1;
 
 	return 0;
 }
 
-static void print_tuple(struct ip_conntrack_tuple *t)
+void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple)
 {
-	fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.sctp.port), 
-				             ntohs(t->dst.u.sctp.port));
+	if (cda[CTA_PROTO_SCTP_SRC-1])
+		tuple->l4src.sctp.port =
+			*(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SCTP_SRC-1]);
+	if (cda[CTA_PROTO_SCTP_DST-1])
+		tuple->l4dst.sctp.port =
+			*(u_int16_t *)NFA_DATA(cda[CTA_PROTO_SCTP_DST-1]);
 }
 
-static void print_proto(union ip_conntrack_proto *proto)
+void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct)
 {
-	if (proto->sctp.state > sizeof(states)/sizeof(char *))
-		fprintf(stdout, "[%u] ", proto->sctp.state);
-	else
-		fprintf(stdout, "[%s] ", states[proto->sctp.state]);
+/*	if (cda[CTA_PROTOINFO_SCTP_STATE-1])
+                ct->protoinfo.sctp.state =
+                        *(u_int8_t *)NFA_DATA(cda[CTA_PROTOINFO_SCTP_STATE-1]);
+*/
 }
 
+void print_protoinfo(union ctnl_protoinfo *protoinfo)
+{
+/*	fprintf(stdout, "%s ", states[protoinfo->sctp.state]); */
+}
+
+void print_proto(struct ctnl_tuple *tuple)
+{
+	fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.sctp.port),
+					      htons(tuple->l4dst.sctp.port));
+}
+
 static struct ctproto_handler sctp = {
-	.name 		= "sctp",
-	.protonum	= 132,
-	.parse		= parse,
-	.print_tuple	= print_tuple,
-	.print_proto	= print_proto,
-	.final_check	= final_check,
-	.help		= help,
-	.opts		= opts,
+	.name 			= "sctp",
+	.protonum		= 132,
+	.parse_opts		= parse_options,
+	.parse_protoinfo	= parse_protoinfo,
+	.parse_proto		= parse_proto,
+	.print_proto		= print_proto,
+	.print_protoinfo	= print_protoinfo,
+	.final_check		= final_check,
+	.help			= help,
+	.opts			= opts
 };
 
 void __attribute__ ((constructor)) init(void);

Modified: trunk/conntrack/extensions/libct_proto_tcp.c
===================================================================
--- trunk/conntrack/extensions/libct_proto_tcp.c	2005-07-12 15:32:18 UTC (rev 4112)
+++ trunk/conntrack/extensions/libct_proto_tcp.c	2005-07-12 23:24:06 UTC (rev 4113)
@@ -10,18 +10,19 @@
 #include <stdio.h>
 #include <getopt.h>
 #include <stdlib.h>
-#include <string.h>
 #include <netinet/in.h> /* For htons */
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_netlink.h>
 #include "libct_proto.h"
+#include "libctnetlink.h"
 
 static struct option opts[] = {
 	{"orig-port-src", 1, 0, '1'},
 	{"orig-port-dst", 1, 0, '2'},
 	{"reply-port-src", 1, 0, '3'},
 	{"reply-port-dst", 1, 0, '4'},
-	{"state", 1, 0, '5'},
+	{"mask-port-src", 1, 0, '5'},
+	{"mask-port-dst", 1, 0, '6'},
+	{"state", 1, 0, '7'},
 	{0, 0, 0, 0}
 };
 
@@ -38,7 +39,13 @@
 	REPL_DPORT_BIT = 3,
 	REPL_DPORT = (1 << REPL_DPORT_BIT),
 
-	STATE_BIT = 4,
+	MASK_SPORT_BIT = 4,
+	MASK_SPORT = (1 << MASK_SPORT_BIT),
+
+	MASK_DPORT_BIT = 5,
+	MASK_DPORT = (1 << MASK_DPORT_BIT),
+
+	STATE_BIT = 6,
 	STATE = (1 << STATE_BIT)
 };
 
@@ -55,48 +62,63 @@
 	"LISTEN"
 };
 
-static void help()
+void help()
 {
 	fprintf(stdout, "--orig-port-src        original source port\n");
 	fprintf(stdout, "--orig-port-dst        original destination port\n");
 	fprintf(stdout, "--reply-port-src       reply source port\n");
 	fprintf(stdout, "--reply-port-dst       reply destination port\n");
+	fprintf(stdout, "--mask-port-src	mask source port\n");
+	fprintf(stdout, "--mask-port-dst	mask destination port\n");
 	fprintf(stdout, "--state                TCP state, fe. ESTABLISHED\n");
 }
 
-static int parse(char c, char *argv[], 
-	   struct ip_conntrack_tuple *orig,
-	   struct ip_conntrack_tuple *reply,
-	   union ip_conntrack_proto *proto,
-	   unsigned int *flags)
+int parse_options(char c, char *argv[], 
+		  struct ctnl_tuple *orig,
+		  struct ctnl_tuple *reply,
+		  struct ctnl_tuple *mask,
+		  union ctnl_protoinfo *proto,
+		  unsigned int *flags)
 {
 	switch(c) {
 		case '1':
 			if (optarg) {
-				orig->src.u.tcp.port = htons(atoi(optarg));
+				orig->l4src.tcp.port = htons(atoi(optarg));
 				*flags |= ORIG_SPORT;
 			}
 			break;
 		case '2':
 			if (optarg) {
-				orig->dst.u.tcp.port = htons(atoi(optarg));
+				orig->l4dst.tcp.port = htons(atoi(optarg));
 				*flags |= ORIG_DPORT;
 			}
 			break;
 		case '3':
 			if (optarg) {
-				reply->src.u.tcp.port = htons(atoi(optarg));
+				reply->l4src.tcp.port = htons(atoi(optarg));
 				*flags |= REPL_SPORT;
 			}
 			break;
 		case '4':
 			if (optarg) {
-				reply->dst.u.tcp.port = htons(atoi(optarg));
+				reply->l4dst.tcp.port = htons(atoi(optarg));
 				*flags |= REPL_DPORT;
 			}
 			break;
 		case '5':
 			if (optarg) {
+				mask->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= MASK_SPORT;
+			}
+			break;
+		case '6':
+			if (optarg) {
+				mask->l4src.tcp.port = htons(atoi(optarg));
+				*flags |= MASK_DPORT;
+			}
+			break;
+		case '7':
+			if (optarg) {
 				int i;
 				for (i=0; i<10; i++) {
 					if (strcmp(optarg, states[i]) == 0) {
@@ -114,39 +136,67 @@
 	return 1;
 }
 
-static int final_check(unsigned int flags)
+int final_check(unsigned int flags,
+		struct ctnl_tuple *orig,
+		struct ctnl_tuple *reply)
 {
-	if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT))
+	if ((flags & (ORIG_SPORT|ORIG_DPORT)) 
+	    && !(flags & (REPL_SPORT|REPL_DPORT))) {
+		reply->l4src.tcp.port = orig->l4dst.tcp.port;
+		reply->l4dst.tcp.port = orig->l4src.tcp.port;
 		return 1;
-	else if ((flags & REPL_SPORT) && (flags & REPL_DPORT))
+	} else if (!(flags & (ORIG_SPORT|ORIG_DPORT))
+	            && (flags & (REPL_SPORT|REPL_DPORT))) {
+		orig->l4src.tcp.port = reply->l4dst.tcp.port;
+		orig->l4dst.tcp.port = reply->l4src.tcp.port;
 		return 1;
+	}
+	if ((flags & (ORIG_SPORT|ORIG_DPORT)) 
+	    && ((flags & (REPL_SPORT|REPL_DPORT))))
+		return 1;
 
 	return 0;
 }
 
-static void print_tuple(struct ip_conntrack_tuple *t)
+void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple)
 {
-	fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.tcp.port), 
-				             ntohs(t->dst.u.tcp.port));
+	if (cda[CTA_PROTO_TCP_SRC-1])
+		tuple->l4src.tcp.port =
+			*(u_int16_t *)NFA_DATA(cda[CTA_PROTO_TCP_SRC-1]);
+	if (cda[CTA_PROTO_TCP_DST-1])
+		tuple->l4dst.tcp.port =
+			*(u_int16_t *)NFA_DATA(cda[CTA_PROTO_TCP_DST-1]);
 }
 
-static void print_proto(union ip_conntrack_proto *proto)
+void parse_protoinfo(struct nfattr *cda[], struct ctnl_conntrack *ct)
 {
-	if (proto->tcp.state > sizeof(states)/sizeof(char *))
-		fprintf(stdout, "[%u] ", states[proto->tcp.state]);
-	else
-		fprintf(stdout, "[%s] ", states[proto->tcp.state]);
+	if (cda[CTA_PROTOINFO_TCP_STATE-1])
+                ct->protoinfo.tcp.state =
+                        *(u_int8_t *)NFA_DATA(cda[CTA_PROTOINFO_TCP_STATE-1]);
 }
 
+void print_protoinfo(union ctnl_protoinfo *protoinfo)
+{
+	fprintf(stdout, "%s ", states[protoinfo->tcp.state]);
+}
+
+void print_proto(struct ctnl_tuple *tuple)
+{
+	fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.tcp.port),
+					      htons(tuple->l4dst.tcp.port));
+}
+
 static struct ctproto_handler tcp = {
-	.name 		= "tcp",
-	.protonum	= 6,
-	.parse		= parse,
-	.print_tuple	= print_tuple,
-	.print_proto	= print_proto,
-	.final_check	= final_check,
-	.help		= help,
-	.opts		= opts,
+	.name 			= "tcp",
+	.protonum		= 6,
+	.parse_opts		= parse_options,
+	.parse_protoinfo	= parse_protoinfo,
+	.parse_proto		= parse_proto,
+	.print_proto		= print_proto,
+	.print_protoinfo	= print_protoinfo,
+	.final_check		= final_check,
+	.help			= help,
+	.opts			= opts
 };
 
 void __attribute__ ((constructor)) init(void);

Modified: trunk/conntrack/extensions/libct_proto_udp.c
===================================================================
--- trunk/conntrack/extensions/libct_proto_udp.c	2005-07-12 15:32:18 UTC (rev 4112)
+++ trunk/conntrack/extensions/libct_proto_udp.c	2005-07-12 23:24:06 UTC (rev 4113)
@@ -11,15 +11,17 @@
 #include <getopt.h>
 #include <stdlib.h>
 #include <netinet/in.h> /* For htons */
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_netlink.h>
 #include "libct_proto.h"
+#include "libctnetlink.h"
 
 static struct option opts[] = {
 	{"orig-port-src", 1, 0, '1'},
 	{"orig-port-dst", 1, 0, '2'},
 	{"reply-port-src", 1, 0, '3'},
 	{"reply-port-dst", 1, 0, '4'},
+	{"mask-port-src", 1, 0, '5'},
+	{"mask-port-dst", 1, 0, '6'},
 	{0, 0, 0, 0}
 };
 
@@ -35,6 +37,12 @@
 
 	REPL_DPORT_BIT = 3,
 	REPL_DPORT = (1 << REPL_DPORT_BIT),
+
+	MASK_SPORT_BIT = 4,
+	MASK_SPORT = (1 << MASK_SPORT_BIT),
+
+	MASK_DPORT_BIT = 5,
+	MASK_DPORT = (1 << MASK_DPORT_BIT),
 };
 
 void help()
@@ -43,67 +51,105 @@
 	fprintf(stdout, "--orig-port-dst        original destination port\n");
 	fprintf(stdout, "--reply-port-src       reply source port\n");
 	fprintf(stdout, "--reply-port-dst       reply destination port\n");
+	fprintf(stdout, "--mask-port-src	mask source port\n");
+	fprintf(stdout, "--mask-port-dst	mask destination port\n");
 }
 
-int parse(char c, char *argv[], 
-	   struct ip_conntrack_tuple *orig,
-	   struct ip_conntrack_tuple *reply,
-	   union ip_conntrack_proto *proto,
-	   unsigned int *flags)
+int parse_options(char c, char *argv[], 
+		  struct ctnl_tuple *orig,
+		  struct ctnl_tuple *reply,
+		  struct ctnl_tuple *mask,
+		  union ctnl_protoinfo *proto,
+		  unsigned int *flags)
 {
 	switch(c) {
 		case '1':
 			if (optarg) {
-				orig->src.u.udp.port = htons(atoi(optarg));
+				orig->l4src.udp.port = htons(atoi(optarg));
 				*flags |= ORIG_SPORT;
 			}
 			break;
 		case '2':
 			if (optarg) {
-				orig->dst.u.udp.port = htons(atoi(optarg));
+				orig->l4dst.udp.port = htons(atoi(optarg));
 				*flags |= ORIG_DPORT;
 			}
 			break;
 		case '3':
 			if (optarg) {
-				reply->src.u.udp.port = htons(atoi(optarg));
+				reply->l4src.udp.port = htons(atoi(optarg));
 				*flags |= REPL_SPORT;
 			}
 			break;
 		case '4':
 			if (optarg) {
-				reply->dst.u.udp.port = htons(atoi(optarg));
+				reply->l4dst.udp.port = htons(atoi(optarg));
 				*flags |= REPL_DPORT;
 			}
 			break;
+		case '5':
+			if (optarg) {
+				mask->l4src.udp.port = htons(atoi(optarg));
+				*flags |= MASK_SPORT;
+			}
+			break;
+		case '6':
+			if (optarg) {
+				mask->l4src.udp.port = htons(atoi(optarg));
+				*flags |= MASK_DPORT;
+			}
+			break;
 	}
 	return 1;
 }
 
-int final_check(unsigned int flags)
+int final_check(unsigned int flags,
+		struct ctnl_tuple *orig,
+		struct ctnl_tuple *reply)
 {
-	if ((flags & ORIG_SPORT) && (flags & ORIG_DPORT))
+	if ((flags & (ORIG_SPORT|ORIG_DPORT)) 
+	    && !(flags & (REPL_SPORT|REPL_DPORT))) {
+		reply->l4src.udp.port = orig->l4dst.udp.port;
+		reply->l4dst.udp.port = orig->l4src.udp.port;
 		return 1;
-	else if ((flags & REPL_SPORT) && (flags & REPL_DPORT))
+	} else if (!(flags & (ORIG_SPORT|ORIG_DPORT))
+	            && (flags & (REPL_SPORT|REPL_DPORT))) {
+		orig->l4src.udp.port = reply->l4dst.udp.port;
+		orig->l4dst.udp.port = reply->l4src.udp.port;
 		return 1;
+	}
+	if ((flags & (ORIG_SPORT|ORIG_DPORT)) 
+	    && ((flags & (REPL_SPORT|REPL_DPORT))))
+		return 1;
 
 	return 0;
 }
 
-void print_tuple(struct ip_conntrack_tuple *t)
+void parse_proto(struct nfattr *cda[], struct ctnl_tuple *tuple)
 {
-	fprintf(stdout, "sport=%d dport=%d ", ntohs(t->src.u.udp.port), 
-				             ntohs(t->dst.u.udp.port));
+	if (cda[CTA_PROTO_UDP_SRC-1])
+		tuple->l4src.udp.port =
+			*(u_int16_t *)NFA_DATA(cda[CTA_PROTO_UDP_SRC-1]);
+	if (cda[CTA_PROTO_UDP_DST-1])
+		tuple->l4dst.udp.port =
+			*(u_int16_t *)NFA_DATA(cda[CTA_PROTO_UDP_DST-1]);
 }
 
+void print_proto(struct ctnl_tuple *tuple)
+{
+	fprintf(stdout, "sport=%u dport=%u ", htons(tuple->l4src.udp.port),
+					      htons(tuple->l4dst.udp.port));
+}
+
 static struct ctproto_handler udp = {
-	.name 		= "udp",
-	.protonum	= 17,
-	.parse		= parse,
-	.print_tuple	= print_tuple,
-	.final_check	= final_check,
-	.help		= help,
-	.opts		= opts
+	.name 			= "udp",
+	.protonum		= 17,
+	.parse_opts		= parse_options,
+	.parse_proto		= parse_proto,
+	.print_proto		= print_proto,
+	.final_check		= final_check,
+	.help			= help,
+	.opts			= opts
 };
 
 void __attribute__ ((constructor)) init(void);

Modified: trunk/conntrack/include/libct_proto.h
===================================================================
--- trunk/conntrack/include/libct_proto.h	2005-07-12 15:32:18 UTC (rev 4112)
+++ trunk/conntrack/include/libct_proto.h	2005-07-12 23:24:06 UTC (rev 4113)
@@ -5,6 +5,7 @@
 
 #include "linux_list.h"
 #include <getopt.h>
+#include "libctnetlink.h"
 
 struct cta_proto;
 
@@ -13,16 +14,24 @@
 
 	char 			*name;
 	u_int16_t 		protonum;
+
+	enum ctattr_protoinfo	protoinfo_attr;
 	
-	int (*parse)(char c, char *argv[], 
-		     struct ip_conntrack_tuple *orig,
-		     struct ip_conntrack_tuple *reply, 
-		     union ip_conntrack_proto *proto,
+	int (*parse_opts)(char c, char *argv[], 
+		     struct ctnl_tuple *orig,
+		     struct ctnl_tuple *reply,
+		     struct ctnl_tuple *mask,
+		     union ctnl_protoinfo *proto,
 		     unsigned int *flags);
-	void (*print_tuple)(struct ip_conntrack_tuple *t);
-	void (*print_proto)(union ip_conntrack_proto *proto);
+	void (*parse_proto)(struct nfattr *cda[], struct ctnl_tuple *tuple);
+	void (*parse_protoinfo)(struct nfattr *cda[], 
+				struct ctnl_conntrack *ct);
+	void (*print_proto)(struct ctnl_tuple *t);
+	void (*print_protoinfo)(union ctnl_protoinfo *protoinfo);
 
-	int (*final_check)(unsigned int flags);
+	int (*final_check)(unsigned int flags,
+			   struct ctnl_tuple *orig,
+			   struct ctnl_tuple *reply);
 
 	void (*help)();
 

Modified: trunk/conntrack/src/conntrack.c
===================================================================
--- trunk/conntrack/src/conntrack.c	2005-07-12 15:32:18 UTC (rev 4112)
+++ trunk/conntrack/src/conntrack.c	2005-07-12 23:24:06 UTC (rev 4113)
@@ -41,7 +41,6 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <string.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include "libctnetlink.h"
 #include "libnfnetlink.h"
@@ -62,35 +61,61 @@
 #endif
 
 enum action {
+	CT_NONE		= 0,
+	
 	CT_LIST_BIT 	= 0,
 	CT_LIST 	= (1 << CT_LIST_BIT),
 	
 	CT_CREATE_BIT	= 1,
 	CT_CREATE	= (1 << CT_CREATE_BIT),
+
+	CT_UPDATE_BIT	= 2,
+	CT_UPDATE	= (1 << CT_UPDATE_BIT),
 	
-	CT_DELETE_BIT	= 2,
+	CT_DELETE_BIT	= 3,
 	CT_DELETE	= (1 << CT_DELETE_BIT),
 	
-	CT_GET_BIT	= 3,
+	CT_GET_BIT	= 4,
 	CT_GET		= (1 << CT_GET_BIT),
 
-	CT_FLUSH_BIT	= 4,
+	CT_FLUSH_BIT	= 5,
 	CT_FLUSH	= (1 << CT_FLUSH_BIT),
 
-	CT_EVENT_BIT	= 5,
+	CT_EVENT_BIT	= 6,
 	CT_EVENT	= (1 << CT_EVENT_BIT),
 
-	CT_ACTION_BIT	= 6,
-	CT_ACTION	= (1 << CT_ACTION_BIT),
-
 	CT_VERSION_BIT	= 7,
 	CT_VERSION	= (1 << CT_VERSION_BIT),
 
 	CT_HELP_BIT	= 8,
 	CT_HELP		= (1 << CT_HELP_BIT),
+
+	EXP_LIST_BIT 	= 9,
+	EXP_LIST 	= (1 << EXP_LIST_BIT),
+	
+	EXP_CREATE_BIT	= 10,
+	EXP_CREATE	= (1 << EXP_CREATE_BIT),
+	
+	EXP_DELETE_BIT	= 11,
+	EXP_DELETE	= (1 << EXP_DELETE_BIT),
+	
+	EXP_GET_BIT	= 12,
+	EXP_GET		= (1 << EXP_GET_BIT),
+
+	EXP_FLUSH_BIT	= 13,
+	EXP_FLUSH	= (1 << EXP_FLUSH_BIT),
+
+	EXP_EVENT_BIT	= 14,
+	EXP_EVENT	= (1 << EXP_EVENT_BIT),
 };
-#define NUMBER_OF_CMD   9
+#define NUMBER_OF_CMD   15
 
+static const char cmdflags[NUMBER_OF_CMD]
+= {'L','I','U','D','G','F','E','V','h','L','I','D','G','F','E'};
+
+static const char cmd_need_param[NUMBER_OF_CMD]
+= {' ','x','x','x','x',' ',' ',' ',' ',' ','x','x','x',' ',' '};
+
 enum options {
 	CT_OPT_ORIG_SRC_BIT	= 0,
 	CT_OPT_ORIG_SRC 	= (1 << CT_OPT_ORIG_SRC_BIT),
@@ -120,36 +145,34 @@
 	CT_OPT_ZERO_BIT		= 7,
 	CT_OPT_ZERO		= (1 << CT_OPT_ZERO_BIT),
 
-	CT_OPT_DUMP_MASK_BIT	= 8,
-	CT_OPT_DUMP_MASK	= (1 << CT_OPT_DUMP_MASK_BIT),
-
-	CT_OPT_GROUP_MASK_BIT	= 9,
-	CT_OPT_GROUP_MASK	= (1 << CT_OPT_GROUP_MASK_BIT),
-
-	CT_OPT_EVENT_MASK_BIT	= 10,
+	CT_OPT_EVENT_MASK_BIT	= 8,
 	CT_OPT_EVENT_MASK	= (1 << CT_OPT_EVENT_MASK_BIT),
 
-	CT_OPT_TUPLE_SRC_BIT	= 11,
-	CT_OPT_TUPLE_SRC	= (1 << CT_OPT_TUPLE_SRC_BIT),
+	CT_OPT_EXP_SRC_BIT	= 9,
+	CT_OPT_EXP_SRC		= (1 << CT_OPT_EXP_SRC_BIT),
 
-	CT_OPT_TUPLE_DST_BIT	= 12,
-	CT_OPT_TUPLE_DST	= (1 << CT_OPT_TUPLE_DST_BIT),
+	CT_OPT_EXP_DST_BIT	= 10,
+	CT_OPT_EXP_DST		= (1 << CT_OPT_EXP_DST_BIT),
 
-	CT_OPT_MASK_SRC_BIT	= 13,
+	CT_OPT_MASK_SRC_BIT	= 11,
 	CT_OPT_MASK_SRC		= (1 << CT_OPT_MASK_SRC_BIT),
 
-	CT_OPT_MASK_DST_BIT	= 14,
+	CT_OPT_MASK_DST_BIT	= 12,
 	CT_OPT_MASK_DST		= (1 << CT_OPT_MASK_DST_BIT),
+
+	CT_OPT_NATRANGE_BIT	= 13,
+	CT_OPT_NATRANGE		= (1 << CT_OPT_NATRANGE_BIT),
 };
-#define NUMBER_OF_OPT   15
+#define NUMBER_OF_OPT   14
 
 static const char optflags[NUMBER_OF_OPT]
-= { 's', 'd', 'r', 'q', 'p', 't', 'u', 'z','m','g','e', '[',']','{','}'};
+= {'s','d','r','q','p','t','u','z','e','[',']','{','}','a'};
 
 static struct option original_opts[] = {
 	{"dump", 2, 0, 'L'},
 	{"create", 1, 0, 'I'},
 	{"delete", 1, 0, 'D'},
+	{"update", 1, 0, 'U'},
 	{"get", 1, 0, 'G'},
 	{"flush", 1, 0, 'F'},
 	{"event", 1, 0, 'E'},
@@ -164,13 +187,12 @@
 	{"timeout", 1, 0, 't'},
 	{"status", 1, 0, 'u'},
 	{"zero", 0, 0, 'z'},
-	{"dump-mask", 1, 0, 'm'},
-	{"groups", 1, 0, 'g'},
 	{"event-mask", 1, 0, 'e'},
 	{"tuple-src", 1, 0, '['},
 	{"tuple-dst", 1, 0, ']'},
 	{"mask-src", 1, 0, '{'},
 	{"mask-dst", 1, 0, '}'},
+	{"nat-range", 1, 0, 'a'},
 	{0, 0, 0, 0}
 };
 
@@ -188,22 +210,29 @@
  *     optional
  */
 
+/* FIXME: I'd need something different than this table to catch up some 
+ *        particular cases. Better later Pablo */
 static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
 /* Well, it's better than "Re: Linux vs FreeBSD" */
 {
-          /*   -s  -d  -r  -q  -p  -t  -u  -z  -m  -g  -e  ts  td  ms  md */
-/*LIST*/      {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x','x'},
-/*CREATE*/    {'+','+','+','+','+','+','+','x','x','x','x','+','+','+','+'},
-/*DELETE*/    {' ',' ',' ',' ',' ','x','x','x','x','x','x',' ',' ',' ',' '},
-/*GET*/       {' ',' ',' ',' ','+','x','x','x','x','x','x',' ',' ',' ',' '},
-/*FLUSH*/     {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'},
-/*EVENT*/     {'x','x','x','x','x','x','x','x','x',' ','x','x','x','x','x'},
-/*ACTION*/    {'x','x','x','x','x','x','x','x',' ','x',' ','x','x','x','x'},
-/*VERSION*/   {'x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'},
-/*HELP*/      {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x'},
+          /*   -s  -d  -r  -q  -p  -t  -u  -z  -e  -x  -y  -k  -l  -a */
+/*CT_LIST*/   {'x','x','x','x','x','x','x',' ','x','x','x','x','x','x'},
+/*CT_CREATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x',' '},
+/*CT_UPDATE*/ {' ',' ',' ',' ','+','+','+','x','x','x','x','x','x','x'},
+/*CT_DELETE*/ {' ',' ',' ',' ',' ','x','x','x','x','x','x','x','x','x'},
+/*CT_GET*/    {' ',' ',' ',' ','+','x','x','x','x','x','x','x','x','x'},
+/*CT_FLUSH*/  {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*CT_EVENT*/  {'x','x','x','x','x','x','x','x',' ','x','x','x','x','x'},
+/*VERSION*/   {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*HELP*/      {'x','x','x','x',' ','x','x','x','x','x','x','x','x','x'},
+/*EXP_LIST*/  {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*EXP_CREATE*/{'+','+',' ',' ','+','+',' ','x','x','+','+','+','+','x'},
+/*EXP_DELETE*/{'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x'},
+/*EXP_GET*/   {'+','+',' ',' ','+','x','x','x','x','x','x','x','x','x'},
+/*EXP_FLUSH*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*EXP_EVENT*/ {'x','x','x','x','x','x','x','x','x','x','x','x','x','x'},
 };
 
-/* FIXME: hardcoded!, this must be defined during compilation time */
 char *lib_dir = CONNTRACK_LIB_DIR;
 
 LIST_HEAD(proto_list);
@@ -259,6 +288,22 @@
 }
 
 static void
+generic_cmd_check(int command, int options)
+{
+	int i;
+	
+	for (i = 0; i < NUMBER_OF_CMD; i++) {
+		if (!(command & (1<<i)))
+			continue;
+
+		if (cmd_need_param[i] == 'x' && !options)
+			exit_error(PARAMETER_PROBLEM,
+				   "You need to supply parameters to `-%c'\n",
+				   cmdflags[i]);
+	}
+}
+
+static void
 generic_opt_check(int command, int options)
 {
 	int i, j, legal = 0;
@@ -332,11 +377,14 @@
 	} table [] =
 	  { { CT_LIST, -ENOTSUPP, "function not implemented" },
 	    { 0xFFFF, -EINVAL, "invalid parameters" },
+	    { CT_CREATE, -EEXIST, "Such conntrack exists, try -U to update" },
 	    { CT_CREATE|CT_GET|CT_DELETE, -ENOENT, 
 		    "such conntrack doesn't exist" },
 	    { CT_CREATE|CT_GET, -ENOMEM, "not enough memory" },
 	    { CT_GET, -EAFNOSUPPORT, "protocol not supported" },
 	    { CT_CREATE, -ETIME, "conntrack has expired" },
+	    { EXP_CREATE, -ENOENT, "master conntrack not found" },
+	    { EXP_CREATE, -EINVAL, "invalid parameters" }
 	  };
 
 	for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
@@ -347,48 +395,29 @@
 	return strerror(err);
 }
 
-static void dump_tuple(struct ip_conntrack_tuple *tp)
+static void dump_tuple(struct ctnl_tuple *tp)
 {
 	fprintf(stdout, "tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",
-		tp, tp->dst.protonum,
-		NIPQUAD(tp->src.ip), ntohs(tp->src.u.all),
-		NIPQUAD(tp->dst.ip), ntohs(tp->dst.u.all));
+		tp, tp->protonum,
+		NIPQUAD(tp->src.v4), ntohs(tp->l4src.all),
+		NIPQUAD(tp->dst.v4), ntohs(tp->l4dst.all));
 }
 
-void not_implemented_yet()
-{
-	exit_error(OTHER_PROBLEM, "Sorry, not implemented yet :(\n");
-}
-
-
 #define PARSE_STATUS 0
-#define PARSE_GROUP 1
-#define PARSE_EVENT 2
-#define PARSE_DUMP 3
-#define PARSE_MAX PARSE_DUMP+1
+#define PARSE_EVENT 1
+#define PARSE_MAX 2
 
 static struct parse_parameter {
-	char 	*parameter[10];
+	char 	*parameter[5];
 	size_t  size;
-	unsigned int value[10];
+	unsigned int value[5];
 } parse_array[PARSE_MAX] = {
-	{ {"EXPECTED", "ASSURED", "SEEN_REPLY", "CONFIRMED", "SNAT", "DNAT", 
-	   "SEQ_ADJUST", "UNSET"},
-	  8,
-	  { IPS_EXPECTED, IPS_ASSURED, IPS_SEEN_REPLY, IPS_CONFIRMED,
-	    IPS_SRC_NAT, IPS_DST_NAT, IPS_SEQ_ADJUST, 0} },
-	{ {"ALL", "TCP", "UDP", "ICMP"},
-	  4,
-	  {~0U, NFGRP_IPV4_CT_TCP, NFGRP_IPV4_CT_UDP, NFGRP_IPV4_CT_ICMP} },
-	{ {"ALL", "NEW", "RELATED", "DESTROY", "REFRESH", "STATUS", 
-	   "PROTOINFO", "HELPER", "HELPINFO", "NATINFO"},
-	  10,
-	  {~0U, IPCT_NEW, IPCT_RELATED, IPCT_DESTROY, IPCT_REFRESH, IPCT_STATUS,
-	   IPCT_PROTOINFO, IPCT_HELPER, IPCT_HELPINFO, IPCT_NATINFO} },
-	{ {"ALL", "TUPLE", "STATUS", "TIMEOUT", "PROTOINFO", "HELPINFO", 
-	   "COUNTERS", "MARK"}, 8,
-	  {~0U, DUMP_TUPLE, DUMP_STATUS, DUMP_TIMEOUT, DUMP_PROTOINFO,
-	   DUMP_HELPINFO, DUMP_COUNTERS, DUMP_MARK} }
+	{ {"ASSURED", "SEEN_REPLY", "UNSET", "SRC_NAT", "DST_NAT"}, 5,
+	  { IPS_ASSURED, IPS_SEEN_REPLY, 0, 
+	    IPS_SRC_NAT_DONE, IPS_DST_NAT_DONE} },
+	{ {"ALL", "NEW", "UPDATES", "DESTROY"}, 4,
+	  {~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE, 
+	   NF_NETLINK_CONNTRACK_DESTROY} },
 };
 
 static int
@@ -425,6 +454,14 @@
 		exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg);
 }
 
+static void
+add_command(int *cmd, const int newcmd, const int othercmds)
+{
+	if (*cmd & (~othercmds))
+		exit_error(PARAMETER_PROBLEM, "Invalid commands combination\n");
+	*cmd |= newcmd;
+}
+
 unsigned int check_type(int argc, char *argv[])
 {
 	char *table = NULL;
@@ -515,15 +552,90 @@
 	return -1;
 }
 
+/* Shamelessly stolen from libipt_DNAT ;). Ranges expected in network order. */
+static void
+nat_parse(char *arg, int portok, struct ctnl_nat *range)
+{
+	char *colon, *dash, *error;
+	unsigned long ip;
+
+	memset(range, 0, sizeof(range));
+	colon = strchr(arg, ':');
+
+	if (colon) {
+		int port;
+
+		if (!portok)
+			exit_error(PARAMETER_PROBLEM,
+				   "Need TCP or UDP with port specification");
+
+		port = atoi(colon+1);
+		if (port == 0 || port > 65535)
+			exit_error(PARAMETER_PROBLEM,
+				   "Port `%s' not valid\n", colon+1);
+
+		error = strchr(colon+1, ':');
+		if (error)
+			exit_error(PARAMETER_PROBLEM,
+				   "Invalid port:port syntax - use dash\n");
+
+		dash = strchr(colon, '-');
+		if (!dash) {
+			range->l4min.tcp.port
+				= range->l4max.tcp.port
+				= htons(port);
+		} else {
+			int maxport;
+
+			maxport = atoi(dash + 1);
+			if (maxport == 0 || maxport > 65535)
+				exit_error(PARAMETER_PROBLEM,
+					   "Port `%s' not valid\n", dash+1);
+			if (maxport < port)
+				// People are stupid. 
+				exit_error(PARAMETER_PROBLEM,
+					   "Port range `%s' funky\n", colon+1);
+			range->l4min.tcp.port = htons(port);
+			range->l4max.tcp.port = htons(maxport);
+		}
+		// Starts with a colon? No IP info...
+		if (colon == arg)
+			return;
+		*colon = '\0';
+	}
+
+	dash = strchr(arg, '-');
+	if (colon && dash && dash > colon)
+		dash = NULL;
+
+	if (dash)
+		*dash = '\0';
+
+	ip = inet_addr(arg);
+	if (!ip)
+		exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+			   arg);
+	range->min_ip = ip;
+	if (dash) {
+		ip = inet_addr(dash+1);
+		if (!ip)
+			exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+				   dash+1);
+		range->max_ip = ip;
+	} else
+		range->max_ip = range->min_ip;
+}
+
 void usage(char *prog) {
 fprintf(stdout, "Tool to manipulate conntrack and expectations. Version %s\n", VERSION);
 fprintf(stdout, "Usage: %s [commands] [options]\n", prog);
 fprintf(stdout, "\n");
 fprintf(stdout, "Commands:\n");
 fprintf(stdout, "-L [table] [-z]   	List conntrack or expectation table\n");
-fprintf(stdout, "-G [table] parameters	Get conntrack or expectation\n");
+fprintf(stdout, "-G [table] parameters  Get conntrack or expectation\n");
 fprintf(stdout, "-D [table] parameters	Delete conntrack or expectation\n");
 fprintf(stdout, "-I [table] parameters	Create a conntrack or expectation\n");
+fprintf(stdout, "-U [table] parameters  Update a conntrack\n");
 fprintf(stdout, "-E [table] [options]	Show events\n");
 fprintf(stdout, "-F [table]	     	Flush table\n");
 fprintf(stdout, "-A [table] [options]	Set action\n");
@@ -535,108 +647,127 @@
 fprintf(stdout, "--reply-dst ip		Destination address from reply direction\n");
 fprintf(stdout, "--tuple-src ip		Source address in expect tuple\n");
 fprintf(stdout, "--tuple-dst ip		Destination address in expect tuple\n");
-fprintf(stdout, "--mask-src ip		Source mask in expect\n");
-fprintf(stdout, "--mask-dst ip		Destination mask in expect\n");
+fprintf(stdout, "--mask-src ip		Source mask address for expectation\n");
+fprintf(stdout, "--mask-dst ip		Destination mask address for expectations\n");
 fprintf(stdout, "-p proto		Layer 4 Protocol\n");
 fprintf(stdout, "-t timeout		Set timeout\n");
 fprintf(stdout, "-u status		Set status\n");
 fprintf(stdout, "-m dumpmask		Set dump mask\n");
 fprintf(stdout, "-g groupmask		Set group mask\n");
 fprintf(stdout, "-e eventmask		Set event mask\n");
+fprintf(stdout, "-a min_ip[-max_ip]	NAT ip range\n");
 fprintf(stdout, "-z 			Zero Counters\n");
 }
 
 int main(int argc, char *argv[])
 {
-	int c;
+	char c;
 	unsigned int command = 0, options = 0;
-	struct ip_conntrack_tuple orig, reply, tuple, mask, *o = NULL, *r = NULL;
+	struct ctnl_tuple orig, reply, mask, *o = NULL, *r = NULL;
+	struct ctnl_tuple exptuple;
 	struct ctproto_handler *h = NULL;
-	union ip_conntrack_proto proto;
+	union ctnl_protoinfo proto;
+	struct ctnl_nat range;
 	unsigned long timeout = 0;
-	unsigned int status = 0, group_mask = 0;
+	unsigned int status = IPS_CONFIRMED;
 	unsigned long id = 0;
 	unsigned int type = 0, dump_mask = 0, extra_flags = 0, event_mask = 0;
+	int manip = -1;
 	int res = 0, retry = 2;
 
-	memset(&proto, 0, sizeof(union ip_conntrack_proto));
-	memset(&orig, 0, sizeof(struct ip_conntrack_tuple));
-	memset(&reply, 0, sizeof(struct ip_conntrack_tuple));
-	orig.dst.dir = IP_CT_DIR_ORIGINAL;
-	reply.dst.dir = IP_CT_DIR_REPLY;
+	memset(&proto, 0, sizeof(union ctnl_protoinfo));
+	memset(&orig, 0, sizeof(struct ctnl_tuple));
+	memset(&reply, 0, sizeof(struct ctnl_tuple));
+	memset(&mask, 0, sizeof(struct ctnl_tuple));
+	memset(&range, 0, sizeof(struct ctnl_nat));
 	
 	while ((c = getopt_long(argc, argv, 
-		"L::I::D::G::E::A::F::hVs:d:r:q:p:t:u:m:g:e:z[:]:{:}:", 
+		"L::I::U::D::G::E::A::F::hVs:d:r:q:p:t:u:e:a:z[:]:{:}:", 
 		opts, NULL)) != -1) {
 	switch(c) {
 		case 'L':
-			command |= CT_LIST;
 			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_LIST, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_LIST, CT_NONE);
 			break;
 		case 'I':
-			command |= CT_CREATE;
 			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_CREATE, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_CREATE, CT_NONE);
 			break;
+		case 'U':
+			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_UPDATE, CT_NONE);
+			else
+				exit_error(PARAMETER_PROBLEM, "Can't update "
+					   "expectations");
+			break;
 		case 'D':
-			command |= CT_DELETE;
 			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_DELETE, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_DELETE, CT_NONE);
 			break;
 		case 'G':
-			command |= CT_GET;
 			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_GET, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_GET, CT_NONE);
 			break;
 		case 'F':
-			command |= CT_FLUSH;
 			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_FLUSH, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_FLUSH, CT_NONE);
 			break;
 		case 'E':
-			command |= CT_EVENT;
 			type = check_type(argc, argv);
+			if (type == 0)
+				add_command(&command, CT_EVENT, CT_NONE);
+			else if (type == 1)
+				add_command(&command, EXP_EVENT, CT_NONE);
 			break;
-		case 'A':
-			command |= CT_ACTION;
-			type = check_type(argc, argv);
-			break;
 		case 'V':
-			command |= CT_VERSION;
+			add_command(&command, CT_VERSION, CT_NONE);
 			break;
 		case 'h':
-			command |= CT_HELP;
+			add_command(&command, CT_HELP, CT_NONE);
 			break;
-		case 'm':
-			if (!optarg)
-				continue;
-			
-			options |= CT_OPT_DUMP_MASK;
-			parse_parameter(optarg, &dump_mask, PARSE_DUMP);
-			break;
 		case 's':
 			options |= CT_OPT_ORIG_SRC;
 			if (optarg)
-				orig.src.ip = inet_addr(optarg);
+				orig.src.v4 = inet_addr(optarg);
 			break;
 		case 'd':
 			options |= CT_OPT_ORIG_DST;
 			if (optarg)
-				orig.dst.ip = inet_addr(optarg);
+				orig.dst.v4 = inet_addr(optarg);
 			break;
 		case 'r':
 			options |= CT_OPT_REPL_SRC;
 			if (optarg)
-				reply.src.ip = inet_addr(optarg);
+				reply.src.v4 = inet_addr(optarg);
 			break;
 		case 'q':
 			options |= CT_OPT_REPL_DST;
 			if (optarg)
-				reply.dst.ip = inet_addr(optarg);
+				reply.dst.v4 = inet_addr(optarg);
 			break;
 		case 'p':
 			options |= CT_OPT_PROTO;
 			h = findproto(optarg);
 			if (!h)
 				exit_error(PARAMETER_PROBLEM, "proto needed\n");
-			orig.dst.protonum = h->protonum;
-			reply.dst.protonum = h->protonum;
+			orig.protonum = h->protonum;
+			reply.protonum = h->protonum;
 			opts = merge_options(opts, h->opts, 
 					     &h->option_offset);
 			break;
@@ -646,20 +777,13 @@
 				timeout = atol(optarg);
 			break;
 		case 'u': {
-		 	/* FIXME: NAT stuff, later... */
 			if (!optarg)
 				continue;
 
 			options |= CT_OPT_STATUS;
 			parse_parameter(optarg, &status, PARSE_STATUS);
-			/* Just insert confirmed conntracks */
-			status |= IPS_CONFIRMED;
 			break;
 		}
-		case 'g':
-			options |= CT_OPT_GROUP_MASK;
-			parse_parameter(optarg, &group_mask, PARSE_GROUP);
-			break;
 		case 'e':
 			options |= CT_OPT_EVENT_MASK;
 			parse_parameter(optarg, &event_mask, PARSE_EVENT);
@@ -667,30 +791,35 @@
 		case 'z':
 			options |= CT_OPT_ZERO;
 			break;
-		case '[':
-			options |= CT_OPT_TUPLE_SRC;
+		case 'k':
+			options |= CT_OPT_MASK_SRC;
 			if (optarg)
-				tuple.src.ip = inet_addr(optarg);
+				mask.src.v4 = inet_addr(optarg);
 			break;
-		case ']':
-			options |= CT_OPT_TUPLE_DST;
+		case 'l':
+			options |= CT_OPT_MASK_DST;
 			if (optarg)
-				tuple.dst.ip = inet_addr(optarg);
+				mask.dst.v4 = inet_addr(optarg);
 			break;
-		case '{':
-			options |= CT_OPT_MASK_SRC;
+		case 'x':
+			options |= CT_OPT_EXP_SRC;
 			if (optarg)
-				mask.src.ip = inet_addr(optarg);
+				exptuple.src.v4 = inet_addr(optarg);
 			break;
-		case '}':
-			options |= CT_OPT_MASK_DST;
+		case 'y':
+			options |= CT_OPT_EXP_DST;
 			if (optarg)
-				mask.dst.ip = inet_addr(optarg);
+				exptuple.dst.v4 = inet_addr(optarg);
 			break;
+		case 'a':
+			options |= CT_OPT_NATRANGE;
+			nat_parse(optarg, 1, &range);
+			break;
 		default:
-			if (h && h->parse && !h->parse(c - h->option_offset, 
-						       argv, &orig, &reply,
-						       &proto, &extra_flags))
+			if (h && h->parse_opts 
+			    &&!h->parse_opts(c - h->option_offset, argv, &orig, 
+				             &reply, &mask, &proto, 
+					     &extra_flags))
 				exit_error(PARAMETER_PROBLEM, "parse error\n");
 
 			/* Unknown argument... */
@@ -703,10 +832,12 @@
 		}
 	}
 
+	generic_cmd_check(command, options);
 	generic_opt_check(command, options);
 
 	if (!(command & CT_HELP)
-	    && h && h->final_check && !h->final_check(extra_flags)) {
+	    && h && h->final_check 
+	    && !h->final_check(extra_flags, &orig, &reply)) {
 		usage(argv[0]);
 		extension_help(h);
 		exit_error(PARAMETER_PROBLEM, "Missing protocol arguments!\n");
@@ -716,71 +847,115 @@
 		retry--;
 		switch(command) {
 		case CT_LIST:
-			if (type == 0) {
-				if (options & CT_OPT_ZERO)
-					res = dump_conntrack_table(1);
-				else
-					res = dump_conntrack_table(0);
-			} else 
-				res = dump_expect_list();
+			if (options & CT_OPT_ZERO)
+				res = dump_conntrack_table(1);
+			else
+				res = dump_conntrack_table(0);
 			break;
+
+		case EXP_LIST:
+			res = dump_expect_list();
+			break;
 			
 		case CT_CREATE:
-			if (type == 0)
+			if ((options & CT_OPT_ORIG) 
+			    && !(options & CT_OPT_REPL)) {
+				reply.src.v4 = orig.dst.v4;
+				reply.dst.v4 = orig.src.v4;
+			} else if (!(options & CT_OPT_ORIG)
+				   && (options & CT_OPT_REPL)) {
+				orig.src.v4 = reply.dst.v4;
+				orig.dst.v4 = reply.src.v4;
+			}
+			if (options & CT_OPT_NATRANGE)
 				res = create_conntrack(&orig, &reply, timeout, 
-						       &proto, status);
+						       &proto, status, &range);
 			else
-				res = create_expect(&tuple, &mask, &orig, 
-						    &reply, timeout);
+				res = create_conntrack(&orig, &reply, timeout,
+						       &proto, status, NULL);
 			break;
+
+		case EXP_CREATE:
+			if (options & CT_OPT_ORIG)
+				res = create_expectation(&orig, 
+							 CTA_TUPLE_ORIG,
+							 &exptuple,
+							 &mask,
+							 timeout);
+			else if (options & CT_OPT_REPL)
+				res = create_expectation(&reply,
+							 CTA_TUPLE_RPLY,
+							 &exptuple,
+							 &mask,
+							 timeout);
+			break;
+
+		case CT_UPDATE:
+			if ((options & CT_OPT_ORIG) 
+			    && !(options & CT_OPT_REPL)) {
+				reply.src.v4 = orig.dst.v4;
+				reply.dst.v4 = orig.src.v4;
+			} else if (!(options & CT_OPT_ORIG)
+				   && (options & CT_OPT_REPL)) {
+				orig.src.v4 = reply.dst.v4;
+				orig.dst.v4 = reply.src.v4;
+			}
+			res = update_conntrack(&orig, &reply, timeout, 
+					       &proto, status);
+			break;
 			
 		case CT_DELETE:
-			if (type == 0) {
-				if (options & CT_OPT_ORIG)
-					res =delete_conntrack(&orig, CTA_ORIG, 
-							      id);
-				else if (options & CT_OPT_REPL)
-					res = delete_conntrack(&reply, CTA_RPLY,
-							       id);
-			} else
-				not_implemented_yet();
+			if (options & CT_OPT_ORIG)
+				res = delete_conntrack(&orig, CTA_TUPLE_ORIG, 
+						       CTNL_DIR_ORIGINAL);
+			else if (options & CT_OPT_REPL)
+				res = delete_conntrack(&reply, CTA_TUPLE_RPLY,
+						       CTNL_DIR_REPLY);
 			break;
-			
+
+		case EXP_DELETE:
+			if (options & CT_OPT_ORIG)
+				res = delete_expectation(&orig, CTA_TUPLE_ORIG);
+			else if (options & CT_OPT_REPL)
+				res = delete_expectation(&reply, CTA_TUPLE_RPLY);
+			break;
+
 		case CT_GET:
-			if (type == 0) {
-				if (options & CT_OPT_ORIG)
-					res = get_conntrack(&orig, CTA_ORIG, 
-							    id);
-				else if (options & CT_OPT_REPL)
-					res = get_conntrack(&reply, CTA_RPLY,
-							    id);
-			} else
-				not_implemented_yet();
+			if (options & CT_OPT_ORIG)
+				res = get_conntrack(&orig, CTA_TUPLE_ORIG, id);
+			else if (options & CT_OPT_REPL)
+				res = get_conntrack(&reply, CTA_TUPLE_RPLY, id);
 			break;
-			
+
+		case EXP_GET:
+			if (options & CT_OPT_ORIG)
+				res = get_expect(&orig, CTA_TUPLE_ORIG);
+			else if (options & CT_OPT_REPL)
+				res = get_expect(&reply, CTA_TUPLE_RPLY);
+			break;
+
 		case CT_FLUSH:
-			if (type == 0)
-				res = flush_conntrack();
-			else
-				not_implemented_yet();
+			res = flush_conntrack();
 			break;
+
+		case EXP_FLUSH:
+			res = flush_expectation();
+			break;
 			
 		case CT_EVENT:
-			if (type == 0) {
-				if (options & CT_OPT_GROUP_MASK)
-					res = event_conntrack(group_mask);
-				else
-					res = event_conntrack(~0U);
-			} else
-				not_implemented_yet();
+			if (options & CT_OPT_EVENT_MASK)
+				res = event_conntrack(event_mask);
+			else
+				res = event_conntrack(~0U);
+			break;
+
+		case EXP_EVENT:
+			if (options & CT_OPT_EVENT_MASK)
+				res = event_expectation(event_mask);
+			else
+				res = event_expectation(~0U);
+			break;
 			
-		case CT_ACTION:
-			if (type == 0)
-				if (options & CT_OPT_DUMP_MASK)
-					res = set_mask(dump_mask, 0);
-				else if (options & CT_OPT_EVENT_MASK)
-					res = set_mask(event_mask, 1);
-			break;
 		case CT_VERSION:
 			fprintf(stdout, "%s v%s\n", PROGNAME, VERSION);
 			break;

Modified: trunk/conntrack/src/libct.c
===================================================================
--- trunk/conntrack/src/libct.c	2005-07-12 15:32:18 UTC (rev 4112)
+++ trunk/conntrack/src/libct.c	2005-07-12 23:24:06 UTC (rev 4113)
@@ -1,5 +1,5 @@
 /*
- * (C) 2005 by Pablo Neira Ayuso <pablo at eurodev.net>,
+ * (C) 2005 by Pablo Neira Ayuso <pablo at eurodev.net>
  *             Harald Welte <laforge at netfilter.org>
  *
  *      This program is free software; you can redistribute it and/or modify
@@ -11,9 +11,13 @@
 #include <getopt.h>
 #include <dlfcn.h>
 #include <stdlib.h>
+#include <signal.h>
 #include <errno.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+/* From kernel.h */
+#define INT_MAX         ((int)(~0U>>1))
+#define INT_MIN         (-INT_MAX - 1)
 #include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_netlink.h>
 #include "libctnetlink.h"
 #include "libnfnetlink.h"
 #include "linux_list.h"
@@ -25,6 +29,7 @@
 #define DEBUGP
 #endif
 
+static struct ctnl_handle cth;
 extern char *lib_dir;
 extern struct list_head proto_list;
 extern char *proto2str[];
@@ -37,89 +42,192 @@
 		fprintf(stdout, "[UNREPLIED] ");
 }
 
+static void parse_ip(struct nfattr *attr, struct ctnl_tuple *tuple)
+{
+	struct nfattr *tb[CTA_IP_MAX];
+
+	memset(tb, 0, CTA_IP_MAX * sizeof(struct nfattr *));
+
+        nfnl_parse_attr(tb, CTA_IP_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr));
+	if (tb[CTA_IP_V4_SRC-1])
+		tuple->src.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
+
+	if (tb[CTA_IP_V4_DST-1])
+		tuple->dst.v4 = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
+}
+
+static void parse_proto(struct nfattr *attr, struct ctnl_tuple *tuple)
+{
+	struct nfattr *tb[CTA_PROTO_MAX];
+	struct ctproto_handler *h;
+	int dir = CTNL_DIR_REPLY;
+
+	memset(tb, 0, CTA_PROTO_MAX * sizeof(struct nfattr *));
+
+	nfnl_parse_attr(tb, CTA_IP_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr));	
+	if (tb[CTA_PROTO_NUM-1])
+		tuple->protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);
+	
+	h = findproto(proto2str[tuple->protonum]);
+	if (h && h->parse_proto)
+		h->parse_proto(tb, tuple);
+}
+
+static void parse_tuple(struct nfattr *attr, struct ctnl_tuple *tuple)
+{
+	struct nfattr *tb[CTA_TUPLE_MAX];
+
+	memset(tb, 0, CTA_TUPLE_MAX*sizeof(struct nfattr *));
+
+	nfnl_parse_attr(tb, CTA_TUPLE_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr));
+	if (tb[CTA_TUPLE_IP-1])
+		parse_ip(tb[CTA_TUPLE_IP-1], tuple);
+	if (tb[CTA_TUPLE_PROTO-1])
+		parse_proto(tb[CTA_TUPLE_PROTO-1], tuple);
+}
+
+static void parse_protoinfo(struct nfattr *attr, struct ctnl_conntrack *ct)
+{
+	struct nfattr *tb[CTA_PROTOINFO_MAX];
+	struct ctproto_handler *h;
+
+	memset(tb, 0, CTA_PROTOINFO_MAX*sizeof(struct nfattr *));
+
+	nfnl_parse_attr(tb,CTA_PROTOINFO_MAX,NFA_DATA(attr), NFA_PAYLOAD(attr));
+
+	h = findproto(proto2str[ct->tuple[CTNL_DIR_ORIGINAL].protonum]);
+        if (h && h->parse_protoinfo)
+		h->parse_protoinfo(tb, ct);
+}
+	
+static void parse_counters(struct nfattr *attr, struct ctnl_conntrack *ct,
+			   enum ctattr_type parent)
+{
+	struct nfattr *tb[CTA_COUNTERS_MAX];
+
+	memset(tb, 0, CTA_COUNTERS_MAX*sizeof(struct nfattr *));
+
+	nfnl_parse_attr(tb, CTA_COUNTERS_MAX, NFA_DATA(attr),NFA_PAYLOAD(attr));
+	if (tb[CTA_COUNTERS_PACKETS_ORIG-1])
+		ct->counters[CTNL_DIR_ORIGINAL].packets
+		      = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS_ORIG-1]);
+	if (tb[CTA_COUNTERS_BYTES_ORIG-1])
+		ct->counters[CTNL_DIR_ORIGINAL].bytes
+		      = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES_ORIG-1]);
+	if (tb[CTA_COUNTERS_PACKETS_RPLY-1])
+		ct->counters[CTNL_DIR_REPLY].packets
+		      = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_PACKETS_RPLY-1]);
+	if (tb[CTA_COUNTERS_BYTES_RPLY-1])
+		ct->counters[CTNL_DIR_REPLY].bytes
+		      = *(u_int64_t *)NFA_DATA(tb[CTA_COUNTERS_BYTES_RPLY-1]);
+}
+
+#define STATUS		1
+#define PROTOINFO 	2
+#define TIMEOUT		4
+#define MARK		8
+#define COUNTERS	16
+#define USE		32
+
 static int handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg)
 {
 	struct nfgenmsg *nfmsg;
 	struct nfattr *nfa;
-	int min_len = 0;
+	int min_len = sizeof(struct nfgenmsg);;
 	struct ctproto_handler *h = NULL;
 	struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
 	int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
+	struct ctnl_conntrack ct;
+	unsigned int flags = 0;
 
-	struct ip_conntrack_tuple *orig, *reply;
-	struct cta_counters *ctr;
-	unsigned long *status, *timeout;
-	struct cta_proto *proto;
-	unsigned long *id, *mark;
+	memset(&ct, 0, sizeof(struct ctnl_conntrack));
 
-	DEBUGP("netlink header\n");
-	DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", 
-		nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, 
-		nlh->nlmsg_seq, nlh->nlmsg_pid);
-
 	nfmsg = NLMSG_DATA(nlh);
-	DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family);
+//	min_len = sizeof(struct nfgenmsg);
 
-	min_len = sizeof(struct nfgenmsg);
 	if (nlh->nlmsg_len < min_len)
 		return -EINVAL;
 
-	DEBUGP("size:%d\n", nlh->nlmsg_len);
-
 	while (NFA_OK(attr, attrlen)) {
 		switch(attr->nfa_type) {
-		case CTA_ORIG:
-			orig = NFA_DATA(attr);
-			fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", 
-					NIPQUAD(orig->src.ip), 
-					NIPQUAD(orig->dst.ip));
-			h = findproto(proto2str[orig->dst.protonum]);
-			if (h && h->print_tuple)
-				h->print_tuple(orig);
+		case CTA_TUPLE_ORIG:
+			parse_tuple(attr, &ct.tuple[CTNL_DIR_ORIGINAL]);
 			break;
-		case CTA_RPLY:
-			reply = NFA_DATA(attr);
-			fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
-					NIPQUAD(reply->src.ip), 
-					NIPQUAD(reply->dst.ip));
-			h = findproto(proto2str[reply->dst.protonum]);
-			if (h && h->print_tuple)
-				h->print_tuple(reply);	
+		case CTA_TUPLE_RPLY:
+			parse_tuple(attr, &ct.tuple[CTNL_DIR_REPLY]);
 			break;
 		case CTA_STATUS:
-			status = NFA_DATA(attr);
-			print_status(*status);
+			ct.status = *(unsigned int *)NFA_DATA(attr);
+			flags |= STATUS;
 			break;
 		case CTA_PROTOINFO:
-			proto = NFA_DATA(attr);
-			if (proto2str[proto->num_proto]) {
-				fprintf(stdout, "%s %d ", proto2str[proto->num_proto], proto->num_proto);
-				h = findproto(proto2str[proto->num_proto]);
-				if (h && h->print_proto)
-					h->print_proto(&proto->proto);
-			} else
-				fprintf(stdout, "unknown %d ", proto->num_proto);
+			parse_protoinfo(attr, &ct);
+			flags |= PROTOINFO;
 			break;
 		case CTA_TIMEOUT:
-			timeout = NFA_DATA(attr);
-			fprintf(stdout, "timeout=%lu ", *timeout);
+			ct.timeout = *(unsigned long *)NFA_DATA(attr);
+			flags |= TIMEOUT;
 			break;
 		case CTA_MARK:
-			mark = NFA_DATA(attr);
-			fprintf(stdout, "mark=%lu ", *mark);
+			ct.mark = *(unsigned long *)NFA_DATA(attr);
+			flags |= MARK;
 			break;
 		case CTA_COUNTERS:
-			ctr = NFA_DATA(attr);
-			fprintf(stdout, "orig_packets=%llu orig_bytes=%llu, "
-			       "reply_packets=%llu reply_bytes=%llu ",
-			       ctr->orig.packets, ctr->orig.bytes,
-			       ctr->reply.packets, ctr->reply.bytes);
+			parse_counters(attr, &ct, CTA_COUNTERS-1);
+			flags |= COUNTERS;
 			break;
+		case CTA_USE:
+			ct.use = *(unsigned int *)NFA_DATA(attr);
+			flags |= USE;
+			break;
 		}
-		DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type);
-		DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len);
 		attr = NFA_NEXT(attr, attrlen);
 	}
+
+	fprintf(stdout, "%-8s %u ", 
+		proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum] == NULL ?
+		"unknown" : proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum], 
+		ct.tuple[CTNL_DIR_ORIGINAL].protonum);
+
+	if (flags & TIMEOUT)
+		fprintf(stdout, "%lu ", ct.timeout);
+
+        h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]);
+        if ((flags & PROTOINFO) && h && h->print_protoinfo)
+                h->print_protoinfo(&ct.protoinfo);
+
+	fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
+		NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].src.v4),
+		NIPQUAD(ct.tuple[CTNL_DIR_ORIGINAL].dst.v4));
+
+	if (h && h->print_proto)
+		h->print_proto(&ct.tuple[CTNL_DIR_ORIGINAL]);
+
+	if (flags & COUNTERS)
+		fprintf(stdout, "packets=%llu bytes=%llu ",
+			ct.counters[CTNL_DIR_ORIGINAL].packets,
+			ct.counters[CTNL_DIR_ORIGINAL].bytes);
+
+        fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
+		NIPQUAD(ct.tuple[CTNL_DIR_REPLY].src.v4),
+		NIPQUAD(ct.tuple[CTNL_DIR_REPLY].dst.v4));
+
+        h = findproto(proto2str[ct.tuple[CTNL_DIR_ORIGINAL].protonum]);
+	if (h && h->print_proto)
+		h->print_proto(&ct.tuple[CTNL_DIR_REPLY]);
+
+	if (flags & COUNTERS)
+		fprintf(stdout, "packets=%llu bytes=%llu ",
+			ct.counters[CTNL_DIR_REPLY].packets,
+			ct.counters[CTNL_DIR_REPLY].bytes);
+	
+	print_status(ct.status);
+
+	if (flags & MARK)
+		fprintf(stdout, "mark=%lu ", ct.mark);
+	if (flags & USE)
+		fprintf(stdout, "use=%u ", ct.use);
+
 	fprintf(stdout, "\n");
 
 	return 0;
@@ -148,140 +256,133 @@
 	return handler(sock, nlh, arg);
 }
 
+void parse_expect(struct nfattr *attr, struct ctnl_tuple *tuple, 
+		  struct ctnl_tuple *mask, unsigned long *timeout)
+{
+	struct nfattr *tb[CTA_EXPECT_MAX];
+
+	memset(tb, 0, CTA_EXPECT_MAX*sizeof(struct nfattr *));
+
+	nfnl_parse_attr(tb, CTA_EXPECT_MAX, NFA_DATA(attr), NFA_PAYLOAD(attr));
+	if (tb[CTA_EXPECT_TUPLE-1])
+		parse_tuple(tb[CTA_EXPECT_TUPLE-1], tuple);
+	if (tb[CTA_EXPECT_MASK-1])
+		parse_tuple(tb[CTA_EXPECT_MASK-1], mask);
+	if (tb[CTA_EXPECT_TIMEOUT-1])
+		*timeout = *(unsigned long *)NFA_DATA(tb[CTA_EXPECT_TIMEOUT-1]);
+}
+
 static int expect_handler(struct sockaddr_nl *sock, struct nlmsghdr *nlh, void *arg)
 {
 	struct nfgenmsg *nfmsg;
 	struct nfattr *nfa;
-	int min_len = 0;
+	int min_len = sizeof(struct nfgenmsg);;
 	struct ctproto_handler *h = NULL;
 	struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
 	int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
+	struct ctnl_tuple tuple, mask;
+	unsigned long timeout = 0;
 
-	struct ip_conntrack_tuple *exp, *mask;
-	unsigned long *timeout;
+	memset(&tuple, 0, sizeof(struct ctnl_tuple));
+	memset(&mask, 0, sizeof(struct ctnl_tuple));
 
-	DEBUGP("netlink header\n");
-	DEBUGP("len: %d type: %d flags: %d seq: %d pid: %d\n", 
-		nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, 
-		nlh->nlmsg_seq, nlh->nlmsg_pid);
-
 	nfmsg = NLMSG_DATA(nlh);
-	DEBUGP("nfmsg->nfgen_family: %d\n", nfmsg->nfgen_family);
 
-	min_len = sizeof(struct nfgenmsg);
 	if (nlh->nlmsg_len < min_len)
 		return -EINVAL;
 
-	DEBUGP("size:%d\n", nlh->nlmsg_len);
-
 	while (NFA_OK(attr, attrlen)) {
 		switch(attr->nfa_type) {
-		case CTA_EXP_TUPLE:
-			exp = NFA_DATA(attr);
-			fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", 
-					NIPQUAD(exp->src.ip), 
-					NIPQUAD(exp->dst.ip));
-			h = findproto(proto2str[exp->dst.protonum]);
-			if (h && h->print_tuple)
-				h->print_tuple(exp);
-			break;
-		case CTA_EXP_MASK:
-			mask = NFA_DATA(attr);
-			fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
-					NIPQUAD(mask->src.ip), 
-					NIPQUAD(mask->dst.ip));
-			h = findproto(proto2str[mask->dst.protonum]);
-			if (h && h->print_tuple)
-				h->print_tuple(mask);	
-			break;
-		case CTA_EXP_TIMEOUT:
-			timeout = NFA_DATA(attr);
-			fprintf(stdout, "timeout:%lu ", *timeout);
-			break;
+			case CTA_EXPECT:
+				parse_expect(attr, &tuple, &mask, &timeout);
+				break;
 		}
-		DEBUGP("nfa->nfa_type: %d\n", attr->nfa_type);
-		DEBUGP("nfa->nfa_len: %d\n", attr->nfa_len);
 		attr = NFA_NEXT(attr, attrlen);
 	}
-	fprintf(stdout, "\n");
+	fprintf(stdout, "%ld proto=%d ", timeout, tuple.protonum);
 
+        fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
+		NIPQUAD(tuple.src.v4),
+		NIPQUAD(tuple.dst.v4));
+
+	fprintf(stdout, "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n",
+		NIPQUAD(mask.src.v4),
+		NIPQUAD(mask.dst.v4));
+
 	return 0;
 }
 
-int create_conntrack(struct ip_conntrack_tuple *orig,
-		     struct ip_conntrack_tuple *reply,
+int create_conntrack(struct ctnl_tuple *orig,
+		     struct ctnl_tuple *reply,
 		     unsigned long timeout,
-		     union ip_conntrack_proto *proto,
-		     unsigned int status)
+		     union ctnl_protoinfo *proto,
+		     unsigned int status,
+		     struct ctnl_nat *range)
 {
-	struct cta_proto cta;
-	struct nfattr *cda[CTA_MAX];
-	struct ctnl_handle cth;
+	struct ctnl_conntrack ct;
 	int ret;
+
+	memset(&ct, 0, sizeof(struct ctnl_conntrack));
+	ct.tuple[CTNL_DIR_ORIGINAL] = *orig;
+	ct.tuple[CTNL_DIR_REPLY] = *reply;
+	ct.timeout = timeout;
+	ct.status = status;
+	ct.protoinfo = *proto;
+	if (range)
+		ct.nat = *range;
 	
-	cta.num_proto = orig->dst.protonum;
-	memcpy(&cta.proto, proto, sizeof(*proto));
 	if ((ret = ctnl_open(&cth, 0)) < 0)
 		return ret;
 
-	if ((ret = ctnl_new_conntrack(&cth, orig, reply, timeout, &cta, 
-					status)) < 0)
-		return ret;
+	ret = ctnl_new_conntrack(&cth, &ct);
 
-	if ((ret = ctnl_close(&cth)) < 0)
-		return ret;
+	ctnl_close(&cth);
 	
-	return 0;
+	return ret;
 }
 
-int create_expect(struct ip_conntrack_tuple *tuple,
-		  struct ip_conntrack_tuple *mask,
-		  struct ip_conntrack_tuple *master_tuple_orig,
-		  struct ip_conntrack_tuple *master_tuple_reply,
-		  unsigned long timeout)
+int update_conntrack(struct ctnl_tuple *orig,
+		     struct ctnl_tuple *reply,
+		     unsigned long timeout,
+		     union ctnl_protoinfo *proto,
+		     unsigned int status)
 {
-	struct ctnl_handle cth;
+	struct ctnl_conntrack ct;
 	int ret;
 
+	memset(&ct, 0, sizeof(struct ctnl_conntrack));
+	ct.tuple[CTNL_DIR_ORIGINAL] = *orig;
+	ct.tuple[CTNL_DIR_REPLY] = *reply;
+	ct.timeout = timeout;
+	ct.status = status;
+	ct.protoinfo = *proto;
+	
 	if ((ret = ctnl_open(&cth, 0)) < 0)
 		return ret;
 
-	if ((ret = ctnl_new_expect(&cth, tuple, mask, master_tuple_orig,
-				   master_tuple_reply, timeout)) < 0)
-		return ret;
+	ret = ctnl_upd_conntrack(&cth, &ct);
 
-	if ((ret = ctnl_close(&cth)) < 0)
-		return ret;
-
-	return -1;
+	ctnl_close(&cth);
+	
+	return ret;
 }
 
-int delete_conntrack(struct ip_conntrack_tuple *tuple,
-		     enum ctattr_type_t t)
+int delete_conntrack(struct ctnl_tuple *tuple, int dir)
 {
-	struct nfattr *cda[CTA_MAX];
-	struct ctnl_handle cth;
 	int ret;
 
 	if ((ret = ctnl_open(&cth, 0)) < 0)
 		return ret;
 
-	if ((ret = ctnl_del_conntrack(&cth, tuple, t)) < 0)
-		return ret;
+	ret = ctnl_del_conntrack(&cth, tuple, dir);
+	ctnl_close(&cth);
 
-	if ((ret = ctnl_close(&cth)) < 0)
-		return ret;
-
-	return 0;
+	return ret;
 }
 
 /* get_conntrack_handler */
-int get_conntrack(struct ip_conntrack_tuple *tuple, 
-		  enum ctattr_type_t t,
-		  unsigned long id)
+int get_conntrack(struct ctnl_tuple *tuple, int dir)
 {
-	struct nfattr *cda[CTA_MAX];
-	struct ctnl_handle cth;
 	struct ctnl_msg_handler h = {
 		.type = 0,
 		.handler = handler
@@ -293,22 +394,17 @@
 
 	ctnl_register_handler(&cth, &h);
 
-	/* FIXME!!!! get_conntrack_handler returns -100 */
-	if ((ret = ctnl_get_conntrack(&cth, tuple, t)) != -100)
-		return ret;
+	ret = ctnl_get_conntrack(&cth, tuple, dir);
+	ctnl_close(&cth);
 
-	if ((ret = ctnl_close(&cth)) < 0)
-		return ret;
-
-	return 0;
+	return ret;
 }
 
 int dump_conntrack_table(int zero)
 {
 	int ret;
-	struct ctnl_handle cth;
 	struct ctnl_msg_handler h = {
-		.type = 0, /* Hm... really? */
+		.type = IPCTNL_MSG_CT_NEW, /* Hm... really? */
 		.handler = handler
 	};
 	
@@ -322,39 +418,38 @@
 	} else
 		ret = ctnl_list_conntrack(&cth, AF_INET);
 
-	if (ret != -100)
-		return ret;
+	ctnl_close(&cth);
 
-	if ((ret = ctnl_close(&cth)) < 0)
-		return ret;
+	return ret;
+}
 
-	return 0;
+static void event_sighandler(int s)
+{
+	fprintf(stdout, "Now closing conntrack event dumping...\n");
+	ctnl_close(&cth);
 }
 
 int event_conntrack(unsigned int event_mask)
 {
-	struct ctnl_handle cth;
 	struct ctnl_msg_handler hnew = {
-		.type = 0, /* new */
+		.type = IPCTNL_MSG_CT_NEW,
 		.handler = event_handler
 	};
 	struct ctnl_msg_handler hdestroy = {
-		.type = 2, /* destroy */
+		.type = IPCTNL_MSG_CT_DELETE,
 		.handler = event_handler
 	};
 	int ret;
-	
+
 	if ((ret = ctnl_open(&cth, event_mask)) < 0)
 		return ret;
 
+	signal(SIGINT, event_sighandler);
 	ctnl_register_handler(&cth, &hnew);
 	ctnl_register_handler(&cth, &hdestroy);
-	if ((ret = ctnl_event_conntrack(&cth, AF_INET)) < 0)
-		return ret;
+	ret = ctnl_event_conntrack(&cth, AF_INET);
+	ctnl_close(&cth);
 
-	if ((ret = ctnl_close(&cth)) < 0)
-		return ret;
-
 	return 0;
 }
 
@@ -404,9 +499,8 @@
 
 int dump_expect_list()
 {
-	struct ctnl_handle cth;
 	struct ctnl_msg_handler h = {
-		.type = 5, /* Hm... really? */
+		.type = IPCTNL_MSG_EXP_NEW,
 		.handler = expect_handler
 	};
 	int ret;
@@ -416,58 +510,114 @@
 
 	ctnl_register_handler(&cth, &h);
 
-	if ((ret = ctnl_list_expect(&cth, AF_INET)) != -100)
-		return ret;
+	ret = ctnl_list_expect(&cth, AF_INET);
+	ctnl_close(&cth);
+	
+	return ret;
+}
 
-	if ((ret = ctnl_close(&cth)) < 0)
+int flush_conntrack()
+{
+	int ret;
+	
+	if ((ret = ctnl_open(&cth, 0)) < 0)
 		return ret;
 
-	return 0;
+	ret = ctnl_flush_conntrack(&cth);
+	ctnl_close(&cth);
+
+	return ret;
 }
 
-int set_mask(unsigned int mask, int type)
+int get_expect(struct ctnl_tuple *tuple,
+	       enum ctattr_type t)
 {
-	struct ctnl_handle cth;
-	enum ctattr_type_t cta_type;
+	/*
+	struct ctnl_msg_handler h = {
+		.type = IPCTNL_MSG_EXP_NEW,
+		.handler = expect_handler
+	};
 	int ret;
 
-	switch(type) {
-		case 0:
-			cta_type = CTA_DUMPMASK;
-			break;
-		case 1:
-			cta_type = CTA_EVENTMASK;
-			break;
-		default:
-			/* Shouldn't happen */
-			return -1;
-	}
+	if ((ret = ctnl_open(&cth, 0)) < 0)
+		return 0;
 
+	ctnl_register_handler(&cth, &h);
+
+	ret = ctnl_get_expect(&cth, tuple, t);
+	ctnl_close(&cth);
+
+	return ret;
+	*/
+}
+
+int create_expectation(struct ctnl_tuple *tuple,
+		       enum ctattr_type t,
+		       struct ctnl_tuple *exptuple,
+		       struct ctnl_tuple *mask,
+		       unsigned long timeout)
+{
+	/*
+	int ret;
+	
 	if ((ret = ctnl_open(&cth, 0)) < 0)
 		return ret;
+
+	ret = ctnl_new_expect(&cth, tuple, t, exptuple, mask, timeout);
+	ctnl_close(&cth);
+
+	return ret;
+	*/
+}
+
+int delete_expectation(struct ctnl_tuple *tuple, enum ctattr_type t)
+{
+	/*
+	int ret;
 	
-	if ((ret = ctnl_set_mask(&cth, mask, cta_type)) < 0)
+	if ((ret = ctnl_open(&cth, 0)) < 0)
 		return ret;
+
+	ret = ctnl_del_expect(&cth, tuple, t);
+	ctnl_close(&cth);
+
+	return ret;
+	*/
+}
+
+int event_expectation(unsigned int event_mask)
+{
+	struct ctnl_msg_handler hnew = {
+		.type = IPCTNL_MSG_EXP_NEW,
+		.handler = expect_handler
+	};
+	struct ctnl_msg_handler hdestroy = {
+		.type = IPCTNL_MSG_EXP_DELETE,
+		.handler = expect_handler
+	};
+	int ret;
 	
-	if ((ret = ctnl_close(&cth)) < 0)
+	if ((ret = ctnl_open(&cth, event_mask)) < 0)
 		return ret;
 
-	return 0;
+	ctnl_register_handler(&cth, &hnew);
+	ctnl_register_handler(&cth, &hdestroy);
+	ret = ctnl_event_expect(&cth, AF_INET);
+	ctnl_close(&cth);
+
+	return ret;
 }
 
-int flush_conntrack()
+int flush_expectation()
 {
-	struct ctnl_handle cth;
 	int ret;
 	
 	if ((ret = ctnl_open(&cth, 0)) < 0)
 		return ret;
 
-	if ((ret = ctnl_flush_conntrack(&cth)) < 0)
-		return ret;
+	ret = ctnl_flush_expect(&cth);
+	ctnl_close(&cth);
 
-	if ((ret = ctnl_close(&cth)) < 0)
-		return ret;
+	return ret;
+}
 
-	return 0;
-}

Modified: trunk/conntrack/test.sh
===================================================================
--- trunk/conntrack/test.sh	2005-07-12 15:32:18 UTC (rev 4112)
+++ trunk/conntrack/test.sh	2005-07-12 23:24:06 UTC (rev 4113)
@@ -2,28 +2,18 @@
 
 SRC=1.1.1.1
 DST=2.2.2.2
-SPORT=1980
-DPORT=2005
+SPORT=2005
+DPORT=21
 
 case $1 in
 	dump)
-		# Setting dump mask
-		echo "dump mask set to TUPLE"
-		$CONNTRACK -A -m TUPLE
+		echo "Dumping conntrack table"
 		$CONNTRACK -L
-		echo "Press any key to continue..."
-		read
-		echo "dump mask set to TUPLE,COUNTERS"
-		$CONNTRACK -A -m TUPLE,COUNTERS
-		$CONNTRACK -L
-		echo "Press any key to continue..."
-		read
-		echo "dump mask set to ALL"
-		$CONNTRACK -A -m ALL
-		$CONNTRACK -L
-		echo "Press any key to continue..."
-		read
 		;;
+	flush)
+		echo "Flushing conntrack table"
+		$CONNTRACK -F
+		;;
 	new)
 		echo "creating a new conntrack"
 		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
@@ -32,6 +22,18 @@
 		 --reply-port-src $DPORT --reply-port-dst $SPORT \
 		--state LISTEN -u SEEN_REPLY -t 50
 		;;
+	new-simple)
+		echo "creating a new conntrack (simplified)"
+		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
+		--state LISTEN -u SEEN_REPLY -t 50
+		;;
+	new-nat)
+		echo "creating a new conntrack (NAT)"
+		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
+		-p tcp --orig-port-src $SPORT  --orig-port-dst $DPORT \
+		--state LISTEN -u SEEN_REPLY,SRC_NAT -t 50 -a 8.8.8.8
+		;;
 	get)
 		echo "getting a conntrack"
 		$CONNTRACK -G --orig-src $SRC --orig-dst $DST \
@@ -40,7 +42,7 @@
 		;;
 	change)
 		echo "change a conntrack"
-		$CONNTRACK -I --orig-src $SRC --orig-dst $DST \
+		$CONNTRACK -U --orig-src $SRC --orig-dst $DST \
 		--reply-src $DST --reply-dst $SRC -p tcp \
 		--orig-port-src $SPORT --orig-port-dst $DPORT \
 		--reply-port-src $DPORT --reply-port-dst $SPORT \
@@ -64,7 +66,44 @@
 			fi
 		fi
 		;;
+	dump-expect)
+		$CONNTRACK -L expect
+		;;
+	flush-expect)
+		$CONNTRACK -F expect
+		;;
+	create-expect)
+		# requires modprobe ip_conntrack_ftp
+		$CONNTRACK -I expect --orig-src $SRC --orig-dst $DST \
+		--exp-src 4.4.4.4 --exp-dst 5.5.5.5 \
+		--mask-src 255.255.255.0 --mask-dst 255.255.255.255 \
+		-p tcp --orig-port-src $SPORT --orig-port-dst $DPORT \
+		-t 200 --mask-port-src 10 --mask-port-dst 300
+		;;
+	get-expect)
+		$CONNTRACK -G expect --orig-src 4.4.4.4 --orig-dst 5.5.5.5 \
+		--p tcp --orig-port-src 0 --orig-port-dst 0 \
+		--mask-port-src 10 --mask-port-dst 11
+		;;
+	delete-expect)
+		$CONNTRACK -D expect --orig-src 4.4.4.4 \
+		--orig-dst 5.5.5.5 -p tcp --orig-port-src 0 \
+		--orig-port-dst 0 --mask-port-src 10 --mask-port-dst 11
+		;;
 	*)
-		echo "Usage: $0 [dump|new|change|delete|output]"
+		echo "Usage: $0 [dump"
+		echo "		|new"
+		echo "		|new-simple"
+		echo "		|new-nat"
+		echo "		|get"
+		echo "		|change"
+		echo "		|delete"
+		echo "		|output"
+		echo "		|flush"
+		echo "		|dump-expect"
+		echo "		|flush-expect"
+		echo "		|create-expect"
+		echo "		|get-expect"
+		echo "		|delete-expect]"
 		;;
 esac




More information about the netfilter-cvslog mailing list