generating basic IKE_SA sync messages
authorMartin Willi <martin@strongswan.org>
Thu, 13 Nov 2008 12:46:01 +0000 (12:46 +0000)
committerMartin Willi <martin@revosec.ch>
Wed, 7 Apr 2010 11:55:11 +0000 (13:55 +0200)
pushing to statically configured failover node

src/charon/plugins/ha_sync/ha_sync_ike.c
src/charon/plugins/ha_sync/ha_sync_message.c
src/charon/plugins/ha_sync/ha_sync_message.h

index e894e39..46af186 100644 (file)
@@ -36,12 +36,114 @@ struct private_ha_sync_ike_t {
 };
 
 /**
+ * Return condition if it is set on ike_sa
+ */
+static ike_condition_t copy_condition(ike_sa_t *ike_sa, ike_condition_t cond)
+{
+       if (ike_sa->has_condition(ike_sa, cond))
+       {
+               return cond;
+       }
+       return 0;
+}
+
+/**
+ * Return extension if it is supported by peers IKE_SA
+ */
+static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext)
+{
+       if (ike_sa->supports_extension(ike_sa, ext))
+       {
+               return ext;
+       }
+       return 0;
+}
+
+/**
  * Implementation of listener_t.ike_keys
  */
 static bool ike_keys(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
                                         diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
                                         ike_sa_t *rekey)
 {
+       iterator_t *iterator;
+       ha_sync_message_t *m;
+       peer_cfg_t *peer_cfg;
+       u_int32_t extension, condition;
+       host_t *local_vip, *remote_vip, *addr;
+       identification_t *eap_id;
+       chunk_t secret;
+
+       peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+
+       condition = copy_condition(ike_sa, COND_NAT_ANY)
+                         | copy_condition(ike_sa, COND_NAT_HERE)
+                         | copy_condition(ike_sa, COND_NAT_THERE)
+                         | copy_condition(ike_sa, COND_NAT_FAKE)
+                         | copy_condition(ike_sa, COND_EAP_AUTHENTICATED)
+                         | copy_condition(ike_sa, COND_CERTREQ_SEEN)
+                         | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR);
+
+       extension = copy_extension(ike_sa, EXT_NATT)
+                         | copy_extension(ike_sa, EXT_MOBIKE)
+                         | copy_extension(ike_sa, EXT_HASH_AND_URL);
+
+       local_vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
+       remote_vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+       eap_id = ike_sa->get_eap_identity(ike_sa);
+
+       if (dh->get_shared_secret(dh, &secret) != SUCCESS)
+       {
+               return TRUE;
+       }
+
+       if (rekey == NULL)
+       {
+               m = ha_sync_message_create(HA_SYNC_IKE_ADD);
+
+               m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
+               m->add_attribute(m, HA_SYNC_LOCAL_ID, ike_sa->get_my_id(ike_sa));
+               m->add_attribute(m, HA_SYNC_REMOTE_ID, ike_sa->get_other_id(ike_sa));
+               m->add_attribute(m, HA_SYNC_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
+               m->add_attribute(m, HA_SYNC_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
+               m->add_attribute(m, HA_SYNC_CONFIG_NAME, peer_cfg->get_name(peer_cfg));
+               m->add_attribute(m, HA_SYNC_CONDITIONS, condition);
+               m->add_attribute(m, HA_SYNC_EXTENSIONS, extension);
+               if (local_vip)
+               {
+                       m->add_attribute(m, HA_SYNC_LOCAL_VIP, local_vip);
+               }
+               if (remote_vip)
+               {
+                       m->add_attribute(m, HA_SYNC_REMOTE_VIP, remote_vip);
+               }
+               if (eap_id)
+               {
+                       m->add_attribute(m, HA_SYNC_EAP_ID, eap_id);
+               }
+               iterator = ike_sa->create_additional_address_iterator(ike_sa);
+               while (iterator->iterate(iterator, (void**)&addr))
+               {
+                       m->add_attribute(m, HA_SYNC_ADDITIONAL_ADDR, addr);
+               }
+               iterator->destroy(iterator);
+       }
+       else
+       {
+               m = ha_sync_message_create(HA_SYNC_IKE_REKEY);
+
+               m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
+               m->add_attribute(m, HA_SYNC_IKE_REKEY_ID, rekey->get_id(rekey));
+       }
+
+       m->add_attribute(m, HA_SYNC_NONCE_I, nonce_i);
+       m->add_attribute(m, HA_SYNC_NONCE_R, nonce_r);
+       m->add_attribute(m, HA_SYNC_SECRET, secret);
+       chunk_clear(&secret);
+
+       this->socket->push(this->socket, m);
+       m->destroy(m);
+
        return TRUE;
 }
 
index fcb601c..ee3aa24 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <daemon.h>
 
+#define ALLOCATION_BLOCK 64
+
 typedef struct private_ha_sync_message_t private_ha_sync_message_t;
 
 /**
@@ -34,7 +36,7 @@ struct private_ha_sync_message_t {
        ha_sync_message_t public;
 
        /**
-        * Number of bytes allocted in buffer
+        * Allocated size of buf
         */
        size_t allocated;
 
@@ -44,6 +46,39 @@ struct private_ha_sync_message_t {
        chunk_t buf;
 };
 
+typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t;
+
+/**
+ * Encoding if an ike_sa_id_t
+ */
+struct ike_sa_id_encoding_t {
+       u_int64_t initiator_spi;
+       u_int64_t responder_spi;
+       u_int8_t initiator;
+} __attribute__((packed));
+
+typedef struct identification_encoding_t identification_encoding_t;
+
+/**
+ * Encoding of a identification_t
+ */
+struct identification_encoding_t {
+       u_int8_t type;
+       u_int8_t len;
+       char encoding[];
+} __attribute__((packed));
+
+typedef struct host_encoding_t host_encoding_t;
+
+/**
+ * encoding of a host_t
+ */
+struct host_encoding_t {
+       u_int16_t port;
+       u_int8_t family;
+       char encoding[];
+} __attribute__((packed));
+
 /**
  * Implementation of ha_sync_message_t.get_type
  */
@@ -57,9 +92,15 @@ static ha_sync_message_type_t get_type(private_ha_sync_message_t *this)
  */
 static void check_buf(private_ha_sync_message_t *this, size_t len)
 {
+       int increased = 0;
+
        while (this->buf.len + len > this->allocated)
        {       /* double size */
-               this->allocated = this->allocated * 2;
+               this->allocated += ALLOCATION_BLOCK;
+               increased++;
+       }
+       if (increased)
+       {
                this->buf.ptr = realloc(this->buf.ptr, this->allocated);
        }
 }
@@ -68,60 +109,119 @@ static void check_buf(private_ha_sync_message_t *this, size_t len)
  * Implementation of ha_sync_message_t.add_attribute
  */
 static void add_attribute(private_ha_sync_message_t *this,
-                                                 ha_sync_message_attribute_t attribute,
-                                                 ha_sync_message_value_t value)
+                                                 ha_sync_message_attribute_t attribute, ...)
 {
        size_t len;
+       va_list args;
 
        check_buf(this, sizeof(u_int8_t));
        this->buf.ptr[this->buf.len] = attribute;
        this->buf.len += sizeof(u_int8_t);
 
+       va_start(args, attribute);
        switch (attribute)
        {
-               case HA_SYNC_ENCAP_U8:
-               case HA_SYNC_MODE_U8:
-               case HA_SYNC_IPCOMP_U8:
-                       check_buf(this, sizeof(value.u8));
-                       this->buf.ptr[this->buf.len] = value.u8;
-                       this->buf.len += sizeof(value.u8);
-                       break;
-               case HA_SYNC_PORT_L_U16:
-               case HA_SYNC_PORT_R_U16:
-               case HA_SYNC_CPI_L_U16:
-               case HA_SYNC_CPI_R_U16:
-               case HA_SYNC_ALG_INTEG_U16:
-               case HA_SYNC_ALG_ENC_U16:
-                       check_buf(this, sizeof(value.u16));
-                       this->buf.ptr[this->buf.len] = htons(value.u16);
-                       this->buf.len += sizeof(value.u16);
+               /* ike_sa_id_t* */
+               case HA_SYNC_IKE_ID:
+               case HA_SYNC_IKE_REKEY_ID:
+               {
+                       ike_sa_id_encoding_t *enc;
+                       ike_sa_id_t *id;
+
+                       id = va_arg(args, ike_sa_id_t*);
+                       check_buf(this, sizeof(ike_sa_id_encoding_t));
+                       enc = (ike_sa_id_encoding_t*)(this->buf.ptr + this->buf.len);
+                       this->buf.len += sizeof(ike_sa_id_encoding_t);
+                       enc->initiator = id->is_initiator(id);
+                       enc->initiator_spi = id->get_initiator_spi(id);
+                       enc->responder_spi = id->get_responder_spi(id);
                        break;
-               case HA_SYNC_SPI_L_U32:
-               case HA_SYNC_SPI_R_U32:
-                       check_buf(this, sizeof(value.u32));
-                       this->buf.ptr[this->buf.len] = htonl(value.u32);
-                       this->buf.len += sizeof(value.u32);
+               }
+               /* identification_t* */
+               case HA_SYNC_LOCAL_ID:
+               case HA_SYNC_REMOTE_ID:
+               case HA_SYNC_EAP_ID:
+               {
+                       identification_encoding_t *enc;
+                       identification_t *id;
+                       chunk_t data;
+
+                       id = va_arg(args, identification_t*);
+                       data = id->get_encoding(id);
+                       check_buf(this, sizeof(identification_encoding_t) + data.len);
+                       enc = (identification_encoding_t*)(this->buf.ptr + this->buf.len);
+                       this->buf.len += sizeof(identification_encoding_t) + data.len;
+                       enc->type = id->get_type(id);
+                       enc->len = data.len;
+                       memcpy(enc->encoding, data.ptr, data.len);
                        break;
-               case HA_SYNC_IPV4_L_CHNK:
-               case HA_SYNC_IPV4_R_CHNK:
-               case HA_SYNC_NONCE_I_CHNK:
-               case HA_SYNC_NONCE_R_CHNK:
-               case HA_SYNC_SECRET_CHNK:
-                       check_buf(this, value.chnk.len);
-                       memcpy(this->buf.ptr + this->buf.len, value.chnk.ptr, value.chnk.len);
-                       this->buf.len += value.chnk.len;
+               }
+               /* host_t* */
+               case HA_SYNC_LOCAL_ADDR:
+               case HA_SYNC_REMOTE_ADDR:
+               case HA_SYNC_LOCAL_VIP:
+               case HA_SYNC_REMOTE_VIP:
+               case HA_SYNC_ADDITIONAL_ADDR:
+               {
+                       host_encoding_t *enc;
+                       host_t *host;
+                       chunk_t data;
+
+                       host = va_arg(args, host_t*);
+                       data = host->get_address(host);
+                       check_buf(this, sizeof(host_encoding_t) + data.len);
+                       enc = (host_encoding_t*)(this->buf.ptr + this->buf.len);
+                       this->buf.len += sizeof(host_encoding_t) + data.len;
+                       enc->family = host->get_family(host);
+                       enc->port = htons(host->get_port(host));
+                       memcpy(enc->encoding, data.ptr, data.len);
                        break;
-               case HA_SYNC_CONFIG_STR:
-                       len = strlen(value.str) + 1;
+               }
+               /* char* */
+               case HA_SYNC_CONFIG_NAME:
+               {
+                       char *str;
+
+                       str = va_arg(args, char*);
+                       len = strlen(str) + 1;
                        check_buf(this, len);
-                       memcpy(this->buf.ptr + this->buf.len, value.str, len);
+                       memcpy(this->buf.ptr + this->buf.len, str, len);
                        this->buf.len += len;
                        break;
+               }
+               /** u_int32_t */
+               case HA_SYNC_CONDITIONS:
+               case HA_SYNC_EXTENSIONS:
+               {
+                       u_int32_t val;
+
+                       val = va_arg(args, u_int32_t);
+                       check_buf(this, sizeof(val));
+                       this->buf.ptr[this->buf.len] = htonl(val);
+                       this->buf.len += sizeof(val);
+                       break;
+               }
+               /** chunk_t */
+               case HA_SYNC_NONCE_I:
+               case HA_SYNC_NONCE_R:
+               case HA_SYNC_SECRET:
+               {
+                       chunk_t chunk;
+
+                       chunk = va_arg(args, chunk_t);
+                       check_buf(this, chunk.len);
+                       memcpy(this->buf.ptr + this->buf.len, chunk.ptr, chunk.len);
+                       this->buf.len += chunk.len;
+                       break;
+               }
                default:
+               {
                        DBG1(DBG_CFG, "unable to encode, attribute %d unknown", attribute);
                        this->buf.len -= sizeof(u_int8_t);
                        break;
+               }
        }
+       va_end(args);
 }
 
 /**
@@ -170,7 +270,7 @@ ha_sync_message_t *ha_sync_message_create(ha_sync_message_type_t type)
 {
        private_ha_sync_message_t *this = ha_sync_message_create_generic();
 
-       this->allocated = 64;
+       this->allocated = ALLOCATION_BLOCK;
        this->buf.ptr = malloc(this->allocated);
        this->buf.len = 2;
        this->buf.ptr[0] = HA_SYNC_MESSAGE_VERSION;
index 714becf..ebe0c2d 100644 (file)
@@ -24,6 +24,9 @@
 #define HA_SYNC_MESSAGE_H_
 
 #include <library.h>
+#include <utils/host.h>
+#include <utils/identification.h>
+#include <sa/ike_sa_id.h>
 
 /**
  * Protocol version of this implementation
@@ -39,32 +42,56 @@ typedef union ha_sync_message_value_t ha_sync_message_value_t;
  * Type of a sync message
  */
 enum ha_sync_message_type_t {
-       HA_SYNC_CHILD_SA = 0,
-       HA_SYNC_IKE_SA,
-       HA_SYNC_IKE_MID,
+       /** add a completely new IKE_SA */
+       HA_SYNC_IKE_ADD = 1,
+       /** update an existing IKE_SA (message IDs, address update, ...) */
+       HA_SYNC_IKE_UPDATE,
+       /** delete an existing IKE_SA */
+       HA_SYNC_IKE_DELETE,
+       /** rekeying an existing IKE_SA, transferring CHILD_SAs to a new one */
+       HA_SYNC_IKE_REKEY,
+       /** add a new CHILD_SA */
+       HA_SYNC_CHILD_ADD,
+       /** delete an existing CHILD_SA */
+       HA_SYNC_CHILD_DELETE,
 };
 
 /**
  * Type of attributes contained in a message
  */
 enum ha_sync_message_attribute_t {
-       HA_SYNC_CONFIG_STR = 0,
-       HA_SYNC_IPV4_L_CHNK,
-       HA_SYNC_IPV4_R_CHNK,
-       HA_SYNC_PORT_L_U16,
-       HA_SYNC_PORT_R_U16,
-       HA_SYNC_SPI_L_U32,
-       HA_SYNC_SPI_R_U32,
-       HA_SYNC_CPI_L_U16,
-       HA_SYNC_CPI_R_U16,
-       HA_SYNC_ENCAP_U8,
-       HA_SYNC_MODE_U8,
-       HA_SYNC_IPCOMP_U8,
-       HA_SYNC_NONCE_I_CHNK,
-       HA_SYNC_NONCE_R_CHNK,
-       HA_SYNC_SECRET_CHNK,
-       HA_SYNC_ALG_INTEG_U16,
-       HA_SYNC_ALG_ENC_U16,
+       /** ike_sa_id_t*, to identify IKE_SA */
+       HA_SYNC_IKE_ID = 1,
+       /** ike_Sa_id_t*, identifies IKE_SA which gets rekeyed */
+       HA_SYNC_IKE_REKEY_ID,
+       /** identification_t*, local identity */
+       HA_SYNC_LOCAL_ID,
+       /** identification_t*, remote identity */
+       HA_SYNC_REMOTE_ID,
+       /** identification_t*, EAP identity */
+       HA_SYNC_EAP_ID,
+       /** host_t*, local address */
+       HA_SYNC_LOCAL_ADDR,
+       /** host_t*, remote address */
+       HA_SYNC_REMOTE_ADDR,
+       /** char*, name of configuration */
+       HA_SYNC_CONFIG_NAME,
+       /** u_int32_t, bitset of ike_condition_t */
+       HA_SYNC_CONDITIONS,
+       /** u_int32_t, bitset of ike_extension_t */
+       HA_SYNC_EXTENSIONS,
+       /** host_t*, local virtual IP */
+       HA_SYNC_LOCAL_VIP,
+       /** host_t*, remote virtual IP */
+       HA_SYNC_REMOTE_VIP,
+       /** host_t*, additional MOBIKE peer address */
+       HA_SYNC_ADDITIONAL_ADDR,
+       /** chunk_t, initiators nonce */
+       HA_SYNC_NONCE_I,
+       /** chunk_t, responders nonce */
+       HA_SYNC_NONCE_R,
+       /** chunk_t, diffie hellman shared secret */
+       HA_SYNC_SECRET,
 };
 
 /**
@@ -75,6 +102,9 @@ union ha_sync_message_value_t {
        u_int32_t u32;
        u_int16_t u16;
        chunk_t chnk;
+       host_t *host;
+       identification_t *id;
+       ike_sa_id_t *ike_sa_id;
        char *str;
 };