diff --git a/SOURCES/0001-conntrack-Support-IPv6-NAT.patch b/SOURCES/0001-conntrack-Support-IPv6-NAT.patch new file mode 100644 index 0000000..48f43dd --- /dev/null +++ b/SOURCES/0001-conntrack-Support-IPv6-NAT.patch @@ -0,0 +1,459 @@ +From c1874130f845e526de76d116639c044cb30fcc9a Mon Sep 17 00:00:00 2001 +From: Neil Wilson +Date: Thu, 16 Mar 2017 11:49:03 +0000 +Subject: [PATCH] conntrack: Support IPv6 NAT + +Refactor and improve nat support to allow conntrack to manage IPv6 +NAT entries. + +Refactor and improve conntrack nat tests to include IPv6 NAT. + +Signed-off-by: Neil Wilson +Signed-off-by: Pablo Neira Ayuso +(cherry picked from commit 29b390a2122143997a651e6b25d7496e62ead2a1) +--- + src/conntrack.c | 213 ++++++++++++++++++++--------- + tests/conntrack/testsuite/00create | 6 + + tests/conntrack/testsuite/03nat | 8 ++ + tests/conntrack/testsuite/07nat6 | 56 ++++++++ + 4 files changed, 216 insertions(+), 67 deletions(-) + create mode 100644 tests/conntrack/testsuite/07nat6 + +diff --git a/src/conntrack.c b/src/conntrack.c +index ff030fe54e103..cbf03c7be8834 100644 +--- a/src/conntrack.c ++++ b/src/conntrack.c +@@ -43,6 +43,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -437,6 +439,9 @@ static const int opt2type[] = { + static const int opt2maskopt[] = { + ['s'] = '{', + ['d'] = '}', ++ ['g'] = 0, ++ ['j'] = 0, ++ ['n'] = 0, + ['r'] = 0, /* no netmask */ + ['q'] = 0, /* support yet */ + ['{'] = 0, +@@ -448,6 +453,8 @@ static const int opt2maskopt[] = { + static const int opt2family_attr[][2] = { + ['s'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, + ['d'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, ++ ['g'] = { ATTR_DNAT_IPV4, ATTR_DNAT_IPV6 }, ++ ['n'] = { ATTR_SNAT_IPV4, ATTR_SNAT_IPV6 }, + ['r'] = { ATTR_REPL_IPV4_SRC, ATTR_REPL_IPV6_SRC }, + ['q'] = { ATTR_REPL_IPV4_DST, ATTR_REPL_IPV6_DST }, + ['{'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, +@@ -459,6 +466,8 @@ static const int opt2family_attr[][2] = { + static const int opt2attr[] = { + ['s'] = ATTR_ORIG_L3PROTO, + ['d'] = ATTR_ORIG_L3PROTO, ++ ['g'] = ATTR_ORIG_L3PROTO, ++ ['n'] = ATTR_ORIG_L3PROTO, + ['r'] = ATTR_REPL_L3PROTO, + ['q'] = ATTR_REPL_L3PROTO, + ['{'] = ATTR_ORIG_L3PROTO, +@@ -1094,58 +1103,85 @@ parse_addr(const char *cp, union ct_address *address, int *mask) + return family; + } + +-static void +-nat_parse(char *arg, struct nf_conntrack *obj, int type) ++static bool ++valid_port(char *cursor) + { +- char *colon, *error; +- union ct_address parse; ++ const char *str = cursor; ++ /* Missing port number */ ++ if (!*str) ++ return false; + +- colon = strchr(arg, ':'); ++ /* Must be entirely digits - no spaces or +/- */ ++ while (*cursor) { ++ if (!isdigit(*cursor)) ++ return false; ++ else ++ ++cursor; ++ } + +- if (colon) { +- uint16_t port; ++ /* Must be in range */ ++ errno = 0; ++ long port = strtol(str, NULL, 10); + +- *colon = '\0'; ++ if ((errno == ERANGE && (port == LONG_MAX || port == LONG_MIN)) ++ || (errno != 0 && port == 0) || (port > USHRT_MAX)) ++ return false; + +- port = (uint16_t)atoi(colon+1); +- if (port == 0) { +- if (strlen(colon+1) == 0) { +- exit_error(PARAMETER_PROBLEM, +- "No port specified after `:'"); +- } else { +- exit_error(PARAMETER_PROBLEM, +- "Port `%s' not valid", colon+1); +- } +- } ++ return true; ++} ++ ++static void ++split_address_and_port(const char *arg, char **address, char **port_str) ++{ ++ char *cursor = strchr(arg, '['); ++ ++ if (cursor) { ++ /* IPv6 address with port*/ ++ char *start = cursor + 1; + +- error = strchr(colon+1, ':'); +- if (error) ++ cursor = strchr(start, ']'); ++ if (start == cursor) { ++ exit_error(PARAMETER_PROBLEM, ++ "No IPv6 address specified"); ++ } else if (!cursor) { + exit_error(PARAMETER_PROBLEM, +- "Invalid port:port syntax"); +- +- if (type == CT_OPT_SRC_NAT) +- nfct_set_attr_u16(tmpl.ct, ATTR_SNAT_PORT, ntohs(port)); +- else if (type == CT_OPT_DST_NAT) +- nfct_set_attr_u16(tmpl.ct, ATTR_DNAT_PORT, ntohs(port)); +- else if (type == CT_OPT_ANY_NAT) { +- nfct_set_attr_u16(tmpl.ct, ATTR_SNAT_PORT, ntohs(port)); +- nfct_set_attr_u16(tmpl.ct, ATTR_DNAT_PORT, ntohs(port)); ++ "No closing ']' around IPv6 address"); + } +- } ++ size_t len = cursor - start; + +- if (parse_addr(arg, &parse, NULL) == AF_UNSPEC) { +- if (strlen(arg) == 0) { +- exit_error(PARAMETER_PROBLEM, "No IP specified"); ++ cursor = strchr(cursor, ':'); ++ if (cursor) { ++ /* Copy address only if there is a port */ ++ *address = strndup(start, len); ++ } ++ } else { ++ cursor = strchr(arg, ':'); ++ if (cursor && !strchr(cursor + 1, ':')) { ++ /* IPv4 address with port */ ++ *address = strndup(arg, cursor - arg); + } else { ++ /* v6 address */ ++ cursor = NULL; ++ } ++ } ++ if (cursor) { ++ /* Parse port entry */ ++ cursor++; ++ if (strlen(cursor) == 0) { + exit_error(PARAMETER_PROBLEM, +- "Invalid IP address `%s'", arg); ++ "No port specified after `:'"); + } ++ if (!valid_port(cursor)) { ++ exit_error(PARAMETER_PROBLEM, ++ "Invalid port `%s'", cursor); ++ } ++ *port_str = strdup(cursor); ++ } else { ++ /* No port colon or more than one colon (ipv6) ++ * assume arg is straight IP address and no port ++ */ ++ *address = strdup(arg); + } +- +- if (type == CT_OPT_SRC_NAT || type == CT_OPT_ANY_NAT) +- nfct_set_attr_u32(tmpl.ct, ATTR_SNAT_IPV4, parse.v4); +- else if (type == CT_OPT_DST_NAT || type == CT_OPT_ANY_NAT) +- nfct_set_attr_u32(tmpl.ct, ATTR_DNAT_IPV4, parse.v4); + } + + static void +@@ -1289,7 +1325,7 @@ nfct_ip6_net_cmp(const union ct_address *addr, const struct ct_network *net) + + static int + nfct_ip_net_cmp(int family, const union ct_address *addr, +- const struct ct_network *net) ++ const struct ct_network *net) + { + switch(family) { + case AF_INET: +@@ -2128,6 +2164,7 @@ static void merge_bitmasks(struct nfct_bitmask **current, + nfct_bitmask_destroy(src); + } + ++ + static void + nfct_build_netmask(uint32_t *dst, int b, int n) + { +@@ -2147,10 +2184,9 @@ nfct_build_netmask(uint32_t *dst, int b, int n) + } + + static void +-nfct_set_addr_opt(int opt, struct nf_conntrack *ct, union ct_address *ad, +- int l3protonum) ++nfct_set_addr_only(const int opt, struct nf_conntrack *ct, union ct_address *ad, ++ const int l3protonum) + { +- options |= opt2type[opt]; + switch (l3protonum) { + case AF_INET: + nfct_set_attr_u32(ct, +@@ -2163,24 +2199,33 @@ nfct_set_addr_opt(int opt, struct nf_conntrack *ct, union ct_address *ad, + &ad->v6); + break; + } ++} ++ ++static void ++nfct_set_addr_opt(const int opt, struct nf_conntrack *ct, union ct_address *ad, ++ const int l3protonum) ++{ ++ options |= opt2type[opt]; ++ nfct_set_addr_only(opt, ct, ad, l3protonum); + nfct_set_attr_u8(ct, opt2attr[opt], l3protonum); + } + + static void +-nfct_parse_addr_from_opt(int opt, struct nf_conntrack *ct, +- struct nf_conntrack *ctmask, +- union ct_address *ad, int *family) ++nfct_parse_addr_from_opt(const int opt, const char *arg, ++ struct nf_conntrack *ct, ++ struct nf_conntrack *ctmask, ++ union ct_address *ad, int *family) + { +- int l3protonum, mask, maskopt; ++ int mask, maskopt; + +- l3protonum = parse_addr(optarg, ad, &mask); ++ const int l3protonum = parse_addr(arg, ad, &mask); + if (l3protonum == AF_UNSPEC) { + exit_error(PARAMETER_PROBLEM, +- "Invalid IP address `%s'", optarg); ++ "Invalid IP address `%s'", arg); + } + set_family(family, l3protonum); + maskopt = opt2maskopt[opt]; +- if (!maskopt && mask != -1) { ++ if (mask != -1 && !maskopt) { + exit_error(PARAMETER_PROBLEM, + "CIDR notation unavailable" + " for `--%s'", get_long_opt(opt)); +@@ -2192,7 +2237,7 @@ nfct_parse_addr_from_opt(int opt, struct nf_conntrack *ct, + nfct_set_addr_opt(opt, ct, ad, l3protonum); + + /* bail if we don't have a netmask to set*/ +- if (!maskopt || mask == -1 || ctmask == NULL) ++ if (mask == -1 || !maskopt || ctmask == NULL) + return; + + switch(l3protonum) { +@@ -2211,6 +2256,24 @@ nfct_parse_addr_from_opt(int opt, struct nf_conntrack *ct, + nfct_set_addr_opt(maskopt, ctmask, ad, l3protonum); + } + ++static void ++nfct_set_nat_details(const int opt, struct nf_conntrack *ct, ++ union ct_address *ad, const char *port_str, ++ const int family) ++{ ++ const int type = opt2type[opt]; ++ ++ nfct_set_addr_only(opt, ct, ad, family); ++ if (port_str && type == CT_OPT_SRC_NAT) { ++ nfct_set_attr_u16(ct, ATTR_SNAT_PORT, ++ ntohs((uint16_t)atoi(port_str))); ++ } else if (port_str && type == CT_OPT_DST_NAT) { ++ nfct_set_attr_u16(ct, ATTR_DNAT_PORT, ++ ntohs((uint16_t)atoi(port_str))); ++ } ++ ++} ++ + int main(int argc, char *argv[]) + { + int c, cmd; +@@ -2289,17 +2352,18 @@ int main(int argc, char *argv[]) + case 'd': + case 'r': + case 'q': +- nfct_parse_addr_from_opt(c, tmpl.ct, tmpl.mask, +- &ad, &family); ++ nfct_parse_addr_from_opt(c, optarg, tmpl.ct, ++ tmpl.mask, &ad, &family); + break; + case '[': + case ']': +- nfct_parse_addr_from_opt(c, tmpl.exptuple, tmpl.mask, +- &ad, &family); ++ nfct_parse_addr_from_opt(c, optarg, tmpl.exptuple, ++ tmpl.mask, &ad, &family); + break; + case '{': + case '}': +- nfct_parse_addr_from_opt(c, tmpl.mask, NULL, &ad, &family); ++ nfct_parse_addr_from_opt(c, optarg, tmpl.mask, ++ NULL, &ad, &family); + break; + case 'p': + options |= CT_OPT_PROTO; +@@ -2341,19 +2405,34 @@ int main(int argc, char *argv[]) + break; + case 'n': + case 'g': +- case 'j': { +- char *tmp = NULL; +- ++ case 'j': + options |= opt2type[c]; +- +- tmp = get_optional_arg(argc, argv); +- if (tmp == NULL) +- continue; +- +- set_family(&family, AF_INET); +- nat_parse(tmp, tmpl.ct, opt2type[c]); ++ char *optional_arg = get_optional_arg(argc, argv); ++ ++ if (optional_arg) { ++ char *port_str = NULL; ++ char *nat_address = NULL; ++ ++ split_address_and_port(optional_arg, ++ &nat_address, ++ &port_str); ++ nfct_parse_addr_from_opt(c, nat_address, ++ tmpl.ct, NULL, ++ &ad, &family); ++ if (c == 'j') { ++ /* Set details on both src and dst ++ * with any-nat ++ */ ++ nfct_set_nat_details('g', tmpl.ct, &ad, ++ port_str, family); ++ nfct_set_nat_details('n', tmpl.ct, &ad, ++ port_str, family); ++ } else { ++ nfct_set_nat_details(c, tmpl.ct, &ad, ++ port_str, family); ++ } ++ } + break; +- } + case 'w': + case '(': + case ')': +diff --git a/tests/conntrack/testsuite/00create b/tests/conntrack/testsuite/00create +index 40e2c1952940c..afe4342e9b00d 100644 +--- a/tests/conntrack/testsuite/00create ++++ b/tests/conntrack/testsuite/00create +@@ -18,3 +18,9 @@ + -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 ++# create a v6 conntrack ++-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK ++# delete v6 conntrack ++-D -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 ; OK ++# mismatched address family ++-I -s 2001:DB8::1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD +diff --git a/tests/conntrack/testsuite/03nat b/tests/conntrack/testsuite/03nat +index f94e8ffeb2f9f..014feb8e6e3ab 100644 +--- a/tests/conntrack/testsuite/03nat ++++ b/tests/conntrack/testsuite/03nat +@@ -36,5 +36,13 @@ + -L --dst-nat 3.3.3.3:81 ; OK + # show + -L --dst-nat 1.1.1.1:80 ; OK ++# badport ++-L --dst-nat 1.1.1.1: ; BAD ++# badport ++-L --dst-nat 1.1.1.1::; BAD ++# badport ++-L --dst-nat 1.1.1.1:80:80; BAD ++# badport ++-L --dst-nat 1.1.1.1:65536; BAD + # delete + -D -s 1.1.1.1 ; OK +diff --git a/tests/conntrack/testsuite/07nat6 b/tests/conntrack/testsuite/07nat6 +new file mode 100644 +index 0000000000000..8cecd8e9bdd88 +--- /dev/null ++++ b/tests/conntrack/testsuite/07nat6 +@@ -0,0 +1,56 @@ ++# create dummy ++-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --dst-nat 2001:DB8::3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK ++# show ++-L --dst-nat ; OK ++# show ++-L --dst-nat 2001:DB8::3.3.3.3 ; OK ++# show ++-L --src-nat ; OK ++# delete ++-D -s 2001:DB8::1.1.1.1 ; OK ++# create dummy again ++-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --src-nat 2001:DB8::3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK ++# show ++-L --src-nat ; OK ++# show ++-L --src-nat 2001:DB8::3.3.3.3 ; OK ++# show ++-L --dst-nat ; OK ++# show any-nat ++-L --any-nat ; OK ++# delete ++-D -s 2001:DB8::1.1.1.1 ; OK ++# bad combination ++-L --dst-nat --any-nat ; BAD ++# bad combination ++-L --src-nat --any-nat ; BAD ++# bad combination ++-L --src-nat --dst-nat --any-nat ; BAD ++# create ++-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --dst-nat [2001:DB8::3.3.3.3]:80 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK ++# show ++-L --dst-nat [2001:DB8::3.3.3.3]:80 ; OK ++# show ++-L --any-nat [2001:DB8::3.3.3.3]:80 ; OK ++# show ++-L --dst-nat [2001:DB8::3.3.3.3]:81 ; OK ++# show ++-L --dst-nat [2001:DB8::1.1.1.1]:80 ; OK ++# noport ++-L --dst-nat [2001:DB8::1.1.1.1]: ; BAD ++# badport ++-L --dst-nat [2001:DB8::1.1.1.1]:: ; BAD ++# badport ++-L --dst-nat [2001:DB8::1.1.1.1]:80:80 ; BAD ++# badport ++-L --dst-nat [2001:DB8::1.1.1.1]:65536 ; BAD ++# delete ++-D -s 2001:DB8::1.1.1.1 ; OK ++# mismatched address family ++-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --dst-nat 3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD ++# mismatched address family ++-I -s 1.1.1.1 -d 2.2.2.2 --dst-nat 2001:DB8::3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD ++# create - brackets only for ports in nat ++-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --dst-nat [2001:DB8::3.3.3.3] -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD ++# create - brackets rejected elsewhere ++-I -s [2001:DB8::1.1.1.1] -d 2001:DB8::2.2.2.2 --dst-nat 2001:DB8::3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD +-- +2.21.0 + diff --git a/SOURCES/0002-conntrackd-helpers-dhcpv6-Fix-potential-array-overru.patch b/SOURCES/0002-conntrackd-helpers-dhcpv6-Fix-potential-array-overru.patch new file mode 100644 index 0000000..acb18a5 --- /dev/null +++ b/SOURCES/0002-conntrackd-helpers-dhcpv6-Fix-potential-array-overru.patch @@ -0,0 +1,33 @@ +From bdb61c66cf0594fef26c6fc790092815c2d09721 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Tue, 12 Feb 2019 17:31:31 +0100 +Subject: [PATCH] conntrackd: helpers: dhcpv6: Fix potential array overrun + +The value dhcpv6_msg_type points at is used as index to dhcpv6_timeouts +array, so upper boundary check has to treat a value of +ARRAY_SIZE(dhcpv6_timeouts) as invalid. + +Fixes: 36118bfc4901b ("conntrackd: helpers: add DHCPv6 helper") +Signed-off-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +(cherry picked from commit 764a435c26e29900921ad5cdbd160a466c3c7416) +--- + src/helpers/dhcpv6.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/helpers/dhcpv6.c b/src/helpers/dhcpv6.c +index 73632ec181a95..f87b6cebfe157 100644 +--- a/src/helpers/dhcpv6.c ++++ b/src/helpers/dhcpv6.c +@@ -72,7 +72,7 @@ dhcpv6_helper_cb(struct pkt_buff *pkt, uint32_t protoff, + return NF_ACCEPT; + + dhcpv6_msg_type = pktb_network_header(pkt) + protoff + sizeof(struct udphdr); +- if (*dhcpv6_msg_type > ARRAY_SIZE(dhcpv6_timeouts)) { ++ if (*dhcpv6_msg_type >= ARRAY_SIZE(dhcpv6_timeouts)) { + printf("Dropping DHCPv6 message with bad type %u\n", + *dhcpv6_msg_type); + return NF_DROP; +-- +2.21.0 + diff --git a/SOURCES/0003-nfct-Drop-dead-code-in-nfct_timeout_parse_params.patch b/SOURCES/0003-nfct-Drop-dead-code-in-nfct_timeout_parse_params.patch new file mode 100644 index 0000000..d39314a --- /dev/null +++ b/SOURCES/0003-nfct-Drop-dead-code-in-nfct_timeout_parse_params.patch @@ -0,0 +1,47 @@ +From 3a78f5f896726ef8ad08cf8f750f2bc57dd85ab5 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Tue, 12 Feb 2019 23:44:46 +0100 +Subject: [PATCH] nfct: Drop dead code in nfct_timeout_parse_params() + +Due to the first switch() in that function, default case in second one +is unreachable. Given that both of them contain the same cases but the +first one merely acts as an invalid command barrier (adding no value to +the second one), drop the first one to make invalid commands actually +hit default case in the second switch(). + +Fixes: dd73ceecdbe87 ("nfct: Update syntax to specify command before subsystem") +Signed-off-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +(cherry picked from commit 9b477e07e00bc2d651784d7c82c2123f0bd7386b) +--- + src/nfct-extensions/timeout.c | 14 -------------- + 1 file changed, 14 deletions(-) + +diff --git a/src/nfct-extensions/timeout.c b/src/nfct-extensions/timeout.c +index 30f94642bd3bd..31e91a63de722 100644 +--- a/src/nfct-extensions/timeout.c ++++ b/src/nfct-extensions/timeout.c +@@ -54,20 +54,6 @@ nfct_timeout_parse_params(struct mnl_socket *nl, int argc, char *argv[], int cmd + return -1; + } + +- switch (cmd) { +- case NFCT_CMD_LIST: +- case NFCT_CMD_ADD: +- case NFCT_CMD_DELETE: +- case NFCT_CMD_GET: +- case NFCT_CMD_FLUSH: +- case NFCT_CMD_DEFAULT_SET: +- case NFCT_CMD_DEFAULT_GET: +- break; +- default: +- nfct_cmd_timeout_usage(argv); +- return -1; +- } +- + switch (cmd) { + case NFCT_CMD_LIST: + ret = nfct_cmd_timeout_list(nl, argc, argv); +-- +2.21.0 + diff --git a/SOURCES/0004-src-Fix-for-implicit-fallthrough-warnings.patch b/SOURCES/0004-src-Fix-for-implicit-fallthrough-warnings.patch new file mode 100644 index 0000000..1a25c02 --- /dev/null +++ b/SOURCES/0004-src-Fix-for-implicit-fallthrough-warnings.patch @@ -0,0 +1,78 @@ +From a194ecd1258b58a5fd42970bdb8f1bf4eead3b13 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 13 Feb 2019 00:13:44 +0100 +Subject: [PATCH] src: Fix for implicit-fallthrough warnings + +Mark fall through cases as such. Note that correctness of those fall +throughs have not been verified. + +Signed-off-by: Phil Sutter +Signed-off-by: Pablo Neira Ayuso +(cherry picked from commit e63c283c4e6a71df358bd12e4ba2fe49c1619d82) +--- + include/jhash.h | 2 +- + src/cache-ct.c | 2 ++ + src/cache-exp.c | 1 + + src/tcp.c | 1 + + 4 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/include/jhash.h b/include/jhash.h +index d164e38bde7f6..9793452ebc23d 100644 +--- a/include/jhash.h ++++ b/include/jhash.h +@@ -106,7 +106,7 @@ static inline u32 jhash2(const u32 *k, u32 length, u32 initval) + c += length * 4; + + switch (len) { +- case 2 : b += k[1]; ++ case 2 : b += k[1]; /* fall through */ + case 1 : a += k[0]; + }; + +diff --git a/src/cache-ct.c b/src/cache-ct.c +index f86d143c8137d..abcfde4c8a260 100644 +--- a/src/cache-ct.c ++++ b/src/cache-ct.c +@@ -266,6 +266,7 @@ static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) + STATE_SYNC(commit).stats.ok = c->stats.commit_ok; + STATE_SYNC(commit).stats.fail = c->stats.commit_fail; + STATE_SYNC(commit).clientfd = clientfd; ++ /* fall through */ + case COMMIT_STATE_MASTER: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, +@@ -280,6 +281,7 @@ static int cache_ct_commit(struct cache *c, struct nfct_handle *h, int clientfd) + } + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_RELATED; ++ /* fall through */ + case COMMIT_STATE_RELATED: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, +diff --git a/src/cache-exp.c b/src/cache-exp.c +index 9183b2c42d93f..63e344078a7c6 100644 +--- a/src/cache-exp.c ++++ b/src/cache-exp.c +@@ -236,6 +236,7 @@ cache_exp_commit(struct cache *c, struct nfct_handle *h, int clientfd) + STATE_SYNC(commit).stats.ok = c->stats.commit_ok; + STATE_SYNC(commit).stats.fail = c->stats.commit_fail; + STATE_SYNC(commit).clientfd = clientfd; ++ /* fall through */ + case COMMIT_STATE_MASTER: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, +diff --git a/src/tcp.c b/src/tcp.c +index c8f254483aa35..91fe524542013 100644 +--- a/src/tcp.c ++++ b/src/tcp.c +@@ -300,6 +300,7 @@ ssize_t tcp_send(struct tcp_sock *m, const void *data, int size) + /* we got connected :) */ + m->state = TCP_CLIENT_CONNECTED; + } ++ /* fall through */ + case TCP_CLIENT_CONNECTED: + ret = sendto(m->fd, data, size, 0, + (struct sockaddr *) &m->addr, m->sockaddr_len); +-- +2.21.0 + diff --git a/SOURCES/conntrack-tools-1.4.4-conntrack.patch b/SOURCES/conntrack-tools-1.4.4-conntrack.patch deleted file mode 100644 index 5148073..0000000 --- a/SOURCES/conntrack-tools-1.4.4-conntrack.patch +++ /dev/null @@ -1,438 +0,0 @@ -diff --git a/src/conntrack.c b/src/conntrack.c -index bd337f4..6e96b58 100644 ---- a/src/conntrack.c -+++ b/src/conntrack.c -@@ -43,6 +43,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -437,6 +439,9 @@ static const int opt2type[] = { - static const int opt2maskopt[] = { - ['s'] = '{', - ['d'] = '}', -+ ['g'] = 0, -+ ['j'] = 0, -+ ['n'] = 0, - ['r'] = 0, /* no netmask */ - ['q'] = 0, /* support yet */ - ['{'] = 0, -@@ -448,6 +453,8 @@ static const int opt2maskopt[] = { - static const int opt2family_attr[][2] = { - ['s'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, - ['d'] = { ATTR_ORIG_IPV4_DST, ATTR_ORIG_IPV6_DST }, -+ ['g'] = { ATTR_DNAT_IPV4, ATTR_DNAT_IPV6 }, -+ ['n'] = { ATTR_SNAT_IPV4, ATTR_SNAT_IPV6 }, - ['r'] = { ATTR_REPL_IPV4_SRC, ATTR_REPL_IPV6_SRC }, - ['q'] = { ATTR_REPL_IPV4_DST, ATTR_REPL_IPV6_DST }, - ['{'] = { ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV6_SRC }, -@@ -459,6 +466,8 @@ static const int opt2family_attr[][2] = { - static const int opt2attr[] = { - ['s'] = ATTR_ORIG_L3PROTO, - ['d'] = ATTR_ORIG_L3PROTO, -+ ['g'] = ATTR_ORIG_L3PROTO, -+ ['n'] = ATTR_ORIG_L3PROTO, - ['r'] = ATTR_REPL_L3PROTO, - ['q'] = ATTR_REPL_L3PROTO, - ['{'] = ATTR_ORIG_L3PROTO, -@@ -1094,58 +1103,85 @@ parse_addr(const char *cp, union ct_address *address, int *mask) - return family; - } - --static void --nat_parse(char *arg, struct nf_conntrack *obj, int type) -+static bool -+valid_port(char *cursor) - { -- char *colon, *error; -- union ct_address parse; -+ const char *str = cursor; -+ /* Missing port number */ -+ if (!*str) -+ return false; - -- colon = strchr(arg, ':'); -+ /* Must be entirely digits - no spaces or +/- */ -+ while (*cursor) { -+ if (!isdigit(*cursor)) -+ return false; -+ else -+ ++cursor; -+ } - -- if (colon) { -- uint16_t port; -+ /* Must be in range */ -+ errno = 0; -+ long port = strtol(str, NULL, 10); - -- *colon = '\0'; -+ if ((errno == ERANGE && (port == LONG_MAX || port == LONG_MIN)) -+ || (errno != 0 && port == 0) || (port > USHRT_MAX)) -+ return false; - -- port = (uint16_t)atoi(colon+1); -- if (port == 0) { -- if (strlen(colon+1) == 0) { -- exit_error(PARAMETER_PROBLEM, -- "No port specified after `:'"); -- } else { -- exit_error(PARAMETER_PROBLEM, -- "Port `%s' not valid", colon+1); -- } -- } -+ return true; -+} -+ -+static void -+split_address_and_port(const char *arg, char **address, char **port_str) -+{ -+ char *cursor = strchr(arg, '['); -+ -+ if (cursor) { -+ /* IPv6 address with port*/ -+ char *start = cursor + 1; - -- error = strchr(colon+1, ':'); -- if (error) -+ cursor = strchr(start, ']'); -+ if (start == cursor) { -+ exit_error(PARAMETER_PROBLEM, -+ "No IPv6 address specified"); -+ } else if (!cursor) { - exit_error(PARAMETER_PROBLEM, -- "Invalid port:port syntax"); -- -- if (type == CT_OPT_SRC_NAT) -- nfct_set_attr_u16(tmpl.ct, ATTR_SNAT_PORT, ntohs(port)); -- else if (type == CT_OPT_DST_NAT) -- nfct_set_attr_u16(tmpl.ct, ATTR_DNAT_PORT, ntohs(port)); -- else if (type == CT_OPT_ANY_NAT) { -- nfct_set_attr_u16(tmpl.ct, ATTR_SNAT_PORT, ntohs(port)); -- nfct_set_attr_u16(tmpl.ct, ATTR_DNAT_PORT, ntohs(port)); -+ "No closing ']' around IPv6 address"); - } -- } -+ size_t len = cursor - start; - -- if (parse_addr(arg, &parse, NULL) == AF_UNSPEC) { -- if (strlen(arg) == 0) { -- exit_error(PARAMETER_PROBLEM, "No IP specified"); -+ cursor = strchr(cursor, ':'); -+ if (cursor) { -+ /* Copy address only if there is a port */ -+ *address = strndup(start, len); -+ } -+ } else { -+ cursor = strchr(arg, ':'); -+ if (cursor && !strchr(cursor + 1, ':')) { -+ /* IPv4 address with port */ -+ *address = strndup(arg, cursor - arg); - } else { -+ /* v6 address */ -+ cursor = NULL; -+ } -+ } -+ if (cursor) { -+ /* Parse port entry */ -+ cursor++; -+ if (strlen(cursor) == 0) { - exit_error(PARAMETER_PROBLEM, -- "Invalid IP address `%s'", arg); -+ "No port specified after `:'"); - } -+ if (!valid_port(cursor)) { -+ exit_error(PARAMETER_PROBLEM, -+ "Invalid port `%s'", cursor); -+ } -+ *port_str = strdup(cursor); -+ } else { -+ /* No port colon or more than one colon (ipv6) -+ * assume arg is straight IP address and no port -+ */ -+ *address = strdup(arg); - } -- -- if (type == CT_OPT_SRC_NAT || type == CT_OPT_ANY_NAT) -- nfct_set_attr_u32(tmpl.ct, ATTR_SNAT_IPV4, parse.v4); -- else if (type == CT_OPT_DST_NAT || type == CT_OPT_ANY_NAT) -- nfct_set_attr_u32(tmpl.ct, ATTR_DNAT_IPV4, parse.v4); - } - - static void -@@ -1289,7 +1325,7 @@ nfct_ip6_net_cmp(const union ct_address *addr, const struct ct_network *net) - - static int - nfct_ip_net_cmp(int family, const union ct_address *addr, -- const struct ct_network *net) -+ const struct ct_network *net) - { - switch(family) { - case AF_INET: -@@ -2128,6 +2164,7 @@ static void merge_bitmasks(struct nfct_bitmask **current, - nfct_bitmask_destroy(src); - } - -+ - static void - nfct_build_netmask(uint32_t *dst, int b, int n) - { -@@ -2147,10 +2184,9 @@ nfct_build_netmask(uint32_t *dst, int b, int n) - } - - static void --nfct_set_addr_opt(int opt, struct nf_conntrack *ct, union ct_address *ad, -- int l3protonum) -+nfct_set_addr_only(const int opt, struct nf_conntrack *ct, union ct_address *ad, -+ const int l3protonum) - { -- options |= opt2type[opt]; - switch (l3protonum) { - case AF_INET: - nfct_set_attr_u32(ct, -@@ -2163,24 +2199,33 @@ nfct_set_addr_opt(int opt, struct nf_conntrack *ct, union ct_address *ad, - &ad->v6); - break; - } -+} -+ -+static void -+nfct_set_addr_opt(const int opt, struct nf_conntrack *ct, union ct_address *ad, -+ const int l3protonum) -+{ -+ options |= opt2type[opt]; -+ nfct_set_addr_only(opt, ct, ad, l3protonum); - nfct_set_attr_u8(ct, opt2attr[opt], l3protonum); - } - - static void --nfct_parse_addr_from_opt(int opt, struct nf_conntrack *ct, -- struct nf_conntrack *ctmask, -- union ct_address *ad, int *family) -+nfct_parse_addr_from_opt(const int opt, const char *arg, -+ struct nf_conntrack *ct, -+ struct nf_conntrack *ctmask, -+ union ct_address *ad, int *family) - { -- int l3protonum, mask, maskopt; -+ int mask, maskopt; - -- l3protonum = parse_addr(optarg, ad, &mask); -+ const int l3protonum = parse_addr(arg, ad, &mask); - if (l3protonum == AF_UNSPEC) { - exit_error(PARAMETER_PROBLEM, -- "Invalid IP address `%s'", optarg); -+ "Invalid IP address `%s'", arg); - } - set_family(family, l3protonum); - maskopt = opt2maskopt[opt]; -- if (!maskopt && mask != -1) { -+ if (mask != -1 && !maskopt) { - exit_error(PARAMETER_PROBLEM, - "CIDR notation unavailable" - " for `--%s'", get_long_opt(opt)); -@@ -2192,7 +2237,7 @@ nfct_parse_addr_from_opt(int opt, struct nf_conntrack *ct, - nfct_set_addr_opt(opt, ct, ad, l3protonum); - - /* bail if we don't have a netmask to set*/ -- if (!maskopt || mask == -1 || ctmask == NULL) -+ if (mask == -1 || !maskopt || ctmask == NULL) - return; - - switch(l3protonum) { -@@ -2211,6 +2256,24 @@ nfct_parse_addr_from_opt(int opt, struct nf_conntrack *ct, - nfct_set_addr_opt(maskopt, ctmask, ad, l3protonum); - } - -+static void -+nfct_set_nat_details(const int opt, struct nf_conntrack *ct, -+ union ct_address *ad, const char *port_str, -+ const int family) -+{ -+ const int type = opt2type[opt]; -+ -+ nfct_set_addr_only(opt, ct, ad, family); -+ if (port_str && type == CT_OPT_SRC_NAT) { -+ nfct_set_attr_u16(ct, ATTR_SNAT_PORT, -+ ntohs((uint16_t)atoi(port_str))); -+ } else if (port_str && type == CT_OPT_DST_NAT) { -+ nfct_set_attr_u16(ct, ATTR_DNAT_PORT, -+ ntohs((uint16_t)atoi(port_str))); -+ } -+ -+} -+ - int main(int argc, char *argv[]) - { - int c, cmd; -@@ -2289,17 +2352,18 @@ int main(int argc, char *argv[]) - case 'd': - case 'r': - case 'q': -- nfct_parse_addr_from_opt(c, tmpl.ct, tmpl.mask, -- &ad, &family); -+ nfct_parse_addr_from_opt(c, optarg, tmpl.ct, -+ tmpl.mask, &ad, &family); - break; - case '[': - case ']': -- nfct_parse_addr_from_opt(c, tmpl.exptuple, tmpl.mask, -- &ad, &family); -+ nfct_parse_addr_from_opt(c, optarg, tmpl.exptuple, -+ tmpl.mask, &ad, &family); - break; - case '{': - case '}': -- nfct_parse_addr_from_opt(c, tmpl.mask, NULL, &ad, &family); -+ nfct_parse_addr_from_opt(c, optarg, tmpl.mask, -+ NULL, &ad, &family); - break; - case 'p': - options |= CT_OPT_PROTO; -@@ -2341,19 +2405,34 @@ int main(int argc, char *argv[]) - break; - case 'n': - case 'g': -- case 'j': { -- char *tmp = NULL; -- -+ case 'j': - options |= opt2type[c]; -- -- tmp = get_optional_arg(argc, argv); -- if (tmp == NULL) -- continue; -- -- set_family(&family, AF_INET); -- nat_parse(tmp, tmpl.ct, opt2type[c]); -+ char *optional_arg = get_optional_arg(argc, argv); -+ -+ if (optional_arg) { -+ char *port_str = NULL; -+ char *nat_address = NULL; -+ -+ split_address_and_port(optional_arg, -+ &nat_address, -+ &port_str); -+ nfct_parse_addr_from_opt(c, nat_address, -+ tmpl.ct, NULL, -+ &ad, &family); -+ if (c == 'j') { -+ /* Set details on both src and dst -+ * with any-nat -+ */ -+ nfct_set_nat_details('g', tmpl.ct, &ad, -+ port_str, family); -+ nfct_set_nat_details('n', tmpl.ct, &ad, -+ port_str, family); -+ } else { -+ nfct_set_nat_details(c, tmpl.ct, &ad, -+ port_str, family); -+ } -+ } - break; -- } - case 'w': - case '(': - case ')': -diff --git a/tests/conntrack/testsuite/00create b/tests/conntrack/testsuite/00create -index 40e2c19..afe4342 100644 ---- a/tests/conntrack/testsuite/00create -+++ b/tests/conntrack/testsuite/00create -@@ -18,3 +18,9 @@ - -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 -+# create a v6 conntrack -+-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK -+# delete v6 conntrack -+-D -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 -p tcp --sport 10 --dport 20 ; OK -+# mismatched address family -+-I -s 2001:DB8::1.1.1.1 -d 2.2.2.2 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD -diff --git a/tests/conntrack/testsuite/03nat b/tests/conntrack/testsuite/03nat -index f94e8ff..014feb8 100644 ---- a/tests/conntrack/testsuite/03nat -+++ b/tests/conntrack/testsuite/03nat -@@ -36,5 +36,13 @@ - -L --dst-nat 3.3.3.3:81 ; OK - # show - -L --dst-nat 1.1.1.1:80 ; OK -+# badport -+-L --dst-nat 1.1.1.1: ; BAD -+# badport -+-L --dst-nat 1.1.1.1::; BAD -+# badport -+-L --dst-nat 1.1.1.1:80:80; BAD -+# badport -+-L --dst-nat 1.1.1.1:65536; BAD - # delete - -D -s 1.1.1.1 ; OK -diff --git a/tests/conntrack/testsuite/07nat6 b/tests/conntrack/testsuite/07nat6 -new file mode 100644 -index 0000000..8cecd8e ---- /dev/null -+++ b/tests/conntrack/testsuite/07nat6 -@@ -0,0 +1,56 @@ -+# create dummy -+-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --dst-nat 2001:DB8::3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK -+# show -+-L --dst-nat ; OK -+# show -+-L --dst-nat 2001:DB8::3.3.3.3 ; OK -+# show -+-L --src-nat ; OK -+# delete -+-D -s 2001:DB8::1.1.1.1 ; OK -+# create dummy again -+-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --src-nat 2001:DB8::3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK -+# show -+-L --src-nat ; OK -+# show -+-L --src-nat 2001:DB8::3.3.3.3 ; OK -+# show -+-L --dst-nat ; OK -+# show any-nat -+-L --any-nat ; OK -+# delete -+-D -s 2001:DB8::1.1.1.1 ; OK -+# bad combination -+-L --dst-nat --any-nat ; BAD -+# bad combination -+-L --src-nat --any-nat ; BAD -+# bad combination -+-L --src-nat --dst-nat --any-nat ; BAD -+# create -+-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --dst-nat [2001:DB8::3.3.3.3]:80 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; OK -+# show -+-L --dst-nat [2001:DB8::3.3.3.3]:80 ; OK -+# show -+-L --any-nat [2001:DB8::3.3.3.3]:80 ; OK -+# show -+-L --dst-nat [2001:DB8::3.3.3.3]:81 ; OK -+# show -+-L --dst-nat [2001:DB8::1.1.1.1]:80 ; OK -+# noport -+-L --dst-nat [2001:DB8::1.1.1.1]: ; BAD -+# badport -+-L --dst-nat [2001:DB8::1.1.1.1]:: ; BAD -+# badport -+-L --dst-nat [2001:DB8::1.1.1.1]:80:80 ; BAD -+# badport -+-L --dst-nat [2001:DB8::1.1.1.1]:65536 ; BAD -+# delete -+-D -s 2001:DB8::1.1.1.1 ; OK -+# mismatched address family -+-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --dst-nat 3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD -+# mismatched address family -+-I -s 1.1.1.1 -d 2.2.2.2 --dst-nat 2001:DB8::3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD -+# create - brackets only for ports in nat -+-I -s 2001:DB8::1.1.1.1 -d 2001:DB8::2.2.2.2 --dst-nat [2001:DB8::3.3.3.3] -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD -+# create - brackets rejected elsewhere -+-I -s [2001:DB8::1.1.1.1] -d 2001:DB8::2.2.2.2 --dst-nat 2001:DB8::3.3.3.3 -p tcp --sport 10 --dport 20 --state LISTEN -u SEEN_REPLY -t 50 ; BAD --- -2.7.4 - diff --git a/SPECS/conntrack-tools.spec b/SPECS/conntrack-tools.spec index 60471ed..619ce4e 100644 --- a/SPECS/conntrack-tools.spec +++ b/SPECS/conntrack-tools.spec @@ -1,6 +1,6 @@ Name: conntrack-tools Version: 1.4.4 -Release: 4%{?dist} +Release: 5%{?dist} Summary: Manipulate netfilter connection tracking table and run High Availability Group: System Environment/Base License: GPLv2 @@ -20,7 +20,10 @@ Requires(preun): systemd Requires(postun): systemd BuildRequires: systemd -Patch1: conntrack-tools-1.4.4-conntrack.patch +Patch1: 0001-conntrack-Support-IPv6-NAT.patch +Patch2: 0002-conntrackd-helpers-dhcpv6-Fix-potential-array-overru.patch +Patch3: 0003-nfct-Drop-dead-code-in-nfct_timeout_parse_params.patch +Patch4: 0004-src-Fix-for-implicit-fallthrough-warnings.patch %description With conntrack-tools you can setup a High Availability cluster and @@ -42,8 +45,7 @@ In addition, you can also monitor connection tracking events, e.g. show an event message (one line) per newly established connection. %prep -%setup -q -%patch1 -p1 +%autosetup -p1 %build # do not use --enable-cthelper --enable-cttimeout, it causes disabling of these features @@ -83,6 +85,12 @@ install -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/conntrackd/ %systemd_postun conntrackd.service %changelog +* Wed Mar 27 2019 Phil Sutter - 1.4.4-5 +- Add git commit info to IPv6 NAT support patch +- Backport: conntrackd: helpers: dhcpv6: Fix potential array overrun +- Backport: nfct: Drop dead code in nfct_timeout_parse_params() +- Backport: src: Fix for implicit-fallthrough warnings + * Fri Aug 24 2018 Paul Wouters - 1.4.4-4 - Resolves: rhbz#1578059 Greatest NVR version of conntrack-tools for ppc64le and x86_64 are different