message: fragment() generates message and fragments and caches them
This commit is contained in:
@@ -877,6 +877,11 @@ struct private_message_t {
|
|||||||
*/
|
*/
|
||||||
packet_t *packet;
|
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 where payload data are stored in.
|
||||||
*/
|
*/
|
||||||
@@ -1051,6 +1056,12 @@ METHOD(message_t, is_encoded, bool,
|
|||||||
return this->packet->get_data(this->packet).ptr != NULL;
|
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,
|
METHOD(message_t, add_payload, void,
|
||||||
private_message_t *this, payload_t *payload)
|
private_message_t *this, payload_t *payload)
|
||||||
{
|
{
|
||||||
@@ -1341,6 +1352,8 @@ static void order_payloads(private_message_t *this)
|
|||||||
payload_t *payload;
|
payload_t *payload;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
DBG2(DBG_ENC, "order payloads in message");
|
||||||
|
|
||||||
/* move to temp list */
|
/* move to temp list */
|
||||||
list = linked_list_create();
|
list = linked_list_create();
|
||||||
while (this->payloads->remove_last(this->payloads,
|
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);
|
dst = this->packet->get_destination(this->packet);
|
||||||
|
|
||||||
message = message_create(this->major_version, this->minor_version);
|
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_message_id(message, this->message_id);
|
||||||
message->set_request(message, this->is_request);
|
message->set_request(message, this->is_request);
|
||||||
message->set_source(message, src->clone(src));
|
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;
|
fragment_payload_t *fragment;
|
||||||
message_t *message;
|
message_t *message;
|
||||||
|
peer_cfg_t *peer_cfg;
|
||||||
|
ike_sa_t *ike_sa;
|
||||||
|
|
||||||
fragment = fragment_payload_create_from_data(num, last, data);
|
fragment = fragment_payload_create_from_data(num, last, data);
|
||||||
message = clone_message(this);
|
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);
|
message->add_payload(message, (payload_t*)fragment);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy all messages in the given array
|
* Destroy all fragments
|
||||||
*/
|
*/
|
||||||
CALLBACK(destroy_fragments, void,
|
static void clear_fragments(private_message_t *this)
|
||||||
array_t *fragments)
|
|
||||||
{
|
{
|
||||||
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,
|
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;
|
message_t *fragment;
|
||||||
|
packet_t *packet;
|
||||||
u_int8_t num, count;
|
u_int8_t num, count;
|
||||||
host_t *src, *dst;
|
host_t *src, *dst;
|
||||||
chunk_t data;
|
chunk_t data;
|
||||||
|
status_t status;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (!is_encoded(this) || this->major_version == IKEV2_MAJOR_VERSION)
|
if (this->major_version == IKEV2_MAJOR_VERSION)
|
||||||
{
|
{
|
||||||
return INVALID_STATE;
|
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);
|
src = this->packet->get_source(this->packet);
|
||||||
dst = this->packet->get_destination(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);
|
data = this->packet->get_data(this->packet);
|
||||||
if (data.len <= frag_len)
|
if (data.len <= frag_len)
|
||||||
{
|
{
|
||||||
return ALREADY_DONE;
|
*fragments = enumerator_create_single(this->packet, NULL);
|
||||||
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
/* overhead for the fragmentation payload header */
|
/* overhead for the fragmentation payload header */
|
||||||
frag_len -= 8;
|
frag_len -= 8;
|
||||||
|
|
||||||
count = data.len / frag_len + (data.len % frag_len ? 1 : 0);
|
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 "
|
DBG2(DBG_ENC, "splitting IKE message with length of %zu bytes into "
|
||||||
"%hhu fragments", data.len, count);
|
"%hhu fragments", data.len, count);
|
||||||
for (num = 1; num <= count; num++)
|
for (num = 1; num <= count; num++)
|
||||||
@@ -1750,34 +1793,39 @@ METHOD(message_t, fragment, status_t,
|
|||||||
len = min(data.len, frag_len);
|
len = min(data.len, frag_len);
|
||||||
fragment = create_fragment(this, num, num == count,
|
fragment = create_fragment(this, num, num == count,
|
||||||
chunk_create(data.ptr, len));
|
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);
|
data = chunk_skip(data, len);
|
||||||
}
|
}
|
||||||
*fragments = enumerator_create_cleaner(array_create_enumerator(messages),
|
*fragments = array_create_enumerator(this->fragments);
|
||||||
destroy_fragments, messages);
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(message_t, get_packet, packet_t*,
|
METHOD(message_t, get_packet, packet_t*,
|
||||||
private_message_t *this)
|
private_message_t *this)
|
||||||
{
|
{
|
||||||
if (this->packet == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return this->packet->clone(this->packet);
|
return this->packet->clone(this->packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(message_t, get_packet_data, chunk_t,
|
METHOD(message_t, get_packet_data, chunk_t,
|
||||||
private_message_t *this)
|
private_message_t *this)
|
||||||
{
|
{
|
||||||
if (this->packet == NULL)
|
|
||||||
{
|
|
||||||
return chunk_empty;
|
|
||||||
}
|
|
||||||
return this->packet->get_data(this->packet);
|
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,
|
METHOD(message_t, parse_header, status_t,
|
||||||
private_message_t *this)
|
private_message_t *this)
|
||||||
{
|
{
|
||||||
@@ -2264,6 +2312,7 @@ METHOD(message_t, destroy, void,
|
|||||||
{
|
{
|
||||||
DESTROY_IF(this->ike_sa_id);
|
DESTROY_IF(this->ike_sa_id);
|
||||||
this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy));
|
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->packet->destroy(this->packet);
|
||||||
this->parser->destroy(this->parser);
|
this->parser->destroy(this->parser);
|
||||||
free(this);
|
free(this);
|
||||||
@@ -2301,6 +2350,7 @@ message_t *message_create_from_packet(packet_t *packet)
|
|||||||
.disable_sort = _disable_sort,
|
.disable_sort = _disable_sort,
|
||||||
.generate = _generate,
|
.generate = _generate,
|
||||||
.is_encoded = _is_encoded,
|
.is_encoded = _is_encoded,
|
||||||
|
.is_fragmented = _is_fragmented,
|
||||||
.fragment = _fragment,
|
.fragment = _fragment,
|
||||||
.set_source = _set_source,
|
.set_source = _set_source,
|
||||||
.get_source = _get_source,
|
.get_source = _get_source,
|
||||||
@@ -2314,6 +2364,7 @@ message_t *message_create_from_packet(packet_t *packet)
|
|||||||
.parse_body = _parse_body,
|
.parse_body = _parse_body,
|
||||||
.get_packet = _get_packet,
|
.get_packet = _get_packet,
|
||||||
.get_packet_data = _get_packet_data,
|
.get_packet_data = _get_packet_data,
|
||||||
|
.get_fragments = _get_fragments,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.exchange_type = EXCHANGE_TYPE_UNDEFINED,
|
.exchange_type = EXCHANGE_TYPE_UNDEFINED,
|
||||||
|
|||||||
@@ -265,24 +265,37 @@ struct message_t {
|
|||||||
bool (*is_encoded)(message_t *this);
|
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).
|
* datagram length).
|
||||||
*
|
*
|
||||||
* @note Only supported for IKEv1 at the moment.
|
* @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
|
* @param frag_len fragment length (maximum total IP datagram length), 0
|
||||||
* for default value depending on address family
|
* 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
|
* which are owned by the enumerator
|
||||||
* @return
|
* @return
|
||||||
* - SUCCESS if message could be fragmented
|
* - SUCCESS if message could be fragmented
|
||||||
* - ALREADY_DONE if message does not need to be fragmented
|
* - INVALID_STATE if message is IKEv2
|
||||||
* - INVALID_STATE if message was not generated or is IKEv2
|
|
||||||
* - FAILED if fragmentation failed
|
* - 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);
|
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.
|
* Gets the source host informations.
|
||||||
*
|
*
|
||||||
@@ -356,11 +369,11 @@ struct message_t {
|
|||||||
notify_payload_t* (*get_notify)(message_t *this, notify_type_t type);
|
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
|
* @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.
|
* Returns a chunk pointing to internal packet_t data.
|
||||||
@@ -369,6 +382,13 @@ struct message_t {
|
|||||||
*/
|
*/
|
||||||
chunk_t (*get_packet_data) (message_t *this);
|
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.
|
* Destroys a message and all including objects.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -401,16 +401,9 @@ static bool generate_message(private_task_manager_t *this, message_t *message,
|
|||||||
bool use_frags = FALSE, result = TRUE;
|
bool use_frags = FALSE, result = TRUE;
|
||||||
ike_cfg_t *ike_cfg;
|
ike_cfg_t *ike_cfg;
|
||||||
enumerator_t *fragments;
|
enumerator_t *fragments;
|
||||||
message_t *fragment;
|
|
||||||
packet_t *packet;
|
packet_t *packet;
|
||||||
status_t status;
|
status_t status;
|
||||||
|
|
||||||
if (this->ike_sa->generate_message(this->ike_sa, message,
|
|
||||||
&packet) != SUCCESS)
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||||
if (ike_cfg)
|
if (ike_cfg)
|
||||||
{
|
{
|
||||||
@@ -430,37 +423,24 @@ static bool generate_message(private_task_manager_t *this, message_t *message,
|
|||||||
|
|
||||||
if (!use_frags)
|
if (!use_frags)
|
||||||
{
|
{
|
||||||
array_insert_create(packets, ARRAY_TAIL, packet);
|
if (this->ike_sa->generate_message(this->ike_sa, message,
|
||||||
return TRUE;
|
&packet) != SUCCESS)
|
||||||
}
|
|
||||||
/* 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 */
|
|
||||||
message->set_exchange_type(message, this->frag.exchange);
|
|
||||||
status = message->fragment(message, this->frag.size, &fragments);
|
|
||||||
if (status == ALREADY_DONE)
|
|
||||||
{
|
|
||||||
array_insert_create(packets, ARRAY_TAIL, packet);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else if (status != SUCCESS)
|
|
||||||
{
|
|
||||||
packet->destroy(packet);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
packet->destroy(packet);
|
|
||||||
|
|
||||||
while (fragments->enumerate(fragments, &fragment))
|
|
||||||
{
|
|
||||||
status = this->ike_sa->generate_message(this->ike_sa, fragment,
|
|
||||||
&packet);
|
|
||||||
if (status != SUCCESS)
|
|
||||||
{
|
{
|
||||||
DBG1(DBG_IKE, "failed to generate IKE fragment");
|
return FALSE;
|
||||||
result = FALSE;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
array_insert_create(packets, ARRAY_TAIL, packet);
|
array_insert_create(packets, ARRAY_TAIL, packet);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
message->set_ike_sa_id(message, this->ike_sa->get_id(this->ike_sa));
|
||||||
|
status = message->fragment(message, this->ike_sa->get_keymat(this->ike_sa),
|
||||||
|
this->frag.size, &fragments);
|
||||||
|
if (status != SUCCESS)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
while (fragments->enumerate(fragments, &packet))
|
||||||
|
{
|
||||||
|
array_insert_create(packets, ARRAY_TAIL, packet->clone(packet));
|
||||||
}
|
}
|
||||||
fragments->destroy(fragments);
|
fragments->destroy(fragments);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
Reference in New Issue
Block a user