[netfilter-cvslog] r4147 - trunk/libctnetlink

laforge at netfilter.org laforge at netfilter.org
Fri Jul 22 09:39:21 CEST 2005


Author: laforge at netfilter.org
Date: 2005-07-22 09:39:17 +0200 (Fri, 22 Jul 2005)
New Revision: 4147

Modified:
   trunk/libctnetlink/libctnetlink.c
   trunk/libctnetlink/libctnetlink.h
Log:
major update, still gets the endian wrong with regard to net-2.6.14 submittd kernel code.


Modified: trunk/libctnetlink/libctnetlink.c
===================================================================
--- trunk/libctnetlink/libctnetlink.c	2005-07-22 06:39:45 UTC (rev 4146)
+++ trunk/libctnetlink/libctnetlink.c	2005-07-22 07:39:17 UTC (rev 4147)
@@ -1,7 +1,8 @@
 /* libctnetlink.c: generic library for access to connection tracking.
  *
  * (C) 2001 by Jay Schulist <jschlst at samba.org>
- * (C) 2002 by Harald Welte <laforge at gnumonks.org>
+ * (C) 2002-2005 by Harald Welte <laforge at gnumonks.org>
+ * (C) 2005 by Pablo Neira Ayuso <pablo at eurodev.net>
  *
  * Development of this code funded by Astaro AG (http://www.astaro.com)
  *
@@ -22,13 +23,7 @@
 #include <asm/types.h>
 #include <linux/if.h>
 #include <linux/netlink.h>
-#include <linux/netfilter_ipv4/ip_nat.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#include <linux/netfilter_ipv4/ip_conntrack_netlink.h>
-
+#include <linux/netfilter/nfnetlink_conntrack.h>
 #include "libctnetlink.h"
 
 #define ctnl_error printf
@@ -48,7 +43,7 @@
                 struct nfgenmsg g;
         } req;
 
-	nfnl_fill_hdr(&cth->nfnlh, &req.nlh, 0, AF_INET,
+	nfnl_fill_hdr(&cth->nfnlh, &req.nlh, 0, AF_INET, 0,
 		      type, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST);
 
 	return nfnl_send(&cth->nfnlh, &req.nlh);
@@ -130,7 +125,7 @@
 int ctnl_register_handler(struct ctnl_handle *cth, 
 			  struct ctnl_msg_handler *hndlr)
 {
-	if (hndlr->type >= IPCTNL_MSG_COUNT)
+	if (hndlr->type >= IPCTNL_MSG_MAX)
 		return -EINVAL;
 
 	cth->handler[hndlr->type] = hndlr;
@@ -146,46 +141,13 @@
  */
 int ctnl_unregister_handler(struct ctnl_handle *cth, int type)
 {
-	if (type >= IPCTNL_MSG_COUNT)
+	if (type >= IPCTNL_MSG_MAX)
 		return -EINVAL;
 
 	cth->handler[type] = NULL;
 	return 0;
 }
 
-int ctnl_set_mask(struct ctnl_handle *cth, unsigned int mask, 
-		  enum ctattr_type_t type)
-{
-	struct {
-		struct nlmsghdr nlh;
-		struct nfgenmsg g;
-	} *req;
-
-	char buf[sizeof(*req) + NFA_LENGTH(sizeof(unsigned int))];
-	memset(&buf, 0, sizeof(buf));
-
-	req = (void *) &buf;
-
-	if (type != CTA_DUMPMASK && type != CTA_EVENTMASK)
-		return -1;
-
-	nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf,
-			0, AF_INET, IPCTNL_MSG_CONFIG,
-			NLM_F_REQUEST);
-
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), type, &mask,
-				sizeof(unsigned int)) < 0) {
-		ctnl_error("error during nfnl_addattr_l\n");
-		return -1;
-	}
-
-	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) {
-		ctnl_error("error while nfnl_send\n");
-		return -1;
-	}
-	return 0;
-}
-
 int ctnl_flush_conntrack(struct ctnl_handle *cth)
 {
 	struct {
@@ -199,14 +161,13 @@
 	req = (void *) &buf;
 
 	nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf,
-			0, AF_INET, IPCTNL_MSG_CT_FLUSH,
-			NLM_F_REQUEST);
+			0, AF_INET, 0, IPCTNL_MSG_CT_DELETE,
+			NLM_F_REQUEST|NLM_F_ACK);
 
-	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) {
-		ctnl_error("error while nfnl_send\n");
+	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 )
 		return -1;
-	}
-	return 0;
+
+	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
 }
 
 /**
@@ -216,643 +177,294 @@
  */
 int ctnl_list_conntrack(struct ctnl_handle *cth, int family)
 {
-	if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_CT_GET) < 0) {
-		ctnl_error("error during ctnl_wilddump_request\n");
+	if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_CT_GET) < 0)
 		return -1;
-	}
 
 	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
