aboutsummaryrefslogtreecommitdiffstats
path: root/main/strongswan/1000-support-gre-key-in-ikev1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/strongswan/1000-support-gre-key-in-ikev1.patch')
-rw-r--r--main/strongswan/1000-support-gre-key-in-ikev1.patch507
1 files changed, 507 insertions, 0 deletions
diff --git a/main/strongswan/1000-support-gre-key-in-ikev1.patch b/main/strongswan/1000-support-gre-key-in-ikev1.patch
new file mode 100644
index 000000000..72cdd8b82
--- /dev/null
+++ b/main/strongswan/1000-support-gre-key-in-ikev1.patch
@@ -0,0 +1,507 @@
+From f69e2daf4c4ccc57c14fd73d6b7320c5359758c8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
+Date: Mon, 13 Jul 2015 14:03:49 +0300
+Subject: [PATCH] support gre key in ikev1
+
+this implements gre key negotiation in ikev1 similarly to the
+ipsec-tools patch in alpine.
+
+the from/to port pair is internally used as gre key for gre
+protocol traffic selectors. since from/to pairs 0/0xffff and
+0xffff/0 have special meaning, the gre keys 0xffff and 0xffff0000
+will not work.
+
+this is not standard compliant, and should probably not be upstreamed
+or used widely, but it is applied for interoperability with alpine
+racoon for the time being.
+---
+ src/libcharon/encoding/payloads/id_payload.c | 68 +++++++++++++++++-----
+ src/libcharon/encoding/payloads/id_payload.h | 6 +-
+ src/libcharon/plugins/stroke/stroke_config.c | 5 ++
+ src/libcharon/plugins/unity/unity_narrow.c | 2 +-
+ src/libcharon/plugins/vici/vici_config.c | 9 ++-
+ src/libcharon/sa/ikev1/tasks/quick_mode.c | 16 ++---
+ .../plugins/kernel_netlink/kernel_netlink_ipsec.c | 40 ++++++++++---
+ src/libstrongswan/selectors/traffic_selector.c | 33 ++++++++++-
+ src/libstrongswan/selectors/traffic_selector.h | 31 ++++++++++
+ 9 files changed, 171 insertions(+), 39 deletions(-)
+
+diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c
+index bb8aab7..2cf08e9 100644
+--- a/src/libcharon/encoding/payloads/id_payload.c
++++ b/src/libcharon/encoding/payloads/id_payload.c
+@@ -245,18 +245,20 @@ METHOD(id_payload_t, get_identification, identification_t*,
+ * Create a traffic selector from an range ID
+ */
+ static traffic_selector_t *get_ts_from_range(private_id_payload_t *this,
+- ts_type_t type)
++ ts_type_t type,
++ u_int16_t from_port, u_int16_t to_port)
+ {
+ return traffic_selector_create_from_bytes(this->protocol_id, type,
+- chunk_create(this->id_data.ptr, this->id_data.len / 2), this->port,
+- chunk_skip(this->id_data, this->id_data.len / 2), this->port ?: 65535);
++ chunk_create(this->id_data.ptr, this->id_data.len / 2), from_port,
++ chunk_skip(this->id_data, this->id_data.len / 2), to_port);
+ }
+
+ /**
+ * Create a traffic selector from an subnet ID
+ */
+ static traffic_selector_t *get_ts_from_subnet(private_id_payload_t *this,
+- ts_type_t type)
++ ts_type_t type,
++ u_int16_t from_port, u_int16_t to_port)
+ {
+ traffic_selector_t *ts;
+ chunk_t net, netmask;
+@@ -269,7 +271,7 @@ static traffic_selector_t *get_ts_from_subnet(private_id_payload_t *this,
+ netmask.ptr[i] = (netmask.ptr[i] ^ 0xFF) | net.ptr[i];
+ }
+ ts = traffic_selector_create_from_bytes(this->protocol_id, type,
+- net, this->port, netmask, this->port ?: 65535);
++ net, from_port, netmask, to_port);
+ chunk_free(&netmask);
+ return ts;
+ }
+@@ -278,51 +280,76 @@ static traffic_selector_t *get_ts_from_subnet(private_id_payload_t *this,
+ * Create a traffic selector from an IP ID
+ */
+ static traffic_selector_t *get_ts_from_ip(private_id_payload_t *this,
+- ts_type_t type)
++ ts_type_t type,
++ u_int16_t from_port, u_int16_t to_port)
+ {
+ return traffic_selector_create_from_bytes(this->protocol_id, type,
+- this->id_data, this->port, this->id_data, this->port ?: 65535);
++ this->id_data, from_port, this->id_data, to_port);
+ }
+
+ METHOD(id_payload_t, get_ts, traffic_selector_t*,
+- private_id_payload_t *this)
++ private_id_payload_t *this, id_payload_t *other_, bool initiator)
+ {
++ private_id_payload_t *other = (private_id_payload_t *) other_;
++ u_int16_t from_port, to_port;
++
++ if (other && this->protocol_id == IPPROTO_GRE && other->protocol_id == IPPROTO_GRE)
++ {
++ if (initiator)
++ {
++ from_port = this->port;
++ to_port = other->port;
++ }
++ else
++ {
++ from_port = other->port;
++ to_port = this->port;
++ }
++ if (from_port == 0 && to_port == 0)
++ to_port = 0xffff;
++ }
++ else
++ {
++ from_port = this->port;
++ to_port = this->port ?: 0xffff;
++ }
++
+ switch (this->id_type)
+ {
+ case ID_IPV4_ADDR_SUBNET:
+ if (this->id_data.len == 8)
+ {
+- return get_ts_from_subnet(this, TS_IPV4_ADDR_RANGE);
++ return get_ts_from_subnet(this, TS_IPV4_ADDR_RANGE, from_port, to_port);
+ }
+ break;
+ case ID_IPV6_ADDR_SUBNET:
+ if (this->id_data.len == 32)
+ {
+- return get_ts_from_subnet(this, TS_IPV6_ADDR_RANGE);
++ return get_ts_from_subnet(this, TS_IPV6_ADDR_RANGE, from_port, to_port);
+ }
+ break;
+ case ID_IPV4_ADDR_RANGE:
+ if (this->id_data.len == 8)
+ {
+- return get_ts_from_range(this, TS_IPV4_ADDR_RANGE);
++ return get_ts_from_range(this, TS_IPV4_ADDR_RANGE, from_port, to_port);
+ }
+ break;
+ case ID_IPV6_ADDR_RANGE:
+ if (this->id_data.len == 32)
+ {
+- return get_ts_from_range(this, TS_IPV6_ADDR_RANGE);
++ return get_ts_from_range(this, TS_IPV6_ADDR_RANGE, from_port, to_port);
+ }
+ break;
+ case ID_IPV4_ADDR:
+ if (this->id_data.len == 4)
+ {
+- return get_ts_from_ip(this, TS_IPV4_ADDR_RANGE);
++ return get_ts_from_ip(this, TS_IPV4_ADDR_RANGE, from_port, to_port);
+ }
+ break;
+ case ID_IPV6_ADDR:
+ if (this->id_data.len == 16)
+ {
+- return get_ts_from_ip(this, TS_IPV6_ADDR_RANGE);
++ return get_ts_from_ip(this, TS_IPV6_ADDR_RANGE, from_port, to_port);
+ }
+ break;
+ default:
+@@ -397,7 +424,7 @@ id_payload_t *id_payload_create_from_identification(payload_type_t type,
+ /*
+ * Described in header.
+ */
+-id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts)
++id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts, bool initiator)
+ {
+ private_id_payload_t *this;
+ u_int8_t mask;
+@@ -460,8 +487,17 @@ id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts)
+ ts->get_from_address(ts), ts->get_to_address(ts));
+ net->destroy(net);
+ }
+- this->port = ts->get_from_port(ts);
+ this->protocol_id = ts->get_protocol(ts);
++ if (initiator || this->protocol_id != IPPROTO_GRE)
++ {
++ this->port = ts->get_from_port(ts);
++ }
++ else
++ {
++ this->port = ts->get_to_port(ts);
++ if (this->port == 0xffff && ts->get_from_port(ts) == 0)
++ this->port = 0;
++ }
+ this->payload_length += this->id_data.len;
+
+ return &this->public;
+diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h
+index df1d075..7558e91 100644
+--- a/src/libcharon/encoding/payloads/id_payload.h
++++ b/src/libcharon/encoding/payloads/id_payload.h
+@@ -48,11 +48,11 @@ struct id_payload_t {
+ identification_t *(*get_identification) (id_payload_t *this);
+
+ /**
+- * Creates a traffic selector form a ID_ADDR_SUBNET/RANGE identity.
++ * Creates a traffic selector form a ID_ADDR_SUBNET/RANGE identity pair.
+ *
+ * @return traffic selector, NULL on failure
+ */
+- traffic_selector_t* (*get_ts)(id_payload_t *this);
++ traffic_selector_t* (*get_ts)(id_payload_t *this, id_payload_t *other, bool initiator);
+
+ /**
+ * Get encoded payload without fixed payload header (used for IKEv1).
+@@ -91,6 +91,6 @@ id_payload_t *id_payload_create_from_identification(payload_type_t type,
+ * @param ts traffic selector
+ * @return PLV1_ID id_paylad_t object.
+ */
+-id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts);
++id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts, bool initiator);
+
+ #endif /** ID_PAYLOAD_H_ @}*/
+diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
+index 55ec7cd..87a1d08 100644
+--- a/src/libcharon/plugins/stroke/stroke_config.c
++++ b/src/libcharon/plugins/stroke/stroke_config.c
+@@ -1032,6 +1032,11 @@ static bool parse_protoport(char *token, u_int16_t *from_port,
+ *from_port = 0xffff;
+ *to_port = 0;
+ }
++ else if (*port && *protocol == IPPROTO_GRE)
++ {
++ p = strtol(port, &endptr, 0);
++ traffic_selector_split_grekey(p, from_port, to_port);
++ }
+ else if (*port)
+ {
+ svc = getservbyname(port, NULL);
+diff --git a/src/libcharon/plugins/unity/unity_narrow.c b/src/libcharon/plugins/unity/unity_narrow.c
+index 227d24b..7749d8c 100644
+--- a/src/libcharon/plugins/unity/unity_narrow.c
++++ b/src/libcharon/plugins/unity/unity_narrow.c
+@@ -247,7 +247,7 @@ METHOD(listener_t, message, bool,
+ if (!first)
+ {
+ id_payload = (id_payload_t*)payload;
+- tsr = id_payload->get_ts(id_payload);
++ tsr = id_payload->get_ts(id_payload, NULL, FALSE);
+ break;
+ }
+ first = FALSE;
+diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
+index 3c4e3ec..9495d4d 100644
+--- a/src/libcharon/plugins/vici/vici_config.c
++++ b/src/libcharon/plugins/vici/vici_config.c
+@@ -586,8 +586,13 @@ CALLBACK(parse_ts, bool,
+ }
+ else if (*port && !streq(port, "any"))
+ {
+- svc = getservbyname(port, NULL);
+- if (svc)
++ if (proto == IPPROTO_GRE)
++ {
++ p = strtol(port, &end, 0);
++ if (*end) return FALSE;
++ traffic_selector_split_grekey(p, &from, &to);
++ }
++ else if ((svc = getservbyname(port, NULL)) != NULL)
+ {
+ from = to = ntohs(svc->s_port);
+ }
+diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
+index 96edfd8..c0830dd 100644
+--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
++++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
+@@ -536,9 +536,9 @@ static void add_ts(private_quick_mode_t *this, message_t *message)
+ {
+ id_payload_t *id_payload;
+
+- id_payload = id_payload_create_from_ts(this->tsi);
++ id_payload = id_payload_create_from_ts(this->tsi, TRUE);
+ message->add_payload(message, &id_payload->payload_interface);
+- id_payload = id_payload_create_from_ts(this->tsr);
++ id_payload = id_payload_create_from_ts(this->tsr, FALSE);
+ message->add_payload(message, &id_payload->payload_interface);
+ }
+
+@@ -549,7 +549,7 @@ static bool get_ts(private_quick_mode_t *this, message_t *message)
+ {
+ traffic_selector_t *tsi = NULL, *tsr = NULL;
+ enumerator_t *enumerator;
+- id_payload_t *id_payload;
++ id_payload_t *idi = NULL, *idr = NULL;
+ payload_t *payload;
+ host_t *hsi, *hsr;
+ bool first = TRUE;
+@@ -559,20 +559,22 @@ static bool get_ts(private_quick_mode_t *this, message_t *message)
+ {
+ if (payload->get_type(payload) == PLV1_ID)
+ {
+- id_payload = (id_payload_t*)payload;
+-
+ if (first)
+ {
+- tsi = id_payload->get_ts(id_payload);
++ idi = (id_payload_t*)payload;
+ first = FALSE;
+ }
+ else
+ {
+- tsr = id_payload->get_ts(id_payload);
++ idr = (id_payload_t*)payload;
+ break;
+ }
+ }
+ }
++ if (idi && idr) {
++ tsi = idi->get_ts(idi, idr, TRUE);
++ tsr = idr->get_ts(idr, idi, FALSE);
++ }
+ enumerator->destroy(enumerator);
+
+ /* create host2host selectors if ID payloads missing */
+diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
+index f22e07d..e43df3f 100644
+--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
++++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
+@@ -743,7 +743,18 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src,
+ ts2subnet(src, &sel.saddr, &sel.prefixlen_s);
+ ts2ports(dst, &sel.dport, &sel.dport_mask);
+ ts2ports(src, &sel.sport, &sel.sport_mask);
+- if ((sel.proto == IPPROTO_ICMP || sel.proto == IPPROTO_ICMPV6) &&
++ if (sel.proto == IPPROTO_GRE)
++ {
++ sel.sport = htons(src->get_from_port(src));
++ sel.dport = htons(src->get_to_port(src));
++ sel.sport_mask = ~0;
++ sel.dport_mask = ~0;
++ if (sel.sport == htons(0) && sel.dport == htons(0xffff))
++ {
++ sel.sport = sel.dport = sel.sport_mask = sel.dport_mask = 0;
++ }
++ }
++ else if ((sel.proto == IPPROTO_ICMP || sel.proto == IPPROTO_ICMPV6) &&
+ (sel.dport || sel.sport))
+ {
+ /* the ICMP type is encoded in the most significant 8 bits and the ICMP
+@@ -767,7 +778,7 @@ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
+ {
+ u_char *addr;
+ u_int8_t prefixlen;
+- u_int16_t port = 0;
++ u_int16_t from_port = 0, to_port = 65535;
+ host_t *host = NULL;
+
+ if (src)
+@@ -776,7 +787,7 @@ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
+ prefixlen = sel->prefixlen_s;
+ if (sel->sport_mask)
+ {
+- port = ntohs(sel->sport);
++ from_port = to_port = ntohs(sel->sport);
+ }
+ }
+ else
+@@ -785,14 +796,27 @@ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
+ prefixlen = sel->prefixlen_d;
+ if (sel->dport_mask)
+ {
+- port = ntohs(sel->dport);
++ from_port = to_port = ntohs(sel->dport);
++ }
++ }
++ if (sel->proto == IPPROTO_GRE)
++ {
++ if (sel->sport_mask)
++ {
++ from_port = ntohs(sel->sport);
++ to_port = ntohs(sel->dport);
++ }
++ else
++ {
++ from_port = 0;
++ to_port = 0xffff;
+ }
+ }
+- if (sel->proto == IPPROTO_ICMP || sel->proto == IPPROTO_ICMPV6)
++ else if (sel->proto == IPPROTO_ICMP || sel->proto == IPPROTO_ICMPV6)
+ { /* convert ICMP[v6] message type and code as supplied by the kernel in
+ * source and destination ports (both in network order) */
+- port = (sel->sport >> 8) | (sel->dport & 0xff00);
+- port = ntohs(port);
++ from_port = (sel->sport >> 8) | (sel->dport & 0xff00);
++ from_port = to_port = ntohs(from_port);
+ }
+ /* The Linux 2.6 kernel does not set the selector's family field,
+ * so as a kludge we additionally test the prefix length.
+@@ -809,7 +833,7 @@ static traffic_selector_t* selector2ts(struct xfrm_selector *sel, bool src)
+ if (host)
+ {
+ return traffic_selector_create_from_subnet(host, prefixlen,
+- sel->proto, port, port ?: 65535);
++ sel->proto, from_port, to_port);
+ }
+ return NULL;
+ }
+diff --git a/src/libstrongswan/selectors/traffic_selector.c b/src/libstrongswan/selectors/traffic_selector.c
+index 3b7f8c5..c593a3f 100644
+--- a/src/libstrongswan/selectors/traffic_selector.c
++++ b/src/libstrongswan/selectors/traffic_selector.c
+@@ -209,6 +209,14 @@ static int print_icmp(printf_hook_data_t *data, u_int16_t port)
+ }
+
+ /**
++ * Print GRE key
++ */
++static int print_grekey(printf_hook_data_t *data, u_int16_t from_port, u_int16_t to_port)
++{
++ return print_in_hook(data, "%d", traffic_selector_grekey(from_port, to_port));
++}
++
++/**
+ * Described in header.
+ */
+ int traffic_selector_printf_hook(printf_hook_data_t *data,
+@@ -313,7 +321,11 @@ int traffic_selector_printf_hook(printf_hook_data_t *data,
+ /* build port string */
+ if (has_ports)
+ {
+- if (this->from_port == this->to_port)
++ if (this->protocol == IPPROTO_GRE)
++ {
++ written += print_grekey(data, this->from_port, this->to_port);
++ }
++ else if (this->from_port == this->to_port)
+ {
+ struct servent *serv;
+
+@@ -398,7 +410,24 @@ METHOD(traffic_selector_t, get_subset, traffic_selector_t*,
+ /* select protocol, which is not zero */
+ protocol = max(this->protocol, other->protocol);
+
+- if ((is_opaque(this) && is_opaque(other)) ||
++ if (this->protocol == IPPROTO_GRE)
++ {
++ if (is_any(this))
++ {
++ from_port = other->from_port;
++ to_port = other->to_port;
++ }
++ else if (is_any(other) ||
++ (this->from_port == other->from_port &&
++ this->to_port == other->to_port))
++ {
++ from_port = this->from_port;
++ to_port = this->to_port;
++ }
++ else
++ return NULL;
++ }
++ else if ((is_opaque(this) && is_opaque(other)) ||
+ (is_opaque(this) && is_any(other)) ||
+ (is_opaque(other) && is_any(this)))
+ {
+diff --git a/src/libstrongswan/selectors/traffic_selector.h b/src/libstrongswan/selectors/traffic_selector.h
+index cf9a286..d458c68 100644
+--- a/src/libstrongswan/selectors/traffic_selector.h
++++ b/src/libstrongswan/selectors/traffic_selector.h
+@@ -120,6 +120,9 @@ struct traffic_selector_t {
+ * 8 bits and the code in the least significant 8 bits. Use the utility
+ * functions to extract them.
+ *
++ * If the protocol is GRE, the high 16-bits of the 32-bit GRE key is stored
++ * in the from port. Use the utility function to merge and split them.
++ *
+ * @return port
+ */
+ u_int16_t (*get_from_port) (traffic_selector_t *this);
+@@ -134,6 +137,9 @@ struct traffic_selector_t {
+ * 8 bits and the code in the least significant 8 bits. Use the utility
+ * functions to extract them.
+ *
++ * If the protocol is GRE, the low 16-bits of the 32-bit GRE key is stored
++ * in the to port. Use the utility function to merge and split them.
++ *
+ * @return port
+ */
+ u_int16_t (*get_to_port) (traffic_selector_t *this);
+@@ -268,6 +274,31 @@ int traffic_selector_cmp(traffic_selector_t *a, traffic_selector_t *b,
+ void *opts);
+
+ /**
++ * Reconstruct the 32-bit GRE KEY in host order from a from/to ports.
++ *
++ * @param from_port port number in host order
++ * @param to_port port number in host order
++ * @return GRE KEY in host order
++ */
++static inline u_int32_t traffic_selector_grekey(u_int16_t from_port, u_int16_t to_port)
++{
++ return (from_port << 16) | to_port;
++}
++
++/**
++ * Split 32-bit GRE KEY in host order to from/to ports.
++ *
++ * @param grekey grekey in host order
++ * @param from_port from port in host order
++ * @param to_port to port in host order
++ */
++static inline void traffic_selector_split_grekey(u_int32_t grekey, u_int16_t *from_port, u_int16_t *to_port)
++{
++ *from_port = grekey >> 16;
++ *to_port = grekey & 0xffff;
++}
++
++/**
+ * Create a new traffic selector using human readable params.
+ *
+ * If protocol is ICMP or ICMPv6 the ports are interpreted as follows: If they
+--
+2.4.5
+