redirect-manager: Add helper function to create and parse REDIRECT notify data
authorTobias Brunner <tobias@strongswan.org>
Wed, 22 Apr 2015 12:34:53 +0000 (14:34 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 4 Mar 2016 15:02:58 +0000 (16:02 +0100)
The same encoding is also used for the REDIRECT_FROM notifies.

src/libcharon/sa/redirect_manager.c
src/libcharon/sa/redirect_manager.h

index e37c26f..ff92ac2 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <collections/linked_list.h>
 #include <threading/rwlock.h>
+#include <bio/bio_reader.h>
+#include <bio/bio_writer.h>
 
 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);
+}
index a74cfa3..45a727c 100644 (file)
@@ -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_ @}*/