-
 }
 
 int ctnl_list_conntrack_zero_counters(struct ctnl_handle *cth, int family)
 {
-	if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_CT_GET_CTRZERO) < 0) {
-		ctnl_error("error during ctnl_wilddump_request\n");
+	if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_CT_GET_CTRZERO) < 0)
 		return -1;
-	}
+
 	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
 }
 
-/* TODO: Don't user list_conntrack_handler */
 int ctnl_event_conntrack(struct ctnl_handle *cth, int family)
 {
 	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
 }
 
-/**
- * ctnl_get_conntrack - get a connection from conntrack hashtable
- * cth: libctnetlink handle
- * t: tuple of connection to get
- * cb: a struct nfattr to put the connection in
- */
-int ctnl_get_conntrack(struct ctnl_handle *cth, 
-		       struct ip_conntrack_tuple *tuple,
-		       enum ctattr_type_t t)
+struct nfnlhdr {
+	struct nlmsghdr nlh;
+	struct nfgenmsg nfmsg;
+}; 
+
+static void ctnl_build_tuple_ip(struct nfnlhdr *req, int size,
+			        struct ctnl_tuple *t)
 {
-	struct {
-		struct nlmsghdr nlh;
-		struct nfgenmsg g;
-	} *req;
+	struct nfattr *nest;
 
-	char buf[sizeof(*req) + NFA_LENGTH(sizeof(*tuple))
-		 + NFA_LENGTH(sizeof(unsigned long))];
-	memset(&buf, 0, sizeof(buf));
+	nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP);
 
-	req = (void *) &buf;
+	nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4, 
+		       sizeof(u_int32_t));
 
-	if (tuple == NULL) {
-		ctnl_error("tuple must be specified\n");
-		return -1;
-	}
+	nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4,
+		       sizeof(u_int32_t));
 
-	nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf,
-			0, AF_INET, IPCTNL_MSG_CT_GET,
-			NLM_F_REQUEST);
+	nfnl_nest_end(&req->nlh, nest);
+}
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), t, tuple,
-				sizeof(*tuple)) < 0) {
-		ctnl_error("error during nfnl_addattr_l\n");
-		return -1;
-	}
+static void ctnl_build_tuple_proto(struct nfnlhdr *req, int size,
+				   struct ctnl_tuple *t)
+{
+	struct nfattr *nest;
 
-	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) {
-		ctnl_error("error while nfnl_send\n");
-		return -1;
-	}
+	nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_PROTO);
 
-	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
+	nfnl_addattr_l(&req->nlh, size, CTA_PROTO_NUM, &t->protonum,
+		       sizeof(u_int16_t));
+
+	switch(t->protonum) {
+	case IPPROTO_TCP:
+	case IPPROTO_UDP:
+	case IPPROTO_SCTP:
+		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_SRC_PORT,
+			       &t->l4src.tcp.port, sizeof(u_int16_t));
+		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_DST_PORT,
+			       &t->l4dst.tcp.port, sizeof(u_int16_t));
+		break;
+	case IPPROTO_ICMP:
+		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_CODE,
+			       &t->l4src.icmp.code, sizeof(u_int8_t));
+		nfnl_addattr_l(&req->nlh, size, CTA_PROTO_ICMP_TYPE,
+			       &t->l4dst.icmp.type, sizeof(u_int8_t));
+		break;
+	}
+	nfnl_nest_end(&req->nlh, nest);
 }
 
-/**
- * ctnl_del_conntrack - delete a connection from conntrack hashtable
- * cth: libctnetlink handle
- * t: tuple of to-be-deleted connection
- */
-int ctnl_del_conntrack(struct ctnl_handle *cth, 
-		       struct ip_conntrack_tuple *tuple,
-		       enum ctattr_type_t t)
+static void ctnl_build_tuple(struct nfnlhdr *req, int size, 
+			     struct ctnl_tuple *t, int dir)
 {
-	struct {
-		struct nlmsghdr nlh;
-		struct nfgenmsg nfmsg;
-	} *req;
+	enum ctattr_type type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG;
+	struct nfattr *nest;
 
-	char buf[sizeof(*req) + NFA_LENGTH(sizeof(*tuple))
-		 + NFA_LENGTH(sizeof(unsigned long))];
-	memset(&buf, 0, sizeof(buf));
+	nest = nfnl_nest(&req->nlh, size, type);
 
-	req = (void *) &buf;
+	ctnl_build_tuple_ip(req, size, t);
+	ctnl_build_tuple_proto(req, size, t);
 
-	if (tuple == NULL) {
-		ctnl_error("tuple must be specified\n");
-		return -1;
-	}
+	nfnl_nest_end(&req->nlh, nest);
+}
+
+static void ctnl_build_protoinfo(struct nfnlhdr *req, int size,
+				 struct ctnl_conntrack *ct)
+{
+	struct nfattr *nest;
 	
-	nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf,
-		      0, AF_INET, IPCTNL_MSG_CT_DELETE,
-		      NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK);
+	nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO);
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), t, tuple, 
-			   sizeof(*tuple)) < 0) {
-		ctnl_error("error during nfnl_addattr_l\n");
-		return -1;
+	switch (ct->tuple[CTNL_DIR_ORIGINAL].protonum) {
+	case IPPROTO_TCP:
+		nfnl_addattr_l(&req->nlh, size, CTA_PROTOINFO_TCP_STATE,
+			       &ct->protoinfo.tcp.state, sizeof(u_int8_t));
+		break;
 	}
 
-	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) {
-		ctnl_error("error while nfnl_send\n");
-		return -1;
-	}
-
-	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
+	nfnl_nest_end(&req->nlh, nest);
 }
 
