From ad33006a162fc6202de096a8f6d65a7c841da1ce Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 22 Jun 2010 11:52:27 +0200 Subject: conntrack: add `--any-nat' to filter any NATted flow This patch adds the --any-nat option that allows to display src-NATted OR dst-NATted flows. Signed-off-by: Pablo Neira Ayuso --- conntrack.8 | 3 ++ include/conntrack.h | 2 +- src/conntrack.c | 92 ++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 74 insertions(+), 23 deletions(-) diff --git a/conntrack.8 b/conntrack.8 index 9b4d14b..fee3a8c 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -146,6 +146,9 @@ Filter source NAT connections. .BI "-g, --dst-nat " Filter destination NAT connections. .TP +.BI "-j, --any-nat " +Filter any NAT connections. +.TP .BI "--tuple-src " IP_ADDRESS Specify the tuple source address of an expectation. .TP diff --git a/include/conntrack.h b/include/conntrack.h index d8112aa..8e18e51 100644 --- a/include/conntrack.h +++ b/include/conntrack.h @@ -10,7 +10,7 @@ #include #define NUMBER_OF_CMD 18 -#define NUMBER_OF_OPT 22 +#define NUMBER_OF_OPT 23 struct ctproto_handler { struct list_head head; diff --git a/src/conntrack.c b/src/conntrack.c index 611b179..b839700 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -190,6 +190,9 @@ enum ct_options { CT_OPT_BUFFERSIZE_BIT = 21, CT_OPT_BUFFERSIZE = (1 << CT_OPT_BUFFERSIZE_BIT), + + CT_OPT_ANY_NAT_BIT = 22, + CT_OPT_ANY_NAT = (1 << CT_OPT_ANY_NAT_BIT), }; /* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ @@ -219,7 +222,8 @@ static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_DST_NAT_BIT] = "dst-nat", [CT_OPT_OUTPUT_BIT] = "output", [CT_OPT_SECMARK_BIT] = "secmark", - [CT_OPT_BUFFERSIZE_BIT] = "buffer-size" + [CT_OPT_BUFFERSIZE_BIT] = "buffer-size", + [CT_OPT_ANY_NAT_BIT] = "any-nat", }; static struct option original_opts[] = { @@ -258,12 +262,13 @@ static struct option original_opts[] = { {"dst-nat", 2, 0, 'g'}, {"output", 1, 0, 'o'}, {"buffer-size", 1, 0, 'b'}, + {"any-nat", 2, 0, 'j'}, {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::S"; + "g::c:b:C::Sj::"; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to @@ -278,25 +283,25 @@ 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*/ -/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,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}, -/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,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}, -/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,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}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,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}, -/*HELP*/ {0,0,0,0,2,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,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}, -/*EXP_DELETE*/{1,1,2,2,1,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}, -/*EXP_FLUSH*/ {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,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}, -/*EXP_COUNT*/ {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}, + /* s d r q p t u z e [ ] { } a m i f n g o c b j*/ +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*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}, +/*VERSION*/ {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}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,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}, +/*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}, +/*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}, +/*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}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,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}, +/*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}, +/*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}, }; static const int cmd2type[][2] = { @@ -325,6 +330,7 @@ static const int opt2type[] = { ['m'] = CT_OPT_MARK, ['c'] = CT_OPT_SECMARK, ['i'] = CT_OPT_ID, + ['j'] = CT_OPT_ANY_NAT, }; static const int opt2family_attr[][2] = { @@ -378,6 +384,7 @@ static const char usage_conntrack_parameters[] = "Conntrack parameters and options:\n" " -n, --src-nat ip\t\t\tsource NAT ip\n" " -g, --dst-nat ip\t\t\tdestination NAT ip\n" + " -j, --any-nat ip\t\t\tsource or destination NAT ip\n" " -m, --mark mark\t\t\tSet mark\n" " -c, --secmark secmark\t\t\tSet selinux secmark\n" " -e, --event-mask eventmask\t\tEvent mask, eg. NEW,DESTROY\n" @@ -827,6 +834,10 @@ nat_parse(char *arg, int portok, struct nf_conntrack *obj, int type) nfct_set_attr_u16(obj, ATTR_SNAT_PORT, ntohs(port)); else if (type == CT_OPT_DST_NAT) nfct_set_attr_u16(obj, ATTR_DNAT_PORT, ntohs(port)); + else if (type == CT_OPT_ANY_NAT) { + nfct_set_attr_u16(obj, ATTR_SNAT_PORT, ntohs(port)); + nfct_set_attr_u16(obj, ATTR_DNAT_PORT, ntohs(port)); + } } if (parse_addr(arg, &parse) == AF_UNSPEC) @@ -890,6 +901,36 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct) !nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) return 1; } + if (options & CT_OPT_ANY_NAT) { + if (nfct_attr_is_set(obj, ATTR_SNAT_IPV4) && + nfct_attr_is_set(obj, ATTR_DNAT_IPV4)) { + uint32_t ip2; + + ip = nfct_get_attr_u32(obj, ATTR_SNAT_IPV4); + ip2 = nfct_get_attr_u32(obj, ATTR_DNAT_IPV4); + if (ip != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST) && + ip2 != nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC)) { + return 1; + } + } + if (nfct_attr_is_set(obj, ATTR_SNAT_PORT) && + nfct_attr_is_set(obj, ATTR_DNAT_PORT)) { + uint16_t p1, p2; + + p1 = nfct_get_attr_u16(obj, ATTR_SNAT_PORT); + p2 = nfct_get_attr_u16(obj, ATTR_DNAT_PORT); + if (p1 != nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST) && + p2 != nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC)) { + return 1; + } + } + if (!nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_SPAT) && + !nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)) { + return 1; + } + } return 0; } @@ -1346,7 +1387,8 @@ int main(int argc, char *argv[]) options |= CT_OPT_ZERO; break; case 'n': - case 'g': { + case 'g': + case 'j': { char *tmp = NULL; options |= opt2type[c]; @@ -1414,6 +1456,12 @@ int main(int argc, char *argv[]) if (family == AF_UNSPEC) family = AF_INET; + /* we cannot check this combination with generic_opt_check. */ + if (options & CT_OPT_ANY_NAT && + ((options & CT_OPT_SRC_NAT) || (options & CT_OPT_DST_NAT))) { + exit_error(PARAMETER_PROBLEM, "cannot specify `--src-nat' or " + "`--dst-nat' with `--any-nat'"); + } cmd = bit2cmd(command); res = generic_opt_check(options, NUMBER_OF_OPT, commands_v_options[cmd], optflags, -- cgit v1.2.3