From: Martin Willi Date: Tue, 13 Dec 2011 15:14:17 +0000 (+0100) Subject: Keep a history of received response hashes to detect late retransmissions X-Git-Tag: 5.0.0~338^2~9^2~224 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fce566a87662988eab6e6f8dcabb08922e489ede;p=thirdparty%2Fstrongswan.git Keep a history of received response hashes to detect late retransmissions If we receive an old response and we already sent out the next request, we must be able to identify that it is not the response to the new request. --- diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 1dc2bc3cd3..e44e4ac334 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -31,6 +31,15 @@ #include #include +/** + * Number of old messages hashes we keep for retransmission. + * + * In Main Mode, we must ignore messages from a previous message pair if + * we already continued to the next. Otherwise a late retransmission + * could be considered as a reply to the newer request. + */ +#define MAX_OLD_HASHES 2 + typedef struct exchange_t exchange_t; /** @@ -96,6 +105,16 @@ struct private_task_manager_t { */ u_int32_t mid; + /** + * Hashes of old responses we can ignore + */ + u_int32_t old_hashes[MAX_OLD_HASHES]; + + /** + * Position in old hash array + */ + int old_hash_pos; + /** * Sequence number of the last sent message */ @@ -826,7 +845,7 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg) METHOD(task_manager_t, process_message, status_t, private_task_manager_t *this, message_t *msg) { - u_int32_t hash, mid; + u_int32_t hash, mid, i; host_t *me, *other; status_t status; @@ -834,11 +853,21 @@ METHOD(task_manager_t, process_message, status_t, me = msg->get_destination(msg); other = msg->get_source(msg); mid = msg->get_message_id(msg); + hash = chunk_hash(msg->get_packet_data(msg)); + for (i = 0; i < MAX_OLD_HASHES; i++) + { + if (this->initiating.old_hashes[i] == hash) + { + DBG1(DBG_IKE, "received retransmit of response with ID %u, " + "but next request already sent", mid); + return SUCCESS; + } + } if ((mid && mid == this->initiating.mid) || (this->initiating.mid == 0 && msg->get_exchange_type(msg) == this->initiating.type && - this->active_tasks->get_count(this->active_tasks))) + this->active_tasks->get_count(this->active_tasks))) { msg->set_request(msg, FALSE); status = parse_message(this, msg); @@ -855,10 +884,11 @@ METHOD(task_manager_t, process_message, status_t, flush(this); return DESTROY_ME; } + this->initiating.old_hashes[(this->initiating.old_hash_pos++) % + MAX_OLD_HASHES] = hash; } else { - hash = chunk_hash(msg->get_packet_data(msg)); if (hash == this->responding.hash) { if (this->responding.packet) @@ -875,7 +905,6 @@ METHOD(task_manager_t, process_message, status_t, } return SUCCESS; } - if (msg->get_exchange_type(msg) == TRANSACTION && this->active_tasks->get_count(this->active_tasks) && !this->queued)