-/**
- * ctnl_new_conntrack - create a connection in the conntrack hashtable
- * cth: libctnetlink handle
- * t: tuple of to-be-created connection
- */
-int ctnl_new_conntrack(struct ctnl_handle *cth,
-		       struct ip_conntrack_tuple *orig,
-		       struct ip_conntrack_tuple *reply, 
-		       unsigned long timeout, struct cta_proto *proto,
-		       unsigned int status)
+static void ctnl_build_protonat(struct nfnlhdr *req, int size,
+				 struct ctnl_conntrack *ct)
 {
-	struct {
-		struct nlmsghdr nlh;
-		struct nfgenmsg nfmsg;
-	} *req;
+	struct nfattr *nest;
+	
+	nest = nfnl_nest(&req->nlh, size, CTA_NAT_PROTO);
 
-	char buf[sizeof(*req) + NFA_LENGTH(sizeof(*orig))
-		 + NFA_LENGTH(sizeof(*reply)) 
-		 + NFA_LENGTH(sizeof(unsigned long))
-		 + NFA_LENGTH(sizeof(*proto))
-		 + NFA_LENGTH(sizeof(unsigned int))];
-	memset(&buf, 0, sizeof(buf));
-
-	req = (void *) &buf;
-
-	nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf,
-		      0, AF_INET, IPCTNL_MSG_CT_NEW,
-		      NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK);
-
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_ORIG, orig, 
-			   sizeof(*orig)) < 0) {
-		ctnl_error("error during nfnl_addattr_l\n");
-		return -1;
+	switch (ct->tuple[CTNL_DIR_ORIGINAL].protonum) {
+#if 0
+	case IPPROTO_TCP:
+		nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_TCP_MIN,
+			       &ct->nat.l4min.tcp.port, sizeof(u_int16_t));
+		nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_TCP_MAX,
+			       &ct->nat.l4max.tcp.port, sizeof(u_int16_t));
+		break;
+	case IPPROTO_UDP:
+		nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_UDP_MIN,
+			       &ct->nat.l4min.udp.port, sizeof(u_int16_t));
+		nfnl_addattr_l(&req->nlh, size, CTA_PROTONAT_UDP_MAX,
+			       &ct->nat.l4max.udp.port, sizeof(u_int16_t));
+		break;
+#endif
 	}
+	nfnl_nest_end(&req->nlh, nest);
+}
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_RPLY, reply, 
-			   sizeof(*reply)) < 0) {
-		ctnl_error("error during nfnl_addattr_l\n");
-		return -1;
-	}
+static void ctnl_build_nat(struct nfnlhdr *req, int size,
+			   struct ctnl_conntrack *ct)
+{
+	struct nfattr *nest;
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_TIMEOUT, &timeout, 
-			   sizeof(unsigned long)) < 0) {
-		ctnl_error("error during nfnl_addattr_l\n");
-		return -1;
-	}
+	nest = nfnl_nest(&req->nlh, size, CTA_NAT);
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_PROTOINFO, proto, 
-			   sizeof(*proto)) < 0) {
-		ctnl_error("error during nfnl_addattr_l\n");
-		return -1;
-	}
+	nfnl_addattr_l(&req->nlh, size, CTA_NAT_MINIP,
+		       &ct->nat.min_ip, sizeof(u_int32_t));
+	
+	if (ct->nat.min_ip != ct->nat.max_ip)
+		nfnl_addattr_l(&req->nlh, size, CTA_NAT_MAXIP,
+			       &ct->nat.max_ip, sizeof(u_int32_t));
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_STATUS, &status,
-			   sizeof(unsigned int)) < 0) {
-		ctnl_error("error during nfnl_addattr_l\n");
-		return -1;
-	}
+	if (ct->nat.l4min.all != ct->nat.l4max.all)
+		ctnl_build_protonat(req, size, ct);
 
-	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) {
-		ctnl_error("error while nfnl_send\n");
-		return -1;
-	}
-
-	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
+	nfnl_nest_end(&req->nlh, nest);
 }
 
