summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac6
-rw-r--r--conntrack.817
-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/conntrack.h68
-rw-r--r--include/local.h4
-rw-r--r--nfct.82
-rw-r--r--src/Makefile.am80
-rw-r--r--src/conntrack.c277
-rw-r--r--src/main.c5
-rw-r--r--src/network.c2
-rw-r--r--src/read_config_lex.l3
-rw-r--r--src/read_config_yy.y280
-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
27 files changed, 781 insertions, 463 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/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/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 */
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 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 666f5e3..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';
@@ -882,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;
@@ -901,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) {
@@ -1091,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 "
@@ -1803,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;
@@ -1977,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)
@@ -1995,47 +1962,6 @@ 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];
-
- 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 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,
@@ -2063,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);
@@ -2258,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 */
@@ -2959,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;
}
@@ -3012,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':
@@ -3083,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':
@@ -3295,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) {
@@ -3368,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))
@@ -3380,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:
@@ -3450,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:
@@ -3558,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;
@@ -3896,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));
@@ -3912,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);
diff --git a/src/main.c b/src/main.c
index de4773d..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);
}
}
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/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