diff options
-rw-r--r-- | src/libcharon/encoding/payloads/attribute_payload_v1.c | 231 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/attribute_payload_v1.h | 93 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/data_attribute_v1.c | 260 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/data_attribute_v1.h | 88 |
4 files changed, 672 insertions, 0 deletions
diff --git a/src/libcharon/encoding/payloads/attribute_payload_v1.c b/src/libcharon/encoding/payloads/attribute_payload_v1.c new file mode 100644 index 000000000..3aa0bc3a1 --- /dev/null +++ b/src/libcharon/encoding/payloads/attribute_payload_v1.c @@ -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 index 000000000..d59d9981e --- /dev/null +++ b/src/libcharon/encoding/payloads/attribute_payload_v1.h @@ -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 index 000000000..37f7c0072 --- /dev/null +++ b/src/libcharon/encoding/payloads/data_attribute_v1.c @@ -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 index 000000000..568b3143a --- /dev/null +++ b/src/libcharon/encoding/payloads/data_attribute_v1.h @@ -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_ @}*/ |