-/**
- * ctnl_list_expect - retrieve a list of expectations from conntrack subsys
- * cth: libctnetlink handle
- * family: AF_INET, ...
- */
-int ctnl_list_expect(struct ctnl_handle *cth, int family)
+static void ctnl_build_conntrack(struct nfnlhdr *req, int size, 
+				 struct ctnl_conntrack *ct)
 {
-	if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_EXP_GET) < 0) {
-		ctnl_error("error during ctnl_wilddump_request\n");
-		return -1;
-	}
+	ctnl_build_tuple(req, size, &ct->tuple[CTNL_DIR_ORIGINAL], 
+			 CTNL_DIR_ORIGINAL);
+	ctnl_build_tuple(req, size, &ct->tuple[CTNL_DIR_REPLY],
+			 CTNL_DIR_REPLY);
+	
+	nfnl_addattr_l(&req->nlh, size, CTA_STATUS, &ct->status, 
+		       sizeof(unsigned int));
+	nfnl_addattr_l(&req->nlh, size, CTA_TIMEOUT, &ct->timeout, 
+		       sizeof(unsigned long));
 
-	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
-
+	ctnl_build_protoinfo(req, size, ct);
+	if (ct->nat.min_ip != 0)
+		ctnl_build_nat(req, size, ct);
 }
 
 /**
- * ctnl_del_expect - delete an expectation from conntrack subsystem
- *
+ * ctnl_get_conntrack - get a connection from conntrack hashtable
  * cth: libctnetlink handle
- * t: tuple of to-be-deleted expectation
+ * t: tuple of connection to get
+ * cb: a struct nfattr to put the connection in
  */
-int ctnl_del_expect(struct ctnl_handle *cth, struct ip_conntrack_tuple *t)
+int ctnl_get_conntrack(struct ctnl_handle *cth, 
+		       struct ctnl_tuple *tuple,
+		       int dir)
 {
-	struct {
-		struct nlmsghdr nlh;
-		struct nfgenmsg nfmsg;
-	} *req;
-
-	char buf[sizeof(*req) + NFA_LENGTH(sizeof(*t))];
+	struct nfnlhdr *req;
+	char buf[CTNL_BUFFSIZE];
+	
 	memset(&buf, 0, sizeof(buf));
-
 	req = (void *) &buf;
 
 	nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf,
-		      0, AF_INET, IPCTNL_MSG_EXP_DELETE,
-		      NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST);
+			0, AF_INET, 0, IPCTNL_MSG_CT_GET,
+			NLM_F_REQUEST|NLM_F_ACK);
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_ORIG, t, 
-			   sizeof(*t)) < 0) {
-		ctnl_error("error during nfnl_addattr_l\n");
+	ctnl_build_tuple(req, sizeof(buf), tuple, dir); 
+
+	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0)
 		return -1;
-	}
 
-	return nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf);
+	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
 }
 
 /**
- * ctnl_new_expect - create a new expectation
- *
+ * ctnl_del_conntrack - delete a connection from conntrack hashtable
  * cth: libctnetlink handle
- * t: tuple of to-be-created expectation
- * mask: mask of to-be-created expectation
- * master_tuple_orig: tuple of master original direction
- * master_tuple_reply: tuple of master reply direction
- * timeout: timeout of new expectation
+ * t: tuple of to-be-deleted connection
  */
-int ctnl_new_expect(struct ctnl_handle *cth,
-		    struct ip_conntrack_tuple *t,
-		    struct ip_conntrack_tuple *mask,
-		    struct ip_conntrack_tuple *master_tuple_orig,
-		    struct ip_conntrack_tuple *master_tuple_reply,
-		    unsigned long timeout)
+int ctnl_del_conntrack(struct ctnl_handle *cth, 
+		       struct ctnl_tuple *tuple,
+		       int dir)
 {
-	struct {
-		struct nlmsghdr nlh;
-		struct nfgenmsg nfmsg;
-	} *req;
+	struct nfnlhdr *req;
+	char buf[CTNL_BUFFSIZE];
 
-	char buf[sizeof(*req) + NFA_LENGTH(sizeof(*t))
-		 + NFA_LENGTH(sizeof(*mask)) 
-		 + NFA_LENGTH(sizeof(*master_tuple_orig)) 
-		 + NFA_LENGTH(sizeof(*master_tuple_reply)) 
-		 + NFA_LENGTH(sizeof(unsigned long))];
-
 	memset(&buf, 0, sizeof(buf));
-
 	req = (void *) &buf;
 
 	nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf,
-		      0, AF_INET, IPCTNL_MSG_EXP_NEW,
-		      NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK);
+		      0, AF_INET, 0, IPCTNL_MSG_CT_DELETE,
+		      NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK);
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXP_TUPLE, t,
-			   sizeof(*t)) < 0)
-		return -1;
+	ctnl_build_tuple(req, sizeof(buf), tuple, dir); 
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXP_MASK, mask,
-			   sizeof(*mask)) < 0)
+	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0)
 		return -1;
 
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_ORIG, master_tuple_orig,
-			   sizeof(*master_tuple_orig)) < 0)
-		return -1;
-
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_RPLY,
-			   master_tuple_reply, sizeof(*master_tuple_reply)) < 0)
-		return -1;
-
-	if (nfnl_addattr_l(&req->nlh, sizeof(buf), CTA_EXP_TIMEOUT, &timeout,
-			   sizeof(timeout)) < 0)
-		return -1;
-
-	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) {
-		ctnl_error("error while nfnl_send\n");
-		return -1;
-	}
-
 	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
 }
