From aa925010951e79a860d0c1e4365f72d68eedf02d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 14 Feb 2012 03:17:56 +0100 Subject: conntrack: allow to filter by mark from kernel-space This patch uses the new infrastructure that allows us to filter by mark from kernel-space. This change ensures backward compatibility with kernels with no support for filtering by mark (Linux kernel <= 3.4.x). This requires lastest libnetfilter_conntrack library. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 31beba5..b065211 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1,5 +1,6 @@ /* - * (C) 2005-2008 by Pablo Neira Ayuso + * (C) 2005-2012 by Pablo Neira Ayuso + * (C) 2012 by Intra2net AG * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,6 +73,9 @@ static struct { /* Allows filtering/setting specific bits in the ctmark */ struct u32_mask mark; + + /* Allow to filter by mark from kernel-space. */ + struct nfct_filter_dump_mark filter_mark_kernel; } tmpl; static int alloc_tmpl_objects(void) @@ -1632,6 +1636,8 @@ int main(int argc, char *argv[]) case 'm': options |= opt2type[c]; parse_u32_mask(optarg, &tmpl.mark); + tmpl.filter_mark_kernel.val = tmpl.mark.value; + tmpl.filter_mark_kernel.mask = tmpl.mark.mask; break; case 'a': fprintf(stderr, "WARNING: ignoring -%c, " @@ -1705,6 +1711,7 @@ int main(int argc, char *argv[]) h->final_check(l4flags, cmd, tmpl.ct); switch(command) { + struct nfct_filter_dump *filter_dump; case CT_LIST: cth = nfct_open(CONNTRACK, 0); @@ -1718,10 +1725,23 @@ int main(int argc, char *argv[]) nfct_callback_register(cth, NFCT_T_ALL, dump_cb, tmpl.ct); + filter_dump = nfct_filter_dump_create(); + if (filter_dump == NULL) + exit_error(OTHER_PROBLEM, "OOM"); + + nfct_filter_dump_set_attr(filter_dump, NFCT_FILTER_DUMP_MARK, + &tmpl.filter_mark_kernel); + nfct_filter_dump_set_attr_u8(filter_dump, + NFCT_FILTER_DUMP_L3NUM, + family); + if (options & CT_OPT_ZERO) - res = nfct_query(cth, NFCT_Q_DUMP_RESET, &family); + res = nfct_query(cth, NFCT_Q_DUMP_FILTER_RESET, + filter_dump); else - res = nfct_query(cth, NFCT_Q_DUMP, &family); + res = nfct_query(cth, NFCT_Q_DUMP_FILTER, filter_dump); + + nfct_filter_dump_destroy(filter_dump); if (dump_xml_header_done == 0) { printf("\n"); @@ -1800,7 +1820,20 @@ int main(int argc, char *argv[]) nfct_callback_register(cth, NFCT_T_ALL, delete_cb, tmpl.ct); - res = nfct_query(cth, NFCT_Q_DUMP, &family); + filter_dump = nfct_filter_dump_create(); + if (filter_dump == NULL) + exit_error(OTHER_PROBLEM, "OOM"); + + nfct_filter_dump_set_attr(filter_dump, NFCT_FILTER_DUMP_MARK, + &tmpl.filter_mark_kernel); + nfct_filter_dump_set_attr_u8(filter_dump, + NFCT_FILTER_DUMP_L3NUM, + family); + + res = nfct_query(cth, NFCT_Q_DUMP_FILTER, filter_dump); + + nfct_filter_dump_destroy(filter_dump); + nfct_close(ith); nfct_close(cth); break; -- cgit v1.2.3 From 867b5b6496a3296078146ba3d06616eda3b0717e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 18 May 2012 01:36:49 +0000 Subject: conntrack: flush stdout for each expectation event, too else, piping "conntrack -E expect" output will be buffered/delayed, which is not what users expect. Normal conntrack events are already flushed. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index b065211..0920bc5 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1380,6 +1380,7 @@ static int event_exp_cb(enum nf_conntrack_msg_type type, nfexp_snprintf(buf,sizeof(buf), exp, type, op_type, op_flags); printf("%s\n", buf); + fflush(stdout); counter++; return NFCT_CB_CONTINUE; -- cgit v1.2.3 From 9aecd75541aab51f5add2884df5105bda87fc05a Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 27 Jun 2012 16:25:05 +0200 Subject: conntrack: add support for stats dumping via ctnetlink Since Linux kernel >= 3.6.x, we can dump the conntrack statistics via ctnetlink instead of using the /proc interface: conntrack -S cpu=0 searched=9177 found=387086 new=250451 invalid=1 ignore=4 delete=254093 delete_list=5467 insert=1825 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0 cpu=1 searched=390 found=37493 new=1531 invalid=0 ignore=0 delete=345 delete_list=345 insert=1531 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0 cpu=2 searched=333 found=68061 new=1895 invalid=0 ignore=1 delete=607 delete_list=607 insert=1896 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0 cpu=3 searched=71 found=13364 new=1254 invalid=0 ignore=0 delete=75 delete_list=75 insert=1254 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0 conntrack -S exp cpu=0 expect_new=9177 expect_create=387284 expect_delete=251141 cpu=1 expect_new=390 expect_create=37496 expect_delete=1531 cpu=2 expect_new=333 expect_create=68117 expect_delete=1895 cpu=3 expect_new=71 expect_create=13366 expect_delete=1255 Note that the output is not backward-compatible, but we fail back to previous output in case that ctnetlink stats dumping is not available. Signed-off-by: Pablo Neira Ayuso --- include/conntrack.h | 2 +- src/Makefile.am | 2 +- src/conntrack.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 215 insertions(+), 9 deletions(-) (limited to 'src/conntrack.c') diff --git a/include/conntrack.h b/include/conntrack.h index 3882de7..fd6126b 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -9,7 +9,7 @@ #include -#define NUMBER_OF_CMD 18 +#define NUMBER_OF_CMD 19 #define NUMBER_OF_OPT 24 struct ctproto_handler { diff --git a/src/Makefile.am b/src/Makefile.am index 5dbdef3..93c035c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ CLEANFILES = read_config_yy.c read_config_lex.c sbin_PROGRAMS = conntrack conntrackd nfct conntrack_SOURCES = conntrack.c -conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_dccp.la ../extensions/libct_proto_gre.la ../extensions/libct_proto_unknown.la ${LIBNETFILTER_CONNTRACK_LIBS} +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} nfct_SOURCES = nfct.c \ nfct-extensions/timeout.c diff --git a/src/conntrack.c b/src/conntrack.c index 0920bc5..6d0f301 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -34,6 +34,8 @@ * Ported to the new libnetfilter_conntrack API * 2008-04-13 Pablo Neira Ayuso : * Way more flexible update and delete operations + * + * Part of this code has been funded by Sophos Astaro */ #include "conntrack.h" @@ -57,6 +59,7 @@ #include #include #include +#include #include struct u32_mask { @@ -157,8 +160,11 @@ enum ct_command { EXP_COUNT_BIT = 16, EXP_COUNT = (1 << EXP_COUNT_BIT), - X_STATS_BIT = 17, - X_STATS = (1 << X_STATS_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 */ @@ -352,7 +358,8 @@ static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /*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}, /*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}, /*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}, -/*X_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}, +/*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}, +/*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}, }; static const int cmd2type[][2] = { @@ -365,6 +372,7 @@ static const int cmd2type[][2] = { ['V'] = { CT_VERSION, CT_VERSION }, ['h'] = { CT_HELP, CT_HELP }, ['C'] = { CT_COUNT, EXP_COUNT }, + ['S'] = { CT_STATS, EXP_STATS }, }; static const int opt2type[] = { @@ -1462,6 +1470,171 @@ out_err: return ret; } +static struct nfct_mnl_socket { + struct mnl_socket *mnl; + uint32_t portid; +} sock; + +static int nfct_mnl_socket_open(void) +{ + sock.mnl = mnl_socket_open(NETLINK_NETFILTER); + if (sock.mnl == NULL) { + perror("mnl_socket_open"); + return -1; + } + if (mnl_socket_bind(sock.mnl, 0, MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + return -1; + } + sock.portid = mnl_socket_get_portid(sock.mnl); + + return 0; +} + +static struct nlmsghdr * +nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type) +{ + struct nlmsghdr *nlh; + struct nfgenmsg *nfh; + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = (subsys << 8) | type; + nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; + nlh->nlmsg_seq = time(NULL); + + nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); + nfh->nfgen_family = AF_INET; + nfh->version = NFNETLINK_V0; + nfh->res_id = 0; + + return nlh; +} + +static void nfct_mnl_socket_close(void) +{ + mnl_socket_close(sock.mnl); +} + +static int +nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + int res; + + nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); + + res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); + if (res < 0) + return res; + + res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf)); + while (res > 0) { + res = mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid, + cb, NULL); + if (res <= MNL_CB_STOP) + break; + + res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf)); + } + + return res; +} + +static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0) + return MNL_CB_OK; + + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + + tb[type] = attr; + return MNL_CB_OK; +} + +static int nfct_stats_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[CTA_STATS_MAX+1] = {}; + struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); + const char *attr2name[CTA_STATS_MAX+1] = { + [CTA_STATS_SEARCHED] = "searched", + [CTA_STATS_FOUND] = "found", + [CTA_STATS_NEW] = "new", + [CTA_STATS_INVALID] = "invalid", + [CTA_STATS_IGNORE] = "ignore", + [CTA_STATS_DELETE] = "delete", + [CTA_STATS_DELETE_LIST] = "delete_list", + [CTA_STATS_INSERT] = "insert", + [CTA_STATS_INSERT_FAILED] = "insert_failed", + [CTA_STATS_DROP] = "drop", + [CTA_STATS_EARLY_DROP] = "early_drop", + [CTA_STATS_ERROR] = "error", + [CTA_STATS_SEARCH_RESTART] = "search_restart", + }; + int i; + + mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_attr_cb, tb); + + printf("cpu=%-4u\t", ntohs(nfg->res_id)); + + for (i=0; ires_id)); + + for (i=0; i= 0) + break; + + goto try_proc; + + case EXP_STATS: + /* If we fail with netlink, fall back to /proc to ensure + * backward compatibility. + */ + if (nfct_mnl_socket_open() < 0) + goto try_proc; + + res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK_EXP, + IPCTNL_MSG_EXP_GET_STATS_CPU, + nfexp_stats_cb); + + nfct_mnl_socket_close(); + + /* don't look at /proc, we got the information via ctnetlink */ + if (res >= 0) + break; +try_proc: if (display_proc_conntrack_stats() < 0) exit_error(OTHER_PROBLEM, "Can't open /proc interface"); break; -- cgit v1.2.3 From ec4c0ff33746fb2c663194f27dd41deee83f870f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 27 Jun 2012 16:47:56 +0200 Subject: conntrack: -C uses ctnetlink instead of /proc/sys/net/netfilter/nf_conntrack_count Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 6d0f301..7451a80 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1541,6 +1541,26 @@ nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb) return res; } +static int +nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + int res; + + nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); + + res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); + if (res < 0) + return res; + + res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf)); + if (res < 0) + return res; + + return mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid, cb, NULL); +} + static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; @@ -1635,6 +1655,37 @@ static int nfexp_stats_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } +static int nfct_stats_global_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTA_STATS_GLOBAL_MAX) < 0) + return MNL_CB_OK; + + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { + perror("mnl_attr_validate"); + return MNL_CB_ERROR; + } + + tb[type] = attr; + return MNL_CB_OK; +} + +static int nfct_global_stats_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[CTA_STATS_GLOBAL_MAX+1] = {}; + struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_global_attr_cb, tb); + + if (tb[CTA_STATS_GLOBAL_ENTRIES]) { + printf("%d\n", + ntohl(mnl_attr_get_u32(tb[CTA_STATS_GLOBAL_ENTRIES]))); + } + return MNL_CB_OK; +} + static struct ctproto_handler *h; int main(int argc, char *argv[]) @@ -2136,7 +2187,25 @@ int main(int argc, char *argv[]) res = nfexp_catch(cth); nfct_close(cth); break; - case CT_COUNT: { + case CT_COUNT: + /* If we fail with netlink, fall back to /proc to ensure + * backward compatibility. + */ + if (nfct_mnl_socket_open() < 0) + goto try_proc_count; + + res = nfct_mnl_get(NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_CT_GET_STATS, + nfct_global_stats_cb); + + nfct_mnl_socket_close(); + + /* don't look at /proc, we got the information via ctnetlink */ + if (res >= 0) + break; + +try_proc_count: + { #define NF_CONNTRACK_COUNT_PROC "/proc/sys/net/netfilter/nf_conntrack_count" FILE *fd; int count; -- cgit v1.2.3 From 134bffa852edc341664dcc4808b1de41107d16d6 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 27 Nov 2012 20:57:42 +0100 Subject: conntrack: add support to dump the dying and unconfirmed list via ctnetlink This patch adds support for: conntrack -L dying conntrack -L unconfirmed To display the list of dying and unconfirmed conntracks. This provides some instrumentation in case that `conntrack -C` really deviates from what `conntrack -L | wc -l` says. Users like to check this to make sure things are going OK. Still, some conntrack objects may be still in the dying and the unconfirmed list. With this patch, we can also dump their content, before it was not possible. In normal cases both lists would be simply empty, or in the case of the dying list, you can observe that entries go slightly down in number. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 13 deletions(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 7451a80..227c355 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -822,27 +822,45 @@ add_command(unsigned int *cmd, const int newcmd) *cmd |= newcmd; } -static unsigned int -check_type(int argc, char *argv[]) +static char *get_table(int argc, char *argv[]) { char *table = NULL; - /* Nasty bug or feature in getopt_long ? + /* Nasty bug or feature in getopt_long ? * It seems that it behaves badly with optional arguments. * Fortunately, I just stole the fix from iptables ;) */ if (optarg) return 0; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') + else if (optind < argc && argv[optind][0] != '-' && + argv[optind][0] != '!') table = argv[optind++]; - - if (!table) - return 0; - + + return table; +} + +enum { + CT_TABLE_CONNTRACK, + CT_TABLE_EXPECT, + CT_TABLE_DYING, + CT_TABLE_UNCONFIRMED, +}; + +static unsigned int check_type(int argc, char *argv[]) +{ + const char *table = get_table(argc, argv); + + /* default to conntrack subsystem if nothing has been specified. */ + if (table == NULL) + return CT_TABLE_CONNTRACK; + if (strncmp("expect", table, strlen(table)) == 0) - return 1; + return CT_TABLE_EXPECT; else if (strncmp("conntrack", table, strlen(table)) == 0) - return 0; + return CT_TABLE_CONNTRACK; + else if (strncmp("dying", table, strlen(table)) == 0) + return CT_TABLE_DYING; + else if (strncmp("unconfirmed", table, strlen(table)) == 0) + return CT_TABLE_UNCONFIRMED; else exit_error(PARAMETER_PROBLEM, "unknown type `%s'", table); @@ -1686,6 +1704,27 @@ static int nfct_global_stats_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } +static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nf_conntrack *ct; + char buf[4096]; + + ct = nfct_new(); + if (ct == NULL) + return MNL_CB_OK; + + nfct_nlmsg_parse(nlh, ct); + + nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0); + printf("%s\n", buf); + + nfct_destroy(ct); + + counter++; + + return MNL_CB_OK; +} + static struct ctproto_handler *h; int main(int argc, char *argv[]) @@ -1720,6 +1759,16 @@ int main(int argc, char *argv[]) switch(c) { /* commands */ case 'L': + type = check_type(argc, argv); + /* Special case: dumping dying and unconfirmed list + * are handled like normal conntrack dumps. + */ + if (type == CT_TABLE_DYING || + type == CT_TABLE_UNCONFIRMED) + add_command(&command, cmd2type[c][0]); + else + add_command(&command, cmd2type[c][type]); + break; case 'I': case 'D': case 'G': @@ -1730,14 +1779,25 @@ int main(int argc, char *argv[]) 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': type = check_type(argc, argv); - if (type == 0) + 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 - exit_error(PARAMETER_PROBLEM, + exit_error(PARAMETER_PROBLEM, "Can't update expectations"); break; /* options */ @@ -1937,6 +1997,28 @@ int main(int argc, char *argv[]) struct nfct_filter_dump *filter_dump; case CT_LIST: + if (type == CT_TABLE_DYING) { + if (nfct_mnl_socket_open() < 0) + exit_error(OTHER_PROBLEM, "Can't open handler"); + + res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_CT_GET_DYING, + mnl_nfct_dump_cb); + + nfct_mnl_socket_close(); + break; + } else if (type == CT_TABLE_UNCONFIRMED) { + if (nfct_mnl_socket_open() < 0) + exit_error(OTHER_PROBLEM, "Can't open handler"); + + res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, + IPCTNL_MSG_CT_GET_UNCONFIRMED, + mnl_nfct_dump_cb); + + nfct_mnl_socket_close(); + break; + } + cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); -- cgit v1.2.3 From ca99976f450afa0f7ec2f4320e863860990af61d Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 15 May 2013 16:38:30 +0200 Subject: conntrack: fix timestamps when microseconds are less than 100000 The fractional portion of timestamps reported by conntrack is printed as a left-justified integer instead of fixed-width and zero-padded. Closes netfilter's bugzilla 817: https://bugzilla.netfilter.org/show_bug.cgi?id=817 Reported-by: hoffman@stanford.edu Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 227c355..d4e79de 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1141,7 +1141,7 @@ static int event_cb(enum nf_conntrack_msg_type type, if (!(output_mask & _O_XML)) { struct timeval tv; gettimeofday(&tv, NULL); - printf("[%-8ld.%-6ld]\t", tv.tv_sec, tv.tv_usec); + printf("[%-.8ld.%-.6ld]\t", tv.tv_sec, tv.tv_usec); } else op_flags |= NFCT_OF_TIME; } -- cgit v1.2.3 From d343b8c554b6a04f6c477841dc4cbb89b5cd1bd9 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 4 Jul 2013 16:04:39 +0200 Subject: conntrack: add connlabel format attribute Signed-off-by: Florian Westphal --- conntrack.8 | 4 +++- src/conntrack.c | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/conntrack.c') diff --git a/conntrack.8 b/conntrack.8 index a411fd4..d80a778 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -88,11 +88,13 @@ Show the in-kernel connection tracking system statistics. 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,id,ktimestamp] " +.BI "-o, --output [extended,xml,timestamp,id,ktimestamp,labels] " Display output in a certain format. With the extended output option, this tool displays the layer 3 information. With ktimestamp, it displays the in-kernel timestamp available since 2.6.38 (you can enable it via echo 1 > /proc/sys/net/netfilter/nf_conntrack_timestamp). +The labels output option tells conntrack to show the names of connection +tracking labels that might be present. .TP .BI "-e, --event-mask " "[ALL|NEW|UPDATES|DESTROY][,...]" Set the bitmask of events that are to be generated by the in-kernel ctnetlink diff --git a/src/conntrack.c b/src/conntrack.c index d4e79de..61e2fce 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -488,6 +488,7 @@ static unsigned int addr_valid_flags[ADDR_VALID_FLAGS_MAX] = { static LIST_HEAD(proto_list); static unsigned int options; +static struct nfct_labelmap *labelmap; void register_proto(struct ctproto_handler *h) { @@ -731,6 +732,7 @@ enum { _O_TMS = (1 << 2), _O_ID = (1 << 3), _O_KTMS = (1 << 4), + _O_CL = (1 << 5), }; enum { @@ -749,8 +751,8 @@ static struct parse_parameter { { IPS_ASSURED, IPS_SEEN_REPLY, 0, IPS_FIXED_TIMEOUT, IPS_EXPECTED} }, { {"ALL", "NEW", "UPDATES", "DESTROY"}, 4, { CT_EVENT_F_ALL, CT_EVENT_F_NEW, CT_EVENT_F_UPD, CT_EVENT_F_DEL } }, - { {"xml", "extended", "timestamp", "id", "ktimestamp"}, 5, - { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS }, + { {"xml", "extended", "timestamp", "id", "ktimestamp", "labels", }, 6, + { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS, _O_CL }, }, }; @@ -1150,7 +1152,7 @@ static int event_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf, sizeof(buf), ct, type, op_type, op_flags); + nfct_snprintf_labels(buf, sizeof(buf), ct, type, op_type, op_flags, labelmap); printf("%s\n", buf); fflush(stdout); @@ -1194,7 +1196,7 @@ static int dump_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); + nfct_snprintf_labels(buf, sizeof(buf), ct, type, op_type, op_flags, labelmap); printf("%s\n", buf); counter++; @@ -1879,6 +1881,11 @@ int main(int argc, char *argv[]) case 'o': options |= CT_OPT_OUTPUT; parse_parameter(optarg, &output_mask, PARSE_OUTPUT); + if (output_mask & _O_CL) { + labelmap = nfct_labelmap_new(NULL); + if (!labelmap) + perror("nfct_labelmap_new"); + } break; case 'z': options |= CT_OPT_ZERO; @@ -2372,6 +2379,8 @@ try_proc: free_tmpl_objects(); free_options(); + if (labelmap) + nfct_labelmap_destroy(labelmap); if (command && exit_msg[cmd][0]) { fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION); -- cgit v1.2.3 From 1239b83da27545e3275127ac339cdca29c872304 Mon Sep 17 00:00:00 2001 From: Clemence Faure Date: Tue, 9 Jul 2013 10:37:02 +0200 Subject: conntrack: introduce -l option to filter by labels Signed-off-by: Clemence Faure Signed-off-by: Florian Westphal --- conntrack.8 | 5 ++ include/conntrack.h | 2 +- src/conntrack.c | 156 +++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 137 insertions(+), 26 deletions(-) (limited to 'src/conntrack.c') diff --git a/conntrack.8 b/conntrack.8 index d80a778..f273434 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -144,6 +144,11 @@ 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. .TP +.BI "-l, --label " "LABEL,..." +Specify the conntrack labels. +This option is only available in conjunction with "-L, --dump" or "-E, --event". +Match entries whose labels matches at least those specified as arguments. +.TP .BI "-c, --secmark " "SECMARK" Specify the conntrack selinux security mark. .TP diff --git a/include/conntrack.h b/include/conntrack.h index fd6126b..6cd9962 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -10,7 +10,7 @@ #include #define NUMBER_OF_CMD 19 -#define NUMBER_OF_OPT 24 +#define NUMBER_OF_OPT 25 struct ctproto_handler { struct list_head head; diff --git a/src/conntrack.c b/src/conntrack.c index 61e2fce..353ff61 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -79,6 +79,9 @@ static struct { /* Allow to filter by mark from kernel-space. */ struct nfct_filter_dump_mark filter_mark_kernel; + + /* Allows filtering by ctlabels */ + struct nfct_bitmask *label; } tmpl; static int alloc_tmpl_objects(void) @@ -104,6 +107,8 @@ static void free_tmpl_objects(void) nfct_destroy(tmpl.mask); if (tmpl.exp) nfexp_destroy(tmpl.exp); + if (tmpl.label) + nfct_bitmask_destroy(tmpl.label); } enum ct_command { @@ -247,13 +252,16 @@ enum ct_options { CT_OPT_ZONE_BIT = 23, CT_OPT_ZONE = (1 << CT_OPT_ZONE_BIT), + + CT_OPT_LABEL_BIT = 24, + CT_OPT_LABEL = (1 << CT_OPT_LABEL_BIT), }; /* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ /* Update this mask to allow to filter based on new options. */ #define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | \ CT_OPT_MARK | CT_OPT_SECMARK | CT_OPT_STATUS | \ - CT_OPT_ID | CT_OPT_ZONE) + CT_OPT_ID | CT_OPT_ZONE | CT_OPT_LABEL) static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_ORIG_SRC_BIT] = "src", @@ -280,6 +288,7 @@ static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_BUFFERSIZE_BIT] = "buffer-size", [CT_OPT_ANY_NAT_BIT] = "any-nat", [CT_OPT_ZONE_BIT] = "zone", + [CT_OPT_LABEL_BIT] = "label", }; static struct option original_opts[] = { @@ -320,12 +329,13 @@ static struct option original_opts[] = { {"buffer-size", 1, 0, 'b'}, {"any-nat", 2, 0, 'j'}, {"zone", 1, 0, 'w'}, + {"label", 1, 0, 'l'}, {0, 0, 0, 0} }; static const char *getopt_str = "L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" - "g::c:b:C::Sj::w:"; + "g::c:b:C::Sj::w:l:"; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to @@ -340,26 +350,26 @@ 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*/ -/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,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}, -/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0}, -/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,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}, -/*CT_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}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,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,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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, + /* 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,0,0,0,2,0,2,2,2,2,2,0,2,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}, +/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0}, +/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,2,0}, +/*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,0}, +/*CT_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}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,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,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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, }; static const int cmd2type[][2] = { @@ -391,6 +401,7 @@ static const int opt2type[] = { ['i'] = CT_OPT_ID, ['j'] = CT_OPT_ANY_NAT, ['w'] = CT_OPT_ZONE, + ['l'] = CT_OPT_LABEL, }; static const int opt2family_attr[][2] = { @@ -413,6 +424,7 @@ static const int opt2attr[] = { ['c'] = ATTR_SECMARK, ['i'] = ATTR_ID, ['w'] = ATTR_ZONE, + ['l'] = ATTR_CONNLABELS, }; static char exit_msg[NUMBER_OF_CMD][64] = { @@ -450,7 +462,8 @@ static const char usage_conntrack_parameters[] = " -c, --secmark secmark\t\t\tSet selinux secmark\n" " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" " -z, --zero \t\t\t\tZero counters while listing\n" - " -o, --output type[,...]\t\tOutput format, eg. xml\n"; + " -o, --output type[,...]\t\tOutput format, eg. xml\n" + " -l, --label label[,...]\t\tconntrack labels\n"; static const char usage_expectation_parameters[] = "Expectation parameters and options:\n" @@ -816,6 +829,59 @@ parse_u32_mask(const char *arg, struct u32_mask *m) m->mask = ~0; } +static int +get_label(char *name) +{ + int bit = nfct_labelmap_get_bit(labelmap, name); + if (bit < 0) + exit_error(PARAMETER_PROBLEM, "unknown label '%s'", name); + return bit; +} + +static void +set_label(struct nfct_bitmask *b, char *name) +{ + int bit = get_label(name); + nfct_bitmask_set_bit(b, bit); +} + +static unsigned int +set_max_label(char *name, unsigned int current_max) +{ + int bit = get_label(name); + if ((unsigned int) bit > current_max) + return (unsigned int) bit; + return current_max; +} + +static unsigned int +parse_label_get_max(char *arg) +{ + unsigned int max = 0; + char *parse; + + while ((parse = strchr(arg, ',')) != NULL) { + parse[0] = '\0'; + max = set_max_label(arg, max); + arg = &parse[1]; + } + + max = set_max_label(arg, max); + return max; +} + +static void +parse_label(struct nfct_bitmask *b, char *arg) +{ + char * parse; + while ((parse = strchr(arg, ',')) != NULL) { + parse[0] = '\0'; + set_label(b, arg); + arg = &parse[1]; + } + set_label(b, arg); +} + static void add_command(unsigned int *cmd, const int newcmd) { @@ -984,6 +1050,24 @@ usage(char *prog) static unsigned int output_mask; +static int +filter_label(const struct nf_conntrack *ct) +{ + if (tmpl.label == NULL) + return 0; + + const struct nfct_bitmask *ctb = nfct_get_attr(ct, ATTR_CONNLABELS); + if (ctb == NULL) + return 1; + + for (unsigned int i = 0; i <= nfct_bitmask_maxbit(tmpl.label); i++) { + if (nfct_bitmask_test_bit(tmpl.label, i) && + !nfct_bitmask_test_bit(ctb, i)) + return 1; + } + + return 0; +} static int filter_mark(const struct nf_conntrack *ct) @@ -994,7 +1078,6 @@ filter_mark(const struct nf_conntrack *ct) return 0; } - static int filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) { @@ -1125,6 +1208,9 @@ static int event_cb(enum nf_conntrack_msg_type type, if (filter_mark(ct)) return NFCT_CB_CONTINUE; + if (filter_label(ct)) + return NFCT_CB_CONTINUE; + if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) return NFCT_CB_CONTINUE; @@ -1177,6 +1263,9 @@ static int dump_cb(enum nf_conntrack_msg_type type, if (filter_mark(ct)) return NFCT_CB_CONTINUE; + if (filter_label(ct)) + return NFCT_CB_CONTINUE; + if (options & CT_COMPARISON && !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) return NFCT_CB_CONTINUE; @@ -1882,7 +1971,8 @@ int main(int argc, char *argv[]) options |= CT_OPT_OUTPUT; parse_parameter(optarg, &output_mask, PARSE_OUTPUT); if (output_mask & _O_CL) { - labelmap = nfct_labelmap_new(NULL); + if (!labelmap) + labelmap = nfct_labelmap_new(NULL); if (!labelmap) perror("nfct_labelmap_new"); } @@ -1929,6 +2019,22 @@ int main(int argc, char *argv[]) tmpl.filter_mark_kernel.val = tmpl.mark.value; tmpl.filter_mark_kernel.mask = tmpl.mark.mask; break; + case 'l': + options |= opt2type[c]; + char *optarg2 = strdup(optarg); + + if (!labelmap) + labelmap = nfct_labelmap_new(NULL); + if (!labelmap) + exit_error(OTHER_PROBLEM, "unable to open labelmap file"); + + unsigned int max = parse_label_get_max(optarg); + struct nfct_bitmask * b = nfct_bitmask_new(max); + + parse_label(b, optarg2); + tmpl.label = b; + free(optarg2); + break; case 'a': fprintf(stderr, "WARNING: ignoring -%c, " "deprecated option.\n", c); -- cgit v1.2.3 From 89d016bb2cd72013cec1ae1c5cb2dfff15563d51 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 24 Jul 2013 12:40:50 +0200 Subject: conntrack: fix -L format output commit d343b8c (conntrack: add connlabel format attribute) erronously removed _UNKNOWN format, i.e. conntrack -L displayed [UPDATE] tcp 6 114 TIME_WAIT src=.. ^^^^^ Reported-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 353ff61..af36f78 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1285,7 +1285,7 @@ static int dump_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf_labels(buf, sizeof(buf), ct, type, op_type, op_flags, labelmap); + nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap); printf("%s\n", buf); counter++; -- cgit v1.2.3 From 8e9906b69b03eb12fc75e857a347c4505332b820 Mon Sep 17 00:00:00 2001 From: Clemence Faure Date: Tue, 23 Jul 2013 15:00:18 +0200 Subject: conntrack: fix reporting of unknown arguments short options were always reported as "unknown argument". getopt(3) says: if [it] finds an option character in argv that was not included in optstring, or if it detects a missing option argument, it returns '?' and sets the external variable optopt to the actual option character. If the first character [...] of optstring is a colon (':'), then getopt() returns ':' instead of '?' to indicate a missing option argument. Signed-off-by: Clemence Faure Signed-off-by: Florian Westphal --- src/conntrack.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index af36f78..7d2a365 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -333,7 +333,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::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" "g::c:b:C::Sj::w:l:"; @@ -2054,15 +2054,13 @@ int main(int argc, char *argv[]) socketbuffersize = atol(optarg); options |= CT_OPT_BUFFERSIZE; break; + case ':': + exit_error(PARAMETER_PROBLEM, + "option `%s' requires an " + "argument", argv[optind-1]); case '?': - if (optopt) - exit_error(PARAMETER_PROBLEM, - "option `%s' requires an " - "argument", argv[optind-1]); - else - exit_error(PARAMETER_PROBLEM, - "unknown option `%s'", - argv[optind-1]); + exit_error(PARAMETER_PROBLEM, + "unknown option `%s'", argv[optind-1]); break; default: if (h && h->parse_opts -- cgit v1.2.3 From 5c35c86e2d9d4c522514cceec5e19e08e05ed4db Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 7 Aug 2013 15:22:41 +0200 Subject: conntrack: fix dump of IPv6 entries in the dying and unconfirmed list Use selected the family, instead of inconditionally request for IPv4. Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 7d2a365..bb4a026 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1601,7 +1601,8 @@ static int nfct_mnl_socket_open(void) } static struct nlmsghdr * -nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type) +nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type, + uint8_t family) { struct nlmsghdr *nlh; struct nfgenmsg *nfh; @@ -1612,7 +1613,7 @@ nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type) nlh->nlmsg_seq = time(NULL); nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); - nfh->nfgen_family = AF_INET; + nfh->nfgen_family = family; nfh->version = NFNETLINK_V0; nfh->res_id = 0; @@ -1625,13 +1626,13 @@ static void nfct_mnl_socket_close(void) } static int -nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb) +nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; int res; - nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); + nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family); res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); if (res < 0) @@ -1651,13 +1652,13 @@ nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb) } static int -nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb) +nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; int res; - nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); + nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family); res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); if (res < 0) @@ -2114,7 +2115,7 @@ int main(int argc, char *argv[]) res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_DYING, - mnl_nfct_dump_cb); + mnl_nfct_dump_cb, family); nfct_mnl_socket_close(); break; @@ -2124,7 +2125,7 @@ int main(int argc, char *argv[]) res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_UNCONFIRMED, - mnl_nfct_dump_cb); + mnl_nfct_dump_cb, family); nfct_mnl_socket_close(); break; @@ -2389,7 +2390,7 @@ int main(int argc, char *argv[]) res = nfct_mnl_get(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS, - nfct_global_stats_cb); + nfct_global_stats_cb, AF_UNSPEC); nfct_mnl_socket_close(); @@ -2434,7 +2435,7 @@ try_proc_count: res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS_CPU, - nfct_stats_cb); + nfct_stats_cb, AF_UNSPEC); nfct_mnl_socket_close(); @@ -2453,7 +2454,7 @@ try_proc_count: res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET_STATS_CPU, - nfexp_stats_cb); + nfexp_stats_cb, AF_UNSPEC); nfct_mnl_socket_close(); -- cgit v1.2.3 From 43fbb438858cb704e23763091f1bc97a6c4bb098 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 3 Sep 2013 17:28:40 +0200 Subject: conntrack: minor cleanup Rename get_table to generic "optional argument handling" helper, so it can be re-used in upcoming patch. While at it, avoid copy&paste of "labelmap" handling. Signed-off-by: Florian Westphal --- src/conntrack.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index bb4a026..8da94bf 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -890,20 +890,20 @@ add_command(unsigned int *cmd, const int newcmd) *cmd |= newcmd; } -static char *get_table(int argc, char *argv[]) +static char *get_optional_arg(int argc, char *argv[]) { - char *table = NULL; + char *arg = NULL; /* Nasty bug or feature in getopt_long ? * It seems that it behaves badly with optional arguments. * Fortunately, I just stole the fix from iptables ;) */ if (optarg) - return 0; + return arg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') - table = argv[optind++]; + arg = argv[optind++]; - return table; + return arg; } enum { @@ -915,7 +915,7 @@ enum { static unsigned int check_type(int argc, char *argv[]) { - const char *table = get_table(argc, argv); + const char *table = get_optional_arg(argc, argv); /* default to conntrack subsystem if nothing has been specified. */ if (table == NULL) @@ -1819,6 +1819,15 @@ static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data) static struct ctproto_handler *h; +static void labelmap_init(void) +{ + if (labelmap) + return; + labelmap = nfct_labelmap_new(NULL); + if (!labelmap) + perror("nfct_labelmap_new"); +} + int main(int argc, char *argv[]) { int c, cmd; @@ -1971,12 +1980,8 @@ int main(int argc, char *argv[]) case 'o': options |= CT_OPT_OUTPUT; parse_parameter(optarg, &output_mask, PARSE_OUTPUT); - if (output_mask & _O_CL) { - if (!labelmap) - labelmap = nfct_labelmap_new(NULL); - if (!labelmap) - perror("nfct_labelmap_new"); - } + if (output_mask & _O_CL) + labelmap_init(); break; case 'z': options |= CT_OPT_ZERO; @@ -1988,12 +1993,7 @@ int main(int argc, char *argv[]) options |= opt2type[c]; - if (optarg) - continue; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - tmp = argv[optind++]; - + tmp = get_optional_arg(argc, argv); if (tmp == NULL) continue; @@ -2024,10 +2024,7 @@ int main(int argc, char *argv[]) options |= opt2type[c]; char *optarg2 = strdup(optarg); - if (!labelmap) - labelmap = nfct_labelmap_new(NULL); - if (!labelmap) - exit_error(OTHER_PROBLEM, "unable to open labelmap file"); + labelmap_init(); unsigned int max = parse_label_get_max(optarg); struct nfct_bitmask * b = nfct_bitmask_new(max); -- cgit v1.2.3 From 06454c33f44c0f4d71a88a82b82da7bba5abde2d Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 5 Sep 2013 11:27:48 +0200 Subject: conntrack: support multiple -l options Using -l foo -l bar caused the "foo" label to be lost. Merge multiple -l options so "-l foo,bar" and "-l foo -l bar" have same effect. Signed-off-by: Florian Westphal --- conntrack.8 | 7 ++++--- src/conntrack.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) (limited to 'src/conntrack.c') diff --git a/conntrack.8 b/conntrack.8 index f273434..6410e5b 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -144,10 +144,11 @@ 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. .TP -.BI "-l, --label " "LABEL,..." -Specify the conntrack labels. +.BI "-l, --label " "LABEL" +Specify a conntrack label. This option is only available in conjunction with "-L, --dump" or "-E, --event". -Match entries whose labels matches at least those specified as arguments. +Match entries whose labels match at least those specified. +Use multiple -l commands to specify multiple labels that need to be set. .TP .BI "-c, --secmark " "SECMARK" Specify the conntrack selinux security mark. diff --git a/src/conntrack.c b/src/conntrack.c index 8da94bf..fe68e42 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1828,6 +1828,31 @@ static void labelmap_init(void) perror("nfct_labelmap_new"); } +static void merge_bitmasks(struct nfct_bitmask **current, + struct nfct_bitmask *src) +{ + unsigned int i; + + if (*current == NULL) { + *current = src; + return; + } + + /* "current" must be the larger bitmask object */ + if (nfct_bitmask_maxbit(src) > nfct_bitmask_maxbit(*current)) { + struct nfct_bitmask *tmp = *current; + *current = src; + src = tmp; + } + + for (i = 0; i <= nfct_bitmask_maxbit(src); i++) { + if (nfct_bitmask_test_bit(src, i)) + nfct_bitmask_set_bit(*current, i); + } + + nfct_bitmask_destroy(src); +} + int main(int argc, char *argv[]) { int c, cmd; @@ -2030,7 +2055,9 @@ int main(int argc, char *argv[]) struct nfct_bitmask * b = nfct_bitmask_new(max); parse_label(b, optarg2); - tmpl.label = b; + + /* join "-l foo -l bar" into single bitmask object */ + merge_bitmasks(&tmpl.label, b); free(optarg2); break; case 'a': -- cgit v1.2.3 From 991fc4ae561bfc7c9bc9da9598b0cc704295811f Mon Sep 17 00:00:00 2001 From: Clemence Faure Date: Thu, 5 Sep 2013 11:27:49 +0200 Subject: conntrack: support add/delete of conntrack labels new options "--label-add" and "--label-delete" to alter connlabels assigned to a connection. Signed-off-by: Clemence Faure Signed-off-by: Florian Westphal --- conntrack.8 | 10 +++- include/conntrack.h | 2 +- src/conntrack.c | 154 ++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 140 insertions(+), 26 deletions(-) (limited to 'src/conntrack.c') diff --git a/conntrack.8 b/conntrack.8 index 6410e5b..45e8582 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -146,9 +146,17 @@ In "--create" mode, the mask is ignored. .TP .BI "-l, --label " "LABEL" Specify a conntrack label. -This option is only available in conjunction with "-L, --dump" or "-E, --event". +This option is only available in conjunction with "-L, --dump", "-E, --event", or "-U --update". Match entries whose labels match at least those specified. Use multiple -l commands to specify multiple labels that need to be set. +Match entries whose labels matches at least those specified as arguments. +.BI "--label-add " "LABEL" +Specify the conntrack label to add to to the selected conntracks. +This option is only available in conjunction with "-I, --create" or "-U, --update". +.BI "--label-del " "[LABEL]" +Specify the conntrack label to delete from the selected conntracks. +If no label is given, all labels are deleted. +This option is only available in conjunction with "-U, --update". .TP .BI "-c, --secmark " "SECMARK" Specify the conntrack selinux security mark. diff --git a/include/conntrack.h b/include/conntrack.h index 6cd9962..c2a0c8f 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -10,7 +10,7 @@ #include #define NUMBER_OF_CMD 19 -#define NUMBER_OF_OPT 25 +#define NUMBER_OF_OPT 27 struct ctproto_handler { struct list_head head; diff --git a/src/conntrack.c b/src/conntrack.c index fe68e42..404ecc9 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -82,6 +82,9 @@ static struct { /* Allows filtering by ctlabels */ struct nfct_bitmask *label; + + /* Allows setting/removing specific ctlabels */ + struct nfct_bitmask *label_modify; } tmpl; static int alloc_tmpl_objects(void) @@ -109,6 +112,8 @@ static void free_tmpl_objects(void) nfexp_destroy(tmpl.exp); if (tmpl.label) nfct_bitmask_destroy(tmpl.label); + if (tmpl.label_modify) + nfct_bitmask_destroy(tmpl.label_modify); } enum ct_command { @@ -255,6 +260,12 @@ enum ct_options { CT_OPT_LABEL_BIT = 24, CT_OPT_LABEL = (1 << CT_OPT_LABEL_BIT), + + CT_OPT_ADD_LABEL_BIT = 25, + CT_OPT_ADD_LABEL = (1 << CT_OPT_ADD_LABEL_BIT), + + CT_OPT_DEL_LABEL_BIT = 26, + CT_OPT_DEL_LABEL = (1 << CT_OPT_DEL_LABEL_BIT), }; /* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ @@ -289,6 +300,8 @@ static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_ANY_NAT_BIT] = "any-nat", [CT_OPT_ZONE_BIT] = "zone", [CT_OPT_LABEL_BIT] = "label", + [CT_OPT_ADD_LABEL_BIT] = "label-add", + [CT_OPT_DEL_LABEL_BIT] = "label-del", }; static struct option original_opts[] = { @@ -330,12 +343,14 @@ static struct option original_opts[] = { {"any-nat", 2, 0, 'j'}, {"zone", 1, 0, 'w'}, {"label", 1, 0, 'l'}, + {"label-add", 1, 0, '<'}, + {"label-del", 2, 0, '>'}, {0, 0, 0, 0} }; static const char *getopt_str = ":L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" - "g::c:b:C::Sj::w:l:"; + "g::c:b:C::Sj::w:l:<:>::"; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to @@ -350,26 +365,26 @@ 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,0,0,0,2,0,2,2,2,2,2,0,2,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}, -/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0}, -/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,2,0}, -/*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,0}, -/*CT_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}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,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,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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, + /* 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,0,0,0,2,0,2,2,2,2,2,0,2,2,2,0,0}, +/*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}, +/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,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,0,0,0,2,2,0,0}, +/*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}, +/*CT_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}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2,2,0,0}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, }; static const int cmd2type[][2] = { @@ -402,6 +417,8 @@ static const int opt2type[] = { ['j'] = CT_OPT_ANY_NAT, ['w'] = CT_OPT_ZONE, ['l'] = CT_OPT_LABEL, + ['<'] = CT_OPT_ADD_LABEL, + ['>'] = CT_OPT_DEL_LABEL, }; static const int opt2family_attr[][2] = { @@ -425,6 +442,8 @@ static const int opt2attr[] = { ['i'] = ATTR_ID, ['w'] = ATTR_ZONE, ['l'] = ATTR_CONNLABELS, + ['<'] = ATTR_CONNLABELS, + ['>'] = ATTR_CONNLABELS, }; static char exit_msg[NUMBER_OF_CMD][64] = { @@ -472,6 +491,11 @@ static const char usage_expectation_parameters[] = " --mask-src ip\t\tSource mask address\n" " --mask-dst ip\t\tDestination mask address\n"; +static const char usage_update_parameters[] = + "Updating parameters and options:\n" + " --label-add label\tAdd label\n" + " --label-del label\tDelete label\n"; + static const char usage_parameters[] = "Common parameters and options:\n" " -s, --orig-src ip\t\tSource address from original direction\n" @@ -1045,6 +1069,7 @@ usage(char *prog) fprintf(stdout, "\n%s", usage_tables); fprintf(stdout, "\n%s", usage_conntrack_parameters); fprintf(stdout, "\n%s", usage_expectation_parameters); + fprintf(stdout, "\n%s", usage_update_parameters); fprintf(stdout, "\n%s\n", usage_parameters); } @@ -1349,7 +1374,7 @@ static int print_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); + nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap); printf("%s\n", buf); return NFCT_CB_CONTINUE; @@ -1376,6 +1401,58 @@ static void copy_status(struct nf_conntrack *tmp, const struct nf_conntrack *ct) } } +static struct nfct_bitmask *xnfct_bitmask_clone(const struct nfct_bitmask *a) +{ + struct nfct_bitmask *b = nfct_bitmask_clone(a); + if (!b) + exit_error(OTHER_PROBLEM, "out of memory"); + return b; +} + +static void copy_label(struct nf_conntrack *tmp, const struct nf_conntrack *ct) +{ + struct nfct_bitmask *ctb, *newmask; + unsigned int i; + + if ((options & (CT_OPT_ADD_LABEL|CT_OPT_DEL_LABEL)) == 0) + return; + + nfct_copy_attr(tmp, ct, ATTR_CONNLABELS); + ctb = (void *) nfct_get_attr(tmp, ATTR_CONNLABELS); + + if (options & CT_OPT_ADD_LABEL) { + if (ctb == NULL) { + newmask = xnfct_bitmask_clone(tmpl.label_modify); + nfct_set_attr(tmp, ATTR_CONNLABELS, newmask); + return; + } + + for (i = 0; i <= nfct_bitmask_maxbit(ctb); i++) { + if (nfct_bitmask_test_bit(tmpl.label_modify, i)) + nfct_bitmask_set_bit(ctb, i); + } + + newmask = xnfct_bitmask_clone(tmpl.label_modify); + nfct_set_attr(tmp, ATTR_CONNLABELS_MASK, newmask); + } else if (ctb != NULL) { + /* CT_OPT_DEL_LABEL */ + if (tmpl.label_modify == NULL) { + newmask = nfct_bitmask_new(0); + if (newmask) + nfct_set_attr(tmp, ATTR_CONNLABELS, newmask); + return; + } + + for (i = 0; i <= nfct_bitmask_maxbit(ctb); i++) { + if (nfct_bitmask_test_bit(tmpl.label_modify, i)) + nfct_bitmask_unset_bit(ctb, i); + } + + newmask = xnfct_bitmask_clone(tmpl.label_modify); + nfct_set_attr(tmp, ATTR_CONNLABELS_MASK, newmask); + } +} + static int update_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -1395,6 +1472,9 @@ static int update_cb(enum nf_conntrack_msg_type type, if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(obj, ct, NFCT_CMP_REPL)) return NFCT_CB_CONTINUE; + if (filter_label(ct)) + return NFCT_CB_CONTINUE; + tmp = nfct_new(); if (tmp == NULL) exit_error(OTHER_PROBLEM, "out of memory"); @@ -1403,6 +1483,7 @@ static int update_cb(enum nf_conntrack_msg_type type, nfct_copy(tmp, obj, NFCT_CP_META); copy_mark(tmp, ct, &tmpl.mark); copy_status(tmp, ct); + copy_label(tmp, ct); /* do not send NFCT_Q_UPDATE if ct appears unchanged */ if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) { @@ -2046,18 +2127,39 @@ int main(int argc, char *argv[]) tmpl.filter_mark_kernel.mask = tmpl.mark.mask; break; case 'l': + case '<': + case '>': options |= opt2type[c]; - char *optarg2 = strdup(optarg); labelmap_init(); + if ((options & (CT_OPT_DEL_LABEL|CT_OPT_ADD_LABEL)) == + (CT_OPT_DEL_LABEL|CT_OPT_ADD_LABEL)) + exit_error(OTHER_PROBLEM, "cannot use --label-add and " + "--label-del at the same time"); + + if (c == '>') { /* DELETE */ + char *tmp = get_optional_arg(argc, argv); + if (tmp == NULL) /* delete all labels */ + break; + optarg = tmp; + } + + char *optarg2 = strdup(optarg); unsigned int max = parse_label_get_max(optarg); struct nfct_bitmask * b = nfct_bitmask_new(max); + if (!b) + exit_error(OTHER_PROBLEM, "out of memory"); parse_label(b, optarg2); /* join "-l foo -l bar" into single bitmask object */ - merge_bitmasks(&tmpl.label, b); + if (c == 'l') { + merge_bitmasks(&tmpl.label, b); + } else { + merge_bitmasks(&tmpl.label_modify, b); + } + free(optarg2); break; case 'a': @@ -2216,6 +2318,10 @@ int main(int argc, char *argv[]) if (options & CT_OPT_MARK) nfct_set_attr_u32(tmpl.ct, ATTR_MARK, tmpl.mark.value); + if (options & CT_OPT_ADD_LABEL) + nfct_set_attr(tmpl.ct, ATTR_CONNLABELS, + xnfct_bitmask_clone(tmpl.label_modify)); + cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); -- cgit v1.2.3 From fee95ed0db0745b551dfb15c58800da5c1ca9e5f Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 5 Sep 2013 11:27:50 +0200 Subject: conntrack: do not exit when update returns an error If we fail to update an entry, just try to continue with the next one instead of exiting. Can happen f.e. when using "conntrack -U --add-label bla", but the conntrack entry in the kernel does not have the label extension set. Signed-off-by: Florian Westphal --- src/conntrack.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 404ecc9..1e45ca8 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1492,12 +1492,10 @@ static int update_cb(enum nf_conntrack_msg_type type, } res = nfct_query(ith, NFCT_Q_UPDATE, tmp); - if (res < 0) { - nfct_destroy(tmp); - exit_error(OTHER_PROBLEM, - "Operation failed: %s", + if (res < 0) + fprintf(stderr, + "Operation failed: %s\n", err2str(errno, CT_UPDATE)); - } nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL); res = nfct_query(ith, NFCT_Q_GET, tmp); -- cgit v1.2.3 From a3cd4dfb85b3ee9194ea82eb5185f9df2cb4ecf8 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Mon, 2 Feb 2015 12:35:12 -0800 Subject: conntrack: fix setting labels in updates When updating labels we always have to send the same sized bitmask as we received, as the bits we do omit will otherwise cleared as "padding". Mask has to have the same size as the labels, otherwise it will not be encoded by libnetfilter_conntrack, as different sizes are not accepted by the kernel either. Finally, kernel only retains old bit values that we send as zeroes in BOTH the label and the mask, due to XOR used in bit manipulation. This patch fixes all these issues and allows updates to set new labels without accidentally clearing old ones. Signed-off-by: Jarno Rajahalme Signed-off-by: Florian Westphal --- src/conntrack.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 1e45ca8..f6d7d9a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1422,17 +1422,31 @@ static void copy_label(struct nf_conntrack *tmp, const struct nf_conntrack *ct) if (options & CT_OPT_ADD_LABEL) { if (ctb == NULL) { - newmask = xnfct_bitmask_clone(tmpl.label_modify); - nfct_set_attr(tmp, ATTR_CONNLABELS, newmask); + nfct_set_attr(tmp, ATTR_CONNLABELS, + xnfct_bitmask_clone(tmpl.label_modify)); return; } + /* If we send a bitmask shorter than the kernel sent to us, the bits we + * omit will be cleared (as "padding"). So we always have to send the + * same sized bitmask as we received. + * + * Mask has to have the same size as the labels, otherwise it will not + * be encoded by libnetfilter_conntrack, as different sizes are not + * accepted by the kernel. + */ + newmask = nfct_bitmask_new(nfct_bitmask_maxbit(ctb)); for (i = 0; i <= nfct_bitmask_maxbit(ctb); i++) { - if (nfct_bitmask_test_bit(tmpl.label_modify, i)) + if (nfct_bitmask_test_bit(tmpl.label_modify, i)) { nfct_bitmask_set_bit(ctb, i); + nfct_bitmask_set_bit(newmask, i); + } else if (nfct_bitmask_test_bit(ctb, i)) { + /* Kernel only retains old bit values that are sent as + * zeroes in BOTH labels and mask. + */ + nfct_bitmask_unset_bit(ctb, i); + } } - - newmask = xnfct_bitmask_clone(tmpl.label_modify); nfct_set_attr(tmp, ATTR_CONNLABELS_MASK, newmask); } else if (ctb != NULL) { /* CT_OPT_DEL_LABEL */ -- cgit v1.2.3 From d5fdfac4873061620546c2328c55f9c5830fd0f8 Mon Sep 17 00:00:00 2001 From: Szilárd Pfeiffer Date: Thu, 25 Jun 2015 12:22:10 +0200 Subject: conntrack: refactor handling of address options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Szilárd Pfeiffer Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 69 ++++++++++++++++++++++++++------------------------------- 1 file changed, 32 insertions(+), 37 deletions(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index f6d7d9a..1bf5b2b 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -437,6 +437,10 @@ static const int opt2attr[] = { ['d'] = ATTR_ORIG_L3PROTO, ['r'] = ATTR_REPL_L3PROTO, ['q'] = ATTR_REPL_L3PROTO, + ['{'] = ATTR_ORIG_L3PROTO, + ['}'] = ATTR_ORIG_L3PROTO, + ['['] = ATTR_ORIG_L3PROTO, + [']'] = ATTR_ORIG_L3PROTO, ['m'] = ATTR_MARK, ['c'] = ATTR_SECMARK, ['i'] = ATTR_ID, @@ -1946,6 +1950,31 @@ static void merge_bitmasks(struct nfct_bitmask **current, nfct_bitmask_destroy(src); } +static void +nfct_set_addr_from_opt(int opt, struct nf_conntrack *ct, union ct_address *ad, + int *family) +{ + int l3protonum; + + options |= opt2type[opt]; + l3protonum = parse_addr(optarg, ad); + if (l3protonum == AF_UNSPEC) { + exit_error(PARAMETER_PROBLEM, + "Invalid IP address `%s'", optarg); + } + set_family(family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(ct, + opt2family_attr[opt][0], + ad->v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(ct, + opt2family_attr[opt][1], + &ad->v6); + } + nfct_set_attr_u8(ct, opt2attr[opt], l3protonum); +} + int main(int argc, char *argv[]) { int c, cmd; @@ -1953,7 +1982,7 @@ int main(int argc, char *argv[]) int res = 0, partial; size_t socketbuffersize = 0; int family = AF_UNSPEC; - int l3protonum, protonum = 0; + int protonum = 0; union ct_address ad; unsigned int command = 0; @@ -2024,47 +2053,13 @@ int main(int argc, char *argv[]) case 'd': case 'r': case 'q': - options |= opt2type[c]; - - l3protonum = parse_addr(optarg, &ad); - if (l3protonum == AF_UNSPEC) { - exit_error(PARAMETER_PROBLEM, - "Invalid IP address `%s'", optarg); - } - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(tmpl.ct, - opt2family_attr[c][0], - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(tmpl.ct, - opt2family_attr[c][1], - &ad.v6); - } - nfct_set_attr_u8(tmpl.ct, opt2attr[c], l3protonum); + nfct_set_addr_from_opt(c, tmpl.ct, &ad, &family); break; case '{': case '}': case '[': case ']': - options |= opt2type[c]; - l3protonum = parse_addr(optarg, &ad); - if (l3protonum == AF_UNSPEC) { - exit_error(PARAMETER_PROBLEM, - "Invalid IP address `%s'", optarg); - } - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(tmpl.mask, - opt2family_attr[c][0], - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(tmpl.mask, - opt2family_attr[c][1], - &ad.v6); - } - nfct_set_attr_u8(tmpl.mask, - ATTR_ORIG_L3PROTO, l3protonum); + nfct_set_addr_from_opt(c, tmpl.mask, &ad, &family); break; case 'p': options |= CT_OPT_PROTO; -- cgit v1.2.3 From 3309fdb4413cb32f9b95e05064dc9dbb56550939 Mon Sep 17 00:00:00 2001 From: Szilárd Pfeiffer Date: Thu, 25 Jun 2015 12:22:11 +0200 Subject: conntrack: fix expectation entry creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Szilárd Pfeiffer Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 1bf5b2b..67fcda0 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -2057,6 +2057,8 @@ int main(int argc, char *argv[]) break; case '{': case '}': + nfct_set_addr_from_opt(c, tmpl.exptuple, &ad, &family); + break; case '[': case ']': nfct_set_addr_from_opt(c, tmpl.mask, &ad, &family); -- cgit v1.2.3 From 900d7e80b8d8339622912c88f6faea96af4115d7 Mon Sep 17 00:00:00 2001 From: Szilárd Pfeiffer Date: Fri, 3 Jul 2015 01:04:58 +0200 Subject: conntrack: made the protocol option value case insensitive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extensions register protocols by lowercase protocol name, but value of proto command line option may be uppercase. Extension related options cannot be used when protocol name comparision fails. Signed-off-by: Szilárd Pfeiffer Signed-off-by: Florian Westphal --- src/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index 67fcda0..00b09b6 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -551,7 +551,7 @@ static struct ctproto_handler *findproto(char *name, int *pnum) /* is it in the list of supported protocol? */ list_for_each_entry(cur, &proto_list, head) { - if (strcmp(cur->name, name) == 0) { + if (strcasecmp(cur->name, name) == 0) { *pnum = cur->protonum; return cur; } -- cgit v1.2.3 From 8845f3db20c951fcf1db3229a818cfd185f17f2e Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 25 Aug 2015 15:33:51 +0200 Subject: conntrack: add zone direction support This patch adds support for zone directions. Since all options have the orig/reply as a prefix, I named it --orig-zone and --reply-zone to stay consistent with the rest of the cmdline options. As for the option chars, there was no unallocated reasonable combination, thus only long options are officially exposed in the help, similarly as in other cases. Test suite results, after patch: OK: 79 BAD: 0 Signed-off-by: Daniel Borkmann Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 10 +++++- include/conntrack.h | 2 +- src/conntrack.c | 67 ++++++++++++++++++++++++++-------------- tests/conntrack/testsuite/04zone | 18 ++++++++++- 4 files changed, 70 insertions(+), 27 deletions(-) (limited to 'src/conntrack.c') diff --git a/conntrack.8 b/conntrack.8 index abc26c5..a981a76 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -1,4 +1,4 @@ -.TH CONNTRACK 8 "Sep 25, 2014" "" "" +.TH CONNTRACK 8 "Aug 24, 2015" "" "" .\" Man page written by Harald Welte #define NUMBER_OF_CMD 19 -#define NUMBER_OF_OPT 27 +#define NUMBER_OF_OPT 29 struct ctproto_handler { struct list_head head; diff --git a/src/conntrack.c b/src/conntrack.c index 00b09b6..3ae4527 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -262,17 +262,24 @@ enum ct_options { CT_OPT_LABEL = (1 << CT_OPT_LABEL_BIT), CT_OPT_ADD_LABEL_BIT = 25, - CT_OPT_ADD_LABEL = (1 << CT_OPT_ADD_LABEL_BIT), + CT_OPT_ADD_LABEL = (1 << CT_OPT_ADD_LABEL_BIT), CT_OPT_DEL_LABEL_BIT = 26, - CT_OPT_DEL_LABEL = (1 << CT_OPT_DEL_LABEL_BIT), + CT_OPT_DEL_LABEL = (1 << CT_OPT_DEL_LABEL_BIT), + + CT_OPT_ORIG_ZONE_BIT = 27, + CT_OPT_ORIG_ZONE = (1 << CT_OPT_ORIG_ZONE_BIT), + + CT_OPT_REPL_ZONE_BIT = 28, + CT_OPT_REPL_ZONE = (1 << CT_OPT_REPL_ZONE_BIT), }; /* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ /* Update this mask to allow to filter based on new options. */ #define CT_COMPARISON (CT_OPT_PROTO | CT_OPT_ORIG | CT_OPT_REPL | \ CT_OPT_MARK | CT_OPT_SECMARK | CT_OPT_STATUS | \ - CT_OPT_ID | CT_OPT_ZONE | CT_OPT_LABEL) + CT_OPT_ID | CT_OPT_ZONE | CT_OPT_LABEL | \ + CT_OPT_ORIG_ZONE | CT_OPT_REPL_ZONE) static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_ORIG_SRC_BIT] = "src", @@ -302,6 +309,8 @@ static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_LABEL_BIT] = "label", [CT_OPT_ADD_LABEL_BIT] = "label-add", [CT_OPT_DEL_LABEL_BIT] = "label-del", + [CT_OPT_ORIG_ZONE_BIT] = "orig-zone", + [CT_OPT_REPL_ZONE_BIT] = "reply-zone", }; static struct option original_opts[] = { @@ -345,12 +354,14 @@ static struct option original_opts[] = { {"label", 1, 0, 'l'}, {"label-add", 1, 0, '<'}, {"label-del", 2, 0, '>'}, + {"orig-zone", 1, 0, '('}, + {"reply-zone", 1, 0, ')'}, {0, 0, 0, 0} }; static const char *getopt_str = ":L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" - "g::c:b:C::Sj::w:l:<:>::"; + "g::c:b:C::Sj::w:l:<:>::(:):"; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to @@ -365,26 +376,26 @@ 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,0,0,0,2,0,2,2,2,2,2,0,2,2,2,0,0}, -/*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}, -/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,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,0,0,0,2,2,0,0}, -/*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}, -/*CT_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}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2,2,0,0}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, -/*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}, + /* 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,0,0,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,0,0,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,0,0,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,0,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,0,0,0,2,0,0,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}, }; static const int cmd2type[][2] = { @@ -419,6 +430,8 @@ static const int opt2type[] = { ['l'] = CT_OPT_LABEL, ['<'] = CT_OPT_ADD_LABEL, ['>'] = CT_OPT_DEL_LABEL, + ['('] = CT_OPT_ORIG_ZONE, + [')'] = CT_OPT_REPL_ZONE, }; static const int opt2family_attr[][2] = { @@ -448,6 +461,8 @@ static const int opt2attr[] = { ['l'] = ATTR_CONNLABELS, ['<'] = ATTR_CONNLABELS, ['>'] = ATTR_CONNLABELS, + ['('] = ATTR_ORIG_ZONE, + [')'] = ATTR_REPL_ZONE, }; static char exit_msg[NUMBER_OF_CMD][64] = { @@ -511,6 +526,8 @@ static const char usage_parameters[] = " -t, --timeout timeout\t\tSet timeout\n" " -u, --status status\t\tSet status, eg. ASSURED\n" " -w, --zone value\t\tSet conntrack zone\n" + " --orig-zone value\t\tSet zone for original direction\n" + " --reply-zone value\t\tSet zone for reply direction\n" " -b, --buffer-size\t\tNetlink socket buffer size\n" ; @@ -2117,6 +2134,8 @@ int main(int argc, char *argv[]) break; } case 'w': + case '(': + case ')': options |= opt2type[c]; nfct_set_attr_u16(tmpl.ct, opt2attr[c], diff --git a/tests/conntrack/testsuite/04zone b/tests/conntrack/testsuite/04zone index 4ff3d34..dc8b691 100644 --- a/tests/conntrack/testsuite/04zone +++ b/tests/conntrack/testsuite/04zone @@ -1,4 +1,4 @@ -# create dummy +# 1) zone, 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 --zone 1; OK # display dummy -L --zone 1; OK @@ -6,3 +6,19 @@ -L --zone 0; OK # delete dummy -D --zone 1; OK +# 2) orig-zone, 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 --orig-zone 2; OK +# display dummy +-L --orig-zone 2; OK +# display dummy +-L --orig-zone 0; OK +# delete dummy +-D --orig-zone 2; OK +# 3) reply-zone, 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 --reply-zone 3; OK +# display dummy +-L --reply-zone 3; OK +# display dummy +-L --reply-zone 0; OK +# delete dummy +-D --reply-zone 3; OK -- cgit v1.2.3