From 953bcf62fbd110f63c946905f9642d17b63c50cf Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 16 Apr 2008 14:54:24 +0000 Subject: 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 --- ChangeLog | 3 ++ configure.in | 2 +- conntrack.8 | 27 +++++++++------ include/conntrack.h | 12 +++---- qa/test-conntrack.c | 18 +++++++--- qa/testsuite/00create | 4 +++ qa/testsuite/01delete | 8 +++-- qa/testsuite/02filter | 20 +++++++++++ src/conntrack.c | 92 +++++++++++++++++++++++++++++---------------------- 9 files changed, 120 insertions(+), 66 deletions(-) create mode 100644 qa/testsuite/02filter 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; } -- cgit v1.2.3