-
-#if 0
-int ctnl_listen(struct ctnl_handle *cth,
-	int (*handler)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
-        void *jarg)
+static int new_update_conntrack(struct ctnl_handle *cth,
+				struct ctnl_conntrack *ct,
+				u_int16_t msg_flags)
 {
-	struct sockaddr_nl nladdr;
+	struct nfnlhdr *req;
 	char buf[CTNL_BUFFSIZE];
-	struct nlmsghdr *h;
-	struct iovec iov;
-        int status;
-        struct msghdr msg = {
-                (void*)&nladdr, sizeof(nladdr),
-                &iov, 1,
-                NULL, 0,
-                0
-        };
 
-        memset(&nladdr, 0, sizeof(nladdr));
-        nladdr.nl_family = AF_NETLINK;
-        nladdr.nl_pid	 = 0;
-        nladdr.nl_groups = 0;
-        iov.iov_base	 = buf;
-        iov.iov_len  	 = sizeof(buf);
+	memset(&buf, 0, sizeof(buf));
+	req = (void *) &buf;
 
-        while(1)
-	{
-                status = recvmsg(cth->fd, &msg, 0);
-                if(status < 0)
-		{
-                        if(errno == EINTR)
-                                continue;
-			ctnl_error("ctnl_listen: recvmsg over-run\n");
-                        continue;
-                }
-                if(status == 0)
-		{
-			ctnl_error("ctnl_listen: EOF on netlink\n");
-                        return (-1);
-                }
-                if(msg.msg_namelen != sizeof(nladdr)) 
-		{
-			ctnl_error("ctnl_listen: Bad sender address len (%d)\n",
-	 			msg.msg_namelen);
-                        return (-1);
-                }
+	nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf,
+		      0, AF_INET, 0, IPCTNL_MSG_CT_NEW,
+		      NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|msg_flags);
 
-                for(h = (struct nlmsghdr *)buf; status >= sizeof(*h);) 
-		{
-                        int err;
-                        int len = h->nlmsg_len;
-                        int l = len - sizeof(*h);
+	ctnl_build_conntrack(req, sizeof(buf), ct);
 
-                        if(l < 0 || len > status) 
-			{
-                                if(msg.msg_flags & MSG_TRUNC) 
-				{
-					ctnl_error("ctnl_listen: MSG_TRUNC\n");
-                                        return (-1);
-                                }
-				ctnl_error("ctnl_listen: Malformed msg (%d)\n",
-					len);
-                                return (-1);
-                        }
+	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 )
+		return -1;
 
-                        err = handler(&nladdr, h, jarg);
-                        if(err < 0)
-                                return (err);
-
-                        status -= NLMSG_ALIGN(len);
-                        h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
-                }
-                if(msg.msg_flags & MSG_TRUNC) 
-		{
-			ctnl_error("ctnl_listen: MSG_TRUNC\n");
-                        continue;
-                }
-                if(status) 
-		{
-			ctnl_error("ctnl_listen: Remnant size (%d)\n", status);
-                        return (-1);
-                }
-        }
-
-	return (0);
+	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
 }
 
