summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--configure.in2
-rw-r--r--conntrack.827
-rw-r--r--include/conntrack.h12
-rw-r--r--qa/test-conntrack.c18
-rw-r--r--qa/testsuite/00create4
-rw-r--r--qa/testsuite/01delete8
-rw-r--r--qa/testsuite/02filter20
-rw-r--r--src/conntrack.c92
9 files changed, 120 insertions, 66 deletions
diff --git a/ChangeLog b/ChangeLog
index f15849b..d6fbe30 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,7 +14,10 @@ o simplify parameter-handling code
o check for missing source/address IP/ports in creation and get operations
o way more flexible conntrack updates and deletions
o fix NAT filtering via --src-nat and --dst-nat (reported by K.Oledzki)
+o recover the ID support
o show display counters to stderr
+o enable filtering by status and ID
+o update manpage
o minor cleanups
= conntrackd =
diff --git a/configure.in b/configure.in
index 46dd7b8..17101e9 100644
--- a/configure.in
+++ b/configure.in
@@ -18,7 +18,7 @@ esac
dnl Dependencies
LIBNFNETLINK_REQUIRED=0.0.32
-LIBNETFILTER_CONNTRACK_REQUIRED=0.0.91
+LIBNETFILTER_CONNTRACK_REQUIRED=0.0.92
AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes)
if test "x$HAVE_PKG_CONFIG" = "x"
diff --git a/conntrack.8 b/conntrack.8
index 670770a..9fb9508 100644
--- a/conntrack.8
+++ b/conntrack.8
@@ -73,9 +73,8 @@ Flush the whole given table
Atomically zero counters after reading them. This option is only valid in
combination with the "-L, --dump" command options.
.TP
-.BI "-o, --output [extended,xml,timestamp] "
-Display output in a certain format. This option is only valid in combination
-with the "-L, --dump", "-E, --event" and "-G, --get" command options.
+.BI "-o, --output [extended,xml,timestamp,id] "
+Display output in a certain format.
.TP
.BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]"
Set the bitmask of events that are to be generated by the in-kernel ctnetlink
@@ -136,10 +135,10 @@ Specify the destination address mask of an expectation.
.TP
TCP-specific fields:
.TP
-.BI "--orig-port-src " "PORT"
+.BI "--sport, --orig-port-src " "PORT"
Source port in original direction
.TP
-.BI "--orig-port-dst " "PORT"
+.BI "--dport, --orig-port-dst " "PORT"
Destination port in original direction
.TP
.BI "--reply-port-src " "PORT"
@@ -153,10 +152,10 @@ TCP state
.TP
UDP-specific fields:
.TP
-.BI "--orig-port-src " "PORT"
+.BI "--sport, --orig-port-src " "PORT"
Source port in original direction
.TP
-.BI "--orig-port-dst " "PORT"
+.BI "--dport, --orig-port-dst " "PORT"
Destination port in original direction
.TP
.BI "--reply-port-src " "PORT"
@@ -182,22 +181,28 @@ cause an exit code of 1.
.SH EXAMPLES
.TP
.B conntrack \-L
-Dump the connection tracking table in /proc/net/ip_conntrack format
+Show the connection tracking table in /proc/net/ip_conntrack format
.TP
.B conntrack \-L -o extended
-Dump the connection tracking table in /proc/net/nf_conntrack format
+Show the connection tracking table in /proc/net/nf_conntrack format
.TP
.B conntrack \-L \-o xml
-Dump the connection tracking table in XML
+Show the connection tracking table in XML
.TP
.B conntrack \-L -f ipv6 -o extended
Only dump IPv6 connections in /proc/net/nf_conntrack format
.TP
.B conntrack \-L --src-nat
-Dump source NAT connections
+Show source NAT connections
.TP
.B conntrack \-E \-o timestamp
Show connection events together with the timestamp
+.TP
+.B conntrack \-D \-s 1.2.3.4
+Delete all flow whose source address is 1.2.3.4
+.TP
+.B conntrack \-U \-s 1.2.3.4 \-m 1
+Set connmark to 1 of all the flows whose source address is 1.2.3.4
.SH BUGS
Bugs? What's this ;-)
.SH SEE ALSO
diff --git a/include/conntrack.h b/include/conntrack.h
index 9e005d9..2e17475 100644
--- a/include/conntrack.h
+++ b/include/conntrack.h
@@ -138,14 +138,10 @@ enum options {
#define NUMBER_OF_OPT CT_OPT_MAX+1
enum {
- _O_XML_BIT = 0,
- _O_XML = (1 << _O_XML_BIT),
-
- _O_EXT_BIT = 1,
- _O_EXT = (1 << _O_EXT_BIT),
-
- _O_TMS_BIT = 2,
- _O_TMS = (1 << _O_TMS_BIT),
+ _O_XML = (1 << 0),
+ _O_EXT = (1 << 1),
+ _O_TMS = (1 << 2),
+ _O_ID = (1 << 3),
};
struct ctproto_handler {
diff --git a/qa/test-conntrack.c b/qa/test-conntrack.c
index c58aa8d..c9097b6 100644
--- a/qa/test-conntrack.c
+++ b/qa/test-conntrack.c
@@ -21,7 +21,7 @@
int main()
{
- int ret, ok = 0, bad = 0;
+ int ret, ok = 0, bad = 0, line;
FILE *fp;
DIR *d;
char buf[1024];
@@ -34,6 +34,8 @@ int main()
sprintf(file, "testsuite/%s", dent->d_name);
+ line = 0;
+
fp = fopen(file, "r");
if (fp == NULL) {
perror("cannot find testsuite file");
@@ -44,15 +46,22 @@ int main()
char tmp[1024] = CT_PROG, *res;
tmp[strlen(CT_PROG)] = ' ';
+ line++;
+
if (buf[0] == '#' || buf[0] == ' ')
continue;
res = strchr(buf, ';');
+ if (!res) {
+ printf("malformed file %s at line %d\n",
+ dent->d_name, line);
+ exit(EXIT_FAILURE);
+ }
*res = '\0';
res+=2;
strcpy(tmp + strlen(CT_PROG) + 1, buf);
- printf("Executing: %s\n", tmp);
+ printf("(%d) Executing: %s\n", line, tmp);
ret = system(tmp);
@@ -75,10 +84,11 @@ int main()
printf("^----- BAD\n");
}
}
+ printf("=====\n");
}
+ fclose(fp);
}
+ closedir(d);
fprintf(stdout, "OK: %d BAD: %d\n", ok, bad);
-
- fclose(fp);
}
diff --git a/qa/testsuite/00create b/qa/testsuite/00create
index 7af7d37..40e2c19 100644
--- a/qa/testsuite/00create
+++ b/qa/testsuite/00create
@@ -12,5 +12,9 @@
-I -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
-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
+# delete
+-D -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 ; OK
# create from reply
-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 ; 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
diff --git a/qa/testsuite/01delete b/qa/testsuite/01delete
index dd3ca8b..3c38ac5 100644
--- a/qa/testsuite/01delete
+++ b/qa/testsuite/01delete
@@ -1,2 +1,6 @@
-# delete
--D -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 ; OK
+# create dummy
+-I -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 bad source
+-D -s 2.2.2.2 -p tcp --sport 10 --dport 20 ; BAD
+# delete by source
+-D -s 1.1.1.1 ; OK
diff --git a/qa/testsuite/02filter b/qa/testsuite/02filter
new file mode 100644
index 0000000..1ae9abd
--- /dev/null
+++ b/qa/testsuite/02filter
@@ -0,0 +1,20 @@
+# create dummy
+conntrack -I -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK
+# filter by source
+conntrack -L -s 1.1.1.1 ; OK
+# filter by destination
+conntrack -L -d 2.2.2.2 ; OK
+# filter by protocol
+conntrack -L -p tcp ; OK
+# filter by status
+conntrack -L -u SEEN_REPLY ; OK
+# filter by TCP protocol state
+conntrack -L -p tcp --state LISTEN ; OK
+# update mark of dummy conntrack
+conntrack -U -s 1.1.1.1 -m 1 ; OK
+# filter by mark
+conntrack -L -m 1 ; OK
+# filter by layer 3 protocol
+conntrack -L -f ipv4 ; OK
+# delete dummy
+conntrack -D -d 2.2.2.2 ; OK
diff --git a/src/conntrack.c b/src/conntrack.c
index 2dfb601..9ab4558 100644
--- a/src/conntrack.c
+++ b/src/conntrack.c
@@ -121,7 +121,7 @@ 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 */
-/*CT_LIST*/ {2,2,2,2,2,0,0,2,0,0,0,0,0,0,2,2,2,2,2,2,2},
+/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2},
/*CT_CREATE*/ {2,2,2,2,1,1,1,0,0,0,0,0,0,2,2,0,0,2,2,0,2},
/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2},
/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2},
@@ -130,7 +130,7 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2},
/*VERSION*/ {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},
-/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,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,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},
/*EXP_DELETE*/{1,1,2,2,1,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},
@@ -143,7 +143,7 @@ static LIST_HEAD(proto_list);
static unsigned int options;
#define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | CT_OPT_MARK |\
- CT_OPT_SECMARK)
+ CT_OPT_SECMARK | CT_OPT_STATUS | CT_OPT_ID)
void register_proto(struct ctproto_handler *h)
{
@@ -328,8 +328,8 @@ static struct parse_parameter {
{ {"ALL", "NEW", "UPDATES", "DESTROY"}, 4,
{~0U, NF_NETLINK_CONNTRACK_NEW, NF_NETLINK_CONNTRACK_UPDATE,
NF_NETLINK_CONNTRACK_DESTROY} },
- { {"xml", "extended", "timestamp" }, 3,
- { _O_XML, _O_EXT, _O_TMS },
+ { {"xml", "extended", "timestamp", "id" }, 4,
+ { _O_XML, _O_EXT, _O_TMS, _O_ID },
},
};
@@ -603,13 +603,13 @@ static int ignore_nat(const struct nf_conntrack *obj,
return 0;
}
-static int events_counter;
+static int counter;
static void __attribute__((noreturn))
event_sighandler(int s)
{
fprintf(stderr, "%s v%s: ", PROGNAME, VERSION);
- fprintf(stderr, "%d flow events has been shown.\n", events_counter);
+ fprintf(stderr, "%d flow events has been shown.\n", counter);
nfct_close(cth);
exit(0);
}
@@ -640,19 +640,19 @@ static int event_cb(enum nf_conntrack_msg_type type,
printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec);
} else
op_flags |= NFCT_OF_TIME;
- }
+ }
+ if (output_mask & _O_ID)
+ op_flags |= NFCT_OF_ID;
nfct_snprintf(buf, 1024, ct, type, op_type, op_flags);
printf("%s\n", buf);
fflush(stdout);
- events_counter++;
+ counter++;
return NFCT_CB_CONTINUE;
}
-static int list_counter;
-
static int dump_cb(enum nf_conntrack_msg_type type,
struct nf_conntrack *ct,
void *data)
@@ -672,17 +672,17 @@ static int dump_cb(enum nf_conntrack_msg_type type,
op_type = NFCT_O_XML;
if (output_mask & _O_EXT)
op_flags = NFCT_OF_SHOW_LAYER3;
+ if (output_mask & _O_ID)
+ op_flags |= NFCT_OF_ID;
nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags);
printf("%s\n", buf);
- list_counter++;
+ counter++;
return NFCT_CB_CONTINUE;
}
-static int delete_counter;
-
static int delete_cb(enum nf_conntrack_msg_type type,
struct nf_conntrack *ct,
void *data)
@@ -709,17 +709,17 @@ static int delete_cb(enum nf_conntrack_msg_type type,
op_type = NFCT_O_XML;
if (output_mask & _O_EXT)
op_flags = NFCT_OF_SHOW_LAYER3;
+ if (output_mask & _O_ID)
+ op_flags |= NFCT_OF_ID;
nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags);
printf("%s\n", buf);
- delete_counter++;
+ counter++;
return NFCT_CB_CONTINUE;
}
-static int update_counter;
-
static int update_cb(enum nf_conntrack_msg_type type,
struct nf_conntrack *ct,
void *data)
@@ -737,6 +737,10 @@ static int update_cb(enum nf_conntrack_msg_type type,
if (ignore_nat(tmp, ct))
return NFCT_CB_CONTINUE;
+ if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) &&
+ nfct_get_attr_u32(obj, ATTR_ID) != nfct_get_attr_u32(ct, ATTR_ID))
+ return NFCT_CB_CONTINUE;
+
if (options & CT_OPT_TUPLE_ORIG && !nfct_cmp(tmp, ct, NFCT_CMP_ORIG))
return NFCT_CB_CONTINUE;
if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(tmp, ct, NFCT_CMP_REPL))
@@ -754,11 +758,13 @@ static int update_cb(enum nf_conntrack_msg_type type,
op_type = NFCT_O_XML;
if (output_mask & _O_EXT)
op_flags = NFCT_OF_SHOW_LAYER3;
+ if (output_mask & _O_ID)
+ op_flags |= NFCT_OF_ID;
nfct_snprintf(buf, 1024, ct, NFCT_T_UNKNOWN, op_type, op_flags);
printf("%s\n", buf);
- update_counter++;
+ counter++;
return NFCT_CB_CONTINUE;
}
@@ -801,6 +807,7 @@ static const int opt2type[] = {
['g'] = CT_OPT_DST_NAT,
['m'] = CT_OPT_MARK,
['c'] = CT_OPT_SECMARK,
+ ['i'] = CT_OPT_ID,
};
static const int opt2family_attr[][2] = {
@@ -821,6 +828,18 @@ static const int opt2attr[] = {
['q'] = ATTR_REPL_L3PROTO,
['m'] = ATTR_MARK,
['c'] = ATTR_SECMARK,
+ ['i'] = ATTR_ID,
+};
+
+static char exit_msg[][64] = {
+ [CT_LIST_BIT] = "%d flow entries has been shown.\n",
+ [CT_CREATE_BIT] = "%d flow entries has been created.\n",
+ [CT_UPDATE_BIT] = "%d flow entries has been updated.\n",
+ [CT_DELETE_BIT] = "%d flow entries has been deleted.\n",
+ [CT_GET_BIT] = "%d flow entries has been shown.\n",
+ [CT_EVENT_BIT] = "%d flow events has been shown.\n",
+ [EXP_LIST_BIT] = "%d expectations has been shown.\n",
+ [EXP_DELETE_BIT] = "%d expectations has been shown.\n",
};
int main(int argc, char *argv[])
@@ -853,7 +872,7 @@ int main(int argc, char *argv[])
register_icmpv6();
while ((c = getopt_long(argc, argv, "L::I::U::D::G::E::F::hVs:d:r:q:"
- "p:t:u:e:a:z[:]:{:}:m:i::f:o:n::"
+ "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::"
"g::c:",
opts, NULL)) != -1) {
switch(c) {
@@ -999,6 +1018,7 @@ int main(int argc, char *argv[])
nat_parse(tmp, 1, obj, opt2type[c]);
break;
}
+ case 'i':
case 'm':
case 'c':
options |= opt2type[c];
@@ -1006,9 +1026,10 @@ int main(int argc, char *argv[])
exit_error(PARAMETER_PROBLEM,
"-%c requires value", c);
- nfct_set_attr_u32(obj, opt2attr[c], atol(optarg));
+ nfct_set_attr_u32(obj,
+ opt2attr[c],
+ strtoul(optarg, NULL, 0));
break;
- case 'i':
case 'a':
fprintf(stderr, "WARNING: ignoring -%c, "
"deprecated option.\n", c);
@@ -1084,10 +1105,6 @@ int main(int argc, char *argv[])
res = nfct_query(cth, NFCT_Q_DUMP, &family);
nfct_close(cth);
-
- fprintf(stderr, "%s v%s: ", PROGNAME, VERSION);
- fprintf(stderr, "%d flow entries has been shown.\n",
- list_counter);
break;
case EXP_LIST:
@@ -1111,10 +1128,9 @@ int main(int argc, char *argv[])
exit_error(OTHER_PROBLEM, "Can't open handler");
res = nfct_query(cth, NFCT_Q_CREATE, obj);
+ if (res != -1)
+ counter++;
nfct_close(cth);
- fprintf(stderr, "%s v%s: ", PROGNAME, VERSION);
- fprintf(stderr, "%d flow entry has been created.\n",
- res == -1 ? 0 : 1);
break;
case EXP_CREATE:
@@ -1142,10 +1158,6 @@ int main(int argc, char *argv[])
res = nfct_query(cth, NFCT_Q_DUMP, &family);
nfct_close(ith);
nfct_close(cth);
-
- fprintf(stderr, "%s v%s: ", PROGNAME, VERSION);
- fprintf(stderr, "%d flow entries has been updated.\n",
- update_counter);
break;
case CT_DELETE:
@@ -1159,10 +1171,6 @@ int main(int argc, char *argv[])
res = nfct_query(cth, NFCT_Q_DUMP, &family);
nfct_close(ith);
nfct_close(cth);
-
- fprintf(stderr, "%s v%s: ", PROGNAME, VERSION);
- fprintf(stderr, "%d flow entries has been deleted.\n",
- delete_counter);
break;
case EXP_DELETE:
@@ -1184,9 +1192,6 @@ int main(int argc, char *argv[])
nfct_callback_register(cth, NFCT_T_ALL, dump_cb, obj);
res = nfct_query(cth, NFCT_Q_GET, obj);
nfct_close(cth);
- fprintf(stderr, "%s v%s: ", PROGNAME, VERSION);
- fprintf(stderr, "%d flow entry has been shown.\n",
- res == -1 ? 0 : 1);
break;
case EXP_GET:
@@ -1268,5 +1273,12 @@ int main(int argc, char *argv[])
exit_error(OTHER_PROBLEM, "Operation failed: %s",
err2str(errno, command));
- return 0;
+ if (exit_msg[cmd][0]) {
+ fprintf(stderr, "%s v%s: ", PROGNAME, VERSION);
+ fprintf(stderr, exit_msg[cmd], counter);
+ if (counter == 0 && !(command & (CT_LIST | EXP_LIST)))
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
}