diff options
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | conntrack.8 | 17 | ||||
-rw-r--r-- | conntrackd.conf.5 | 4 | ||||
-rw-r--r-- | extensions/libct_proto_dccp.c | 33 | ||||
-rw-r--r-- | extensions/libct_proto_gre.c | 33 | ||||
-rw-r--r-- | extensions/libct_proto_icmp.c | 33 | ||||
-rw-r--r-- | extensions/libct_proto_icmpv6.c | 33 | ||||
-rw-r--r-- | extensions/libct_proto_sctp.c | 33 | ||||
-rw-r--r-- | extensions/libct_proto_tcp.c | 33 | ||||
-rw-r--r-- | extensions/libct_proto_udp.c | 33 | ||||
-rw-r--r-- | extensions/libct_proto_udplite.c | 33 | ||||
-rw-r--r-- | include/conntrack.h | 68 | ||||
-rw-r--r-- | include/local.h | 4 | ||||
-rw-r--r-- | nfct.8 | 2 | ||||
-rw-r--r-- | src/Makefile.am | 80 | ||||
-rw-r--r-- | src/conntrack.c | 217 | ||||
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/network.c | 2 | ||||
-rw-r--r-- | src/read_config_lex.l | 3 | ||||
-rw-r--r-- | src/read_config_yy.y | 280 | ||||
-rw-r--r-- | src/vector.c | 7 | ||||
-rw-r--r-- | tests/conntrack/load-stress.sh | 62 | ||||
-rw-r--r-- | tests/conntrack/testsuite/08stdin | 47 | ||||
-rw-r--r-- | tests/conntrack/testsuite/09dumpopt | 26 | ||||
-rw-r--r-- | tests/conntrack/testsuite/10add | 42 |
25 files changed, 718 insertions, 418 deletions
diff --git a/configure.ac b/configure.ac index d9d351b..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])]) @@ -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]) ]) diff --git a/conntrack.8 b/conntrack.8 index 0db427b..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]" @@ -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. @@ -175,7 +180,7 @@ 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. @@ -186,8 +191,12 @@ 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 the selected conntracks. -This option is only available in conjunction with "\-I, \-\-create" or -"\-U, \-\-update". +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. 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/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/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 */ @@ -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 a1a91a0..352aa37 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,18 @@ BUILT_SOURCES = read_config_yy.h 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 @@ -35,22 +46,54 @@ if HAVE_CTHELPER nfct_LDADD += ${LIBNETFILTER_CTHELPER_LIBS} endif -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 @@ -60,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/conntrack.c b/src/conntrack.c index e381543..0d71352 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -139,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) @@ -153,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), @@ -353,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'}, @@ -396,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:<:>::(:):"; @@ -413,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] = { @@ -446,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[] = { @@ -549,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[] = @@ -593,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" @@ -800,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: @@ -817,7 +763,6 @@ static int ct_save_snprintf(char *buf, size_t len, BUFFER_SIZE(ret, size, len, offset); break; default: - ret = 0; break; } @@ -860,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) @@ -870,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'; @@ -884,12 +837,11 @@ extern struct ctproto_handler ct_proto_unknown; static int parse_proto_num(const char *str) { + unsigned long val; char *endptr; - long val; - val = strtol(str, &endptr, 0); - if (val >= IPPROTO_MAX || - val < 0 || + val = strtoul(str, &endptr, 0); + if (val > IPPROTO_RAW || endptr == str || *endptr != '\0') return -1; @@ -1106,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 " @@ -1818,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; @@ -1992,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 (nlh->nlmsg_pid) { + if (nlh->nlmsg_pid && !(output_mask & _O_XML)) { char *prog = get_progname(nlh->nlmsg_pid); if (prog) @@ -2037,10 +1989,14 @@ static int mnl_nfct_delete_cb(const struct nlmsghdr *nlh, void *data) 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) + 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); @@ -2232,15 +2188,26 @@ static int mnl_nfct_update_cb(const struct nlmsghdr *nlh, void *data) if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) goto destroy_ok; - res = nfct_mnl_request(modifier_sock, NFNL_SUBSYS_CTNETLINK, cmd->family, + 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) { - fprintf(stderr, "Operation failed: %s\n", - err2str(errno, CT_UPDATE)); + /* 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)); } - res = nfct_mnl_request(modifier_sock, NFNL_SUBSYS_CTNETLINK, cmd->family, - IPCTNL_MSG_CT_GET, NLM_F_ACK, + 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) { /* the entry has vanish in middle of the update */ @@ -2933,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; } @@ -2986,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': @@ -3057,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': @@ -3269,6 +3233,7 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd, 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) { @@ -3342,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)) @@ -3354,13 +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)); + if (cmd->command == CT_CREATE) + nl_flags = NLM_F_EXCL; + res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, cmd->family, IPCTNL_MSG_CT_NEW, - NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL, + NLM_F_CREATE | NLM_F_ACK | nl_flags, NULL, cmd->tmpl.ct, NULL); if (res >= 0) counter++; - break; case EXP_CREATE: @@ -3425,7 +3393,7 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd, case CT_GET: res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, cmd->family, - IPCTNL_MSG_CT_GET, NLM_F_ACK, + IPCTNL_MSG_CT_GET, 0, mnl_nfct_dump_cb, cmd->tmpl.ct, cmd); break; @@ -3528,7 +3496,7 @@ 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(event_sock->mnl); break; @@ -3866,7 +3834,8 @@ int main(int argc, char *argv[]) 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)); @@ -3882,8 +3851,8 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "OOM"); do_parse(cmd, argc, argv); - do_command_ct(argv[0], cmd, sock); - res = print_stats(cmd); + res = do_command_ct(argv[0], cmd, sock); + res |= print_stats(cmd); free(cmd); } nfct_mnl_socket_close(sock); @@ -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); } } 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/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 5815d6a..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; @@ -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, sizeof(conf.local.path), "%s", $2); + strcpy(conf.local.path, $2); free($2); }; @@ -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; @@ -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/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/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 |