-int ctnl_talk(struct ctnl_handle *cth, struct nlmsghdr *n, pid_t peer,
-	unsigned groups, struct nlmsghdr *answer,
-        int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
-        void *jarg)
+/**
+ * ctnl_new_conntrack - create a connection in the conntrack hashtable
+ * cth: libctnetlink handle
+ * t: tuple of to-be-created connection
+ */
+int ctnl_new_conntrack(struct ctnl_handle *cth, struct ctnl_conntrack *ct)
 {
-	char buf[CTNL_BUFFSIZE];
-	struct sockaddr_nl nladdr;
-	struct nlmsghdr *h;
-	unsigned seq;
-        int status;
-        struct iovec iov  = { 
-		(void *)n, n->nlmsg_len 
-	};
-        struct msghdr msg = {
-                (void*)&nladdr, sizeof(nladdr),
-                &iov, 1,
-                NULL, 0,
-                0
-        };
-
-        memset(&nladdr, 0, sizeof(nladdr));
-        nladdr.nl_family = AF_NETLINK;
-        nladdr.nl_pid 	 = peer;
-        nladdr.nl_groups = groups;
-
-        n->nlmsg_seq = seq = ++cth->seq;
-        if(answer == NULL)
-                n->nlmsg_flags |= NLM_F_ACK;
-
-        status = sendmsg(cth->fd, &msg, 0);
-        if(status < 0) 
-	{
-		ctnl_error("ctnl_talk: sendmsg(netlink) %s\n",
-			strerror(errno));
-                return (-1);
-        }
-
-        iov.iov_base = buf;
-        iov.iov_len = sizeof(buf);
-
-        while(1) 
-	{
-                status = recvmsg(cth->fd, &msg, 0);
-                if(status < 0) 
-		{
-                        if(errno == EINTR)
-                                continue;
-			ctnl_error("ctnl_talk: recvmsg over-run\n");
-                        continue;
-                }
-                if(status == 0) 
-		{
-			ctnl_error("ctnl_talk: EOF on netlink\n");
-                        return (-1);
-                }
-                if(msg.msg_namelen != sizeof(nladdr)) 
-		{
-			ctnl_error("ctnl_talk: Bad sender address len (%d)\n",
-                                msg.msg_namelen);
-                        return (-1);
-                }
-
-                for(h = (struct nlmsghdr *)buf; status >= sizeof(*h);) 
-		{
-                        int len = h->nlmsg_len;
-                        int l = len - sizeof(*h);
-			int err;
-
-                        if(l < 0 || len > status) 
-			{
-                                if(msg.msg_flags & MSG_TRUNC) 
-				{
-					ctnl_error("ctnl_talk: MSG_TRUNC\n");
-                                        return (-1);
-                                }
-				ctnl_error("ctnl_talk: Malformed msg (%d)\n", 
-					len);
-                                return (-1);
-                        }
-
-                        if(h->nlmsg_pid != cth->local.nl_pid
-                            || h->nlmsg_seq != seq) 
-			{
-                                if(junk) 
-				{
-                                        err = junk(&nladdr, h, jarg);
-                                        if(err < 0)
-                                                return (err);
-                                }
-                                continue;
-                        }
-
-                        if(h->nlmsg_type == NLMSG_ERROR) 
-			{
-                                struct nlmsgerr *nerr 
-					= (struct nlmsgerr *)NLMSG_DATA(h);
-                                if(l < sizeof(struct nlmsgerr))
-					ctnl_error("ctnl_talk: ERROR MSG_TRUNC\n");
-                                else 
-				{
-                                        errno = -nerr->error;
-                                        if(errno == 0) 
-					{
-                                                if(answer)
-                                                        memcpy(answer, h, h->nlmsg_len);
-                                                return (0);
-                                        }
-                                }
-                                return (-1);
-                        }
-                        if(answer)
-			{
-                                memcpy(answer, h, h->nlmsg_len);
-                                return (0);
-                        }
-
-			ctnl_error("ctnl_talk: Unexpected reply\n");
-
-                        status -= NLMSG_ALIGN(len);
-                        h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
-                }
-                if(msg.msg_flags & MSG_TRUNC)
-		{
-			ctnl_error("ctnl_talk: MSG_TRUNC\n");
-                        continue;
-                }
-                if(status) 
-		{
-			ctnl_error("ctnl_talk: Remnant size (%d)\n", status);
-                        return (-1);
-                }
-        }
-
-	return (0);
+	return new_update_conntrack(cth, ct, NLM_F_EXCL);
 }
 
-int ctnl_dump_request(struct ctnl_handle *cth, int type, void *req, int len)
+int ctnl_upd_conntrack(struct ctnl_handle *cth, struct ctnl_conntrack *ct)
 {
-	struct sockaddr_nl nladdr;
-        struct nlmsghdr nlh;
-        struct iovec iov[2] = { 
-		{ &nlh, sizeof(nlh) }, 
-		{ req, len } 
-	};
-        struct msghdr msg = {
-                (void*)&nladdr, sizeof(nladdr),
-                iov,  2,
-                NULL, 0,
-                0
-        };
-
-        memset(&nladdr, 0, sizeof(nladdr));
-        nladdr.nl_family = AF_NETLINK;
-
-        nlh.nlmsg_len	= NLMSG_LENGTH(len);
-        nlh.nlmsg_type 	= type;
-        nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
-        nlh.nlmsg_pid 	= 0;
-        nlh.nlmsg_seq =	 cth->dump = ++cth->seq;
-
-        return (sendmsg(cth->fd, &msg, 0));
+	return new_update_conntrack(cth, ct, 0);
 }
 
-int ctnl_dump_filter(struct ctnl_handle *cth,
-	int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
-        void *arg1,
-        int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
-        void *arg2)
+/**
+ * ctnl_list_expect - retrieve a list of expectations from conntrack subsys
+ * cth: libctnetlink handle
+ * family: AF_INET, ...
+ */
+int ctnl_list_expect(struct ctnl_handle *cth, int family)
 {
-	struct sockaddr_nl nladdr;
-	char buf[CTNL_BUFFSIZE];
-        struct iovec iov = { 
-		buf, sizeof(buf) 
-	};
+	if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_EXP_GET) < 0)
+		return -1;
 
