From 8aa719eb1afb6c6e0a5bf74cbdab79dc82da6c80 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=pablo/emailAddress=pablo@netfilter.org" Date: Mon, 26 Dec 2005 02:29:02 +0000 Subject: o add IPv6 support o clean up layer-4 compare functions o finish the comparison infrastructure: support for tuple/mark matching o fix bug in the default event display when used in conjunction with the comparison infrastructure. o Bumped version to 0.0.30 Thanks to Yasuyuki Kozakai for: [LIBNETFILTER_CONNTRACK] fix dumping IPv6 connections that in included in this commit. --- Makefile.am | 2 +- configure.in | 39 ++++- extensions/libnetfilter_conntrack_icmp.c | 10 +- extensions/libnetfilter_conntrack_sctp.c | 12 +- extensions/libnetfilter_conntrack_tcp.c | 14 +- extensions/libnetfilter_conntrack_udp.c | 12 +- include/libnetfilter_conntrack/Makefile.am | 2 +- .../libnetfilter_conntrack.h | 8 +- .../libnetfilter_conntrack_ipv4.h | 29 ++++ .../libnetfilter_conntrack_ipv6.h | 29 ++++ .../libnetfilter_conntrack_l3extensions.h | 29 ++++ l3extensions/Makefile.am | 16 ++ l3extensions/libnetfilter_conntrack_ipv4.c | 94 +++++++++++ l3extensions/libnetfilter_conntrack_ipv6.c | 115 ++++++++++++++ src/libnetfilter_conntrack.c | 173 ++++++++++++++++----- 15 files changed, 512 insertions(+), 72 deletions(-) create mode 100644 include/libnetfilter_conntrack/libnetfilter_conntrack_ipv4.h create mode 100644 include/libnetfilter_conntrack/libnetfilter_conntrack_ipv6.h create mode 100644 include/libnetfilter_conntrack/libnetfilter_conntrack_l3extensions.h create mode 100644 l3extensions/Makefile.am create mode 100644 l3extensions/libnetfilter_conntrack_ipv4.c create mode 100644 l3extensions/libnetfilter_conntrack_ipv6.c 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 +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#include +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 + * + * 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 + * + * 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 + * + * 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 + * + * 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 +#include +#include /* For htons */ +#include +#include +#include +#include + +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 + * + * 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 +#include +#include +#include +#include /* For htons */ +#include +#include +#include +#include +#include + +#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 #include +#include #include #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); -- cgit v1.2.3