diff --git a/0004-Support-GRE-key-in-selectors.patch b/0004-Support-GRE-key-in-selectors.patch new file mode 100644 index 0000000..1f47942 --- /dev/null +++ b/0004-Support-GRE-key-in-selectors.patch @@ -0,0 +1,292 @@ +From 0ceda5a95355bb803cbcdf3eeabbcb6ec2577922 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zoran=20Peri=C4=8Di=C4=87?= +Date: Sun, 21 Jan 2024 03:11:32 +0100 +Subject: [PATCH 4/4] Support GRE key in selectors. + +--- + .../kernel_netlink/kernel_netlink_ipsec.c | 20 ++++++++++++ + .../plugins/load_tester/load_tester_config.c | 22 ++++++++++++- + src/libcharon/plugins/stroke/stroke_config.c | 22 ++++++++++++- + src/libcharon/plugins/vici/vici_config.c | 32 ++++++++++++++++++- + .../selectors/traffic_selector.c | 20 ++++++++++++ + .../selectors/traffic_selector.h | 12 +++++++ + src/starter/confread.c | 24 +++++++++++++- + src/swanctl/swanctl.opt | 3 ++ + 8 files changed, 151 insertions(+), 4 deletions(-) + +diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +index db0b2ac37..e4e7d9ecb 100644 +--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c ++++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +@@ -864,6 +864,7 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src, + { + struct xfrm_selector sel; + uint16_t port; ++ uint32_t gre_key; + + memset(&sel, 0, sizeof(sel)); + sel.family = (src->get_type(src) == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6; +@@ -884,6 +885,25 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src, + sel.dport = htons(traffic_selector_icmp_code(port)); + sel.dport_mask = sel.dport ? ~0 : 0; + } ++ if (sel.proto == IPPROTO_GRE) ++ { ++ /* the kernel expects the GRE key in the source and destination ++ * port fields, respectively. */ ++ gre_key = htons(traffic_selector_gre_key(dst->get_from_port(dst), dst->get_to_port(dst))); ++ if ( gre_key != 0 ) ++ { ++ DBG2(DBG_KNL, "Policy GRE key: %d (%d-%d) %d", gre_key, dst->get_from_port(dst), dst->get_to_port(dst), traffic_selector_gre_key(dst->get_from_port(dst), dst->get_to_port(dst))); ++ sel.sport = gre_key >> 16; ++ sel.sport_mask = ~0; ++ sel.dport = gre_key & 0xffff; ++ sel.dport_mask = ~0; ++ } else { ++ sel.sport = 0; ++ sel.sport_mask = 0; ++ sel.dport = 0; ++ sel.dport_mask = 0; ++ } ++ } + sel.ifindex = interface ? if_nametoindex(interface) : 0; + sel.user = 0; + +diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c +index 58e1cd98a..ac67875d8 100644 +--- a/src/libcharon/plugins/load_tester/load_tester_config.c ++++ b/src/libcharon/plugins/load_tester/load_tester_config.c +@@ -498,7 +498,27 @@ static bool parse_protoport(char *token, uint16_t *from_port, + *protocol = (uint8_t)p; + } + } +- if (streq(port, "%any")) ++ if (*protocol == IPPROTO_GRE) ++ { ++ if (*port && !streq(port, "%any")) ++ { ++ p = strtol(port, &endptr, 0); ++ if (p < 0 || p > 0xffffffff) ++ { ++ return FALSE; ++ } ++ end->from_port = (p >> 16) & 0xffff; ++ end->to_port = p & 0xffff; ++ if (*endptr) ++ { ++ return FALSE; ++ } ++ } else { ++ end->from_port = 0; ++ end->to_port = 0; ++ } ++ } ++ else if (streq(port, "%any")) + { + *from_port = 0; + *to_port = 0xffff; +diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c +index 55db379ff..b4340b8d1 100644 +--- a/src/libcharon/plugins/stroke/stroke_config.c ++++ b/src/libcharon/plugins/stroke/stroke_config.c +@@ -927,7 +927,27 @@ static bool parse_protoport(char *token, uint16_t *from_port, + *protocol = (uint8_t)p; + } + } +- if (streq(port, "%any")) ++ if (*protocol == IPPROTO_GRE) ++ { ++ if (*port && !streq(port, "%any")) ++ { ++ p = strtol(port, &endptr, 0); ++ if (p < 0 || p > 0xffffffff) ++ { ++ return FALSE; ++ } ++ *from_port = (p >> 16) & 0xffff; ++ *to_port = p & 0xffff; ++ if (*endptr) ++ return FALSE; ++ } ++ else ++ { ++ *from_port = 0; ++ *to_port = 0; ++ } ++ } ++ else if (streq(port, "%any")) + { + *from_port = 0; + *to_port = 0xffff; +diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c +index c858e9945..c72c97f76 100644 +--- a/src/libcharon/plugins/vici/vici_config.c ++++ b/src/libcharon/plugins/vici/vici_config.c +@@ -715,7 +715,31 @@ CALLBACK(parse_ts, bool, + proto = (uint8_t)p; + } + } +- if (streq(port, "opaque")) ++ if (proto == IPPROTO_GRE) ++ { ++ if (*port && !streq(port, "any")) ++ { ++ DBG2(DBG_CFG, " GRE key %s", port); ++ p = strtol(port, &end, 0); ++ if (p < 0 || p > 0xffffffff) ++ { ++ DBG2(DBG_CFG, " Invalid GRE key %s", port); ++ return FALSE; ++ } ++ from = (p >> 16) & 0xffff; ++ to = p & 0xffff; ++ DBG2(DBG_CFG, " Parsed GRE key %d-%d(%d)", from, to, p); ++ if (*end) ++ { ++ DBG2(DBG_CFG, " Invalid GRE key %s", port); ++ return FALSE; ++ } ++ } else { ++ from = 0; ++ to = 0; ++ } ++ } ++ else if (streq(port, "opaque")) + { + from = 0xffff; + to = 0; +@@ -752,8 +776,14 @@ CALLBACK(parse_ts, bool, + } + } + } ++ else if (proto == IPPROTO_GRE) ++ { ++ from = 0; ++ to = 0; ++ } + if (streq(buf, "dynamic")) + { ++ DBG2(DBG_CFG, " Create dynamic selector GRE key proto=%d, from_port=%d, to_port=%d", proto, from, to); + ts = traffic_selector_create_dynamic(proto, from, to); + } + else if (strchr(buf, '-')) +diff --git a/src/libstrongswan/selectors/traffic_selector.c b/src/libstrongswan/selectors/traffic_selector.c +index fe61e3768..09757ec36 100644 +--- a/src/libstrongswan/selectors/traffic_selector.c ++++ b/src/libstrongswan/selectors/traffic_selector.c +@@ -205,6 +205,18 @@ static int print_icmp(printf_hook_data_t *data, uint16_t port) + return print_in_hook(data, "%d", type); + } + ++/** ++ * Print GRE key ++ */ ++static int print_gre(printf_hook_data_t *data, uint16_t from_port, uint16_t to_port) ++{ ++ uint32_t gre_key; ++ ++ gre_key = traffic_selector_gre_key(from_port, to_port); ++ ++ return print_in_hook(data, "%d", gre_key); ++} ++ + /** + * Described in header. + */ +@@ -319,6 +331,10 @@ int traffic_selector_printf_hook(printf_hook_data_t *data, + { + written += print_icmp(data, this->from_port); + } ++ else if (this->protocol == IPPROTO_GRE) ++ { ++ written += print_gre(data, this->from_port, this->to_port); ++ } + else + { + serv = getservbyport(htons(this->from_port), serv_proto); +@@ -332,6 +348,10 @@ int traffic_selector_printf_hook(printf_hook_data_t *data, + } + } + } ++ else if (this->protocol == IPPROTO_GRE) ++ { ++ written += print_gre(data, this->from_port, this->to_port); ++ } + else if (is_opaque(this)) + { + written += print_in_hook(data, "OPAQUE"); +diff --git a/src/libstrongswan/selectors/traffic_selector.h b/src/libstrongswan/selectors/traffic_selector.h +index 367b4fff9..b7010e4a7 100644 +--- a/src/libstrongswan/selectors/traffic_selector.h ++++ b/src/libstrongswan/selectors/traffic_selector.h +@@ -272,6 +272,18 @@ static inline uint8_t traffic_selector_icmp_code(uint16_t port) + return port & 0xff; + } + ++/** ++ * Extract the GRE key from a source and destination port in host order ++ * ++ * @param from_port port number in host order ++ * @param to_port port number in host order ++ * @return GRE key ++ */ ++static inline uint8_t traffic_selector_gre_key(uint16_t from_port, uint16_t to_port) ++{ ++ return (from_port & 0xffff) << 16 | (to_port & 0xffff); ++} ++ + /** + * Compare two traffic selectors, usable as sort function + * +diff --git a/src/starter/confread.c b/src/starter/confread.c +index 5065bc369..039b6f402 100644 +--- a/src/starter/confread.c ++++ b/src/starter/confread.c +@@ -325,7 +325,29 @@ static void kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token, + end->protocol = (uint8_t)p; + } + } +- if (streq(port, "%any")) ++ if (end->protocol == IPPROTO_GRE) ++ { ++ if (*port && !streq(port, "%any")) ++ { ++ p = strtol(port, &endptr, 0); ++ if (p < 0 || p > 0xffffffff) ++ { ++ DBG1(DBG_APP, "# bad GRE key: %s=%s", key, port); ++ goto err; ++ } ++ end->from_port = (p >> 16) & 0xffff; ++ end->to_port = p & 0xffff; ++ if (*endptr) ++ { ++ DBG1(DBG_APP, "# bad GRE key: %s=%s", key, port); ++ goto err; ++ } ++ } else { ++ end->from_port = 0; ++ end->to_port = 0; ++ } ++ } ++ else if (streq(port, "%any")) + { + end->from_port = 0; + end->to_port = 0xffff; +diff --git a/src/swanctl/swanctl.opt b/src/swanctl/swanctl.opt +index d9fd949ed..1d63dadb8 100644 +--- a/src/swanctl/swanctl.opt ++++ b/src/swanctl/swanctl.opt +@@ -765,6 +765,9 @@ connections..children..local_ts = dynamic + value _opaque_ for RFC 4301 OPAQUE selectors. Port ranges may be specified + as well, none of the kernel backends currently support port ranges, though. + ++ If protocol is restricted to GRE, port restriction specifies GRE key ++ in 32 bit numeric form eg. dynamic[gre/100]. ++ + When IKEv1 is used only the first selector is interpreted, except if + the Cisco Unity extension plugin is used. This is due to a limitation of the + IKEv1 protocol, which only allows a single pair of selectors per CHILD_SA. +-- +2.45.2 + diff --git a/strongswan.spec b/strongswan.spec index e34e2fd..f81c93f 100644 --- a/strongswan.spec +++ b/strongswan.spec @@ -1,6 +1,6 @@ %global _hardened_build 1 #%%define prerelease dr1 -%global dist .nhrp.9%{?dist} +%global dist .nhrp.11%{?dist} # pytho vici bindings cannot build without network, so temp. disabled %bcond_with python3 @@ -33,6 +33,7 @@ Patch3: strongswan-6.0.2-no-md5-b3011e8e.patch Patch10: 0001-charon-add-optional-source-and-remote-overrides-for-.patch Patch11: 0002-vici-send-certificates-for-ike-sa-events.patch Patch12: 0003-vici-add-support-for-individual-sa-state-changes.patch +Patch13: 0004-Support-GRE-key-in-selectors.patch BuildRequires: autoconf BuildRequires: automake