Add support for using CIDR notation in -s and -d arguments, instead of free-form formatting IPv6 netmask in --mask-src and --mask-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 <ast@xxxxxxxxxx> --- conntrack.8 | 2 ++ src/conntrack.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/conntrack.8 b/conntrack.8 index 4bb8bfe..5072839 100644 --- a/conntrack.8 +++ b/conntrack.8 @@ -117,9 +117,11 @@ This option can only be used in conjunction with "\-E, \-\-event". .TP .BI "-s, --orig-src " IP_ADDRESS Match only entries whose source address in the original direction equals the one specified as argument. +Implies "--mask-src" when CIDR notation is used. .TP .BI "-d, --orig-dst " IP_ADDRESS Match only entries whose destination address in the original direction equals the one specified as argument. +Implies "--mask-dst" when CIDR notation is used. .TP .BI "-r, --reply-src " IP_ADDRESS Match only entries whose source address in the reply direction equals the one specified as argument. diff --git a/src/conntrack.c b/src/conntrack.c index ceafb0c..87903b9 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -421,6 +421,13 @@ static const int opt2type[] = { ['>'] = CT_OPT_DEL_LABEL, }; +static const char opt2mask[] = { + ['s'] = '{', + ['d'] = '}', + ['r'] = 0, /* no netmask */ + ['q'] = 0, /* support yet */ +}; + static const int opt2family_attr[][2] = { ['s'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, ['d'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, @@ -1008,15 +1015,37 @@ parse_inetaddr(const char *cp, struct addr_parse *parse) } static int -parse_addr(const char *cp, union ct_address *address) +parse_addr(const char *cp, union ct_address *address, int *mask) { struct addr_parse parse; int ret; + char buf[INET6_ADDRSTRLEN]; + char *slash, *end; + + strncpy((char *) &buf, cp, INET6_ADDRSTRLEN); + buf[INET6_ADDRSTRLEN-1] = '\0'; + + if (mask != NULL) { + slash = strchr(buf, '/'); + if (slash != NULL) { + *mask = strtol(slash+1, &end, 10); + if (*mask < 0 || end != slash+strlen(slash)) + *mask = -2; + slash[0] = '\0'; + } else { + *mask = -1; + } + } - if ((ret = parse_inetaddr(cp, &parse)) == AF_INET) + if ((ret = parse_inetaddr(buf, &parse)) == AF_INET) { address->v4 = parse.addr.s_addr; - else if (ret == AF_INET6) + if (mask != NULL && *mask > 32) + *mask = -2; + } else if (ret == AF_INET6) { memcpy(address->v6, &parse.addr6, sizeof(parse.addr6)); + if (mask != NULL && *mask > 128) + *mask = -2; + } return ret; } @@ -1060,7 +1089,7 @@ nat_parse(char *arg, struct nf_conntrack *obj, int type) } } - if (parse_addr(arg, &parse) == AF_UNSPEC) { + if (parse_addr(arg, &parse, NULL) == AF_UNSPEC) { if (strlen(arg) == 0) { exit_error(PARAMETER_PROBLEM, "No IP specified"); } else { @@ -2048,6 +2077,24 @@ static void merge_bitmasks(struct nfct_bitmask **current, nfct_bitmask_destroy(src); } +static void +buildnetmask(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; + } + } +} + int main(int argc, char *argv[]) { int c, cmd; @@ -2058,6 +2105,7 @@ int main(int argc, char *argv[]) int l3protonum, protonum = 0; union ct_address ad; unsigned int command = 0; + int mask, mc; /* we release these objects in the exit_error() path. */ if (!alloc_tmpl_objects()) @@ -2128,29 +2176,55 @@ int main(int argc, char *argv[]) case 'q': options |= opt2type[c]; - l3protonum = parse_addr(optarg, &ad); + l3protonum = parse_addr(optarg, &ad, &mask); if (l3protonum == AF_UNSPEC) { exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'", optarg); } set_family(&family, l3protonum); + mc = opt2mask[c]; + if (mask != -1 && !mc) { + exit_error(PARAMETER_PROBLEM, + "CIDR notation unavailable" + " for `%c'", c); + } else if (mask == -2) { + exit_error(PARAMETER_PROBLEM, + "Invalid netmask"); + } if (l3protonum == AF_INET) { nfct_set_attr_u32(tmpl.ct, opt2family_attr[c][0], ad.v4); + if (mc) { + if (mask >= 0 && mask < 32) + buildnetmask(&ad.v4, mask, 1); + else + mc = 0; + } } else if (l3protonum == AF_INET6) { nfct_set_attr(tmpl.ct, opt2family_attr[c][1], &ad.v6); + if (mc) { + if (mask >= 0 && mask < 128) + buildnetmask((uint32_t *) &ad.v6, mask, 4); + else + mc = 0; + } } nfct_set_attr_u8(tmpl.ct, opt2attr[c], l3protonum); + if (mc) { + c = mc; + goto set_netmask; + } break; case '{': case '}': case '[': case ']': + l3protonum = parse_addr(optarg, &ad, NULL); +set_netmask: options |= opt2type[c]; - l3protonum = parse_addr(optarg, &ad); if (l3protonum == AF_UNSPEC) { exit_error(PARAMETER_PROBLEM, "Invalid IP address `%s'", optarg); -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html