Merge branch 'ikev2-fragmentation'
This adds support for IKEv2 fragmentation as per RFC 7383.
This commit is contained in:
@@ -85,9 +85,10 @@ charon.flush_auth_cfg = no
|
||||
this might conflict with plugins that later need access to e.g. the used
|
||||
certificates.
|
||||
|
||||
charon.fragment_size = 512
|
||||
Maximum size (in bytes) of a sent fragment when using the proprietary IKEv1
|
||||
fragmentation extension.
|
||||
charon.fragment_size = 0
|
||||
Maximum size (complete IP datagram size in bytes) of a sent fragment when
|
||||
using the proprietary IKEv1 fragmentation extension (0 for address family
|
||||
specific default values). If specified this limit is used for IPv4 and IPv6.
|
||||
|
||||
charon.group
|
||||
Name of the group the daemon changes to after startup.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/encryption_payload.h>
|
||||
#include <encoding/payloads/encrypted_payload.h>
|
||||
|
||||
typedef struct private_ike_auth_fill_t private_ike_auth_fill_t;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ encoding/payloads/cp_payload.c encoding/payloads/cp_payload.h \
|
||||
encoding/payloads/delete_payload.c encoding/payloads/delete_payload.h \
|
||||
encoding/payloads/eap_payload.c encoding/payloads/eap_payload.h \
|
||||
encoding/payloads/encodings.c encoding/payloads/encodings.h \
|
||||
encoding/payloads/encryption_payload.c encoding/payloads/encryption_payload.h \
|
||||
encoding/payloads/encrypted_payload.c encoding/payloads/encrypted_payload.h \
|
||||
encoding/payloads/id_payload.c encoding/payloads/id_payload.h \
|
||||
encoding/payloads/ike_header.c encoding/payloads/ike_header.h \
|
||||
encoding/payloads/ke_payload.c encoding/payloads/ke_payload.h \
|
||||
|
||||
@@ -23,7 +23,8 @@ encoding/payloads/cp_payload.c encoding/payloads/cp_payload.h \
|
||||
encoding/payloads/delete_payload.c encoding/payloads/delete_payload.h \
|
||||
encoding/payloads/eap_payload.c encoding/payloads/eap_payload.h \
|
||||
encoding/payloads/encodings.c encoding/payloads/encodings.h \
|
||||
encoding/payloads/encryption_payload.c encoding/payloads/encryption_payload.h \
|
||||
encoding/payloads/encrypted_payload.c encoding/payloads/encrypted_payload.h \
|
||||
encoding/payloads/encrypted_fragment_payload.h \
|
||||
encoding/payloads/id_payload.c encoding/payloads/id_payload.h \
|
||||
encoding/payloads/ike_header.c encoding/payloads/ike_header.h \
|
||||
encoding/payloads/ke_payload.c encoding/payloads/ke_payload.h \
|
||||
|
||||
@@ -101,9 +101,11 @@ enum alert_t {
|
||||
/** received IKE message with invalid body, argument is message_t*,
|
||||
* followed by a status_t result returned by message_t.parse_body(). */
|
||||
ALERT_PARSE_ERROR_BODY,
|
||||
/** sending a retransmit for a message, argument is packet_t */
|
||||
/** sending a retransmit for a message, argument is packet_t, if the message
|
||||
* got fragmented only the first fragment is passed */
|
||||
ALERT_RETRANSMIT_SEND,
|
||||
/** sending retransmits timed out, argument is packet_t, if available */
|
||||
/** sending retransmits timed out, argument is packet_t, if available and if
|
||||
* the message got fragmented only the first fragment is passed */
|
||||
ALERT_RETRANSMIT_SEND_TIMEOUT,
|
||||
/** received a retransmit for a message, argument is message_t */
|
||||
ALERT_RETRANSMIT_RECEIVE,
|
||||
|
||||
+913
-180
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2011 Tobias Brunner
|
||||
* Copyright (C) 2006-2014 Tobias Brunner
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
@@ -39,7 +39,7 @@ typedef struct message_t message_t;
|
||||
*
|
||||
* The message handles parsing and generation of payloads
|
||||
* via parser_t/generator_t. Encryption is done transparently
|
||||
* via the encryption_payload_t. A set of rules for messages
|
||||
* via the encrypted_payload_t. A set of rules for messages
|
||||
* and payloads does check parsed messages.
|
||||
*/
|
||||
struct message_t {
|
||||
@@ -264,6 +264,53 @@ struct message_t {
|
||||
*/
|
||||
bool (*is_encoded)(message_t *this);
|
||||
|
||||
/**
|
||||
* Generates the message split into fragments of the given size (total IP
|
||||
* datagram length).
|
||||
*
|
||||
* @param keymat keymat to encrypt/sign message(s)
|
||||
* @param frag_len fragment length (maximum total IP datagram length), 0
|
||||
* for default value depending on address family
|
||||
* @param fragments receives an enumerator with generated packet_t*,
|
||||
* which are owned by the enumerator
|
||||
* @return
|
||||
* - SUCCESS if message could be fragmented
|
||||
* - FAILED if fragmentation failed
|
||||
* - and the possible return values of generate()
|
||||
*/
|
||||
status_t (*fragment)(message_t *this, keymat_t *keymat, size_t frag_len,
|
||||
enumerator_t **fragments);
|
||||
|
||||
/**
|
||||
* Check if the message has been encoded and fragmented using fragment(),
|
||||
* and whether there actually resulted fragments (if not is_encoded() will
|
||||
* be TRUE).
|
||||
*
|
||||
* The packets of individual fragments can be retrieved with
|
||||
* get_fragments().
|
||||
*
|
||||
* @return TRUE if message has been encoded and fragmented
|
||||
*/
|
||||
bool (*is_fragmented)(message_t *this);
|
||||
|
||||
/**
|
||||
* Add a fragment to the message if it was created with
|
||||
* message_create_defrag().
|
||||
*
|
||||
* Once the message is completed it should be processed like any other
|
||||
* inbound message.
|
||||
*
|
||||
* @param fragment fragment to add
|
||||
* @return
|
||||
* - SUCCESS if message was reassembled
|
||||
* - NEED_MORE if not all fragments have yet been received
|
||||
* - FAILED if reassembling failed
|
||||
* - INVALID_ARG if fragment is invalid for some reason
|
||||
* - INVALID_STATE if message was not created using
|
||||
* message_create_defrag()
|
||||
*/
|
||||
status_t (*add_fragment)(message_t *this, message_t *fragment);
|
||||
|
||||
/**
|
||||
* Gets the source host informations.
|
||||
*
|
||||
@@ -337,11 +384,11 @@ struct message_t {
|
||||
notify_payload_t* (*get_notify)(message_t *this, notify_type_t type);
|
||||
|
||||
/**
|
||||
* Returns a clone of the internal stored packet_t object.
|
||||
* Returns a clone of the internally stored packet_t object.
|
||||
*
|
||||
* @return packet_t object as clone of internal one
|
||||
*/
|
||||
packet_t * (*get_packet) (message_t *this);
|
||||
packet_t *(*get_packet) (message_t *this);
|
||||
|
||||
/**
|
||||
* Returns a chunk pointing to internal packet_t data.
|
||||
@@ -350,6 +397,13 @@ struct message_t {
|
||||
*/
|
||||
chunk_t (*get_packet_data) (message_t *this);
|
||||
|
||||
/**
|
||||
* Returns internally stored packet_t* objects for each fragment.
|
||||
*
|
||||
* @return enumerator internal packet_t* objects
|
||||
*/
|
||||
enumerator_t *(*get_fragments)(message_t *this);
|
||||
|
||||
/**
|
||||
* Destroys a message and all including objects.
|
||||
*/
|
||||
@@ -380,4 +434,14 @@ message_t *message_create_from_packet(packet_t *packet);
|
||||
*/
|
||||
message_t *message_create(int major, int minor);
|
||||
|
||||
/**
|
||||
* Creates a message_t object that is used to reassemble fragmented messages.
|
||||
*
|
||||
* Use add_fragment() to add fragments.
|
||||
*
|
||||
* @param fragment initial fragment (is not added)
|
||||
* @return message_t object, NULL if fragment is not actually one
|
||||
*/
|
||||
message_t *message_create_defrag(message_t *fragment);
|
||||
|
||||
#endif /** MESSAGE_H_ @}*/
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include <encoding/payloads/nonce_payload.h>
|
||||
#include <encoding/payloads/id_payload.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <encoding/payloads/encryption_payload.h>
|
||||
#include <encoding/payloads/encrypted_payload.h>
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/certreq_payload.h>
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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 encrypted_fragment_payload encrypted_fragment_payload
|
||||
* @{ @ingroup payloads
|
||||
*/
|
||||
|
||||
#ifndef ENCRYPTED_FRAGMENT_PAYLOAD_H_
|
||||
#define ENCRYPTED_FRAGMENT_PAYLOAD_H_
|
||||
|
||||
typedef struct encrypted_fragment_payload_t encrypted_fragment_payload_t;
|
||||
|
||||
#include <encoding/payloads/encrypted_payload.h>
|
||||
|
||||
/**
|
||||
* The Encrypted Fragment Payload as described in RFC 7383
|
||||
*
|
||||
* The implementation is located in encrypted_payload.c as it is very similar.
|
||||
*/
|
||||
struct encrypted_fragment_payload_t {
|
||||
|
||||
/**
|
||||
* Implements payload_t interface.
|
||||
*/
|
||||
encrypted_payload_t encrypted;
|
||||
|
||||
/**
|
||||
* Get the fragment number.
|
||||
*
|
||||
* @return fragment number
|
||||
*/
|
||||
u_int16_t (*get_fragment_number)(encrypted_fragment_payload_t *this);
|
||||
|
||||
/**
|
||||
* Get the total number of fragments.
|
||||
*
|
||||
* @return total number of fragments
|
||||
*/
|
||||
u_int16_t (*get_total_fragments)(encrypted_fragment_payload_t *this);
|
||||
|
||||
/**
|
||||
* Get the (decrypted) content of this payload.
|
||||
*
|
||||
* @return internal payload data
|
||||
*/
|
||||
chunk_t (*get_content)(encrypted_fragment_payload_t *this);
|
||||
|
||||
/**
|
||||
* Destroys an encrypted_fragment_payload_t object.
|
||||
*/
|
||||
void (*destroy)(encrypted_fragment_payload_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an empty encrypted_fragment_payload_t object.
|
||||
*
|
||||
* @return encrypted_fragment_payload_t object
|
||||
*/
|
||||
encrypted_fragment_payload_t *encrypted_fragment_payload_create();
|
||||
|
||||
/**
|
||||
* Creates an encrypted fragment payload from the given data.
|
||||
*
|
||||
* @param num fragment number (first one should be 1)
|
||||
* @param total total number of fragments
|
||||
* @param data fragment data (gets cloned)
|
||||
* @return encrypted_fragment_payload_t object
|
||||
*/
|
||||
encrypted_fragment_payload_t *encrypted_fragment_payload_create_from_data(
|
||||
u_int16_t num, u_int16_t total, chunk_t data);
|
||||
|
||||
#endif /** ENCRYPTED_FRAGMENT_PAYLOAD_H_ @}*/
|
||||
File diff suppressed because it is too large
Load Diff
+39
-18
@@ -1,4 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Tobias Brunner
|
||||
* Copyright (C) 2005-2010 Martin Willi
|
||||
* Copyright (C) 2010 revosec AG
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
@@ -16,23 +17,24 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup encryption_payload encryption_payload
|
||||
* @defgroup encrypted_payload encrypted_payload
|
||||
* @{ @ingroup payloads
|
||||
*/
|
||||
|
||||
#ifndef ENCRYPTION_PAYLOAD_H_
|
||||
#define ENCRYPTION_PAYLOAD_H_
|
||||
#ifndef ENCRYPTED_PAYLOAD_H_
|
||||
#define ENCRYPTED_PAYLOAD_H_
|
||||
|
||||
typedef struct encryption_payload_t encryption_payload_t;
|
||||
typedef struct encrypted_payload_t encrypted_payload_t;
|
||||
|
||||
#include <library.h>
|
||||
#include <crypto/aead.h>
|
||||
#include <encoding/payloads/payload.h>
|
||||
#include <encoding/generator.h>
|
||||
|
||||
/**
|
||||
* The encryption payload as described in RFC section 3.14.
|
||||
* The encrypted payload as described in RFC section 3.14.
|
||||
*/
|
||||
struct encryption_payload_t {
|
||||
struct encrypted_payload_t {
|
||||
|
||||
/**
|
||||
* Implements payload_t interface.
|
||||
@@ -44,14 +46,14 @@ struct encryption_payload_t {
|
||||
*
|
||||
* @return (expected) payload length
|
||||
*/
|
||||
size_t (*get_length)(encryption_payload_t *this);
|
||||
size_t (*get_length)(encrypted_payload_t *this);
|
||||
|
||||
/**
|
||||
* Adds a payload to this encryption payload.
|
||||
*
|
||||
* @param payload payload_t object to add
|
||||
*/
|
||||
void (*add_payload) (encryption_payload_t *this, payload_t *payload);
|
||||
void (*add_payload) (encrypted_payload_t *this, payload_t *payload);
|
||||
|
||||
/**
|
||||
* Remove the first payload in the list
|
||||
@@ -59,14 +61,22 @@ struct encryption_payload_t {
|
||||
* @param payload removed payload
|
||||
* @return payload, NULL if none left
|
||||
*/
|
||||
payload_t* (*remove_payload)(encryption_payload_t *this);
|
||||
payload_t* (*remove_payload)(encrypted_payload_t *this);
|
||||
|
||||
/**
|
||||
* Uses the given generator to generate the contained payloads.
|
||||
*
|
||||
* @param generator generator used to generate the contained payloads
|
||||
*/
|
||||
void (*generate_payloads)(encrypted_payload_t *this,
|
||||
generator_t *generator);
|
||||
|
||||
/**
|
||||
* Set the AEAD transform to use.
|
||||
*
|
||||
* @param aead aead transform to use
|
||||
*/
|
||||
void (*set_transform) (encryption_payload_t *this, aead_t *aead);
|
||||
void (*set_transform) (encrypted_payload_t *this, aead_t *aead);
|
||||
|
||||
/**
|
||||
* Generate, encrypt and sign contained payloads.
|
||||
@@ -78,7 +88,7 @@ struct encryption_payload_t {
|
||||
* - FAILED if encryption failed
|
||||
* - INVALID_STATE if aead not supplied, but needed
|
||||
*/
|
||||
status_t (*encrypt) (encryption_payload_t *this, u_int64_t mid,
|
||||
status_t (*encrypt) (encrypted_payload_t *this, u_int64_t mid,
|
||||
chunk_t assoc);
|
||||
|
||||
/**
|
||||
@@ -92,20 +102,31 @@ struct encryption_payload_t {
|
||||
* - FAILED if integrity check failed
|
||||
* - INVALID_STATE if aead not supplied, but needed
|
||||
*/
|
||||
status_t (*decrypt) (encryption_payload_t *this, chunk_t assoc);
|
||||
status_t (*decrypt) (encrypted_payload_t *this, chunk_t assoc);
|
||||
|
||||
/**
|
||||
* Destroys an encryption_payload_t object.
|
||||
* Destroys an encrypted_payload_t object.
|
||||
*/
|
||||
void (*destroy) (encryption_payload_t *this);
|
||||
void (*destroy) (encrypted_payload_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an empty encryption_payload_t object.
|
||||
* Creates an empty encrypted_payload_t object.
|
||||
*
|
||||
* @param type PLV2_ENCRYPTED or PLV1_ENCRYPTED
|
||||
* @return encryption_payload_t object
|
||||
* @return encrypted_payload_t object
|
||||
*/
|
||||
encryption_payload_t *encryption_payload_create(payload_type_t type);
|
||||
encrypted_payload_t *encrypted_payload_create(payload_type_t type);
|
||||
|
||||
#endif /** ENCRYPTION_PAYLOAD_H_ @}*/
|
||||
/**
|
||||
* Creates an encrypted payload with the given plain text data and next payload
|
||||
* type.
|
||||
*
|
||||
* @param next next payload type
|
||||
* @param plain plaintext data (gets adopted)
|
||||
* @return encrypted_payload_t object
|
||||
*/
|
||||
encrypted_payload_t *encrypted_payload_create_from_plain(payload_type_t next,
|
||||
chunk_t plain);
|
||||
|
||||
#endif /** ENCRYPTED_PAYLOAD_H_ @}*/
|
||||
@@ -1,635 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2010 Martin Willi
|
||||
* Copyright (C) 2010 revosec AG
|
||||
* Copyright (C) 2011 Tobias Brunner
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* 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 <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "encryption_payload.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/encodings.h>
|
||||
#include <collections/linked_list.h>
|
||||
#include <encoding/generator.h>
|
||||
#include <encoding/parser.h>
|
||||
|
||||
typedef struct private_encryption_payload_t private_encryption_payload_t;
|
||||
|
||||
/**
|
||||
* Private data of an encryption_payload_t' Object.
|
||||
*
|
||||
*/
|
||||
struct private_encryption_payload_t {
|
||||
|
||||
/**
|
||||
* Public encryption_payload_t interface.
|
||||
*/
|
||||
encryption_payload_t public;
|
||||
|
||||
/**
|
||||
* There is no next payload for an encryption payload,
|
||||
* since encryption payload MUST be the last one.
|
||||
* next_payload means here the first payload of the
|
||||
* contained, encrypted payload.
|
||||
*/
|
||||
u_int8_t next_payload;
|
||||
|
||||
/**
|
||||
* Flags, including reserved bits
|
||||
*/
|
||||
u_int8_t flags;
|
||||
|
||||
/**
|
||||
* Length of this payload
|
||||
*/
|
||||
u_int16_t payload_length;
|
||||
|
||||
/**
|
||||
* Chunk containing the IV, plain, padding and ICV.
|
||||
*/
|
||||
chunk_t encrypted;
|
||||
|
||||
/**
|
||||
* AEAD transform to use
|
||||
*/
|
||||
aead_t *aead;
|
||||
|
||||
/**
|
||||
* Contained payloads
|
||||
*/
|
||||
linked_list_t *payloads;
|
||||
|
||||
/**
|
||||
* Type of payload, PLV2_ENCRYPTED or PLV1_ENCRYPTED
|
||||
*/
|
||||
payload_type_t type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encoding rules to parse or generate a IKEv2-Encryption Payload.
|
||||
*
|
||||
* The defined offsets are the positions in a object of type
|
||||
* private_encryption_payload_t.
|
||||
*/
|
||||
static encoding_rule_t encodings_v2[] = {
|
||||
/* 1 Byte next payload type, stored in the field next_payload */
|
||||
{ U_INT_8, offsetof(private_encryption_payload_t, next_payload) },
|
||||
/* Critical and 7 reserved bits, all stored for reconstruction */
|
||||
{ U_INT_8, offsetof(private_encryption_payload_t, flags) },
|
||||
/* Length of the whole encryption payload*/
|
||||
{ PAYLOAD_LENGTH, offsetof(private_encryption_payload_t, payload_length) },
|
||||
/* encrypted data, stored in a chunk. contains iv, data, padding */
|
||||
{ CHUNK_DATA, offsetof(private_encryption_payload_t, encrypted) },
|
||||
};
|
||||
|
||||
/*
|
||||
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 !
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
! Initialization Vector !
|
||||
! (length is block size for encryption algorithm) !
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
! Encrypted IKE Payloads !
|
||||
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
! ! Padding (0-255 octets) !
|
||||
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||
! ! Pad Length !
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
~ Integrity Checksum Data ~
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encoding rules to parse or generate a complete encrypted IKEv1 message.
|
||||
*
|
||||
* The defined offsets are the positions in a object of type
|
||||
* private_encryption_payload_t.
|
||||
*/
|
||||
static encoding_rule_t encodings_v1[] = {
|
||||
/* encrypted data, stored in a chunk */
|
||||
{ ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) },
|
||||
};
|
||||
|
||||
/*
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
! Encrypted IKE Payloads !
|
||||
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
! ! Padding (0-255 octets) !
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
METHOD(payload_t, verify, status_t,
|
||||
private_encryption_payload_t *this)
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(payload_t, get_encoding_rules, int,
|
||||
private_encryption_payload_t *this, encoding_rule_t **rules)
|
||||
{
|
||||
if (this->type == PLV2_ENCRYPTED)
|
||||
{
|
||||
*rules = encodings_v2;
|
||||
return countof(encodings_v2);
|
||||
}
|
||||
*rules = encodings_v1;
|
||||
return countof(encodings_v1);
|
||||
}
|
||||
|
||||
METHOD(payload_t, get_header_length, int,
|
||||
private_encryption_payload_t *this)
|
||||
{
|
||||
if (this->type == PLV2_ENCRYPTED)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
METHOD(payload_t, get_type, payload_type_t,
|
||||
private_encryption_payload_t *this)
|
||||
{
|
||||
return this->type;
|
||||
}
|
||||
|
||||
METHOD(payload_t, get_next_type, payload_type_t,
|
||||
private_encryption_payload_t *this)
|
||||
{
|
||||
return this->next_payload;
|
||||
}
|
||||
|
||||
METHOD(payload_t, set_next_type, void,
|
||||
private_encryption_payload_t *this, payload_type_t type)
|
||||
{
|
||||
/* the next payload is set during add, still allow this for IKEv1 */
|
||||
this->next_payload = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the length of the whole payload
|
||||
*/
|
||||
static void compute_length(private_encryption_payload_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
payload_t *payload;
|
||||
size_t bs, length = 0;
|
||||
|
||||
if (this->encrypted.len)
|
||||
{
|
||||
length = this->encrypted.len;
|
||||
}
|
||||
else
|
||||
{
|
||||
enumerator = this->payloads->create_enumerator(this->payloads);
|
||||
while (enumerator->enumerate(enumerator, &payload))
|
||||
{
|
||||
length += payload->get_length(payload);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (this->aead)
|
||||
{
|
||||
/* append padding */
|
||||
bs = this->aead->get_block_size(this->aead);
|
||||
length += bs - (length % bs);
|
||||
/* add iv */
|
||||
length += this->aead->get_iv_size(this->aead);
|
||||
/* add icv */
|
||||
length += this->aead->get_icv_size(this->aead);
|
||||
}
|
||||
}
|
||||
length += get_header_length(this);
|
||||
this->payload_length = length;
|
||||
}
|
||||
|
||||
METHOD2(payload_t, encryption_payload_t, get_length, size_t,
|
||||
private_encryption_payload_t *this)
|
||||
{
|
||||
compute_length(this);
|
||||
return this->payload_length;
|
||||
}
|
||||
|
||||
METHOD(encryption_payload_t, add_payload, void,
|
||||
private_encryption_payload_t *this, payload_t *payload)
|
||||
{
|
||||
payload_t *last_payload;
|
||||
|
||||
if (this->payloads->get_count(this->payloads) > 0)
|
||||
{
|
||||
this->payloads->get_last(this->payloads, (void **)&last_payload);
|
||||
last_payload->set_next_type(last_payload, payload->get_type(payload));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->next_payload = payload->get_type(payload);
|
||||
}
|
||||
payload->set_next_type(payload, PL_NONE);
|
||||
this->payloads->insert_last(this->payloads, payload);
|
||||
compute_length(this);
|
||||
}
|
||||
|
||||
METHOD(encryption_payload_t, remove_payload, payload_t *,
|
||||
private_encryption_payload_t *this)
|
||||
{
|
||||
payload_t *payload;
|
||||
|
||||
if (this->payloads->remove_first(this->payloads,
|
||||
(void**)&payload) == SUCCESS)
|
||||
{
|
||||
return payload;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate payload before encryption
|
||||
*/
|
||||
static chunk_t generate(private_encryption_payload_t *this,
|
||||
generator_t *generator)
|
||||
{
|
||||
payload_t *current, *next;
|
||||
enumerator_t *enumerator;
|
||||
u_int32_t *lenpos;
|
||||
chunk_t chunk = chunk_empty;
|
||||
|
||||
enumerator = this->payloads->create_enumerator(this->payloads);
|
||||
if (enumerator->enumerate(enumerator, ¤t))
|
||||
{
|
||||
this->next_payload = current->get_type(current);
|
||||
|
||||
while (enumerator->enumerate(enumerator, &next))
|
||||
{
|
||||
current->set_next_type(current, next->get_type(next));
|
||||
generator->generate_payload(generator, current);
|
||||
current = next;
|
||||
}
|
||||
current->set_next_type(current, PL_NONE);
|
||||
generator->generate_payload(generator, current);
|
||||
|
||||
chunk = generator->get_chunk(generator, &lenpos);
|
||||
DBG2(DBG_ENC, "generated content in encryption payload");
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the encryption payload header to the associated data
|
||||
*/
|
||||
static chunk_t append_header(private_encryption_payload_t *this, chunk_t assoc)
|
||||
{
|
||||
struct {
|
||||
u_int8_t next_payload;
|
||||
u_int8_t flags;
|
||||
u_int16_t length;
|
||||
} __attribute__((packed)) header = {
|
||||
.next_payload = this->next_payload,
|
||||
.flags = this->flags,
|
||||
.length = htons(get_length(this)),
|
||||
};
|
||||
return chunk_cat("cc", assoc, chunk_from_thing(header));
|
||||
}
|
||||
|
||||
METHOD(encryption_payload_t, encrypt, status_t,
|
||||
private_encryption_payload_t *this, u_int64_t mid, chunk_t assoc)
|
||||
{
|
||||
chunk_t iv, plain, padding, icv, crypt;
|
||||
generator_t *generator;
|
||||
iv_gen_t *iv_gen;
|
||||
rng_t *rng;
|
||||
size_t bs;
|
||||
|
||||
if (this->aead == NULL)
|
||||
{
|
||||
DBG1(DBG_ENC, "encrypting encryption payload failed, transform missing");
|
||||
return INVALID_STATE;
|
||||
}
|
||||
|
||||
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||
if (!rng)
|
||||
{
|
||||
DBG1(DBG_ENC, "encrypting encryption payload failed, no RNG found");
|
||||
return NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
iv_gen = this->aead->get_iv_gen(this->aead);
|
||||
if (!iv_gen)
|
||||
{
|
||||
DBG1(DBG_ENC, "encrypting encryption payload failed, no IV generator");
|
||||
return NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
assoc = append_header(this, assoc);
|
||||
|
||||
generator = generator_create();
|
||||
plain = generate(this, generator);
|
||||
bs = this->aead->get_block_size(this->aead);
|
||||
/* we need at least one byte padding to store the padding length */
|
||||
padding.len = bs - (plain.len % bs);
|
||||
iv.len = this->aead->get_iv_size(this->aead);
|
||||
icv.len = this->aead->get_icv_size(this->aead);
|
||||
|
||||
/* prepare data to authenticate-encrypt:
|
||||
* | IV | plain | padding | ICV |
|
||||
* \____crypt______/ ^
|
||||
* | /
|
||||
* v /
|
||||
* assoc -> + ------->/
|
||||
*/
|
||||
free(this->encrypted.ptr);
|
||||
this->encrypted = chunk_alloc(iv.len + plain.len + padding.len + icv.len);
|
||||
iv.ptr = this->encrypted.ptr;
|
||||
memcpy(iv.ptr + iv.len, plain.ptr, plain.len);
|
||||
plain.ptr = iv.ptr + iv.len;
|
||||
padding.ptr = plain.ptr + plain.len;
|
||||
icv.ptr = padding.ptr + padding.len;
|
||||
crypt = chunk_create(plain.ptr, plain.len + padding.len);
|
||||
generator->destroy(generator);
|
||||
|
||||
if (!iv_gen->get_iv(iv_gen, mid, iv.len, iv.ptr) ||
|
||||
!rng->get_bytes(rng, padding.len - 1, padding.ptr))
|
||||
{
|
||||
DBG1(DBG_ENC, "encrypting encryption payload failed, no IV or padding");
|
||||
rng->destroy(rng);
|
||||
free(assoc.ptr);
|
||||
return FAILED;
|
||||
}
|
||||
padding.ptr[padding.len - 1] = padding.len - 1;
|
||||
rng->destroy(rng);
|
||||
|
||||
DBG3(DBG_ENC, "encryption payload encryption:");
|
||||
DBG3(DBG_ENC, "IV %B", &iv);
|
||||
DBG3(DBG_ENC, "plain %B", &plain);
|
||||
DBG3(DBG_ENC, "padding %B", &padding);
|
||||
DBG3(DBG_ENC, "assoc %B", &assoc);
|
||||
|
||||
if (!this->aead->encrypt(this->aead, crypt, assoc, iv, NULL))
|
||||
{
|
||||
free(assoc.ptr);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
DBG3(DBG_ENC, "encrypted %B", &crypt);
|
||||
DBG3(DBG_ENC, "ICV %B", &icv);
|
||||
|
||||
free(assoc.ptr);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(encryption_payload_t, encrypt_v1, status_t,
|
||||
private_encryption_payload_t *this, u_int64_t mid, chunk_t iv)
|
||||
{
|
||||
generator_t *generator;
|
||||
chunk_t plain, padding;
|
||||
size_t bs;
|
||||
|
||||
if (this->aead == NULL)
|
||||
{
|
||||
DBG1(DBG_ENC, "encryption failed, transform missing");
|
||||
return INVALID_STATE;
|
||||
}
|
||||
|
||||
generator = generator_create();
|
||||
plain = generate(this, generator);
|
||||
bs = this->aead->get_block_size(this->aead);
|
||||
padding.len = bs - (plain.len % bs);
|
||||
|
||||
/* prepare data to encrypt:
|
||||
* | plain | padding | */
|
||||
free(this->encrypted.ptr);
|
||||
this->encrypted = chunk_alloc(plain.len + padding.len);
|
||||
memcpy(this->encrypted.ptr, plain.ptr, plain.len);
|
||||
plain.ptr = this->encrypted.ptr;
|
||||
padding.ptr = plain.ptr + plain.len;
|
||||
memset(padding.ptr, 0, padding.len);
|
||||
generator->destroy(generator);
|
||||
|
||||
DBG3(DBG_ENC, "encrypting payloads:");
|
||||
DBG3(DBG_ENC, "IV %B", &iv);
|
||||
DBG3(DBG_ENC, "plain %B", &plain);
|
||||
DBG3(DBG_ENC, "padding %B", &padding);
|
||||
|
||||
if (!this->aead->encrypt(this->aead, this->encrypted, chunk_empty, iv, NULL))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
DBG3(DBG_ENC, "encrypted %B", &this->encrypted);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the payloads after decryption.
|
||||
*/
|
||||
static status_t parse(private_encryption_payload_t *this, chunk_t plain)
|
||||
{
|
||||
parser_t *parser;
|
||||
payload_type_t type;
|
||||
|
||||
parser = parser_create(plain);
|
||||
type = this->next_payload;
|
||||
while (type != PL_NONE)
|
||||
{
|
||||
payload_t *payload;
|
||||
|
||||
if (plain.len < 4 || untoh16(plain.ptr + 2) > plain.len)
|
||||
{
|
||||
DBG1(DBG_ENC, "invalid %N payload length, decryption failed?",
|
||||
payload_type_names, type);
|
||||
parser->destroy(parser);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
if (parser->parse_payload(parser, type, &payload) != SUCCESS)
|
||||
{
|
||||
parser->destroy(parser);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
if (payload->verify(payload) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_ENC, "%N verification failed",
|
||||
payload_type_names, payload->get_type(payload));
|
||||
payload->destroy(payload);
|
||||
parser->destroy(parser);
|
||||
return VERIFY_ERROR;
|
||||
}
|
||||
type = payload->get_next_type(payload);
|
||||
this->payloads->insert_last(this->payloads, payload);
|
||||
}
|
||||
parser->destroy(parser);
|
||||
DBG2(DBG_ENC, "parsed content of encryption payload");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(encryption_payload_t, decrypt, status_t,
|
||||
private_encryption_payload_t *this, chunk_t assoc)
|
||||
{
|
||||
chunk_t iv, plain, padding, icv, crypt;
|
||||
size_t bs;
|
||||
|
||||
if (this->aead == NULL)
|
||||
{
|
||||
DBG1(DBG_ENC, "decrypting encryption payload failed, transform missing");
|
||||
return INVALID_STATE;
|
||||
}
|
||||
|
||||
/* prepare data to authenticate-decrypt:
|
||||
* | IV | plain | padding | ICV |
|
||||
* \____crypt______/ ^
|
||||
* | /
|
||||
* v /
|
||||
* assoc -> + ------->/
|
||||
*/
|
||||
|
||||
bs = this->aead->get_block_size(this->aead);
|
||||
iv.len = this->aead->get_iv_size(this->aead);
|
||||
iv.ptr = this->encrypted.ptr;
|
||||
icv.len = this->aead->get_icv_size(this->aead);
|
||||
icv.ptr = this->encrypted.ptr + this->encrypted.len - icv.len;
|
||||
crypt.ptr = iv.ptr + iv.len;
|
||||
crypt.len = this->encrypted.len - iv.len;
|
||||
|
||||
if (iv.len + icv.len > this->encrypted.len ||
|
||||
(crypt.len - icv.len) % bs)
|
||||
{
|
||||
DBG1(DBG_ENC, "decrypting encryption payload failed, invalid length");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
assoc = append_header(this, assoc);
|
||||
|
||||
DBG3(DBG_ENC, "encryption payload decryption:");
|
||||
DBG3(DBG_ENC, "IV %B", &iv);
|
||||
DBG3(DBG_ENC, "encrypted %B", &crypt);
|
||||
DBG3(DBG_ENC, "ICV %B", &icv);
|
||||
DBG3(DBG_ENC, "assoc %B", &assoc);
|
||||
|
||||
if (!this->aead->decrypt(this->aead, crypt, assoc, iv, NULL))
|
||||
{
|
||||
DBG1(DBG_ENC, "verifying encryption payload integrity failed");
|
||||
free(assoc.ptr);
|
||||
return FAILED;
|
||||
}
|
||||
free(assoc.ptr);
|
||||
|
||||
plain = chunk_create(crypt.ptr, crypt.len - icv.len);
|
||||
padding.len = plain.ptr[plain.len - 1] + 1;
|
||||
if (padding.len > plain.len)
|
||||
{
|
||||
DBG1(DBG_ENC, "decrypting encryption payload failed, "
|
||||
"padding invalid %B", &crypt);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
plain.len -= padding.len;
|
||||
padding.ptr = plain.ptr + plain.len;
|
||||
|
||||
DBG3(DBG_ENC, "plain %B", &plain);
|
||||
DBG3(DBG_ENC, "padding %B", &padding);
|
||||
|
||||
return parse(this, plain);
|
||||
}
|
||||
|
||||
METHOD(encryption_payload_t, decrypt_v1, status_t,
|
||||
private_encryption_payload_t *this, chunk_t iv)
|
||||
{
|
||||
if (this->aead == NULL)
|
||||
{
|
||||
DBG1(DBG_ENC, "decryption failed, transform missing");
|
||||
return INVALID_STATE;
|
||||
}
|
||||
|
||||
/* data must be a multiple of block size */
|
||||
if (iv.len != this->aead->get_block_size(this->aead) ||
|
||||
this->encrypted.len < iv.len || this->encrypted.len % iv.len)
|
||||
{
|
||||
DBG1(DBG_ENC, "decryption failed, invalid length");
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
DBG3(DBG_ENC, "decrypting payloads:");
|
||||
DBG3(DBG_ENC, "encrypted %B", &this->encrypted);
|
||||
|
||||
if (!this->aead->decrypt(this->aead, this->encrypted, chunk_empty, iv, NULL))
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
DBG3(DBG_ENC, "plain %B", &this->encrypted);
|
||||
|
||||
return parse(this, this->encrypted);
|
||||
}
|
||||
|
||||
METHOD(encryption_payload_t, set_transform, void,
|
||||
private_encryption_payload_t *this, aead_t* aead)
|
||||
{
|
||||
this->aead = aead;
|
||||
}
|
||||
|
||||
METHOD2(payload_t, encryption_payload_t, destroy, void,
|
||||
private_encryption_payload_t *this)
|
||||
{
|
||||
this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy));
|
||||
free(this->encrypted.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header
|
||||
*/
|
||||
encryption_payload_t *encryption_payload_create(payload_type_t type)
|
||||
{
|
||||
private_encryption_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_length = _get_length,
|
||||
.add_payload = _add_payload,
|
||||
.remove_payload = _remove_payload,
|
||||
.set_transform = _set_transform,
|
||||
.encrypt = _encrypt,
|
||||
.decrypt = _decrypt,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.next_payload = PL_NONE,
|
||||
.payloads = linked_list_create(),
|
||||
.type = type,
|
||||
);
|
||||
this->payload_length = get_header_length(this);
|
||||
|
||||
if (type == PLV1_ENCRYPTED)
|
||||
{
|
||||
this->public.encrypt = _encrypt_v1;
|
||||
this->public.decrypt = _decrypt_v1;
|
||||
}
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ ENUM_NEXT(notify_type_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, CHILD_SA_NOT_
|
||||
"ME_CONNECT_FAILED");
|
||||
ENUM_NEXT(notify_type_names, MS_NOTIFY_STATUS, MS_NOTIFY_STATUS, ME_CONNECT_FAILED,
|
||||
"MS_NOTIFY_STATUS");
|
||||
ENUM_NEXT(notify_type_names, INITIAL_CONTACT, IFOM_CAPABILITY, MS_NOTIFY_STATUS,
|
||||
ENUM_NEXT(notify_type_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_NOTIFY_STATUS,
|
||||
"INITIAL_CONTACT",
|
||||
"SET_WINDOW_SIZE",
|
||||
"ADDITIONAL_TS_POSSIBLE",
|
||||
@@ -110,8 +110,10 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, IFOM_CAPABILITY, MS_NOTIFY_STATUS,
|
||||
"PSK_PERSIST",
|
||||
"PSK_CONFIRM",
|
||||
"ERX_SUPPORTED",
|
||||
"IFOM_CAPABILITY");
|
||||
ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, IFOM_CAPABILITY,
|
||||
"IFOM_CAPABILITY",
|
||||
"SENDER_REQUEST_ID",
|
||||
"FRAGMENTATION_SUPPORTED");
|
||||
ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, FRAGMENTATION_SUPPORTED,
|
||||
"INITIAL_CONTACT");
|
||||
ENUM_NEXT(notify_type_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1,
|
||||
"DPD_R_U_THERE",
|
||||
@@ -128,7 +130,7 @@ ENUM_NEXT(notify_type_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE,
|
||||
"ME_CONNECTKEY",
|
||||
"ME_CONNECTAUTH",
|
||||
"ME_RESPONSE",
|
||||
"RADIUS_ATTRIBUTE",);
|
||||
"RADIUS_ATTRIBUTE");
|
||||
ENUM_END(notify_type_names, RADIUS_ATTRIBUTE);
|
||||
|
||||
|
||||
@@ -172,7 +174,7 @@ ENUM_NEXT(notify_type_short_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, CHILD_S
|
||||
"ME_CONN_FAIL");
|
||||
ENUM_NEXT(notify_type_short_names, MS_NOTIFY_STATUS, MS_NOTIFY_STATUS, ME_CONNECT_FAILED,
|
||||
"MS_STATUS");
|
||||
ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, IFOM_CAPABILITY, MS_NOTIFY_STATUS,
|
||||
ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_NOTIFY_STATUS,
|
||||
"INIT_CONTACT",
|
||||
"SET_WINSIZE",
|
||||
"ADD_TS_POSS",
|
||||
@@ -217,8 +219,10 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, IFOM_CAPABILITY, MS_NOTIFY_S
|
||||
"PSK_PST",
|
||||
"PSK_CFM",
|
||||
"ERX_SUP",
|
||||
"IFOM_CAP");
|
||||
ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, IFOM_CAPABILITY,
|
||||
"IFOM_CAP",
|
||||
"SENDER_REQ_ID",
|
||||
"FRAG_SUP");
|
||||
ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, FRAGMENTATION_SUPPORTED,
|
||||
"INITIAL_CONTACT");
|
||||
ENUM_NEXT(notify_type_short_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1,
|
||||
"DPD",
|
||||
|
||||
@@ -147,6 +147,10 @@ enum notify_type_t {
|
||||
ERX_SUPPORTED = 16427,
|
||||
/* IFOM capability, 3GPP TS 24.303, annex B.2 */
|
||||
IFOM_CAPABILITY = 16428,
|
||||
/* SENDER_REQUEST_ID (draft-yeung-g-ikev2) */
|
||||
SENDER_REQUEST_ID = 16429,
|
||||
/* IKEv2 fragmentation supported, RFC 7383 */
|
||||
FRAGMENTATION_SUPPORTED = 16430,
|
||||
/* IKEv1 initial contact */
|
||||
INITIAL_CONTACT_IKEV1 = 24578,
|
||||
/* IKEv1 DPD */
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
#include <encoding/payloads/auth_payload.h>
|
||||
#include <encoding/payloads/cert_payload.h>
|
||||
#include <encoding/payloads/certreq_payload.h>
|
||||
#include <encoding/payloads/encryption_payload.h>
|
||||
#include <encoding/payloads/encrypted_payload.h>
|
||||
#include <encoding/payloads/encrypted_fragment_payload.h>
|
||||
#include <encoding/payloads/ts_payload.h>
|
||||
#include <encoding/payloads/delete_payload.h>
|
||||
#include <encoding/payloads/vendor_id_payload.h>
|
||||
@@ -59,7 +60,7 @@ ENUM_NEXT(payload_type_names, PLV1_SECURITY_ASSOCIATION, PLV1_CONFIGURATION, PL_
|
||||
ENUM_NEXT(payload_type_names, PLV1_NAT_D, PLV1_NAT_OA, PLV1_CONFIGURATION,
|
||||
"NAT_D_V1",
|
||||
"NAT_OA_V1");
|
||||
ENUM_NEXT(payload_type_names, PLV2_SECURITY_ASSOCIATION, PLV2_GSPM, PLV1_NAT_OA,
|
||||
ENUM_NEXT(payload_type_names, PLV2_SECURITY_ASSOCIATION, PLV2_FRAGMENT, PLV1_NAT_OA,
|
||||
"SECURITY_ASSOCIATION",
|
||||
"KEY_EXCHANGE",
|
||||
"ID_INITIATOR",
|
||||
@@ -76,16 +77,20 @@ ENUM_NEXT(payload_type_names, PLV2_SECURITY_ASSOCIATION, PLV2_GSPM, PLV1_NAT_OA,
|
||||
"ENCRYPTED",
|
||||
"CONFIGURATION",
|
||||
"EAP",
|
||||
"GSPM");
|
||||
"GSPM",
|
||||
"GROUP_ID",
|
||||
"GROUP_SECURITY_ASSOCIATION",
|
||||
"KEY_DOWNLOAD",
|
||||
"ENCRYPTED_FRAGMENT");
|
||||
#ifdef ME
|
||||
ENUM_NEXT(payload_type_names, PLV2_ID_PEER, PLV2_ID_PEER, PLV2_GSPM,
|
||||
ENUM_NEXT(payload_type_names, PLV2_ID_PEER, PLV2_ID_PEER, PLV2_FRAGMENT,
|
||||
"ID_PEER");
|
||||
ENUM_NEXT(payload_type_names, PLV1_NAT_D_DRAFT_00_03, PLV1_FRAGMENT, PLV2_ID_PEER,
|
||||
"NAT_D_DRAFT_V1",
|
||||
"NAT_OA_DRAFT_V1",
|
||||
"FRAGMENT");
|
||||
#else
|
||||
ENUM_NEXT(payload_type_names, PLV1_NAT_D_DRAFT_00_03, PLV1_FRAGMENT, PLV2_GSPM,
|
||||
ENUM_NEXT(payload_type_names, PLV1_NAT_D_DRAFT_00_03, PLV1_FRAGMENT, PLV2_FRAGMENT,
|
||||
"NAT_D_DRAFT_V1",
|
||||
"NAT_OA_DRAFT_V1",
|
||||
"FRAGMENT");
|
||||
@@ -125,7 +130,7 @@ ENUM_NEXT(payload_type_short_names, PLV1_SECURITY_ASSOCIATION, PLV1_CONFIGURATIO
|
||||
ENUM_NEXT(payload_type_short_names, PLV1_NAT_D, PLV1_NAT_OA, PLV1_CONFIGURATION,
|
||||
"NAT-D",
|
||||
"NAT-OA");
|
||||
ENUM_NEXT(payload_type_short_names, PLV2_SECURITY_ASSOCIATION, PLV2_GSPM, PLV1_NAT_OA,
|
||||
ENUM_NEXT(payload_type_short_names, PLV2_SECURITY_ASSOCIATION, PLV2_FRAGMENT, PLV1_NAT_OA,
|
||||
"SA",
|
||||
"KE",
|
||||
"IDi",
|
||||
@@ -142,16 +147,20 @@ ENUM_NEXT(payload_type_short_names, PLV2_SECURITY_ASSOCIATION, PLV2_GSPM, PLV1_N
|
||||
"E",
|
||||
"CP",
|
||||
"EAP",
|
||||
"GSPM");
|
||||
"GSPM",
|
||||
"IDg",
|
||||
"GSA",
|
||||
"KD",
|
||||
"EF");
|
||||
#ifdef ME
|
||||
ENUM_NEXT(payload_type_short_names, PLV2_ID_PEER, PLV2_ID_PEER, PLV2_GSPM,
|
||||
ENUM_NEXT(payload_type_short_names, PLV2_ID_PEER, PLV2_ID_PEER, PLV2_FRAGMENT,
|
||||
"IDp");
|
||||
ENUM_NEXT(payload_type_short_names, PLV1_NAT_D_DRAFT_00_03, PLV1_FRAGMENT, PLV2_ID_PEER,
|
||||
"NAT-D",
|
||||
"NAT-OA",
|
||||
"FRAG");
|
||||
#else
|
||||
ENUM_NEXT(payload_type_short_names, PLV1_NAT_D_DRAFT_00_03, PLV1_FRAGMENT, PLV2_GSPM,
|
||||
ENUM_NEXT(payload_type_short_names, PLV1_NAT_D_DRAFT_00_03, PLV1_FRAGMENT, PLV2_FRAGMENT,
|
||||
"NAT-D",
|
||||
"NAT-OA",
|
||||
"FRAG");
|
||||
@@ -244,9 +253,11 @@ payload_t *payload_create(payload_type_t type)
|
||||
return (payload_t*)eap_payload_create();
|
||||
case PLV2_ENCRYPTED:
|
||||
case PLV1_ENCRYPTED:
|
||||
return (payload_t*)encryption_payload_create(type);
|
||||
return (payload_t*)encrypted_payload_create(type);
|
||||
case PLV1_FRAGMENT:
|
||||
return (payload_t*)fragment_payload_create();
|
||||
case PLV2_FRAGMENT:
|
||||
return (payload_t*)encrypted_fragment_payload_create();
|
||||
default:
|
||||
return (payload_t*)unknown_payload_create(type);
|
||||
}
|
||||
@@ -261,10 +272,6 @@ bool payload_is_known(payload_type_t type)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (type >= PLV2_SECURITY_ASSOCIATION && type <= PLV2_EAP)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (type >= PLV1_SECURITY_ASSOCIATION && type <= PLV1_CONFIGURATION)
|
||||
{
|
||||
return TRUE;
|
||||
@@ -273,6 +280,14 @@ bool payload_is_known(payload_type_t type)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (type >= PLV2_SECURITY_ASSOCIATION && type <= PLV2_EAP)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
if (type == PLV2_FRAGMENT)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
#ifdef ME
|
||||
if (type == PLV2_ID_PEER)
|
||||
{
|
||||
|
||||
@@ -193,7 +193,7 @@ enum payload_type_t {
|
||||
PLV2_TS_RESPONDER = 45,
|
||||
|
||||
/**
|
||||
* Encryption payload, contains other payloads (E).
|
||||
* Encrypted payload, contains other payloads (E).
|
||||
*/
|
||||
PLV2_ENCRYPTED = 46,
|
||||
|
||||
@@ -212,6 +212,26 @@ enum payload_type_t {
|
||||
*/
|
||||
PLV2_GSPM = 49,
|
||||
|
||||
/**
|
||||
* Group Identification (draft-yeung-g-ikev2)
|
||||
*/
|
||||
PLV2_IDG = 50,
|
||||
|
||||
/**
|
||||
* Group Security Association (draft-yeung-g-ikev2)
|
||||
*/
|
||||
PLV2_GSA = 51,
|
||||
|
||||
/**
|
||||
* Key Download (draft-yeung-g-ikev2)
|
||||
*/
|
||||
PLV2_KD = 52,
|
||||
|
||||
/**
|
||||
* Encrypted fragment payload (SKF), RFC 7383
|
||||
*/
|
||||
PLV2_FRAGMENT = 53,
|
||||
|
||||
#ifdef ME
|
||||
/**
|
||||
* Identification payload for peers has a value from
|
||||
@@ -231,7 +251,7 @@ enum payload_type_t {
|
||||
PLV1_NAT_OA_DRAFT_00_03 = 131,
|
||||
|
||||
/**
|
||||
* IKE fragment (proprietary IKEv1 extension)
|
||||
* IKEv1 fragment (proprietary IKEv1 extension)
|
||||
*/
|
||||
PLV1_FRAGMENT = 132,
|
||||
|
||||
|
||||
@@ -45,9 +45,6 @@
|
||||
#include <daemon.h>
|
||||
#include <threading/thread.h>
|
||||
|
||||
/* Maximum size of a packet */
|
||||
#define MAX_PACKET 10000
|
||||
|
||||
/* these are not defined on some platforms */
|
||||
#ifndef SOL_IP
|
||||
#define SOL_IP IPPROTO_IP
|
||||
@@ -739,7 +736,7 @@ socket_default_socket_t *socket_default_socket_create()
|
||||
.natt = lib->settings->get_int(lib->settings,
|
||||
"%s.port_nat_t", CHARON_NATT_PORT, lib->ns),
|
||||
.max_packet = lib->settings->get_int(lib->settings,
|
||||
"%s.max_packet", MAX_PACKET, lib->ns),
|
||||
"%s.max_packet", PACKET_MAX_DEFAULT, lib->ns),
|
||||
.set_source = lib->settings->get_bool(lib->settings,
|
||||
"%s.plugins.socket-default.set_source", TRUE,
|
||||
lib->ns),
|
||||
|
||||
@@ -42,9 +42,6 @@
|
||||
#include <threading/rwlock.h>
|
||||
#include <collections/hashtable.h>
|
||||
|
||||
/* Maximum size of a packet */
|
||||
#define MAX_PACKET 10000
|
||||
|
||||
/* these are not defined on some platforms */
|
||||
#ifndef SOL_IP
|
||||
#define SOL_IP IPPROTO_IP
|
||||
@@ -668,7 +665,7 @@ socket_dynamic_socket_t *socket_dynamic_socket_create()
|
||||
},
|
||||
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
||||
.max_packet = lib->settings->get_int(lib->settings,
|
||||
"%s.max_packet", MAX_PACKET, lib->ns),
|
||||
"%s.max_packet", PACKET_MAX_DEFAULT, lib->ns),
|
||||
);
|
||||
|
||||
if (pipe(this->notify) != 0)
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
|
||||
#include <mswsock.h>
|
||||
|
||||
/* Maximum size of a packet */
|
||||
#define MAX_PACKET 10000
|
||||
|
||||
/* number of sockets in use */
|
||||
#define SOCKET_COUNT 2
|
||||
|
||||
@@ -458,7 +455,7 @@ socket_win_socket_t *socket_win_socket_create()
|
||||
"%s.port_nat_t", CHARON_NATT_PORT, lib->ns),
|
||||
},
|
||||
.max_packet = lib->settings->get_int(lib->settings,
|
||||
"%s.max_packet", MAX_PACKET, lib->ns),
|
||||
"%s.max_packet", PACKET_MAX_DEFAULT, lib->ns),
|
||||
);
|
||||
|
||||
for (i = 0; i < SOCKET_COUNT; i++)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2013 Tobias Brunner
|
||||
* Copyright (C) 2006-2014 Tobias Brunner
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
@@ -251,6 +251,11 @@ struct private_ike_sa_t {
|
||||
* Flush auth configs once established?
|
||||
*/
|
||||
bool flush_auth_cfg;
|
||||
|
||||
/**
|
||||
* Maximum length of a single fragment, 0 for address-specific defaults
|
||||
*/
|
||||
size_t fragment_size;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -994,6 +999,61 @@ METHOD(ike_sa_t, generate_message, status_t,
|
||||
return status;
|
||||
}
|
||||
|
||||
static bool filter_fragments(private_ike_sa_t *this, packet_t **fragment,
|
||||
packet_t **packet)
|
||||
{
|
||||
*packet = (*fragment)->clone(*fragment);
|
||||
set_dscp(this, *packet);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, generate_message_fragmented, status_t,
|
||||
private_ike_sa_t *this, message_t *message, enumerator_t **packets)
|
||||
{
|
||||
enumerator_t *fragments;
|
||||
packet_t *packet;
|
||||
status_t status;
|
||||
bool use_frags = FALSE;
|
||||
|
||||
if (this->ike_cfg)
|
||||
{
|
||||
switch (this->ike_cfg->fragmentation(this->ike_cfg))
|
||||
{
|
||||
case FRAGMENTATION_FORCE:
|
||||
use_frags = TRUE;
|
||||
break;
|
||||
case FRAGMENTATION_YES:
|
||||
use_frags = supports_extension(this, EXT_IKE_FRAGMENTATION);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!use_frags)
|
||||
{
|
||||
status = generate_message(this, message, &packet);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
*packets = enumerator_create_single(packet, NULL);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
this->stats[STAT_OUTBOUND] = time_monotonic(NULL);
|
||||
message->set_ike_sa_id(message, this->ike_sa_id);
|
||||
charon->bus->message(charon->bus, message, FALSE, TRUE);
|
||||
status = message->fragment(message, this->keymat, this->fragment_size,
|
||||
&fragments);
|
||||
if (status == SUCCESS)
|
||||
{
|
||||
charon->bus->message(charon->bus, message, FALSE, FALSE);
|
||||
*packets = enumerator_create_filter(fragments, (void*)filter_fragments,
|
||||
this, NULL);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
METHOD(ike_sa_t, set_kmaddress, void,
|
||||
private_ike_sa_t *this, host_t *local, host_t *remote)
|
||||
{
|
||||
@@ -2362,6 +2422,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
|
||||
.inherit_pre = _inherit_pre,
|
||||
.inherit_post = _inherit_post,
|
||||
.generate_message = _generate_message,
|
||||
.generate_message_fragmented = _generate_message_fragmented,
|
||||
.reset = _reset,
|
||||
.get_unique_id = _get_unique_id,
|
||||
.add_virtual_ip = _add_virtual_ip,
|
||||
@@ -2407,6 +2468,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
|
||||
"%s.retry_initiate_interval", 0, lib->ns),
|
||||
.flush_auth_cfg = lib->settings->get_bool(lib->settings,
|
||||
"%s.flush_auth_cfg", FALSE, lib->ns),
|
||||
.fragment_size = lib->settings->get_int(lib->settings,
|
||||
"%s.fragment_size", 0, lib->ns),
|
||||
);
|
||||
|
||||
if (version == IKEV2)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2012 Tobias Brunner
|
||||
* Copyright (C) 2006-2014 Tobias Brunner
|
||||
* Copyright (C) 2006 Daniel Roethlisberger
|
||||
* Copyright (C) 2005-2009 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
@@ -128,7 +128,7 @@ enum ike_extension_t {
|
||||
EXT_NATT_DRAFT_02_03 = (1<<10),
|
||||
|
||||
/**
|
||||
* peer support proprietary IKE fragmentation
|
||||
* peer supports proprietary IKEv1 or standardized IKEv2 fragmentation
|
||||
*/
|
||||
EXT_IKE_FRAGMENTATION = (1<<11),
|
||||
};
|
||||
@@ -756,7 +756,7 @@ struct ike_sa_t {
|
||||
status_t (*roam)(ike_sa_t *this, bool address);
|
||||
|
||||
/**
|
||||
* Processes a incoming IKEv2-Message.
|
||||
* Processes an incoming IKE message.
|
||||
*
|
||||
* Message processing may fail. If a critical failure occurs,
|
||||
* process_message() return DESTROY_ME. Then the caller must
|
||||
@@ -768,10 +768,10 @@ struct ike_sa_t {
|
||||
* - FAILED
|
||||
* - DESTROY_ME if this IKE_SA MUST be deleted
|
||||
*/
|
||||
status_t (*process_message) (ike_sa_t *this, message_t *message);
|
||||
status_t (*process_message)(ike_sa_t *this, message_t *message);
|
||||
|
||||
/**
|
||||
* Generate a IKE message to send it to the peer.
|
||||
* Generate an IKE message to send it to the peer.
|
||||
*
|
||||
* This method generates all payloads in the message and encrypts/signs
|
||||
* the packet.
|
||||
@@ -783,8 +783,26 @@ struct ike_sa_t {
|
||||
* - FAILED
|
||||
* - DESTROY_ME if this IKE_SA MUST be deleted
|
||||
*/
|
||||
status_t (*generate_message) (ike_sa_t *this, message_t *message,
|
||||
packet_t **packet);
|
||||
status_t (*generate_message)(ike_sa_t *this, message_t *message,
|
||||
packet_t **packet);
|
||||
|
||||
/**
|
||||
* Generate an IKE message to send it to the peer. If enabled and supported
|
||||
* it will be fragmented.
|
||||
*
|
||||
* This method generates all payloads in the message and encrypts/signs
|
||||
* the packet/fragments.
|
||||
*
|
||||
* @param message message to generate
|
||||
* @param packets enumerator of generated packet_t* (are not destroyed
|
||||
* with the enumerator)
|
||||
* @return
|
||||
* - SUCCESS
|
||||
* - FAILED
|
||||
* - DESTROY_ME if this IKE_SA MUST be deleted
|
||||
*/
|
||||
status_t (*generate_message_fragmented)(ike_sa_t *this, message_t *message,
|
||||
enumerator_t **packets);
|
||||
|
||||
/**
|
||||
* Retransmits a request.
|
||||
|
||||
@@ -1302,8 +1302,9 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
|
||||
|
||||
ike_id = entry->ike_sa->get_id(entry->ike_sa);
|
||||
entry->checked_out = TRUE;
|
||||
if (message->get_first_payload_type(message) != PLV1_FRAGMENT)
|
||||
{
|
||||
if (message->get_first_payload_type(message) != PLV1_FRAGMENT &&
|
||||
message->get_first_payload_type(message) != PLV2_FRAGMENT)
|
||||
{ /* TODO-FRAG: this fails if there are unencrypted payloads */
|
||||
entry->processing = get_message_id_or_hash(message);
|
||||
}
|
||||
if (ike_id->get_responder_spi(ike_id) == 0)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2013 Tobias Brunner
|
||||
* Copyright (C) 2007-2014 Tobias Brunner
|
||||
* Copyright (C) 2007-2011 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -38,8 +38,7 @@
|
||||
#include <processing/jobs/dpd_timeout_job.h>
|
||||
#include <processing/jobs/process_message_job.h>
|
||||
|
||||
#include <encoding/payloads/fragment_payload.h>
|
||||
#include <bio/bio_writer.h>
|
||||
#include <collections/array.h>
|
||||
|
||||
/**
|
||||
* Number of old messages hashes we keep for retransmission.
|
||||
@@ -50,20 +49,6 @@
|
||||
*/
|
||||
#define MAX_OLD_HASHES 2
|
||||
|
||||
/**
|
||||
* Maximum packet size for fragmented packets (same as in sockets)
|
||||
*/
|
||||
#define MAX_PACKET 10000
|
||||
|
||||
/**
|
||||
* Maximum size of fragment data when sending packets (currently the same is
|
||||
* used for IPv4 and IPv6, even though the latter has a higher minimum datagram
|
||||
* size). 576 (= min. IPv4) - 20 (= IP header) - 8 (= UDP header) -
|
||||
* - 28 (= IKE header) - 8 (= fragment header) = 512
|
||||
* This is reduced by 4 in case of NAT-T (due to the non-ESP marker).
|
||||
*/
|
||||
#define MAX_FRAGMENT_SIZE 512
|
||||
|
||||
/**
|
||||
* First sequence number of responding packets.
|
||||
*
|
||||
@@ -127,9 +112,9 @@ struct private_task_manager_t {
|
||||
u_int32_t hash;
|
||||
|
||||
/**
|
||||
* packet for retransmission
|
||||
* packet(s) for retransmission
|
||||
*/
|
||||
packet_t *packet;
|
||||
array_t *packets;
|
||||
|
||||
/**
|
||||
* Sequence number of the last sent message
|
||||
@@ -173,9 +158,9 @@ struct private_task_manager_t {
|
||||
u_int retransmitted;
|
||||
|
||||
/**
|
||||
* packet for retransmission
|
||||
* packet(s) for retransmission
|
||||
*/
|
||||
packet_t *packet;
|
||||
array_t *packets;
|
||||
|
||||
/**
|
||||
* type of the initiated exchange
|
||||
@@ -185,50 +170,9 @@ struct private_task_manager_t {
|
||||
} initiating;
|
||||
|
||||
/**
|
||||
* Data used to reassemble a fragmented message
|
||||
* Message we are currently defragmenting, if any (only one at a time)
|
||||
*/
|
||||
struct {
|
||||
|
||||
/**
|
||||
* Fragment ID (currently only one is supported at a time)
|
||||
*/
|
||||
u_int16_t id;
|
||||
|
||||
/**
|
||||
* The number of the last fragment (in case we receive the fragments out
|
||||
* of order), since the first starts with 1 this defines the number of
|
||||
* fragments we expect
|
||||
*/
|
||||
u_int8_t last;
|
||||
|
||||
/**
|
||||
* List of fragments (fragment_t*)
|
||||
*/
|
||||
linked_list_t *list;
|
||||
|
||||
/**
|
||||
* Length of all currently received fragments
|
||||
*/
|
||||
size_t len;
|
||||
|
||||
/**
|
||||
* Maximum length of a fragmented packet
|
||||
*/
|
||||
size_t max_packet;
|
||||
|
||||
/**
|
||||
* Maximum length of a single fragment (when sending)
|
||||
*/
|
||||
size_t size;
|
||||
|
||||
/**
|
||||
* The exchange type we use for fragments. Always the initial type even
|
||||
* for fragmented quick mode or transaction messages (i.e. either
|
||||
* ID_PROT or AGGRESSIVE)
|
||||
*/
|
||||
exchange_type_t exchange;
|
||||
|
||||
} frag;
|
||||
message_t *defrag;
|
||||
|
||||
/**
|
||||
* List of queued tasks not yet in action
|
||||
@@ -277,31 +221,16 @@ struct private_task_manager_t {
|
||||
};
|
||||
|
||||
/**
|
||||
* A single fragment within a fragmented message
|
||||
* Reset retransmission packet list
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
/** fragment number */
|
||||
u_int8_t num;
|
||||
|
||||
/** fragment data */
|
||||
chunk_t data;
|
||||
|
||||
} fragment_t;
|
||||
|
||||
static void fragment_destroy(fragment_t *this)
|
||||
static void clear_packets(array_t *array)
|
||||
{
|
||||
chunk_free(&this->data);
|
||||
free(this);
|
||||
}
|
||||
packet_t *packet;
|
||||
|
||||
static void clear_fragments(private_task_manager_t *this, u_int16_t id)
|
||||
{
|
||||
DESTROY_FUNCTION_IF(this->frag.list, (void*)fragment_destroy);
|
||||
this->frag.list = NULL;
|
||||
this->frag.last = 0;
|
||||
this->frag.len = 0;
|
||||
this->frag.id = id;
|
||||
while (array_remove(array, ARRAY_TAIL, &packet))
|
||||
{
|
||||
packet->destroy(packet);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, flush_queue, void,
|
||||
@@ -321,8 +250,7 @@ METHOD(task_manager_t, flush_queue, void,
|
||||
list = this->active_tasks;
|
||||
/* cancel pending retransmits */
|
||||
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
|
||||
DESTROY_IF(this->initiating.packet);
|
||||
this->initiating.packet = NULL;
|
||||
clear_packets(this->initiating.packets);
|
||||
break;
|
||||
case TASK_QUEUE_PASSIVE:
|
||||
list = this->passive_tasks;
|
||||
@@ -373,110 +301,53 @@ static bool activate_task(private_task_manager_t *this, task_type_t type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a single fragment with the given data
|
||||
* Send packets in the given array (they get cloned)
|
||||
*/
|
||||
static bool send_fragment(private_task_manager_t *this, bool request,
|
||||
host_t *src, host_t *dst, fragment_payload_t *fragment)
|
||||
static void send_packets(private_task_manager_t *this, array_t *packets)
|
||||
{
|
||||
message_t *message;
|
||||
enumerator_t *enumerator;
|
||||
packet_t *packet;
|
||||
status_t status;
|
||||
|
||||
message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION);
|
||||
/* other implementations seem to just use 0 as message ID, so here we go */
|
||||
message->set_message_id(message, 0);
|
||||
message->set_request(message, request);
|
||||
message->set_source(message, src->clone(src));
|
||||
message->set_destination(message, dst->clone(dst));
|
||||
message->set_exchange_type(message, this->frag.exchange);
|
||||
message->add_payload(message, (payload_t*)fragment);
|
||||
enumerator = array_create_enumerator(packets);
|
||||
while (enumerator->enumerate(enumerator, &packet))
|
||||
{
|
||||
charon->sender->send(charon->sender, packet->clone(packet));
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
status = this->ike_sa->generate_message(this->ike_sa, message, &packet);
|
||||
if (status != SUCCESS)
|
||||
/**
|
||||
* Generates the given message and stores packet(s) in the given array
|
||||
*/
|
||||
static bool generate_message(private_task_manager_t *this, message_t *message,
|
||||
array_t **packets)
|
||||
{
|
||||
enumerator_t *fragments;
|
||||
packet_t *fragment;
|
||||
|
||||
if (this->ike_sa->generate_message_fragmented(this->ike_sa, message,
|
||||
&fragments) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "failed to generate IKE fragment");
|
||||
message->destroy(message);
|
||||
return FALSE;
|
||||
}
|
||||
charon->sender->send(charon->sender, packet);
|
||||
message->destroy(message);
|
||||
while (fragments->enumerate(fragments, &fragment))
|
||||
{
|
||||
array_insert_create(packets, ARRAY_TAIL, fragment);
|
||||
}
|
||||
fragments->destroy(fragments);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet, if supported and required do so in fragments
|
||||
* Retransmit a packet (or its fragments)
|
||||
*/
|
||||
static bool send_packet(private_task_manager_t *this, bool request,
|
||||
packet_t *packet)
|
||||
{
|
||||
bool use_frags = FALSE;
|
||||
ike_cfg_t *ike_cfg;
|
||||
chunk_t data;
|
||||
|
||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
if (ike_cfg)
|
||||
{
|
||||
switch (ike_cfg->fragmentation(ike_cfg))
|
||||
{
|
||||
case FRAGMENTATION_FORCE:
|
||||
use_frags = TRUE;
|
||||
break;
|
||||
case FRAGMENTATION_YES:
|
||||
use_frags = this->ike_sa->supports_extension(this->ike_sa,
|
||||
EXT_IKE_FRAGMENTATION);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
data = packet->get_data(packet);
|
||||
if (data.len > this->frag.size && use_frags)
|
||||
{
|
||||
fragment_payload_t *fragment;
|
||||
u_int8_t num, count;
|
||||
size_t len, frag_size;
|
||||
host_t *src, *dst;
|
||||
|
||||
src = packet->get_source(packet);
|
||||
dst = packet->get_destination(packet);
|
||||
|
||||
frag_size = this->frag.size;
|
||||
if (dst->get_port(dst) != IKEV2_UDP_PORT &&
|
||||
src->get_port(src) != IKEV2_UDP_PORT)
|
||||
{ /* reduce size due to non-ESP marker */
|
||||
frag_size -= 4;
|
||||
}
|
||||
count = data.len / frag_size + (data.len % frag_size ? 1 : 0);
|
||||
|
||||
DBG1(DBG_IKE, "sending IKE message with length of %zu bytes in "
|
||||
"%hhu fragments", data.len, count);
|
||||
for (num = 1; num <= count; num++)
|
||||
{
|
||||
len = min(data.len, frag_size);
|
||||
fragment = fragment_payload_create_from_data(num, num == count,
|
||||
chunk_create(data.ptr, len));
|
||||
if (!send_fragment(this, request, src, dst, fragment))
|
||||
{
|
||||
packet->destroy(packet);
|
||||
return FALSE;
|
||||
}
|
||||
data = chunk_skip(data, len);
|
||||
}
|
||||
packet->destroy(packet);
|
||||
return TRUE;
|
||||
}
|
||||
charon->sender->send(charon->sender, packet);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retransmit a packet, either as initiator or as responder
|
||||
*/
|
||||
static status_t retransmit_packet(private_task_manager_t *this, bool request,
|
||||
u_int32_t seqnr, u_int mid, u_int retransmitted, packet_t *packet)
|
||||
static status_t retransmit_packet(private_task_manager_t *this, u_int32_t seqnr,
|
||||
u_int mid, u_int retransmitted, array_t *packets)
|
||||
{
|
||||
packet_t *packet;
|
||||
u_int32_t t;
|
||||
|
||||
array_get(packets, 0, &packet);
|
||||
if (retransmitted > this->retransmit_tries)
|
||||
{
|
||||
DBG1(DBG_IKE, "giving up after %u retransmits", retransmitted - 1);
|
||||
@@ -492,10 +363,7 @@ static status_t retransmit_packet(private_task_manager_t *this, bool request,
|
||||
mid, seqnr < RESPONDING_SEQ ? seqnr : seqnr - RESPONDING_SEQ);
|
||||
charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND, packet);
|
||||
}
|
||||
if (!send_packet(this, request, packet->clone(packet)))
|
||||
{
|
||||
return DESTROY_ME;
|
||||
}
|
||||
send_packets(this, packets);
|
||||
lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)
|
||||
retransmit_job_create(seqnr, this->ike_sa->get_id(this->ike_sa)), t);
|
||||
return NEED_MORE;
|
||||
@@ -506,20 +374,22 @@ METHOD(task_manager_t, retransmit, status_t,
|
||||
{
|
||||
status_t status = SUCCESS;
|
||||
|
||||
if (seqnr == this->initiating.seqnr && this->initiating.packet)
|
||||
if (seqnr == this->initiating.seqnr &&
|
||||
array_count(this->initiating.packets))
|
||||
{
|
||||
status = retransmit_packet(this, TRUE, seqnr, this->initiating.mid,
|
||||
this->initiating.retransmitted, this->initiating.packet);
|
||||
status = retransmit_packet(this, seqnr, this->initiating.mid,
|
||||
this->initiating.retransmitted, this->initiating.packets);
|
||||
if (status == NEED_MORE)
|
||||
{
|
||||
this->initiating.retransmitted++;
|
||||
status = SUCCESS;
|
||||
}
|
||||
}
|
||||
if (seqnr == this->responding.seqnr && this->responding.packet)
|
||||
if (seqnr == this->responding.seqnr &&
|
||||
array_count(this->responding.packets))
|
||||
{
|
||||
status = retransmit_packet(this, FALSE, seqnr, this->responding.mid,
|
||||
this->responding.retransmitted, this->responding.packet);
|
||||
status = retransmit_packet(this, seqnr, this->responding.mid,
|
||||
this->responding.retransmitted, this->responding.packets);
|
||||
if (status == NEED_MORE)
|
||||
{
|
||||
this->responding.retransmitted++;
|
||||
@@ -586,7 +456,6 @@ METHOD(task_manager_t, initiate, status_t,
|
||||
task_t *task;
|
||||
message_t *message;
|
||||
host_t *me, *other;
|
||||
status_t status;
|
||||
exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED;
|
||||
bool new_mid = FALSE, expect_response = FALSE, cancelled = FALSE, keep = FALSE;
|
||||
|
||||
@@ -790,10 +659,8 @@ METHOD(task_manager_t, initiate, status_t,
|
||||
return initiate(this);
|
||||
}
|
||||
|
||||
DESTROY_IF(this->initiating.packet);
|
||||
status = this->ike_sa->generate_message(this->ike_sa, message,
|
||||
&this->initiating.packet);
|
||||
if (status != SUCCESS)
|
||||
clear_packets(this->initiating.packets);
|
||||
if (!generate_message(this, message, &this->initiating.packets))
|
||||
{
|
||||
/* message generation failed. There is nothing more to do than to
|
||||
* close the SA */
|
||||
@@ -811,13 +678,12 @@ METHOD(task_manager_t, initiate, status_t,
|
||||
}
|
||||
if (keep)
|
||||
{ /* keep the packet for retransmission, the responder might request it */
|
||||
send_packet(this, TRUE,
|
||||
this->initiating.packet->clone(this->initiating.packet));
|
||||
send_packets(this, this->initiating.packets);
|
||||
}
|
||||
else
|
||||
{
|
||||
send_packet(this, TRUE, this->initiating.packet);
|
||||
this->initiating.packet = NULL;
|
||||
send_packets(this, this->initiating.packets);
|
||||
clear_packets(this->initiating.packets);
|
||||
}
|
||||
message->destroy(message);
|
||||
|
||||
@@ -848,7 +714,6 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
|
||||
message_t *message;
|
||||
host_t *me, *other;
|
||||
bool delete = FALSE, cancelled = FALSE, expect_request = FALSE;
|
||||
status_t status;
|
||||
|
||||
me = request->get_destination(request);
|
||||
other = request->get_source(request);
|
||||
@@ -900,28 +765,25 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
DESTROY_IF(this->responding.packet);
|
||||
this->responding.packet = NULL;
|
||||
clear_packets(this->responding.packets);
|
||||
if (cancelled)
|
||||
{
|
||||
message->destroy(message);
|
||||
return initiate(this);
|
||||
}
|
||||
status = this->ike_sa->generate_message(this->ike_sa, message,
|
||||
&this->responding.packet);
|
||||
message->destroy(message);
|
||||
if (status != SUCCESS)
|
||||
if (!generate_message(this, message, &this->responding.packets))
|
||||
{
|
||||
message->destroy(message);
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
message->destroy(message);
|
||||
|
||||
if (expect_request && !delete)
|
||||
{
|
||||
return retransmit(this, this->responding.seqnr);
|
||||
}
|
||||
send_packet(this, FALSE,
|
||||
this->responding.packet->clone(this->responding.packet));
|
||||
send_packets(this, this->responding.packets);
|
||||
if (delete)
|
||||
{
|
||||
return DESTROY_ME;
|
||||
@@ -937,7 +799,7 @@ static void send_notify(private_task_manager_t *this, message_t *request,
|
||||
notify_type_t type)
|
||||
{
|
||||
message_t *response;
|
||||
packet_t *packet;
|
||||
array_t *packets = NULL;
|
||||
host_t *me, *other;
|
||||
u_int32_t mid;
|
||||
|
||||
@@ -973,11 +835,12 @@ static void send_notify(private_task_manager_t *this, message_t *request,
|
||||
}
|
||||
response->set_source(response, me->clone(me));
|
||||
response->set_destination(response, other->clone(other));
|
||||
if (this->ike_sa->generate_message(this->ike_sa, response,
|
||||
&packet) == SUCCESS)
|
||||
if (generate_message(this, response, &packets))
|
||||
{
|
||||
send_packet(this, TRUE, packet);
|
||||
send_packets(this, packets);
|
||||
}
|
||||
clear_packets(packets);
|
||||
array_destroy(packets);
|
||||
response->destroy(response);
|
||||
}
|
||||
|
||||
@@ -1075,7 +938,6 @@ static status_t process_request(private_task_manager_t *this,
|
||||
this->passive_tasks->insert_last(this->passive_tasks, task);
|
||||
task = (task_t *)isakmp_natd_create(this->ike_sa, FALSE);
|
||||
this->passive_tasks->insert_last(this->passive_tasks, task);
|
||||
this->frag.exchange = AGGRESSIVE;
|
||||
break;
|
||||
case QUICK_MODE:
|
||||
if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
|
||||
@@ -1164,8 +1026,7 @@ static status_t process_request(private_task_manager_t *this,
|
||||
else
|
||||
{ /* We don't send a response, so don't retransmit one if we get
|
||||
* the same message again. */
|
||||
DESTROY_IF(this->responding.packet);
|
||||
this->responding.packet = NULL;
|
||||
clear_packets(this->responding.packets);
|
||||
}
|
||||
if (this->passive_tasks->get_count(this->passive_tasks) == 0 &&
|
||||
this->queued_tasks->get_count(this->queued_tasks) > 0)
|
||||
@@ -1237,8 +1098,7 @@ static status_t process_response(private_task_manager_t *this,
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
|
||||
DESTROY_IF(this->initiating.packet);
|
||||
this->initiating.packet = NULL;
|
||||
clear_packets(this->initiating.packets);
|
||||
|
||||
if (this->queued && this->active_tasks->get_count(this->active_tasks) == 0)
|
||||
{
|
||||
@@ -1258,107 +1118,23 @@ static status_t process_response(private_task_manager_t *this,
|
||||
|
||||
static status_t handle_fragment(private_task_manager_t *this, message_t *msg)
|
||||
{
|
||||
fragment_payload_t *payload;
|
||||
enumerator_t *enumerator;
|
||||
fragment_t *fragment;
|
||||
status_t status = SUCCESS;
|
||||
chunk_t data;
|
||||
u_int8_t num;
|
||||
status_t status;
|
||||
|
||||
payload = (fragment_payload_t*)msg->get_payload(msg, PLV1_FRAGMENT);
|
||||
if (!payload)
|
||||
if (!this->defrag)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
if (!this->frag.list || this->frag.id != payload->get_id(payload))
|
||||
{
|
||||
clear_fragments(this, payload->get_id(payload));
|
||||
this->frag.list = linked_list_create();
|
||||
}
|
||||
|
||||
num = payload->get_number(payload);
|
||||
if (!this->frag.last && payload->is_last(payload))
|
||||
{
|
||||
this->frag.last = num;
|
||||
}
|
||||
|
||||
enumerator = this->frag.list->create_enumerator(this->frag.list);
|
||||
while (enumerator->enumerate(enumerator, &fragment))
|
||||
{
|
||||
if (fragment->num == num)
|
||||
{ /* ignore a duplicate fragment */
|
||||
DBG1(DBG_IKE, "received duplicate fragment #%hhu", num);
|
||||
enumerator->destroy(enumerator);
|
||||
return NEED_MORE;
|
||||
}
|
||||
if (fragment->num > num)
|
||||
this->defrag = message_create_defrag(msg);
|
||||
if (!this->defrag)
|
||||
{
|
||||
break;
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
data = payload->get_data(payload);
|
||||
this->frag.len += data.len;
|
||||
if (this->frag.len > this->frag.max_packet)
|
||||
status = this->defrag->add_fragment(this->defrag, msg);
|
||||
if (status == SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "fragmented IKE message is too large");
|
||||
enumerator->destroy(enumerator);
|
||||
clear_fragments(this, 0);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
INIT(fragment,
|
||||
.num = num,
|
||||
.data = chunk_clone(data),
|
||||
);
|
||||
|
||||
this->frag.list->insert_before(this->frag.list, enumerator, fragment);
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
if (this->frag.list->get_count(this->frag.list) == this->frag.last)
|
||||
{
|
||||
message_t *message;
|
||||
packet_t *pkt;
|
||||
host_t *src, *dst;
|
||||
bio_writer_t *writer;
|
||||
|
||||
writer = bio_writer_create(this->frag.len);
|
||||
DBG1(DBG_IKE, "received fragment #%hhu, reassembling fragmented IKE "
|
||||
"message", num);
|
||||
enumerator = this->frag.list->create_enumerator(this->frag.list);
|
||||
while (enumerator->enumerate(enumerator, &fragment))
|
||||
{
|
||||
writer->write_data(writer, fragment->data);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
src = msg->get_source(msg);
|
||||
dst = msg->get_destination(msg);
|
||||
pkt = packet_create_from_data(src->clone(src), dst->clone(dst),
|
||||
writer->extract_buf(writer));
|
||||
writer->destroy(writer);
|
||||
|
||||
message = message_create_from_packet(pkt);
|
||||
if (message->parse_header(message) != SUCCESS)
|
||||
{
|
||||
DBG1(DBG_IKE, "failed to parse header of reassembled IKE message");
|
||||
message->destroy(message);
|
||||
status = FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
lib->processor->queue_job(lib->processor,
|
||||
(job_t*)process_message_job_create(message));
|
||||
status = NEED_MORE;
|
||||
|
||||
}
|
||||
clear_fragments(this, 0);
|
||||
}
|
||||
else
|
||||
{ /* there are some fragments missing */
|
||||
DBG1(DBG_IKE, "received fragment #%hhu, waiting for complete IKE "
|
||||
"message", num);
|
||||
lib->processor->queue_job(lib->processor,
|
||||
(job_t*)process_message_job_create(this->defrag));
|
||||
this->defrag = NULL;
|
||||
/* do not process the last fragment */
|
||||
status = NEED_MORE;
|
||||
}
|
||||
return status;
|
||||
@@ -1435,15 +1211,14 @@ METHOD(task_manager_t, process_message, status_t,
|
||||
{
|
||||
if (this->initiating.old_hashes[i] == hash)
|
||||
{
|
||||
if (this->initiating.packet &&
|
||||
if (array_count(this->initiating.packets) &&
|
||||
i == (this->initiating.old_hash_pos % MAX_OLD_HASHES) &&
|
||||
(msg->get_exchange_type(msg) == QUICK_MODE ||
|
||||
msg->get_exchange_type(msg) == AGGRESSIVE))
|
||||
{
|
||||
DBG1(DBG_IKE, "received retransmit of response with ID %u, "
|
||||
"resending last request", mid);
|
||||
send_packet(this, TRUE,
|
||||
this->initiating.packet->clone(this->initiating.packet));
|
||||
send_packets(this, this->initiating.packets);
|
||||
return SUCCESS;
|
||||
}
|
||||
DBG1(DBG_IKE, "received retransmit of response with ID %u, "
|
||||
@@ -1484,20 +1259,18 @@ METHOD(task_manager_t, process_message, status_t,
|
||||
{
|
||||
if (hash == this->responding.hash)
|
||||
{
|
||||
if (this->responding.packet)
|
||||
if (array_count(this->responding.packets))
|
||||
{
|
||||
DBG1(DBG_IKE, "received retransmit of request with ID %u, "
|
||||
"retransmitting response", mid);
|
||||
send_packet(this, FALSE,
|
||||
this->responding.packet->clone(this->responding.packet));
|
||||
send_packets(this, this->responding.packets);
|
||||
}
|
||||
else if (this->initiating.packet &&
|
||||
else if (array_count(this->initiating.packets) &&
|
||||
this->initiating.type == INFORMATIONAL_V1)
|
||||
{
|
||||
DBG1(DBG_IKE, "received retransmit of DPD request, "
|
||||
"retransmitting response");
|
||||
send_packet(this, TRUE,
|
||||
this->initiating.packet->clone(this->initiating.packet));
|
||||
send_packets(this, this->initiating.packets);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1657,7 +1430,6 @@ METHOD(task_manager_t, queue_ike, void,
|
||||
{
|
||||
queue_task(this, (task_t*)aggressive_mode_create(this->ike_sa, TRUE));
|
||||
}
|
||||
this->frag.exchange = AGGRESSIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1984,17 +1756,16 @@ METHOD(task_manager_t, reset, void,
|
||||
task_t *task;
|
||||
|
||||
/* reset message counters and retransmit packets */
|
||||
DESTROY_IF(this->responding.packet);
|
||||
DESTROY_IF(this->initiating.packet);
|
||||
this->responding.packet = NULL;
|
||||
clear_packets(this->responding.packets);
|
||||
clear_packets(this->initiating.packets);
|
||||
this->responding.seqnr = RESPONDING_SEQ;
|
||||
this->responding.retransmitted = 0;
|
||||
this->initiating.packet = NULL;
|
||||
this->initiating.mid = 0;
|
||||
this->initiating.seqnr = 0;
|
||||
this->initiating.retransmitted = 0;
|
||||
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
|
||||
clear_fragments(this, 0);
|
||||
DESTROY_IF(this->defrag);
|
||||
this->defrag = NULL;
|
||||
if (initiate != UINT_MAX)
|
||||
{
|
||||
this->dpd_send = initiate;
|
||||
@@ -2045,11 +1816,13 @@ METHOD(task_manager_t, destroy, void,
|
||||
this->active_tasks->destroy(this->active_tasks);
|
||||
this->queued_tasks->destroy(this->queued_tasks);
|
||||
this->passive_tasks->destroy(this->passive_tasks);
|
||||
clear_fragments(this, 0);
|
||||
DESTROY_IF(this->defrag);
|
||||
|
||||
DESTROY_IF(this->queued);
|
||||
DESTROY_IF(this->responding.packet);
|
||||
DESTROY_IF(this->initiating.packet);
|
||||
clear_packets(this->responding.packets);
|
||||
array_destroy(this->responding.packets);
|
||||
clear_packets(this->initiating.packets);
|
||||
array_destroy(this->initiating.packets);
|
||||
DESTROY_IF(this->rng);
|
||||
free(this);
|
||||
}
|
||||
@@ -2094,13 +1867,6 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
|
||||
.responding = {
|
||||
.seqnr = RESPONDING_SEQ,
|
||||
},
|
||||
.frag = {
|
||||
.exchange = ID_PROT,
|
||||
.max_packet = lib->settings->get_int(lib->settings,
|
||||
"%s.max_packet", MAX_PACKET, lib->ns),
|
||||
.size = lib->settings->get_int(lib->settings,
|
||||
"%s.fragment_size", MAX_FRAGMENT_SIZE, lib->ns),
|
||||
},
|
||||
.ike_sa = ike_sa,
|
||||
.rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
|
||||
.queued_tasks = linked_list_create(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011 Tobias Brunner
|
||||
* Copyright (C) 2007-2014 Tobias Brunner
|
||||
* Copyright (C) 2007-2010 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
@@ -90,9 +90,14 @@ struct private_task_manager_t {
|
||||
u_int32_t mid;
|
||||
|
||||
/**
|
||||
* packet for retransmission
|
||||
* packet(s) for retransmission
|
||||
*/
|
||||
packet_t *packet;
|
||||
array_t *packets;
|
||||
|
||||
/**
|
||||
* Helper to defragment the request
|
||||
*/
|
||||
message_t *defrag;
|
||||
|
||||
} responding;
|
||||
|
||||
@@ -111,9 +116,9 @@ struct private_task_manager_t {
|
||||
u_int retransmitted;
|
||||
|
||||
/**
|
||||
* packet for retransmission
|
||||
* packet(s) for retransmission
|
||||
*/
|
||||
packet_t *packet;
|
||||
array_t *packets;
|
||||
|
||||
/**
|
||||
* type of the initated exchange
|
||||
@@ -125,6 +130,11 @@ struct private_task_manager_t {
|
||||
*/
|
||||
bool deferred;
|
||||
|
||||
/**
|
||||
* Helper to defragment the response
|
||||
*/
|
||||
message_t *defrag;
|
||||
|
||||
} initiating;
|
||||
|
||||
/**
|
||||
@@ -163,6 +173,19 @@ struct private_task_manager_t {
|
||||
double retransmit_base;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset retransmission packet list
|
||||
*/
|
||||
static void clear_packets(array_t *array)
|
||||
{
|
||||
packet_t *packet;
|
||||
|
||||
while (array_remove(array, ARRAY_TAIL, &packet))
|
||||
{
|
||||
packet->destroy(packet);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, flush_queue, void,
|
||||
private_task_manager_t *this, task_queue_t queue)
|
||||
{
|
||||
@@ -222,10 +245,60 @@ static bool activate_task(private_task_manager_t *this, task_type_t type)
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send packets in the given array (they get cloned). Optionally, the
|
||||
* source and destination addresses are changed before sending it.
|
||||
*/
|
||||
static void send_packets(private_task_manager_t *this, array_t *packets,
|
||||
host_t *src, host_t *dst)
|
||||
{
|
||||
packet_t *packet, *clone;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < array_count(packets); i++)
|
||||
{
|
||||
array_get(packets, i, &packet);
|
||||
clone = packet->clone(packet);
|
||||
if (src)
|
||||
{
|
||||
clone->set_source(clone, src->clone(src));
|
||||
}
|
||||
if (dst)
|
||||
{
|
||||
clone->set_destination(clone, dst->clone(dst));
|
||||
}
|
||||
charon->sender->send(charon->sender, clone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the given message and stores packet(s) in the given array
|
||||
*/
|
||||
static bool generate_message(private_task_manager_t *this, message_t *message,
|
||||
array_t **packets)
|
||||
{
|
||||
enumerator_t *fragments;
|
||||
packet_t *fragment;
|
||||
|
||||
if (this->ike_sa->generate_message_fragmented(this->ike_sa, message,
|
||||
&fragments) != SUCCESS)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
while (fragments->enumerate(fragments, &fragment))
|
||||
{
|
||||
array_insert_create(packets, ARRAY_TAIL, fragment);
|
||||
}
|
||||
fragments->destroy(fragments);
|
||||
array_compress(*packets);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(task_manager_t, retransmit, status_t,
|
||||
private_task_manager_t *this, u_int32_t message_id)
|
||||
{
|
||||
if (this->initiating.packet && message_id == this->initiating.mid)
|
||||
if (message_id == this->initiating.mid &&
|
||||
array_count(this->initiating.packets))
|
||||
{
|
||||
u_int32_t timeout;
|
||||
job_t *job;
|
||||
@@ -234,6 +307,8 @@ METHOD(task_manager_t, retransmit, status_t,
|
||||
task_t *task;
|
||||
ike_mobike_t *mobike = NULL;
|
||||
|
||||
array_get(this->initiating.packets, 0, &packet);
|
||||
|
||||
/* check if we are retransmitting a MOBIKE routability check */
|
||||
if (this->initiating.type == INFORMATIONAL)
|
||||
{
|
||||
@@ -261,7 +336,7 @@ METHOD(task_manager_t, retransmit, status_t,
|
||||
DBG1(DBG_IKE, "giving up after %d retransmits",
|
||||
this->initiating.retransmitted - 1);
|
||||
charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND_TIMEOUT,
|
||||
this->initiating.packet);
|
||||
packet);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
@@ -269,17 +344,17 @@ METHOD(task_manager_t, retransmit, status_t,
|
||||
{
|
||||
DBG1(DBG_IKE, "retransmit %d of request with message ID %d",
|
||||
this->initiating.retransmitted, message_id);
|
||||
charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND,
|
||||
this->initiating.packet);
|
||||
charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND, packet);
|
||||
}
|
||||
if (!mobike)
|
||||
{
|
||||
packet = this->initiating.packet->clone(this->initiating.packet);
|
||||
charon->sender->send(charon->sender, packet);
|
||||
send_packets(this, this->initiating.packets,
|
||||
this->ike_sa->get_my_host(this->ike_sa),
|
||||
this->ike_sa->get_other_host(this->ike_sa));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mobike->transmit(mobike, this->initiating.packet))
|
||||
if (!mobike->transmit(mobike, packet))
|
||||
{
|
||||
DBG1(DBG_IKE, "no route found to reach peer, MOBIKE update "
|
||||
"deferred");
|
||||
@@ -311,7 +386,9 @@ METHOD(task_manager_t, retransmit, status_t,
|
||||
DBG1(DBG_IKE, "path probing attempt %d",
|
||||
this->initiating.retransmitted);
|
||||
}
|
||||
if (!mobike->transmit(mobike, this->initiating.packet))
|
||||
/* TODO-FRAG: presumably these small packets are not fragmented,
|
||||
* we should maybe ensure this is the case when generating them */
|
||||
if (!mobike->transmit(mobike, packet))
|
||||
{
|
||||
DBG1(DBG_IKE, "no route found to reach peer, path probing "
|
||||
"deferred");
|
||||
@@ -336,7 +413,6 @@ METHOD(task_manager_t, initiate, status_t,
|
||||
task_t *task;
|
||||
message_t *message;
|
||||
host_t *me, *other;
|
||||
status_t status;
|
||||
exchange_type_t exchange = 0;
|
||||
|
||||
if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED)
|
||||
@@ -529,9 +605,7 @@ METHOD(task_manager_t, initiate, status_t,
|
||||
/* update exchange type if a task changed it */
|
||||
this->initiating.type = message->get_exchange_type(message);
|
||||
|
||||
status = this->ike_sa->generate_message(this->ike_sa, message,
|
||||
&this->initiating.packet);
|
||||
if (status != SUCCESS)
|
||||
if (!generate_message(this, message, &this->initiating.packets))
|
||||
{
|
||||
/* message generation failed. There is nothing more to do than to
|
||||
* close the SA */
|
||||
@@ -603,8 +677,7 @@ static status_t process_response(private_task_manager_t *this,
|
||||
|
||||
this->initiating.mid++;
|
||||
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
|
||||
this->initiating.packet->destroy(this->initiating.packet);
|
||||
this->initiating.packet = NULL;
|
||||
clear_packets(this->initiating.packets);
|
||||
|
||||
array_compress(this->active_tasks);
|
||||
|
||||
@@ -672,8 +745,8 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
|
||||
host_t *me, *other;
|
||||
bool delete = FALSE, hook = FALSE;
|
||||
ike_sa_id_t *id = NULL;
|
||||
u_int64_t responder_spi;
|
||||
status_t status;
|
||||
u_int64_t responder_spi = 0;
|
||||
bool result;
|
||||
|
||||
me = request->get_destination(request);
|
||||
other = request->get_source(request);
|
||||
@@ -735,23 +808,20 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
|
||||
}
|
||||
|
||||
/* message complete, send it */
|
||||
DESTROY_IF(this->responding.packet);
|
||||
this->responding.packet = NULL;
|
||||
status = this->ike_sa->generate_message(this->ike_sa, message,
|
||||
&this->responding.packet);
|
||||
clear_packets(this->responding.packets);
|
||||
result = generate_message(this, message, &this->responding.packets);
|
||||
message->destroy(message);
|
||||
if (id)
|
||||
{
|
||||
id->set_responder_spi(id, responder_spi);
|
||||
}
|
||||
if (status != SUCCESS)
|
||||
if (!result)
|
||||
{
|
||||
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
|
||||
return DESTROY_ME;
|
||||
}
|
||||
|
||||
charon->sender->send(charon->sender,
|
||||
this->responding.packet->clone(this->responding.packet));
|
||||
send_packets(this, this->responding.packets, NULL, NULL);
|
||||
if (delete)
|
||||
{
|
||||
if (hook)
|
||||
@@ -999,6 +1069,48 @@ METHOD(task_manager_t, incr_mid, void,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the given IKE fragment, if it is one.
|
||||
*
|
||||
* Returns SUCCESS if the message is not a fragment, and NEED_MORE if it was
|
||||
* handled properly. Error states are returned if the fragment was invalid or
|
||||
* the reassembled message could not have been processed properly.
|
||||
*/
|
||||
static status_t handle_fragment(private_task_manager_t *this,
|
||||
message_t **defrag, message_t *msg)
|
||||
{
|
||||
message_t *reassembled;
|
||||
status_t status;
|
||||
|
||||
if (!msg->get_payload(msg, PLV2_FRAGMENT))
|
||||
{
|
||||
return SUCCESS;
|
||||
}
|
||||
if (!*defrag)
|
||||
{
|
||||
*defrag = message_create_defrag(msg);
|
||||
if (!*defrag)
|
||||
{
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
status = (*defrag)->add_fragment(*defrag, msg);
|
||||
if (status == SUCCESS)
|
||||
{
|
||||
/* reinject the reassembled message */
|
||||
reassembled = *defrag;
|
||||
*defrag = NULL;
|
||||
status = this->ike_sa->process_message(this->ike_sa, reassembled);
|
||||
if (status == SUCCESS)
|
||||
{
|
||||
/* avoid processing the last fragment */
|
||||
status = NEED_MORE;
|
||||
}
|
||||
reassembled->destroy(reassembled);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notify back to the sender
|
||||
*/
|
||||
@@ -1192,6 +1304,11 @@ METHOD(task_manager_t, process_message, status_t,
|
||||
{ /* with MOBIKE, we do no implicit updates */
|
||||
this->ike_sa->update_hosts(this->ike_sa, me, other, mid == 1);
|
||||
}
|
||||
status = handle_fragment(this, &this->responding.defrag, msg);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
charon->bus->message(charon->bus, msg, TRUE, TRUE);
|
||||
if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED)
|
||||
{ /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */
|
||||
@@ -1204,20 +1321,19 @@ METHOD(task_manager_t, process_message, status_t,
|
||||
}
|
||||
this->responding.mid++;
|
||||
}
|
||||
else if ((mid == this->responding.mid - 1) && this->responding.packet)
|
||||
else if ((mid == this->responding.mid - 1) &&
|
||||
array_count(this->responding.packets))
|
||||
{
|
||||
packet_t *clone;
|
||||
host_t *host;
|
||||
|
||||
status = handle_fragment(this, &this->responding.defrag, msg);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
DBG1(DBG_IKE, "received retransmit of request with ID %d, "
|
||||
"retransmitting response", mid);
|
||||
charon->bus->alert(charon->bus, ALERT_RETRANSMIT_RECEIVE, msg);
|
||||
clone = this->responding.packet->clone(this->responding.packet);
|
||||
host = msg->get_destination(msg);
|
||||
clone->set_source(clone, host->clone(host));
|
||||
host = msg->get_source(msg);
|
||||
clone->set_destination(clone, host->clone(host));
|
||||
charon->sender->send(charon->sender, clone);
|
||||
send_packets(this, this->responding.packets,
|
||||
msg->get_destination(msg), msg->get_source(msg));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1245,6 +1361,11 @@ METHOD(task_manager_t, process_message, status_t,
|
||||
this->ike_sa->update_hosts(this->ike_sa, NULL, other, FALSE);
|
||||
}
|
||||
}
|
||||
status = handle_fragment(this, &this->initiating.defrag, msg);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
charon->bus->message(charon->bus, msg, TRUE, TRUE);
|
||||
if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED)
|
||||
{ /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */
|
||||
@@ -1539,10 +1660,12 @@ METHOD(task_manager_t, reset, void,
|
||||
task_t *task;
|
||||
|
||||
/* reset message counters and retransmit packets */
|
||||
DESTROY_IF(this->responding.packet);
|
||||
DESTROY_IF(this->initiating.packet);
|
||||
this->responding.packet = NULL;
|
||||
this->initiating.packet = NULL;
|
||||
clear_packets(this->responding.packets);
|
||||
clear_packets(this->initiating.packets);
|
||||
DESTROY_IF(this->responding.defrag);
|
||||
DESTROY_IF(this->initiating.defrag);
|
||||
this->responding.defrag = NULL;
|
||||
this->initiating.defrag = NULL;
|
||||
if (initiate != UINT_MAX)
|
||||
{
|
||||
this->initiating.mid = initiate;
|
||||
@@ -1596,8 +1719,12 @@ METHOD(task_manager_t, destroy, void,
|
||||
array_destroy(this->queued_tasks);
|
||||
array_destroy(this->passive_tasks);
|
||||
|
||||
DESTROY_IF(this->responding.packet);
|
||||
DESTROY_IF(this->initiating.packet);
|
||||
clear_packets(this->responding.packets);
|
||||
array_destroy(this->responding.packets);
|
||||
clear_packets(this->initiating.packets);
|
||||
array_destroy(this->initiating.packets);
|
||||
DESTROY_IF(this->responding.defrag);
|
||||
DESTROY_IF(this->initiating.defrag);
|
||||
free(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,19 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
|
||||
message->add_payload(message, (payload_t*)ke_payload);
|
||||
message->add_payload(message, (payload_t*)nonce_payload);
|
||||
}
|
||||
|
||||
/* negotiate fragmentation if we are not rekeying */
|
||||
if (!this->old_sa &&
|
||||
this->config->fragmentation(this->config) != FRAGMENTATION_NO)
|
||||
{
|
||||
if (this->initiator ||
|
||||
this->ike_sa->supports_extension(this->ike_sa,
|
||||
EXT_IKE_FRAGMENTATION))
|
||||
{
|
||||
message->add_notify(message, FALSE, FRAGMENTATION_SUPPORTED,
|
||||
chunk_empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,6 +233,16 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
|
||||
this->other_nonce = nonce_payload->get_nonce(nonce_payload);
|
||||
break;
|
||||
}
|
||||
case PLV2_NOTIFY:
|
||||
{
|
||||
notify_payload_t *notify = (notify_payload_t*)payload;
|
||||
|
||||
if (notify->get_notify_type(notify) == FRAGMENTATION_SUPPORTED)
|
||||
{
|
||||
this->ike_sa->enable_extension(this->ike_sa,
|
||||
EXT_IKE_FRAGMENTATION);
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,11 @@ typedef struct packet_t packet_t;
|
||||
#include <library.h>
|
||||
#include <networking/host.h>
|
||||
|
||||
/**
|
||||
* Maximum packet size we handle by default
|
||||
*/
|
||||
#define PACKET_MAX_DEFAULT 10000
|
||||
|
||||
/**
|
||||
* Abstraction of an IP/UDP-Packet, contains data, sender and receiver.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
moon::cat /var/log/daemon.log::received FRAGMENTATION vendor ID::YES
|
||||
sun::cat /var/log/daemon.log::received FRAGMENTATION vendor ID::YES
|
||||
moon::cat /var/log/daemon.log::sending IKE message with length of 1468 bytes in 2 fragments::YES
|
||||
sun::cat /var/log/daemon.log::sending IKE message with length of 1388 bytes in 2 fragments::YES
|
||||
moon::cat /var/log/daemon.log::splitting IKE message with length of 1468 bytes into 2 fragments::YES
|
||||
sun::cat /var/log/daemon.log::splitting IKE message with length of 1388 bytes into 2 fragments::YES
|
||||
moon::cat /var/log/daemon.log::received fragment #1, waiting for complete IKE message::YES
|
||||
moon::cat /var/log/daemon.log::received fragment #2, reassembling fragmented IKE message::YES
|
||||
sun::cat /var/log/daemon.log::received fragment #1, waiting for complete IKE message::YES
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
A connection between the subnets behind the gateways <b>moon</b> and <b>sun</b> is set up.
|
||||
The authentication is based on <b>X.509 certificates</b>. The IKEv2 fragmentation protocol
|
||||
defined in <b>RFC 7383</b> prevents the IP fragmentation of the IKEv2 messages carrying the
|
||||
large X.509 certificates.
|
||||
<p/>
|
||||
Upon the successful establishment of the IPsec tunnel, <b>leftfirewall=yes</b> automatically
|
||||
inserts iptables-based firewall rules that let pass the tunneled traffic.
|
||||
In order to test both tunnel and firewall, client <b>alice</b> behind gateway <b>moon</b>
|
||||
pings client <b>bob</b> located behind gateway <b>sun</b>.
|
||||
@@ -0,0 +1,15 @@
|
||||
moon::cat /var/log/daemon.log::IKE_SA_INIT request 0.*FRAG_SUP::YES
|
||||
sun::cat /var/log/daemon.log::IKE_SA_INIT response 0.*FRAG_SUP::YES
|
||||
moon::cat /var/log/daemon.log::splitting IKE message with length of 1804 bytes into 2 fragments::YES
|
||||
sun::cat /var/log/daemon.log::splitting IKE message with length of 1596 bytes into 2 fragments::YES
|
||||
moon::cat /var/log/daemon.log::received fragment #1 of 2, waiting for complete IKE message::YES
|
||||
moon::cat /var/log/daemon.log::received fragment #2 of 2, reassembling fragmented IKE message::YES
|
||||
sun::cat /var/log/daemon.log::received fragment #1 of 2, waiting for complete IKE message::YES
|
||||
sun::cat /var/log/daemon.log::received fragment #2 of 2, reassembling fragmented IKE message::YES
|
||||
moon::ipsec status 2> /dev/null::net-net.*ESTABLISHED.*moon.strongswan.org.*sun.strongswan.org::YES
|
||||
sun:: ipsec status 2> /dev/null::net-net.*ESTABLISHED.*sun.strongswan.org.*moon.strongswan.org::YES
|
||||
moon::ipsec status 2> /dev/null::net-net.*INSTALLED, TUNNEL::YES
|
||||
sun:: ipsec status 2> /dev/null::net-net.*INSTALLED, TUNNEL::YES
|
||||
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_req=1::YES
|
||||
sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES
|
||||
sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES
|
||||
@@ -0,0 +1,22 @@
|
||||
# /etc/ipsec.conf - strongSwan IPsec configuration file
|
||||
|
||||
config setup
|
||||
|
||||
conn %default
|
||||
ikelifetime=60m
|
||||
keylife=20m
|
||||
rekeymargin=3m
|
||||
keyingtries=1
|
||||
keyexchange=ikev2
|
||||
fragmentation=yes
|
||||
|
||||
conn net-net
|
||||
left=PH_IP_MOON
|
||||
leftcert=moonCert.pem
|
||||
[email protected]
|
||||
leftsubnet=10.1.0.0/16
|
||||
leftfirewall=yes
|
||||
right=PH_IP_SUN
|
||||
[email protected]
|
||||
rightsubnet=10.2.0.0/16
|
||||
auto=add
|
||||
@@ -0,0 +1,8 @@
|
||||
# /etc/strongswan.conf - strongSwan configuration file
|
||||
|
||||
charon {
|
||||
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation hmac stroke kernel-netlink socket-default updown
|
||||
|
||||
fragment_size = 1024
|
||||
dh_exponent_ansi_x9_42 = no
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
# /etc/ipsec.conf - strongSwan IPsec configuration file
|
||||
|
||||
config setup
|
||||
|
||||
conn %default
|
||||
ikelifetime=60m
|
||||
keylife=20m
|
||||
rekeymargin=3m
|
||||
keyingtries=1
|
||||
keyexchange=ikev2
|
||||
fragmentation=yes
|
||||
|
||||
conn net-net
|
||||
left=PH_IP_SUN
|
||||
leftcert=sunCert.pem
|
||||
[email protected]
|
||||
leftsubnet=10.2.0.0/16
|
||||
leftfirewall=yes
|
||||
right=PH_IP_MOON
|
||||
[email protected]
|
||||
rightsubnet=10.1.0.0/16
|
||||
auto=add
|
||||
@@ -0,0 +1,8 @@
|
||||
# /etc/strongswan.conf - strongSwan configuration file
|
||||
|
||||
charon {
|
||||
load = curl aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 revocation hmac stroke kernel-netlink socket-default updown
|
||||
|
||||
fragment_size = 1024
|
||||
dh_exponent_ansi_x9_42 = no
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
moon::ipsec stop
|
||||
sun::ipsec stop
|
||||
moon::iptables-restore < /etc/iptables.flush
|
||||
sun::iptables-restore < /etc/iptables.flush
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
moon::iptables-restore < /etc/iptables.rules
|
||||
sun::iptables-restore < /etc/iptables.rules
|
||||
moon::ipsec start
|
||||
sun::ipsec start
|
||||
moon::expect-connection net-net
|
||||
moon::ipsec up net-net
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This configuration file provides information on the
|
||||
# guest instances used for this test
|
||||
|
||||
# All guest instances that are required for this test
|
||||
#
|
||||
VIRTHOSTS="alice moon winnetou sun bob"
|
||||
|
||||
# Corresponding block diagram
|
||||
#
|
||||
DIAGRAM="a-m-w-s-b.png"
|
||||
|
||||
# Guest instances on which tcpdump is to be started
|
||||
#
|
||||
TCPDUMPHOSTS="sun"
|
||||
|
||||
# Guest instances on which IPsec is started
|
||||
# Used for IPsec logging purposes
|
||||
#
|
||||
IPSECHOSTS="moon sun"
|
||||
Reference in New Issue
Block a user