aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/encoding
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2014-06-12 10:14:00 +0200
committerTobias Brunner <tobias@strongswan.org>2014-10-10 09:30:26 +0200
commit2e7a2c06a1121b2b1b6ce8f17860dbda081cf89d (patch)
tree189c87c8fde4653d64b73bf85abf6f5b3b070a9a /src/libcharon/encoding
parente0b35142c1c72144bf251d23aa5b494b525d3a92 (diff)
downloadstrongswan-2e7a2c06a1121b2b1b6ce8f17860dbda081cf89d.tar.bz2
strongswan-2e7a2c06a1121b2b1b6ce8f17860dbda081cf89d.tar.xz
message: fragment() generates message and fragments and caches them
Diffstat (limited to 'src/libcharon/encoding')
-rw-r--r--src/libcharon/encoding/message.c91
-rw-r--r--src/libcharon/encoding/message.h34
2 files changed, 98 insertions, 27 deletions
diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c
index 44221b6ae..31f8c14aa 100644
--- a/src/libcharon/encoding/message.c
+++ b/src/libcharon/encoding/message.c
@@ -878,6 +878,11 @@ struct private_message_t {
packet_t *packet;
/**
+ * Array of generated fragments (if any), as packet_t*.
+ */
+ array_t *fragments;
+
+ /**
* Linked List where payload data are stored in.
*/
linked_list_t *payloads;
@@ -1051,6 +1056,12 @@ METHOD(message_t, is_encoded, bool,
return this->packet->get_data(this->packet).ptr != NULL;
}
+METHOD(message_t, is_fragmented, bool,
+ private_message_t *this)
+{
+ return array_count(this->fragments) > 0;
+}
+
METHOD(message_t, add_payload, void,
private_message_t *this, payload_t *payload)
{
@@ -1341,6 +1352,8 @@ static void order_payloads(private_message_t *this)
payload_t *payload;
int i;
+ DBG2(DBG_ENC, "order payloads in message");
+
/* move to temp list */
list = linked_list_create();
while (this->payloads->remove_last(this->payloads,
@@ -1669,6 +1682,7 @@ static message_t *clone_message(private_message_t *this)
dst = this->packet->get_destination(this->packet);
message = message_create(this->major_version, this->minor_version);
+ message->set_ike_sa_id(message, this->ike_sa_id);
message->set_message_id(message, this->message_id);
message->set_request(message, this->is_request);
message->set_source(message, src->clone(src));
@@ -1685,36 +1699,64 @@ static message_t *create_fragment(private_message_t *this, u_int8_t num,
{
fragment_payload_t *fragment;
message_t *message;
+ peer_cfg_t *peer_cfg;
+ ike_sa_t *ike_sa;
fragment = fragment_payload_create_from_data(num, last, data);
message = clone_message(this);
+ /* other implementations seem to just use 0 as message ID, so here we go */
+ message->set_message_id(message, 0);
+ /* always use the initial message type for fragments, even for quick mode
+ * or transaction messages. */
+ ike_sa = charon->bus->get_sa(charon->bus);
+ if (ike_sa && (peer_cfg = ike_sa->get_peer_cfg(ike_sa)) &&
+ peer_cfg->use_aggressive(peer_cfg))
+ {
+ message->set_exchange_type(message, AGGRESSIVE);
+ }
+ else
+ {
+ message->set_exchange_type(message, ID_PROT);
+ }
message->add_payload(message, (payload_t*)fragment);
return message;
}
/**
- * Destroy all messages in the given array
+ * Destroy all fragments
*/
-CALLBACK(destroy_fragments, void,
- array_t *fragments)
+static void clear_fragments(private_message_t *this)
{
- array_destroy_offset(fragments, offsetof(message_t, destroy));
+ array_destroy_offset(this->fragments, offsetof(packet_t, destroy));
+ this->fragments = NULL;
}
METHOD(message_t, fragment, status_t,
- private_message_t *this, size_t frag_len, enumerator_t **fragments)
+ private_message_t *this, keymat_t *keymat, size_t frag_len,
+ enumerator_t **fragments)
{
- array_t *messages;
message_t *fragment;
+ packet_t *packet;
u_int8_t num, count;
host_t *src, *dst;
chunk_t data;
+ status_t status;
size_t len;
- if (!is_encoded(this) || this->major_version == IKEV2_MAJOR_VERSION)
+ if (this->major_version == IKEV2_MAJOR_VERSION)
{
return INVALID_STATE;
}
+ clear_fragments(this);
+
+ if (!is_encoded(this))
+ {
+ status = generate(this, keymat, NULL);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ }
src = this->packet->get_source(this->packet);
dst = this->packet->get_destination(this->packet);
@@ -1736,13 +1778,14 @@ METHOD(message_t, fragment, status_t,
data = this->packet->get_data(this->packet);
if (data.len <= frag_len)
{
- return ALREADY_DONE;
+ *fragments = enumerator_create_single(this->packet, NULL);
+ return SUCCESS;
}
/* overhead for the fragmentation payload header */
frag_len -= 8;
count = data.len / frag_len + (data.len % frag_len ? 1 : 0);
- messages = array_create(0, count);
+ this->fragments = array_create(0, count);
DBG2(DBG_ENC, "splitting IKE message with length of %zu bytes into "
"%hhu fragments", data.len, count);
for (num = 1; num <= count; num++)
@@ -1750,34 +1793,39 @@ METHOD(message_t, fragment, status_t,
len = min(data.len, frag_len);
fragment = create_fragment(this, num, num == count,
chunk_create(data.ptr, len));
- array_insert(messages, ARRAY_TAIL, fragment);
+ status = fragment->generate(fragment, keymat, &packet);
+ fragment->destroy(fragment);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "failed to generate IKE fragment");
+ clear_fragments(this);
+ return FAILED;
+ }
+ array_insert(this->fragments, ARRAY_TAIL, packet);
data = chunk_skip(data, len);
}
- *fragments = enumerator_create_cleaner(array_create_enumerator(messages),
- destroy_fragments, messages);
+ *fragments = array_create_enumerator(this->fragments);
return SUCCESS;
}
METHOD(message_t, get_packet, packet_t*,
private_message_t *this)
{
- if (this->packet == NULL)
- {
- return NULL;
- }
return this->packet->clone(this->packet);
}
METHOD(message_t, get_packet_data, chunk_t,
private_message_t *this)
{
- if (this->packet == NULL)
- {
- return chunk_empty;
- }
return this->packet->get_data(this->packet);
}
+METHOD(message_t, get_fragments, enumerator_t*,
+ private_message_t *this)
+{
+ return array_create_enumerator(this->fragments);
+}
+
METHOD(message_t, parse_header, status_t,
private_message_t *this)
{
@@ -2264,6 +2312,7 @@ METHOD(message_t, destroy, void,
{
DESTROY_IF(this->ike_sa_id);
this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy));
+ array_destroy_offset(this->fragments, offsetof(packet_t, destroy));
this->packet->destroy(this->packet);
this->parser->destroy(this->parser);
free(this);
@@ -2301,6 +2350,7 @@ message_t *message_create_from_packet(packet_t *packet)
.disable_sort = _disable_sort,
.generate = _generate,
.is_encoded = _is_encoded,
+ .is_fragmented = _is_fragmented,
.fragment = _fragment,
.set_source = _set_source,
.get_source = _get_source,
@@ -2314,6 +2364,7 @@ message_t *message_create_from_packet(packet_t *packet)
.parse_body = _parse_body,
.get_packet = _get_packet,
.get_packet_data = _get_packet_data,
+ .get_fragments = _get_fragments,
.destroy = _destroy,
},
.exchange_type = EXCHANGE_TYPE_UNDEFINED,
diff --git a/src/libcharon/encoding/message.h b/src/libcharon/encoding/message.h
index bd329657a..e8db51ce5 100644
--- a/src/libcharon/encoding/message.h
+++ b/src/libcharon/encoding/message.h
@@ -265,25 +265,38 @@ struct message_t {
bool (*is_encoded)(message_t *this);
/**
- * Split the (generated) message into fragments of the given size (total IP
+ * Generates the message split into fragments of the given size (total IP
* datagram length).
*
* @note Only supported for IKEv1 at the moment.
*
+ * @param keymat keymat to encrypt/sign message(s)
* @param frag_len fragment length (maximum total IP datagram length), 0
* for default value depending on address family
- * @param fragments receives an enumerator with message_t* (not generated),
+ * @param fragments receives an enumerator with generated packet_t*,
* which are owned by the enumerator
* @return
* - SUCCESS if message could be fragmented
- * - ALREADY_DONE if message does not need to be fragmented
- * - INVALID_STATE if message was not generated or is IKEv2
+ * - INVALID_STATE if message is IKEv2
* - FAILED if fragmentation failed
+ * - and the possible return values of generate()
*/
- status_t (*fragment)(message_t *this, size_t frag_len,
+ status_t (*fragment)(message_t *this, keymat_t *keymat, size_t frag_len,
enumerator_t **fragments);
/**
+ * Check if the message has been encoded and fragmented using fragment(),
+ * and whether there actually resulted fragments (if not is_encoded() will
+ * be TRUE).
+ *
+ * The packets of individual fragments can be retrieved with
+ * get_fragments().
+ *
+ * @return TRUE if message has been encoded and fragmented
+ */
+ bool (*is_fragmented)(message_t *this);
+
+ /**
* Gets the source host informations.
*
* @warning Returned host_t object is not getting cloned,
@@ -356,11 +369,11 @@ struct message_t {
notify_payload_t* (*get_notify)(message_t *this, notify_type_t type);
/**
- * Returns a clone of the internal stored packet_t object.
+ * Returns a clone of the internally stored packet_t object.
*
* @return packet_t object as clone of internal one
*/
- packet_t * (*get_packet) (message_t *this);
+ packet_t *(*get_packet) (message_t *this);
/**
* Returns a chunk pointing to internal packet_t data.
@@ -370,6 +383,13 @@ struct message_t {
chunk_t (*get_packet_data) (message_t *this);
/**
+ * Returns internally stored packet_t* objects for each fragment.
+ *
+ * @return enumerator internal packet_t* objects
+ */
+ enumerator_t *(*get_fragments)(message_t *this);
+
+ /**
* Destroys a message and all including objects.
*/
void (*destroy) (message_t *this);