From: Tobias Brunner Date: Wed, 22 Apr 2015 12:34:53 +0000 (+0200) Subject: redirect-manager: Add helper function to create and parse REDIRECT notify data X-Git-Tag: 5.4.0dr8~12^2~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2beb26b9489b0d94d2c1be3022099aa8bd02735c;p=thirdparty%2Fstrongswan.git redirect-manager: Add helper function to create and parse REDIRECT notify data The same encoding is also used for the REDIRECT_FROM notifies. --- diff --git a/src/libcharon/sa/redirect_manager.c b/src/libcharon/sa/redirect_manager.c index e37c26f0d8..ff92ac29f8 100644 --- a/src/libcharon/sa/redirect_manager.c +++ b/src/libcharon/sa/redirect_manager.c @@ -17,6 +17,8 @@ #include #include +#include +#include typedef struct private_redirect_manager_t private_redirect_manager_t; @@ -41,6 +43,57 @@ struct private_redirect_manager_t { rwlock_t *lock; }; + +/** + * Gateway identify types + * + * The encoding is the same as that for corresponding ID payloads. + */ +typedef enum { + /** IPv4 address of the VPN gateway */ + GATEWAY_ID_TYPE_IPV4 = 1, + /** IPv6 address of the VPN gateway */ + GATEWAY_ID_TYPE_IPV6 = 2, + /** FQDN of the VPN gateway */ + GATEWAY_ID_TYPE_FQDN = 3, +} gateway_id_type_t; + +/** + * Mapping of gateway identity types to identity types + */ +static id_type_t gateway_to_id_type(gateway_id_type_t type) +{ + switch (type) + { + case GATEWAY_ID_TYPE_IPV4: + return ID_IPV4_ADDR; + case GATEWAY_ID_TYPE_IPV6: + return ID_IPV6_ADDR; + case GATEWAY_ID_TYPE_FQDN: + return ID_FQDN; + default: + return 0; + } +} + +/** + * Mapping of identity types to gateway identity types + */ +static gateway_id_type_t id_type_to_gateway(id_type_t type) +{ + switch (type) + { + case ID_IPV4_ADDR: + return GATEWAY_ID_TYPE_IPV4; + case ID_IPV6_ADDR: + return GATEWAY_ID_TYPE_IPV6; + case ID_FQDN: + return GATEWAY_ID_TYPE_FQDN; + default: + return 0; + } +} + METHOD(redirect_manager_t, add_provider, void, private_redirect_manager_t *this, redirect_provider_t *provider) { @@ -75,19 +128,16 @@ static bool should_redirect(private_redirect_manager_t *this, ike_sa_t *ike_sa, bool (**method)(void*,ike_sa_t*,identification_t**) = provider + offset; if (*method && (*method)(provider, ike_sa, gateway)) { - switch (*gateway ? (*gateway)->get_type(*gateway) : 0) + if (*gateway && id_type_to_gateway((*gateway)->get_type(*gateway))) { - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - case ID_FQDN: - redirect = TRUE; - break; - default: - DBG1(DBG_CFG, "redirect provider returned invalid gateway"); - DESTROY_IF(*gateway); - continue; + redirect = TRUE; + break; + } + else + { + DBG1(DBG_CFG, "redirect provider returned invalid gateway ID"); + DESTROY_IF(*gateway); } - break; } } enumerator->destroy(enumerator); @@ -140,3 +190,85 @@ redirect_manager_t *redirect_manager_create() return &this->public; } + +/* + * Encoding of a REDIRECT or REDIRECTED_FROM notify + * + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Next Payload |C| RESERVED | Payload Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |Protocol ID(=0)| SPI Size (=0) | Notify Message Type | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | GW Ident Type | GW Ident Len | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~ + ~ New Responder GW Identity ~ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + ~ Nonce Data ~ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/* + * Described in header + */ +chunk_t redirect_data_create(identification_t *gw, chunk_t nonce) +{ + gateway_id_type_t type; + bio_writer_t *writer; + chunk_t data; + + type = id_type_to_gateway(gw->get_type(gw)); + if (!type) + { + return chunk_empty; + } + + writer = bio_writer_create(0); + writer->write_uint8(writer, type); + writer->write_data8(writer, gw->get_encoding(gw)); + if (nonce.ptr) + { + writer->write_data(writer, nonce); + } + + data = writer->extract_buf(writer); + writer->destroy(writer); + return data; +} + +/* + * Described in header + */ +identification_t *redirect_data_parse(chunk_t data, chunk_t *nonce) +{ + bio_reader_t *reader; + id_type_t id_type; + chunk_t gateway; + u_int8_t type; + + reader = bio_reader_create(data); + if (!reader->read_uint8(reader, &type) || + !reader->read_data8(reader, &gateway)) + { + DBG1(DBG_ENC, "invalid REDIRECT notify data"); + reader->destroy(reader); + return NULL; + } + id_type = gateway_to_id_type(type); + if (!id_type) + { + DBG1(DBG_ENC, "invalid gateway ID type (%d) in REDIRECT notify", type); + reader->destroy(reader); + return NULL; + } + if (nonce) + { + *nonce = chunk_clone(reader->peek(reader)); + } + reader->destroy(reader); + return identification_create_from_encoding(id_type, gateway); +} diff --git a/src/libcharon/sa/redirect_manager.h b/src/libcharon/sa/redirect_manager.h index a74cfa3b47..45a727c29e 100644 --- a/src/libcharon/sa/redirect_manager.h +++ b/src/libcharon/sa/redirect_manager.h @@ -87,4 +87,23 @@ struct redirect_manager_t { */ redirect_manager_t *redirect_manager_create(); +/** + * Create notification data of a REDIRECT or REDIRECT_FROM payload using the + * given gateway identity and optional nonce (only used during IKE_SA_INIT). + * + * @param gw gateway identity (IP or FQDN), gets cloned + * @param nonce nonce value, or chunk_empty, gets cloned + * @return notify data, chunk_empty if ID type is not supported + */ +chunk_t redirect_data_create(identification_t *gw, chunk_t nonce); + +/** + * Parse notification data of a REDIRECT or REDIRECTED_FROM notify payload. + * + * @param data notification data to parse + * @param nonce[out] nonce data (allocated), if any was provided + * @return gateway identity, NULL if data is invalid + */ +identification_t *redirect_data_parse(chunk_t data, chunk_t *nonce); + #endif /** REDIRECT_MANAGER_H_ @}*/