diff options
Diffstat (limited to 'main/strongswan/1000-support-gre-key-in-ikev1.patch')
-rw-r--r-- | main/strongswan/1000-support-gre-key-in-ikev1.patch | 507 |
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 + |