Merge branch 'ikev1-fragmentation'
This adds support for the proprietary IKEv1 fragmentation extension. Conflicts: NEWS
This commit is contained in:
@@ -35,6 +35,10 @@ strongswan-5.0.2
|
||||
In contrast to our own DER parser, OpenSSL can handle BER files, which is
|
||||
required for interoperability of our scepclient with EJBCA.
|
||||
|
||||
- Support for the proprietary IKEv1 fragmentation extension has been added.
|
||||
Fragments are always handled on receipt but only sent if supported by the peer
|
||||
and if enabled with the new fragmentation ipsec.conf option.
|
||||
|
||||
- IKEv1 in charon can now parse certificates received in PKCS#7 containers and
|
||||
supports NAT traversal as used by Windows clients. Patches courtesy of
|
||||
Volker Rümelin.
|
||||
|
||||
@@ -403,6 +403,21 @@ force UDP encapsulation for ESP packets even if no NAT situation is detected.
|
||||
This may help to surmount restrictive firewalls. In order to force the peer to
|
||||
encapsulate packets, NAT detection payloads are faked.
|
||||
.TP
|
||||
.BR fragmentation " = yes | force | " no
|
||||
whether to use IKE fragmentation (proprietary IKEv1 extension). Acceptable
|
||||
values are
|
||||
.BR yes ,
|
||||
.B force
|
||||
and
|
||||
.B no
|
||||
(the default). Fragmented messages sent by a peer are always accepted
|
||||
irrespective of the value of this option. If set to
|
||||
.BR yes ,
|
||||
and the peer supports it, larger IKE messages will be sent in fragments.
|
||||
If set to
|
||||
.B force
|
||||
the initial IKE message will already be fragmented if required.
|
||||
.TP
|
||||
.BR ike " = <cipher suites>"
|
||||
comma-separated list of IKE/ISAKMP SA encryption/authentication algorithms
|
||||
to be used, e.g.
|
||||
|
||||
@@ -164,6 +164,10 @@ are released to free memory once an IKE_SA is established.
|
||||
Enabling this might conflict with plugins that later need access to e.g. the
|
||||
used certificates.
|
||||
.TP
|
||||
.BR charon.fragment_size " [512]"
|
||||
Maximum size (in bytes) of a sent fragment when using the proprietary IKEv1
|
||||
fragmentation extension.
|
||||
.TP
|
||||
.BR charon.half_open_timeout " [30]"
|
||||
Timeout in seconds for connecting IKE_SAs (also see IKE_SA_INIT DROPPING).
|
||||
.TP
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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_ @}*/
|
||||
|
||||
@@ -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_ @}*/
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -42,6 +42,7 @@ typedef enum {
|
||||
KW_AAA_IDENTITY,
|
||||
KW_MOBIKE,
|
||||
KW_FORCEENCAPS,
|
||||
KW_FRAGMENTATION,
|
||||
KW_IKELIFETIME,
|
||||
KW_KEYLIFE,
|
||||
KW_REKEYMARGIN,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user