summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac17
-rw-r--r--conntrack.842
-rw-r--r--conntrackd.conf.54
-rw-r--r--extensions/libct_proto_dccp.c33
-rw-r--r--extensions/libct_proto_gre.c33
-rw-r--r--extensions/libct_proto_icmp.c33
-rw-r--r--extensions/libct_proto_icmpv6.c33
-rw-r--r--extensions/libct_proto_sctp.c33
-rw-r--r--extensions/libct_proto_tcp.c33
-rw-r--r--extensions/libct_proto_udp.c33
-rw-r--r--extensions/libct_proto_udplite.c33
-rw-r--r--extensions/libct_proto_unknown.c11
-rw-r--r--include/Makefile.am2
-rw-r--r--include/conntrack.h68
-rw-r--r--include/helper.h1
-rw-r--r--include/helpers/Makefile.am1
-rw-r--r--include/helpers/ftp.h14
-rw-r--r--include/helpers/rpc.h15
-rw-r--r--include/helpers/sane.h13
-rw-r--r--include/helpers/tns.h9
-rw-r--r--include/local.h4
-rw-r--r--nfct.82
-rw-r--r--src/Makefile.am83
-rw-r--r--src/build.c15
-rw-r--r--src/cache-ct.c11
-rw-r--r--src/cache.c4
-rw-r--r--src/conntrack.c667
-rw-r--r--src/filter.c2
-rw-r--r--src/hash.c1
-rw-r--r--src/helpers.c3
-rw-r--r--src/helpers/Makefile.am2
-rw-r--r--src/helpers/ftp.c32
-rw-r--r--src/helpers/rpc.c13
-rw-r--r--src/helpers/sane.c10
-rw-r--r--src/helpers/ssdp.c9
-rw-r--r--src/helpers/tns.c7
-rw-r--r--src/main.c7
-rw-r--r--src/network.c2
-rw-r--r--src/nfct-extensions/helper.c184
-rw-r--r--src/process.c2
-rw-r--r--src/queue.c4
-rw-r--r--src/read_config_lex.l3
-rw-r--r--src/read_config_yy.y290
-rw-r--r--src/run.c2
-rw-r--r--src/vector.c7
-rw-r--r--tests/conntrack/load-stress.sh62
-rw-r--r--tests/conntrack/testsuite/00create37
-rw-r--r--tests/conntrack/testsuite/08stdin47
-rw-r--r--tests/conntrack/testsuite/09dumpopt26
-rw-r--r--tests/conntrack/testsuite/10add42
50 files changed, 1311 insertions, 730 deletions
diff --git a/configure.ac b/configure.ac
index 3a3af45..da852b1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,10 @@
-AC_INIT([conntrack-tools],[1.4.6],[pablo@netfilter.org])
+AC_INIT([conntrack-tools],[1.4.8],[pablo@netfilter.org])
AC_CONFIG_AUX_DIR([build-aux])
AC_CANONICAL_HOST
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects
- tar-pax no-dist-gzip dist-bzip2 1.6])
+ tar-pax no-dist-gzip dist-xz 1.6])
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -17,7 +17,7 @@ AM_PROG_AR
LT_INIT([disable-static])
AC_PROG_INSTALL
AC_PROG_LN_S
-AM_PROG_LEX
+AC_PROG_LEX([noyywrap])
AC_PROG_YACC
case "$host" in
@@ -26,13 +26,13 @@ case "$host" in
esac
dnl Dependencies
-if test -z "$ac_cv_prog_YACC"
+if test -z "$ac_cv_prog_YACC" -a ! -f "${srcdir}/src/read_config_yy.c"
then
echo "*** Error: No suitable bison/yacc found. ***"
echo " Please install the 'bison' package."
exit 1
fi
-if test -z "$ac_cv_prog_LEX"
+if test -z "$ac_cv_prog_LEX" -a ! -f "${srcdir}/src/read_config_lex.c"
then
echo "*** Error: No suitable flex/lex found. ***"
echo " Please install the 'flex' package."
@@ -53,7 +53,7 @@ AC_CHECK_HEADER([rpc/rpc_msg.h], [AC_SUBST([LIBTIRPC_CFLAGS],'')], [PKG_CHECK_MO
PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 1.0.1])
PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.3])
-PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 1.0.8])
+PKG_CHECK_MODULES([LIBNETFILTER_CONNTRACK], [libnetfilter_conntrack >= 1.0.9])
AS_IF([test "x$enable_cttimeout" = "xyes"], [
PKG_CHECK_MODULES([LIBNETFILTER_CTTIMEOUT], [libnetfilter_cttimeout >= 1.0.0])
])
@@ -77,15 +77,12 @@ AC_CHECK_HEADERS([linux/capability.h],, [AC_MSG_ERROR([Cannot find linux/capabib
AC_CHECK_HEADERS(arpa/inet.h)
AC_CHECK_FUNCS(inet_pton)
-# Let nfct use dlopen() on helper libraries without resolving all symbols.
-AX_CHECK_LINK_FLAG([-Wl,-z,lazy], [AC_SUBST([LAZY_LDFLAGS], [-Wl,-z,lazy])])
-
if test ! -z "$libdir"; then
MODULE_DIR="\\\"$libdir/conntrack-tools/\\\""
CFLAGS="$CFLAGS -DCONNTRACKD_LIB_DIR=$MODULE_DIR"
fi
-AC_CONFIG_FILES([Makefile src/Makefile include/Makefile include/linux/Makefile include/linux/netfilter/Makefile extensions/Makefile src/helpers/Makefile])
+AC_CONFIG_FILES([Makefile src/Makefile include/Makefile include/helpers/Makefile include/linux/Makefile include/linux/netfilter/Makefile extensions/Makefile src/helpers/Makefile])
AC_OUTPUT
echo "
diff --git a/conntrack.8 b/conntrack.8
index a14cca6..3b6a15b 100644
--- a/conntrack.8
+++ b/conntrack.8
@@ -14,6 +14,8 @@ conntrack \- command line interface for netfilter connection tracking
.br
.BR "conntrack -I [table] parameters"
.br
+.BR "conntrack -A [table] parameters"
+.br
.BR "conntrack -U [table] parameters"
.br
.BR "conntrack -E [table] [options]"
@@ -26,7 +28,7 @@ conntrack \- command line interface for netfilter connection tracking
.br
.BR "conntrack -R file"
.SH DESCRIPTION
-The \fBconntrack\fP utilty provides a full featured userspace interface to the
+The \fBconntrack\fP utility provides a full\-featured userspace interface to the
Netfilter connection tracking system that is intended to replace the old
/proc/net/ip_conntrack interface. This tool can be used to search, list,
inspect and maintain the connection tracking subsystem of the Linux kernel.
@@ -88,7 +90,10 @@ Search for and show a particular (matching) entry in the given table.
Delete an entry from the given table.
.TP
.BI "-I, --create "
-Create a new entry from the given table.
+Create a new entry from the given table, it fails if it already exists.
+.TP
+.BI "-A, --add "
+Add a new entry from the given table.
.TP
.BI "-U, --update "
Update an entry from the given table.
@@ -114,19 +119,19 @@ Load entries from a given file. To read from stdin, "\-" should be specified.
Atomically zero counters after reading them. This option is only valid in
combination with the "\-L, \-\-dump" command options.
.TP
-.BI "-o, --output [extended,xml,save,timestamp,id,ktimestamp,labels,userspace] "
+.BI "-o, --output [extended,xml,save,timestamp,id,ktimestamp,labels] "
Display output in a certain format. With the extended output option, this tool
displays the layer 3 information. With ktimestamp, it displays the in-kernel
timestamp available since 2.6.38 (you can enable it via the \fBsysctl(8)\fP
key \fBnet.netfilter.nf_conntrack_timestamp\fP).
The labels output option tells \fBconntrack\fP to show the names of connection
tracking labels that might be present.
-The userspace output options tells if the event has been triggered by a process.
+The userspace output option tells if the event has been triggered by a process.
.TP
.BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]"
Set the bitmask of events that are to be generated by the in-kernel ctnetlink
event code. Using this parameter, you can reduce the event messages generated
-by the kernel to those types to those that you are actually interested in.
+by the kernel to the types that you are actually interested in.
.
This option can only be used in conjunction with "\-E, \-\-event".
.TP
@@ -135,7 +140,7 @@ Set the Netlink socket buffer size in bytes. This option is useful if the
command line tool reports ENOBUFS errors. If you do not pass this option, the
default value available at \fBsysctl(8)\fP key \fBnet.core.rmem_default\fP is
used. The tool reports this problem if your process is too slow to handle all
-the event messages or, in other words, if the amount of events are big enough
+the event messages or, in other words, if the amount of events is big enough
to overrun the socket buffer. Note that using a big buffer reduces the chances
to hit ENOBUFS, however, this results in more memory consumption.
.
@@ -163,7 +168,7 @@ one specified as argument.
Specify layer four (TCP, UDP, ...) protocol.
.TP
.BI "-f, --family " "PROTO"
-Specify layer three (ipv4, ipv6) protocol
+Specify layer three (ipv4, ipv6) protocol.
This option is only required in conjunction with "\-L, \-\-dump". If this
option is not passed, the default layer 3 protocol will be IPv4.
.TP
@@ -175,20 +180,23 @@ Specify the conntrack mark. Optionally, a mask value can be specified.
In "\-\-update" mode, this mask specifies the bits that should be zeroed before
XORing the MARK value into the ctmark.
Otherwise, the mask is logically ANDed with the existing mark before the
-comparision. In "\-\-create" mode, the mask is ignored.
+comparison. In "\-\-create" mode, the mask is ignored.
.TP
.BI "-l, --label " "LABEL"
Specify a conntrack label.
This option is only available in conjunction with "\-L, \-\-dump",
"\-E, \-\-event", "\-U \-\-update" or "\-D \-\-delete".
-Match entries whose labels match at least those specified.
-Use multiple \-l commands to specify multiple labels that need to be set.
-Match entries whose labels matches at least those specified as arguments.
+Match entries whose labels include those specified as arguments.
+Use multiple \-l options to specify multiple labels that need to be set.
.TP
.BI "--label-add " "LABEL"
-Specify the conntrack label to add to to the selected conntracks.
-This option is only available in conjunction with "\-I, \-\-create" or
-"\-U, \-\-update".
+Specify the conntrack label to add to the selected conntracks.
+This option is only available in conjunction with "\-I, \-\-create",
+"\-A, \-\-add" or "\-U, \-\-update".
+As a rule of thumb, you must use either the 'connlabel' match in your iptables
+ruleset or the 'ct label' statement in your nftables ruleset, this turns on the
+ct label support in the kernel and it allows you to update labels via
+"\-U, \-\-update", otherwise label updates are ignored.
.TP
.BI "--label-del " "[LABEL]"
Specify the conntrack label to delete from the selected conntracks.
@@ -395,7 +403,7 @@ Show source NAT connections
Show connection events together with the timestamp
.TP
.B conntrack \-D \-s 1.2.3.4
-Delete all flow whose source address is 1.2.3.4
+Delete all flows whose source address is 1.2.3.4
.TP
.B conntrack \-U \-s 1.2.3.4 \-m 1
Set connmark to 1 of all the flows whose source address is 1.2.3.4
@@ -417,8 +425,8 @@ See
Jay Schulist, Patrick McHardy, Harald Welte and Pablo Neira Ayuso wrote the
kernel-level "ctnetlink" interface that is used by the conntrack tool.
.PP
-Pablo Neira Ayuso wrote and maintain the conntrack tool, Harald Welte added
-support for conntrack based accounting counters.
+Pablo Neira Ayuso wrote and maintains the conntrack tool, Harald Welte added
+support for conntrack\-based accounting counters.
.PP
Man page written by Harald Welte <laforge@netfilter.org> and
Pablo Neira Ayuso <pablo@netfilter.org>.
diff --git a/conntrackd.conf.5 b/conntrackd.conf.5
index a73c3f7..50d7b98 100644
--- a/conntrackd.conf.5
+++ b/conntrackd.conf.5
@@ -52,7 +52,7 @@ You should consider this file as case-sensitive.
Empty lines and lines starting with the '#' character are ignored.
Before starting to develop a new configuration, you may want to learn the
-concepts behind this technlogy at
+concepts behind this technology at
\fIhttp://conntrack-tools.netfilter.org/manual.html\fP.
There are complete configuration examples at the end of this man page.
@@ -630,7 +630,7 @@ filter-sets in positive or negative logic depending on your needs.
You can select if \fBconntrackd(8)\fP filters the event messages from
user-space or kernel-space. The kernel-space event filtering saves some CPU
cycles by avoiding the copy of the event message from kernel-space to
-user-space. The kernel-space event filtering is prefered, however, you require
+user-space. The kernel-space event filtering is preferred, however, you require
a \fBLinux kernel >= 2.6.29\fP to filter from kernel-space.
The syntax for this section is: \fBFilter From <from> { }\fP.
diff --git a/extensions/libct_proto_dccp.c b/extensions/libct_proto_dccp.c
index e9da474..0204929 100644
--- a/extensions/libct_proto_dccp.c
+++ b/extensions/libct_proto_dccp.c
@@ -67,22 +67,23 @@ static const char *dccp_optflags[DCCP_OPT_MAX] = {
static char dccp_commands_v_options[NUMBER_OF_CMD][DCCP_OPT_MAX] =
/* Well, it's better than "Re: Sevilla vs Betis" */
{
- /* 1 2 3 4 5 6 7 8 9 10*/
-/*CT_LIST*/ {2,2,2,2,0,0,2,0,0,0},
-/*CT_CREATE*/ {3,3,3,3,0,0,1,0,0,1},
-/*CT_UPDATE*/ {2,2,2,2,0,0,2,0,0,0},
-/*CT_DELETE*/ {2,2,2,2,0,0,2,0,0,0},
-/*CT_GET*/ {3,3,3,3,0,0,2,0,0,0},
-/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0},
-/*CT_EVENT*/ {2,2,2,2,0,0,2,0,0,0},
-/*CT_VERSION*/ {0,0,0,0,0,0,0,0,0,0},
-/*CT_HELP*/ {0,0,0,0,0,0,0,0,0,0},
-/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0},
-/*EXP_CREATE*/ {1,1,0,0,1,1,0,1,1,1},
-/*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0,0},
-/*EXP_GET*/ {1,1,1,1,0,0,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0},
+ /* 1 2 3 4 5 6 7 8 9 10 */
+ [CT_LIST_BIT] = {2,2,2,2,0,0,2,0,0,0},
+ [CT_CREATE_BIT] = {3,3,3,3,0,0,1,0,0,1},
+ [CT_UPDATE_BIT] = {2,2,2,2,0,0,2,0,0,0},
+ [CT_DELETE_BIT] = {2,2,2,2,0,0,2,0,0,0},
+ [CT_GET_BIT] = {3,3,3,3,0,0,2,0,0,0},
+ [CT_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0,0},
+ [CT_EVENT_BIT] = {2,2,2,2,0,0,2,0,0,0},
+ [CT_VERSION_BIT] = {0,0,0,0,0,0,0,0,0,0},
+ [CT_HELP_BIT] = {0,0,0,0,0,0,0,0,0,0},
+ [EXP_LIST_BIT] = {0,0,0,0,0,0,0,0,0,0},
+ [EXP_CREATE_BIT] = {1,1,0,0,1,1,0,1,1,1},
+ [EXP_DELETE_BIT] = {1,1,1,1,0,0,0,0,0,0},
+ [EXP_GET_BIT] = {1,1,1,1,0,0,0,0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0,0,0,0,0,0,0,0},
+ [CT_ADD_BIT] = {3,3,3,3,0,0,1,0,0,1},
};
static const char *dccp_states[DCCP_CONNTRACK_MAX] = {
diff --git a/extensions/libct_proto_gre.c b/extensions/libct_proto_gre.c
index a36d111..2f216b9 100644
--- a/extensions/libct_proto_gre.c
+++ b/extensions/libct_proto_gre.c
@@ -66,22 +66,23 @@ static void help(void)
static char gre_commands_v_options[NUMBER_OF_CMD][GRE_OPT_MAX] =
{
- /* 1 2 3 4 5 6 7 8 */
-/*CT_LIST*/ {2,2,2,2,0,0,0,0},
-/*CT_CREATE*/ {3,3,3,3,0,0,0,0},
-/*CT_UPDATE*/ {2,2,2,2,0,0,0,0},
-/*CT_DELETE*/ {2,2,2,2,0,0,0,0},
-/*CT_GET*/ {3,3,3,3,0,0,0,0},
-/*CT_FLUSH*/ {0,0,0,0,0,0,0,0},
-/*CT_EVENT*/ {2,2,2,2,0,0,0,0},
-/*CT_VERSION*/ {0,0,0,0,0,0,0,0},
-/*CT_HELP*/ {0,0,0,0,0,0,0,0},
-/*EXP_LIST*/ {0,0,0,0,0,0,0,0},
-/*EXP_CREATE*/ {1,1,1,1,1,1,1,1},
-/*EXP_DELETE*/ {1,1,1,1,0,0,0,0},
-/*EXP_GET*/ {1,1,1,1,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0},
+ /* 1 2 3 4 5 6 7 8 */
+ [CT_LIST_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_CREATE_BIT] = {3,3,3,3,0,0,0,0},
+ [CT_UPDATE_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_DELETE_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_GET_BIT] = {3,3,3,3,0,0,0,0},
+ [CT_FLUSH_BIT] = {0,0,0,0,0,0,0,0},
+ [CT_EVENT_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_VERSION_BIT] = {0,0,0,0,0,0,0,0},
+ [CT_HELP_BIT] = {0,0,0,0,0,0,0,0},
+ [EXP_LIST_BIT] = {0,0,0,0,0,0,0,0},
+ [EXP_CREATE_BIT] = {1,1,1,1,1,1,1,1},
+ [EXP_DELETE_BIT] = {1,1,1,1,0,0,0,0},
+ [EXP_GET_BIT] = {1,1,1,1,0,0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0,0,0,0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0,0,0,0,0,0},
+ [CT_ADD_BIT] = {3,3,3,3,0,0,0,0},
};
static int parse_options(char c,
diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c
index ec52c39..9f67cf4 100644
--- a/extensions/libct_proto_icmp.c
+++ b/extensions/libct_proto_icmp.c
@@ -40,22 +40,23 @@ static const char *icmp_optflags[ICMP_NUMBER_OF_OPT] = {
static char icmp_commands_v_options[NUMBER_OF_CMD][ICMP_NUMBER_OF_OPT] =
/* Well, it's better than "Re: Maradona vs Pele" */
{
- /* 1 2 3 */
-/*CT_LIST*/ {2,2,2},
-/*CT_CREATE*/ {1,1,2},
-/*CT_UPDATE*/ {2,2,2},
-/*CT_DELETE*/ {2,2,2},
-/*CT_GET*/ {1,1,2},
-/*CT_FLUSH*/ {0,0,0},
-/*CT_EVENT*/ {2,2,2},
-/*CT_VERSION*/ {0,0,0},
-/*CT_HELP*/ {0,0,0},
-/*EXP_LIST*/ {0,0,0},
-/*EXP_CREATE*/ {0,0,0},
-/*EXP_DELETE*/ {0,0,0},
-/*EXP_GET*/ {0,0,0},
-/*EXP_FLUSH*/ {0,0,0},
-/*EXP_EVENT*/ {0,0,0},
+ /* 1 2 3 */
+ [CT_LIST_BIT] = {2,2,2},
+ [CT_CREATE_BIT] = {1,1,2},
+ [CT_UPDATE_BIT] = {2,2,2},
+ [CT_DELETE_BIT] = {2,2,2},
+ [CT_GET_BIT] = {1,1,2},
+ [CT_FLUSH_BIT] = {0,0,0},
+ [CT_EVENT_BIT] = {2,2,2},
+ [CT_VERSION_BIT] = {0,0,0},
+ [CT_HELP_BIT] = {0,0,0},
+ [EXP_LIST_BIT] = {0,0,0},
+ [EXP_CREATE_BIT] = {0,0,0},
+ [EXP_DELETE_BIT] = {0,0,0},
+ [EXP_GET_BIT] = {0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0},
+ [CT_ADD_BIT] = {1,1,2},
};
static void help(void)
diff --git a/extensions/libct_proto_icmpv6.c b/extensions/libct_proto_icmpv6.c
index fe16a1d..216757e 100644
--- a/extensions/libct_proto_icmpv6.c
+++ b/extensions/libct_proto_icmpv6.c
@@ -43,22 +43,23 @@ static const char *icmpv6_optflags[ICMPV6_NUMBER_OF_OPT] = {
static char icmpv6_commands_v_options[NUMBER_OF_CMD][ICMPV6_NUMBER_OF_OPT] =
/* Well, it's better than "Re: Maradona vs Pele" */
{
- /* 1 2 3 */
-/*CT_LIST*/ {2,2,2},
-/*CT_CREATE*/ {1,1,2},
-/*CT_UPDATE*/ {2,2,2},
-/*CT_DELETE*/ {2,2,2},
-/*CT_GET*/ {1,1,2},
-/*CT_FLUSH*/ {0,0,0},
-/*CT_EVENT*/ {2,2,2},
-/*CT_VERSION*/ {0,0,0},
-/*CT_HELP*/ {0,0,0},
-/*EXP_LIST*/ {0,0,0},
-/*EXP_CREATE*/ {0,0,0},
-/*EXP_DELETE*/ {0,0,0},
-/*EXP_GET*/ {0,0,0},
-/*EXP_FLUSH*/ {0,0,0},
-/*EXP_EVENT*/ {0,0,0},
+ /* 1 2 3 */
+ [CT_LIST_BIT] = {2,2,2},
+ [CT_CREATE_BIT] = {1,1,2},
+ [CT_UPDATE_BIT] = {2,2,2},
+ [CT_DELETE_BIT] = {2,2,2},
+ [CT_GET_BIT] = {1,1,2},
+ [CT_FLUSH_BIT] = {0,0,0},
+ [CT_EVENT_BIT] = {2,2,2},
+ [CT_VERSION_BIT] = {0,0,0},
+ [CT_HELP_BIT] = {0,0,0},
+ [EXP_LIST_BIT] = {0,0,0},
+ [EXP_CREATE_BIT] = {0,0,0},
+ [EXP_DELETE_BIT] = {0,0,0},
+ [EXP_GET_BIT] = {0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0},
+ [CT_ADD_BIT] = {1,1,2},
};
static void help(void)
diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c
index a58ccde..8099b83 100644
--- a/extensions/libct_proto_sctp.c
+++ b/extensions/libct_proto_sctp.c
@@ -70,22 +70,23 @@ static const char *sctp_optflags[SCTP_OPT_MAX] = {
static char sctp_commands_v_options[NUMBER_OF_CMD][SCTP_OPT_MAX] =
/* Well, it's better than "Re: Sevilla vs Betis" */
{
- /* 1 2 3 4 5 6 7 8 9 10 11*/
-/*CT_LIST*/ {2,2,2,2,0,0,2,0,0,0,0},
-/*CT_CREATE*/ {3,3,3,3,0,0,1,0,0,1,1},
-/*CT_UPDATE*/ {2,2,2,2,0,0,2,0,0,2,2},
-/*CT_DELETE*/ {2,2,2,2,0,0,2,0,0,0,0},
-/*CT_GET*/ {3,3,3,3,0,0,2,0,0,2,2},
-/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0},
-/*CT_EVENT*/ {2,2,2,2,0,0,2,0,0,0,0},
-/*CT_VERSION*/ {0,0,0,0,0,0,0,0,0,0,0},
-/*CT_HELP*/ {0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_CREATE*/ {1,1,0,0,1,1,0,1,1,1,1},
-/*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0,0,0},
-/*EXP_GET*/ {1,1,1,1,0,0,0,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0},
+ /* 1 2 3 4 5 6 7 8 9 10 11 */
+ [CT_LIST_BIT] = {2,2,2,2,0,0,2,0,0,0,0},
+ [CT_CREATE_BIT] = {3,3,3,3,0,0,1,0,0,1,1},
+ [CT_UPDATE_BIT] = {2,2,2,2,0,0,2,0,0,2,2},
+ [CT_DELETE_BIT] = {2,2,2,2,0,0,2,0,0,0,0},
+ [CT_GET_BIT] = {3,3,3,3,0,0,2,0,0,2,2},
+ [CT_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0,0,0},
+ [CT_EVENT_BIT] = {2,2,2,2,0,0,2,0,0,0,0},
+ [CT_VERSION_BIT] = {0,0,0,0,0,0,0,0,0,0,0},
+ [CT_HELP_BIT] = {0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_LIST_BIT] = {0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_CREATE_BIT] = {1,1,0,0,1,1,0,1,1,1,1},
+ [EXP_DELETE_BIT] = {1,1,1,1,0,0,0,0,0,0,0},
+ [EXP_GET_BIT] = {1,1,1,1,0,0,0,0,0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0,0,0,0,0,0,0,0,0},
+ [CT_ADD_BIT] = {3,3,3,3,0,0,1,0,0,1,1},
};
static const char *sctp_states[SCTP_CONNTRACK_MAX] = {
diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c
index 3da0dc6..27f5833 100644
--- a/extensions/libct_proto_tcp.c
+++ b/extensions/libct_proto_tcp.c
@@ -54,22 +54,23 @@ static const char *tcp_optflags[TCP_NUMBER_OF_OPT] = {
static char tcp_commands_v_options[NUMBER_OF_CMD][TCP_NUMBER_OF_OPT] =
/* Well, it's better than "Re: Sevilla vs Betis" */
{
- /* 1 2 3 4 5 6 7 8 9 */
-/*CT_LIST*/ {2,2,2,2,0,0,2,0,0},
-/*CT_CREATE*/ {3,3,3,3,0,0,1,0,0},
-/*CT_UPDATE*/ {2,2,2,2,0,0,2,0,0},
-/*CT_DELETE*/ {2,2,2,2,0,0,2,0,0},
-/*CT_GET*/ {3,3,3,3,0,0,2,0,0},
-/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0},
-/*CT_EVENT*/ {2,2,2,2,0,0,2,0,0},
-/*CT_VERSION*/ {0,0,0,0,0,0,0,0,0},
-/*CT_HELP*/ {0,0,0,0,0,0,0,0,0},
-/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0},
-/*EXP_CREATE*/ {1,1,0,0,1,1,0,1,1},
-/*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0},
-/*EXP_GET*/ {1,1,1,1,0,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0},
+ /* 1 2 3 4 5 6 7 8 9 */
+ [CT_LIST_BIT] = {2,2,2,2,0,0,2,0,0},
+ [CT_CREATE_BIT] = {3,3,3,3,0,0,1,0,0},
+ [CT_UPDATE_BIT] = {2,2,2,2,0,0,2,0,0},
+ [CT_DELETE_BIT] = {2,2,2,2,0,0,2,0,0},
+ [CT_GET_BIT] = {3,3,3,3,0,0,2,0,0},
+ [CT_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0},
+ [CT_EVENT_BIT] = {2,2,2,2,0,0,2,0,0},
+ [CT_VERSION_BIT] = {0,0,0,0,0,0,0,0,0},
+ [CT_HELP_BIT] = {0,0,0,0,0,0,0,0,0},
+ [EXP_LIST_BIT] = {0,0,0,0,0,0,0,0,0},
+ [EXP_CREATE_BIT] = {1,1,0,0,1,1,0,1,1},
+ [EXP_DELETE_BIT] = {1,1,1,1,0,0,0,0,0},
+ [EXP_GET_BIT] = {1,1,1,1,0,0,0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0,0,0,0,0,0,0},
+ [CT_ADD_BIT] = {3,3,3,3,0,0,1,0,0},
};
static const char *tcp_states[TCP_CONNTRACK_MAX] = {
diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c
index fe43548..a78857f 100644
--- a/extensions/libct_proto_udp.c
+++ b/extensions/libct_proto_udp.c
@@ -62,22 +62,23 @@ static void help(void)
static char udp_commands_v_options[NUMBER_OF_CMD][UDP_NUMBER_OF_OPT] =
/* Well, it's better than "Re: Galeano vs Vargas Llosa" */
{
- /* 1 2 3 4 5 6 7 8 */
-/*CT_LIST*/ {2,2,2,2,0,0,0,0},
-/*CT_CREATE*/ {3,3,3,3,0,0,0,0},
-/*CT_UPDATE*/ {2,2,2,2,0,0,0,0},
-/*CT_DELETE*/ {2,2,2,2,0,0,0,0},
-/*CT_GET*/ {3,3,3,3,0,0,0,0},
-/*CT_FLUSH*/ {0,0,0,0,0,0,0,0},
-/*CT_EVENT*/ {2,2,2,2,0,0,0,0},
-/*CT_VERSION*/ {0,0,0,0,0,0,0,0},
-/*CT_HELP*/ {0,0,0,0,0,0,0,0},
-/*EXP_LIST*/ {0,0,0,0,0,0,0,0},
-/*EXP_CREATE*/ {1,1,0,0,1,1,1,1},
-/*EXP_DELETE*/ {1,1,1,1,0,0,0,0},
-/*EXP_GET*/ {1,1,1,1,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0},
+ /* 1 2 3 4 5 6 7 8 */
+ [CT_LIST_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_CREATE_BIT] = {3,3,3,3,0,0,0,0},
+ [CT_UPDATE_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_DELETE_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_GET_BIT] = {3,3,3,3,0,0,0,0},
+ [CT_FLUSH_BIT] = {0,0,0,0,0,0,0,0},
+ [CT_EVENT_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_VERSION_BIT] = {0,0,0,0,0,0,0,0},
+ [CT_HELP_BIT] = {0,0,0,0,0,0,0,0},
+ [EXP_LIST_BIT] = {0,0,0,0,0,0,0,0},
+ [EXP_CREATE_BIT] = {1,1,0,0,1,1,1,1},
+ [EXP_DELETE_BIT] = {1,1,1,1,0,0,0,0},
+ [EXP_GET_BIT] = {1,1,1,1,0,0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0,0,0,0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0,0,0,0,0,0},
+ [CT_ADD_BIT] = {3,3,3,3,0,0,0,0},
};
static int parse_options(char c,
diff --git a/extensions/libct_proto_udplite.c b/extensions/libct_proto_udplite.c
index 2bece38..3df3142 100644
--- a/extensions/libct_proto_udplite.c
+++ b/extensions/libct_proto_udplite.c
@@ -70,22 +70,23 @@ static void help(void)
static char udplite_commands_v_options[NUMBER_OF_CMD][UDP_OPT_MAX] =
{
- /* 1 2 3 4 5 6 7 8 */
-/*CT_LIST*/ {2,2,2,2,0,0,0,0},
-/*CT_CREATE*/ {3,3,3,3,0,0,0,0},
-/*CT_UPDATE*/ {2,2,2,2,0,0,0,0},
-/*CT_DELETE*/ {2,2,2,2,0,0,0,0},
-/*CT_GET*/ {3,3,3,3,0,0,0,0},
-/*CT_FLUSH*/ {0,0,0,0,0,0,0,0},
-/*CT_EVENT*/ {2,2,2,2,0,0,0,0},
-/*CT_VERSION*/ {0,0,0,0,0,0,0,0},
-/*CT_HELP*/ {0,0,0,0,0,0,0,0},
-/*EXP_LIST*/ {0,0,0,0,0,0,0,0},
-/*EXP_CREATE*/ {1,1,0,0,1,1,1,1},
-/*EXP_DELETE*/ {1,1,1,1,0,0,0,0},
-/*EXP_GET*/ {1,1,1,1,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0},
+ /* 1 2 3 4 5 6 7 8 */
+ [CT_LIST_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_CREATE_BIT] = {3,3,3,3,0,0,0,0},
+ [CT_UPDATE_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_DELETE_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_GET_BIT] = {3,3,3,3,0,0,0,0},
+ [CT_FLUSH_BIT] = {0,0,0,0,0,0,0,0},
+ [CT_EVENT_BIT] = {2,2,2,2,0,0,0,0},
+ [CT_VERSION_BIT] = {0,0,0,0,0,0,0,0},
+ [CT_HELP_BIT] = {0,0,0,0,0,0,0,0},
+ [EXP_LIST_BIT] = {0,0,0,0,0,0,0,0},
+ [EXP_CREATE_BIT] = {1,1,0,0,1,1,1,1},
+ [EXP_DELETE_BIT] = {1,1,1,1,0,0,0,0},
+ [EXP_GET_BIT] = {1,1,1,1,0,0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0,0,0,0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0,0,0,0,0,0},
+ [CT_ADD_BIT] = {3,3,3,3,0,0,0,0},
};
static int parse_options(char c,
diff --git a/extensions/libct_proto_unknown.c b/extensions/libct_proto_unknown.c
index 2a47704..b877c56 100644
--- a/extensions/libct_proto_unknown.c
+++ b/extensions/libct_proto_unknown.c
@@ -21,10 +21,21 @@ static void help(void)
fprintf(stdout, " no options (unsupported)\n");
}
+static void final_check(unsigned int flags,
+ unsigned int cmd,
+ struct nf_conntrack *ct)
+{
+ if (nfct_attr_is_set(ct, ATTR_REPL_L3PROTO) &&
+ nfct_attr_is_set(ct, ATTR_L4PROTO) &&
+ !nfct_attr_is_set(ct, ATTR_REPL_L4PROTO))
+ nfct_set_attr_u8(ct, ATTR_REPL_L4PROTO, nfct_get_attr_u8(ct, ATTR_L4PROTO));
+}
+
struct ctproto_handler ct_proto_unknown = {
.name = "unknown",
.help = help,
.opts = opts,
+ .final_check = final_check,
.version = VERSION,
};
diff --git a/include/Makefile.am b/include/Makefile.am
index 352054e..4741b50 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = linux
+SUBDIRS = linux helpers
noinst_HEADERS = alarm.h jhash.h cache.h linux_list.h linux_rbtree.h \
sync.h conntrackd.h local.h udp.h tcp.h \
diff --git a/include/conntrack.h b/include/conntrack.h
index 1c1720e..6dad4a1 100644
--- a/include/conntrack.h
+++ b/include/conntrack.h
@@ -11,7 +11,73 @@
#include <linux/netfilter/nf_conntrack_common.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-#define NUMBER_OF_CMD 19
+enum ct_command {
+ CT_NONE = 0,
+
+ CT_LIST_BIT = 0,
+ CT_LIST = (1 << CT_LIST_BIT),
+
+ CT_CREATE_BIT = 1,
+ CT_CREATE = (1 << CT_CREATE_BIT),
+
+ CT_UPDATE_BIT = 2,
+ CT_UPDATE = (1 << CT_UPDATE_BIT),
+
+ CT_DELETE_BIT = 3,
+ CT_DELETE = (1 << CT_DELETE_BIT),
+
+ CT_GET_BIT = 4,
+ CT_GET = (1 << CT_GET_BIT),
+
+ CT_FLUSH_BIT = 5,
+ CT_FLUSH = (1 << CT_FLUSH_BIT),
+
+ CT_EVENT_BIT = 6,
+ CT_EVENT = (1 << CT_EVENT_BIT),
+
+ CT_VERSION_BIT = 7,
+ CT_VERSION = (1 << CT_VERSION_BIT),
+
+ CT_HELP_BIT = 8,
+ CT_HELP = (1 << CT_HELP_BIT),
+
+ EXP_LIST_BIT = 9,
+ EXP_LIST = (1 << EXP_LIST_BIT),
+
+ EXP_CREATE_BIT = 10,
+ EXP_CREATE = (1 << EXP_CREATE_BIT),
+
+ EXP_DELETE_BIT = 11,
+ EXP_DELETE = (1 << EXP_DELETE_BIT),
+
+ EXP_GET_BIT = 12,
+ EXP_GET = (1 << EXP_GET_BIT),
+
+ EXP_FLUSH_BIT = 13,
+ EXP_FLUSH = (1 << EXP_FLUSH_BIT),
+
+ EXP_EVENT_BIT = 14,
+ EXP_EVENT = (1 << EXP_EVENT_BIT),
+
+ CT_COUNT_BIT = 15,
+ CT_COUNT = (1 << CT_COUNT_BIT),
+
+ EXP_COUNT_BIT = 16,
+ EXP_COUNT = (1 << EXP_COUNT_BIT),
+
+ CT_STATS_BIT = 17,
+ CT_STATS = (1 << CT_STATS_BIT),
+
+ EXP_STATS_BIT = 18,
+ EXP_STATS = (1 << EXP_STATS_BIT),
+
+ CT_ADD_BIT = 19,
+ CT_ADD = (1 << CT_ADD_BIT),
+
+ _CT_BIT_MAX = 20,
+};
+
+#define NUMBER_OF_CMD _CT_BIT_MAX
#define NUMBER_OF_OPT 29
struct nf_conntrack;
diff --git a/include/helper.h b/include/helper.h
index d540667..08d4cf4 100644
--- a/include/helper.h
+++ b/include/helper.h
@@ -56,6 +56,7 @@ extern int in4_pton(const char *src, int srclen, uint8_t *dst, int delim, const
extern int in6_pton(const char *src, int srclen, uint8_t *dst, int delim, const char **end);
extern void helper_register(struct ctd_helper *helper);
+struct ctd_helper *__helper_find(const char *helper_name, uint8_t l4proto);
struct ctd_helper *helper_find(const char *libdir_path, const char *name, uint8_t l4proto, int flags);
#define min_t(type, x, y) ({ \
diff --git a/include/helpers/Makefile.am b/include/helpers/Makefile.am
new file mode 100644
index 0000000..99a4257
--- /dev/null
+++ b/include/helpers/Makefile.am
@@ -0,0 +1 @@
+noinst_HEADERS = ftp.h rpc.h sane.h tns.h
diff --git a/include/helpers/ftp.h b/include/helpers/ftp.h
new file mode 100644
index 0000000..50e2d0c
--- /dev/null
+++ b/include/helpers/ftp.h
@@ -0,0 +1,14 @@
+#ifndef _CTD_FTP_H
+#define _CTD_FTP_H
+
+#define NUM_SEQ_TO_REMEMBER 2
+
+/* This structure exists only once per master */
+struct ftp_info {
+ /* Valid seq positions for cmd matching after newline */
+ uint32_t seq_aft_nl[MYCT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
+ /* 0 means seq_match_aft_nl not set */
+ int seq_aft_nl_num[MYCT_DIR_MAX];
+};
+
+#endif
diff --git a/include/helpers/rpc.h b/include/helpers/rpc.h
new file mode 100644
index 0000000..b0b8d17
--- /dev/null
+++ b/include/helpers/rpc.h
@@ -0,0 +1,15 @@
+#ifndef _CTD_RPC_H
+#define _CTD_RPC_H
+
+struct rpc_info {
+ /* XID */
+ uint32_t xid;
+ /* program */
+ uint32_t pm_prog;
+ /* program version */
+ uint32_t pm_vers;
+ /* transport protocol: TCP|UDP */
+ uint32_t pm_prot;
+};
+
+#endif
diff --git a/include/helpers/sane.h b/include/helpers/sane.h
new file mode 100644
index 0000000..1e70ff6
--- /dev/null
+++ b/include/helpers/sane.h
@@ -0,0 +1,13 @@
+#ifndef _CTD_SANE_H
+#define _CTD_SANE_H
+
+enum sane_state {
+ SANE_STATE_NORMAL,
+ SANE_STATE_START_REQUESTED,
+};
+
+struct nf_ct_sane_master {
+ enum sane_state state;
+};
+
+#endif
diff --git a/include/helpers/tns.h b/include/helpers/tns.h
new file mode 100644
index 0000000..60dcf25
--- /dev/null
+++ b/include/helpers/tns.h
@@ -0,0 +1,9 @@
+#ifndef _CTD_TNS_H
+#define _CTD_TNS_H
+
+struct tns_info {
+ /* Scan next DATA|REDIRECT packet */
+ bool parse;
+};
+
+#endif
diff --git a/include/local.h b/include/local.h
index 9379446..22859d7 100644
--- a/include/local.h
+++ b/include/local.h
@@ -7,12 +7,12 @@
struct local_conf {
int reuseaddr;
- char path[UNIX_PATH_MAX + 1];
+ char path[UNIX_PATH_MAX];
};
struct local_server {
int fd;
- char path[UNIX_PATH_MAX + 1];
+ char path[UNIX_PATH_MAX];
};
/* callback return values */
diff --git a/nfct.8 b/nfct.8
index c38bdbe..b130a88 100644
--- a/nfct.8
+++ b/nfct.8
@@ -8,7 +8,7 @@ nfct \- command line tool to configure with the connection tracking system
.BR "nfct command subsystem [parameters]"
.SH DESCRIPTION
.B nfct
-is the command line tool that allows to configure the Connection Tracking
+is the command line tool that allows you to configure the Connection Tracking
System.
.SH COMMANDS
.TP
diff --git a/src/Makefile.am b/src/Makefile.am
index 1f23474..352aa37 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,12 +7,22 @@ endif
AM_YFLAGS = -d
BUILT_SOURCES = read_config_yy.h
-MAINTAINERCLEANFILES = read_config_yy.c read_config_yy.h read_config_lex.c
sbin_PROGRAMS = conntrack conntrackd nfct
conntrack_SOURCES = conntrack.c
-conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_dccp.la ../extensions/libct_proto_gre.la ../extensions/libct_proto_unknown.la ${LIBNETFILTER_CONNTRACK_LIBS} ${LIBMNL_LIBS} ${LIBNFNETLINK_LIBS}
+conntrack_LDADD = ../extensions/libct_proto_dccp.la \
+ ../extensions/libct_proto_gre.la \
+ ../extensions/libct_proto_icmp.la \
+ ../extensions/libct_proto_icmpv6.la \
+ ../extensions/libct_proto_sctp.la \
+ ../extensions/libct_proto_tcp.la \
+ ../extensions/libct_proto_udp.la \
+ ../extensions/libct_proto_udplite.la \
+ ../extensions/libct_proto_unknown.la \
+ ${LIBMNL_LIBS} \
+ ${LIBNETFILTER_CONNTRACK_LIBS} \
+ ${LIBNFNETLINK_LIBS}
nfct_SOURCES = nfct.c
@@ -36,24 +46,54 @@ if HAVE_CTHELPER
nfct_LDADD += ${LIBNETFILTER_CTHELPER_LIBS}
endif
-nfct_LDFLAGS = -export-dynamic ${LAZY_LDFLAGS}
-
-conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c queue_tx.c rbtree.c \
- local.c log.c mcast.c udp.c netlink.c vector.c \
- filter.c fds.c event.c process.c origin.c date.c \
- cache.c cache-ct.c cache-exp.c \
- cache_timer.c \
- ctnl.c \
- sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \
- traffic_stats.c stats-mode.c \
- network.c cidr.c \
- build.c parse.c \
- channel.c multichannel.c channel_mcast.c channel_udp.c \
- tcp.c channel_tcp.c \
- external_cache.c external_inject.c \
- internal_cache.c internal_bypass.c \
- read_config_yy.y read_config_lex.l \
- stack.c resync.c
+conntrackd_SOURCES = alarm.c \
+ build.c \
+ cache.c \
+ cache-ct.c \
+ cache-exp.c \
+ cache_timer.c \
+ channel.c \
+ channel_mcast.c \
+ channel_tcp.c \
+ channel_udp.c \
+ cidr.c \
+ ctnl.c \
+ date.c \
+ event.c \
+ external_cache.c \
+ external_inject.c \
+ fds.c \
+ filter.c \
+ hash.c \
+ internal_bypass.c \
+ internal_cache.c \
+ local.c \
+ log.c \
+ main.c \
+ mcast.c \
+ multichannel.c \
+ netlink.c \
+ network.c \
+ origin.c \
+ parse.c \
+ process.c \
+ queue.c \
+ queue_tx.c \
+ rbtree.c \
+ read_config_lex.l \
+ read_config_yy.y \
+ resync.c \
+ run.c \
+ stack.c \
+ stats-mode.c \
+ sync-alarm.c \
+ sync-ftfw.c \
+ sync-mode.c \
+ sync-notrack.c \
+ tcp.c \
+ traffic_stats.c \
+ udp.c \
+ vector.c
if HAVE_CTHELPER
conntrackd_SOURCES += cthelper.c helpers.c utils.c expect.c
@@ -63,9 +103,6 @@ if HAVE_SYSTEMD
conntrackd_SOURCES += systemd.c
endif
-# yacc and lex generate dirty code
-read_config_yy.o read_config_lex.o: AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls -Wno-sign-compare
-
conntrackd_LDADD = ${LIBMNL_LIBS} ${LIBNETFILTER_CONNTRACK_LIBS} \
${libdl_LIBS} ${LIBNFNETLINK_LIBS}
diff --git a/src/build.c b/src/build.c
index 63e47c7..c07974f 100644
--- a/src/build.c
+++ b/src/build.c
@@ -133,11 +133,12 @@ static enum nf_conntrack_attr nat_type[] =
/* ICMP, UDP and TCP are always loaded with nf_conntrack_ipv4 */
static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n)
{
+ ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
+ sizeof(struct nfct_attr_grp_port));
+
if (!nfct_attr_is_set(ct, ATTR_TCP_STATE))
return;
- ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
- sizeof(struct nfct_attr_grp_port));
ct_build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE);
if (CONFIG(sync).tcp_window_tracking) {
ct_build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG);
@@ -147,12 +148,13 @@ static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n)
static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n)
{
+ ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
+ sizeof(struct nfct_attr_grp_port));
+
/* SCTP is optional, make sure nf_conntrack_sctp is loaded */
if (!nfct_attr_is_set(ct, ATTR_SCTP_STATE))
return;
- ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
- sizeof(struct nfct_attr_grp_port));
ct_build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE);
ct_build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG);
ct_build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL);
@@ -160,12 +162,13 @@ static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n)
static void build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n)
{
+ ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
+ sizeof(struct nfct_attr_grp_port));
+
/* DCCP is optional, make sure nf_conntrack_dccp is loaded */
if (!nfct_attr_is_set(ct, ATTR_DCCP_STATE))
return;
- ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
- sizeof(struct nfct_attr_grp_port));
ct_build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE);
ct_build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE);
}
diff --git a/src/cache-ct.c b/src/cache-ct.c
index fe01e16..f56e450 100644
--- a/src/cache-ct.c
+++ b/src/cache-ct.c
@@ -90,21 +90,12 @@ cache_ct_hash(const void *data, const struct hashtable *table)
return ret;
}
-/* master conntrack of expectations have no ID */
-static inline int
-cache_ct_cmp_id(const struct nf_conntrack *ct1, const struct nf_conntrack *ct2)
-{
- return nfct_attr_is_set(ct2, ATTR_ID) ?
- nfct_get_attr_u32(ct1, ATTR_ID) == nfct_get_attr_u32(ct2, ATTR_ID) : 1;
-}
-
static int cache_ct_cmp(const void *data1, const void *data2)
{
const struct cache_object *obj = data1;
const struct nf_conntrack *ct = data2;
- return nfct_cmp(obj->ptr, ct, NFCT_CMP_ORIG) &&
- cache_ct_cmp_id(obj->ptr, ct);
+ return nfct_cmp(obj->ptr, ct, NFCT_CMP_ORIG);
}
static void *cache_ct_alloc(void)
diff --git a/src/cache.c b/src/cache.c
index 79a024f..9bc8d0f 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -69,12 +69,12 @@ struct cache *cache_create(const char *name, enum cache_type type,
memcpy(c->feature_type, feature_type, sizeof(feature_type));
- c->features = malloc(sizeof(struct cache_feature) * j);
+ c->features = malloc(sizeof(struct cache_feature *) * j);
if (!c->features) {
free(c);
return NULL;
}
- memcpy(c->features, feature_array, sizeof(struct cache_feature) * j);
+ memcpy(c->features, feature_array, sizeof(struct cache_feature *) * j);
c->num_features = j;
c->extra_offset = size;
diff --git a/src/conntrack.c b/src/conntrack.c
index 9e2fa25..0d71352 100644
--- a/src/conntrack.c
+++ b/src/conntrack.c
@@ -68,10 +68,14 @@
#include <linux/netfilter/nf_conntrack_common.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-static struct nfct_mnl_socket {
+struct nfct_mnl_socket {
struct mnl_socket *mnl;
uint32_t portid;
-} sock;
+};
+
+static struct nfct_mnl_socket _sock;
+static struct nfct_mnl_socket _modifier_sock;
+static struct nfct_mnl_socket _event_sock;
struct u32_mask {
uint32_t value;
@@ -135,6 +139,8 @@ static int alloc_tmpl_objects(struct ct_tmpl *tmpl)
static void free_tmpl_objects(struct ct_tmpl *tmpl)
{
+ if (!tmpl)
+ return;
if (tmpl->ct)
nfct_destroy(tmpl->ct);
if (tmpl->exptuple)
@@ -149,68 +155,6 @@ static void free_tmpl_objects(struct ct_tmpl *tmpl)
nfct_bitmask_destroy(tmpl->label_modify);
}
-enum ct_command {
- CT_NONE = 0,
-
- CT_LIST_BIT = 0,
- CT_LIST = (1 << CT_LIST_BIT),
-
- CT_CREATE_BIT = 1,
- CT_CREATE = (1 << CT_CREATE_BIT),
-
- CT_UPDATE_BIT = 2,
- CT_UPDATE = (1 << CT_UPDATE_BIT),
-
- CT_DELETE_BIT = 3,
- CT_DELETE = (1 << CT_DELETE_BIT),
-
- CT_GET_BIT = 4,
- CT_GET = (1 << CT_GET_BIT),
-
- CT_FLUSH_BIT = 5,
- CT_FLUSH = (1 << CT_FLUSH_BIT),
-
- CT_EVENT_BIT = 6,
- CT_EVENT = (1 << CT_EVENT_BIT),
-
- CT_VERSION_BIT = 7,
- CT_VERSION = (1 << CT_VERSION_BIT),
-
- CT_HELP_BIT = 8,
- CT_HELP = (1 << CT_HELP_BIT),
-
- EXP_LIST_BIT = 9,
- EXP_LIST = (1 << EXP_LIST_BIT),
-
- EXP_CREATE_BIT = 10,
- EXP_CREATE = (1 << EXP_CREATE_BIT),
-
- EXP_DELETE_BIT = 11,
- EXP_DELETE = (1 << EXP_DELETE_BIT),
-
- EXP_GET_BIT = 12,
- EXP_GET = (1 << EXP_GET_BIT),
-
- EXP_FLUSH_BIT = 13,
- EXP_FLUSH = (1 << EXP_FLUSH_BIT),
-
- EXP_EVENT_BIT = 14,
- EXP_EVENT = (1 << EXP_EVENT_BIT),
-
- CT_COUNT_BIT = 15,
- CT_COUNT = (1 << CT_COUNT_BIT),
-
- EXP_COUNT_BIT = 16,
- EXP_COUNT = (1 << EXP_COUNT_BIT),
-
- CT_STATS_BIT = 17,
- CT_STATS = (1 << CT_STATS_BIT),
-
- EXP_STATS_BIT = 18,
- EXP_STATS = (1 << EXP_STATS_BIT),
-};
-/* If you add a new command, you have to update NUMBER_OF_CMD in conntrack.h */
-
enum ct_options {
CT_OPT_ORIG_SRC_BIT = 0,
CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT),
@@ -349,6 +293,7 @@ static const char *optflags[NUMBER_OF_OPT] = {
static struct option original_opts[] = {
{"dump", 2, 0, 'L'},
{"create", 2, 0, 'I'},
+ {"add", 2, 0, 'A'},
{"delete", 2, 0, 'D'},
{"update", 2, 0, 'U'},
{"get", 2, 0, 'G'},
@@ -392,7 +337,7 @@ static struct option original_opts[] = {
{0, 0, 0, 0}
};
-static const char *getopt_str = ":L::I::U::D::G::E::F::hVs:d:r:q:"
+static const char *getopt_str = ":L::I::U::D::G::E::F::A::hVs:d:r:q:"
"p:t:u:e:a:z[:]:{:}:m:i:f:o:n::"
"g::c:b:C::Sj::w:l:<:>::(:):";
@@ -409,26 +354,27 @@ static const char *getopt_str = ":L::I::U::D::G::E::F::hVs:d:r:q:"
static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
/* Well, it's better than "Re: Linux vs FreeBSD" */
{
- /* s d r q p t u z e [ ] { } a m i f n g o c b j w l < > ( ) */
-/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,2,2,0,2,0,2,2,2,2,2,0,2,2,2,0,0,2,2},
-/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0,2,0,2,2},
-/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,0,2,2,2,0,0},
-/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,2,2,0,0,2,2},
-/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,2,0,0,0,0},
-/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0},
-/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,2,2,0,2,0,2,2,2,2,2,2,2,2,2,0,0,2,2},
-/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0},
-/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0},
-/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*CT_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ /* s d r q p t u z e [ ] { } a m i f n g o c b j w l < > ( ) */
+ [CT_LIST_BIT] = {2,2,2,2,2,0,2,2,0,0,0,2,2,0,2,0,2,2,2,2,2,0,2,2,2,0,0,2,2},
+ [CT_CREATE_BIT] = {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0,2,0,2,2},
+ [CT_UPDATE_BIT] = {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,0,2,2,2,0,0},
+ [CT_DELETE_BIT] = {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,2,2,0,0,2,2},
+ [CT_GET_BIT] = {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,2,0,0,0,0},
+ [CT_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0},
+ [CT_EVENT_BIT] = {2,2,2,2,2,0,0,0,2,0,0,2,2,0,2,0,2,2,2,2,2,2,2,2,2,0,0,2,2},
+ [CT_VERSION_BIT]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [CT_HELP_BIT] = {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_LIST_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0},
+ [EXP_CREATE_BIT]= {1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_DELETE_BIT]= {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_GET_BIT] = {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0},
+ [CT_COUNT_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_COUNT_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [CT_STATS_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_STATS_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [CT_ADD_BIT] = {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0,2,0,2,2},
};
static const int cmd2type[][2] = {
@@ -442,6 +388,8 @@ static const int cmd2type[][2] = {
['h'] = { CT_HELP, CT_HELP },
['C'] = { CT_COUNT, EXP_COUNT },
['S'] = { CT_STATS, EXP_STATS },
+ ['U'] = { CT_UPDATE, 0 },
+ ['A'] = { CT_ADD, 0 },
};
static const int opt2type[] = {
@@ -545,6 +493,7 @@ static char exit_msg[NUMBER_OF_CMD][64] = {
[CT_EVENT_BIT] = "%d flow events have been shown.\n",
[EXP_LIST_BIT] = "%d expectations have been shown.\n",
[EXP_DELETE_BIT] = "%d expectations have been shown.\n",
+ [CT_ADD_BIT] = "%d flow entries have been added.\n",
};
static const char usage_commands[] =
@@ -589,7 +538,7 @@ static const char usage_parameters[] =
"Common parameters and options:\n"
" -s, --src, --orig-src ip\t\tSource address from original direction\n"
" -d, --dst, --orig-dst ip\t\tDestination address from original direction\n"
- " -r, --reply-src ip\t\tSource addres from reply direction\n"
+ " -r, --reply-src ip\t\tSource address from reply direction\n"
" -q, --reply-dst ip\t\tDestination address from reply direction\n"
" -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n"
" -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n"
@@ -605,7 +554,7 @@ static const char usage_parameters[] =
#define OPTION_OFFSET 256
-static struct nfct_handle *cth, *ith;
+static struct nfct_handle *cth;
static struct option *opts = original_opts;
static unsigned int global_option_offset = 0;
@@ -796,12 +745,13 @@ static int ct_save_snprintf(char *buf, size_t len,
struct ctproto_handler *cur;
uint8_t l3proto, l4proto;
int tuple_attrs[4] = {};
+ bool l4proto_set;
unsigned i;
int ret;
switch (type) {
case NFCT_T_NEW:
- ret = snprintf(buf + offset, len, "-I ");
+ ret = snprintf(buf + offset, len, "-A ");
BUFFER_SIZE(ret, size, len, offset);
break;
case NFCT_T_UPDATE:
@@ -813,7 +763,6 @@ static int ct_save_snprintf(char *buf, size_t len,
BUFFER_SIZE(ret, size, len, offset);
break;
default:
- ret = 0;
break;
}
@@ -856,6 +805,7 @@ static int ct_save_snprintf(char *buf, size_t len,
l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO);
+ l4proto_set = false;
/* is it in the list of supported protocol? */
list_for_each_entry(cur, &proto_list, head) {
if (cur->protonum != l4proto)
@@ -866,9 +816,16 @@ static int ct_save_snprintf(char *buf, size_t len,
ret = ct_snprintf_opts(buf + offset, len, ct, cur->print_opts);
BUFFER_SIZE(ret, size, len, offset);
+
+ l4proto_set = true;
break;
}
+ if (!l4proto_set) {
+ ret = snprintf(buf + offset, len, "-p %d ", l4proto);
+ BUFFER_SIZE(ret, size, len, offset);
+ }
+
/* skip trailing space, if any */
for (; size && buf[size-1] == ' '; --size)
buf[size-1] = '\0';
@@ -878,6 +835,20 @@ static int ct_save_snprintf(char *buf, size_t len,
extern struct ctproto_handler ct_proto_unknown;
+static int parse_proto_num(const char *str)
+{
+ unsigned long val;
+ char *endptr;
+
+ val = strtoul(str, &endptr, 0);
+ if (val > IPPROTO_RAW ||
+ endptr == str ||
+ *endptr != '\0')
+ return -1;
+
+ return val;
+}
+
static struct ctproto_handler *findproto(char *name, int *pnum)
{
struct ctproto_handler *cur;
@@ -897,8 +868,8 @@ static struct ctproto_handler *findproto(char *name, int *pnum)
return &ct_proto_unknown;
}
/* using a protocol number? */
- protonum = atoi(name);
- if (protonum >= 0 && protonum <= IPPROTO_MAX) {
+ protonum = parse_proto_num(name);
+ if (protonum >= 0) {
/* try lookup by number, perhaps this protocol is supported */
list_for_each_entry(cur, &proto_list, head) {
if (cur->protonum == protonum) {
@@ -1087,11 +1058,11 @@ err2str(int err, enum ct_command command)
{ { CT_LIST, ENOTSUPP, "function not implemented" },
{ 0xFFFF, EINVAL, "invalid parameters" },
{ CT_CREATE, EEXIST, "Such conntrack exists, try -U to update" },
- { CT_CREATE|CT_GET|CT_DELETE, ENOENT,
+ { CT_CREATE|CT_GET|CT_DELETE|CT_ADD, ENOENT,
"such conntrack doesn't exist" },
- { CT_CREATE|CT_GET, ENOMEM, "not enough memory" },
+ { CT_CREATE|CT_GET|CT_ADD, ENOMEM, "not enough memory" },
{ CT_GET, EAFNOSUPPORT, "protocol not supported" },
- { CT_CREATE, ETIME, "conntrack has expired" },
+ { CT_CREATE|CT_ADD, ETIME, "conntrack has expired" },
{ EXP_CREATE, ENOENT, "master conntrack not found" },
{ EXP_CREATE, EINVAL, "invalid parameters" },
{ ~0U, EPERM, "sorry, you must be root or get "
@@ -1124,8 +1095,7 @@ enum {
_O_ID = (1 << 3),
_O_KTMS = (1 << 4),
_O_CL = (1 << 5),
- _O_US = (1 << 6),
- _O_SAVE = (1 << 7),
+ _O_SAVE = (1 << 6),
};
enum {
@@ -1145,7 +1115,7 @@ static struct parse_parameter {
{ {"ALL", "NEW", "UPDATES", "DESTROY"}, 4,
{ CT_EVENT_F_ALL, CT_EVENT_F_NEW, CT_EVENT_F_UPD, CT_EVENT_F_DEL } },
{ {"xml", "extended", "timestamp", "id", "ktimestamp", "labels", "userspace", "save"}, 8,
- { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS, _O_CL, _O_US, _O_SAVE },
+ { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS, _O_CL, 0, _O_SAVE },
},
};
@@ -1725,7 +1695,7 @@ event_sighandler(int s)
fprintf(stderr, "%s v%s (conntrack-tools): ", PROGNAME, VERSION);
fprintf(stderr, "%d flow events have been shown.\n", counter);
- mnl_socket_close(sock.mnl);
+ mnl_socket_close(_sock.mnl);
exit(0);
}
@@ -1800,7 +1770,7 @@ static char *portid2name(pid_t pid, uint32_t portid, unsigned long inode)
continue;
rl = readlink(procname, tmp, sizeof(tmp));
- if (rl <= 0 || rl > (ssize_t)sizeof(tmp))
+ if (rl <= 0 || rl >= (ssize_t)sizeof(tmp))
continue;
tmp[rl] = 0;
@@ -1974,7 +1944,7 @@ static int event_cb(const struct nlmsghdr *nlh, void *data)
nfct_snprintf_labels(buf, sizeof(buf), ct, type, op_type, op_flags, labelmap);
done:
- if ((output_mask & _O_US) && nlh->nlmsg_pid) {
+ if (nlh->nlmsg_pid && !(output_mask & _O_XML)) {
char *prog = get_progname(nlh->nlmsg_pid);
if (prog)
@@ -1992,65 +1962,41 @@ out:
return MNL_CB_OK;
}
-static int dump_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
-{
- unsigned int op_type = NFCT_O_DEFAULT;
- unsigned int op_flags = 0;
- struct ct_cmd *cmd = data;
- char buf[1024];
+static int nfct_mnl_request(struct nfct_mnl_socket *sock, uint16_t subsys,
+ int family, uint16_t type, uint16_t flags,
+ mnl_cb_t cb, const struct nf_conntrack *ct,
+ const struct ct_cmd *cmd);
- if (nfct_filter(cmd, ct, cur_tmpl))
- return NFCT_CB_CONTINUE;
-
- if (output_mask & _O_SAVE) {
- ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_NEW);
- goto done;
- }
-
- if (output_mask & _O_XML) {
- op_type = NFCT_O_XML;
- if (dump_xml_header_done) {
- dump_xml_header_done = 0;
- printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- "<conntrack>\n");
- }
- }
- if (output_mask & _O_EXT)
- op_flags = NFCT_OF_SHOW_LAYER3;
- if (output_mask & _O_KTMS)
- op_flags |= NFCT_OF_TIMESTAMP;
- if (output_mask & _O_ID)
- op_flags |= NFCT_OF_ID;
-
- nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap);
-done:
- printf("%s\n", buf);
-
- counter++;
-
- return NFCT_CB_CONTINUE;
-}
-
-static int delete_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
+static int mnl_nfct_delete_cb(const struct nlmsghdr *nlh, void *data)
{
+ struct nfct_mnl_socket *modifier_sock = &_modifier_sock;
unsigned int op_type = NFCT_O_DEFAULT;
unsigned int op_flags = 0;
struct ct_cmd *cmd = data;
+ struct nf_conntrack *ct;
char buf[1024];
int res;
+ ct = nfct_new();
+ if (ct == NULL)
+ return MNL_CB_OK;
+
+ nfct_nlmsg_parse(nlh, ct);
+
if (nfct_filter(cmd, ct, cur_tmpl))
- return NFCT_CB_CONTINUE;
+ goto destroy_ok;
- res = nfct_query(ith, NFCT_Q_DESTROY, ct);
- if (res < 0)
+ res = nfct_mnl_request(modifier_sock, NFNL_SUBSYS_CTNETLINK,
+ nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO),
+ IPCTNL_MSG_CT_DELETE, NLM_F_ACK, NULL, ct, NULL);
+ if (res < 0) {
+ /* the entry has vanish in middle of the delete */
+ if (errno == ENOENT)
+ goto done;
exit_error(OTHER_PROBLEM,
"Operation failed: %s",
err2str(errno, CT_DELETE));
+ }
if (output_mask & _O_SAVE) {
ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_DESTROY);
@@ -2070,16 +2016,23 @@ done:
counter++;
- return NFCT_CB_CONTINUE;
+destroy_ok:
+ nfct_destroy(ct);
+ return MNL_CB_OK;
}
-static int print_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
+static int mnl_nfct_print_cb(const struct nlmsghdr *nlh, void *data)
{
- char buf[1024];
unsigned int op_type = NFCT_O_DEFAULT;
unsigned int op_flags = 0;
+ struct nf_conntrack *ct;
+ char buf[1024];
+
+ ct = nfct_new();
+ if (ct == NULL)
+ return MNL_CB_OK;
+
+ nfct_nlmsg_parse(nlh, ct);
if (output_mask & _O_SAVE) {
ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_NEW);
@@ -2097,7 +2050,9 @@ static int print_cb(enum nf_conntrack_msg_type type,
done:
printf("%s\n", buf);
- return NFCT_CB_CONTINUE;
+ nfct_destroy(ct);
+
+ return MNL_CB_OK;
}
static void copy_mark(const struct ct_cmd *cmd, struct nf_conntrack *tmp,
@@ -2190,29 +2145,34 @@ static void copy_label(const struct ct_cmd *cmd, struct nf_conntrack *tmp,
}
}
-static int update_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
+static int mnl_nfct_update_cb(const struct nlmsghdr *nlh, void *data)
{
struct ct_cmd *cmd = data;
- struct nf_conntrack *obj = cmd->tmpl.ct, *tmp;
+ struct nfct_mnl_socket *modifier_sock = &_modifier_sock;
+ struct nf_conntrack *ct, *obj = cmd->tmpl.ct, *tmp = NULL;
int res;
+ ct = nfct_new();
+ if (ct == NULL)
+ return MNL_CB_OK;
+
+ nfct_nlmsg_parse(nlh, ct);
+
if (filter_nat(cmd, ct) ||
filter_label(ct, cur_tmpl) ||
filter_network(cmd, ct))
- return NFCT_CB_CONTINUE;
+ goto destroy_ok;
if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) &&
nfct_get_attr_u32(obj, ATTR_ID) != nfct_get_attr_u32(ct, ATTR_ID))
- return NFCT_CB_CONTINUE;
+ goto destroy_ok;
if (cmd->options & CT_OPT_TUPLE_ORIG &&
!nfct_cmp(obj, ct, NFCT_CMP_ORIG))
- return NFCT_CB_CONTINUE;
+ goto destroy_ok;
if (cmd->options & CT_OPT_TUPLE_REPL &&
!nfct_cmp(obj, ct, NFCT_CMP_REPL))
- return NFCT_CB_CONTINUE;
+ goto destroy_ok;
tmp = nfct_new();
if (tmp == NULL)
@@ -2225,36 +2185,47 @@ static int update_cb(enum nf_conntrack_msg_type type,
copy_label(cmd, tmp, ct, cur_tmpl);
/* do not send NFCT_Q_UPDATE if ct appears unchanged */
- if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) {
- nfct_destroy(tmp);
- return NFCT_CB_CONTINUE;
- }
+ if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK))
+ goto destroy_ok;
- res = nfct_query(ith, NFCT_Q_UPDATE, tmp);
- if (res < 0)
- fprintf(stderr,
- "Operation failed: %s\n",
+ res = nfct_mnl_request(modifier_sock, NFNL_SUBSYS_CTNETLINK,
+ nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO),
+ IPCTNL_MSG_CT_NEW, NLM_F_ACK, NULL, tmp, NULL);
+ if (res < 0) {
+ /* the entry has vanish in middle of the update */
+ if (errno == ENOENT)
+ goto destroy_ok;
+ else if (cmd->options & (CT_OPT_ADD_LABEL | CT_OPT_DEL_LABEL) &&
+ !nfct_attr_is_set(ct, ATTR_CONNLABELS) &&
+ errno == ENOSPC)
+ goto destroy_ok;
+
+ exit_error(OTHER_PROBLEM,
+ "Operation failed: %s",
err2str(errno, CT_UPDATE));
- nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL);
+ }
- res = nfct_query(ith, NFCT_Q_GET, tmp);
+ res = nfct_mnl_request(modifier_sock, NFNL_SUBSYS_CTNETLINK,
+ nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO),
+ IPCTNL_MSG_CT_GET, 0,
+ mnl_nfct_print_cb, tmp, NULL);
if (res < 0) {
- nfct_destroy(tmp);
/* the entry has vanish in middle of the update */
- if (errno == ENOENT) {
- nfct_callback_unregister(ith);
- return NFCT_CB_CONTINUE;
- }
+ if (errno == ENOENT)
+ goto destroy_ok;
exit_error(OTHER_PROBLEM,
"Operation failed: %s",
err2str(errno, CT_UPDATE));
}
- nfct_destroy(tmp);
- nfct_callback_unregister(ith);
counter++;
- return NFCT_CB_CONTINUE;
+destroy_ok:
+ if (tmp)
+ nfct_destroy(tmp);
+ nfct_destroy(ct);
+
+ return MNL_CB_OK;
}
static int dump_exp_cb(enum nf_conntrack_msg_type type,
@@ -2399,32 +2370,33 @@ out_err:
return ret;
}
-static int nfct_mnl_socket_open(unsigned int events)
+static int nfct_mnl_socket_open(struct nfct_mnl_socket *socket,
+ unsigned int events)
{
- sock.mnl = mnl_socket_open(NETLINK_NETFILTER);
- if (sock.mnl == NULL) {
+ socket->mnl = mnl_socket_open(NETLINK_NETFILTER);
+ if (socket->mnl == NULL) {
perror("mnl_socket_open");
return -1;
}
- if (mnl_socket_bind(sock.mnl, events, MNL_SOCKET_AUTOPID) < 0) {
+ if (mnl_socket_bind(socket->mnl, events, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
return -1;
}
- sock.portid = mnl_socket_get_portid(sock.mnl);
+ socket->portid = mnl_socket_get_portid(socket->mnl);
return 0;
}
static struct nlmsghdr *
nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type,
- uint8_t family)
+ uint16_t flags, uint8_t family)
{
struct nlmsghdr *nlh;
struct nfgenmsg *nfh;
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = (subsys << 8) | type;
- nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+ nlh->nlmsg_flags = NLM_F_REQUEST | flags;
nlh->nlmsg_seq = time(NULL);
nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
@@ -2435,55 +2407,104 @@ nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type,
return nlh;
}
-static void nfct_mnl_socket_close(void)
+static void nfct_mnl_socket_close(const struct nfct_mnl_socket *sock)
{
- mnl_socket_close(sock.mnl);
+ mnl_socket_close(sock->mnl);
}
-static int
-nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family)
+static int nfct_mnl_socket_check_open(struct nfct_mnl_socket *socket,
+ unsigned int events)
+{
+ if (socket->mnl != NULL)
+ return 0;
+
+ return nfct_mnl_socket_open(socket, events);
+}
+
+static void nfct_mnl_socket_check_close(struct nfct_mnl_socket *sock)
+{
+ if (sock->mnl) {
+ nfct_mnl_socket_close(sock);
+ memset(sock, 0, sizeof(*sock));
+ }
+}
+
+static int __nfct_mnl_dump(struct nfct_mnl_socket *sock,
+ const struct nlmsghdr *nlh, mnl_cb_t cb, void *data)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
- struct nlmsghdr *nlh;
int res;
- nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family);
-
- res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len);
+ res = mnl_socket_sendto(sock->mnl, nlh, nlh->nlmsg_len);
if (res < 0)
return res;
- res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf));
+ res = mnl_socket_recvfrom(sock->mnl, buf, sizeof(buf));
while (res > 0) {
- res = mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid,
- cb, NULL);
+ res = mnl_cb_run(buf, res, nlh->nlmsg_seq, sock->portid,
+ cb, data);
if (res <= MNL_CB_STOP)
break;
- res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf));
+ res = mnl_socket_recvfrom(sock->mnl, buf, sizeof(buf));
}
return res;
}
static int
-nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family)
+nfct_mnl_dump(struct nfct_mnl_socket *sock, uint16_t subsys, uint16_t type,
+ mnl_cb_t cb, struct ct_cmd *cmd,
+ const struct nfct_filter_dump *filter_dump)
{
+ uint8_t family = cmd ? cmd->family : AF_UNSPEC;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
- int res;
- nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family);
+ nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, NLM_F_DUMP, family);
- res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len);
- if (res < 0)
- return res;
+ if (filter_dump)
+ nfct_nlmsg_build_filter(nlh, filter_dump);
- res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf));
- if (res < 0)
- return res;
+ return __nfct_mnl_dump(sock, nlh, cb, cmd);
+}
+
+static int nfct_mnl_talk(struct nfct_mnl_socket *sock,
+ const struct nlmsghdr *nlh, mnl_cb_t cb,
+ const struct ct_cmd *cmd)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ int ret;
+
+ ret = mnl_socket_sendto(sock->mnl, nlh, nlh->nlmsg_len);
+ if (ret < 0)
+ return ret;
+
+ ret = mnl_socket_recvfrom(sock->mnl, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ return mnl_cb_run(buf, ret, nlh->nlmsg_seq, sock->portid, cb, (void *)cmd);
+}
+
+static int nfct_mnl_request(struct nfct_mnl_socket *sock, uint16_t subsys,
+ int family, uint16_t type, uint16_t flags,
+ mnl_cb_t cb, const struct nf_conntrack *ct,
+ const struct ct_cmd *cmd)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ int err;
+
+ nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, flags, family);
+
+ if (ct) {
+ err = nfct_nlmsg_build(nlh, ct);
+ if (err < 0)
+ return err;
+ }
- return mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid, cb, NULL);
+ return nfct_mnl_talk(sock, nlh, cb, cmd);
}
#define UNKNOWN_STATS_NUM 4
@@ -2625,6 +2646,9 @@ static int nfct_global_stats_cb(const struct nlmsghdr *nlh, void *data)
static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data)
{
+ unsigned int op_type = NFCT_O_DEFAULT;
+ unsigned int op_flags = 0;
+ struct ct_cmd *cmd = data;
struct nf_conntrack *ct;
char buf[4096];
@@ -2634,7 +2658,34 @@ static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data)
nfct_nlmsg_parse(nlh, ct);
- nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0);
+ if (nfct_filter(cmd, ct, cur_tmpl)) {
+ nfct_destroy(ct);
+ return MNL_CB_OK;
+ }
+
+ if (output_mask & _O_SAVE) {
+ ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_NEW);
+ goto done;
+ }
+
+ if (output_mask & _O_XML) {
+ op_type = NFCT_O_XML;
+ if (dump_xml_header_done) {
+ dump_xml_header_done = 0;
+ printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<conntrack>\n");
+ }
+ }
+ if (output_mask & _O_EXT)
+ op_flags = NFCT_OF_SHOW_LAYER3;
+ if (output_mask & _O_KTMS)
+ op_flags |= NFCT_OF_TIMESTAMP;
+ if (output_mask & _O_ID)
+ op_flags |= NFCT_OF_ID;
+
+ nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type,
+ op_flags, labelmap);
+done:
printf("%s\n", buf);
nfct_destroy(ct);
@@ -2849,7 +2900,8 @@ static int print_stats(const struct ct_cmd *cmd)
if (cmd->command && exit_msg[cmd->cmd][0]) {
fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION);
fprintf(stderr, exit_msg[cmd->cmd], counter);
- if (counter == 0 && !(cmd->command & (CT_LIST | EXP_LIST)))
+ if (counter == 0 &&
+ !(cmd->command & (CT_LIST | EXP_LIST)))
return -1;
}
@@ -2902,27 +2954,24 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[])
case 'h':
case 'C':
case 'S':
- type = check_type(argc, argv);
- if (type == CT_TABLE_DYING ||
- type == CT_TABLE_UNCONFIRMED) {
- exit_error(PARAMETER_PROBLEM,
- "Can't do that command with "
- "tables `dying' and `unconfirmed'");
- }
- add_command(&command, cmd2type[c][type]);
- break;
case 'U':
+ case 'A':
type = check_type(argc, argv);
if (type == CT_TABLE_DYING ||
type == CT_TABLE_UNCONFIRMED) {
exit_error(PARAMETER_PROBLEM,
"Can't do that command with "
"tables `dying' and `unconfirmed'");
- } else if (type == CT_TABLE_CONNTRACK)
- add_command(&command, CT_UPDATE);
- else
+ }
+ if (cmd2type[c][type])
+ add_command(&command, cmd2type[c][type]);
+ else {
exit_error(PARAMETER_PROBLEM,
- "Can't update expectations");
+ "Can't do --%s on %s",
+ get_long_opt(c),
+ type == CT_TABLE_CONNTRACK ?
+ "conntrack" : "expectations");
+ }
break;
/* options */
case 's':
@@ -2973,8 +3022,7 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[])
if (tmpl->filter_status_kernel.mask == 0)
tmpl->filter_status_kernel.mask = status;
- tmpl->mark.value = status;
- tmpl->filter_status_kernel.val = tmpl->mark.value;
+ tmpl->filter_status_kernel.val = status;
tmpl->filter_status_kernel_set = true;
break;
case 'e':
@@ -3023,6 +3071,8 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[])
nfct_set_nat_details(c, tmpl->ct, &ad,
port_str, family);
}
+ free(port_str);
+ free(nat_address);
}
break;
case 'w':
@@ -3177,39 +3227,29 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[])
ct_cmd->socketbuffersize = socketbuffersize;
}
-static int do_command_ct(const char *progname, struct ct_cmd *cmd)
+static int do_command_ct(const char *progname, struct ct_cmd *cmd,
+ struct nfct_mnl_socket *sock)
{
+ struct nfct_mnl_socket *modifier_sock = &_modifier_sock;
+ struct nfct_mnl_socket *event_sock = &_event_sock;
struct nfct_filter_dump *filter_dump;
+ uint16_t nl_flags = 0;
int res = 0;
switch(cmd->command) {
case CT_LIST:
if (cmd->type == CT_TABLE_DYING) {
- if (nfct_mnl_socket_open(0) < 0)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
- res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK,
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
IPCTNL_MSG_CT_GET_DYING,
- mnl_nfct_dump_cb, cmd->family);
-
- nfct_mnl_socket_close();
+ mnl_nfct_dump_cb, cmd, NULL);
break;
} else if (cmd->type == CT_TABLE_UNCONFIRMED) {
- if (nfct_mnl_socket_open(0) < 0)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
- res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK,
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
IPCTNL_MSG_CT_GET_UNCONFIRMED,
- mnl_nfct_dump_cb, cmd->family);
-
- nfct_mnl_socket_close();
+ mnl_nfct_dump_cb, cmd, NULL);
break;
}
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
if (cmd->options & CT_COMPARISON &&
cmd->options & CT_OPT_ZERO)
exit_error(PARAMETER_PROBLEM, "Can't use -z with "
@@ -3217,8 +3257,6 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
nfct_filter_init(cmd);
- nfct_callback_register(cth, NFCT_T_ALL, dump_cb, cmd);
-
filter_dump = nfct_filter_dump_create();
if (filter_dump == NULL)
exit_error(OTHER_PROBLEM, "OOM");
@@ -3236,11 +3274,15 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
NFCT_FILTER_DUMP_STATUS,
&cmd->tmpl.filter_status_kernel);
}
- if (cmd->options & CT_OPT_ZERO)
- res = nfct_query(cth, NFCT_Q_DUMP_FILTER_RESET,
- filter_dump);
- else
- res = nfct_query(cth, NFCT_Q_DUMP_FILTER, filter_dump);
+ if (cmd->options & CT_OPT_ZERO) {
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
+ IPCTNL_MSG_CT_GET_CTRZERO,
+ mnl_nfct_dump_cb, cmd, filter_dump);
+ } else {
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
+ IPCTNL_MSG_CT_GET,
+ mnl_nfct_dump_cb, cmd, filter_dump);
+ }
nfct_filter_dump_destroy(filter_dump);
@@ -3248,10 +3290,7 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
printf("</conntrack>\n");
fflush(stdout);
}
-
- nfct_close(cth);
break;
-
case EXP_LIST:
cth = nfct_open(EXPECT, 0);
if (!cth)
@@ -3268,6 +3307,7 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
break;
case CT_CREATE:
+ case CT_ADD:
if ((cmd->options & CT_OPT_ORIG) && !(cmd->options & CT_OPT_REPL))
nfct_setobjopt(cmd->tmpl.ct, NFCT_SOPT_SETUP_REPLY);
else if (!(cmd->options & CT_OPT_ORIG) && (cmd->options & CT_OPT_REPL))
@@ -3280,14 +3320,15 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
nfct_set_attr(cmd->tmpl.ct, ATTR_CONNLABELS,
xnfct_bitmask_clone(cmd->tmpl.label_modify));
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
+ if (cmd->command == CT_CREATE)
+ nl_flags = NLM_F_EXCL;
- res = nfct_query(cth, NFCT_Q_CREATE, cmd->tmpl.ct);
- if (res != -1)
+ res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, cmd->family,
+ IPCTNL_MSG_CT_NEW,
+ NLM_F_CREATE | NLM_F_ACK | nl_flags,
+ NULL, cmd->tmpl.ct, NULL);
+ if (res >= 0)
counter++;
- nfct_close(cth);
break;
case EXP_CREATE:
@@ -3304,31 +3345,21 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
break;
case CT_UPDATE:
- cth = nfct_open(CONNTRACK, 0);
- /* internal handler for delete_cb, otherwise we hit EILSEQ */
- ith = nfct_open(CONNTRACK, 0);
- if (!cth || !ith)
+ if (nfct_mnl_socket_check_open(modifier_sock, 0) < 0)
exit_error(OTHER_PROBLEM, "Can't open handler");
nfct_filter_init(cmd);
-
- nfct_callback_register(cth, NFCT_T_ALL, update_cb, cmd);
-
- res = nfct_query(cth, NFCT_Q_DUMP, &cmd->family);
- nfct_close(ith);
- nfct_close(cth);
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
+ IPCTNL_MSG_CT_GET, mnl_nfct_update_cb,
+ cmd, NULL);
break;
case CT_DELETE:
- cth = nfct_open(CONNTRACK, 0);
- ith = nfct_open(CONNTRACK, 0);
- if (!cth || !ith)
+ if (nfct_mnl_socket_check_open(modifier_sock, 0) < 0)
exit_error(OTHER_PROBLEM, "Can't open handler");
nfct_filter_init(cmd);
- nfct_callback_register(cth, NFCT_T_ALL, delete_cb, cmd);
-
filter_dump = nfct_filter_dump_create();
if (filter_dump == NULL)
exit_error(OTHER_PROBLEM, "OOM");
@@ -3342,12 +3373,11 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
NFCT_FILTER_DUMP_L3NUM,
cmd->family);
- res = nfct_query(cth, NFCT_Q_DUMP_FILTER, filter_dump);
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
+ IPCTNL_MSG_CT_GET, mnl_nfct_delete_cb,
+ cmd, filter_dump);
nfct_filter_dump_destroy(filter_dump);
-
- nfct_close(ith);
- nfct_close(cth);
break;
case EXP_DELETE:
@@ -3362,13 +3392,9 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
break;
case CT_GET:
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
- nfct_callback_register(cth, NFCT_T_ALL, dump_cb, cmd);
- res = nfct_query(cth, NFCT_Q_GET, cmd->tmpl.ct);
- nfct_close(cth);
+ res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, cmd->family,
+ IPCTNL_MSG_CT_GET, 0,
+ mnl_nfct_dump_cb, cmd->tmpl.ct, cmd);
break;
case EXP_GET:
@@ -3384,11 +3410,9 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
break;
case CT_FLUSH:
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
- res = nfct_query(cth, NFCT_Q_FLUSH_FILTER, &cmd->family);
- nfct_close(cth);
+ res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, cmd->family,
+ IPCTNL_MSG_CT_DELETE, NLM_F_ACK, NULL, NULL, NULL);
+
fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION);
fprintf(stderr,"connection tracking table has been emptied.\n");
break;
@@ -3414,9 +3438,10 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
if (cmd->event_mask & CT_EVENT_F_DEL)
nl_events |= NF_NETLINK_CONNTRACK_DESTROY;
- res = nfct_mnl_socket_open(nl_events);
+ res = nfct_mnl_socket_open(event_sock, nl_events);
} else {
- res = nfct_mnl_socket_open(NF_NETLINK_CONNTRACK_NEW |
+ res = nfct_mnl_socket_open(event_sock,
+ NF_NETLINK_CONNTRACK_NEW |
NF_NETLINK_CONNTRACK_UPDATE |
NF_NETLINK_CONNTRACK_DESTROY);
}
@@ -3429,17 +3454,17 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
socklen_t socklen = sizeof(socketbuffersize);
- res = setsockopt(mnl_socket_get_fd(sock.mnl),
+ res = setsockopt(mnl_socket_get_fd(sock->mnl),
SOL_SOCKET, SO_RCVBUFFORCE,
&socketbuffersize,
sizeof(socketbuffersize));
if (res < 0) {
- setsockopt(mnl_socket_get_fd(sock.mnl),
+ setsockopt(mnl_socket_get_fd(sock->mnl),
SOL_SOCKET, SO_RCVBUF,
&socketbuffersize,
sizeof(socketbuffersize));
}
- getsockopt(mnl_socket_get_fd(sock.mnl), SOL_SOCKET,
+ getsockopt(mnl_socket_get_fd(sock->mnl), SOL_SOCKET,
SO_RCVBUF, &socketbuffersize, &socklen);
fprintf(stderr, "NOTICE: Netlink socket buffer size "
"has been set to %zu bytes.\n",
@@ -3454,7 +3479,7 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
while (1) {
char buf[MNL_SOCKET_BUFFER_SIZE];
- res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf));
+ res = mnl_socket_recvfrom(event_sock->mnl, buf, sizeof(buf));
if (res < 0) {
if (errno == ENOBUFS) {
fprintf(stderr,
@@ -3471,9 +3496,9 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
strerror(errno));
break;
}
- res = mnl_cb_run(buf, res, 0, 0, event_cb, cmd);
+ mnl_cb_run(buf, res, 0, 0, event_cb, cmd);
}
- mnl_socket_close(sock.mnl);
+ mnl_socket_close(event_sock->mnl);
break;
case EXP_EVENT:
@@ -3507,20 +3532,14 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
/* If we fail with netlink, fall back to /proc to ensure
* backward compatibility.
*/
- if (nfct_mnl_socket_open(0) < 0)
- goto try_proc_count;
-
- res = nfct_mnl_get(NFNL_SUBSYS_CTNETLINK,
- IPCTNL_MSG_CT_GET_STATS,
- nfct_global_stats_cb, AF_UNSPEC);
-
- nfct_mnl_socket_close();
+ res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, AF_UNSPEC,
+ IPCTNL_MSG_CT_GET_STATS, 0,
+ nfct_global_stats_cb, NULL, NULL);
/* don't look at /proc, we got the information via ctnetlink */
if (res >= 0)
break;
-try_proc_count:
{
#define NF_CONNTRACK_COUNT_PROC "/proc/sys/net/netfilter/nf_conntrack_count"
FILE *fd;
@@ -3552,14 +3571,9 @@ try_proc_count:
/* If we fail with netlink, fall back to /proc to ensure
* backward compatibility.
*/
- if (nfct_mnl_socket_open(0) < 0)
- goto try_proc;
-
- res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK,
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
IPCTNL_MSG_CT_GET_STATS_CPU,
- nfct_stats_cb, AF_UNSPEC);
-
- nfct_mnl_socket_close();
+ nfct_stats_cb, NULL, NULL);
/* don't look at /proc, we got the information via ctnetlink */
if (res >= 0)
@@ -3571,14 +3585,9 @@ try_proc_count:
/* If we fail with netlink, fall back to /proc to ensure
* backward compatibility.
*/
- if (nfct_mnl_socket_open(0) < 0)
- goto try_proc;
-
- res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK_EXP,
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK_EXP,
IPCTNL_MSG_EXP_GET_STATS_CPU,
- nfexp_stats_cb, AF_UNSPEC);
-
- nfct_mnl_socket_close();
+ nfexp_stats_cb, NULL, NULL);
/* don't look at /proc, we got the information via ctnetlink */
if (res >= 0)
@@ -3801,6 +3810,8 @@ static const char *ct_unsupp_cmd_file(const struct ct_cmd *cmd)
int main(int argc, char *argv[])
{
+ struct nfct_mnl_socket *modifier_sock = &_modifier_sock;
+ struct nfct_mnl_socket *sock = &_sock;
struct ct_cmd *cmd, *next;
LIST_HEAD(cmd_list);
int res = 0;
@@ -3815,18 +3826,22 @@ int main(int argc, char *argv[])
register_gre();
register_unknown();
+ if (nfct_mnl_socket_open(sock, 0) < 0)
+ exit_error(OTHER_PROBLEM, "Can't open handler");
+
if (argc > 2 &&
(!strcmp(argv[1], "-R") || !strcmp(argv[1], "--load-file"))) {
ct_parse_file(&cmd_list, argv[0], argv[2]);
list_for_each_entry(cmd, &cmd_list, list) {
- if (!(cmd->command & (CT_CREATE | CT_UPDATE | CT_DELETE | CT_FLUSH)))
+ if (!(cmd->command &
+ (CT_CREATE | CT_ADD | CT_UPDATE | CT_DELETE | CT_FLUSH)))
exit_error(PARAMETER_PROBLEM,
"Cannot use command `%s' with --load-file",
ct_unsupp_cmd_file(cmd));
}
list_for_each_entry_safe(cmd, next, &cmd_list, list) {
- res |= do_command_ct(argv[0], cmd);
+ res |= do_command_ct(argv[0], cmd, sock);
list_del(&cmd->list);
free(cmd);
}
@@ -3836,10 +3851,12 @@ int main(int argc, char *argv[])
exit_error(OTHER_PROBLEM, "OOM");
do_parse(cmd, argc, argv);
- do_command_ct(argv[0], cmd);
- res = print_stats(cmd);
+ res = do_command_ct(argv[0], cmd, sock);
+ res |= print_stats(cmd);
free(cmd);
}
+ nfct_mnl_socket_close(sock);
+ nfct_mnl_socket_check_close(modifier_sock);
return res < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/filter.c b/src/filter.c
index 6577102..ee316e7 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -476,7 +476,7 @@ struct exp_filter *exp_filter_create(void)
struct exp_filter_item {
struct list_head head;
- char helper_name[NFCT_HELPER_NAME_MAX];
+ char helper_name[NFCT_HELPER_NAME_MAX + 1];
};
/* this is ugly, but it simplifies read_config_yy.y */
diff --git a/src/hash.c b/src/hash.c
index fe6a047..a0f240c 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -55,6 +55,7 @@ hashtable_create(int hashsize, int limit,
void hashtable_destroy(struct hashtable *h)
{
+ hashtable_flush(h);
free(h);
}
diff --git a/src/helpers.c b/src/helpers.c
index 3e4e6c8..8ca78dc 100644
--- a/src/helpers.c
+++ b/src/helpers.c
@@ -26,8 +26,7 @@ void helper_register(struct ctd_helper *helper)
list_add(&helper->head, &helper_list);
}
-static struct ctd_helper *
-__helper_find(const char *helper_name, uint8_t l4proto)
+struct ctd_helper *__helper_find(const char *helper_name, uint8_t l4proto)
{
struct ctd_helper *cur, *helper = NULL;
diff --git a/src/helpers/Makefile.am b/src/helpers/Makefile.am
index e4f10c9..e458ab4 100644
--- a/src/helpers/Makefile.am
+++ b/src/helpers/Makefile.am
@@ -11,7 +11,7 @@ pkglib_LTLIBRARIES = ct_helper_amanda.la \
ct_helper_slp.la \
ct_helper_ssdp.la
-HELPER_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) $(LAZY_LDFLAGS)
+HELPER_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS)
HELPER_CFLAGS = $(AM_CFLAGS) $(LIBNETFILTER_CONNTRACK_CFLAGS)
ct_helper_amanda_la_SOURCES = amanda.c
diff --git a/src/helpers/ftp.c b/src/helpers/ftp.c
index 2505c71..2b34534 100644
--- a/src/helpers/ftp.c
+++ b/src/helpers/ftp.c
@@ -36,17 +36,9 @@
#include <libnetfilter_queue/pktbuff.h>
#include <linux/netfilter.h>
-static bool loose; /* XXX: export this as config option. */
-
-#define NUM_SEQ_TO_REMEMBER 2
+#include "helpers/ftp.h"
-/* This structure exists only once per master */
-struct ftp_info {
- /* Valid seq positions for cmd matching after newline */
- uint32_t seq_aft_nl[MYCT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
- /* 0 means seq_match_aft_nl not set */
- int seq_aft_nl_num[MYCT_DIR_MAX];
-};
+static bool loose; /* XXX: export this as config option. */
enum nf_ct_ftp_type {
/* PORT command from client */
@@ -340,23 +332,21 @@ static int nf_nat_ftp_fmt_cmd(enum nf_ct_ftp_type type,
char *buffer, size_t buflen,
uint32_t addr, uint16_t port)
{
+ union {
+ unsigned char c[4];
+ uint32_t d;
+ } tmp;
+
+ tmp.d = addr;
switch (type) {
case NF_CT_FTP_PORT:
case NF_CT_FTP_PASV:
return snprintf(buffer, buflen, "%u,%u,%u,%u,%u,%u",
- ((unsigned char *)&addr)[0],
- ((unsigned char *)&addr)[1],
- ((unsigned char *)&addr)[2],
- ((unsigned char *)&addr)[3],
- port >> 8,
- port & 0xFF);
+ tmp.c[0], tmp.c[1], tmp.c[2], tmp.c[3],
+ port >> 8, port & 0xFF);
case NF_CT_FTP_EPRT:
return snprintf(buffer, buflen, "|1|%u.%u.%u.%u|%u|",
- ((unsigned char *)&addr)[0],
- ((unsigned char *)&addr)[1],
- ((unsigned char *)&addr)[2],
- ((unsigned char *)&addr)[3],
- port);
+ tmp.c[0], tmp.c[1], tmp.c[2], tmp.c[3], port);
case NF_CT_FTP_EPSV:
return snprintf(buffer, buflen, "|||%u|", port);
}
diff --git a/src/helpers/rpc.c b/src/helpers/rpc.c
index 3b3d0a7..732e9ba 100644
--- a/src/helpers/rpc.c
+++ b/src/helpers/rpc.c
@@ -41,21 +41,12 @@
#include <libnetfilter_queue/pktbuff.h>
#include <linux/netfilter.h>
+#include "helpers/rpc.h"
+
/* RFC 1050: RPC: Remote Procedure Call Protocol Specification Version 2 */
/* RFC 1014: XDR: External Data Representation Standard */
#define SUPPORTED_RPC_VERSION 2
-struct rpc_info {
- /* XID */
- uint32_t xid;
- /* program */
- uint32_t pm_prog;
- /* program version */
- uint32_t pm_vers;
- /* transport protocol: TCP|UDP */
- uint32_t pm_prot;
-};
-
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int
diff --git a/src/helpers/sane.c b/src/helpers/sane.c
index 2c07099..ebcb24c 100644
--- a/src/helpers/sane.c
+++ b/src/helpers/sane.c
@@ -39,11 +39,7 @@
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
#include <linux/netfilter.h>
-
-enum sane_state {
- SANE_STATE_NORMAL,
- SANE_STATE_START_REQUESTED,
-};
+#include "helpers/sane.h"
struct sane_request {
uint32_t RPC_code;
@@ -61,10 +57,6 @@ struct sane_reply_net_start {
/* other fields aren't interesting for conntrack */
};
-struct nf_ct_sane_master {
- enum sane_state state;
-};
-
static int
sane_helper_cb(struct pkt_buff *pkt, uint32_t protoff,
struct myct *myct, uint32_t ctinfo)
diff --git a/src/helpers/ssdp.c b/src/helpers/ssdp.c
index 56526f4..527892c 100644
--- a/src/helpers/ssdp.c
+++ b/src/helpers/ssdp.c
@@ -48,7 +48,6 @@
#include <errno.h>
#include <stdlib.h>
#include <arpa/inet.h>
-#include <netinet/ip.h>
#define _GNU_SOURCE
#include <netinet/tcp.h>
#include <netinet/udp.h>
@@ -159,11 +158,9 @@ static int handle_ssdp_new(struct pkt_buff *pkt, uint32_t protoff,
{
int ret = NF_ACCEPT;
union nfct_attr_grp_addr daddr, saddr, taddr;
- struct iphdr *net_hdr = (struct iphdr *)pktb_network_header(pkt);
int good_packet = 0;
struct nf_expect *exp;
uint16_t port;
- unsigned int dataoff;
void *sb_ptr;
cthelper_get_addr_dst(myct->ct, MYCT_DIR_ORIG, &daddr);
@@ -201,13 +198,12 @@ static int handle_ssdp_new(struct pkt_buff *pkt, uint32_t protoff,
}
/* No data? Ignore */
- dataoff = net_hdr->ihl*4 + sizeof(struct udphdr);
- if (dataoff >= pktb_len(pkt)) {
+ if (protoff + sizeof(struct udphdr) >= pktb_len(pkt)) {
pr_debug("ssdp_help: UDP payload too small for M-SEARCH; ignoring\n");
return NF_ACCEPT;
}
- sb_ptr = pktb_network_header(pkt) + dataoff;
+ sb_ptr = pktb_network_header(pkt) + protoff + sizeof(struct udphdr);
if (memcmp(sb_ptr, SSDP_M_SEARCH, SSDP_M_SEARCH_SIZE) != 0) {
pr_debug("ssdp_help: UDP payload does not begin with 'M-SEARCH'; ignoring\n");
@@ -260,7 +256,6 @@ static int find_hdr(const char *name, const uint8_t *data, int data_len,
data += i+2;
}
- data_len -= name_len;
data += name_len;
if (pos)
*pos = data;
diff --git a/src/helpers/tns.c b/src/helpers/tns.c
index 803f40a..5692f29 100644
--- a/src/helpers/tns.c
+++ b/src/helpers/tns.c
@@ -29,6 +29,8 @@
#include <libnetfilter_queue/pktbuff.h>
#include <linux/netfilter.h>
+#include "helpers/tns.h"
+
/* TNS SQL*Net Version 2 */
enum tns_types {
TNS_TYPE_CONNECT = 1,
@@ -58,11 +60,6 @@ struct tns_redirect {
uint16_t data_len;
};
-struct tns_info {
- /* Scan next DATA|REDIRECT packet */
- bool parse;
-};
-
static int try_number(const char *data, size_t dlen, uint32_t array[],
int array_size, char sep, char term)
{
diff --git a/src/main.c b/src/main.c
index 31e0eed..c6b2600 100644
--- a/src/main.c
+++ b/src/main.c
@@ -175,7 +175,7 @@ int main(int argc, char *argv[])
}
show_usage(argv[0]);
dlog(LOG_ERR, "Missing config filename");
- break;
+ exit(EXIT_FAILURE);
case 'F':
set_operation_mode(&type, REQUEST, argv);
i = set_action_by_table(i, argc, argv,
@@ -309,8 +309,7 @@ int main(int argc, char *argv[])
default:
show_usage(argv[0]);
dlog(LOG_ERR, "Unknown option: %s", argv[i]);
- return 0;
- break;
+ exit(EXIT_FAILURE);
}
}
@@ -319,7 +318,7 @@ int main(int argc, char *argv[])
umask(0177);
- if ((ret = init_config(config_file)) == -1) {
+ if (init_config(config_file) == -1) {
dlog(LOG_ERR, "can't open config file `%s'", config_file);
exit(EXIT_FAILURE);
}
diff --git a/src/network.c b/src/network.c
index 13db37c..2560d97 100644
--- a/src/network.c
+++ b/src/network.c
@@ -113,7 +113,7 @@ void nethdr_track_update_seq(uint32_t seq)
STATE_SYNC(last_seq_recv) = seq;
}
-int nethdr_track_is_seq_set()
+int nethdr_track_is_seq_set(void)
{
return local_seq_set;
}
diff --git a/src/nfct-extensions/helper.c b/src/nfct-extensions/helper.c
index e5d8d0a..894bf26 100644
--- a/src/nfct-extensions/helper.c
+++ b/src/nfct-extensions/helper.c
@@ -180,7 +180,7 @@ static int nfct_cmd_helper_add(struct mnl_socket *nl, int argc, char *argv[])
return -1;
}
- helper = helper_find(CONNTRACKD_LIB_DIR, argv[3], l4proto, RTLD_LAZY);
+ helper = __helper_find(argv[3], l4proto);
if (helper == NULL) {
nfct_perror("that helper is not supported");
return -1;
@@ -430,7 +430,7 @@ nfct_cmd_helper_disable(struct mnl_socket *nl, int argc, char *argv[])
return -1;
}
- helper = helper_find(CONNTRACKD_LIB_DIR, argv[3], l4proto, RTLD_LAZY);
+ helper = __helper_find(argv[3], l4proto);
if (helper == NULL) {
nfct_perror("that helper is not supported");
return -1;
@@ -468,7 +468,187 @@ static struct nfct_extension helper = {
.parse_params = nfct_helper_parse_params,
};
+/*
+ * supported helpers: to set up helpers via nfct, the following definitions are
+ * provided for backward compatibility reasons since conntrackd does not depend
+ * on nfct anymore to set up the userspace helpers.
+ */
+
+static struct ctd_helper amanda_helper = {
+ .name = "amanda",
+ .l4proto = IPPROTO_UDP,
+ .policy = {
+ [0] = {
+ .name = "amanda",
+ .expect_max = 3,
+ .expect_timeout = 180,
+ },
+ },
+};
+
+static struct ctd_helper dhcpv6_helper = {
+ .name = "dhcpv6",
+ .l4proto = IPPROTO_UDP,
+ .policy = {
+ [0] = {
+ .name = "dhcpv6",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
+#include "helpers/ftp.h"
+
+static struct ctd_helper ftp_helper = {
+ .name = "ftp",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = sizeof(struct ftp_info),
+ .policy = {
+ [0] = {
+ .name = "ftp",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
+static struct ctd_helper mdns_helper = {
+ .name = "mdns",
+ .l4proto = IPPROTO_UDP,
+ .priv_data_len = 0,
+ .policy = {
+ [0] = {
+ .name = "mdns",
+ .expect_max = 8,
+ .expect_timeout = 30,
+ },
+ },
+};
+
+#include "helpers/rpc.h"
+
+static struct ctd_helper rpc_helper_tcp = {
+ .name = "rpc",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = sizeof(struct rpc_info),
+ .policy = {
+ {
+ .name = "rpc",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
+static struct ctd_helper rpc_helper_udp = {
+ .name = "rpc",
+ .l4proto = IPPROTO_UDP,
+ .priv_data_len = sizeof(struct rpc_info),
+ .policy = {
+ {
+ .name = "rpc",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
+#include "helpers/sane.h"
+
+static struct ctd_helper sane_helper = {
+ .name = "sane",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = sizeof(struct nf_ct_sane_master),
+ .policy = {
+ [0] = {
+ .name = "sane",
+ .expect_max = 1,
+ .expect_timeout = 5 * 60,
+ },
+ },
+};
+
+static struct ctd_helper slp_helper = {
+ .name = "slp",
+ .l4proto = IPPROTO_UDP,
+ .priv_data_len = 0,
+ .policy = {
+ [0] = {
+ .name = "slp",
+ .expect_max = 8,
+ .expect_timeout = 16, /* default CONFIG_MC_MAX + 1 */
+ },
+ },
+};
+
+static struct ctd_helper ssdp_helper_udp = {
+ .name = "ssdp",
+ .l4proto = IPPROTO_UDP,
+ .priv_data_len = 0,
+ .policy = {
+ [0] = {
+ .name = "ssdp",
+ .expect_max = 8,
+ .expect_timeout = 5 * 60,
+ },
+ },
+};
+
+static struct ctd_helper ssdp_helper_tcp = {
+ .name = "ssdp",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = 0,
+ .policy = {
+ [0] = {
+ .name = "ssdp",
+ .expect_max = 8,
+ .expect_timeout = 5 * 60,
+ },
+ },
+};
+
+static struct ctd_helper tftp_helper = {
+ .name = "tftp",
+ .l4proto = IPPROTO_UDP,
+ .policy = {
+ [0] = {
+ .name = "tftp",
+ .expect_max = 1,
+ .expect_timeout = 5 * 60,
+ },
+ },
+};
+
+#include "helpers/tns.h"
+
+static struct ctd_helper tns_helper = {
+ .name = "tns",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = sizeof(struct tns_info),
+ .policy = {
+ [0] = {
+ .name = "tns",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
static void __init helper_init(void)
{
+ helper_register(&amanda_helper);
+ helper_register(&dhcpv6_helper);
+ helper_register(&ftp_helper);
+ helper_register(&mdns_helper);
+ helper_register(&rpc_helper_tcp);
+ helper_register(&rpc_helper_udp);
+ helper_register(&sane_helper);
+ helper_register(&slp_helper);
+ helper_register(&ssdp_helper_udp);
+ helper_register(&ssdp_helper_tcp);
+ helper_register(&tftp_helper);
+ helper_register(&tns_helper);
+
nfct_extension_register(&helper);
}
diff --git a/src/process.c b/src/process.c
index 3ddad5f..08598ee 100644
--- a/src/process.c
+++ b/src/process.c
@@ -84,7 +84,7 @@ void fork_process_dump(int fd)
int size = 0;
list_for_each_entry(this, &process_list, head) {
- size += snprintf(buf+size, sizeof(buf),
+ size += snprintf(buf + size, sizeof(buf) - size,
"PID=%u type=%s\n",
this->pid,
this->type < CTD_PROC_MAX ?
diff --git a/src/queue.c b/src/queue.c
index 76425b1..e94dc7c 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -69,12 +69,12 @@ void queue_stats_show(int fd)
int size = 0;
char buf[512];
- size += snprintf(buf+size, sizeof(buf),
+ size += snprintf(buf + size, sizeof(buf) - size,
"allocated queue nodes:\t\t%12u\n\n",
qobjects_num);
list_for_each_entry(this, &queue_list, list) {
- size += snprintf(buf+size, sizeof(buf),
+ size += snprintf(buf + size, sizeof(buf) - size,
"queue %s:\n"
"current elements:\t\t%12u\n"
"maximum elements:\t\t%12u\n"
diff --git a/src/read_config_lex.l b/src/read_config_lex.l
index 7dc400a..2708432 100644
--- a/src/read_config_lex.l
+++ b/src/read_config_lex.l
@@ -21,6 +21,7 @@
#include <string.h>
+#include "log.h"
#include "conntrackd.h"
#include "read_config_yy.h"
%}
@@ -174,7 +175,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k]
%%
int
-yywrap()
+yywrap(void)
{
return 1;
}
diff --git a/src/read_config_yy.y b/src/read_config_yy.y
index 95845a1..a116b0b 100644
--- a/src/read_config_yy.y
+++ b/src/read_config_yy.y
@@ -31,19 +31,40 @@
#include "cidr.h"
#include "helper.h"
#include "stack.h"
+#include "log.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
#include <sched.h>
#include <dlfcn.h>
+
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
extern char *yytext;
extern int yylineno;
+int yylex (void);
+int yyerror (const char *msg);
+void yyrestart (FILE *input_file);
+
struct ct_conf conf;
static void __kernel_filter_start(void);
static void __kernel_filter_add_state(int value);
-static void __max_dedicated_links_reached(void);
+
+static struct channel_conf *conf_get_channel(void)
+{
+ if (conf.channel_num >= MULTICHANNEL_MAX) {
+ dlog(LOG_ERR, "too many dedicated links in the configuration "
+ "file (Maximum: %d)", MULTICHANNEL_MAX);
+ exit(EXIT_FAILURE);
+ }
+
+ return &conf.channel[conf.channel_num];
+}
struct stack symbol_stack;
@@ -121,7 +142,7 @@ logfile_path : T_LOG T_PATH_VAL
FILENAME_MAXLEN);
exit(EXIT_FAILURE);
}
- snprintf(conf.logfile, FILENAME_MAXLEN, "%s", $2);
+ snprintf(conf.logfile, sizeof(conf.logfile), "%s", $2);
free($2);
};
@@ -176,7 +197,7 @@ lock : T_LOCK T_PATH_VAL
FILENAME_MAXLEN);
exit(EXIT_FAILURE);
}
- snprintf(conf.lockfile, FILENAME_MAXLEN, "%s", $2);
+ snprintf(conf.lockfile, sizeof(conf.lockfile), "%s", $2);
free($2);
};
@@ -202,6 +223,8 @@ purge: T_PURGE T_NUMBER
multicast_line : T_MULTICAST '{' multicast_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_MCAST) {
dlog(LOG_ERR, "cannot use `Multicast' with other "
@@ -209,13 +232,15 @@ multicast_line : T_MULTICAST '{' multicast_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_MCAST;
- conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED;
+ channel_conf->channel_type = CHANNEL_MCAST;
+ channel_conf->channel_flags = CHANNEL_F_BUFFERED;
conf.channel_num++;
};
multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_MCAST) {
dlog(LOG_ERR, "cannot use `Multicast' with other "
@@ -223,9 +248,8 @@ multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_MCAST;
- conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
- CHANNEL_F_BUFFERED;
+ channel_conf->channel_type = CHANNEL_MCAST;
+ channel_conf->channel_flags = CHANNEL_F_DEFAULT | CHANNEL_F_BUFFERED;
conf.channel_default = conf.channel_num;
conf.channel_num++;
};
@@ -235,15 +259,15 @@ multicast_options :
multicast_option : T_IPV4_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.in)) {
+ if (!inet_aton($2, &channel_conf->u.mcast.in.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
- if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) {
+ if (channel_conf->u.mcast.ipproto == AF_INET6) {
dlog(LOG_WARNING, "your multicast address is IPv4 but "
"is binded to an IPv6 interface? "
"Surely, this is not what you want");
@@ -251,16 +275,15 @@ multicast_option : T_IPV4_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET;
+ channel_conf->u.mcast.ipproto = AF_INET;
};
multicast_option : T_IPV6_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.mcast.in);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.mcast.in);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -270,7 +293,7 @@ multicast_option : T_IPV6_ADDR T_IP
exit(EXIT_FAILURE);
}
- if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET) {
+ if (channel_conf->u.mcast.ipproto == AF_INET) {
dlog(LOG_WARNING, "your multicast address is IPv6 but "
"is binded to an IPv4 interface? "
"Surely this is not what you want");
@@ -278,10 +301,10 @@ multicast_option : T_IPV6_ADDR T_IP
break;
}
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6;
+ channel_conf->u.mcast.ipproto = AF_INET6;
- if (conf.channel[conf.channel_num].channel_ifname[0] &&
- !conf.channel[conf.channel_num].u.mcast.ifa.interface_index6) {
+ if (channel_conf->channel_ifname[0] &&
+ !channel_conf->u.mcast.ifa.interface_index6) {
unsigned int idx;
idx = if_nametoindex($2);
@@ -291,31 +314,31 @@ multicast_option : T_IPV6_ADDR T_IP
break;
}
- conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx;
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6;
+ channel_conf->u.mcast.ifa.interface_index6 = idx;
+ channel_conf->u.mcast.ipproto = AF_INET6;
}
free($2);
};
multicast_option : T_IPV4_IFACE T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.ifa)) {
+ if (!inet_aton($2, &channel_conf->u.mcast.ifa.interface_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) {
+ if (channel_conf->u.mcast.ipproto == AF_INET6) {
dlog(LOG_WARNING, "your multicast interface is IPv4 but "
"is binded to an IPv6 interface? "
"Surely, this is not what you want");
break;
}
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET;
+ channel_conf->u.mcast.ipproto = AF_INET;
};
multicast_option : T_IPV6_IFACE T_IP
@@ -326,11 +349,10 @@ multicast_option : T_IPV6_IFACE T_IP
multicast_option : T_IFACE T_STRING
{
+ struct channel_conf *channel_conf = conf_get_channel();
unsigned int idx;
- __max_dedicated_links_reached();
-
- strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
+ strncpy(channel_conf->channel_ifname, $2, IFNAMSIZ);
idx = if_nametoindex($2);
if (!idx) {
@@ -339,9 +361,9 @@ multicast_option : T_IFACE T_STRING
break;
}
- if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) {
- conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx;
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6;
+ if (channel_conf->u.mcast.ipproto == AF_INET6) {
+ channel_conf->u.mcast.ifa.interface_index6 = idx;
+ channel_conf->u.mcast.ipproto = AF_INET6;
}
free($2);
@@ -349,36 +371,43 @@ multicast_option : T_IFACE T_STRING
multicast_option : T_GROUP T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.port = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.port = $2;
};
multicast_option: T_SNDBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.sndbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.sndbuf = $2;
};
multicast_option: T_RCVBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.rcvbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.rcvbuf = $2;
};
-multicast_option: T_CHECKSUM T_ON
+multicast_option: T_CHECKSUM T_ON
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.checksum = 0;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.checksum = 0;
};
multicast_option: T_CHECKSUM T_OFF
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.checksum = 1;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.checksum = 1;
};
udp_line : T_UDP '{' udp_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_UDP) {
dlog(LOG_ERR, "cannot use `UDP' with other "
@@ -386,13 +415,15 @@ udp_line : T_UDP '{' udp_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_UDP;
- conf.channel[conf.channel_num].channel_type = CHANNEL_UDP;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED;
+ channel_conf->channel_type = CHANNEL_UDP;
+ channel_conf->channel_flags = CHANNEL_F_BUFFERED;
conf.channel_num++;
};
udp_line : T_UDP T_DEFAULT '{' udp_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_UDP) {
dlog(LOG_ERR, "cannot use `UDP' with other "
@@ -400,9 +431,8 @@ udp_line : T_UDP T_DEFAULT '{' udp_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_UDP;
- conf.channel[conf.channel_num].channel_type = CHANNEL_UDP;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
- CHANNEL_F_BUFFERED;
+ channel_conf->channel_type = CHANNEL_UDP;
+ channel_conf->channel_flags = CHANNEL_F_DEFAULT | CHANNEL_F_BUFFERED;
conf.channel_default = conf.channel_num;
conf.channel_num++;
};
@@ -412,24 +442,23 @@ udp_options :
udp_option : T_IPV4_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.server.ipv4)) {
+ if (!inet_aton($2, &channel_conf->u.udp.server.ipv4.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- conf.channel[conf.channel_num].u.udp.ipproto = AF_INET;
+ channel_conf->u.udp.ipproto = AF_INET;
};
udp_option : T_IPV6_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.udp.server.ipv6);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.udp.server.ipv6);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -440,29 +469,28 @@ udp_option : T_IPV6_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6;
+ channel_conf->u.udp.ipproto = AF_INET6;
};
udp_option : T_IPV4_DEST_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.client)) {
+ if (!inet_aton($2, &channel_conf->u.udp.client.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- conf.channel[conf.channel_num].u.udp.ipproto = AF_INET;
+ channel_conf->u.udp.ipproto = AF_INET;
};
udp_option : T_IPV6_DEST_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.udp.client);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.udp.client);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -473,15 +501,15 @@ udp_option : T_IPV6_DEST_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6;
+ channel_conf->u.udp.ipproto = AF_INET6;
};
udp_option : T_IFACE T_STRING
{
+ struct channel_conf *channel_conf = conf_get_channel();
int idx;
- __max_dedicated_links_reached();
- strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
+ strncpy(channel_conf->channel_ifname, $2, IFNAMSIZ);
idx = if_nametoindex($2);
if (!idx) {
@@ -489,43 +517,50 @@ udp_option : T_IFACE T_STRING
free($2);
break;
}
- conf.channel[conf.channel_num].u.udp.server.ipv6.scope_id = idx;
+ channel_conf->u.udp.server.ipv6.scope_id = idx;
free($2);
};
udp_option : T_PORT T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.port = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.port = $2;
};
udp_option: T_SNDBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.sndbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.sndbuf = $2;
};
udp_option: T_RCVBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.rcvbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.rcvbuf = $2;
};
-udp_option: T_CHECKSUM T_ON
+udp_option: T_CHECKSUM T_ON
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.checksum = 0;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.checksum = 0;
};
udp_option: T_CHECKSUM T_OFF
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.checksum = 1;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.checksum = 1;
};
tcp_line : T_TCP '{' tcp_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_TCP) {
dlog(LOG_ERR, "cannot use `TCP' with other "
@@ -533,15 +568,17 @@ tcp_line : T_TCP '{' tcp_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_TCP;
- conf.channel[conf.channel_num].channel_type = CHANNEL_TCP;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED |
- CHANNEL_F_STREAM |
- CHANNEL_F_ERRORS;
+ channel_conf->channel_type = CHANNEL_TCP;
+ channel_conf->channel_flags = CHANNEL_F_BUFFERED |
+ CHANNEL_F_STREAM |
+ CHANNEL_F_ERRORS;
conf.channel_num++;
};
tcp_line : T_TCP T_DEFAULT '{' tcp_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_TCP) {
dlog(LOG_ERR, "cannot use `TCP' with other "
@@ -549,11 +586,11 @@ tcp_line : T_TCP T_DEFAULT '{' tcp_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_TCP;
- conf.channel[conf.channel_num].channel_type = CHANNEL_TCP;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
- CHANNEL_F_BUFFERED |
- CHANNEL_F_STREAM |
- CHANNEL_F_ERRORS;
+ channel_conf->channel_type = CHANNEL_TCP;
+ channel_conf->channel_flags = CHANNEL_F_DEFAULT |
+ CHANNEL_F_BUFFERED |
+ CHANNEL_F_STREAM |
+ CHANNEL_F_ERRORS;
conf.channel_default = conf.channel_num;
conf.channel_num++;
};
@@ -563,24 +600,23 @@ tcp_options :
tcp_option : T_IPV4_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.tcp.server.ipv4)) {
+ if (!inet_aton($2, &channel_conf->u.tcp.server.ipv4.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET;
+ channel_conf->u.tcp.ipproto = AF_INET;
};
tcp_option : T_IPV6_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.tcp.server.ipv6);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.tcp.server.ipv6);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -591,29 +627,28 @@ tcp_option : T_IPV6_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET6;
+ channel_conf->u.tcp.ipproto = AF_INET6;
};
tcp_option : T_IPV4_DEST_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.tcp.client)) {
+ if (!inet_aton($2, &channel_conf->u.tcp.client.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET;
+ channel_conf->u.tcp.ipproto = AF_INET;
};
tcp_option : T_IPV6_DEST_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.tcp.client);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.tcp.client);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -624,15 +659,15 @@ tcp_option : T_IPV6_DEST_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET6;
+ channel_conf->u.tcp.ipproto = AF_INET6;
};
tcp_option : T_IFACE T_STRING
{
+ struct channel_conf *channel_conf = conf_get_channel();
int idx;
- __max_dedicated_links_reached();
- strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
+ strncpy(channel_conf->channel_ifname, $2, IFNAMSIZ);
idx = if_nametoindex($2);
if (!idx) {
@@ -640,44 +675,48 @@ tcp_option : T_IFACE T_STRING
free($2);
break;
}
- conf.channel[conf.channel_num].u.tcp.server.ipv6.scope_id = idx;
+ channel_conf->u.tcp.server.ipv6.scope_id = idx;
free($2);
};
tcp_option : T_PORT T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.port = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.port = $2;
};
tcp_option: T_SNDBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.sndbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.sndbuf = $2;
};
tcp_option: T_RCVBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.rcvbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.rcvbuf = $2;
};
-tcp_option: T_CHECKSUM T_ON
+tcp_option: T_CHECKSUM T_ON
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.checksum = 0;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.checksum = 0;
};
tcp_option: T_CHECKSUM T_OFF
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.checksum = 1;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.checksum = 1;
};
tcp_option: T_ERROR_QUEUE_LENGTH T_NUMBER
{
- __max_dedicated_links_reached();
CONFIG(channelc).error_queue_length = $2;
};
@@ -699,12 +738,12 @@ unix_options:
unix_option : T_PATH T_PATH_VAL
{
- if (strlen($2) > UNIX_PATH_MAX) {
+ if (strlen($2) >= UNIX_PATH_MAX) {
dlog(LOG_ERR, "Path is longer than %u characters",
- UNIX_PATH_MAX);
+ UNIX_PATH_MAX - 1);
exit(EXIT_FAILURE);
}
- snprintf(conf.local.path, UNIX_PATH_MAX, "%s", $2);
+ strcpy(conf.local.path, $2);
free($2);
};
@@ -1052,7 +1091,7 @@ scheduler_line : T_PRIO T_NUMBER
{
conf.sched.prio = $2;
if (conf.sched.prio < 0 || conf.sched.prio > 99) {
- dlog(LOG_ERR, "`Priority' must be [0, 99]\n", $2);
+ dlog(LOG_ERR, "`Priority' must be [0, 99]\n");
exit(EXIT_FAILURE);
}
};
@@ -1228,7 +1267,7 @@ filter_address_item : T_IPV4_ADDR T_IP
}
}
- if (!inet_aton($2, &ip.ipv4)) {
+ if (!inet_aton($2, (struct in_addr *) &ip.ipv4)) {
dlog(LOG_WARNING, "%s is not a valid IPv4, ignoring", $2);
free($2);
break;
@@ -1396,7 +1435,7 @@ stat_logfile_path : T_LOG T_PATH_VAL
FILENAME_MAXLEN);
exit(EXIT_FAILURE);
}
- snprintf(conf.stats.logfile, FILENAME_MAXLEN, "%s", $2);
+ snprintf(conf.stats.logfile, sizeof(conf.stats.logfile), "%s", $2);
free($2);
};
@@ -1622,7 +1661,7 @@ helper_type: T_HELPER_POLICY T_STRING '{' helper_policy_list '}'
}
policy = (struct ctd_helper_policy *) &e->data;
- snprintf(policy->name, CTD_HELPER_NAME_LEN, "%s", $2);
+ snprintf(policy->name, sizeof(policy->name), "%s", $2);
free($2);
/* Now object is complete. */
e->type = SYMBOL_HELPER_POLICY_EXPECT_ROOT;
@@ -1670,7 +1709,7 @@ helper_policy_expect_timeout: T_HELPER_EXPECT_TIMEOUT T_NUMBER
%%
int __attribute__((noreturn))
-yyerror(char *msg)
+yyerror(const char *msg)
{
dlog(LOG_ERR, "parsing config file in line (%d), symbol '%s': %s",
yylineno, yytext, msg);
@@ -1701,15 +1740,6 @@ static void __kernel_filter_add_state(int value)
&filter_proto);
}
-static void __max_dedicated_links_reached(void)
-{
- if (conf.channel_num >= MULTICHANNEL_MAX) {
- dlog(LOG_ERR, "too many dedicated links in the configuration "
- "file (Maximum: %d)", MULTICHANNEL_MAX);
- exit(EXIT_FAILURE);
- }
-}
-
int
init_config(char *filename)
{
diff --git a/src/run.c b/src/run.c
index f11a532..37a0eb1 100644
--- a/src/run.c
+++ b/src/run.c
@@ -67,7 +67,7 @@ void killer(int signo)
close_log();
sd_ct_stop();
- exit(0);
+ _exit(0);
}
static void child(int foo)
diff --git a/src/vector.c b/src/vector.c
index c81e7ce..92a5436 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -60,13 +60,16 @@ void vector_destroy(struct vector *v)
int vector_add(struct vector *v, void *data)
{
+ void *ptr;
+
if (v->cur_elems >= v->max_elems) {
v->max_elems += DEFAULT_VECTOR_GROWTH;
- v->data = realloc(v->data, v->max_elems * v->size);
- if (v->data == NULL) {
+ ptr = realloc(v->data, v->max_elems * v->size);
+ if (!ptr) {
v->max_elems -= DEFAULT_VECTOR_GROWTH;
return -1;
}
+ v->data = ptr;
}
memcpy(v->data + (v->size * v->cur_elems), data, v->size);
v->cur_elems++;
diff --git a/tests/conntrack/load-stress.sh b/tests/conntrack/load-stress.sh
new file mode 100644
index 0000000..597c4c6
--- /dev/null
+++ b/tests/conntrack/load-stress.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+SPORT_COUNT=128
+DPORT_COUNT=128
+
+function ct_data_gen()
+{
+ for (( d = 1; d <= $DPORT_COUNT; d++ )) do
+ for (( s = 1; s <= $SPORT_COUNT; s++ )) do
+ ip netns exec ct-ns-test conntrack -I -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport ${s} --dport ${d} --state LISTEN -u SEEN_REPLY -t 300 &> /dev/null
+ if [ $? -ne 0 ]
+ then
+ echo "[FAILED] cannot insert conntrack entries"
+ exit 1
+ fi
+ done
+ done
+}
+
+ip netns add ct-ns-test
+
+if [ $UID -ne 0 ]
+then
+ echo "Run this test as root"
+ exit 1
+fi
+
+echo "Creating conntrack entries, please wait..."
+ct_data_gen
+ip netns exec ct-ns-test conntrack -U -p tcp -m 1
+if [ $? -ne 0 ]
+then
+ echo "[FAILED] cannot update conntrack entries"
+ exit 1
+fi
+
+COUNT=`ip netns exec ct-ns-test conntrack -L | wc -l`
+if [ $COUNT -ne 16384 ]
+then
+ echo "$COUNT entries, expecting 131072"
+ exit 1
+fi
+
+ip netns exec ct-ns-test conntrack -F
+if [ $? -ne 0 ]
+then
+ echo "[FAILED] faild to flush conntrack entries"
+ exit 1
+fi
+
+COUNT=`ip netns exec ct-ns-test conntrack -L | wc -l`
+if [ $COUNT -ne 0 ]
+then
+ echo "$COUNT entries, expecting 0"
+ exit 1
+fi
+
+ip netns del ct-ns-test
+
+echo "[OK] test successful"
+
+exit 0
diff --git a/tests/conntrack/testsuite/00create b/tests/conntrack/testsuite/00create
index 911e711..af22f18 100644
--- a/tests/conntrack/testsuite/00create
+++ b/tests/conntrack/testsuite/00create
@@ -34,3 +34,40 @@
-I -t 29 -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ; OK
# delete icmp ping request entry
-D -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ; OK
+# Test protocols unknown by the conntrack tool
+# IGMP
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2 ; OK
+# Create again - should fail
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2 ; BAD
+# repeat using protocol name instead of the value, should fail as well
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p igmp ; BAD
+# delete
+-D -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2 ; OK
+# delete again should fail
+-D -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2 ; BAD
+# create using protocol name instead of the value
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p igmp ; OK
+# update
+-U -t 11 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2 ; OK
+# delete
+-D -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2 ; OK
+# delete again should fail
+-D -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p igmp ; BAD
+# take some protocol that is not normally not in /etc/protocols
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 200 ; OK
+# update
+-U -t 11 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 200 ; OK
+# delete
+-D -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 200 ; OK
+# delete again
+-D -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 200 ; BAD
+# Invalid protocol values
+# 256 should fail
+-I -t 10 -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p 256 ; BAD
+# take some invalid protocol name
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p foo ; BAD
+# take some other invalid protocol values
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p -10 ; BAD
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2000 ; BAD
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 20foo ; BAD
+-I -t 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p foo20 ; BAD
diff --git a/tests/conntrack/testsuite/08stdin b/tests/conntrack/testsuite/08stdin
index 1d31176..158c4c3 100644
--- a/tests/conntrack/testsuite/08stdin
+++ b/tests/conntrack/testsuite/08stdin
@@ -77,4 +77,49 @@
-D -w 123 ;
-R - ; OK
# validate it via standard command line way
--D -w 123 ; BAD \ No newline at end of file
+-D -w 123 ; BAD
+# create with -A
+# create a conntrack
+-A -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ;
+# create from reply
+-A -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 --state LISTEN -u SEEN_REPLY -t 50 ;
+# create a v6 conntrack
+-A -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ;
+# creae icmp ping request entry
+-A -t 29 -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ;
+-R - ; OK
+# create again
+-I -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD
+-I -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 --state LISTEN -u SEEN_REPLY -t 50 ; BAD
+-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD
+-I -t 29 -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ; BAD
+# repeat, it should succeed
+-A -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ;
+# create from reply
+-A -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 --state LISTEN -u SEEN_REPLY -t 50 ;
+# create a v6 conntrack
+-A -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ;
+# creae icmp ping request entry
+-A -t 29 -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ;
+-R - ; OK
+# delete
+-D -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 ;
+# empty lines should be just ignored
+;
+;
+# delete reverse
+-D -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 ;
+# empty lines with spaces or tabs should be ignored as well
+ ;
+ ;
+ ;
+ ;
+ ;
+ ;
+# delete v6 conntrack
+-D -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 ;
+# delete icmp ping request entry
+-D -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ;
+;
+;
+-R - ; OK
diff --git a/tests/conntrack/testsuite/09dumpopt b/tests/conntrack/testsuite/09dumpopt
index 447590b..c1e0e6e 100644
--- a/tests/conntrack/testsuite/09dumpopt
+++ b/tests/conntrack/testsuite/09dumpopt
@@ -145,3 +145,29 @@
-D -w 11 -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ; OK
# clean up after yourself
-D -w 10 ; OK
+# Cover protocols unknown to the conntrack tool
+# Create a conntrack entries
+# IGMP
+-I -w 10 -t 59 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2 ;
+# Some fency protocol
+-I -w 10 -t 59 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 200 ;
+# Some fency protocol with IPv6
+-I -w 10 -t 59 -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p 200 ;
+-R - ; OK
+# copy to zone 11
+-L -w 10 -o save ; |s/-w 10/-w 11/g
+-R - ; OK
+# Delete stuff in zone 10, should succeed
+# IGMP
+-D -w 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2 ; OK
+# Some fency protocol
+-D -w 10 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 200 ; OK
+# Some fency protocol with IPv6
+-D -w 10 -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p 200 ; OK
+# Delete stuff in zone 11, should succeed
+# IGMP
+-D -w 11 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 2 ; OK
+# Some fency protocol
+-D -w 11 -s 0.0.0.0 -d 224.0.0.22 -r 224.0.0.22 -q 0.0.0.0 -p 200 ; OK
+# Some fency protocol with IPv6
+-D -w 11 -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p 200 ; OK
diff --git a/tests/conntrack/testsuite/10add b/tests/conntrack/testsuite/10add
new file mode 100644
index 0000000..4f9f3b9
--- /dev/null
+++ b/tests/conntrack/testsuite/10add
@@ -0,0 +1,42 @@
+#missing destination
+-A -s 1.1.1.1 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD
+#missing source
+-A -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD
+#missing protocol
+-A -s 1.1.1.1 -d 2.2.2.2 --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD
+#missing source port
+-A -s 1.1.1.1 -d 2.2.2.2 -p tcp --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD
+#missing destination port
+-A -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD
+#missing timeout
+-A -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY ; BAD
+# create a conntrack
+-A -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK
+# create again
+-A -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK
+# delete
+-D -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 ; OK
+# delete again
+-D -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 ; BAD
+# create from reply
+-A -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 --state LISTEN -u SEEN_REPLY -t 50 ; OK
+# create again from reply
+-A -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 --state LISTEN -u SEEN_REPLY -t 50 ; OK
+# delete reverse
+-D -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 ; OK
+# delete reverse again
+-D -r 2.2.2.2 -q 1.1.1.1 -p tcp --reply-port-src 11 --reply-port-dst 21 ; BAD
+# create a v6 conntrack
+-A -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK
+# create again a v6 conntrack
+-A -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK
+# delete v6 conntrack
+-D -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 ; OK
+# mismatched address family
+-A -s 2001:DB8::1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD
+# creae icmp ping request entry
+-A -t 29 -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ; OK
+# creae again icmp ping request entry
+-A -t 29 -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ; OK
+# delete icmp ping request entry
+-D -u SEEN_REPLY -s 1.1.1.1 -d 2.2.2.2 -r 2.2.2.2 -q 1.1.1.1 -p icmp --icmp-type 8 --icmp-code 0 --icmp-id 1226 ; OK