From 8021789a9c6f98a42e30b70a782842a1dcc45efc Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Sat, 30 Jul 2005 21:10:38 +0000 Subject: restructuring libctnetlink -> libnfnetlink_conntrack --- Makefile.am | 11 + configure.in | 67 +++ .../libnfnetlink_conntrack.h | 122 ++++++ src/Makefile.am | 12 + src/libnfnetlink_conntrack.c | 470 +++++++++++++++++++++ utils/Makefile.am | 8 + utils/ctnl_test.c | 188 +++++++++ 7 files changed, 878 insertions(+) create mode 100644 Makefile.am create mode 100644 configure.in create mode 100644 include/libnfnetlink_conntrack/libnfnetlink_conntrack.h create mode 100644 src/Makefile.am create mode 100644 src/libnfnetlink_conntrack.c create mode 100644 utils/Makefile.am create mode 100644 utils/ctnl_test.c diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..04bb1f6 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,11 @@ +AUTOMAKE_OPTIONS = foreign + +INCLUDES =$(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} +SUBDIRS = include src utils +LINKOPTS = -lnfnetlink + +man_MANS = #nfnetlink_conntrack.3 nfnetlink_conntrack.7 + +$(OBJECTS): libtool +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..1516c80 --- /dev/null +++ b/configure.in @@ -0,0 +1,67 @@ +dnl Process this file with autoconf to create configure. + +AC_INIT + +AC_CANONICAL_SYSTEM + +AM_INIT_AUTOMAKE(libnfnetlink_conntrack, 0.10) + +AC_PROG_CC +AM_PROG_LIBTOOL +AC_PROG_INSTALL +AC_PROG_LN_S + +AC_SUBST(LIBTOOL_DEPS) + +case $target in +*-*-linux*) ;; +*) AC_MSG_ERROR([Linux only, dude!]);; +esac + +AC_CHECK_LIB([nfnetlink], [nfnl_listen]) + + + +dnl-------------------------------- + +AC_DEFUN([NF_KERNEL_SOURCE],[ + + if test "$with_kernel" = ""; then + KERNEL="`uname -r`" + else + KERNEL="$with_kernel" + fi + + THIS_PREFIX="" + for i in "/lib/modules/$KERNEL/build/include" "$KERNEL" "$KERNEL/include" "/usr/src/linux-$KERNEL" "/usr/src/kernel-$KERNEL" "/usr/src/linux-headers-$KERNEL" "/usr/src/kernel-headers-$KERNEL" + do + AC_MSG_CHECKING([Looking for kernel source or headers in $i]) + if test -r "$i/linux/config.h" + then + THIS_PREFIX="$i" + AC_MSG_RESULT([found]) + break + fi + AC_MSG_RESULT([ ]) + done + if test -r "$THIS_PREFIX/linux/config.h" ; then + AC_SUBST(KERNELDIR,[$THIS_PREFIX]) + AC_MSG_RESULT([found]) + else + AC_MSG_ERROR([not found $THIS_PREFIX]) + fi + + # somehow add this as an include path +]) + +AC_ARG_WITH(kernel, + AC_HELP_STRING([--with-kernel=DIR], + [ Show location of kernel source. Default is to use uname -r and look in /lib/modules/KERNEL/build/include. ]), + NF_KERNEL_SOURCE($with_kernel),NF_KERNEL_SOURCE()) + +dnl-------------------------------- + + +dnl Output the makefile +AC_OUTPUT(Makefile src/Makefile include/Makefile include/libnfnetlink_conntrack/Makefile utils/Makefile) + diff --git a/include/libnfnetlink_conntrack/libnfnetlink_conntrack.h b/include/libnfnetlink_conntrack/libnfnetlink_conntrack.h new file mode 100644 index 0000000..7f66510 --- /dev/null +++ b/include/libnfnetlink_conntrack/libnfnetlink_conntrack.h @@ -0,0 +1,122 @@ +/* libctnetlink.h: Header file for the Connection Tracking library. + * + * Jay Schulist , Copyright (c) 2001. + * (C) 2002 by Harald Welte + * (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 __LIBCTNETLINK_H +#define __LIBCTNETLINK_H + +#include +#include +#include +#include +#include +#include "libnfnetlink.h" + +#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); +}; + +struct ctnl_handle { + struct nfnl_handle nfnlh; + struct ctnl_msg_handler *handler[IPCTNL_MSG_MAX]; +}; + +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 *, int); +extern int ctnl_event_expect(struct ctnl_handle *, int); +extern int ctnl_flush_expect(struct ctnl_handle *); + +extern int ctnl_send(struct ctnl_handle *, struct nlmsghdr *); +extern int ctnl_wilddump_request(struct ctnl_handle *, int , int); + +#endif /* __LIBCTNETLINK_H */ diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..599e4ba --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,12 @@ +#AUTOMAKE_OPTIONS = no-dependencies foreign + +#EXTRA_DIST = $(man_MANS) acinclude.m4 + +INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} +AM_CFLAGS=-fPIC -Wall +LIBS= + +lib_LTLIBRARIES = libnfnetlink_conntrack.la + +libnfnetlink_conntrack_la_LDFLAGS = -Wc,-nostartfiles +libnfnetlink_conntrack_la_SOURCES = libnfnetlink_conntrack.c diff --git a/src/libnfnetlink_conntrack.c b/src/libnfnetlink_conntrack.c new file mode 100644 index 0000000..1039e25 --- /dev/null +++ b/src/libnfnetlink_conntrack.c @@ -0,0 +1,470 @@ +/* libctnetlink.c: generic library for access to connection tracking. + * + * (C) 2001 by Jay Schulist + * (C) 2002-2005 by Harald Welte + * (C) 2005 by Pablo Neira Ayuso + * + * Development of this code funded by Astaro AG (http://www.astaro.com) + * + * this software may be used and distributed according to the terms + * of the gnu general public license, incorporated herein by reference. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libctnetlink.h" + +#define ctnl_error printf + +/*********************************************************************** + * low level stuff + ***********************************************************************/ +int ctnl_send(struct ctnl_handle *cth, struct nlmsghdr *n) +{ + return nfnl_send(&cth->nfnlh, n); +} + +int ctnl_wilddump_request(struct ctnl_handle *cth, int family, int type) +{ + struct { + struct nlmsghdr nlh; + struct nfgenmsg g; + } req; + + 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); +} + +/* handler used for nfnl_listen */ +static int list_conntrack_handler(struct sockaddr_nl *nladdr, + struct nlmsghdr *n, void *arg) +{ + struct ctnl_handle *cth = (struct ctnl_handle *) arg; + int type = NFNL_MSG_TYPE(n->nlmsg_type); + struct ctnl_msg_handler *hdlr = cth->handler[type]; + int ret; + + if (NFNL_SUBSYS_ID(n->nlmsg_type) != NFNL_SUBSYS_CTNETLINK) { + ctnl_error("received message for wrong subsys, skipping\n"); + nfnl_dump_packet(n, n->nlmsg_len, "list_conntrack_handler"); + return 0; + } + + if (!hdlr) { + ctnl_error("no handler for type %d\n", type); + return 0; + } + + if (!hdlr->handler) { + ctnl_error("no handler function for type %d\n", type); + return 0; + } + + ret = hdlr->handler(nladdr, n, arg); + + return ret; +} + +/*********************************************************************** + * high level stuff + ***********************************************************************/ + +/** + * ctnl_open - open a libctnetlink handle + * + * cth: pointer to already allocated library handle + * subscriptions: netlink groups we are interested in + */ +int ctnl_open(struct ctnl_handle *cth, unsigned subscriptions) +{ + int err; + + memset(cth, 0, sizeof(*cth)); + + err = nfnl_open(&cth->nfnlh, NFNL_SUBSYS_CTNETLINK, subscriptions); + if (err < 0) { + return err; + } + + return 0; +} + +/** + * ctnl_close - close a libctnetlink handle + * + * cth: libctnetlink handle + */ +int ctnl_close(struct ctnl_handle *cth) +{ + int err; + + err = nfnl_close(&cth->nfnlh); + + return err; +} + +/* ctnl_register_handler - register handler for ctnetlink mesage type + * + * cth: libctnetlink handle + * hndlr: handler structure + */ +int ctnl_register_handler(struct ctnl_handle *cth, + struct ctnl_msg_handler *hndlr) +{ + if (hndlr->type >= IPCTNL_MSG_MAX) + return -EINVAL; + + cth->handler[hndlr->type] = hndlr; + + return 0; +} + +/** + * ctnl_unregister_handler - unregister handler for ctnetlink msgtype + * + * cth: libctnetlink handle + * type: message type + */ +int ctnl_unregister_handler(struct ctnl_handle *cth, int type) +{ + if (type >= IPCTNL_MSG_MAX) + return -EINVAL; + + cth->handler[type] = NULL; + return 0; +} + +int ctnl_flush_conntrack(struct ctnl_handle *cth) +{ + struct { + struct nlmsghdr nlh; + struct nfgenmsg g; + } *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_CT_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); +} + +/** + * ctnl_list_conntrack - list connection tracking table + * cth: libctnetlink handle + * family: AF_INET, ... + */ +int ctnl_list_conntrack(struct ctnl_handle *cth, int family) +{ + 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) + return -1; + + return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth); +} + +int ctnl_event_conntrack(struct ctnl_handle *cth, int family) +{ + return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth); +} + +struct nfnlhdr { + struct nlmsghdr nlh; + struct nfgenmsg nfmsg; +}; + +static void ctnl_build_tuple_ip(struct nfnlhdr *req, int size, + struct ctnl_tuple *t) +{ + struct nfattr *nest; + + 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)); + + nfnl_nest_end(&req->nlh, nest); +} + +static void ctnl_build_tuple_proto(struct nfnlhdr *req, int size, + struct ctnl_tuple *t) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_TUPLE_PROTO); + + 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); +} + +static void ctnl_build_tuple(struct nfnlhdr *req, int size, + struct ctnl_tuple *t, int dir) +{ + enum ctattr_type type = dir ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG; + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, type); + + ctnl_build_tuple_ip(req, size, t); + ctnl_build_tuple_proto(req, size, t); + + nfnl_nest_end(&req->nlh, nest); +} + +static void ctnl_build_protoinfo(struct nfnlhdr *req, int size, + struct ctnl_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_PROTOINFO); + + 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; + } + + nfnl_nest_end(&req->nlh, nest); +} + +static void ctnl_build_protonat(struct nfnlhdr *req, int size, + struct ctnl_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT_PROTO); + + 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); +} + +static void ctnl_build_nat(struct nfnlhdr *req, int size, + struct ctnl_conntrack *ct) +{ + struct nfattr *nest; + + nest = nfnl_nest(&req->nlh, size, CTA_NAT); + + 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 (ct->nat.l4min.all != ct->nat.l4max.all) + ctnl_build_protonat(req, size, ct); + + nfnl_nest_end(&req->nlh, nest); +} + +static void ctnl_build_conntrack(struct nfnlhdr *req, int size, + struct ctnl_conntrack *ct) +{ + 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)); + + ctnl_build_protoinfo(req, size, ct); + if (ct->nat.min_ip != 0) + ctnl_build_nat(req, size, ct); +} + +/** + * 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 ctnl_tuple *tuple, + int dir) +{ + 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, 0, IPCTNL_MSG_CT_GET, + NLM_F_REQUEST|NLM_F_ACK); + + ctnl_build_tuple(req, sizeof(buf), tuple, dir); + + if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0) + return -1; + + return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth); +} + +/** + * 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 ctnl_tuple *tuple, + int dir) +{ + 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, 0, IPCTNL_MSG_CT_DELETE, + NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST|NLM_F_ACK); + + ctnl_build_tuple(req, sizeof(buf), tuple, dir); + + if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0) + return -1; + + return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth); +} +static int new_update_conntrack(struct ctnl_handle *cth, + struct ctnl_conntrack *ct, + u_int16_t msg_flags) +{ + 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, 0, IPCTNL_MSG_CT_NEW, + NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK|msg_flags); + + ctnl_build_conntrack(req, sizeof(buf), ct); + + if (nfnl_send(&cth->nfnlh, (struct nlmsghdr *)&buf) < 0 ) + return -1; + + return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth); +} + +/** + * 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) +{ + return new_update_conntrack(cth, ct, NLM_F_EXCL); +} + +int ctnl_upd_conntrack(struct ctnl_handle *cth, struct ctnl_conntrack *ct) +{ + return new_update_conntrack(cth, ct, 0); +} + +/** + * 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) +{ + if (ctnl_wilddump_request(cth, family, IPCTNL_MSG_EXP_GET) < 0) + return -1; + + return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth); + +} + +int ctnl_event_expect(struct ctnl_handle *cth, int family) +{ + return nfnl_listen(&cth->nfnlh, &list_conntrack_handler, cth); +} + +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); +} diff --git a/utils/Makefile.am b/utils/Makefile.am new file mode 100644 index 0000000..f78bdbe --- /dev/null +++ b/utils/Makefile.am @@ -0,0 +1,8 @@ +bin_PROGRAMS = ctnl_test +ctnl_test_SOURCES = ctnl_test.c + + +INCLUDES = $(all_includes) -I$(top_srcdir)/include -I${KERNELDIR} + +ctnl_test_LDFLAGS = $(all_libraries) -lnfnetlink_conntrack -lnfnetlink + diff --git a/utils/ctnl_test.c b/utils/ctnl_test.c new file mode 100644 index 0000000..bd3173f --- /dev/null +++ b/utils/ctnl_test.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include + + #include + #include + #include + + +#include +#include +#include + +#include "libctnetlink.h" + +static struct ctnl_handle *cth; + +char *display_tuple_flat(struct ip_conntrack_tuple *tuple) +{ + static char buff[250]; + char psb[20]; + int len = 0; + + memset(buff, '\0', sizeof(buff)); + len += sprintf(buff + len, "%s:", inet_ntoa((struct in_addr){tuple->src.ip})); + switch(tuple->dst.protonum) { + case (IPPROTO_ICMP): + len += sprintf(buff + len, "Icmp (id %d)", + ntohs(tuple->src.u.icmp.id)); + break; + case (IPPROTO_TCP): + sprintf(psb, "%d", ntohs(tuple->src.u.tcp.port)); + len += sprintf(buff + len, "%s", psb); + break; + case (IPPROTO_UDP): + sprintf(psb, "%d", ntohs(tuple->src.u.udp.port)); + len += sprintf(buff + len, "%s", psb); + break; + default: + len += sprintf(buff + len, "Unknown"); + break; + } + + len += sprintf(buff + len, "->"); + len += sprintf(buff + len, "%s:", inet_ntoa((struct in_addr){tuple->dst.ip})); + switch(tuple->dst.protonum) { + case (IPPROTO_ICMP): + len += sprintf(buff + len, "Icmp (%d, code %d)", + tuple->dst.u.icmp.type, + tuple->dst.u.icmp.code); + break; + case (IPPROTO_TCP): + sprintf(psb, "%d", ntohs(tuple->dst.u.tcp.port)); + len += sprintf(buff + len, "%s", psb); + break; + case (IPPROTO_UDP): + sprintf(psb, "%d", ntohs(tuple->dst.u.udp.port)); + len += sprintf(buff + len, "%s", psb); + break; + default: + len += sprintf(buff + len, "Unknown"); + break; + } + + return (buff); +} + +int ctnl_parse_attr(struct nfattr *tb[], int max, struct nfattr *cta, int len) +{ + while(NFA_OK(cta, len)) { + if(cta->nfa_type <= max) + tb[cta->nfa_type] = cta; + cta = NFA_NEXT(cta,len); + } + if (len) + printf("ctnl_parse_attr: deficit (%d) len (%d).\n", + len, cta->nfa_len); + return 0; +} + +#if 0 +int dump() +{ + struct { + struct nlmsghdr nlh; + struct nfgenmsg nfmsg; + } req; + struct sockaddr_nl nladdr; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8)|CTNL_MSG_CT_GET; + req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_DUMP|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = 1; + req.nfmsg.nfgen_family = AF_INET; + + return (sendto(ctnlfd, &req, sizeof(req), 0, + (struct sockaddr *) &nladdr, sizeof(nladdr))); + +} +#endif + +int print_msg(struct nfgenmsg *cm, size_t len) +{ + struct nfattr *cb[CTA_MAX + 1]; + + printf("ctm_family=0x%x\n", cm->nfgen_family); + + ctnl_parse_attr(cb, CTA_MAX, NFM_NFA(cm), len); + + if (cb[CTA_ORIG]) { + printf("orig: %s\n", + display_tuple_flat(NFA_DATA(cb[CTA_ORIG]))); + ctnl_del_conntrack(cth, NFA_DATA(cb[CTA_ORIG]), CTA_ORIG); + } + if (cb[CTA_RPLY]) + printf("rply: %s\n", + display_tuple_flat(NFA_DATA(cb[CTA_RPLY]))); + + + return 0; +} + +struct nlmsghdr *ctnl_get_packet(struct nlmsghdr **last_nlhdr, + char *buf, size_t len) +{ + struct nlmsghdr *nlh; + size_t remain_len; + + if ((char *)(*last_nlhdr) > (buf + len) || + (char *)(*last_nlhdr) < buf) + *last_nlhdr = NULL; + + if (!*last_nlhdr) { + nlh = (struct nlmsghdr *) buf; + if (!NLMSG_OK(nlh, len)) { + printf("error parsing nlmsg\n"); + return NULL; + } + } else { + /* we are n-th part of multipart mesasge */ + if ((*last_nlhdr)->nlmsg_type == NLMSG_DONE || + !((*last_nlhdr)->nlmsg_flags & NLM_F_MULTI)) { + *last_nlhdr = NULL; + return NULL; + } + + remain_len = (len - ((char *)(*last_nlhdr) - buf)); + nlh = NLMSG_NEXT(*last_nlhdr, remain_len); + } + + *last_nlhdr = nlh; + return nlh; +} + +int main(int argc, char **argv) +{ + char buf[20480]; + struct nfgenmsg *last_cm = NULL, *cm; + struct nlmsghdr *nlh; + int len; + + cth = malloc(sizeof(*cth)); + if (ctnl_open(cth, 0) < 0) { + exit(2); + } + + ctnl_wilddump_request(cth, AF_INET, IPCTNL_MSG_CT_GET); + + while (len = recv(cth->nfnlh.fd, &buf, sizeof(buf), 0)) { + printf("pkt received\n"); + while (nlh = ctnl_get_packet(&last_cm, (char *)&buf, len)) { + printf(" decoding msg type 0x%04x\n", nlh->nlmsg_type); + if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == + NFNL_SUBSYS_CTNETLINK) { + cm = NLMSG_DATA(nlh); + print_msg(cm, nlh->nlmsg_len); + } + } + } + + return 0; +} + -- cgit v1.2.3