Merge branch 'ikev1-fragmentation'

This adds support for the proprietary IKEv1 fragmentation extension.

Conflicts:
	NEWS
This commit is contained in:
Tobias Brunner
2013-01-12 11:58:26 +01:00
37 changed files with 882 additions and 59 deletions
+2 -1
View File
@@ -500,7 +500,8 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection,
*/
ike_cfg = ike_cfg_create(IKEV2, TRUE, encap, "0.0.0.0", FALSE,
charon->socket->get_port(charon->socket, FALSE),
(char*)address, FALSE, IKEV2_UDP_PORT);
(char*)address, FALSE, IKEV2_UDP_PORT,
FRAGMENTATION_NO);
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
peer_cfg = peer_cfg_create(priv->name, ike_cfg,
CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */
+2 -1
View File
@@ -106,7 +106,8 @@ static ike_cfg_t *load_ike_config(private_config_t *this,
settings->get_str(settings, "configs.%s.lhost", "%any", config), FALSE,
settings->get_int(settings, "configs.%s.lport", 500, config),
settings->get_str(settings, "configs.%s.rhost", "%any", config), FALSE,
settings->get_int(settings, "configs.%s.rport", 500, config));
settings->get_int(settings, "configs.%s.rport", 500, config),
FRAGMENTATION_NO);
token = settings->get_str(settings, "configs.%s.proposal", NULL, config);
if (token)
{
@@ -471,7 +471,8 @@ static job_requeue_t initiate(private_android_service_t *this)
ike_cfg = ike_cfg_create(IKEV2, TRUE, TRUE, "0.0.0.0", FALSE,
charon->socket->get_port(charon->socket, FALSE),
this->gateway, FALSE, IKEV2_UDP_PORT);
this->gateway, FALSE, IKEV2_UDP_PORT,
FRAGMENTATION_NO);
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
peer_cfg = peer_cfg_create("android", ike_cfg, CERT_SEND_IF_ASKED,
+1
View File
@@ -42,6 +42,7 @@ encoding/payloads/ts_payload.c encoding/payloads/ts_payload.h \
encoding/payloads/unknown_payload.c encoding/payloads/unknown_payload.h \
encoding/payloads/vendor_id_payload.c encoding/payloads/vendor_id_payload.h \
encoding/payloads/hash_payload.c encoding/payloads/hash_payload.h \
encoding/payloads/fragment_payload.c encoding/payloads/fragment_payload.h \
kernel/kernel_handler.c kernel/kernel_handler.h \
network/receiver.c network/receiver.h network/sender.c network/sender.h \
network/socket.c network/socket.h \
+1
View File
@@ -40,6 +40,7 @@ encoding/payloads/ts_payload.c encoding/payloads/ts_payload.h \
encoding/payloads/unknown_payload.c encoding/payloads/unknown_payload.h \
encoding/payloads/vendor_id_payload.c encoding/payloads/vendor_id_payload.h \
encoding/payloads/hash_payload.c encoding/payloads/hash_payload.h \
encoding/payloads/fragment_payload.c encoding/payloads/fragment_payload.h \
kernel/kernel_handler.c kernel/kernel_handler.h \
network/receiver.c network/receiver.h network/sender.c network/sender.h \
network/socket.c network/socket.h \
+16 -1
View File
@@ -89,6 +89,11 @@ struct private_ike_cfg_t {
*/
bool force_encap;
/**
* use IKEv1 fragmentation
*/
fragmentation_t fragmentation;
/**
* List of proposals to use
*/
@@ -113,6 +118,12 @@ METHOD(ike_cfg_t, force_encap_, bool,
return this->force_encap;
}
METHOD(ike_cfg_t, fragmentation, fragmentation_t,
private_ike_cfg_t *this)
{
return this->fragmentation;
}
METHOD(ike_cfg_t, get_my_addr, char*,
private_ike_cfg_t *this, bool *allow_any)
{
@@ -268,6 +279,7 @@ METHOD(ike_cfg_t, equals, bool,
this->version == other->version &&
this->certreq == other->certreq &&
this->force_encap == other->force_encap &&
this->fragmentation == other->fragmentation &&
streq(this->me, other->me) &&
streq(this->other, other->other) &&
this->my_port == other->my_port &&
@@ -299,7 +311,8 @@ METHOD(ike_cfg_t, destroy, void,
*/
ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
char *me, bool my_allow_any, u_int16_t my_port,
char *other, bool other_allow_any, u_int16_t other_port)
char *other, bool other_allow_any, u_int16_t other_port,
fragmentation_t fragmentation)
{
private_ike_cfg_t *this;
@@ -308,6 +321,7 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
.get_version = _get_version,
.send_certreq = _send_certreq,
.force_encap = _force_encap_,
.fragmentation = _fragmentation,
.get_my_addr = _get_my_addr,
.get_other_addr = _get_other_addr,
.get_my_port = _get_my_port,
@@ -324,6 +338,7 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
.version = version,
.certreq = certreq,
.force_encap = force_encap,
.fragmentation = fragmentation,
.me = strdup(me),
.other = strdup(other),
.my_allow_any = my_allow_any,
+25 -2
View File
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -23,6 +24,7 @@
#define IKE_CFG_H_
typedef enum ike_version_t ike_version_t;
typedef enum fragmentation_t fragmentation_t;
typedef struct ike_cfg_t ike_cfg_t;
#include <library.h>
@@ -44,6 +46,18 @@ enum ike_version_t {
IKEV2 = 2,
};
/**
* Proprietary IKEv1 fragmentation
*/
enum fragmentation_t {
/** disable fragmentation */
FRAGMENTATION_NO,
/** enable fragmentation if supported by peer */
FRAGMENTATION_YES,
/** force use of fragmentation (even for the first message) */
FRAGMENTATION_FORCE,
};
/**
* enum strings fro ike_version_t
*/
@@ -134,10 +148,17 @@ struct ike_cfg_t {
/**
* Enforce UDP encapsulation by faking NATD notifies?
*
* @return TRUE to enfoce UDP encapsulation
* @return TRUE to enforce UDP encapsulation
*/
bool (*force_encap) (ike_cfg_t *this);
/**
* Use proprietary IKEv1 fragmentation
*
* @return TRUE to use fragmentation
*/
fragmentation_t (*fragmentation) (ike_cfg_t *this);
/**
* Get the DH group to use for IKE_SA setup.
*
@@ -183,10 +204,12 @@ struct ike_cfg_t {
* @param other address/DNS name of remote peer
* @param other_allow_any allow override of remote address by any address
* @param other_port IKE port to use as dest, 500 uses IKEv2 port floating
* @param fragmentation use IKEv1 fragmentation
* @return ike_cfg_t object.
*/
ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
char *me, bool my_allow_any, u_int16_t my_port,
char *other, bool other_allow_any, u_int16_t other_port);
char *other, bool other_allow_any, u_int16_t other_port,
fragmentation_t fragmentation);
#endif /** IKE_CFG_H_ @}*/
+14
View File
@@ -442,6 +442,7 @@ static payload_rule_t id_prot_i_rules[] = {
{CERTIFICATE_V1, 0, 2, TRUE, FALSE},
{SIGNATURE_V1, 0, 1, TRUE, FALSE},
{HASH_V1, 0, 1, TRUE, FALSE},
{FRAGMENT_V1, 0, 1, FALSE, TRUE},
};
/**
@@ -461,6 +462,7 @@ static payload_order_t id_prot_i_order[] = {
{VENDOR_ID_V1, 0},
{NAT_D_V1, 0},
{NAT_D_DRAFT_00_03_V1, 0},
{FRAGMENT_V1, 0},
};
/**
@@ -480,6 +482,7 @@ static payload_rule_t id_prot_r_rules[] = {
{CERTIFICATE_V1, 0, 2, TRUE, FALSE},
{SIGNATURE_V1, 0, 1, TRUE, FALSE},
{HASH_V1, 0, 1, TRUE, FALSE},
{FRAGMENT_V1, 0, 1, FALSE, TRUE},
};
/**
@@ -499,6 +502,7 @@ static payload_order_t id_prot_r_order[] = {
{VENDOR_ID_V1, 0},
{NAT_D_V1, 0},
{NAT_D_DRAFT_00_03_V1, 0},
{FRAGMENT_V1, 0},
};
/**
@@ -518,6 +522,7 @@ static payload_rule_t aggressive_i_rules[] = {
{CERTIFICATE_V1, 0, 1, TRUE, FALSE},
{SIGNATURE_V1, 0, 1, TRUE, FALSE},
{HASH_V1, 0, 1, TRUE, FALSE},
{FRAGMENT_V1, 0, 1, FALSE, TRUE},
};
/**
@@ -537,6 +542,7 @@ static payload_order_t aggressive_i_order[] = {
{CERTIFICATE_REQUEST_V1, 0},
{NOTIFY_V1, 0},
{VENDOR_ID_V1, 0},
{FRAGMENT_V1, 0},
};
/**
@@ -556,6 +562,7 @@ static payload_rule_t aggressive_r_rules[] = {
{CERTIFICATE_V1, 0, 1, FALSE, FALSE},
{SIGNATURE_V1, 0, 1, FALSE, FALSE},
{HASH_V1, 0, 1, FALSE, FALSE},
{FRAGMENT_V1, 0, 1, FALSE, TRUE},
};
/**
@@ -575,6 +582,7 @@ static payload_order_t aggressive_r_order[] = {
{CERTIFICATE_REQUEST_V1, 0},
{NOTIFY_V1, 0},
{VENDOR_ID_V1, 0},
{FRAGMENT_V1, 0},
};
/**
@@ -1693,6 +1701,12 @@ METHOD(message_t, parse_header, status_t,
}
this->first_payload = ike_header->payload_interface.get_next_type(
&ike_header->payload_interface);
if (this->first_payload == FRAGMENT_V1 && this->is_encrypted)
{ /* racoon sets the encryted bit when sending a fragment, but these
* messages are really not encrypted */
this->is_encrypted = FALSE;
}
for (i = 0; i < countof(this->reserved); i++)
{
reserved = payload_get_field(&ike_header->payload_interface,
@@ -0,0 +1,225 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <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 "fragment_payload.h"
#include <encoding/payloads/encodings.h>
/** Flag that is set in case the given fragment is the last for the message */
#define LAST_FRAGMENT 0x01
typedef struct private_fragment_payload_t private_fragment_payload_t;
/**
* Private data of an fragment_payload_t object.
*/
struct private_fragment_payload_t {
/**
* Public fragment_payload_t interface.
*/
fragment_payload_t public;
/**
* Next payload type.
*/
u_int8_t next_payload;
/**
* Reserved byte
*/
u_int8_t reserved;
/**
* Length of this payload.
*/
u_int16_t payload_length;
/**
* Fragment ID.
*/
u_int16_t fragment_id;
/**
* Fragment number.
*/
u_int8_t fragment_number;
/**
* Flags
*/
u_int8_t flags;
/**
* The contained fragment data.
*/
chunk_t data;
};
/**
* Encoding rules for an IKEv1 fragment payload
*/
static encoding_rule_t encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_fragment_payload_t, next_payload) },
{ RESERVED_BYTE, offsetof(private_fragment_payload_t, reserved) },
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_fragment_payload_t, payload_length) },
{ U_INT_16, offsetof(private_fragment_payload_t, fragment_id) },
{ U_INT_8, offsetof(private_fragment_payload_t, fragment_number) },
{ U_INT_8, offsetof(private_fragment_payload_t, flags) },
/* Fragment data is of variable size */
{ CHUNK_DATA, offsetof(private_fragment_payload_t, data) },
};
/*
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload ! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Fragment ID ! Fragment Num ! Flags !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Fragment Data ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
METHOD(payload_t, verify, status_t,
private_fragment_payload_t *this)
{
if (this->fragment_number == 0)
{
return FAILED;
}
return SUCCESS;
}
METHOD(payload_t, get_encoding_rules, int,
private_fragment_payload_t *this, encoding_rule_t **rules)
{
*rules = encodings;
return countof(encodings);
}
METHOD(payload_t, get_header_length, int,
private_fragment_payload_t *this)
{
return 8;
}
METHOD(payload_t, get_type, payload_type_t,
private_fragment_payload_t *this)
{
return FRAGMENT_V1;
}
METHOD(payload_t, get_next_type, payload_type_t,
private_fragment_payload_t *this)
{
return this->next_payload;
}
METHOD(payload_t, set_next_type, void,
private_fragment_payload_t *this, payload_type_t type)
{
this->next_payload = type;
}
METHOD(payload_t, get_length, size_t,
private_fragment_payload_t *this)
{
return this->payload_length;
}
METHOD(fragment_payload_t, get_id, u_int16_t,
private_fragment_payload_t *this)
{
return this->fragment_id;
}
METHOD(fragment_payload_t, get_number, u_int8_t,
private_fragment_payload_t *this)
{
return this->fragment_number;
}
METHOD(fragment_payload_t, is_last, bool,
private_fragment_payload_t *this)
{
return (this->flags & LAST_FRAGMENT) == LAST_FRAGMENT;
}
METHOD(fragment_payload_t, get_data, chunk_t,
private_fragment_payload_t *this)
{
return this->data;
}
METHOD2(payload_t, fragment_payload_t, destroy, void,
private_fragment_payload_t *this)
{
free(this->data.ptr);
free(this);
}
/*
* Described in header
*/
fragment_payload_t *fragment_payload_create()
{
private_fragment_payload_t *this;
INIT(this,
.public = {
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
.get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
.get_type = _get_type,
.destroy = _destroy,
},
.get_id = _get_id,
.get_number = _get_number,
.is_last = _is_last,
.get_data = _get_data,
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
);
this->payload_length = get_header_length(this);
return &this->public;
}
/*
* Described in header
*/
fragment_payload_t *fragment_payload_create_from_data(u_int8_t num, bool last,
chunk_t data)
{
private_fragment_payload_t *this;
this = (private_fragment_payload_t*)fragment_payload_create();
this->fragment_id = 1;
this->fragment_number = num;
this->flags |= (last ? LAST_FRAGMENT : 0);
this->data = chunk_clone(data);
this->payload_length = get_header_length(this) + data.len;
return &this->public;
}
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <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 fragment_payload fragment_payload
* @{ @ingroup payloads
*/
#ifndef FRAGMENT_PAYLOAD_H_
#define FRAGMENT_PAYLOAD_H_
typedef struct fragment_payload_t fragment_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
/**
* Object representing an IKEv1 fragment payload.
*/
struct fragment_payload_t {
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
* Get the fragment ID. Identifies the fragments for a particular IKE
* message.
*
* @return fragment ID
*/
u_int16_t (*get_id)(fragment_payload_t *this);
/**
* Get the fragment number. Defines the order of the fragments.
*
* @return fragment number
*/
u_int8_t (*get_number)(fragment_payload_t *this);
/**
* Check if this is the last fragment.
*
* @return TRUE if this is the last fragment
*/
bool (*is_last)(fragment_payload_t *this);
/**
* Get the fragment data.
*
* @return chunkt to internal fragment data
*/
chunk_t (*get_data)(fragment_payload_t *this);
/**
* Destroys an fragment_payload_t object.
*/
void (*destroy)(fragment_payload_t *this);
};
/**
* Creates an empty fragment_payload_t object.
*
* @return fragment_payload_t object
*/
fragment_payload_t *fragment_payload_create();
/**
* Creates a fragment payload from the given data. All fragments currently
* have the same fragment ID (1), which seems what other implementations are
* doing.
*
* @param num fragment number (first one should be 1)
* @param last TRUE to indicate that this is the last fragment
* @param data fragment data (gets cloned)
* @return fragment_payload_t object
*/
fragment_payload_t *fragment_payload_create_from_data(u_int8_t num, bool last,
chunk_t data);
#endif /** FRAGMENT_PAYLOAD_H_ @}*/
+18 -11
View File
@@ -36,6 +36,7 @@
#include <encoding/payloads/configuration_attribute.h>
#include <encoding/payloads/eap_payload.h>
#include <encoding/payloads/hash_payload.h>
#include <encoding/payloads/fragment_payload.h>
#include <encoding/payloads/unknown_payload.h>
ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD,
@@ -79,15 +80,17 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWORD_METH
#ifdef ME
ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD,
"ID_PEER");
ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, ID_PEER,
ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, FRAGMENT_V1, ID_PEER,
"NAT_D_DRAFT_V1",
"NAT_OA_DRAFT_V1");
"NAT_OA_DRAFT_V1",
"FRAGMENT");
#else
ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, GENERIC_SECURE_PASSWORD_METHOD,
ENUM_NEXT(payload_type_names, NAT_D_DRAFT_00_03_V1, FRAGMENT_V1, GENERIC_SECURE_PASSWORD_METHOD,
"NAT_D_DRAFT_V1",
"NAT_OA_DRAFT_V1");
"NAT_OA_DRAFT_V1",
"FRAGMENT");
#endif /* ME */
ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, NAT_OA_DRAFT_00_03_V1,
ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, FRAGMENT_V1,
"HEADER",
"PROPOSAL_SUBSTRUCTURE",
"PROPOSAL_SUBSTRUCTURE_V1",
@@ -143,15 +146,17 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWOR
#ifdef ME
ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD,
"IDp");
ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, ID_PEER,
ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, FRAGMENT_V1, ID_PEER,
"NAT-D",
"NAT-OA");
"NAT-OA",
"FRAG");
#else
ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, NAT_OA_DRAFT_00_03_V1, GENERIC_SECURE_PASSWORD_METHOD,
ENUM_NEXT(payload_type_short_names, NAT_D_DRAFT_00_03_V1, FRAGMENT_V1, GENERIC_SECURE_PASSWORD_METHOD,
"NAT-D",
"NAT-OA");
"NAT-OA",
"FRAG");
#endif /* ME */
ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, NAT_OA_DRAFT_00_03_V1,
ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, FRAGMENT_V1,
"HDR",
"PROP",
"PROP",
@@ -240,6 +245,8 @@ payload_t *payload_create(payload_type_t type)
case ENCRYPTED:
case ENCRYPTED_V1:
return (payload_t*)encryption_payload_create(type);
case FRAGMENT_V1:
return (payload_t*)fragment_payload_create();
default:
return (payload_t*)unknown_payload_create(type);
}
@@ -272,7 +279,7 @@ bool payload_is_known(payload_type_t type)
return TRUE;
}
#endif
if (type >= NAT_D_DRAFT_00_03_V1 && type <= NAT_OA_DRAFT_00_03_V1)
if (type >= NAT_D_DRAFT_00_03_V1 && type <= FRAGMENT_V1)
{
return TRUE;
}
@@ -230,6 +230,11 @@ enum payload_type_t {
*/
NAT_OA_DRAFT_00_03_V1 = 131,
/**
* IKE fragment (proprietary IKEv1 extension)
*/
FRAGMENT_V1 = 132,
/**
* Header has a value of PRIVATE USE space.
*
+4 -2
View File
@@ -94,10 +94,11 @@ METHOD(sender_t, send_, void,
{
host_t *src, *dst;
/* if neither source nor destination port is 500 we add a Non-ESP marker */
src = packet->get_source(packet);
dst = packet->get_destination(packet);
DBG1(DBG_NET, "sending packet: from %#H to %#H", src, dst);
DBG1(DBG_NET, "sending packet: from %#H to %#H (%zu bytes)", src, dst,
packet->get_data(packet).len);
if (this->send_delay)
{
@@ -120,6 +121,7 @@ METHOD(sender_t, send_, void,
message->destroy(message);
}
/* if neither source nor destination port is 500 we add a Non-ESP marker */
if (dst->get_port(dst) != IKEV2_UDP_PORT &&
src->get_port(src) != IKEV2_UDP_PORT)
{
@@ -266,7 +266,7 @@ static job_requeue_t initiate(private_android_service_t *this)
ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE,
charon->socket->get_port(charon->socket, FALSE),
hostname, FALSE, IKEV2_UDP_PORT);
hostname, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO);
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
peer_cfg = peer_cfg_create("android", ike_cfg, CERT_SEND_IF_ASKED,
+1 -1
View File
@@ -205,7 +205,7 @@ static void setup_tunnel(private_ha_tunnel_t *this,
/* create config and backend */
ike_cfg = ike_cfg_create(IKEV2, FALSE, FALSE, local, FALSE,
charon->socket->get_port(charon->socket, FALSE),
remote, FALSE, IKEV2_UDP_PORT);
remote, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO);
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
peer_cfg = peer_cfg_create("ha", ike_cfg, CERT_NEVER_SEND,
UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, 30,
@@ -490,14 +490,16 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num)
{
ike_cfg = ike_cfg_create(this->version, TRUE, FALSE,
local, FALSE, this->port + num - 1,
remote, FALSE, IKEV2_NATT_PORT);
remote, FALSE, IKEV2_NATT_PORT,
FRAGMENTATION_NO);
}
else
{
ike_cfg = ike_cfg_create(this->version, TRUE, FALSE,
local, FALSE,
charon->socket->get_port(charon->socket, FALSE),
remote, FALSE, IKEV2_UDP_PORT);
remote, FALSE, IKEV2_UDP_PORT,
FRAGMENTATION_NO);
}
ike_cfg->add_proposal(ike_cfg, this->proposal->clone(this->proposal));
peer_cfg = peer_cfg_create("load-test", ike_cfg,
+1 -1
View File
@@ -325,7 +325,7 @@ static gboolean initiate_connection(private_maemo_service_t *this,
ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE,
charon->socket->get_port(charon->socket, FALSE),
hostname, FALSE, IKEV2_UDP_PORT);
hostname, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO);
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
peer_cfg = peer_cfg_create(this->current, ike_cfg,
+3 -2
View File
@@ -105,7 +105,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*,
ike_cfg = ike_cfg_create(IKEV2, FALSE, FALSE,
"0.0.0.0", FALSE,
charon->socket->get_port(charon->socket, FALSE),
address, FALSE, IKEV2_UDP_PORT);
address, FALSE, IKEV2_UDP_PORT, FRAGMENTATION_NO);
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
med_cfg = peer_cfg_create(
"mediation", ike_cfg,
@@ -380,7 +380,8 @@ medcli_config_t *medcli_config_create(database_t *db)
.ike = ike_cfg_create(IKEV2, FALSE, FALSE,
"0.0.0.0", FALSE,
charon->socket->get_port(charon->socket, FALSE),
"0.0.0.0", FALSE, IKEV2_UDP_PORT),
"0.0.0.0", FALSE, IKEV2_UDP_PORT,
FRAGMENTATION_NO),
);
this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE));
+2 -1
View File
@@ -142,7 +142,8 @@ medsrv_config_t *medsrv_config_create(database_t *db)
.ike = ike_cfg_create(IKEV2, FALSE, FALSE,
"0.0.0.0", FALSE,
charon->socket->get_port(charon->socket, FALSE),
"0.0.0.0", FALSE, IKEV2_UDP_PORT),
"0.0.0.0", FALSE, IKEV2_UDP_PORT,
FRAGMENTATION_NO),
);
this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE));
+2 -1
View File
@@ -261,7 +261,8 @@ static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e,
ike_cfg = ike_cfg_create(IKEV2, certreq, force_encap,
local, FALSE,
charon->socket->get_port(charon->socket, FALSE),
remote, FALSE, IKEV2_UDP_PORT);
remote, FALSE, IKEV2_UDP_PORT,
FRAGMENTATION_NO);
add_ike_proposals(this, ike_cfg, id);
return ike_cfg;
}
+2 -1
View File
@@ -233,7 +233,8 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg
ikeport,
msg->add_conn.other.address,
msg->add_conn.other.allow_any,
msg->add_conn.other.ikeport);
msg->add_conn.other.ikeport,
msg->add_conn.fragmentation);
add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL);
return ike_cfg;
}
+4 -2
View File
@@ -155,7 +155,8 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool,
ike_cfg = ike_cfg_create(IKEV2, FALSE, FALSE,
local_addr, FALSE,
charon->socket->get_port(charon->socket, FALSE),
remote_addr, FALSE, IKEV2_UDP_PORT);
remote_addr, FALSE, IKEV2_UDP_PORT,
FRAGMENTATION_NO);
ike_cfg->add_proposal(ike_cfg, create_proposal(ike_proposal, PROTO_IKE));
this->peer_cfg = peer_cfg_create(
name, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO,
@@ -253,7 +254,8 @@ METHOD(enumerator_t, ike_enumerator_enumerate, bool,
this->ike_cfg = ike_cfg_create(IKEV2, FALSE, FALSE,
local_addr, FALSE,
charon->socket->get_port(charon->socket, FALSE),
remote_addr, FALSE, IKEV2_UDP_PORT);
remote_addr, FALSE, IKEV2_UDP_PORT,
FRAGMENTATION_NO);
this->ike_cfg->add_proposal(this->ike_cfg,
create_proposal(ike_proposal, PROTO_IKE));
@@ -67,9 +67,10 @@ METHOD(job_t, execute, job_requeue_t,
this->message);
if (ike_sa)
{
DBG1(DBG_NET, "received packet: from %#H to %#H",
DBG1(DBG_NET, "received packet: from %#H to %#H (%zu bytes)",
this->message->get_source(this->message),
this->message->get_destination(this->message));
this->message->get_destination(this->message),
this->message->get_packet_data(this->message).len);
if (ike_sa->process_message(ike_sa, this->message) == DESTROY_ME)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+2 -1
View File
@@ -1232,7 +1232,8 @@ METHOD(ike_sa_t, process_message, status_t,
case IKE_SA_INIT:
case IKE_AUTH:
if (this->state != IKE_CREATED &&
this->state != IKE_CONNECTING)
this->state != IKE_CONNECTING &&
message->get_first_payload_type(message) != FRAGMENT_V1)
{
DBG1(DBG_IKE, "ignoring %N in established IKE_SA state",
exchange_type_names, message->get_exchange_type(message));
+5
View File
@@ -126,6 +126,11 @@ enum ike_extension_t {
* draft-ietf-ipsec-nat-t-ike-02 .. -03
*/
EXT_NATT_DRAFT_02_03 = (1<<10),
/**
* peer support proprietary IKE fragmentation
*/
EXT_IKE_FRAGMENTATION = (1<<11),
};
/**
+28 -2
View File
@@ -968,14 +968,37 @@ static u_int64_t get_spi(private_ike_sa_manager_t *this)
static bool get_init_hash(private_ike_sa_manager_t *this, message_t *message,
chunk_t *hash)
{
host_t *src;
if (!this->hasher)
{ /* this might be the case when flush() has been called */
return FALSE;
}
if (message->get_first_payload_type(message) == FRAGMENT_V1)
{ /* only hash the source IP, port and SPI for fragmented init messages */
u_int16_t port;
u_int64_t spi;
src = message->get_source(message);
if (!this->hasher->allocate_hash(this->hasher,
src->get_address(src), NULL))
{
return FALSE;
}
port = src->get_port(src);
if (!this->hasher->allocate_hash(this->hasher,
chunk_from_thing(port), NULL))
{
return FALSE;
}
spi = message->get_initiator_spi(message);
return this->hasher->allocate_hash(this->hasher,
chunk_from_thing(spi), hash);
}
if (message->get_exchange_type(message) == ID_PROT)
{ /* include the source for Main Mode as the hash will be the same if
* SPIs are reused by two initiators that use the same proposal */
host_t *src = message->get_source(message);
src = message->get_source(message);
if (!this->hasher->allocate_hash(this->hasher,
src->get_address(src), NULL))
@@ -1280,7 +1303,10 @@ 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;
entry->message_id = message->get_message_id(message);
if (message->get_first_payload_type(message) != FRAGMENT_V1)
{
entry->message_id = message->get_message_id(message);
}
if (ike_id->get_responder_spi(ike_id) == 0)
{
ike_id->set_responder_spi(ike_id, id->get_responder_spi(id));
+327 -17
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2011 Tobias Brunner
* Copyright (C) 2007-2013 Tobias Brunner
* Copyright (C) 2007-2011 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -36,6 +36,10 @@
#include <processing/jobs/retransmit_job.h>
#include <processing/jobs/delete_ike_sa_job.h>
#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>
/**
* Number of old messages hashes we keep for retransmission.
@@ -46,6 +50,20 @@
*/
#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.
*
@@ -160,19 +178,65 @@ struct private_task_manager_t {
packet_t *packet;
/**
* type of the initated exchange
* type of the initiated exchange
*/
exchange_type_t type;
} initiating;
/**
* Data used to reassemble a fragmented message
*/
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;
/**
* List of queued tasks not yet in action
*/
linked_list_t *queued_tasks;
/**
* List of active tasks, initiated by ourselve
* List of active tasks, initiated by ourselves
*/
linked_list_t *active_tasks;
@@ -212,6 +276,34 @@ struct private_task_manager_t {
u_int32_t dpd_recv;
};
/**
* A single fragment within a fragmented message
*/
typedef struct {
/** fragment number */
u_int8_t num;
/** fragment data */
chunk_t data;
} fragment_t;
static void fragment_destroy(fragment_t *this)
{
chunk_free(&this->data);
free(this);
}
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;
}
METHOD(task_manager_t, flush_queue, void,
private_task_manager_t *this, task_queue_t queue)
{
@@ -282,11 +374,94 @@ static bool activate_task(private_task_manager_t *this, task_type_t type)
return found;
}
/**
* Send a single fragment with the given data
*/
static bool send_fragment(private_task_manager_t *this, bool request,
host_t *src, host_t *dst, fragment_payload_t *fragment)
{
message_t *message;
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);
status = this->ike_sa->generate_message(this->ike_sa, message, &packet);
if (status != SUCCESS)
{
DBG1(DBG_IKE, "failed to generate IKE fragment");
message->destroy(message);
return FALSE;
}
charon->sender->send(charon->sender, packet);
message->destroy(message);
return TRUE;
}
/**
* Send a packet, if supported and required do so in fragments
*/
static bool send_packet(private_task_manager_t *this, bool request,
packet_t *packet)
{
fragmentation_t fragmentation;
ike_cfg_t *ike_cfg;
host_t *src, *dst;
chunk_t data;
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
fragmentation = ike_cfg->fragmentation(ike_cfg);
data = packet->get_data(packet);
if (data.len > this->frag.size && (fragmentation == FRAGMENTATION_FORCE ||
(this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_FRAGMENTATION) &&
fragmentation == FRAGMENTATION_YES)))
{
fragment_payload_t *fragment;
u_int8_t num, count;
size_t len, frag_size;
bool nat;
/* reduce size due to non-ESP marker */
nat = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
frag_size = this->frag.size - (nat ? 4 : 0);
src = packet->get_source(packet);
dst = packet->get_destination(packet);
count = (data.len / (frag_size + 1)) + 1;
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, u_int32_t seqnr,
u_int mid, u_int retransmitted, packet_t *packet)
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)
{
u_int32_t t;
@@ -305,7 +480,10 @@ static status_t retransmit_packet(private_task_manager_t *this, u_int32_t seqnr,
mid, seqnr < RESPONDING_SEQ ? seqnr : seqnr - RESPONDING_SEQ);
charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND, packet);
}
charon->sender->send(charon->sender, packet->clone(packet));
if (!send_packet(this, request, packet->clone(packet)))
{
return DESTROY_ME;
}
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;
@@ -318,7 +496,7 @@ METHOD(task_manager_t, retransmit, status_t,
if (seqnr == this->initiating.seqnr && this->initiating.packet)
{
status = retransmit_packet(this, seqnr, this->initiating.mid,
status = retransmit_packet(this, TRUE, seqnr, this->initiating.mid,
this->initiating.retransmitted, this->initiating.packet);
if (status == NEED_MORE)
{
@@ -328,7 +506,7 @@ METHOD(task_manager_t, retransmit, status_t,
}
if (seqnr == this->responding.seqnr && this->responding.packet)
{
status = retransmit_packet(this, seqnr, this->responding.mid,
status = retransmit_packet(this, FALSE, seqnr, this->responding.mid,
this->responding.retransmitted, this->responding.packet);
if (status == NEED_MORE)
{
@@ -604,12 +782,12 @@ METHOD(task_manager_t, initiate, status_t,
}
if (keep)
{ /* keep the packet for retransmission, the responder might request it */
charon->sender->send(charon->sender,
send_packet(this, TRUE,
this->initiating.packet->clone(this->initiating.packet));
}
else
{
charon->sender->send(charon->sender, this->initiating.packet);
send_packet(this, TRUE, this->initiating.packet);
this->initiating.packet = NULL;
}
message->destroy(message);
@@ -713,8 +891,8 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
{
return retransmit(this, this->responding.seqnr);
}
charon->sender->send(charon->sender,
this->responding.packet->clone(this->responding.packet));
send_packet(this, FALSE,
this->responding.packet->clone(this->responding.packet));
if (delete)
{
return DESTROY_ME;
@@ -769,7 +947,7 @@ static void send_notify(private_task_manager_t *this, message_t *request,
if (this->ike_sa->generate_message(this->ike_sa, response,
&packet) == SUCCESS)
{
charon->sender->send(charon->sender, packet);
send_packet(this, TRUE, packet);
}
response->destroy(response);
}
@@ -868,6 +1046,7 @@ 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)
@@ -1038,6 +1217,114 @@ static status_t process_response(private_task_manager_t *this,
return initiate(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;
payload = (fragment_payload_t*)msg->get_payload(msg, FRAGMENT_V1);
if (!payload)
{
return FAILED;
}
if (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)
{
break;
}
}
data = payload->get_data(payload);
this->frag.len += data.len;
if (this->frag.len > this->frag.max_packet)
{
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);
status = NEED_MORE;
}
return status;
}
/**
* Parse the given message and verify that it is valid.
*/
@@ -1085,6 +1372,11 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg)
return DESTROY_ME;
}
}
if (msg->get_first_payload_type(msg) == FRAGMENT_V1)
{
return handle_fragment(this, msg);
}
return status;
}
@@ -1111,8 +1403,8 @@ METHOD(task_manager_t, process_message, status_t,
{
DBG1(DBG_IKE, "received retransmit of response with ID %u, "
"resending last request", mid);
charon->sender->send(charon->sender,
this->initiating.packet->clone(this->initiating.packet));
send_packet(this, TRUE,
this->initiating.packet->clone(this->initiating.packet));
return SUCCESS;
}
DBG1(DBG_IKE, "received retransmit of response with ID %u, "
@@ -1129,6 +1421,10 @@ METHOD(task_manager_t, process_message, status_t,
msg->set_request(msg, FALSE);
charon->bus->message(charon->bus, msg, TRUE, FALSE);
status = parse_message(this, msg);
if (status == NEED_MORE)
{
return SUCCESS;
}
if (status != SUCCESS)
{
return status;
@@ -1153,7 +1449,7 @@ METHOD(task_manager_t, process_message, status_t,
{
DBG1(DBG_IKE, "received retransmit of request with ID %u, "
"retransmitting response", mid);
charon->sender->send(charon->sender,
send_packet(this, FALSE,
this->responding.packet->clone(this->responding.packet));
}
else if (this->initiating.packet &&
@@ -1161,7 +1457,7 @@ METHOD(task_manager_t, process_message, status_t,
{
DBG1(DBG_IKE, "received retransmit of DPD request, "
"retransmitting response");
charon->sender->send(charon->sender,
send_packet(this, TRUE,
this->initiating.packet->clone(this->initiating.packet));
}
else
@@ -1196,6 +1492,10 @@ METHOD(task_manager_t, process_message, status_t,
msg->set_request(msg, TRUE);
charon->bus->message(charon->bus, msg, TRUE, FALSE);
status = parse_message(this, msg);
if (status == NEED_MORE)
{
return SUCCESS;
}
if (status != SUCCESS)
{
return status;
@@ -1288,6 +1588,7 @@ METHOD(task_manager_t, queue_ike, void,
{
queue_task(this, (task_t*)aggressive_mode_create(this->ike_sa, TRUE));
}
this->frag.exchange = AGGRESSIVE;
}
else
{
@@ -1591,6 +1892,7 @@ METHOD(task_manager_t, reset, void,
this->initiating.seqnr = 0;
this->initiating.retransmitted = 0;
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
clear_fragments(this, 0);
if (initiate != UINT_MAX)
{
this->dpd_send = initiate;
@@ -1641,6 +1943,7 @@ 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->queued);
DESTROY_IF(this->responding.packet);
@@ -1687,6 +1990,13 @@ 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, charon->name),
.size = lib->settings->get_int(lib->settings,
"%s.fragment_size", MAX_FRAGMENT_SIZE, charon->name),
},
.ike_sa = ike_sa,
.rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK),
.queued_tasks = linked_list_create(),
+44 -5
View File
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -99,6 +100,11 @@ static struct {
{ "Cisco Unity", EXT_CISCO_UNITY, FALSE, 16,
"\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00"},
/* Proprietary IKE fragmentation extension. Capabilities are handled
* specially on receipt of this VID. */
{ "FRAGMENTATION", EXT_IKE_FRAGMENTATION, FALSE, 20,
"\x40\x48\xb7\xd5\x6e\xbc\xe8\x85\x25\xe7\xde\x7f\x00\xd6\xc2\xd3\x80\x00\x00\x00"},
}, vendor_natt_ids[] = {
/* NAT-Traversal VIDs ordered by preference */
@@ -145,24 +151,55 @@ static struct {
{ "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16,
"\x27\xba\xb5\xdc\x01\xea\x07\x60\xea\x4e\x31\x90\xac\x27\xc0\xd0"},
};
/**
* According to racoon 0x80000000 seems to indicate support for fragmentation
* of Aggressive and Main mode messages. 0x40000000 seems to indicate support
* for fragmentation of base ISAKMP messages (Cisco adds that and thus sends
* 0xc0000000)
*/
static const u_int32_t fragmentation_ike = 0x80000000;
/**
* Check if the given vendor ID indicate support for fragmentation
*/
static bool fragmentation_supported(chunk_t data, int i)
{
if (vendor_ids[i].extension == EXT_IKE_FRAGMENTATION &&
data.len == 20 && memeq(data.ptr, vendor_ids[i].id, 16))
{
return untoh32(&data.ptr[16]) & fragmentation_ike;
}
return FALSE;
}
METHOD(task_t, build, status_t,
private_isakmp_vendor_t *this, message_t *message)
{
vendor_id_payload_t *vid_payload;
bool strongswan, cisco_unity;
bool strongswan, cisco_unity, fragmentation;
ike_cfg_t *ike_cfg;
int i;
strongswan = lib->settings->get_bool(lib->settings,
"%s.send_vendor_id", FALSE, charon->name);
"%s.send_vendor_id", FALSE, charon->name);
cisco_unity = lib->settings->get_bool(lib->settings,
"%s.cisco_unity", FALSE, charon->name);
"%s.cisco_unity", FALSE, charon->name);
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
fragmentation = ike_cfg->fragmentation(ike_cfg) != FRAGMENTATION_NO;
if (!this->initiator && fragmentation)
{
fragmentation = this->ike_sa->supports_extension(this->ike_sa,
EXT_IKE_FRAGMENTATION);
}
for (i = 0; i < countof(vendor_ids); i++)
{
if (vendor_ids[i].send ||
(vendor_ids[i].extension == EXT_STRONGSWAN && strongswan) ||
(vendor_ids[i].extension == EXT_CISCO_UNITY && cisco_unity))
(vendor_ids[i].extension == EXT_CISCO_UNITY && cisco_unity) ||
(vendor_ids[i].extension == EXT_IKE_FRAGMENTATION && fragmentation))
{
DBG2(DBG_IKE, "sending %s vendor ID", vendor_ids[i].desc);
vid_payload = vendor_id_payload_create_data(VENDOR_ID_V1,
@@ -175,6 +212,7 @@ METHOD(task_t, build, status_t,
if ((this->initiator && vendor_natt_ids[i].send) ||
this->best_natt_ext == i)
{
DBG2(DBG_IKE, "sending %s vendor ID", vendor_natt_ids[i].desc);
vid_payload = vendor_id_payload_create_data(VENDOR_ID_V1,
chunk_clone(chunk_create(vendor_natt_ids[i].id,
vendor_natt_ids[i].len)));
@@ -206,7 +244,8 @@ METHOD(task_t, process, status_t,
for (i = 0; i < countof(vendor_ids); i++)
{
if (chunk_equals(data, chunk_create(vendor_ids[i].id,
vendor_ids[i].len)))
vendor_ids[i].len)) ||
fragmentation_supported(data, i))
{
DBG1(DBG_IKE, "received %s vendor ID", vendor_ids[i].desc);
if (vendor_ids[i].extension)
+8
View File
@@ -108,6 +108,13 @@ static const char *LST_authby[] = {
NULL
};
static const char *LST_fragmentation[] = {
"no",
"yes",
"force",
NULL
};
typedef struct {
arg_t type;
size_t offset;
@@ -138,6 +145,7 @@ static const token_info_t token_info[] =
{ ARG_STR, offsetof(starter_conn_t, aaa_identity), NULL },
{ ARG_MISC, 0, NULL /* KW_MOBIKE */ },
{ ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ },
{ ARG_ENUM, offsetof(starter_conn_t, fragmentation), LST_fragmentation },
{ ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL },
{ ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL },
{ ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL },
+9 -1
View File
@@ -50,7 +50,7 @@ typedef enum {
typedef enum {
STRICT_NO,
STRICT_YES,
STRICT_IFURI
STRICT_IFURI,
} strict_t;
typedef enum {
@@ -69,6 +69,13 @@ typedef enum {
DPD_ACTION_UNKNOW,
} dpd_action_t;
typedef enum {
/* same as in ike_cfg.h */
FRAGMENTATION_NO,
FRAGMENTATION_YES,
FRAGMENTATION_FORCE,
} fragmentation_t;
typedef enum {
/* IPsec options */
SA_OPTION_AUTHENTICATE = 1 << 0, /* use AH instead of ESP? */
@@ -140,6 +147,7 @@ struct starter_conn {
char *authby;
ipsec_mode_t mode;
bool proxy_mode;
fragmentation_t fragmentation;
sa_option_t options;
time_t sa_ike_life_seconds;
time_t sa_ipsec_life_seconds;
+1
View File
@@ -42,6 +42,7 @@ typedef enum {
KW_AAA_IDENTITY,
KW_MOBIKE,
KW_FORCEENCAPS,
KW_FRAGMENTATION,
KW_IKELIFETIME,
KW_KEYLIFE,
KW_REKEYMARGIN,
+1
View File
@@ -40,6 +40,7 @@ eap_identity, KW_EAP_IDENTITY
aaa_identity, KW_AAA_IDENTITY
mobike, KW_MOBIKE
forceencaps, KW_FORCEENCAPS
fragmentation, KW_FRAGMENTATION
ikelifetime, KW_IKELIFETIME
lifetime, KW_KEYLIFE
keylife, KW_KEYLIFE
+1
View File
@@ -180,6 +180,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn)
}
msg.add_conn.mobike = conn->options & SA_OPTION_MOBIKE;
msg.add_conn.force_encap = conn->options & SA_OPTION_FORCE_ENCAP;
msg.add_conn.fragmentation = conn->fragmentation;
msg.add_conn.ipcomp = conn->options & SA_OPTION_COMPRESS;
msg.add_conn.install_policy = conn->install_policy;
msg.add_conn.aggressive = conn->aggressive;
+1
View File
@@ -254,6 +254,7 @@ struct stroke_msg_t {
int mobike;
int aggressive;
int force_encap;
int fragmentation;
int ipcomp;
time_t inactivity;
int proxy_mode;