X-Git-Url: https://git.strongswan.org/?p=strongswan.git;a=blobdiff_plain;f=src%2Fcharon%2Fnetwork%2Freceiver.c;h=1654f0ec9a577e6297ce8bd4d1edec41c5e48e26;hp=dfb7429d9b171e29d5991d9ee5be9c827ec05162;hb=0005cee52795591fc616c1518d205d8be492ee5d;hpb=a6a039aa1054e66a0a2d125d70273176ceabfa70 diff --git a/src/charon/network/receiver.c b/src/charon/network/receiver.c index dfb7429..1654f0e 100644 --- a/src/charon/network/receiver.c +++ b/src/charon/network/receiver.c @@ -1,10 +1,3 @@ -/** - * @file receiver.c - * - * @brief Implementation of receiver_t. - * - */ - /* * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -19,9 +12,12 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. + * + * $Id$ */ #include +#include #include #include "receiver.h" @@ -29,12 +25,11 @@ #include #include #include -#include #include #include +#include +#include -/** length of the full cookie, including time (u_int32_t + SHA1()) */ -#define COOKIE_LENGTH 24 /** lifetime of a cookie, in seconds */ #define COOKIE_LIFETIME 10 /** how many times to reuse the secret */ @@ -55,12 +50,17 @@ struct private_receiver_t { /** * Public part of a receiver_t object. */ - receiver_t public; + receiver_t public; + + /** + * Threads job receiving packets + */ + callback_job_t *job; - /** - * Assigned thread. - */ - pthread_t assigned_thread; + /** + * Assigned thread. + */ + pthread_t assigned_thread; /** * current secret to use for cookie calculation @@ -88,9 +88,9 @@ struct private_receiver_t { u_int32_t secret_offset; /** - * the randomizer to use for secret generation + * the RNG to use for secret generation */ - randomizer_t *randomizer; + rng_t *rng; /** * hasher to use for cookie calculation @@ -139,11 +139,12 @@ static chunk_t cookie_build(private_receiver_t *this, message_t *message, { u_int64_t spi = message->get_initiator_spi(message); host_t *ip = message->get_source(message); - chunk_t input, hash = chunk_alloca(this->hasher->get_hash_size(this->hasher)); + chunk_t input, hash; /* COOKIE = t | sha1( IPi | SPIi | t | secret ) */ input = chunk_cata("cccc", ip->get_address(ip), chunk_from_thing(spi), chunk_from_thing(t), secret); + hash = chunk_alloca(this->hasher->get_hash_size(this->hasher)); this->hasher->get_hash(this->hasher, input, hash.ptr); return chunk_cat("cc", chunk_from_thing(t), hash); } @@ -161,7 +162,8 @@ static bool cookie_verify(private_receiver_t *this, message_t *message, now = time(NULL); t = *(u_int32_t*)cookie.ptr; - if (cookie.len != COOKIE_LENGTH || + if (cookie.len != sizeof(u_int32_t) + + this->hasher->get_hash_size(this->hasher) || t < now - this->secret_offset - COOKIE_LIFETIME) { DBG2(DBG_NET, "received cookie lifetime expired, rejecting"); @@ -206,7 +208,8 @@ static bool cookie_required(private_receiver_t *this, message_t *message) packet_t *packet = message->get_packet(message); chunk_t data = packet->get_data(packet); if (data.len < - IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH + COOKIE_LENGTH || + IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH + + sizeof(u_int32_t) + this->hasher->get_hash_size(this->hasher) || *(data.ptr + 16) != NOTIFY || *(u_int16_t*)(data.ptr + IKE_HEADER_LENGTH + 6) != htons(COOKIE)) { @@ -216,7 +219,7 @@ static bool cookie_required(private_receiver_t *this, message_t *message) else { data.ptr += IKE_HEADER_LENGTH + NOTIFY_PAYLOAD_HEADER_LENGTH; - data.len = COOKIE_LENGTH; + data.len = sizeof(u_int32_t) + this->hasher->get_hash_size(this->hasher); if (!cookie_verify(this, message, data)) { DBG2(DBG_NET, "found cookie, but content invalid"); @@ -244,94 +247,83 @@ static bool peer_to_aggressive(private_receiver_t *this, message_t *message) /** * Implementation of receiver_t.receive_packets. */ -static void receive_packets(private_receiver_t *this) +static job_requeue_t receive_packets(private_receiver_t *this) { packet_t *packet; message_t *message; job_t *job; - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - DBG1(DBG_NET, "receiver thread running, thread_ID: %06u", - (int)pthread_self()); + /* read in a packet */ + if (charon->socket->receive(charon->socket, &packet) != SUCCESS) + { + DBG2(DBG_NET, "receiving from socket failed!"); + return JOB_REQUEUE_FAIR; + } - charon->drop_capabilities(charon, TRUE); + /* parse message header */ + message = message_create_from_packet(packet); + if (message->parse_header(message) != SUCCESS) + { + DBG1(DBG_NET, "received invalid IKE header from %H - ignored", + packet->get_source(packet)); + message->destroy(message); + return JOB_REQUEUE_DIRECT; + } - while (TRUE) + /* check IKE major version */ + if (message->get_major_version(message) != IKE_MAJOR_VERSION) { - /* read in a packet */ - if (charon->socket->receive(charon->socket, &packet) != SUCCESS) - { - DBG2(DBG_NET, "receiving from socket failed!"); - /* try again after a delay */ - sleep(1); - continue; - } - - /* parse message header */ - message = message_create_from_packet(packet); - if (message->parse_header(message) != SUCCESS) + DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, " + "sending INVALID_MAJOR_VERSION", message->get_major_version(message), + message->get_minor_version(message), packet->get_source(packet)); + send_notify(message, INVALID_MAJOR_VERSION, chunk_empty); + message->destroy(message); + return JOB_REQUEUE_DIRECT; + } + + if (message->get_request(message) && + message->get_exchange_type(message) == IKE_SA_INIT) + { + /* check for cookies */ + if (cookie_required(this, message)) { - DBG1(DBG_NET, "received invalid IKE header from %H, ignored", - packet->get_source(packet)); + u_int32_t now = time(NULL); + chunk_t 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)); + DBG2(DBG_NET, "sending COOKIE notify to %H", + message->get_source(message)); + send_notify(message, COOKIE, cookie); + chunk_free(&cookie); + if (++this->secret_used > COOKIE_REUSE) + { + /* create new cookie */ + DBG1(DBG_NET, "generating new cookie secret after %d uses", + this->secret_used); + memcpy(this->secret_old, this->secret, SECRET_LENGTH); + this->rng->get_bytes(this->rng, SECRET_LENGTH, this->secret); + this->secret_switch = now; + this->secret_used = 0; + } message->destroy(message); - continue; + return JOB_REQUEUE_DIRECT; } - /* check IKE major version */ - if (message->get_major_version(message) != IKE_MAJOR_VERSION) + /* check if peer has not too many IKE_SAs half open */ + if (peer_to_aggressive(this, message)) { - DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, " - "sending INVALID_MAJOR_VERSION", message->get_major_version(message), - message->get_minor_version(message), packet->get_source(packet)); - send_notify(message, INVALID_MAJOR_VERSION, chunk_empty); + DBG1(DBG_NET, "ignoring IKE_SA setup from %H, " + "peer too aggressive", message->get_source(message)); message->destroy(message); - continue; - } - - if (message->get_request(message) && - message->get_exchange_type(message) == IKE_SA_INIT) - { - /* check for cookies */ - if (cookie_required(this, message)) - { - u_int32_t now = time(NULL); - chunk_t 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)); - DBG2(DBG_NET, "sending COOKIE notify to %H", - message->get_source(message)); - send_notify(message, COOKIE, cookie); - chunk_free(&cookie); - if (++this->secret_used > COOKIE_REUSE) - { - /* create new cookie */ - DBG1(DBG_NET, "generating new cookie secret after %d uses", - this->secret_used); - memcpy(this->secret_old, this->secret, SECRET_LENGTH); - this->randomizer->get_pseudo_random_bytes(this->randomizer, - SECRET_LENGTH, this->secret); - this->secret_switch = now; - this->secret_used = 0; - } - message->destroy(message); - continue; - } - - /* check if peer has not too many IKE_SAs half open */ - if (peer_to_aggressive(this, message)) - { - DBG1(DBG_NET, "ignoring IKE_SA setup from %H, " - "peer to aggressive", message->get_source(message)); - message->destroy(message); - continue; - } + return JOB_REQUEUE_DIRECT; } - job = (job_t *)process_message_job_create(message); - charon->job_queue->add(charon->job_queue, job); } + job = (job_t*)process_message_job_create(message); + charon->processor->queue_job(charon->processor, job); + return JOB_REQUEUE_DIRECT; } /** @@ -339,9 +331,8 @@ static void receive_packets(private_receiver_t *this) */ static void destroy(private_receiver_t *this) { - pthread_cancel(this->assigned_thread); - pthread_join(this->assigned_thread, NULL); - this->randomizer->destroy(this->randomizer); + this->job->cancel(this->job); + this->rng->destroy(this->rng); this->hasher->destroy(this->hasher); free(this); } @@ -356,21 +347,31 @@ receiver_t *receiver_create() this->public.destroy = (void(*)(receiver_t*)) destroy; - this->randomizer = randomizer_create(); - this->hasher = hasher_create(HASH_SHA1); + this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED); + if (this->hasher == NULL) + { + DBG1(DBG_NET, "creating cookie hasher failed, no hashers supported"); + free(this); + return NULL; + } + this->rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); + if (this->rng == NULL) + { + DBG1(DBG_NET, "creating cookie RNG failed, no RNG supported"); + this->hasher->destroy(this->hasher); + free(this); + return NULL; + } this->secret_switch = now; this->secret_offset = random() % now; this->secret_used = 0; - this->randomizer->get_pseudo_random_bytes(this->randomizer, SECRET_LENGTH, - this->secret); + this->rng->get_bytes(this->rng, SECRET_LENGTH, this->secret); memcpy(this->secret_old, this->secret, SECRET_LENGTH); - if (pthread_create(&this->assigned_thread, NULL, - (void*)receive_packets, this) != 0) - { - free(this); - charon->kill(charon, "unable to create receiver thread"); - } + this->job = callback_job_create((callback_job_cb_t)receive_packets, + this, NULL, NULL); + charon->processor->queue_job(charon->processor, (job_t*)this->job); return &this->public; } +