diff options
Diffstat (limited to 'src/libcharon/sa/ikev1/task_manager_v1.c')
-rwxr-xr-x[-rw-r--r--] | src/libcharon/sa/ikev1/task_manager_v1.c | 85 |
1 files changed, 81 insertions, 4 deletions
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index f7415a5ad..7e1ff616a 100644..100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -31,6 +31,8 @@ #include <sa/ikev1/tasks/isakmp_cert_pre.h> #include <sa/ikev1/tasks/isakmp_cert_post.h> #include <sa/ikev1/tasks/isakmp_delete.h> +#include <sa/ikev1/tasks/isakmp_dpd.h> + #include <processing/jobs/retransmit_job.h> #include <processing/jobs/delete_ike_sa_job.h> @@ -197,6 +199,16 @@ struct private_task_manager_t { * Base to calculate retransmission timeout */ double retransmit_base; + + /** + * Sequence number for sending DPD requests + */ + u_int32_t dpd_send_seqnr; + + /** + * Sequence number for received DPD requests + */ + u_int32_t dpd_rec_seqnr; }; /** @@ -406,6 +418,13 @@ METHOD(task_manager_t, initiate, status_t, new_mid = TRUE; break; } + + if (activate_task(this, TASK_ISAKMP_DPD)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } break; default: break; @@ -580,7 +599,20 @@ static status_t build_response(private_task_manager_t *this, message_t *request) /* send response along the path the request came in */ message->set_source(message, me->clone(me)); message->set_destination(message, other->clone(other)); - message->set_message_id(message, request->get_message_id(request)); + + /* Create new message id for informational exchanges*/ + if (request->get_exchange_type(request) == INFORMATIONAL_V1) + { + u_int32_t message_id; + + this->rng->get_bytes(this->rng, sizeof(message_id), + (void*)&message_id); + message->set_message_id(message, message_id); + } + else + { + message->set_message_id(message, request->get_message_id(request)); + } message->set_request(message, FALSE); this->responding.mid = request->get_message_id(request); @@ -710,6 +742,7 @@ static status_t process_request(private_task_manager_t *this, enumerator_t *enumerator; task_t *task = NULL; bool send_response = FALSE; + bool informational = FALSE; if (message->get_exchange_type(message) == INFORMATIONAL_V1 || this->passive_tasks->get_count(this->passive_tasks) == 0) @@ -752,8 +785,9 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); break; case INFORMATIONAL_V1: - task = (task_t *)informational_create(this->ike_sa, NULL); + task = (task_t *)informational_create(this->ike_sa, NULL, this->dpd_rec_seqnr); this->passive_tasks->insert_first(this->passive_tasks, task); + informational = TRUE; break; case TRANSACTION: if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) @@ -784,6 +818,15 @@ static status_t process_request(private_task_manager_t *this, case NEED_MORE: /* processed, but task needs at least another call to build() */ send_response = TRUE; + if (informational && !this->dpd_rec_seqnr) + { + /* Update the received DPD sequence number if it the first received one */ + if (task->get_type(task) == TASK_ISAKMP_DPD) + { + isakmp_dpd_t *isakmp_dpd = (isakmp_dpd_t *)task; + this->dpd_rec_seqnr = isakmp_dpd->get_dpd_seqnr(isakmp_dpd); + } + } continue; case ALREADY_DONE: send_response = FALSE; @@ -950,6 +993,7 @@ METHOD(task_manager_t, process_message, status_t, u_int32_t hash, mid, i; host_t *me, *other; status_t status; + bool dpd_response = FALSE; /* TODO-IKEv1: update hosts more selectively */ me = msg->get_destination(msg); @@ -977,7 +1021,27 @@ METHOD(task_manager_t, process_message, status_t, } } - if ((mid && mid == this->initiating.mid) || + /* DPD Acks are not sent with a same message ID as the request.*/ + if (msg->get_exchange_type(msg) == INFORMATIONAL_V1 && + this->active_tasks->get_count(this->active_tasks)) + { + enumerator_t *enumerator; + task_t *task; + /* In case of ongoing DPD request, let the DPD task handle all information exchanges. */ + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) + { + if (task->get_type(task) == TASK_ISAKMP_DPD) + { + dpd_response = TRUE; + break; + } + } + enumerator->destroy(enumerator); + } + + + if ((mid && mid == this->initiating.mid) || dpd_response || (this->initiating.mid == 0 && msg->get_exchange_type(msg) == this->initiating.type && this->active_tasks->get_count(this->active_tasks))) @@ -1271,10 +1335,16 @@ METHOD(task_manager_t, queue_child_delete, void, spi, FALSE, expired)); } +METHOD(task_manager_v1_t, get_dpd_seqnr, u_int32_t, + private_task_manager_t *this) +{ + return this->dpd_send_seqnr++; +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { - /* TODO-IKEv1: DPD checking */ + queue_task(this, (task_t*)isakmp_dpd_create(this->ike_sa, NULL, _get_dpd_seqnr(&this->public))); } METHOD(task_manager_t, adopt_tasks, void, @@ -1401,6 +1471,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .create_task_enumerator = _create_task_enumerator, .destroy = _destroy, }, + .get_dpd_seqnr = _get_dpd_seqnr, }, .ike_sa = ike_sa, .initiating.type = EXCHANGE_TYPE_UNDEFINED, @@ -1417,5 +1488,11 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) "charon.retransmit_base", RETRANSMIT_BASE), ); + this->rng->get_bytes(this->rng, sizeof(this->dpd_send_seqnr), + (void*)&this->dpd_send_seqnr); + + this->dpd_send_seqnr &= 0x7FFFFFFF; + return &this->public; } + |