summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--configure.in39
-rw-r--r--extensions/libnetfilter_conntrack_icmp.c10
-rw-r--r--extensions/libnetfilter_conntrack_sctp.c12
-rw-r--r--extensions/libnetfilter_conntrack_tcp.c14
-rw-r--r--extensions/libnetfilter_conntrack_udp.c12
-rw-r--r--include/libnetfilter_conntrack/Makefile.am2
-rw-r--r--include/libnetfilter_conntrack/libnetfilter_conntrack.h8
-rw-r--r--include/libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h29
-rw-r--r--include/libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h29
-rw-r--r--include/libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h29
-rw-r--r--l3extensions/Makefile.am16
-rw-r--r--l3extensions/libnetfilter_conntrack_ipv4.c94
-rw-r--r--l3extensions/libnetfilter_conntrack_ipv6.c115
-rw-r--r--src/libnetfilter_conntrack.c173
15 files changed, 512 insertions, 72 deletions
diff --git a/Makefile.am b/Makefile.am
index eca4cfc..4e4a678 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@ include $(top_srcdir)/Make_global.am
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
-SUBDIRS = include src extensions utils
+SUBDIRS = include src l3extensions extensions utils
LINKOPTS = -lnfnetlink
man_MANS = #nfnetlink_conntrack.3 nfnetlink_conntrack.7
diff --git a/configure.in b/configure.in
index b269bec..bb58014 100644
--- a/configure.in
+++ b/configure.in
@@ -4,7 +4,7 @@ AC_INIT
AC_CANONICAL_SYSTEM
-AM_INIT_AUTOMAKE(libnetfilter_conntrack, 0.0.29)
+AM_INIT_AUTOMAKE(libnetfilter_conntrack, 0.0.30)
AC_PROG_CC
AM_PROG_LIBTOOL
@@ -21,6 +21,41 @@ esac
AC_CHECK_LIB([nfnetlink], [nfnl_listen])
AC_CHECK_HEADER([libnfnetlink/linux_nfnetlink.h], [AC_MSG_RESULT([found])], [AC_MSG_ERROR([libnfnetlink 0.0.12 or later needed])])
+AC_CHECK_HEADERS(arpa/inet.h)
+dnl Check for inet_ntop
+AC_CHECK_FUNCS(inet_ntop)
+dnl Again, some systems have it, but not IPv6
+if test "$ac_cv_func_inet_ntop" = "yes" ; then
+AC_MSG_CHECKING(if inet_ntop supports IPv6)
+AC_TRY_RUN(
+ [
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <errno.h>
+int main()
+ {
+ struct in6_addr addr6;
+ char buf[128];
+ if (inet_ntop(AF_INET6, &addr6, buf, 128) == 0 && errno == EAFNOSUPPORT)
+ exit(1);
+ else
+ exit(0);
+ }
+ ], [ AC_MSG_RESULT(yes)
+ AC_DEFINE_UNQUOTED(HAVE_INET_NTOP_IPV6, 1, [Define to 1 if inet_ntop supports IPv6.])
+ ], AC_MSG_RESULT(no),AC_MSG_RESULT(no))
+fi
+
if test ! -z "$libdir"; then
MODULE_DIR="\\\"$libdir/libnetfilter_conntrack/\\\""
CFLAGS="$CFLAGS -DLIBNETFILTER_CONNTRACK_DIR=$MODULE_DIR"
@@ -28,5 +63,5 @@ fi
dnl Output the makefile
-AC_OUTPUT(Makefile src/Makefile include/Makefile utils/Makefile include/libnetfilter_conntrack/Makefile extensions/Makefile)
+AC_OUTPUT(Makefile src/Makefile include/Makefile utils/Makefile include/libnetfilter_conntrack/Makefile l3extensions/Makefile extensions/Makefile)
diff --git a/extensions/libnetfilter_conntrack_icmp.c b/extensions/libnetfilter_conntrack_icmp.c
index a69f43d..72a7eb0 100644
--- a/extensions/libnetfilter_conntrack_icmp.c
+++ b/extensions/libnetfilter_conntrack_icmp.c
@@ -56,22 +56,20 @@ static int compare(struct nfct_conntrack *ct1,
struct nfct_conntrack *ct2,
unsigned int flags)
{
- int ret = 1;
-
if (flags & ICMP_TYPE)
if (ct1->tuple[NFCT_DIR_ORIGINAL].l4dst.icmp.type !=
ct2->tuple[NFCT_DIR_ORIGINAL].l4dst.icmp.type)
- ret = 0;
+ return 0;
if (flags & ICMP_CODE)
if (ct1->tuple[NFCT_DIR_ORIGINAL].l4dst.icmp.code !=
ct2->tuple[NFCT_DIR_ORIGINAL].l4dst.icmp.code)
- ret = 0;
+ return 0;
if (flags & ICMP_ID)
if (ct1->tuple[NFCT_DIR_REPLY].l4src.icmp.id !=
ct2->tuple[NFCT_DIR_REPLY].l4src.icmp.id)
- ret = 0;
+ return 0;
- return ret;
+ return 1;
}
static struct nfct_proto icmp = {
diff --git a/extensions/libnetfilter_conntrack_sctp.c b/extensions/libnetfilter_conntrack_sctp.c
index aa06f6d..3785c2e 100644
--- a/extensions/libnetfilter_conntrack_sctp.c
+++ b/extensions/libnetfilter_conntrack_sctp.c
@@ -60,26 +60,24 @@ static int compare(struct nfct_conntrack *ct1,
struct nfct_conntrack *ct2,
unsigned int flags)
{
- int ret = 1;
-
if (flags & SCTP_ORIG_SPORT)
if (ct1->tuple[NFCT_DIR_ORIGINAL].l4src.sctp.port !=
ct2->tuple[NFCT_DIR_ORIGINAL].l4src.sctp.port)
- ret = 0;
+ return 0;
if (flags & SCTP_ORIG_DPORT)
if (ct1->tuple[NFCT_DIR_ORIGINAL].l4dst.sctp.port !=
ct2->tuple[NFCT_DIR_ORIGINAL].l4dst.sctp.port)
- ret = 0;
+ return 0;
if (flags & SCTP_REPL_SPORT)
if (ct1->tuple[NFCT_DIR_REPLY].l4src.sctp.port !=
ct2->tuple[NFCT_DIR_REPLY].l4src.sctp.port)
- ret = 0;
+ return 0;
if (flags & SCTP_REPL_DPORT)
if (ct1->tuple[NFCT_DIR_REPLY].l4dst.sctp.port !=
ct2->tuple[NFCT_DIR_REPLY].l4dst.sctp.port)
- ret = 0;
+ return 0;
- return ret;
+ return 1;
}
static struct nfct_proto sctp = {
diff --git a/extensions/libnetfilter_conntrack_tcp.c b/extensions/libnetfilter_conntrack_tcp.c
index dc50315..9efdbb7 100644
--- a/extensions/libnetfilter_conntrack_tcp.c
+++ b/extensions/libnetfilter_conntrack_tcp.c
@@ -98,29 +98,27 @@ static int compare(struct nfct_conntrack *ct1,
struct nfct_conntrack *ct2,
unsigned int flags)
{
- int ret = 1;
-
if (flags & TCP_ORIG_SPORT)
if (ct1->tuple[NFCT_DIR_ORIGINAL].l4src.tcp.port !=
ct2->tuple[NFCT_DIR_ORIGINAL].l4src.tcp.port)
- ret = 0;
+ return 0;
if (flags & TCP_ORIG_DPORT)
if (ct1->tuple[NFCT_DIR_ORIGINAL].l4dst.tcp.port !=
ct2->tuple[NFCT_DIR_ORIGINAL].l4dst.tcp.port)
- ret = 0;
+ return 0;
if (flags & TCP_REPL_SPORT)
if (ct1->tuple[NFCT_DIR_REPLY].l4src.tcp.port !=
ct2->tuple[NFCT_DIR_REPLY].l4src.tcp.port)
- ret = 0;
+ return 0;
if (flags & TCP_REPL_DPORT)
if (ct1->tuple[NFCT_DIR_REPLY].l4dst.tcp.port !=
ct2->tuple[NFCT_DIR_REPLY].l4dst.tcp.port)
- ret = 0;
+ return 0;
if (flags & TCP_STATE)
if (ct1->protoinfo.tcp.state != ct2->protoinfo.tcp.state)
- ret = 0;
+ return 0;
- return ret;
+ return 1;
}
static struct nfct_proto tcp = {
diff --git a/extensions/libnetfilter_conntrack_udp.c b/extensions/libnetfilter_conntrack_udp.c
index bd33280..c1d20c3 100644
--- a/extensions/libnetfilter_conntrack_udp.c
+++ b/extensions/libnetfilter_conntrack_udp.c
@@ -46,26 +46,24 @@ static int compare(struct nfct_conntrack *ct1,
struct nfct_conntrack *ct2,
unsigned int flags)
{
- int ret = 1;
-
if (flags & UDP_ORIG_SPORT)
if (ct1->tuple[NFCT_DIR_ORIGINAL].l4src.udp.port !=
ct2->tuple[NFCT_DIR_ORIGINAL].l4src.udp.port)
- ret = 0;
+ return 0;
if (flags & UDP_ORIG_DPORT)
if (ct1->tuple[NFCT_DIR_ORIGINAL].l4dst.udp.port !=
ct2->tuple[NFCT_DIR_ORIGINAL].l4dst.udp.port)
- ret = 0;
+ return 0;
if (flags & UDP_REPL_SPORT)
if (ct1->tuple[NFCT_DIR_REPLY].l4src.udp.port !=
ct2->tuple[NFCT_DIR_REPLY].l4src.udp.port)
- ret = 0;
+ return 0;
if (flags & UDP_REPL_DPORT)
if (ct1->tuple[NFCT_DIR_REPLY].l4dst.udp.port !=
ct2->tuple[NFCT_DIR_REPLY].l4dst.udp.port)
- ret = 0;
+ return 0;
- return ret;
+ return 1;
}
static struct nfct_proto udp = {
diff --git a/include/libnetfilter_conntrack/Makefile.am b/include/libnetfilter_conntrack/Makefile.am
index d6e11c5..1630695 100644
--- a/include/libnetfilter_conntrack/Makefile.am
+++ b/include/libnetfilter_conntrack/Makefile.am
@@ -1,4 +1,4 @@
-pkginclude_HEADERS = libnetfilter_conntrack.h linux_nfnetlink_conntrack.h libnetfilter_conntrack_tcp.h libnetfilter_conntrack_udp.h libnetfilter_conntrack_icmp.h libnetfilter_conntrack_sctp.h
+pkginclude_HEADERS = libnetfilter_conntrack.h linux_nfnetlink_conntrack.h libnetfilter_conntrack_tcp.h libnetfilter_conntrack_udp.h libnetfilter_conntrack_icmp.h libnetfilter_conntrack_sctp.h libnetfilter_conntrack_ipv4.h libnetfilter_conntrack_ipv6.h
noinst_HEADERS = libnetfilter_conntrack_extensions.h
diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack.h b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
index 4b751a2..46ba5da 100644
--- a/include/libnetfilter_conntrack/libnetfilter_conntrack.h
+++ b/include/libnetfilter_conntrack/libnetfilter_conntrack.h
@@ -109,8 +109,9 @@ struct nfct_expect {
struct nfct_conntrack_compare {
struct nfct_conntrack *ct;
- unsigned int flag;
- unsigned int protoflag;
+ unsigned int flags;
+ unsigned int l3flags;
+ unsigned int l4flags;
};
enum {
@@ -294,8 +295,7 @@ extern int nfct_sprintf_id(char *buf, u_int32_t id);
*/
extern int nfct_conntrack_compare(struct nfct_conntrack *ct1,
struct nfct_conntrack *ct2,
- unsigned int cmp_flag,
- unsigned int cmp_protoflag);
+ struct nfct_conntrack_compare *cmp);
/*
* Expectations
diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h b/include/libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h
new file mode 100644
index 0000000..d15a7e3
--- /dev/null
+++ b/include/libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h
@@ -0,0 +1,29 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef _LIBNETFILTER_CONNTRACK_IPV4_H_
+#define _LIBNETFILTER_CONNTRACK_IPV4_H_
+
+enum ipv4_flags {
+ IPV4_ORIG_SRC_BIT = 0,
+ IPV4_ORIG_SRC = (1 << IPV4_ORIG_SRC_BIT),
+
+ IPV4_ORIG_DST_BIT = 1,
+ IPV4_ORIG_DST = (1 << IPV4_ORIG_DST_BIT),
+
+ IPV4_ORIG = (IPV4_ORIG_SRC | IPV4_ORIG_DST),
+
+ IPV4_REPL_SRC_BIT = 2,
+ IPV4_REPL_SRC = (1 << IPV4_REPL_SRC_BIT),
+
+ IPV4_REPL_DST_BIT = 3,
+ IPV4_REPL_DST = (1 << IPV4_REPL_DST_BIT),
+
+ IPV4_REPL = (IPV4_REPL_SRC | IPV4_REPL_DST)
+};
+
+#endif
diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h b/include/libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h
new file mode 100644
index 0000000..280c5cd
--- /dev/null
+++ b/include/libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h
@@ -0,0 +1,29 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef _LIBNETFILTER_CONNTRACK_IPV6_H_
+#define _LIBNETFILTER_CONNTRACK_IPV6_H_
+
+enum ipv6_flags {
+ IPV6_ORIG_SRC_BIT = 0,
+ IPV6_ORIG_SRC = (1 << IPV6_ORIG_SRC_BIT),
+
+ IPV6_ORIG_DST_BIT = 1,
+ IPV6_ORIG_DST = (1 << IPV6_ORIG_DST_BIT),
+
+ IPV6_ORIG = (IPV6_ORIG_SRC | IPV6_ORIG_DST),
+
+ IPV6_REPL_SRC_BIT = 2,
+ IPV6_REPL_SRC = (1 << IPV6_REPL_SRC_BIT),
+
+ IPV6_REPL_DST_BIT = 3,
+ IPV6_REPL_DST = (1 << IPV6_REPL_DST_BIT),
+
+ IPV6_REPL = (IPV6_REPL_SRC | IPV6_REPL_DST)
+};
+
+#endif
diff --git a/include/libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h b/include/libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h
new file mode 100644
index 0000000..86e002a
--- /dev/null
+++ b/include/libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h
@@ -0,0 +1,29 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef _LIBNETFILTER_CONNTRACK_L3EXTENSIONS_H_
+#define _LIBNETFILTER_CONNTRACK_L3EXTENSIONS_H_
+
+#include "linux_list.h"
+
+struct nfct_l3proto {
+ struct list_head head;
+
+ char *name;
+ u_int16_t protonum;
+ char *version;
+
+ void (*parse_proto)(struct nfattr **, struct nfct_tuple *);
+ void (*build_tuple_proto)(struct nfnlhdr *, int, struct nfct_tuple *);
+ int (*print_proto)(char *, struct nfct_tuple *);
+ int (*compare)(struct nfct_conntrack *, struct nfct_conntrack *,
+ unsigned int);
+};
+
+extern void nfct_register_l3proto(struct nfct_l3proto *h);
+
+#endif
diff --git a/l3extensions/Makefile.am b/l3extensions/Makefile.am
new file mode 100644
index 0000000..fa21b2d
--- /dev/null
+++ b/l3extensions/Makefile.am
@@ -0,0 +1,16 @@
+include $(top_srcdir)/Make_global.am
+
+AUTOMAKE_OPTIONS = no-dependencies foreign
+
+AM_CFLAGS=-fPIC -Wall
+LIBS=
+
+pkglib_LTLIBRARIES = nfct_l3proto_ipv4.la nfct_l3proto_ipv6.la
+
+nfct_l3proto_ipv4_la_SOURCES = libnetfilter_conntrack_ipv4.c
+nfct_l3proto_ipv4_la_LDFLAGS = -module -avoid-version -release $(VERSION)
+nfct_l3proto_ipv4_la_LIBADD = ../src/libnetfilter_conntrack.la
+
+nfct_l3proto_ipv6_la_SOURCES = libnetfilter_conntrack_ipv6.c
+nfct_l3proto_ipv6_la_LDFLAGS = -module -avoid-version -release $(VERSION)
+nfct_l3proto_ipv6_la_LIBADD = ../src/libnetfilter_conntrack.la
diff --git a/l3extensions/libnetfilter_conntrack_ipv4.c b/l3extensions/libnetfilter_conntrack_ipv4.c
new file mode 100644
index 0000000..727ea01
--- /dev/null
+++ b/l3extensions/libnetfilter_conntrack_ipv4.c
@@ -0,0 +1,94 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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 <arpa/inet.h>
+#include <netinet/in.h> /* For htons */
+#include <libnetfilter_conntrack/linux_nfnetlink_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h>
+
+static void parse_proto(struct nfattr *cda[], struct nfct_tuple *tuple)
+{
+ if (cda[CTA_IP_V4_SRC-1])
+ tuple->src.v4 = *(u_int32_t *)NFA_DATA(cda[CTA_IP_V4_SRC-1]);
+
+ if (cda[CTA_IP_V4_DST-1])
+ tuple->dst.v4 = *(u_int32_t *)NFA_DATA(cda[CTA_IP_V4_DST-1]);
+}
+
+static void build_tuple_proto(struct nfnlhdr *req, int size,
+ struct nfct_tuple *t)
+{
+ nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4,
+ sizeof(u_int32_t));
+ nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4,
+ sizeof(u_int32_t));
+}
+
+static int print_proto(char *buf, struct nfct_tuple *tuple)
+{
+ struct in_addr src = { .s_addr = tuple->src.v4 };
+ struct in_addr dst = { .s_addr = tuple->dst.v4 };
+ int size;
+
+ size = sprintf(buf, "src=%s ", inet_ntoa(src));
+ size += sprintf(buf+size, "dst=%s ", inet_ntoa(dst));
+
+ return size;
+}
+
+static int compare(struct nfct_conntrack *ct1,
+ struct nfct_conntrack *ct2,
+ unsigned int flags)
+{
+ if (flags & IPV4_ORIG)
+ if (ct1->tuple[NFCT_DIR_ORIGINAL].l3protonum !=
+ ct2->tuple[NFCT_DIR_ORIGINAL].l3protonum)
+ return 0;
+ if (flags & IPV4_REPL)
+ if (ct1->tuple[NFCT_DIR_REPLY].l3protonum !=
+ ct2->tuple[NFCT_DIR_REPLY].l3protonum)
+ return 0;
+ if (flags & IPV4_ORIG_SRC)
+ if (ct1->tuple[NFCT_DIR_ORIGINAL].src.v4 !=
+ ct2->tuple[NFCT_DIR_ORIGINAL].src.v4)
+ return 0;
+ if (flags & IPV4_ORIG_DST)
+ if (ct1->tuple[NFCT_DIR_ORIGINAL].dst.v4 !=
+ ct2->tuple[NFCT_DIR_ORIGINAL].dst.v4)
+ return 0;
+ if (flags & IPV4_REPL_SRC)
+ if (ct1->tuple[NFCT_DIR_REPLY].src.v4 !=
+ ct2->tuple[NFCT_DIR_REPLY].src.v4)
+ return 0;
+ if (flags & IPV4_REPL_DST)
+ if (ct1->tuple[NFCT_DIR_REPLY].dst.v4 !=
+ ct2->tuple[NFCT_DIR_REPLY].dst.v4)
+ return 0;
+
+ return 1;
+}
+
+static struct nfct_l3proto ipv4 = {
+ .name = "ipv4",
+ .protonum = AF_INET,
+ .parse_proto = parse_proto,
+ .build_tuple_proto = build_tuple_proto,
+ .print_proto = print_proto,
+ .compare = compare,
+ .version = VERSION
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+ nfct_register_l3proto(&ipv4);
+}
diff --git a/l3extensions/libnetfilter_conntrack_ipv6.c b/l3extensions/libnetfilter_conntrack_ipv6.c
new file mode 100644
index 0000000..b0c7a3f
--- /dev/null
+++ b/l3extensions/libnetfilter_conntrack_ipv6.c
@@ -0,0 +1,115 @@
+/*
+ * (C) 2005 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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 <arpa/inet.h>
+#include <libnetfilter_conntrack/linux_nfnetlink_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h>
+
+#ifndef HAVE_INET_NTOP_IPV6
+#warning "inet_ntop does not support IPv6"
+#endif
+
+static void parse_proto(struct nfattr *cda[], struct nfct_tuple *tuple)
+{
+ if (cda[CTA_IP_V6_SRC-1])
+ memcpy(tuple->src.v6, NFA_DATA(cda[CTA_IP_V6_SRC-1]),
+ sizeof(u_int32_t)*4);
+
+ if (cda[CTA_IP_V6_DST-1])
+ memcpy(tuple->dst.v6, NFA_DATA(cda[CTA_IP_V6_DST-1]),
+ sizeof(u_int32_t)*4);
+}
+
+static void build_tuple_proto(struct nfnlhdr *req, int size,
+ struct nfct_tuple *t)
+{
+ nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_SRC, &t->src.v6,
+ sizeof(u_int32_t)*4);
+ nfnl_addattr_l(&req->nlh, size, CTA_IP_V6_DST, &t->dst.v6,
+ sizeof(u_int32_t)*4);
+}
+
+static int print_proto(char *buf, struct nfct_tuple *tuple)
+{
+ struct in6_addr src;
+ struct in6_addr dst;
+ char tmp[INET6_ADDRSTRLEN];
+ int size;
+
+ memcpy(&src.in6_u, tuple->src.v6, sizeof(struct in6_addr));
+ memcpy(&dst.in6_u, tuple->dst.v6, sizeof(struct in6_addr));
+
+ if (!inet_ntop(AF_INET6, &src, tmp, sizeof(tmp)))
+ return 0;
+ size = sprintf(buf, "src=%s ", tmp);
+ if (!inet_ntop(AF_INET6, &dst, tmp, sizeof(tmp)))
+ return 0;
+ size += sprintf(buf + size, "dst=%s ", tmp);
+
+ return size;
+}
+
+static int compare(struct nfct_conntrack *ct1,
+ struct nfct_conntrack *ct2,
+ unsigned int flags)
+{
+ if (flags & IPV6_ORIG)
+ if (ct1->tuple[NFCT_DIR_ORIGINAL].l3protonum !=
+ ct2->tuple[NFCT_DIR_ORIGINAL].l3protonum)
+ return 0;
+ if (flags & IPV6_REPL)
+ if (ct1->tuple[NFCT_DIR_REPLY].l3protonum !=
+ ct2->tuple[NFCT_DIR_REPLY].l3protonum)
+ return 0;
+ if (flags & IPV6_ORIG_SRC)
+ if (memcmp(ct1->tuple[NFCT_DIR_ORIGINAL].src.v6,
+ ct2->tuple[NFCT_DIR_ORIGINAL].src.v6,
+ sizeof(u_int32_t)*4) == 0)
+ return 0;
+ if (flags & IPV6_ORIG_DST)
+ if (memcmp(ct1->tuple[NFCT_DIR_ORIGINAL].dst.v6,
+ ct2->tuple[NFCT_DIR_ORIGINAL].dst.v6,
+ sizeof(u_int32_t)*4) == 0)
+ return 0;
+ if (flags & IPV6_REPL_SRC)
+ if (memcmp(ct1->tuple[NFCT_DIR_REPLY].src.v6,
+ ct2->tuple[NFCT_DIR_REPLY].src.v6,
+ sizeof(u_int32_t)*4) == 0)
+ return 0;
+ if (flags & IPV6_REPL_DST)
+ if (memcmp(ct1->tuple[NFCT_DIR_REPLY].dst.v6,
+ ct2->tuple[NFCT_DIR_REPLY].dst.v6,
+ sizeof(u_int32_t)*4) == 0)
+ return 0;
+
+ return 1;
+}
+
+static struct nfct_l3proto ipv6 = {
+ .name = "ipv6",
+ .protonum = AF_INET6,
+ .parse_proto = parse_proto,
+ .build_tuple_proto = build_tuple_proto,
+ .print_proto = print_proto,
+ .compare = compare,
+ .version = VERSION
+};
+
+static void __attribute__ ((constructor)) init(void);
+
+static void init(void)
+{
+ nfct_register_l3proto(&ipv6);
+}
diff --git a/src/libnetfilter_conntrack.c b/src/libnetfilter_conntrack.c
index 3651fc7..0c7ba8a 100644
--- a/src/libnetfilter_conntrack.c
+++ b/src/libnetfilter_conntrack.c
@@ -19,6 +19,7 @@
#include "linux_list.h"
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack_extensions.h>
#define NFCT_BUFSIZE 4096
@@ -36,13 +37,19 @@ struct nfct_handle {
static char *lib_dir = LIBNETFILTER_CONNTRACK_DIR;
static LIST_HEAD(proto_list);
+static LIST_HEAD(l3proto_list);
static char *proto2str[IPPROTO_MAX] = {
[IPPROTO_TCP] = "tcp",
[IPPROTO_UDP] = "udp",
[IPPROTO_ICMP] = "icmp",
[IPPROTO_SCTP] = "sctp"
};
+static char *l3proto2str[AF_MAX] = {
+ [AF_INET] = "ipv4",
+ [AF_INET6] = "ipv6"
+};
static struct nfct_proto *findproto(char *name);
+static struct nfct_l3proto *findl3proto(char *name);
/* handler used for nfnl_listen */
static int callback_handler(struct sockaddr_nl *nladdr,
@@ -133,14 +140,13 @@ static void nfct_build_tuple_ip(struct nfnlhdr *req, int size,
struct nfct_tuple *t)
{
struct nfattr *nest;
+ struct nfct_l3proto *h;
nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_IP);
- nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_SRC, &t->src.v4,
- sizeof(u_int32_t));
-
- nfnl_addattr_l(&req->nlh, size, CTA_IP_V4_DST, &t->dst.v4,
- sizeof(u_int32_t));
+ h = findl3proto(l3proto2str[t->l3protonum]);
+ if (h && h->build_tuple_proto)
+ h->build_tuple_proto(req, size, t);
nfnl_nest_end(&req->nlh, nest);
}
@@ -282,6 +288,39 @@ static struct nfct_proto *findproto(char *name)
return handler;
}
+static struct nfct_l3proto *findl3proto(char *name)
+{
+ struct list_head *i;
+ struct nfct_l3proto *cur = NULL, *handler = NULL;
+
+ if (!name)
+ return handler;
+
+ lib_dir = getenv("LIBNETFILTER_CONNTRACK_DIR");
+ if (!lib_dir)
+ lib_dir = LIBNETFILTER_CONNTRACK_DIR;
+
+ list_for_each(i, &l3proto_list) {
+ cur = (struct nfct_l3proto *) i;
+ if (strcmp(cur->name, name) == 0) {
+ handler = cur;
+ break;
+ }
+ }
+
+ if (!handler) {
+ char path[sizeof("nfct_l3proto_.so") + strlen(VERSION)
+ + strlen(name) + strlen(lib_dir)];
+ sprintf(path, "%s/nfct_l3proto_%s-%s.so",lib_dir,name,VERSION);
+ if (dlopen(path, RTLD_NOW))
+ handler = findl3proto(name);
+ else
+ fprintf(stderr, "%s\n", dlerror());
+ }
+
+ return handler;
+}
+
int nfct_sprintf_status_assured(char *buf, struct nfct_conntrack *ct)
{
int size = 0;
@@ -305,13 +344,12 @@ int nfct_sprintf_status_seen_reply(char *buf, struct nfct_conntrack *ct)
static void parse_ip(struct nfattr *attr, struct nfct_tuple *tuple)
{
struct nfattr *tb[CTA_IP_MAX];
+ struct nfct_l3proto *h;
nfnl_parse_nested(tb, CTA_IP_MAX, 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]);
+ h = findl3proto(l3proto2str[tuple->l3protonum]);
+ if (h && h->parse_proto)
+ h->parse_proto(tb, tuple);
}
static void parse_proto(struct nfattr *attr, struct nfct_tuple *tuple)
@@ -412,6 +450,9 @@ static int nfct_conntrack_netlink_handler(struct nfct_handle *cth,
memset(&ct, 0, sizeof(struct nfct_conntrack));
+ ct.tuple[NFCT_DIR_ORIGINAL].l3protonum = nfhdr->nfgen_family;
+ ct.tuple[NFCT_DIR_REPLY].l3protonum = nfhdr->nfgen_family;
+
nfnl_parse_attr(cda, CTA_MAX, NFA_DATA(nfhdr), len);
if (cda[CTA_TUPLE_ORIG-1])
@@ -500,11 +541,11 @@ int nfct_sprintf_protoinfo(char *buf, struct nfct_conntrack *ct)
int nfct_sprintf_address(char *buf, struct nfct_tuple *t)
{
int size = 0;
- struct in_addr src = { .s_addr = t->src.v4 };
- struct in_addr dst = { .s_addr = t->dst.v4 };
+ struct nfct_l3proto *h;
- size += sprintf(buf, "src=%s ", inet_ntoa(src));
- size += sprintf(buf+size, "dst=%s ", inet_ntoa(dst));
+ h = findl3proto(l3proto2str[t->l3protonum]);
+ if (h && h->print_proto)
+ size += h->print_proto(buf, t);
return size;
}
@@ -607,7 +648,7 @@ int nfct_default_conntrack_display(void *arg, unsigned int flags, int type,
int size;
struct nfct_conntrack_compare *cmp = data;
- if (cmp && !nfct_conntrack_compare(cmp->ct, arg, 0, cmp->protoflag))
+ if (cmp && !nfct_conntrack_compare(cmp->ct, arg, cmp))
return 0;
memset(buf, 0, sizeof(buf));
@@ -625,7 +666,7 @@ int nfct_default_conntrack_display_id(void *arg, unsigned int flags, int type,
int size;
struct nfct_conntrack_compare *cmp = data;
- if (cmp && !nfct_conntrack_compare(cmp->ct, arg, 0, cmp->protoflag))
+ if (cmp && !nfct_conntrack_compare(cmp->ct, arg, cmp))
return 0;
memset(buf, 0, sizeof(buf));
@@ -639,8 +680,20 @@ int nfct_default_conntrack_display_id(void *arg, unsigned int flags, int type,
int nfct_default_conntrack_event_display(void *arg, unsigned int flags,
int type, void *data)
{
- fprintf(stdout, "%9s ", msgtype[type]);
- return nfct_default_conntrack_display_id(arg, flags, type, data);
+ char buf[512];
+ int size;
+ struct nfct_conntrack_compare *cmp = data;
+
+ if (cmp && !nfct_conntrack_compare(cmp->ct, arg, cmp))
+ return 0;
+
+ memset(buf, 0, sizeof(buf));
+ size = sprintf(buf, "%9s ", msgtype[type]);
+ size += nfct_sprintf_conntrack_id(buf + size, arg, flags);
+ sprintf(buf+size, "\n");
+ fprintf(stdout, buf);
+
+ return 0;
}
int nfct_sprintf_expect_proto(char *buf, struct nfct_expect *exp)
@@ -715,6 +768,8 @@ static int nfct_expect_netlink_handler(struct nfct_handle *cth,
memset(&exp, 0, sizeof(struct nfct_expect));
+ exp.tuple.l3protonum = nfhdr->nfgen_family;
+
nfnl_parse_attr(cda, CTA_EXPECT_MAX, NFA_DATA(nfhdr), len);
if (cda[CTA_EXPECT_TUPLE-1])
@@ -770,26 +825,55 @@ void nfct_conntrack_free(struct nfct_conntrack *ct)
free(ct);
}
+#define L3PROTONUM(ct) ct->tuple[NFCT_DIR_ORIGINAL].l3protonum
+#define L4PROTONUM(ct) ct->tuple[NFCT_DIR_ORIGINAL].protonum
+
int nfct_conntrack_compare(struct nfct_conntrack *ct1,
struct nfct_conntrack *ct2,
- unsigned int cmp_flag,
- unsigned int cmp_protoflag)
+ struct nfct_conntrack_compare *cmp)
{
+ struct nfct_l3proto *l3proto;
struct nfct_proto *proto;
+ unsigned int l3flags = cmp->l3flags;
+ unsigned int l4flags = cmp->l4flags;
+ unsigned int flags = cmp->flags;
- if (ct1->tuple[NFCT_DIR_ORIGINAL].protonum !=
- ct2->tuple[NFCT_DIR_ORIGINAL].protonum)
+ if ((flags & NFCT_MARK) && (ct1->mark != ct2->mark))
return 0;
- /*
- * TODO: implement tuple, status, mark... comparison.
- */
+ if (l3flags) {
+ if (ct1->tuple[NFCT_DIR_ORIGINAL].l3protonum != AF_UNSPEC &&
+ ct2->tuple[NFCT_DIR_ORIGINAL].l3protonum != AF_UNSPEC &&
+ ct1->tuple[NFCT_DIR_ORIGINAL].l3protonum !=
+ ct2->tuple[NFCT_DIR_ORIGINAL].l3protonum)
+ return 0;
+ if (ct1->tuple[NFCT_DIR_REPLY].l3protonum != AF_UNSPEC &&
+ ct2->tuple[NFCT_DIR_REPLY].l3protonum != AF_UNSPEC &&
+ ct1->tuple[NFCT_DIR_REPLY].l3protonum !=
+ ct2->tuple[NFCT_DIR_REPLY].l3protonum)
+ return 0;
+ l3proto = findl3proto(l3proto2str[L3PROTONUM(ct1)]);
+ if (l3proto && !l3proto->compare(ct1, ct2, l3flags))
+ return 0;
+ }
- proto = findproto(proto2str[ct1->tuple[NFCT_DIR_ORIGINAL].protonum]);
- if (!proto)
- return 0;
+ if (l4flags) {
+ if (ct1->tuple[NFCT_DIR_ORIGINAL].protonum != 0 &&
+ ct2->tuple[NFCT_DIR_ORIGINAL].protonum != 0 &&
+ ct1->tuple[NFCT_DIR_ORIGINAL].protonum !=
+ ct2->tuple[NFCT_DIR_ORIGINAL].protonum)
+ return 0;
+ if (ct1->tuple[NFCT_DIR_REPLY].protonum != 0 &&
+ ct2->tuple[NFCT_DIR_REPLY].protonum != 0 &&
+ ct1->tuple[NFCT_DIR_REPLY].protonum !=
+ ct2->tuple[NFCT_DIR_REPLY].protonum)
+ return 0;
+ proto = findproto(proto2str[L4PROTONUM(ct1)]);
+ if (proto && !proto->compare(ct1, ct2, l4flags))
+ return 0;
+ }
- return proto->compare(ct1, ct2, cmp_protoflag);
+ return 1;
}
int nfct_create_conntrack(struct nfct_handle *cth, struct nfct_conntrack *ct)
@@ -799,12 +883,13 @@ int nfct_create_conntrack(struct nfct_handle *cth, struct nfct_conntrack *ct)
u_int32_t status = htonl(ct->status | IPS_CONFIRMED);
u_int32_t timeout = htonl(ct->timeout);
u_int32_t mark = htonl(ct->mark);
+ u_int8_t l3num = ct->tuple[NFCT_DIR_ORIGINAL].l3protonum;
req = (void *) buf;
memset(buf, 0, sizeof(buf));
- nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_CT_NEW,
+ nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, l3num, 0, IPCTNL_MSG_CT_NEW,
NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|NLM_F_EXCL);
nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_ORIGINAL],
@@ -838,11 +923,12 @@ int nfct_update_conntrack(struct nfct_handle *cth, struct nfct_conntrack *ct)
u_int32_t timeout = htonl(ct->timeout);
u_int32_t id = htonl(ct->id);
u_int32_t mark = htonl(ct->mark);
+ u_int8_t l3num = ct->tuple[NFCT_DIR_ORIGINAL].l3protonum;
req = (void *) &buf;
memset(&buf, 0, sizeof(buf));
- nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_CT_NEW,
+ nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, l3num, 0, IPCTNL_MSG_CT_NEW,
NLM_F_REQUEST|NLM_F_ACK);
nfct_build_tuple(req, sizeof(buf), &ct->tuple[NFCT_DIR_ORIGINAL],
@@ -881,12 +967,13 @@ int nfct_delete_conntrack(struct nfct_handle *cth, struct nfct_tuple *tuple,
struct nfnlhdr *req;
char buf[NFCT_BUFSIZE];
int type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG;
+ u_int8_t l3num = tuple->l3protonum;
req = (void *) &buf;
memset(&buf, 0, sizeof(buf));
nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0,
- AF_INET, 0, IPCTNL_MSG_CT_DELETE,
+ l3num, 0, IPCTNL_MSG_CT_DELETE,
NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK);
nfct_build_tuple(req, sizeof(buf), tuple, type);
@@ -907,6 +994,7 @@ int nfct_get_conntrack(struct nfct_handle *cth, struct nfct_tuple *tuple,
struct nfnlhdr *req;
char buf[NFCT_BUFSIZE];
int type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG;
+ u_int8_t l3num = tuple->l3protonum;
cth->handler = nfct_conntrack_netlink_handler;
@@ -914,7 +1002,7 @@ int nfct_get_conntrack(struct nfct_handle *cth, struct nfct_tuple *tuple,
req = (void *) &buf;
nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0,
- AF_INET, 0, IPCTNL_MSG_CT_GET,
+ l3num, 0, IPCTNL_MSG_CT_GET,
NLM_F_REQUEST|NLM_F_ACK);
nfct_build_tuple(req, sizeof(buf), tuple, type);
@@ -989,6 +1077,16 @@ void nfct_register_proto(struct nfct_proto *h)
list_add(&h->head, &proto_list);
}
+void nfct_register_l3proto(struct nfct_l3proto *h)
+{
+ if (strcmp(h->version, VERSION) != 0) {
+ fprintf(stderr, "plugin `%s': version %s (I'm %s)\n",
+ h->name, h->version, VERSION);
+ exit(1);
+ }
+ list_add(&h->head, &l3proto_list);
+}
+
int nfct_dump_expect_list(struct nfct_handle *cth, int family)
{
int err;
@@ -1026,11 +1124,12 @@ int nfct_get_expectation(struct nfct_handle *cth, struct nfct_tuple *tuple,
int err;
struct nfnlhdr *req;
char buf[NFCT_BUFSIZE];
+ u_int8_t l3num = tuple->l3protonum;
memset(&buf, 0, sizeof(buf));
req = (void *) &buf;
- nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_EXP_GET,
+ nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, l3num, 0, IPCTNL_MSG_EXP_GET,
NLM_F_REQUEST|NLM_F_ACK);
cth->handler = nfct_expect_netlink_handler;
@@ -1080,10 +1179,11 @@ int nfct_create_expectation(struct nfct_handle *cth, struct nfct_expect *exp)
struct nfnlhdr *req;
char buf[NFCT_BUFSIZE];
req = (void *) &buf;
+ u_int8_t l3num = exp->tuple.l3protonum;
memset(&buf, 0, sizeof(buf));
- nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET, 0, IPCTNL_MSG_EXP_NEW,
+ nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, l3num, 0, IPCTNL_MSG_EXP_NEW,
NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK);
nfct_build_tuple(req, sizeof(buf), &exp->master, CTA_EXPECT_MASTER);
@@ -1106,11 +1206,12 @@ int nfct_delete_expectation(struct nfct_handle *cth,struct nfct_tuple *tuple,
int err;
struct nfnlhdr *req;
char buf[NFCT_BUFSIZE];
+ u_int8_t l3num = tuple->l3protonum;
memset(&buf, 0, sizeof(buf));
req = (void *) &buf;
- nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, AF_INET,
+ nfnl_fill_hdr(&cth->nfnlh, &req->nlh, 0, l3num,
0, IPCTNL_MSG_EXP_DELETE,
NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK);