From: Tobias Brunner Date: Wed, 12 Dec 2012 17:16:58 +0000 (+0100) Subject: Payload added to handle IKE fragments X-Git-Tag: 5.0.2dr4~8^2~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8f0ab6dd366ff4d43f5372113035de46d376f784;p=thirdparty%2Fstrongswan.git Payload added to handle IKE fragments --- diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk index 9eb864f50a..b2d6c3128b 100644 --- a/src/libcharon/Android.mk +++ b/src/libcharon/Android.mk @@ -42,6 +42,7 @@ encoding/payloads/ts_payload.c encoding/payloads/ts_payload.h \ encoding/payloads/unknown_payload.c encoding/payloads/unknown_payload.h \ encoding/payloads/vendor_id_payload.c encoding/payloads/vendor_id_payload.h \ encoding/payloads/hash_payload.c encoding/payloads/hash_payload.h \ +encoding/payloads/fragment_payload.c encoding/payloads/fragment_payload.h \ kernel/kernel_handler.c kernel/kernel_handler.h \ network/receiver.c network/receiver.h network/sender.c network/sender.h \ network/socket.c network/socket.h \ diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 1ca4ddee7a..5203890ff8 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -40,6 +40,7 @@ encoding/payloads/ts_payload.c encoding/payloads/ts_payload.h \ encoding/payloads/unknown_payload.c encoding/payloads/unknown_payload.h \ encoding/payloads/vendor_id_payload.c encoding/payloads/vendor_id_payload.h \ encoding/payloads/hash_payload.c encoding/payloads/hash_payload.h \ +encoding/payloads/fragment_payload.c encoding/payloads/fragment_payload.h \ kernel/kernel_handler.c kernel/kernel_handler.h \ network/receiver.c network/receiver.h network/sender.c network/sender.h \ network/socket.c network/socket.h \ diff --git a/src/libcharon/encoding/payloads/fragment_payload.c b/src/libcharon/encoding/payloads/fragment_payload.c new file mode 100644 index 0000000000..2e7e061988 --- /dev/null +++ b/src/libcharon/encoding/payloads/fragment_payload.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "fragment_payload.h" + +#include + +/** Flag that is set in case the given fragment is the last for the message */ +#define LAST_FRAGMENT 0x01 + +typedef struct private_fragment_payload_t private_fragment_payload_t; + +/** + * Private data of an fragment_payload_t object. + */ +struct private_fragment_payload_t { + + /** + * Public fragment_payload_t interface. + */ + fragment_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Reserved byte + */ + u_int8_t reserved; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Fragment ID. + */ + u_int16_t fragment_id; + + /** + * Fragment number. + */ + u_int8_t fragment_number; + + /** + * Flags + */ + u_int8_t flags; + + /** + * The contained fragment data. + */ + chunk_t data; +}; + +/** + * Encoding rules for an IKEv1 fragment payload + */ +static encoding_rule_t encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_fragment_payload_t, next_payload) }, + { RESERVED_BYTE, offsetof(private_fragment_payload_t, reserved) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_fragment_payload_t, payload_length) }, + { U_INT_16, offsetof(private_fragment_payload_t, fragment_id) }, + { U_INT_8, offsetof(private_fragment_payload_t, fragment_number) }, + { U_INT_8, offsetof(private_fragment_payload_t, flags) }, + /* Fragment data is of variable size */ + { CHUNK_DATA, offsetof(private_fragment_payload_t, data) }, +}; + +/* + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Fragment ID ! Fragment Num ! Flags ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Fragment Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +METHOD(payload_t, verify, status_t, + private_fragment_payload_t *this) +{ + if (this->fragment_number == 0) + { + return FAILED; + } + return SUCCESS; +} + +METHOD(payload_t, get_encoding_rules, int, + private_fragment_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_fragment_payload_t *this) +{ + return 8; +} + +METHOD(payload_t, get_type, payload_type_t, + private_fragment_payload_t *this) +{ + return FRAGMENT_V1; +} + +METHOD(payload_t, get_next_type, payload_type_t, + private_fragment_payload_t *this) +{ + return this->next_payload; +} + +METHOD(payload_t, set_next_type, void, + private_fragment_payload_t *this, payload_type_t type) +{ + this->next_payload = type; +} + +METHOD(payload_t, get_length, size_t, + private_fragment_payload_t *this) +{ + return this->payload_length; +} + +METHOD(fragment_payload_t, get_id, u_int16_t, + private_fragment_payload_t *this) +{ + return this->fragment_id; +} + +METHOD(fragment_payload_t, get_number, u_int8_t, + private_fragment_payload_t *this) +{ + return this->fragment_number; +} + +METHOD(fragment_payload_t, is_last, bool, + private_fragment_payload_t *this) +{ + return (this->flags & LAST_FRAGMENT) == LAST_FRAGMENT; +} + +METHOD(fragment_payload_t, get_data, chunk_t, + private_fragment_payload_t *this) +{ + return this->data; +} + +METHOD2(payload_t, fragment_payload_t, destroy, void, + private_fragment_payload_t *this) +{ + free(this->data.ptr); + free(this); +} + +/* + * Described in header + */ +fragment_payload_t *fragment_payload_create() +{ + private_fragment_payload_t *this; + + INIT(this, + .public = { + .payload_interface = { + .verify = _verify, + .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, + .get_length = _get_length, + .get_next_type = _get_next_type, + .set_next_type = _set_next_type, + .get_type = _get_type, + .destroy = _destroy, + }, + .get_id = _get_id, + .get_number = _get_number, + .is_last = _is_last, + .get_data = _get_data, + .destroy = _destroy, + }, + .next_payload = NO_PAYLOAD, + ); + this->payload_length = get_header_length(this); + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/fragment_payload.h b/src/libcharon/encoding/payloads/fragment_payload.h new file mode 100644 index 0000000000..60358abb99 --- /dev/null +++ b/src/libcharon/encoding/payloads/fragment_payload.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup fragment_payload fragment_payload + * @{ @ingroup payloads + */ + +#ifndef FRAGMENT_PAYLOAD_H_ +#define FRAGMENT_PAYLOAD_H_ + +typedef struct fragment_payload_t fragment_payload_t; + +#include +#include + +/** + * Object representing an IKEv1 fragment payload. + */ +struct fragment_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the fragment ID. Identifies the fragments for a particular IKE + * message. + * + * @return fragment ID + */ + u_int16_t (*get_id)(fragment_payload_t *this); + + /** + * Get the fragment number. Defines the order of the fragments. + * + * @return fragment number + */ + u_int8_t (*get_number)(fragment_payload_t *this); + + /** + * Check if this is the last fragment. + * + * @return TRUE if this is the last fragment + */ + bool (*is_last)(fragment_payload_t *this); + + /** + * Get the fragment data. + * + * @return chunkt to internal fragment data + */ + chunk_t (*get_data)(fragment_payload_t *this); + + /** + * Destroys an fragment_payload_t object. + */ + void (*destroy)(fragment_payload_t *this); +}; + +/** + * Creates an empty fragment_payload_t object. + * + * @return fragment_payload_t object + */ +fragment_payload_t *fragment_payload_create(); + +#endif /** FRAGMENT_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 7ddd8e72d3..f9dd33edb6 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -36,6 +36,7 @@ #include #include #include +#include #include ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD, @@ -79,15 +80,17 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWORD_METH #ifdef ME ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD, "ID_PEER"); -ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, ID_PEER, +ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, FRAGMENT_V1, ID_PEER, "NAT_D_DRAFT_V1", - "NAT_OA_DRAFT_V1"); + "NAT_OA_DRAFT_V1", + "FRAGMENT"); #else -ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, GENERIC_SECURE_PASSWORD_METHOD, +ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, FRAGMENT_V1, GENERIC_SECURE_PASSWORD_METHOD, "NAT_D_DRAFT_V1", - "NAT_OA_DRAFT_V1"); + "NAT_OA_DRAFT_V1", + "FRAGMENT"); #endif /* ME */ -ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, NAT_OA_DRAFT_00_03_V1, +ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, FRAGMENT_V1, "HEADER", "PROPOSAL_SUBSTRUCTURE", "PROPOSAL_SUBSTRUCTURE_V1", @@ -143,15 +146,17 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWOR #ifdef ME ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD, "IDp"); -ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, ID_PEER, +ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, FRAGMENT_V1, ID_PEER, "NAT-D", - "NAT-OA"); + "NAT-OA", + "FRAG"); #else -ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, GENERIC_SECURE_PASSWORD_METHOD, +ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, FRAGMENT_V1, GENERIC_SECURE_PASSWORD_METHOD, "NAT-D", - "NAT-OA"); + "NAT-OA", + "FRAG"); #endif /* ME */ -ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, NAT_OA_DRAFT_00_03_V1, +ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, FRAGMENT_V1, "HDR", "PROP", "PROP", @@ -240,6 +245,8 @@ payload_t *payload_create(payload_type_t type) case ENCRYPTED: case ENCRYPTED_V1: return (payload_t*)encryption_payload_create(type); + case FRAGMENT_V1: + return (payload_t*)fragment_payload_create(); default: return (payload_t*)unknown_payload_create(type); } @@ -272,7 +279,7 @@ bool payload_is_known(payload_type_t type) return TRUE; } #endif - if (type >= NAT_D_DRAFT_00_03_V1 && type <= NAT_OA_DRAFT_00_03_V1) + if (type >= NAT_D_DRAFT_00_03_V1 && type <= FRAGMENT_V1) { return TRUE; } diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index d18bbea2da..0e8a9267bb 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -230,6 +230,11 @@ enum payload_type_t { */ NAT_OA_DRAFT_00_03_V1 = 131, + /** + * IKE fragment (proprietary IKEv1 extension) + */ + FRAGMENT_V1 = 132, + /** * Header has a value of PRIVATE USE space. *