-        while(1) 
-	{
-		struct nlmsghdr *h;
-                int status;
-                struct msghdr msg = {
-                        (void*)&nladdr, sizeof(nladdr),
-                        &iov, 1,
-                        NULL, 0,
-                        0
-                };
+	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
 
-                status = recvmsg(cth->fd, &msg, 0);
-                if(status < 0)
-		{
-                        if(errno == EINTR)
-                                continue;
-			ctnl_error("ctnl_dump_filter: recvmsg over-run\n");
-                        continue;
-                }
-                if(status == 0) 
-		{
-			ctnl_error("ctnl_dump_filter: EOF on netlink\n");
-                        return (-1);
-                }
-                if(msg.msg_namelen != sizeof(nladdr)) 
-		{
-			ctnl_error("ctnl_dump_filter: Bad sender address len (%d)\n",
-                                msg.msg_namelen);
-                        return (-1);
-                }
+}
 
-                h = (struct nlmsghdr *)buf;
-                while(NLMSG_OK(h, status)) 
-		{
-                        int err;
-
-                        if(h->nlmsg_pid != cth->local.nl_pid
-                        	|| h->nlmsg_seq != cth->dump) 
-			{
-                                if(junk) 
-				{
-                                        err = junk(&nladdr, h, arg2);
-                                        if(err < 0)
-                                                return (err);
-                                }
-                                goto skip_it;
-                        }
-
-                        if(h->nlmsg_type == NLMSG_DONE)
-                                return (0);
-                        if(h->nlmsg_type == NLMSG_ERROR) 
-			{
-                                struct nlmsgerr *nerr 
-					= (struct nlmsgerr *)NLMSG_DATA(h);
-                                if(h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
-					ctnl_error("ctnl_dump_filter: MSG_TRUNC\n");
-                                else 
-                                        errno = -nerr->error;
-                                return (-1);
-                        }
-
-                        err = filter(&nladdr, h, arg1);
-                        if(err < 0)
-                                return (err);
-
-skip_it:
-                        h = NLMSG_NEXT(h, status);
-                }
-
-                if(msg.msg_flags & MSG_TRUNC)
-		{
-			ctnl_error("ctnl_dump_filter: MSG_TRUNC\n");
-                        continue;
-                }
-                if(status) 
-		{
-			ctnl_error("ctnl_dump_filter: Remnant size (%d)\n", 
-				status);
-                        return (-1);
-                }
-        }
-
-	return (0);
+int ctnl_event_expect(struct ctnl_handle *cth, int family)
+{
+	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
 }
-#endif
 
+int ctnl_flush_expect(struct ctnl_handle *cth)
+{
+	struct nfnlhdr *req;
+	char buf[sizeof(*req)];
 
+	memset(&buf, 0, sizeof(buf));
+	req = (void *) &buf;
 
+	nfnl_fill_hdr(&cth->nfnlh, (struct nlmsghdr *) &buf,
+			0, AF_INET, 0, IPCTNL_MSG_EXP_DELETE,
+			NLM_F_REQUEST|NLM_F_ACK);
 
+	if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 )
+		return -1;
 
+	return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth);
+}

Modified: trunk/libctnetlink/libctnetlink.h
===================================================================
--- trunk/libctnetlink/libctnetlink.h	2005-07-22 06:39:45 UTC (rev 4146)
+++ trunk/libctnetlink/libctnetlink.h	2005-07-22 07:39:17 UTC (rev 4147)
@@ -2,6 +2,7 @@
  *
  * Jay Schulist <jschlst at samba.org>, Copyright (c) 2001.
  * (C) 2002 by Harald Welte <laforge at gnumonks.org>
+ * (C) 2005 by Pablo Neira Ayuso <pablo at eurodev.net>
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
@@ -14,12 +15,79 @@
 #include <asm/types.h>
 #include <linux/if.h>
 #include <linux/netfilter/nfnetlink.h>
-#include <linux/netfilter_ipv4/ip_conntrack_netlink.h> 
-#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter/nfnetlink_conntrack.h> 
 #include "libnfnetlink.h"
 
-#define CTNL_BUFFSIZE	8192
+#define CTNL_BUFFSIZE	4096
 
