fixed typo
[strongswan.git] / src / charon / network / receiver.c
index 9b4bf71..1654f0e 100644 (file)
@@ -1,10 +1,3 @@
-/**
- * @file receiver.c
- *
- * @brief Implementation of receiver_t.
- *
- */
-
 /*
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
@@ -19,6 +12,8 @@
  * 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 <stdlib.h>
 #include <daemon.h>
 #include <network/socket.h>
 #include <network/packet.h>
-#include <processing/job_queue.h>
 #include <processing/jobs/job.h>
 #include <processing/jobs/process_message_job.h>
+#include <processing/jobs/callback_job.h>
+#include <crypto/hashers/hasher.h>
 
-/** 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 */
@@ -56,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
@@ -89,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
@@ -140,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);
 }
@@ -162,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");
@@ -207,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))
                {
@@ -217,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");
@@ -245,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;
 }
 
 /**
@@ -340,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);
 }
@@ -357,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;
 }
+