diff options
Diffstat (limited to 'src/libcharon/network')
-rw-r--r-- | src/libcharon/network/receiver.c | 48 | ||||
-rw-r--r-- | src/libcharon/network/sender.c | 10 | ||||
-rw-r--r-- | src/libcharon/network/sender.h | 7 |
3 files changed, 58 insertions, 7 deletions
diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index 599249fcb..fcc730439 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -30,6 +30,8 @@ /** lifetime of a cookie, in seconds */ #define COOKIE_LIFETIME 10 +/** time we wait before disabling cookies */ +#define COOKIE_CALMDOWN_DELAY 10 /** how many times to reuse the secret */ #define COOKIE_REUSE 10000 /** default value for private_receiver_t.cookie_threshold */ @@ -98,6 +100,11 @@ struct private_receiver_t { u_int32_t cookie_threshold; /** + * timestamp of last cookie requested + */ + time_t last_cookie; + + /** * how many half open IKE_SAs per peer before blocking */ u_int32_t block_threshold; @@ -262,24 +269,55 @@ static bool check_cookie(private_receiver_t *this, message_t *message) } /** + * Check if we currently require cookies + */ +static bool cookie_required(private_receiver_t *this, + u_int half_open, u_int32_t now) +{ + if (this->cookie_threshold && half_open >= this->cookie_threshold) + { + this->last_cookie = now; + return TRUE; + } + if (now < this->last_cookie + COOKIE_CALMDOWN_DELAY) + { + /* We don't disable cookies unless we haven't seen IKE_SA_INITs + * for COOKIE_CALMDOWN_DELAY seconds. This avoids jittering between + * cookie on / cookie off states, which is problematic. Consider the + * following: A legitimiate initiator sends a IKE_SA_INIT while we + * are under a DoS attack. If we toggle our cookie behavior, + * multiple retransmits of this IKE_SA_INIT might get answered with + * and without cookies. The initiator goes on and retries with + * a cookie, but it can't know if the completing IKE_SA_INIT response + * is to its IKE_SA_INIT request with or without cookies. This is + * problematic, as the cookie is part of AUTH payload data. + */ + this->last_cookie = now; + return TRUE; + } + return FALSE; +} + +/** * Check if we should drop IKE_SA_INIT because of cookie/overload checking */ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message) { u_int half_open; + u_int32_t now; + now = time_monotonic(NULL); half_open = charon->ike_sa_manager->get_half_open_count( charon->ike_sa_manager, NULL); /* check for cookies in IKEv2 */ if (message->get_major_version(message) == IKEV2_MAJOR_VERSION && - this->cookie_threshold && half_open >= this->cookie_threshold && - !check_cookie(this, message)) + cookie_required(this, half_open, now) && !check_cookie(this, message)) { - u_int32_t now = time_monotonic(NULL); - chunk_t cookie = cookie_build(this, message, now - this->secret_offset, - chunk_from_thing(this->secret)); + chunk_t cookie; + cookie = cookie_build(this, message, now - this->secret_offset, + chunk_from_thing(this->secret)); DBG2(DBG_NET, "received packet from: %#H to %#H", message->get_source(message), message->get_destination(message)); diff --git a/src/libcharon/network/sender.c b/src/libcharon/network/sender.c index 4df930b15..6d5ad8f2a 100644 --- a/src/libcharon/network/sender.c +++ b/src/libcharon/network/sender.c @@ -149,7 +149,7 @@ static job_requeue_t send_packets(private_sender_t * this) return JOB_REQUEUE_DIRECT; } -METHOD(sender_t, destroy, void, +METHOD(sender_t, flush, void, private_sender_t *this) { /* send all packets in the queue */ @@ -159,8 +159,13 @@ METHOD(sender_t, destroy, void, this->sent->wait(this->sent, this->mutex); } this->mutex->unlock(this->mutex); +} + +METHOD(sender_t, destroy, void, + private_sender_t *this) +{ this->job->cancel(this->job); - this->list->destroy(this->list); + this->list->destroy_offset(this->list, offsetof(packet_t, destroy)); this->got->destroy(this->got); this->sent->destroy(this->sent); this->mutex->destroy(this->mutex); @@ -177,6 +182,7 @@ sender_t * sender_create() INIT(this, .public = { .send = _send_, + .flush = _flush, .destroy = _destroy, }, .list = linked_list_create(), diff --git a/src/libcharon/network/sender.h b/src/libcharon/network/sender.h index f77fadab2..6ee070435 100644 --- a/src/libcharon/network/sender.h +++ b/src/libcharon/network/sender.h @@ -44,6 +44,13 @@ struct sender_t { void (*send) (sender_t *this, packet_t *packet); /** + * Enforce a flush of the send queue. + * + * This function blocks until all queued packets have been sent. + */ + void (*flush)(sender_t *this); + + /** * Destroys a sender object. */ void (*destroy) (sender_t *this); |