+union ctnl_l4 {
+	/* Add other protocols here. */
+	u_int16_t all;
+	struct {
+		u_int16_t port;
+	} tcp;
+	struct {
+		u_int16_t port;
+	} udp;
+	struct {
+		u_int8_t type, code;
+		u_int16_t id;
+	} icmp;
+	struct {
+		u_int16_t port;
+	} sctp;
+};
+
+struct ctnl_tuple {
+	union {
+		u_int32_t v4;
+		u_int64_t v6;
+	} src;
+
+	union {
+		u_int32_t v4;
+		u_int64_t v6;
+	} dst;
+
+	u_int8_t protonum;
+	union ctnl_l4 l4src;
+	union ctnl_l4 l4dst;
+};
+
+union ctnl_protoinfo {
+	struct {
+		u_int8_t state;
+	} tcp;
+};
+
+struct ctnl_counters {
+	u_int64_t packets;
+	u_int64_t bytes;
+};
+
+struct ctnl_nat {
+	u_int32_t min_ip, max_ip;
+	union ctnl_l4 l4min, l4max;
+};
+
+#define CTNL_DIR_ORIGINAL 0
+#define CTNL_DIR_REPLY 1
+#define CTNL_DIR_MAX CTNL_DIR_REPLY+1
+
+struct ctnl_conntrack {
+	struct ctnl_tuple tuple[CTNL_DIR_MAX];
+	
+	unsigned long 	timeout;
+	unsigned long	mark;
+	unsigned int 	status;
+	unsigned int	use;
+	unsigned int	id;
+
+	union ctnl_protoinfo protoinfo;
+	struct ctnl_counters counters[CTNL_DIR_MAX];
+	struct ctnl_nat nat;
+};
+
 struct ctnl_msg_handler {
 	int type;
 	int (*handler)(struct sockaddr_nl *, struct nlmsghdr *, void *arg);
@@ -27,52 +95,28 @@
 
 struct ctnl_handle {
 	struct nfnl_handle nfnlh;
-	struct ctnl_msg_handler *handler[IPCTNL_MSG_COUNT];
+	struct ctnl_msg_handler *handler[IPCTNL_MSG_MAX];
 };
 
-extern int ctnl_open(struct ctnl_handle *cth, unsigned subscriptions);
-extern int ctnl_close(struct ctnl_handle *cth);
-extern int ctnl_unregister_handler(struct ctnl_handle *cth, int type);
-extern int ctnl_register_handler(struct ctnl_handle *cth, 
-				 struct ctnl_msg_handler *hndlr);
-extern int ctnl_get_conntrack(struct ctnl_handle *cth,
-			      struct ip_conntrack_tuple *tuple,
-			      enum ctattr_type_t t);
-extern int ctnl_del_conntrack(struct ctnl_handle *cth,
-			      struct ip_conntrack_tuple *tuple,
-			      enum ctattr_type_t t);
-extern int ctnl_list_conntrack(struct ctnl_handle *cth, int family);
-extern int ctnl_list_conntrack_zero_counters(struct ctnl_handle *cth, int family);
-extern int ctnl_flush_conntrack(struct ctnl_handle *cth);
+extern int ctnl_open(struct ctnl_handle *, unsigned);
+extern int ctnl_close(struct ctnl_handle *);
+extern int ctnl_unregister_handler(struct ctnl_handle *, int);
+extern int ctnl_register_handler(struct ctnl_handle *, 
+				 struct ctnl_msg_handler *);
+extern int ctnl_new_conntrack(struct ctnl_handle *, struct ctnl_conntrack *);
+extern int ctnl_upd_conntrack(struct ctnl_handle *, struct ctnl_conntrack *);
+extern int ctnl_get_conntrack(struct ctnl_handle *, struct ctnl_tuple *, int);
+extern int ctnl_del_conntrack(struct ctnl_handle *, struct ctnl_tuple *, int);
+extern int ctnl_list_conntrack(struct ctnl_handle *, int);
+extern int ctnl_list_conntrack_zero_counters(struct ctnl_handle *, int);
+extern int ctnl_event_conntrack(struct ctnl_handle *, int);
+extern int ctnl_flush_conntrack(struct ctnl_handle *);
 
-extern int ctnl_list_expect(struct ctnl_handle *cth, int family);
-extern int ctnl_del_expect(struct ctnl_handle *cth,
-			   struct ip_conntrack_tuple *t);
-extern int ctnl_new_expect(struct ctnl_handle *cth,
-			   struct ip_conntrack_tuple *t,
-			   struct ip_conntrack_tuple *mask,
-			   struct ip_conntrack_tuple *master_tuple_orig,
-			   struct ip_conntrack_tuple *master_tuple_reply,
-			   unsigned long timeout);
+extern int ctnl_list_expect(struct ctnl_handle *, int);
+extern int ctnl_event_expect(struct ctnl_handle *, int);
+extern int ctnl_flush_expect(struct ctnl_handle *);
 
-#if 0
-extern int ctnl_listen(struct ctnl_handle *ctnl,
-        int (*handler)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
-        void *jarg);
-extern int ctnl_talk(struct ctnl_handle *ctnl, struct nlmsghdr *n, pid_t peer,
-        unsigned groups, struct nlmsghdr *answer,
-        int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
-	void *jarg);
-extern int ctnl_dump_request(struct ctnl_handle *cth, int type, void *req, 
-	int len);
-extern int ctnl_dump_filter(struct ctnl_handle *cth,
-        int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
-        void *arg1,
-        int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
-        void *arg2);
-#endif
+extern int ctnl_send(struct ctnl_handle *, struct nlmsghdr *);
+extern int ctnl_wilddump_request(struct ctnl_handle *, int , int);
 
-extern int ctnl_send(struct ctnl_handle *cth, struct nlmsghdr *n);
-extern int ctnl_wilddump_request(struct ctnl_handle *cth, int family, int type);
-
 #endif	/* __LIBCTNETLINK_H */




More information about the netfilter-cvslog mailing list