IKEv1 ConfigMode: Added the payload handlers for attribute_payload and data_attribute...
authorClavister OpenSource <opensource@clavister.com>
Wed, 23 Nov 2011 07:36:22 +0000 (08:36 +0100)
committerClavister OpenSource <opensource@clavister.com>
Tue, 20 Mar 2012 16:30:49 +0000 (17:30 +0100)
src/libcharon/encoding/payloads/attribute_payload_v1.c [new file with mode: 0644]
src/libcharon/encoding/payloads/attribute_payload_v1.h [new file with mode: 0644]
src/libcharon/encoding/payloads/data_attribute_v1.c [new file with mode: 0644]
src/libcharon/encoding/payloads/data_attribute_v1.h [new file with mode: 0644]

diff --git a/src/libcharon/encoding/payloads/attribute_payload_v1.c b/src/libcharon/encoding/payloads/attribute_payload_v1.c
new file mode 100644 (file)
index 0000000..3aa0bc3
--- /dev/null
@@ -0,0 +1,231 @@
+
+#include <stddef.h>
+
+#include "attribute_payload_v1.h"
+
+#include <encoding/payloads/encodings.h>
+#include <utils/linked_list.h>
+
+ENUM(config_type_v1_names, ISAKMP_CFG_REQUEST, ISAKMP_CFG_ACK,
+       "ISAKMP_CFG_REQUEST",
+       "ISAKMP_CFG_REPLY",
+       "ISAKMP_CFG_SET",
+       "ISAKMP_CFG_ACK",
+);
+
+typedef struct private_attribute_payload_v1_t private_attribute_payload_v1_t;
+
+/**
+ * Private data of an attribute_payload_v1_t object.
+ */
+struct private_attribute_payload_v1_t {
+
+       /**
+        * Public cp_payload_t interface.
+        */
+       attribute_payload_v1_t public;
+
+       /**
+        * Next payload type.
+        */
+       u_int8_t  next_payload;
+
+       /**
+        * Length of this payload.
+        */
+       u_int16_t payload_length;
+
+       /**
+        * List of attributes, as configuration_attribute_t
+        */
+       linked_list_t *attributes;
+
+       /**
+        * Reserved bytes
+        */
+       u_int8_t reserved_byte[2];
+
+       /**
+        * Identifier
+        */
+       u_int16_t identifier;
+
+       /**
+        * Config Type.
+        */
+       u_int8_t type;
+};
+
+/**
+ * Encoding rules to parse or generate a IKEv2-CP Payload
+ *
+ * The defined offsets are the positions in a object of type
+ * private_attribute_payload_v1_t.
+ */
+encoding_rule_t attribute_payload_v1_encodings[] = {
+       /* 1 Byte next payload type, stored in the field next_payload */
+       { U_INT_8,                                      offsetof(private_attribute_payload_v1_t, next_payload)  },
+       /* reserved byte */
+       { RESERVED_BYTE,                                offsetof(private_attribute_payload_v1_t, reserved_byte[0])      },
+       /* Length of the whole Attribute payload*/
+       { PAYLOAD_LENGTH,                       offsetof(private_attribute_payload_v1_t, payload_length)        },
+       /* Config type */
+       { U_INT_8,                                      offsetof(private_attribute_payload_v1_t, type)                  },
+       /* 3 reserved bytes */
+       { RESERVED_BYTE,                        offsetof(private_attribute_payload_v1_t, reserved_byte[1])},
+
+       /* Identifier */
+       { U_INT_16,                             offsetof(private_attribute_payload_v1_t, identifier)},
+
+       /* List of configuration attributes */
+       { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE,       offsetof(private_attribute_payload_v1_t, attributes)            }
+};
+
+/*
+                           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  !   RESERVED    !         Payload Length        !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !   CFG Type    !   RESERVED    !           Identifier          !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !                                                               !
+      ~                   Configuration Attributes                    ~
+      !                                                               !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+METHOD(payload_t, verify, status_t,
+       private_attribute_payload_v1_t *this)
+{
+       status_t status = SUCCESS;
+       enumerator_t *enumerator;
+       payload_t *attribute;
+
+       enumerator = this->attributes->create_enumerator(this->attributes);
+       while (enumerator->enumerate(enumerator, &attribute))
+       {
+               status = attribute->verify(attribute);
+               if (status != SUCCESS)
+               {
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       return status;
+}
+
+METHOD(payload_t, get_encoding_rules, void,
+       private_attribute_payload_v1_t *this, encoding_rule_t **rules, size_t *rule_count)
+{
+       *rules = attribute_payload_v1_encodings;
+       *rule_count = countof(attribute_payload_v1_encodings);
+}
+
+METHOD(payload_t, get_type, payload_type_t,
+       private_attribute_payload_v1_t *this)
+{
+       return ATTRIBUTE_V1;
+}
+
+METHOD(payload_t, get_next_type, payload_type_t,
+       private_attribute_payload_v1_t *this)
+{
+       return this->next_payload;
+}
+
+METHOD(payload_t, set_next_type, void,
+       private_attribute_payload_v1_t *this,payload_type_t type)
+{
+       this->next_payload = type;
+}
+
+/**
+ * recompute the length of the payload.
+ */
+static void compute_length(private_attribute_payload_v1_t *this)
+{
+       enumerator_t *enumerator;
+       payload_t *attribute;
+
+       this->payload_length = ATTRIBUTE_PAYLOAD_V1_HEADER_LENGTH;
+
+       enumerator = this->attributes->create_enumerator(this->attributes);
+       while (enumerator->enumerate(enumerator, &attribute))
+       {
+               this->payload_length += attribute->get_length(attribute);
+       }
+       enumerator->destroy(enumerator);
+}
+
+METHOD(payload_t, get_length, size_t,
+       private_attribute_payload_v1_t *this)
+{
+       return this->payload_length;
+}
+
+METHOD(attribute_payload_v1_t, create_attribute_enumerator, enumerator_t*,
+       private_attribute_payload_v1_t *this)
+{
+       return this->attributes->create_enumerator(this->attributes);
+}
+
+METHOD(attribute_payload_v1_t, add_attribute, void,
+       private_attribute_payload_v1_t *this, data_attribute_v1_t *attribute)
+{
+       this->attributes->insert_last(this->attributes, attribute);
+       compute_length(this);
+}
+
+METHOD(attribute_payload_v1_t, get_config_type, config_type_v1_t,
+       private_attribute_payload_v1_t *this)
+{
+       return this->type;
+}
+
+METHOD2(payload_t, attribute_payload_v1_t, destroy, void,
+       private_attribute_payload_v1_t *this)
+{
+       this->attributes->destroy_offset(this->attributes,
+                                                               offsetof(data_attribute_v1_t, destroy));
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+attribute_payload_v1_t *attribute_payload_v1_create_type(config_type_v1_t type)
+{
+       private_attribute_payload_v1_t *this;
+
+       INIT(this,
+               .public = {
+                       .payload_interface = {
+                               .verify = _verify,
+                               .get_encoding_rules = _get_encoding_rules,
+                               .get_length = _get_length,
+                               .get_next_type = _get_next_type,
+                               .set_next_type = _set_next_type,
+                               .get_type = _get_type,
+                               .destroy = _destroy,
+                       },
+                       .create_attribute_enumerator = _create_attribute_enumerator,
+                       .add_attribute = _add_attribute,
+                       .get_type = _get_config_type,
+                       .destroy = _destroy,
+               },
+               .next_payload = NO_PAYLOAD,
+               .payload_length = ATTRIBUTE_PAYLOAD_V1_HEADER_LENGTH,
+               .attributes = linked_list_create(),
+               .type = type,
+       );
+       return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+attribute_payload_v1_t *attribute_payload_v1_create()
+{
+       return attribute_payload_v1_create_type(ISAKMP_CFG_REQUEST);
+}
diff --git a/src/libcharon/encoding/payloads/attribute_payload_v1.h b/src/libcharon/encoding/payloads/attribute_payload_v1.h
new file mode 100644 (file)
index 0000000..d59d998
--- /dev/null
@@ -0,0 +1,93 @@
+
+/**
+ * @defgroup attribute_payload_v1 attribute_payload_v1
+ * @{ @ingroup payloads
+ */
+
+#ifndef ATTRIBUTE_PAYLOAD_V1_H_
+#define ATTRIBUTE_PAYLOAD_V1_H_
+
+typedef enum config_type_v1_t config_type_v1_t;
+typedef struct attribute_payload_v1_t attribute_payload_v1_t;
+
+#include <library.h>
+#include <encoding/payloads/payload.h>
+#include <encoding/payloads/data_attribute_v1.h>
+#include <utils/enumerator.h>
+
+/**
+ * ATTRIBUTE_PAYLOAD_V1 length in bytes without any proposal substructure.
+ */
+#define ATTRIBUTE_PAYLOAD_V1_HEADER_LENGTH 8
+
+/**
+ * Config Type of an Attribute Payload.
+ */
+enum config_type_v1_t {
+       ISAKMP_CFG_REQUEST = 1,
+       ISAKMP_CFG_REPLY = 2,
+       ISAKMP_CFG_SET = 3,
+       ISAKMP_CFG_ACK = 4,
+};
+
+/**
+ * enum name for config_type_v1_t.
+ */
+extern enum_name_t *config_type_v1_names;
+
+/**
+ * Class representing an ISAKMP Config Mode Attribute Payload.
+ *
+ * The Attribute Payload format is described in draft-ietf-ipsec-isakmp-mode-cfg-o5.txt section 3.2.
+ */
+struct attribute_payload_v1_t {
+
+       /**
+        * The payload_t interface.
+        */
+       payload_t payload_interface;
+
+       /**
+        * Creates an enumerator of stored data_attribute_v1_t objects.
+        *
+        * @return                      enumerator over configration_attribute_t
+        */
+       enumerator_t *(*create_attribute_enumerator) (attribute_payload_v1_t *this);
+
+       /**
+        * Adds a configuration attribute to the attribute payload.
+        *
+        * @param attribute     attribute to add
+        */
+       void (*add_attribute)(attribute_payload_v1_t *this,
+                                                 data_attribute_v1_t *attribute);
+
+       /**
+        * Get the attribute payload type.
+        *
+        * @return                      type of attribute payload
+        */
+       config_type_v1_t (*get_type) (attribute_payload_v1_t *this);
+
+       /**
+        * Destroys an attribute_payload_v1_t object.
+        */
+       void (*destroy) (attribute_payload_v1_t *this);
+};
+
+/**
+ * Creates an empty attribute payload
+ *
+ * @return             empty attribute payload
+ */
+attribute_payload_v1_t *attribute_payload_v1_create();
+
+/**
+ * Creates an attribute_payload_v1_t with type and value
+ *
+ * @param config_type  type of attribute payload to create
+ * @return                             created attribute payload
+ */
+attribute_payload_v1_t *attribute_payload_v1_create_type(config_type_v1_t config_type);
+
+#endif /** ATTRIBUTE_PAYLOAD_V1_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/data_attribute_v1.c b/src/libcharon/encoding/payloads/data_attribute_v1.c
new file mode 100644 (file)
index 0000000..37f7c00
--- /dev/null
@@ -0,0 +1,260 @@
+
+#include <stddef.h>
+
+#include "data_attribute_v1.h"
+
+#include <encoding/payloads/encodings.h>
+#include <library.h>
+#include <daemon.h>
+
+typedef struct private_data_attribute_v1_t private_data_attribute_v1_t;
+
+/**
+ * Private data of an data_attribute_v1_t object.
+ */
+struct private_data_attribute_v1_t {
+
+       /**
+        * Public data_attribute_v1_t interface.
+        */
+       data_attribute_v1_t public;
+
+       /**
+        * Reserved bit
+        */
+       bool af_flag;
+
+       /**
+        * Type of the attribute.
+        */
+       u_int16_t type;
+
+       /**
+        * Length of the attribute.
+        */
+       u_int16_t length_or_value;
+
+       /**
+        * Attribute value as chunk.
+        */
+       chunk_t value;
+};
+
+/**
+ * Encoding rules to parse or generate a configuration attribute.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_data_attribute_v1_t.
+ */
+encoding_rule_t data_attribute_v1_encodings[] = {
+       /* AF Flag */
+       { FLAG,                                         offsetof(private_data_attribute_v1_t, af_flag)},
+       /* type of the attribute as 15 bit unsigned integer */
+       { ATTRIBUTE_TYPE,                                       offsetof(private_data_attribute_v1_t, type)     },
+       /* Length of attribute value */
+       { ATTRIBUTE_LENGTH_OR_VALUE,    offsetof(private_data_attribute_v1_t, length_or_value)  },
+       /* Value of attribute if attribute format flag is zero */
+       { ATTRIBUTE_VALUE,      offsetof(private_data_attribute_v1_t, value)    }
+};
+
+/*
+                           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
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !R|         Attribute Type      !            Length             |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      |                                                               |
+      ~                             Value                             ~
+      |                                                               |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+METHOD(payload_t, verify, status_t,
+       private_data_attribute_v1_t *this)
+{
+       bool failed = FALSE;
+
+       if (this->length_or_value != this->value.len)
+       {
+               DBG1(DBG_ENC, "invalid attribute length");
+               return FAILED;
+       }
+
+       switch (this->type)
+       {
+                case INTERNAL_IP4_ADDRESS:
+                case INTERNAL_IP4_NETMASK:
+                case INTERNAL_IP4_DNS:
+                case INTERNAL_IP4_NBNS:
+                case INTERNAL_ADDRESS_EXPIRY:
+                case INTERNAL_IP4_DHCP:
+                       if (this->length_or_value != 0 && this->length_or_value != 4)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
+                case INTERNAL_IP4_SUBNET:
+                       if (this->length_or_value != 0 && this->length_or_value != 8)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
+                case INTERNAL_IP6_ADDRESS:
+                case INTERNAL_IP6_SUBNET:
+                       if (this->length_or_value != 0 && this->length_or_value != 17)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
+                case INTERNAL_IP6_DNS:
+                case INTERNAL_IP6_NBNS:
+                case INTERNAL_IP6_DHCP:
+                       if (this->length_or_value != 0 && this->length_or_value != 16)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
+                case SUPPORTED_ATTRIBUTES:
+                       if (this->length_or_value % 2)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
+                case APPLICATION_VERSION:
+                       /* any length acceptable */
+                       break;
+                default:
+                       DBG1(DBG_ENC, "unknown attribute type %N",
+                                configuration_attribute_type_names, this->type);
+                       break;
+       }
+
+       if (failed)
+       {
+               DBG1(DBG_ENC, "invalid attribute length %d for %N",
+                        this->length_or_value, configuration_attribute_type_names, this->type);
+               return FAILED;
+       }
+       return SUCCESS;
+}
+
+METHOD(payload_t, get_encoding_rules, void,
+       private_data_attribute_v1_t *this, encoding_rule_t **rules,
+       size_t *rule_count)
+{
+       *rules = data_attribute_v1_encodings;
+       *rule_count = countof(data_attribute_v1_encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+       private_data_attribute_v1_t *this)
+{
+       return 4;
+}
+
+METHOD(payload_t, get_type, payload_type_t,
+       private_data_attribute_v1_t *this)
+{
+       return DATA_ATTRIBUTE_V1;
+}
+
+METHOD(payload_t, get_next_type, payload_type_t,
+       private_data_attribute_v1_t *this)
+{
+       return NO_PAYLOAD;
+}
+
+METHOD(payload_t, set_next_type, void,
+       private_data_attribute_v1_t *this, payload_type_t type)
+{
+}
+
+METHOD(payload_t, get_length, size_t,
+       private_data_attribute_v1_t *this)
+{
+       return get_header_length(this) + this->value.len;
+}
+
+METHOD(data_attribute_v1_t, get_dattr_type, configuration_attribute_type_t,
+       private_data_attribute_v1_t *this)
+{
+       return this->type;
+}
+
+METHOD(data_attribute_v1_t, get_value, u_int16_t,
+       private_data_attribute_v1_t *this)
+{
+       return this->length_or_value;
+}
+
+METHOD(data_attribute_v1_t, get_value_chunk, chunk_t,
+       private_data_attribute_v1_t *this)
+{
+       return this->value;
+}
+
+METHOD2(payload_t, data_attribute_v1_t, destroy, void,
+       private_data_attribute_v1_t *this)
+{
+       free(this->value.ptr);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+data_attribute_v1_t *data_attribute_v1_create()
+{
+       private_data_attribute_v1_t *this;
+
+       INIT(this,
+               .public = {
+                       .payload_interface = {
+                               .verify = _verify,
+                               .get_encoding_rules = _get_encoding_rules,
+                               .get_length = _get_length,
+                               .get_next_type = _get_next_type,
+                               .set_next_type = _set_next_type,
+                               .get_type = _get_type,
+                               .destroy = _destroy,
+                       },
+                       .get_value_chunk = _get_value_chunk,
+                       .get_type = _get_dattr_type,
+                       .destroy = _destroy,
+               },
+       );
+       return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+data_attribute_v1_t *data_attribute_v1_create_value(
+                                                       configuration_attribute_type_t type, chunk_t value)
+{
+       private_data_attribute_v1_t *this;
+
+       this = (private_data_attribute_v1_t*)data_attribute_v1_create();
+       this->type = ((u_int16_t)type) & 0x7FFF;
+       this->value = chunk_clone(value);
+       this->length_or_value = value.len;
+       this->af_flag = FALSE;
+
+       return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+data_attribute_v1_t *data_attribute_v1_create_basic(
+                                                       configuration_attribute_type_t type, u_int16_t value)
+{
+       private_data_attribute_v1_t *this;
+
+       this = (private_data_attribute_v1_t*)data_attribute_v1_create();
+       this->type = ((u_int16_t)type) & 0x7FFF;
+       this->length_or_value = value;
+       this->af_flag = TRUE;
+
+       return &this->public;
+}
diff --git a/src/libcharon/encoding/payloads/data_attribute_v1.h b/src/libcharon/encoding/payloads/data_attribute_v1.h
new file mode 100644 (file)
index 0000000..568b314
--- /dev/null
@@ -0,0 +1,88 @@
+
+/**
+ * @defgroup data_attribute_v1 data_attribute_v1
+ * @{ @ingroup payloads
+ */
+
+#ifndef DATA_ATTRIBUTE_V1_H_
+#define DATA_ATTRIBUTE_V1_H_
+
+typedef struct data_attribute_v1_t data_attribute_v1_t;
+
+#include <library.h>
+#include <attributes/attributes.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Configuration attribute header length in bytes.
+ */
+#define DATA_ATTRIBUTE_V1_HEADER_LENGTH 4
+
+/**
+ * Class representing an IKEv1-Data Attribute.
+ *
+ * The DATA_ATTRIBUTE_V1 format is described in RFC section 3.15.1.
+ */
+struct data_attribute_v1_t {
+
+       /**
+        * Implements payload_t interface.
+        */
+       payload_t payload_interface;
+
+       /**
+        * Get the type of the attribute.
+        *
+        * @return              type of the data attribute
+        */
+       configuration_attribute_type_t (*get_type)(data_attribute_v1_t *this);
+
+       /**
+        * Returns the value of the attribute.
+        *
+        * @return              the basic internal value
+        */
+       u_int16_t (*get_value) (data_attribute_v1_t *this);
+
+       /**
+        * Returns the value of the attribute.
+        *
+        * @return              chunk_t pointing to the internal value
+        */
+       chunk_t (*get_value_chunk) (data_attribute_v1_t *this);
+
+       /**
+        * Destroys an configuration_attribute_t object.
+        */
+       void (*destroy) (data_attribute_v1_t *this);
+};
+
+/**
+ * Creates an empty data attribute.
+ *
+ * @return             created data attribute
+ */
+data_attribute_v1_t *data_attribute_v1_create();
+
+/**
+ * Creates a data attribute with type and value.
+ *
+ * @param type type of data attribute
+ * @param value        value, gets cloned
+ * @return             created data attribute
+ */
+data_attribute_v1_t *data_attribute_v1_create_value(
+                                                       configuration_attribute_type_t type, chunk_t value);
+
+
+/**
+ * Creates a data attribute with type and value.
+ *
+ * @param type type of data attribute
+ * @param value        value
+ * @return             created data attribute
+ */
+data_attribute_v1_t *data_attribute_v1_create_basic(
+                                                       configuration_attribute_type_t type, u_int16_t value);
+
+#endif /** DATA_ATTRIBUTE_V1_H_ @}*/