From 3f6a2e90936bbaac3a66e9bfb2a21e22c3504045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Mon, 1 Feb 2016 13:30:06 +0000 Subject: conntrack: add support for CIDR notation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for using CIDR notation in --{orig,tuple}-{src,dst} arguments, instead of free-form formatting netmask in --mask-{src,dst}. Example: conntrack -L -s 2001:db8::/56 Instead of: conntrack -L -s 2001:db8:: --mask-src ffff:ffff:ffff:ff00:: Signed-off-by: Asbjørn Sloth Tønnesen Signed-off-by: Pablo Neira Ayuso --- src/conntrack.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 5 deletions(-) (limited to 'src/conntrack.c') diff --git a/src/conntrack.c b/src/conntrack.c index cdf7311..2367459 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -434,6 +434,17 @@ static const int opt2type[] = { [')'] = CT_OPT_REPL_ZONE, }; +static const int opt2maskopt[] = { + ['s'] = '{', + ['d'] = '}', + ['r'] = 0, /* no netmask */ + ['q'] = 0, /* support yet */ + ['{'] = 0, + ['}'] = 0, + ['['] = '{', + [']'] = '}', +}; + static const int opt2family_attr[][2] = { ['s'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, ['d'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, @@ -684,6 +695,21 @@ static int bit2cmd(int command) return i; } +static const char *get_long_opt(int opt) +{ + struct option o; + int i; + + for (i = 0;; i++) { + o = opts[i]; + if (o.name == NULL) + break; + if (o.val == opt) + return o.name; + } + return "unknown"; +} + int generic_opt_check(int local_options, int num_opts, char *optset, const char *optflg[], unsigned int *coupled_flags, int coupled_flags_size, @@ -2102,6 +2128,24 @@ static void merge_bitmasks(struct nfct_bitmask **current, nfct_bitmask_destroy(src); } +static void +nfct_build_netmask(uint32_t *dst, int b, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if (b >= 32) { + dst[i] = 0xffffffff; + b -= 32; + } else if (b > 0) { + dst[i] = (1 << b) - 1; + b = 0; + } else { + dst[i] = 0; + } + } +} + static void nfct_set_addr_opt(int opt, struct nf_conntrack *ct, union ct_address *ad, int l3protonum) @@ -2124,17 +2168,47 @@ nfct_set_addr_opt(int opt, struct nf_conntrack *ct, union ct_address *ad, static void nfct_parse_addr_from_opt(int opt, struct nf_conntrack *ct, + struct nf_conntrack *ctmask, union ct_address *ad, int *family) { - int l3protonum; + int l3protonum, mask, maskopt; - l3protonum = parse_addr(optarg, ad, NULL); + l3protonum = parse_addr(optarg, ad, &mask); if (l3protonum == AF_UNSPEC) { exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'", optarg); } set_family(family, l3protonum); + maskopt = opt2maskopt[opt]; + if (!maskopt && mask != -1) { + exit_error(PARAMETER_PROBLEM, + "CIDR notation unavailable" + " for `--%s'", get_long_opt(opt)); + } else if (mask == -2) { + exit_error(PARAMETER_PROBLEM, + "Invalid netmask"); + } + nfct_set_addr_opt(opt, ct, ad, l3protonum); + + /* bail if we don't have a netmask to set*/ + if (!maskopt || mask == -1 || ctmask == NULL) + return; + + switch(l3protonum) { + case AF_INET: + if (mask == 32) + return; + nfct_build_netmask(&ad->v4, mask, 1); + break; + case AF_INET6: + if (mask == 128) + return; + nfct_build_netmask((uint32_t *) &ad->v6, mask, 4); + break; + } + + nfct_set_addr_opt(maskopt, ctmask, ad, l3protonum); } int main(int argc, char *argv[]) @@ -2215,15 +2289,17 @@ int main(int argc, char *argv[]) case 'd': case 'r': case 'q': - nfct_parse_addr_from_opt(c, tmpl.ct, &ad, &family); + nfct_parse_addr_from_opt(c, tmpl.ct, tmpl.mask, + &ad, &family); break; case '[': case ']': - nfct_parse_addr_from_opt(c, tmpl.exptuple, &ad, &family); + nfct_parse_addr_from_opt(c, tmpl.exptuple, tmpl.mask, + &ad, &family); break; case '{': case '}': - nfct_parse_addr_from_opt(c, tmpl.mask, &ad, &family); + nfct_parse_addr_from_opt(c, tmpl.mask, NULL, &ad, &family); break; case 'p': options |= CT_OPT_PROTO; -- cgit v1.2.3