]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
merged tasking branch into trunk
authorMartin Willi <martin@strongswan.org>
Wed, 28 Feb 2007 14:04:36 +0000 (14:04 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 28 Feb 2007 14:04:36 +0000 (14:04 -0000)
96 files changed:
configure.in
src/charon/Makefile.am
src/charon/bus/bus.c
src/charon/bus/bus.h
src/charon/bus/listeners/file_logger.c
src/charon/bus/listeners/sys_logger.c
src/charon/config/configuration.c
src/charon/config/configuration.h
src/charon/config/policies/policy.c
src/charon/config/policies/policy.h
src/charon/config/traffic_selector.c
src/charon/config/traffic_selector.h
src/charon/encoding/message.c
src/charon/encoding/message.h
src/charon/encoding/payloads/cert_payload.c
src/charon/encoding/payloads/certreq_payload.c
src/charon/encoding/payloads/configuration_attribute.c
src/charon/encoding/payloads/configuration_attribute.h
src/charon/encoding/payloads/cp_payload.c
src/charon/encoding/payloads/cp_payload.h
src/charon/encoding/payloads/notify_payload.c
src/charon/network/packet.c
src/charon/queues/jobs/acquire_job.c
src/charon/queues/jobs/delete_child_sa_job.c
src/charon/queues/jobs/delete_ike_sa_job.c
src/charon/queues/jobs/incoming_packet_job.c
src/charon/queues/jobs/initiate_job.c
src/charon/queues/jobs/initiate_job.h
src/charon/queues/jobs/job.c
src/charon/queues/jobs/job.h
src/charon/queues/jobs/rekey_child_sa_job.c
src/charon/queues/jobs/rekey_ike_sa_job.c
src/charon/queues/jobs/retransmit_job.c [moved from src/charon/queues/jobs/retransmit_request_job.c with 54% similarity]
src/charon/queues/jobs/retransmit_job.h [moved from src/charon/queues/jobs/retransmit_request_job.h with 64% similarity]
src/charon/queues/jobs/route_job.c
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/ike_sa_manager.c
src/charon/sa/ike_sa_manager.h
src/charon/sa/task_manager.c [new file with mode: 0644]
src/charon/sa/task_manager.h [new file with mode: 0644]
src/charon/sa/tasks/child_create.c [new file with mode: 0644]
src/charon/sa/tasks/child_create.h [new file with mode: 0644]
src/charon/sa/tasks/child_delete.c [new file with mode: 0644]
src/charon/sa/tasks/child_delete.h [new file with mode: 0644]
src/charon/sa/tasks/child_rekey.c [new file with mode: 0644]
src/charon/sa/tasks/child_rekey.h [new file with mode: 0644]
src/charon/sa/tasks/ike_auth.c [new file with mode: 0644]
src/charon/sa/tasks/ike_auth.h [new file with mode: 0644]
src/charon/sa/tasks/ike_cert.c [new file with mode: 0644]
src/charon/sa/tasks/ike_cert.h [new file with mode: 0644]
src/charon/sa/tasks/ike_config.c [new file with mode: 0644]
src/charon/sa/tasks/ike_config.h [new file with mode: 0644]
src/charon/sa/tasks/ike_delete.c [new file with mode: 0644]
src/charon/sa/tasks/ike_delete.h [new file with mode: 0644]
src/charon/sa/tasks/ike_dpd.c [new file with mode: 0644]
src/charon/sa/tasks/ike_dpd.h [new file with mode: 0644]
src/charon/sa/tasks/ike_init.c [new file with mode: 0644]
src/charon/sa/tasks/ike_init.h [new file with mode: 0644]
src/charon/sa/tasks/ike_natd.c [new file with mode: 0644]
src/charon/sa/tasks/ike_natd.h [new file with mode: 0644]
src/charon/sa/tasks/ike_rekey.c [new file with mode: 0644]
src/charon/sa/tasks/ike_rekey.h [new file with mode: 0644]
src/charon/sa/tasks/task.c [new file with mode: 0644]
src/charon/sa/tasks/task.h [new file with mode: 0644]
src/charon/sa/transactions/create_child_sa.c [deleted file]
src/charon/sa/transactions/create_child_sa.h [deleted file]
src/charon/sa/transactions/dead_peer_detection.c [deleted file]
src/charon/sa/transactions/dead_peer_detection.h [deleted file]
src/charon/sa/transactions/delete_child_sa.c [deleted file]
src/charon/sa/transactions/delete_child_sa.h [deleted file]
src/charon/sa/transactions/delete_ike_sa.c [deleted file]
src/charon/sa/transactions/delete_ike_sa.h [deleted file]
src/charon/sa/transactions/ike_auth.c [deleted file]
src/charon/sa/transactions/ike_auth.h [deleted file]
src/charon/sa/transactions/ike_sa_init.c [deleted file]
src/charon/sa/transactions/ike_sa_init.h [deleted file]
src/charon/sa/transactions/rekey_ike_sa.c [deleted file]
src/charon/sa/transactions/rekey_ike_sa.h [deleted file]
src/charon/sa/transactions/transaction.c [deleted file]
src/charon/sa/transactions/transaction.h [deleted file]
src/charon/threads/kernel_interface.c
src/charon/threads/kernel_interface.h
src/charon/threads/stroke_interface.c
src/libstrongswan/utils/host.c
src/libstrongswan/utils/host.h
src/libstrongswan/utils/identification.c
src/libstrongswan/utils/identification.h
src/libstrongswan/utils/iterator.h
src/libstrongswan/utils/linked_list.c
src/starter/confread.c
src/starter/starterstroke.c
src/stroke/stroke.c
src/stroke/stroke.h

index 89ab54fffcaece94a628b022ee7e35e756f437d2..aa8b624fa20d458ab0a2f55ff514af1759c9b766 100644 (file)
@@ -45,6 +45,12 @@ AC_ARG_WITH(
     [AC_DEFINE_UNQUOTED(DEV_RANDOM, "$withval")],
     [AC_DEFINE_UNQUOTED(DEV_RANDOM, "/dev/random")]
 )
+AC_ARG_WITH(
+    [resolv-conf],
+    AS_HELP_STRING([--with-resolv-conf=file],[set the file to store DNS server information other than "sysconfdir/resolv.conf"]),
+    [AC_DEFINE_UNQUOTED(RESOLV_CONF, "$withval")],
+    [AC_DEFINE_UNQUOTED(RESOLV_CONF, "${sysconfdir}/resolv.conf")]
+)
 
 AC_ARG_WITH(
     [urandom-device],
index c4a6afa5f6005d63371d8cdf987131cf877fbc74..e370874860e1d7a17bd98cbf70ad7ab30465957c 100644 (file)
@@ -17,21 +17,25 @@ config/policies/local_policy_store.c config/policies/policy_store.h config/polic
 config/credentials/local_credential_store.c config/credentials/local_credential_store.h \
 config/credentials/credential_store.h config/traffic_selector.c config/traffic_selector.h \
 config/proposal.c config/proposal.h config/configuration.c config/configuration.h \
-sa/transactions/transaction.h sa/transactions/transaction.c \
-sa/transactions/ike_sa_init.h sa/transactions/ike_sa_init.c \
-sa/transactions/ike_auth.h sa/transactions/ike_auth.c \
-sa/transactions/create_child_sa.h sa/transactions/create_child_sa.c \
-sa/transactions/delete_child_sa.h sa/transactions/delete_child_sa.c \
-sa/transactions/dead_peer_detection.h sa/transactions/dead_peer_detection.c \
-sa/transactions/delete_ike_sa.h sa/transactions/delete_ike_sa.c \
-sa/transactions/rekey_ike_sa.h sa/transactions/rekey_ike_sa.c \
-sa/authenticators/authenticator.h sa/authenticators/authenticator.c \
-sa/authenticators/rsa_authenticator.h sa/authenticators/rsa_authenticator.c \
-sa/authenticators/psk_authenticator.h sa/authenticators/psk_authenticator.c \
 sa/authenticators/eap_authenticator.h sa/authenticators/eap_authenticator.c \
 sa/authenticators/eap/eap_method.h sa/authenticators/eap/eap_method.c \
 sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \
-sa/ike_sa_id.c sa/ike_sa_id.h encoding/payloads/encryption_payload.c \
+sa/ike_sa_id.c sa/ike_sa_id.h sa/tasks/task.c sa/tasks/task.h \
+sa/tasks/ike_init.c sa/tasks/ike_init.h \
+sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
+sa/tasks/ike_auth.c sa/tasks/ike_auth.h \
+sa/tasks/ike_config.c sa/tasks/ike_config.h \
+sa/tasks/ike_cert.c sa/tasks/ike_cert.h \
+sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
+sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
+sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
+sa/tasks/child_create.c sa/tasks/child_create.h \
+sa/tasks/child_delete.c sa/tasks/child_delete.h \
+sa/tasks/child_rekey.c sa/tasks/child_rekey.h \
+sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
+sa/authenticators/rsa_authenticator.c sa/authenticators/rsa_authenticator.h \
+sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \
+sa/task_manager.c sa/task_manager.h encoding/payloads/encryption_payload.c \
 encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \
 encoding/payloads/configuration_attribute.h encoding/payloads/proposal_substructure.h \
 encoding/payloads/transform_attribute.c encoding/payloads/transform_attribute.h \
@@ -51,10 +55,10 @@ encoding/payloads/vendor_id_payload.h encoding/payloads/proposal_substructure.c
 encoding/parser.h encoding/message.c encoding/generator.c encoding/message.h encoding/generator.h \
 encoding/parser.c daemon.c daemon.h network/packet.c \
 network/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \
-queues/jobs/retransmit_request_job.h queues/jobs/initiate_job.h \
+queues/jobs/retransmit_job.h queues/jobs/initiate_job.h \
 queues/jobs/incoming_packet_job.h queues/jobs/incoming_packet_job.c \
 queues/jobs/delete_ike_sa_job.c queues/jobs/delete_ike_sa_job.h \
-queues/jobs/retransmit_request_job.c queues/jobs/initiate_job.c \
+queues/jobs/retransmit_job.c queues/jobs/initiate_job.c \
 queues/jobs/send_keepalive_job.c queues/jobs/send_keepalive_job.h \
 queues/jobs/rekey_child_sa_job.c queues/jobs/rekey_child_sa_job.h queues/jobs/delete_child_sa_job.c queues/jobs/delete_child_sa_job.h \
 queues/jobs/send_dpd_job.c queues/jobs/send_dpd_job.h queues/jobs/route_job.c queues/jobs/route_job.h \
index afed166561e9f2f40e11b38cc108692617b53b58..740663d5ce33952d21e196cb6d42510b6de0724c 100644 (file)
@@ -180,7 +180,7 @@ static int get_thread_number(private_bus_t *this)
 static void add_listener(private_bus_t *this, bus_listener_t *listener)
 {
        pthread_mutex_lock(&this->mutex);
-       this->listeners->insert_last(this->listeners, (void*)listener);
+       this->listeners->insert_last(this->listeners, listener);
        pthread_mutex_unlock(&this->mutex);
 }
 
@@ -301,7 +301,12 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level,
                va_list args_copy;
                
                va_copy(args_copy, args);
-               listener->signal(listener, signal, level, thread, ike_sa, format, args_copy);
+               if (!listener->signal(listener, signal, level, thread, 
+                                                         ike_sa, format, args_copy))
+               {
+                       /* unregister listener if requested */
+                       iterator->remove(iterator);
+               }
                va_end(args_copy);
        }
        iterator->destroy(iterator);
index 974d460b9104a3276010c9a75a457735412eb5bc..200525fb7dd67efc19ffd8ec63758df08beecb71 100644 (file)
@@ -224,6 +224,8 @@ struct bus_listener_t {
         * an additional informational or error message with a printf() like
         * variable argument list. This is in the va_list form, as forwarding
         * a "..." parameters to functions is not (cleanly) possible.
+        * The implementing signal function returns TRUE to stay registered
+        * to the bus, or FALSE to unregister itself.
         *
         * @param this          listener
         * @param singal        kind of the signal (up, down, rekeyed, ...)
@@ -232,8 +234,9 @@ struct bus_listener_t {
         * @param ike_sa        IKE_SA associated to the event
         * @param format        printf() style format string
         * @param args          vprintf() style va_list argument list
+        " @return                      TRUE to stay registered, FALSE to unregister
         */
-       void (*signal) (bus_listener_t *this, signal_t signal, level_t level,
+       bool (*signal) (bus_listener_t *this, signal_t signal, level_t level,
                                        int thread, ike_sa_t *ike_sa, char* format, va_list args);
 };
 
index 4c9e13b3fe4bd2641347ab5f185c3d5f8e732424..14f9f72cf3e10ce3f35f0c26771587152f054d84 100644 (file)
@@ -53,7 +53,7 @@ struct private_file_logger_t {
 /**
  * Implementation of bus_listener_t.signal.
  */
-static void signal_(private_file_logger_t *this, signal_t signal, level_t level,
+static bool signal_(private_file_logger_t *this, signal_t signal, level_t level,
                                        int thread, ike_sa_t* ike_sa, char *format, va_list args)
 {
        if (level <= this->levels[SIG_TYPE(signal)])
@@ -76,6 +76,8 @@ static void signal_(private_file_logger_t *this, signal_t signal, level_t level,
                        current = next;
                }
        }
+       /* always stay registered */
+       return TRUE;
 }
 
 /**
@@ -114,7 +116,7 @@ file_logger_t *file_logger_create(FILE *out)
        private_file_logger_t *this = malloc_thing(private_file_logger_t);
        
        /* public functions */
-       this->public.listener.signal = (void(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
+       this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
        this->public.set_level = (void(*)(file_logger_t*,signal_t,level_t))set_level;
        this->public.destroy = (void(*)(file_logger_t*))destroy;
        
index 58c59c4f7077c223dd546160f2d9f835e83d192a..d26d14dc00356d9d27c1fd0e542a6ffa5e9cb6e2 100644 (file)
@@ -54,7 +54,7 @@ struct private_sys_logger_t {
 /**
  * Implementation of bus_listener_t.signal.
  */
-static void signal_(private_sys_logger_t *this, signal_t signal, level_t level,
+static bool signal_(private_sys_logger_t *this, signal_t signal, level_t level,
                                        int thread, ike_sa_t* ike_sa, char *format, va_list args)
 {
        if (level <= this->levels[SIG_TYPE(signal)])
@@ -78,6 +78,8 @@ static void signal_(private_sys_logger_t *this, signal_t signal, level_t level,
                        current = next;
                }
        }
+       /* always stay registered */
+       return TRUE;
 }
 
 /**
@@ -117,7 +119,7 @@ sys_logger_t *sys_logger_create(int facility)
        private_sys_logger_t *this = malloc_thing(private_sys_logger_t);
        
        /* public functions */
-       this->public.listener.signal = (void(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
+       this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
        this->public.set_level = (void(*)(sys_logger_t*,signal_t,level_t))set_level;
        this->public.destroy = (void(*)(sys_logger_t*))destroy;
        
index 39fc4d9222f9861fd269c8d49a448b431f5db679..f43afdaa4dc5187e124ad796486458ea48e79a5c 100755 (executable)
 #define HALF_OPEN_IKE_SA_TIMEOUT 30000
 
 /**
- * The retransmission algorithm uses a multiple sequences.
- * Each sequence contains multiple retransmits. Those retransmits
- * are sent using a exponential backoff algorithm. The sequences
- * are retried with linear timings:
+ * Retransmission uses a backoff algorithm. The timeout is calculated using
+ * TIMEOUT * (BASE ** try).
+ * When try reaches TRIES, retransmission is given up.
  *
- * <------sequence---------><------sequence---------><------sequence--------->
- *
- * T-R---R-----R---------R--R-R---R-----R---------R--R-R---R-----R---------R--X
- *
- * T = first transmit
- * R = retransmit
- * X = giving up, peer is dead
- *
- * if (retransmit >= TRIES * sequences)
- *     => abort
- * TIMEOUT * (BASE ** (try % TRIES))
- *
- * Using an initial TIMEOUT of 4s, a BASE of 1.8, 5 TRIES
- * per sequnce and 3 sequences, this gives us:
+ * Using an initial TIMEOUT of 4s, a BASE of 1.8, and 5 TRIES gives us:
  *
  *                        | relative | absolute
  * ---------------------------------------------------------
  * 4s * (1.8 ** (3  % 5)) =   23s        47s
  * 4s * (1.8 ** (4  % 5)) =   42s        89s
  * 4s * (1.8 ** (5  % 5)) =   76s       165s
- * 4s * (1.8 ** (6  % 5)) =    4s       169s
- * 4s * (1.8 ** (7  % 5)) =    7s       176s
- * 4s * (1.8 ** (8  % 5)) =   13s       189s
- * 4s * (1.8 ** (9  % 5)) =   23s       212s
- * 4s * (1.8 ** (10 % 5)) =   42s       254s
- * 4s * (1.8 ** (11 % 5)) =   76s       330s
- * 4s * (1.8 ** (12 % 5)) =    4s       334
- * 4s * (1.8 ** (13 % 5)) =    7s       341s
- * 4s * (1.8 ** (14 % 5)) =   13s       354s
- * 4s * (1.8 ** (15 % 5)) =   23s       377s
- * 4s * (1.8 ** (16 % 5)) =   42s       419s
- * 4s * (1.8 ** (17 % 5)) =   76s       495s
  *
- * If the configuration uses 1 sequence, the peer is considered dead
- * after 2min 45s when no reply comes in. If it uses 3 sequences, after
- * 8min 15s the DPD action is executed...
+ * The peer is considered dead after 2min 45s when no reply comes in.
  */
 
 /**
@@ -119,17 +91,15 @@ struct private_configuration_t {
  * Implementation of configuration_t.get_retransmit_timeout.
  */
 static u_int32_t get_retransmit_timeout (private_configuration_t *this,
-                                                                                u_int32_t retransmit_count,
-                                                                                u_int32_t max_sequences)
+                                                                                u_int32_t retransmit_count)
 {
-       if (max_sequences != 0 && 
-               retransmit_count >= RETRANSMIT_TRIES * max_sequences)
+       if (retransmit_count > RETRANSMIT_TRIES)
        {
                /* give up */
                return 0;
        }
-       return (u_int32_t)(RETRANSMIT_TIMEOUT *
-                                          pow(RETRANSMIT_BASE, retransmit_count % RETRANSMIT_TRIES));
+       return (u_int32_t)
+                               (RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
 }
 
 /**
@@ -165,7 +135,7 @@ configuration_t *configuration_create()
        
        /* public functions */
        this->public.destroy = (void(*)(configuration_t*))destroy;
-       this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t*,u_int32_t,u_int32_t))get_retransmit_timeout;
+       this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t*,u_int32_t))get_retransmit_timeout;
        this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t*)) get_half_open_ike_sa_timeout;
        this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t*)) get_keepalive_interval;
        
index 2bb0b106e523165b62248a02512c83e413765b1d..77d1fd85de96b8ad4e8417cafd3e21b902d91290 100755 (executable)
@@ -40,19 +40,15 @@ struct configuration_t {
        /**
         * @brief Returns the retransmit timeout.
         *
-        * A return value of zero means the request should not be retransmitted again.
-        * The retransmission algorithm uses sequences of retransmits, in which
-        * every sequence contains exponential delayed retransmits. These
-        * sequences are compareable to the keyingtries mechanism used in pluto.
+        * A return value of zero means the request should not be
+        * retransmitted again.
         *
         * @param this                          calling object
         * @param retransmitted         number of times a message was retransmitted so far
-        * @param max_sequences         maximum number of retransmission sequences to allow
-        * @return                                      time in milliseconds, when to schedule next retransmit
+        * @return                                      time in milliseconds, when to do next retransmit
         */
        u_int32_t (*get_retransmit_timeout) (configuration_t *this, 
-                                                                                u_int32_t retransmitted, 
-                                                                                u_int32_t max_sequences);
+                                                                                u_int32_t retransmitted);
        
        /**
         * @brief Returns the timeout for an half open IKE_SA in ms.
index e68a8ad2b2f250e54956c0f21a847825d3c60051..fa23955fbf1adcb59e7450e4e348f01bae14848a 100644 (file)
@@ -78,6 +78,16 @@ struct private_policy_t {
         */
        identification_t *other_id;
        
+       /**
+        * virtual IP to use locally
+        */
+       host_t *my_virtual_ip;
+       
+       /**
+        * virtual IP to use remotly
+        */
+       host_t *other_virtual_ip;
+       
        /**
         * Method to use for own authentication data
         */
@@ -209,7 +219,8 @@ static eap_type_t get_eap_type(private_policy_t *this)
 /**
  * Get traffic selectors, with wildcard-address update
  */
-static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_t *list, host_t *host)
+static linked_list_t *get_traffic_selectors(private_policy_t *this,
+                                                                                       linked_list_t *list, host_t *host)
 {
        iterator_t *iterator;
        traffic_selector_t *current;
@@ -222,7 +233,10 @@ static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_
                /* we make a copy of the TS, this allows us to update wildcard
                 * addresses in it. We won't pollute the shared policy. */
                current = current->clone(current);
-               current->update_address_range(current, host);
+               if (host)
+               {
+                       current->update_address_range(current, host);
+               }
                
                result->insert_last(result, (void*)current);
        }
@@ -269,7 +283,10 @@ static linked_list_t *select_traffic_selectors(private_policy_t *this,
                /* we make a copy of the TS, this allows us to update wildcard
                 * addresses in it. We won't pollute the shared policy. */
                stored_ts = stored_ts->clone(stored_ts);
-               stored_ts->update_address_range(stored_ts, host);
+               if (host)
+               {
+                       stored_ts->update_address_range(stored_ts, host);
+               }
                
                supplied_iter->reset(supplied_iter);
                /* iterate over all supplied traffic selectors */
@@ -456,6 +473,30 @@ static mode_t get_mode(private_policy_t *this)
        return this->mode;
 }
 
+/**
+ * Implementation of policy_t.get_virtual_ip.
+ */
+static host_t* get_virtual_ip(private_policy_t *this, host_t *suggestion)
+{
+       if (suggestion == NULL)
+       {
+               if (this->my_virtual_ip)
+               {
+                       return this->my_virtual_ip->clone(this->my_virtual_ip);
+               }
+               return NULL;
+       }
+       if (this->other_virtual_ip)
+       {
+               return this->other_virtual_ip->clone(this->other_virtual_ip);
+       }
+       if (suggestion->is_anyaddr(suggestion))
+       {
+               return NULL;
+       }
+       return suggestion->clone(suggestion);
+}
+
 /**
  * Implements policy_t.get_ref.
  */
@@ -477,14 +518,8 @@ static void destroy(private_policy_t *this)
                this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
                
                /* delete certification authorities */
-               if (this->my_ca)
-               {
-                       this->my_ca->destroy(this->my_ca);
-               }
-               if (this->other_ca)
-               {
-                       this->other_ca->destroy(this->other_ca);
-               }
+               DESTROY_IF(this->my_ca);
+               DESTROY_IF(this->other_ca);
                
                /* delete updown script */
                if (this->updown)
@@ -495,6 +530,8 @@ static void destroy(private_policy_t *this)
                /* delete ids */
                this->my_id->destroy(this->my_id);
                this->other_id->destroy(this->other_id);
+               DESTROY_IF(this->my_virtual_ip);
+               DESTROY_IF(this->other_virtual_ip);
                
                free(this->name);
                free(this);
@@ -505,6 +542,7 @@ static void destroy(private_policy_t *this)
  * Described in header-file
  */
 policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
+                                               host_t *my_virtual_ip, host_t *other_virtual_ip,
                                                auth_method_t auth_method, eap_type_t eap_type,
                                                u_int32_t hard_lifetime, u_int32_t soft_lifetime, 
                                                u_int32_t jitter, char *updown, bool hostaccess,
@@ -536,6 +574,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
        this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
        this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
        this->public.get_mode = (mode_t (*) (policy_t *))get_mode;
+       this->public.get_virtual_ip = (host_t* (*)(policy_t*,host_t*))get_virtual_ip;
        this->public.get_ref = (void (*) (policy_t*))get_ref;
        this->public.destroy = (void (*) (policy_t*))destroy;
        
@@ -543,6 +582,8 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
        this->name = strdup(name);
        this->my_id = my_id;
        this->other_id = other_id;
+       this->my_virtual_ip = my_virtual_ip;
+       this->other_virtual_ip = other_virtual_ip;
        this->auth_method = auth_method;
        this->eap_type = eap_type;
        this->hard_lifetime = hard_lifetime;
index a2d9ae8d09f935d1bd42d2ff1ada86b1f7c0ff7c..d8916b29ec7e0257f3306889f2e80a1056fb8669 100644 (file)
@@ -328,6 +328,25 @@ struct policy_t {
         */
        mode_t (*get_mode) (policy_t *this);
        
+       /**
+        * @brief Get a virtual IP for the local or the remote host.
+        *
+        * By supplying NULL as IP, an IP for the local host is requested. It
+        * may be %any or specific. 
+        * By supplying %any as host, an IP from the pool is selected to be
+        * served to the peer.
+        * If a specified host is supplied, it is checked if this address
+        * is acceptable to serve to the peer. If so, it is returned. Otherwise,
+        * an alternative IP is returned.
+        * In any mode, this call may return NULL indicating virtual IP should
+        * not be used.
+        * 
+        * @param this                  policy
+        * @param suggestion    NULL, %any or specific, see description
+        * @return                              clone of an IP to use, or NULL
+        */
+       host_t* (*get_virtual_ip) (policy_t *this, host_t *suggestion);
+       
        /**
         * @brief Get a new reference.
         *
@@ -356,6 +375,8 @@ struct policy_t {
  * @brief Create a configuration object for IKE_AUTH and later.
  * 
  * name-string gets cloned, ID's not.
+ * Virtual IPs are used if they are != NULL. A %any host means the virtual
+ * IP should be obtained from the other peer.
  * Lifetimes are in seconds. To prevent to peers to start rekeying at the
  * same time, a jitter may be specified. Rekeying of an SA starts at
  * (soft_lifetime - random(0, jitter)). After a successful rekeying, 
@@ -366,6 +387,8 @@ struct policy_t {
  * @param name                         name of the policy
  * @param my_id                        identification_t for ourselves
  * @param other_id                     identification_t for the remote guy
+ * @param my_virtual_ip                virtual IP for local host, or NULL
+ * @param other_virtual_ip     virtual IP for remote host, or NULL
  * @param auth_method          Authentication method to use for our(!) auth data
  * @param eap_type                     EAP type to use for peer authentication
  * @param hard_lifetime                lifetime before deleting an SA
@@ -381,6 +404,7 @@ struct policy_t {
  */
 policy_t *policy_create(char *name, 
                                                identification_t *my_id, identification_t *other_id,
+                                               host_t *my_virtual_ip, host_t *other_virtual_ip,
                                                auth_method_t auth_method, eap_type_t eap_type,
                                                u_int32_t hard_lifetime, u_int32_t soft_lifetime,
                                                u_int32_t jitter, char *updown, bool hostaccess,
index 2afeb5e48d04622b6714e488eb8fead10e982727..519c90f77319da03b2cebbbaa49989a1a07a1904 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 /*
+ * Copyright (C) 2007 Tobias Brunner
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -493,6 +494,26 @@ static void update_address_range(private_traffic_selector_t *this, host_t *host)
        }
 }
 
+/**
+ * Implements traffic_selector_t.includes.
+ */
+static bool includes(private_traffic_selector_t *this, host_t *host)
+{
+       chunk_t addr;
+       int family = host->get_family(host);
+
+       if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
+               (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
+       {
+               addr = host->get_address(host);
+               
+               return memcmp(this->from, addr.ptr, addr.len) <= 0 &&
+                               memcmp(this->to, addr.ptr, addr.len) >= 0;
+       }
+
+       return FALSE;   
+}
+
 /**
  * Implements traffic_selector_t.clone.
  */
@@ -698,6 +719,7 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts
        this->public.get_type = (ts_type_t(*)(traffic_selector_t*))get_type;
        this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol;
        this->public.is_host = (bool(*)(traffic_selector_t*,host_t*))is_host;
+       this->public.includes = (bool(*)(traffic_selector_t*,host_t*))includes;
        this->public.update_address_range = (void(*)(traffic_selector_t*,host_t*))update_address_range;
        this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone_;
        this->public.destroy = (void(*)(traffic_selector_t*))destroy;
@@ -709,3 +731,6 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts
        
        return this;
 }
+
+/* vim: set ts=4 sw=4 noet: */
+
index 5d1ccaf2fe863c14592aeec9cd89242ae38cf998..7728ba307d1ee8d085e6f178a57f0d9e402c099d 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 /*
+ * Copyright (C) 2007 Tobias Brunner
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -105,7 +106,7 @@ struct traffic_selector_t {
         *
         * Chunk is in network order gets allocated.
         *
-        * @param this          calling object
+        * @param this          called object
         * @return                      chunk containing the address
         */
        chunk_t (*get_from_address) (traffic_selector_t *this);
@@ -115,7 +116,7 @@ struct traffic_selector_t {
         *
         * Chunk is in network order gets allocated.
         *
-        * @param this          calling object
+        * @param this          called object
         * @return                      chunk containing the address
         */
        chunk_t (*get_to_address) (traffic_selector_t *this);
@@ -126,7 +127,7 @@ struct traffic_selector_t {
         * Port is in host order, since the parser converts it.
         * Size depends on protocol.
         *  
-        * @param this          calling object
+        * @param this          called object
         * @return                      port
         */
        u_int16_t (*get_from_port) (traffic_selector_t *this);
@@ -137,7 +138,7 @@ struct traffic_selector_t {
         * Port is in host order, since the parser converts it.
         * Size depends on protocol.
         *
-        * @param this          calling object
+        * @param this          called object
         * @return                      port
         */
        u_int16_t (*get_to_port) (traffic_selector_t *this);
@@ -145,7 +146,7 @@ struct traffic_selector_t {
        /**
         * @brief Get the type of the traffic selector.
         *
-        * @param this          calling obect
+        * @param this          called object
         * @return                      ts_type_t specifying the type
         */
        ts_type_t (*get_type) (traffic_selector_t *this);
@@ -153,7 +154,7 @@ struct traffic_selector_t {
        /**
         * @brief Get the protocol id of this ts.
         *
-        * @param this          calling obect
+        * @param this          called object
         * @return                      protocol id
         */
        u_int8_t (*get_protocol) (traffic_selector_t *this);
@@ -167,7 +168,7 @@ struct traffic_selector_t {
         * If host is NULL, the traffic selector is checked if it is a single host,
         * but not a specific one.
         *
-        * @param this          calling obect
+        * @param this          called object
         * @param host          host_t specifying the address range
         */
        bool (*is_host) (traffic_selector_t *this, host_t* host);
@@ -180,7 +181,7 @@ struct traffic_selector_t {
         * starts from the supplied address and also ends there 
         * (which means it is a one-host-address-range ;-).
         *
-        * @param this          calling obect
+        * @param this          called object
         * @param host          host_t specifying the address range
         */
        void (*update_address_range) (traffic_selector_t *this, host_t* host);
@@ -193,11 +194,19 @@ struct traffic_selector_t {
         * @return                      pointer to a string.
         */
        bool (*equals) (traffic_selector_t *this, traffic_selector_t *other);
+
+       /**
+        * @brief Check if a specific host is included in the address range of this traffic selector.
+        *
+        * @param this          called object
+        * @param host          the host to check
+        */
+       bool (*includes) (traffic_selector_t *this, host_t *host);
        
        /**
         * @brief Destroys the ts object
         *
-        * @param this          calling object
+        * @param this          called object
         */
        void (*destroy) (traffic_selector_t *this);
 };
@@ -269,3 +278,6 @@ traffic_selector_t *traffic_selector_create_from_subnet(
                                                                        u_int8_t protocol, u_int16_t port);
 
 #endif /* TRAFFIC_SELECTOR_H_ */
+
+/* vim: set ts=4 sw=4 noet: */
+
index fb37c996d2ab6a9254aa1cd5e4f0642f44d13f93..acc3abd1b669ec7302bed165dd909d39edbfba59 100644 (file)
@@ -345,6 +345,7 @@ static status_t get_payload_rule(private_message_t *this, payload_type_t payload
  */
 static void set_ike_sa_id (private_message_t *this,ike_sa_id_t *ike_sa_id)
 {
+       DESTROY_IF(this->ike_sa_id);
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
 }
 
@@ -489,6 +490,29 @@ static void add_payload(private_message_t *this, payload_t *payload)
                 payload_type_names, payload->get_type(payload));
 }
 
+/**
+ * Implementation of message_t.add_notify.
+ */
+static void add_notify(private_message_t *this, bool flush, notify_type_t type, 
+                                          chunk_t data)
+{
+       notify_payload_t *notify;
+       payload_t *payload;
+       
+       if (flush)
+       {
+               while (this->payloads->remove_last(this->payloads, 
+                                                                                               (void**)&payload) == SUCCESS)
+               {
+                       payload->destroy(payload);
+               }
+       }
+       notify = notify_payload_create();
+       notify->set_notify_type(notify, type);
+       notify->set_notification_data(notify, data);
+       add_payload(this, (payload_t*)notify);
+}
+
 /**
  * Implementation of message_t.set_source.
  */
@@ -522,13 +546,34 @@ static host_t * get_destination(private_message_t *this)
 }
 
 /**
- * Implementation of message_t.get_destination.
+ * Implementation of message_t.get_payload_iterator.
  */
 static iterator_t *get_payload_iterator(private_message_t *this)
 {
        return this->payloads->create_iterator(this->payloads, TRUE);
 }
 
+/**
+ * Implementation of message_t.get_payload.
+ */
+static payload_t *get_payload(private_message_t *this, payload_type_t type)
+{
+       payload_t *current, *found = NULL;
+       iterator_t *iterator;
+       
+       iterator = this->payloads->create_iterator(this->payloads, TRUE);
+       while (iterator->iterate(iterator, (void**)&current))
+       {
+               if (current->get_type(current) == type)
+               {
+                       found = current;
+                       break;
+               }
+       }
+       iterator->destroy(iterator);
+       return found;
+}
+
 /**
  * output handler in printf()
  */
@@ -786,6 +831,10 @@ static status_t generate(private_message_t *this, crypter_t *crypter, signer_t*
  */
 static packet_t *get_packet (private_message_t *this)
 {
+       if (this->packet == NULL)
+       {
+               return NULL;
+       }
        return this->packet->clone(this->packet);
 }
 
@@ -794,6 +843,10 @@ static packet_t *get_packet (private_message_t *this)
  */
 static chunk_t get_packet_data (private_message_t *this)
 {
+       if (this->packet == NULL)
+       {
+               return chunk_empty;
+       }
        return chunk_clone(this->packet->get_data(this->packet));
 }
 
@@ -1147,7 +1200,6 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t
        status = verify(this);
        if (status != SUCCESS)
        {
-               DBG1(DBG_ENC, "verification of message failed");
                return status;
        }
        
@@ -1191,12 +1243,14 @@ message_t *message_create_from_packet(packet_t *packet)
        this->public.set_request = (void(*)(message_t*, bool))set_request;
        this->public.get_request = (bool(*)(message_t*))get_request;
        this->public.add_payload = (void(*)(message_t*,payload_t*))add_payload;
+       this->public.add_notify = (void(*)(message_t*,bool,notify_type_t,chunk_t))add_notify;
        this->public.generate = (status_t (*) (message_t *,crypter_t*,signer_t*,packet_t**)) generate;
        this->public.set_source = (void (*) (message_t*,host_t*)) set_source;
        this->public.get_source = (host_t * (*) (message_t*)) get_source;
        this->public.set_destination = (void (*) (message_t*,host_t*)) set_destination;
        this->public.get_destination = (host_t * (*) (message_t*)) get_destination;
        this->public.get_payload_iterator = (iterator_t * (*) (message_t *)) get_payload_iterator;
+       this->public.get_payload = (payload_t * (*) (message_t *, payload_type_t)) get_payload;
        this->public.parse_header = (status_t (*) (message_t *)) parse_header;
        this->public.parse_body = (status_t (*) (message_t *,crypter_t*,signer_t*)) parse_body;
        this->public.get_packet = (packet_t * (*) (message_t*)) get_packet;
index dfb6d64af922d290769a91cce4b22d67f4663505..73c2e05c67c86b37ea8d96bdd68fce9037220324 100644 (file)
@@ -183,6 +183,21 @@ struct message_t {
         */     
        void (*add_payload) (message_t *this, payload_t *payload);
 
+       /**
+        * @brief Build a notify payload and add it to the message.
+        * 
+        * This is a helper method to create notify messages or add
+        * notify payload to messages. The flush parameter specifies if existing
+        * payloads should get removed before appending the notify.
+        *
+        * @param this                  message_t object
+        * @param flush                 TRUE to remove existing payloads
+        * @param type                  type of the notify
+        * @param data                  a chunk of data to add to the notify, gets cloned
+        */     
+       void (*add_notify) (message_t *this, bool flush, notify_type_t type, 
+                                               chunk_t data);
+
        /**
         * @brief Parses header of message.
         * 
@@ -303,6 +318,17 @@ struct message_t {
         */     
        iterator_t * (*get_payload_iterator) (message_t *this);
        
+       /**
+        * @brief Find a payload of a spicific type.
+        * 
+        * Returns the first occurance. 
+        *
+        * @param this          message_t object
+        * @param type          type of the payload to find
+        * @return                      payload, or NULL if no such payload found
+        */     
+       payload_t* (*get_payload) (message_t *this, payload_type_t type);
+       
        /**
         * @brief Returns a clone of the internal stored packet_t object.
         *
index 2e690b45d6db645ee63ca739f839359b8d1eb1ec..8f477ffd005ad3bafc2e702afccfbca48f9378b6 100644 (file)
@@ -270,7 +270,7 @@ cert_payload_t *cert_payload_create()
        /* private variables */
        this->critical = FALSE;
        this->next_payload = NO_PAYLOAD;
-       this->payload_length =CERT_PAYLOAD_HEADER_LENGTH;
+       this->payload_length = CERT_PAYLOAD_HEADER_LENGTH;
        this->cert_data = chunk_empty;
 
        return (&(this->public));
index 86f2e35242643873b1592c6e4e05ee3c64458075..fcddcf971634193f30588b747c18d23722cf6441 100644 (file)
@@ -306,7 +306,10 @@ certreq_payload_t *certreq_payload_create_from_cacerts(void)
        int count = iterator->get_count(iterator);
 
        if (count == 0)
+       {
+               iterator->destroy(iterator);
                return NULL;
+       }
 
        this = certreq_payload_create();
        keyids = chunk_alloc(count * HASH_SIZE_SHA1);
index e7000e1b5f32867dfa2c8aee8a64b63438d0d106..0aa82169f2fed529568f99681dc7b609da6eb5eb 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <encoding/payloads/encodings.h>
 #include <library.h>
+#include <daemon.h>
 
 
 typedef struct private_configuration_attribute_t private_configuration_attribute_t;
@@ -50,7 +51,6 @@ struct private_configuration_attribute_t {
         * Length of the attribute.
         */
        u_int16_t attribute_length;
-       
 
        /**
         * Attribute value as chunk.
@@ -58,7 +58,7 @@ struct private_configuration_attribute_t {
        chunk_t attribute_value;
 };
 
-ENUM_BEGIN(configuration_attribute_type_name, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS,
+ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS,
        "INTERNAL_IP4_ADDRESS",
        "INTERNAL_IP4_NETMASK",
        "INTERNAL_IP4_DNS",
@@ -67,14 +67,14 @@ ENUM_BEGIN(configuration_attribute_type_name, INTERNAL_IP4_ADDRESS, INTERNAL_IP6
        "INTERNAL_IP4_DHCP",
        "APPLICATION_VERSION",
        "INTERNAL_IP6_ADDRESS");
-ENUM_NEXT(configuration_attribute_type_name, INTERNAL_IP6_DNS, INTERNAL_IP6_SUBNET, INTERNAL_IP6_ADDRESS,
+ENUM_NEXT(configuration_attribute_type_names, INTERNAL_IP6_DNS, INTERNAL_IP6_SUBNET, INTERNAL_IP6_ADDRESS,
        "INTERNAL_IP6_DNS",
        "INTERNAL_IP6_NBNS",
        "INTERNAL_IP6_DHCP",
        "INTERNAL_IP4_SUBNET",
        "SUPPORTED_ATTRIBUTES",
        "INTERNAL_IP6_SUBNET");
-ENUM_END(configuration_attribute_type_name, INTERNAL_IP6_SUBNET);
+ENUM_END(configuration_attribute_type_names, INTERNAL_IP6_SUBNET);
 
 /**
  * Encoding rules to parse or generate a configuration attribute.
@@ -111,6 +111,14 @@ encoding_rule_t configuration_attribute_encodings[] = {
  */
 static status_t verify(private_configuration_attribute_t *this)
 {
+       bool failed = FALSE;
+
+       if (this->attribute_length != this->attribute_value.len)
+       {
+               DBG1(DBG_ENC, "invalid attribute length");
+               return FAILED;
+       }
+
        switch (this->attribute_type)
        {
          case INTERNAL_IP4_ADDRESS:
@@ -119,27 +127,54 @@ static status_t verify(private_configuration_attribute_t *this)
                 case INTERNAL_IP4_NBNS:
                 case INTERNAL_ADDRESS_EXPIRY:
                 case INTERNAL_IP4_DHCP:
-                case APPLICATION_VERSION:
+                       if (this->attribute_length != 0 && this->attribute_length != 4)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
+                case INTERNAL_IP4_SUBNET:
+                       if (this->attribute_length != 0 && this->attribute_length != 8)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
                 case INTERNAL_IP6_ADDRESS:
+                case INTERNAL_IP6_SUBNET:
+                       if (this->attribute_length != 0 && this->attribute_length != 17)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
                 case INTERNAL_IP6_DNS:
                 case INTERNAL_IP6_NBNS:
                 case INTERNAL_IP6_DHCP:
-                case INTERNAL_IP4_SUBNET:
+                       if (this->attribute_length != 0 && this->attribute_length != 16)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
                 case SUPPORTED_ATTRIBUTES:
-                case INTERNAL_IP6_SUBNET:
-                {
-                       /* Attribute types are not checked in here */
+                       if (this->attribute_length % 2)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
+                case APPLICATION_VERSION:
+                       /* any length acceptable */
                        break;
-                }
                 default:
+                       DBG1(DBG_ENC, "unknown attribute type %N", 
+                                configuration_attribute_type_names, this->attribute_type);
                        return FAILED;
        }
        
-       if (this->attribute_length != this->attribute_value.len)
+       if (failed)
        {
+               DBG1(DBG_ENC, "invalid attribute length %d for %N",
+                        this->attribute_length, configuration_attribute_type_names,
+                        this->attribute_type);
                return FAILED;
        }
-       
        return SUCCESS;
 }
 
@@ -208,9 +243,8 @@ static chunk_t get_value (private_configuration_attribute_t *this)
        return this->attribute_value;
 }
 
-
 /**
- * Implementation of configuration_attribute_t.set_attribute_type.
+ * Implementation of configuration_attribute_t.set_type.
  */
 static void set_attribute_type (private_configuration_attribute_t *this, u_int16_t type)
 {
@@ -218,7 +252,7 @@ static void set_attribute_type (private_configuration_attribute_t *this, u_int16
 }
 
 /**
- * Implementation of configuration_attribute_t.get_attribute_type.
+ * Implementation of configuration_attribute_t.get_type.
  */
 static u_int16_t get_attribute_type (private_configuration_attribute_t *this)
 {
@@ -226,7 +260,7 @@ static u_int16_t get_attribute_type (private_configuration_attribute_t *this)
 }
 
 /**
- * Implementation of configuration_attribute_t.get_attribute_length.
+ * Implementation of configuration_attribute_t.get_length.
  */
 static u_int16_t get_attribute_length (private_configuration_attribute_t *this)
 {
@@ -265,9 +299,9 @@ configuration_attribute_t *configuration_attribute_create()
        /* public functions */
        this->public.set_value = (void (*) (configuration_attribute_t *,chunk_t)) set_value;
        this->public.get_value = (chunk_t (*) (configuration_attribute_t *)) get_value;
-       this->public.set_attribute_type = (void (*) (configuration_attribute_t *,u_int16_t type)) set_attribute_type;
-       this->public.get_attribute_type = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_type;
-       this->public.get_attribute_length = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_length;
+       this->public.set_type = (void (*) (configuration_attribute_t *,u_int16_t type)) set_attribute_type;
+       this->public.get_type = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_type;
+       this->public.get_length = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_length;
        this->public.destroy = (void (*) (configuration_attribute_t *)) destroy;
        
        /* set default values of the fields */
index 5a11d0a35a8695b11b358da6ae36ef2a90aa773c..5c4f65b1432295aa86c650d2c604b1c642263d64 100644 (file)
@@ -109,7 +109,7 @@ struct configuration_attribute_t {
         * @param this  calling configuration_attribute_t object
         * @param type  type to set (most significant bit is set to zero)
         */
-       void (*set_attribute_type) (configuration_attribute_t *this, u_int16_t type);
+       void (*set_type) (configuration_attribute_t *this, u_int16_t type);
        
        /**
         * @brief get the type of the attribute.
@@ -117,7 +117,7 @@ struct configuration_attribute_t {
         * @param this  calling configuration_attribute_t object
         * @return              type of the value
         */
-       u_int16_t (*get_attribute_type) (configuration_attribute_t *this);
+       u_int16_t (*get_type) (configuration_attribute_t *this);
        
        /**
         * @brief get the length of an attribute.
@@ -125,7 +125,7 @@ struct configuration_attribute_t {
         * @param this  calling configuration_attribute_t object
         * @return              type of the value
         */
-       u_int16_t (*get_attribute_length) (configuration_attribute_t *this);
+       u_int16_t (*get_length) (configuration_attribute_t *this);
        
        /**
         * @brief Destroys an configuration_attribute_t object.
index bd16abc225a7a9952f451c35482903920f342173..380ed9681341db591f9412d61c7ffcd1483e5aee 100644 (file)
@@ -204,9 +204,9 @@ static size_t get_length(private_cp_payload_t *this)
 /**
  * Implementation of cp_payload_t.create_configuration_attribute_iterator.
  */
-static iterator_t *create_configuration_attribute_iterator (private_cp_payload_t *this,bool forward)
+static iterator_t *create_attribute_iterator (private_cp_payload_t *this)
 {
-       return this->attributes->create_iterator(this->attributes,forward);
+       return this->attributes->create_iterator(this->attributes, TRUE);
 }
 
 /**
@@ -261,7 +261,7 @@ cp_payload_t *cp_payload_create()
        this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
        
        /* public functions */
-       this->public.create_configuration_attribute_iterator = (iterator_t* (*) (cp_payload_t *,bool)) create_configuration_attribute_iterator;
+       this->public.create_attribute_iterator = (iterator_t* (*) (cp_payload_t *)) create_attribute_iterator;
        this->public.add_configuration_attribute = (void (*) (cp_payload_t *,configuration_attribute_t *)) add_configuration_attribute;
        this->public.set_config_type = (void (*) (cp_payload_t *, config_type_t)) set_config_type;
        this->public.get_config_type = (config_type_t (*) (cp_payload_t *)) get_config_type;
index af36b48a396a65acd7fe393ff181fbd4af1e7df5..27ff41005bd127f6ff39fc9bc8b69044fb65e6f9 100644 (file)
@@ -77,23 +77,19 @@ struct cp_payload_t {
        /**
         * @brief Creates an iterator of stored configuration_attribute_t objects.
         * 
-        * @warning The created iterator has to get destroyed by the caller!
-        * 
-        * @warning When deleting an attribute using this iterator, 
-        *                      the length of this configuration_attribute_t has to be refreshed 
-        *                      by calling get_length()!
+        * When deleting an attribute using this iterator, the length of this
+        * configuration_attribute_t has to be refreshed by calling get_length()!
         *
         * @param this                  calling cp_payload_t object
-        * @param[in] forward   iterator direction (TRUE: front to end)
         * @return                              created iterator_t object
         */
-       iterator_t *(*create_configuration_attribute_iterator) (cp_payload_t *this, bool forward);
+       iterator_t *(*create_attribute_iterator) (cp_payload_t *this);
        
        /**
         * @brief Adds a configuration_attribute_t object to this object.
         * 
-        * @warning The added configuration_attribute_t object is 
-        *                      getting destroyed in destroy function of cp_payload_t.
+        * The added configuration_attribute_t object is getting destroyed in
+        * destroy function of cp_payload_t.
         *
         * @param this                  calling cp_payload_t object
         * @param attribute             configuration_attribute_t object to add
index 38ee0946db6f3b958e3f88b9afa1f0233b97bc83..a04901a90dae9868a25feb577ce6d92bc6e08d22 100644 (file)
@@ -209,6 +209,9 @@ static status_t verify(private_notify_payload_t *this)
                        diffie_hellman_group_t dh_group;
                        if (this->notification_data.len != 2)
                        {
+                               DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
+                                        notify_type_names, this->notify_type,
+                                        this->notification_data.len);
                                return FAILED;
                        }
                        dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
@@ -403,7 +406,10 @@ static chunk_t get_notification_data(private_notify_payload_t *this)
 static status_t set_notification_data(private_notify_payload_t *this, chunk_t notification_data)
 {
        chunk_free(&this->notification_data);
-       this->notification_data = chunk_clone(notification_data);
+       if (notification_data.len > 0)
+       {
+               this->notification_data = chunk_clone(notification_data);
+       }
        compute_length(this);
        return SUCCESS;
 }
index ca8b2a616c282d1f82889c77dfb2f2ed78a4b07d..f2fa91569a1e9997502d2e1a07974544533925ec 100644 (file)
@@ -58,10 +58,7 @@ struct private_packet_t {
  */
 static void set_source(private_packet_t *this, host_t *source)
 {
-       if (this->source)
-       {
-               this->source->destroy(this->source);    
-       }
+       DESTROY_IF(this->source);
        this->source = source;
 }
 
@@ -70,10 +67,7 @@ static void set_source(private_packet_t *this, host_t *source)
  */
 static void set_destination(private_packet_t *this, host_t *destination)
 {
-       if (this->destination)
-       {
-               this->destination->destroy(this->destination);  
-       }
+       DESTROY_IF(this->destination);
        this->destination = destination;
 }
 
index 4deadf3fe5d58aa8e4772c81e05e91adba220d73..b4ffb258d3ea2f75fa14aa79b5a74bf1c732a7ad 100644 (file)
@@ -57,8 +57,8 @@ static status_t execute(private_acquire_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
-                                                                                                          this->reqid);
+       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                       this->reqid, TRUE);
        if (ike_sa == NULL)
        {
                DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for acquiring",
index 71ee3f00a1353f0265ce82f0d54e95dde855142a..f694696b051febab0c2bc1666467075a089e04cb 100644 (file)
@@ -68,8 +68,8 @@ static status_t execute(private_delete_child_sa_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
-                                                                                                          this->reqid);
+       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                       this->reqid, TRUE);
        if (ike_sa == NULL)
        {
                DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for delete",
index 9e8173c39709d2d70ef9ce60a678a1434378baf6..706155aa62462b7b4a98c947ba8d5728f2e25751 100644 (file)
@@ -62,41 +62,38 @@ static status_t execute(private_delete_ike_sa_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       if (this->delete_if_established)
+       ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+                                                                                         this->ike_sa_id);
+       if (ike_sa)
        {
-               if (charon->ike_sa_manager->delete(charon->ike_sa_manager, 
-                       this->ike_sa_id) != SUCCESS)
+               if (this->delete_if_established)
                {
-                       DBG2(DBG_JOB, "IKE SA didn't exist anymore");
-               }
-               return DESTROY_ME;
-       }
-       else
-       {
-               ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id);
-               if (ike_sa == NULL)
-               {
-                       /* hm, somebody was faster ;-) */
-                       return DESTROY_ME;
+                       if (ike_sa->delete(ike_sa) == DESTROY_ME)
+                       {
+                               charon->ike_sa_manager->checkin_and_destroy(
+                                                                                               charon->ike_sa_manager, ike_sa);
+                       }
+                       else
+                       {
+                               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+                       }
                }
-               
-               switch (ike_sa->get_state(ike_sa))
+               else
                {
-                       case IKE_ESTABLISHED:
+                       /* destroy only if not ESTABLISHED */
+                       if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
                        {
-                               /* IKE_SA is established and so is not getting destroyed */
                                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-                               return DESTROY_ME;
                        }
-                       default:
+                       else
                        {
-                               /* IKE_SA is half open and gets destroyed */
                                DBG1(DBG_JOB, "deleting half open IKE_SA after timeout");
-                               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
-                               return DESTROY_ME;
+                               charon->ike_sa_manager->checkin_and_destroy(
+                                                                                               charon->ike_sa_manager, ike_sa);
                        }
                }
        }
+       return DESTROY_ME;
 }
 
 /**
index 18671610d134627e3b94ef4a561185e852aff552..c4f211a0439d9beb09fa9e58bf4e85d9cc66a375 100644 (file)
@@ -64,6 +64,13 @@ static void send_notify_response(private_incoming_packet_job_t *this,
        packet_t *packet;
        ike_sa_id_t *ike_sa_id;
        
+       if (request->get_exchange_type(request) != IKE_SA_INIT)
+       {
+               /* TODO: Use transforms implementing the "NULL" algorithm,
+                  we are unable to generate message otherwise */
+               return;
+       }
+       
        ike_sa_id = request->get_ike_sa_id(request);
        ike_sa_id = ike_sa_id->clone(ike_sa_id);
        ike_sa_id->switch_initiator(ike_sa_id);
@@ -80,8 +87,6 @@ static void send_notify_response(private_incoming_packet_job_t *this,
        ike_sa_id->destroy(ike_sa_id);
        notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
        response->add_payload(response, (payload_t *)notify);
-       /* generation may fail, as most messages need a crypter/signer.
-        * TODO: Use transforms implementing the "NULL" algorithm */
        if (response->generate(response, NULL, NULL, &packet) != SUCCESS)
        {
                response->destroy(response);
@@ -107,12 +112,12 @@ static status_t execute(private_incoming_packet_job_t *this)
        message = message_create_from_packet(this->packet->clone(this->packet));
        src = message->get_source(message);
        dst = message->get_destination(message);
-       DBG1(DBG_NET, "received packet: from %#H to %#H", src, dst);
        
        status = message->parse_header(message);
        if (status != SUCCESS)
        {
-               DBG1(DBG_NET, "received message with invalid IKE header, ignored");
+               DBG1(DBG_NET, "received message from %H with invalid IKE header, "
+                        "ignored", src);
                message->destroy(message);
                return DESTROY_ME;
        }
@@ -120,11 +125,12 @@ static status_t execute(private_incoming_packet_job_t *this)
        if ((message->get_major_version(message) != IKE_MAJOR_VERSION) ||
                (message->get_minor_version(message) != IKE_MINOR_VERSION))
        {
-               DBG1(DBG_NET,
-                        "received a packet with IKE version %d.%d, not supported",
-                         message->get_major_version(message),
-                         message->get_minor_version(message));
-               if ((message->get_exchange_type(message) == IKE_SA_INIT) && (message->get_request(message)))
+               DBG1(DBG_NET, "received message from %H with unsupported IKE "
+                       "version %d.%d, ignored", src,  message->get_major_version(message),
+                       message->get_minor_version(message));
+                       
+               if (message->get_exchange_type(message) == IKE_SA_INIT && 
+                       message->get_request(message))
                {
                        send_notify_response(this, message, INVALID_MAJOR_VERSION);
                }
@@ -138,19 +144,19 @@ static status_t execute(private_incoming_packet_job_t *this)
        ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id);
        if (ike_sa == NULL)
        {
-               DBG1(DBG_NET, "received packet for IKE_SA: %J, but no such IKE_SA",
-                        ike_sa_id);
+               DBG1(DBG_NET, "received packet from %#H for IKE_SA: %J, but no such "
+                        "IKE_SA", src, ike_sa_id);
                if (message->get_request(message))
                {
-                       /* TODO: send notify if we have NULL crypters,
-                        * see todo in send_notify_response
-                       send_notify_response(this, message, INVALID_IKE_SPI); */
+                       send_notify_response(this, message, INVALID_IKE_SPI);
                }
                ike_sa_id->destroy(ike_sa_id);  
                message->destroy(message);
                return DESTROY_ME;
        }
        
+       DBG1(DBG_NET, "received packet: from %#H to %#H", src, dst);
+       
        status = ike_sa->process_message(ike_sa, message);
        if (status == DESTROY_ME)
        {
index 8b943a3f1e2561da43681c318b68653d8d3eac30..af50663d6587c797a00c347e9a5b1fa2c21c5768 100644 (file)
@@ -44,11 +44,6 @@ struct private_initiate_job_t {
         */
        connection_t *connection;
        
-       /**
-        * host to connect to, use NULL to use connections one
-        */
-       host_t *other;
-       
        /**
         * associated policy to initiate
         */
@@ -70,19 +65,12 @@ static status_t execute(private_initiate_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+       ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
                                                        this->connection->get_my_host(this->connection),
                                                        this->connection->get_other_host(this->connection),
                                                        this->policy->get_my_id(this->policy),
                                                        this->policy->get_other_id(this->policy));
-       
-       if (this->other)
-       {
-               ike_sa->set_other_host(ike_sa, this->other->clone(this->other));
-       }
-       
-       this->connection->get_ref(this->connection);
-       this->policy->get_ref(this->policy);
+
        if (ike_sa->initiate(ike_sa, this->connection, this->policy) != SUCCESS)
        {
                DBG1(DBG_JOB, "initiation failed, going to delete IKE_SA");
@@ -101,15 +89,13 @@ static void destroy(private_initiate_job_t *this)
 {
        this->connection->destroy(this->connection);
        this->policy->destroy(this->policy);
-       DESTROY_IF(this->other);
        free(this);
 }
 
 /*
  * Described in header
  */
-initiate_job_t *initiate_job_create(connection_t *connection, host_t *other,
-                                                                       policy_t *policy)
+initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy)
 {
        private_initiate_job_t *this = malloc_thing(private_initiate_job_t);
        
@@ -121,7 +107,6 @@ initiate_job_t *initiate_job_create(connection_t *connection, host_t *other,
        /* private variables */
        this->connection = connection;
        this->policy = policy;
-       this->other = other;
        
        return &this->public;
 }
index 2fd0ced939616978c23062e433f26a836d0e479b..af1dd9ece30fa6ab37af3eb57a3c765b3ae2ce53 100644 (file)
@@ -51,13 +51,11 @@ struct initiate_job_t {
  * @brief Creates a job of type INITIATE_IKE_SA.
  * 
  * @param connection   connection_t to initialize
- * @param other                        another host to initiate to, NULL to use connections one
  * @param policy               policy to set up
  * @return                             initiate_job_t object
  * 
  * @ingroup jobs
  */
-initiate_job_t *initiate_job_create(connection_t *connection, host_t *other,
-                                                                   policy_t *policy);
+initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy);
 
 #endif /*INITIATE_IKE_SA_JOB_H_*/
index d88843d7cc27669269132ac451c138de62126ec0..337558c2d1350d480bfbf92bd9535e286e2bc519 100644 (file)
@@ -26,7 +26,7 @@
 
 ENUM(job_type_names, INCOMING_PACKET, SEND_DPD,
        "INCOMING_PACKET",
-       "RETRANSMIT_REQUEST",
+       "RETRANSMIT",
        "INITIATE",
        "ROUTE",
        "ACQUIRE",
index ae3fe7974e55fa64877261f5ea82dff272f33ccc..ae67a2bdced1fd5b6c67213e02a7320249bf6205 100644 (file)
@@ -45,9 +45,9 @@ enum job_type_t {
        /** 
         * Retransmit an IKEv2-Message.
         * 
-        * Job is implemented in class retransmit_request_job_t
+        * Job is implemented in class retransmit_job_t
         */
-       RETRANSMIT_REQUEST,
+       RETRANSMIT,
        
        /** 
         * Set up a CHILD_SA, optional with an IKE_SA.
index 5944aa77f930c4f9670e9f81fdab95b6a55f70fe..3422b614da4918733267713d0dd9367c3a173b25 100644 (file)
@@ -67,8 +67,8 @@ static status_t execute(private_rekey_child_sa_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
-                                                                                                          this->reqid);
+       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                       this->reqid, TRUE);
        if (ike_sa == NULL)
        {
                DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for rekeying",
index f0c4bef4f67b8ac061a8b41c6377c49b3efcd737..2539d997eea9ae2276906c3ca50ecd8f54744639 100644 (file)
@@ -61,7 +61,7 @@ static job_type_t get_type(private_rekey_ike_sa_job_t *this)
 static status_t execute(private_rekey_ike_sa_job_t *this)
 {
        ike_sa_t *ike_sa;
-       status_t status;
+       status_t status = SUCCESS;
        
        ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
                                                                                          this->ike_sa_id);
@@ -73,7 +73,7 @@ static status_t execute(private_rekey_ike_sa_job_t *this)
        
        if (this->reauth)
        {
-               status = ike_sa->reauth(ike_sa);
+               ike_sa->reestablish(ike_sa);
        }
        else
        {
similarity index 54%
rename from src/charon/queues/jobs/retransmit_request_job.c
rename to src/charon/queues/jobs/retransmit_job.c
index 1dee6e52165b083d70f59c0e2c6b2766b4ad80e7..5bfa20dfd1ba2d35606587bf630e989d1949145a 100644 (file)
@@ -1,12 +1,12 @@
 /**
- * @file retransmit_request_job.c
+ * @file retransmit_job.c
  * 
- * @brief Implementation of retransmit_request_job_t.
+ * @brief Implementation of retransmit_job_t.
  * 
  */
 
 /*
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
  * for more details.
  */
  
-#include "retransmit_request_job.h"
+#include "retransmit_job.h"
 
 #include <daemon.h>
 
-typedef struct private_retransmit_request_job_t private_retransmit_request_job_t;
+typedef struct private_retransmit_job_t private_retransmit_job_t;
 
 /**
- * Private data of an retransmit_request_job_t Object.
+ * Private data of an retransmit_job_t Object.
  */
-struct private_retransmit_request_job_t {
+struct private_retransmit_job_t {
        /**
-        * Public retransmit_request_job_t interface.
+        * Public retransmit_job_t interface.
         */
-       retransmit_request_job_t public;
+       retransmit_job_t public;
        
        /**
         * Message ID of the request to resend.
@@ -50,33 +50,32 @@ struct private_retransmit_request_job_t {
 /**
  * Implements job_t.get_type.
  */
-static job_type_t get_type(private_retransmit_request_job_t *this)
+static job_type_t get_type(private_retransmit_job_t *this)
 {
-       return RETRANSMIT_REQUEST;
+       return RETRANSMIT;
 }
 
 /**
  * Implementation of job_t.execute.
  */
-static status_t execute(private_retransmit_request_job_t *this)
+static status_t execute(private_retransmit_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id);
-       if (ike_sa == NULL)
+       ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+                                                                                         this->ike_sa_id);
+       if (ike_sa)
        {
-               DBG2(DBG_JOB, "IKE SA could not be checked out. Already deleted?");
-               return DESTROY_ME;
-       }
-       
-       if (ike_sa->retransmit_request(ike_sa, this->message_id) == DESTROY_ME)
-       {
-               /* retransmission hopeless, kill SA */
-               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
-       }
-       else
-       {
-               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+               if (ike_sa->retransmit(ike_sa, this->message_id) == DESTROY_ME)
+               {
+                       /* retransmitted to many times, giving up */
+                       charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+                                                                                                               ike_sa);
+               }
+               else
+               {
+                       charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+               }
        }
        return DESTROY_ME;
 }
@@ -84,7 +83,7 @@ static status_t execute(private_retransmit_request_job_t *this)
 /**
  * Implements job_t.destroy.
  */
-static void destroy(private_retransmit_request_job_t *this)
+static void destroy(private_retransmit_job_t *this)
 {
        this->ike_sa_id->destroy(this->ike_sa_id);
        free(this);
@@ -93,9 +92,9 @@ static void destroy(private_retransmit_request_job_t *this)
 /*
  * Described in header.
  */
-retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id)
+retransmit_job_t *retransmit_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id)
 {
-       private_retransmit_request_job_t *this = malloc_thing(private_retransmit_request_job_t);
+       private_retransmit_job_t *this = malloc_thing(private_retransmit_job_t);
        
        /* interface functions */
        this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
@@ -106,5 +105,5 @@ retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike
        this->message_id = message_id;
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
        
-       return &(this->public);
+       return &this->public;
 }
similarity index 64%
rename from src/charon/queues/jobs/retransmit_request_job.h
rename to src/charon/queues/jobs/retransmit_job.h
index 1897af16d3e102c74cdb0ecb756f6f2710e6b6d9..19e29b9094e11b7830c51eebceb05b8c39073792 100644 (file)
@@ -1,12 +1,12 @@
 /**
- * @file retransmit_request_job.h
+ * @file retransmit_job.h
  * 
- * @brief Interface of retransmit_request_job_t.
+ * @brief Interface of retransmit_job_t.
  * 
  */
 
 /*
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
  * for more details.
  */
 
-#ifndef RESEND_MESSAGE_JOB_H_
-#define RESEND_MESSAGE_JOB_H_
+#ifndef RETRANSMIT_JOB_H_
+#define RETRANSMIT_JOB_H_
 
-typedef struct retransmit_request_job_t retransmit_request_job_t;
+typedef struct retransmit_job_t retransmit_job_t;
 
 #include <library.h>
 #include <queues/jobs/job.h>
 #include <sa/ike_sa_id.h>
 
 /**
- * @brief Class representing an RETRANSMIT_REQUEST Job.
+ * @brief Class representing an retransmit Job.
  *
  * This job is scheduled every time a request is sent over the
  * wire. If the response to the request is not received at schedule
  * time, the retransmission will be initiated.
  *
  * @b Constructors:
- * - retransmit_request_job_create()
+ * - retransmit_job_create()
  *
  * @ingroup jobs
  */
-struct retransmit_request_job_t {
+struct retransmit_job_t {
        /**
         * The job_t interface.
         */
@@ -50,15 +50,15 @@ struct retransmit_request_job_t {
 };
 
 /**
- * @brief Creates a job of type RETRANSMIT_REQUEST.
+ * @brief Creates a job of type retransmit.
  * 
  * @param message_id           message_id of the request to resend
- * @param ike_sa_id                    identification of the ike_sa as ike_sa_id_t object (gets cloned)
- * @return                                     retransmit_request_job_t object
+ * @param ike_sa_id                    identification of the ike_sa as ike_sa_id_t
+ * @return                                     retransmit_job_t object
  * 
  * @ingroup jobs
  */
-retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,
-                                                                                                               ike_sa_id_t *ike_sa_id);
+retransmit_job_t *retransmit_job_create(u_int32_t message_id,
+                                                                               ike_sa_id_t *ike_sa_id);
 
-#endif /* RESEND_MESSAGE_JOB_H_ */
+#endif /* RETRANSMIT_JOB_H_ */
index 5a128474b33b2669613f7eea4155ac49d6e6c62e..bb6281dccf62708490bbb4504df971b390fe73b3 100644 (file)
@@ -69,7 +69,7 @@ static status_t execute(private_route_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+       ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
                                                        this->connection->get_my_host(this->connection),
                                                        this->connection->get_other_host(this->connection),
                                                        this->policy->get_my_id(this->policy),
index 1174714721888ba96dcdc94eacd4b121e0b28a07..fa895eb7ed97b09d11211440ba82a7a09cdcd140 100644 (file)
@@ -6,8 +6,8 @@
  */
 
 /*
+ * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -69,11 +69,6 @@ struct private_child_sa_t {
         */
        child_sa_t public;
        
-       /**
-        * Name of the policy used by this CHILD_SA
-        */
-       char *name;
-       
        struct {
                /** address of peer */
                host_t *addr;
@@ -133,35 +128,10 @@ struct private_child_sa_t {
         */
        time_t install_time;
        
-       /**
-        * Lifetime before rekeying
-        */
-       u_int32_t soft_lifetime;
-       
-       /**
-        * Lifetime before delete
-        */
-       u_int32_t hard_lifetime;
-       
        /**
         * state of the CHILD_SA
         */
        child_sa_state_t state;
-       
-       /**
-        * transaction which is rekeying this CHILD_SA
-        */
-       transaction_t *rekeying_transaction;
-
-       /**
-        * Updown script
-        */
-       char *script;
-
-       /**
-        * Allow host access
-        */
-       bool hostaccess;
 
        /**
         * Specifies if NAT traversal is used
@@ -172,6 +142,11 @@ struct private_child_sa_t {
         * mode this SA uses, tunnel/transport
         */
        mode_t mode;
+       
+       /**
+        * policy used to create this child
+        */
+       policy_t *policy;
 };
 
 /**
@@ -179,22 +154,7 @@ struct private_child_sa_t {
  */
 static char *get_name(private_child_sa_t *this)
 {
-       return this->name;
-}
-
-/**
- * Implementation of child_sa_t.set_name.
- */
-static void set_name(private_child_sa_t *this, char* name)
-{
-       char buffer[64];
-       
-       if (snprintf(buffer, sizeof(buffer), "%s[%d]",
-                                name, this->reqid - REQID_START) > 0)
-       {
-               free(this->name);
-               this->name = strdup(buffer);
-       }
+       return this->policy->get_name(this->policy);;
 }
 
 /**
@@ -233,6 +193,14 @@ static child_sa_state_t get_state(private_child_sa_t *this)
        return this->state;
 }
 
+/**
+ * Implements child_sa_t.get_policy
+ */
+static policy_t* get_policy(private_child_sa_t *this)
+{
+       return this->policy;
+}
+
 /**
  * Run the up/down script
  */
@@ -240,8 +208,11 @@ static void updown(private_child_sa_t *this, bool up)
 {
        sa_policy_t *policy;
        iterator_t *iterator;
+       char *script;
        
-       if (this->script == NULL)
+       script = this->policy->get_updown(this->policy);
+       
+       if (script == NULL)
        {
                return;
        }
@@ -307,7 +278,7 @@ static void updown(private_child_sa_t *this, bool up)
                                 policy->my_ts->is_host(policy->my_ts,
                                                        this->me.addr) ? "-host" : "-client",
                                 this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6",
-                                this->name,
+                                this->policy->get_name(this->policy),
                                 ifname,
                                 this->reqid,
                                 this->me.addr,
@@ -322,8 +293,8 @@ static void updown(private_child_sa_t *this, bool up)
                                 other_client, other_client_mask,
                                 policy->other_ts->get_from_port(policy->other_ts),
                                 policy->other_ts->get_protocol(policy->other_ts),
-                                this->hostaccess? "PLUTO_HOST_ACCESS='1' " : "",
-                                this->script);
+                                this->policy->get_hostaccess(this->policy) ?
+                                       "PLUTO_HOST_ACCESS='1' " : "", script);
                free(ifname);
                free(my_client);
                free(other_client);
@@ -332,7 +303,7 @@ static void updown(private_child_sa_t *this, bool up)
 
                if (shell == NULL)
                {
-                       DBG1(DBG_CHD, "could not execute updown script '%s'", this->script);
+                       DBG1(DBG_CHD, "could not execute updown script '%s'", script);
                        return;
                }
                
@@ -447,7 +418,7 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
 static status_t install(private_child_sa_t *this, proposal_t *proposal,
                                                mode_t mode, prf_plus_t *prf_plus, bool mine)
 {
-       u_int32_t spi;
+       u_int32_t spi, soft, hard;;
        algorithm_t *enc_algo, *int_algo;
        algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0};
        algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
@@ -532,16 +503,15 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
                natt = NULL;
        }
        
+       soft = this->policy->get_soft_lifetime(this->policy);
+       hard = this->policy->get_hard_lifetime(this->policy);
        
        /* send SA down to the kernel */
        DBG2(DBG_CHD, "  SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
        status = charon->kernel_interface->add_sa(charon->kernel_interface,
-                                                                                         src, dst,
-                                                                                         spi, this->protocol,
-                                                                                         this->reqid,
-                                                                                         mine ? this->soft_lifetime : 0,
-                                                                                         this->hard_lifetime,
-                                                                                         enc_algo, int_algo,
+                                                                                         src, dst, spi, this->protocol,
+                                                                                         this->reqid, mine ? soft : 0,
+                                                                                         hard, enc_algo, int_algo,
                                                                                          prf_plus, natt, mode, mine);
        
        this->encryption = *enc_algo;
@@ -704,22 +674,6 @@ static linked_list_t *get_other_traffic_selectors(private_child_sa_t *this)
        return this->other_ts;
 }
 
-/**
- * Implementation of child_sa_t.set_rekeying_transaction.
- */
-static void set_rekeying_transaction(private_child_sa_t *this, transaction_t *transaction)
-{
-       this->rekeying_transaction = transaction;
-}
-
-/**
- * Implementation of child_sa_t.get_rekeying_transaction.
- */
-static transaction_t* get_rekeying_transaction(private_child_sa_t *this)
-{
-       return this->rekeying_transaction;
-}
-
 /**
  * Implementation of child_sa_t.get_use_time
  */
@@ -769,7 +723,7 @@ static int print(FILE *stream, const struct printf_info *info,
        private_child_sa_t *this = *((private_child_sa_t**)(args[0]));
        iterator_t *iterator;
        sa_policy_t *policy;
-       u_int32_t now, rekeying;
+       u_int32_t now, rekeying, soft;
        u_int32_t use, use_in, use_fwd;
        status_t status;
        size_t written = 0;
@@ -781,8 +735,9 @@ static int print(FILE *stream, const struct printf_info *info,
        
        now = (u_int32_t)time(NULL);
        
-       written += fprintf(stream, "%12s:  %N, reqid: %d, %N", this->name,
-                                          child_sa_state_names, this->state, this->reqid,
+       written += fprintf(stream, "%12s{%d}:  %N, %N", 
+                                          this->policy->get_name(this->policy), this->reqid,
+                                          child_sa_state_names, this->state,
                                           mode_names, this->mode);
        
        if (this->state == CHILD_INSTALLED)
@@ -793,7 +748,9 @@ static int print(FILE *stream, const struct printf_info *info,
                
                if (info->alt)
                {
-                       written += fprintf(stream, "\n%12s:  ", this->name);
+                       written += fprintf(stream, "\n%12s{%d}:  ",
+                                                          this->policy->get_name(this->policy),
+                                                          this->reqid);
                        
                        if (this->protocol == PROTO_ESP)
                        {
@@ -815,10 +772,11 @@ static int print(FILE *stream, const struct printf_info *info,
                        }
                        written += fprintf(stream, ", rekeying ");
                        
+                       soft = this->policy->get_soft_lifetime(this->policy);
                        /* calculate rekey times */
-                       if (this->soft_lifetime)
+                       if (soft)
                        {
-                               rekeying = this->soft_lifetime - (now - this->install_time);
+                               rekeying = soft - (now - this->install_time);
                                written += fprintf(stream, "in %ds", rekeying);
                        }
                        else
@@ -830,8 +788,9 @@ static int print(FILE *stream, const struct printf_info *info,
        iterator = this->policies->create_iterator(this->policies, TRUE);
        while (iterator->iterate(iterator, (void**)&policy))
        {
-               written += fprintf(stream, "\n%12s:   %R===%R, last use: ",
-                                                  this->name, policy->my_ts, policy->other_ts);
+               written += fprintf(stream, "\n%12s{%d}:   %R===%R, last use: ",
+                                                  this->policy->get_name(this->policy), this->reqid,
+                                                  policy->my_ts, policy->other_ts);
                
                /* query time of last policy use */
 
@@ -1074,25 +1033,22 @@ static void destroy(private_child_sa_t *this)
        this->other.addr->destroy(this->other.addr);
        this->me.id->destroy(this->me.id);
        this->other.id->destroy(this->other.id);
-       free(this->name);
-       free(this->script);
+       this->policy->destroy(this->policy);
        free(this);
 }
 
 /*
  * Described in header.
  */
-child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
+child_sa_t * child_sa_create(host_t *me, host_t* other,
                                                         identification_t *my_id, identification_t *other_id,
-                                                        u_int32_t soft_lifetime, u_int32_t hard_lifetime,
-                                                        char *script, bool hostaccess, bool use_natt)
+                                                        policy_t *policy, u_int32_t rekey, bool use_natt)
 {
-       static u_int32_t reqid = REQID_START;
+       static u_int32_t reqid = 0;
        private_child_sa_t *this = malloc_thing(private_child_sa_t);
 
        /* public functions */
        this->public.get_name = (char*(*)(child_sa_t*))get_name;
-       this->public.set_name = (void(*)(child_sa_t*,char*))set_name;
        this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
        this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
        this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
@@ -1104,14 +1060,12 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors;
        this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors;
        this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
-       this->public.set_rekeying_transaction = (void (*)(child_sa_t*,transaction_t*))set_rekeying_transaction;
-       this->public.get_rekeying_transaction = (transaction_t* (*)(child_sa_t*))get_rekeying_transaction;
        this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
        this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
+       this->public.get_policy = (policy_t*(*)(child_sa_t*))get_policy;
        this->public.destroy = (void(*)(child_sa_t*))destroy;
 
        /* private data */
-       this->name = strdup("(uninitialized)");
        this->me.addr = me->clone(me);
        this->other.addr = other->clone(other);
        this->me.id = my_id->clone(my_id);
@@ -1120,11 +1074,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->other.spi = 0;
        this->alloc_ah_spi = 0;
        this->alloc_esp_spi = 0;
-       this->script = script ? strdup(script) : NULL;
-       this->hostaccess = hostaccess;
        this->use_natt = use_natt;
-       this->soft_lifetime = soft_lifetime;
-       this->hard_lifetime = hard_lifetime;
        this->state = CHILD_CREATED;
        /* reuse old reqid if we are rekeying an existing CHILD_SA */
        this->reqid = rekey ? rekey : ++reqid;
@@ -1137,7 +1087,8 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->other_ts = linked_list_create();
        this->protocol = PROTO_NONE;
        this->mode = MODE_TUNNEL;
-       this->rekeying_transaction = NULL;
+       this->policy = policy;
+       policy->get_ref(policy);
        
        return &this->public;
 }
index 06362f35e43bde44150c21c8bd10a4853bb1eb30..bd0e032da70c80d89fad2466a91f823336c82d54 100644 (file)
@@ -6,8 +6,8 @@
  */
 
 /*
+ * Copyright (C) 2006-2007 Martin Willi
  * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * Copyright (C) 2006 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@ typedef struct child_sa_t child_sa_t;
 #include <crypto/prf_plus.h>
 #include <encoding/payloads/proposal_substructure.h>
 #include <config/proposal.h>
-#include <sa/transactions/transaction.h>
+#include <config/policies/policy.h>
 
 /**
  * Where we should start with reqid enumeration
@@ -109,18 +109,10 @@ struct child_sa_t {
        char* (*get_name) (child_sa_t *this);
        
        /**
-        * @brief Set the name of the policy this IKE_SA uses.
-        *
-        * @param this                  calling object
-        * @param name                  name, gets cloned
-        */
-       void (*set_name) (child_sa_t *this, char* name);
-       
-       /**
-        * @brief Get the unique reqid of the CHILD SA.
+        * @brief Get the reqid of the CHILD SA.
         * 
-        * Every CHILD_SA has a unique reqid, which is also 
-        * stored down in the kernel.
+        * Every CHILD_SA has a reqid. The kernel uses this ID to
+        * identify it.
         *
         * @param this          calling object
         * @return                      reqid of the CHILD SA
@@ -259,23 +251,12 @@ struct child_sa_t {
        void (*set_state) (child_sa_t *this, child_sa_state_t state);
        
        /**
-        * @brief Set the transaction which rekeys this CHILD_SA.
-        *
-        * Since either end may initiate CHILD_SA rekeying, we must detect
-        * such situations to handle them cleanly. A rekeying transaction
-        * registers itself to the CHILD_SA, and checks later if another
-        * transaction is in progress of a rekey.
+        * @brief Get the policy used to set up this child sa.
         *
         * @param this          calling object
-        */     
-       void (*set_rekeying_transaction) (child_sa_t *this, transaction_t *transaction);
-       
-       /**
-        * @brief Get the transaction which rekeys this CHILD_SA.
-        *
-        * @param this          calling object
-        */     
-       transaction_t* (*get_rekeying_transaction) (child_sa_t *this);
+        * @return                      policy
+        */
+       policy_t* (*get_policy) (child_sa_t *this);
        
        /**
         * @brief Destroys a child_sa.
@@ -288,23 +269,19 @@ struct child_sa_t {
 /**
  * @brief Constructor to create a new child_sa_t.
  *
- * @param rekey_reqid  reqid of old CHILD_SA when rekeying, 0 otherwise
  * @param me                   own address
  * @param other                        remote address
  * @param my_id                        id of own peer
  * @param other_id             id of remote peer
- * @param soft_lifetime        time before rekeying
- * @param hard_lifteime        time before delete
- * @param script               updown script to use when calling child_sa_t.script()
- * @param hostaccess   allow host access (needed by updown script)
+ * @param policy               policy this CHILD_SA instantiates
+ * @param reqid                        reqid of old CHILD_SA when rekeying, 0 otherwise
  * @param use_natt             TRUE if NAT traversal is used
  * @return                             child_sa_t object
  * 
  * @ingroup sa
  */
-child_sa_t * child_sa_create(u_int32_t rekey_reqid, host_t *me, host_t *other,
+child_sa_t * child_sa_create(host_t *me, host_t *other,
                                                         identification_t *my_id, identification_t* other_id,
-                                                        u_int32_t soft_lifetime, u_int32_t hard_lifetime,
-                                                        char *script, bool hostaccess, bool use_natt);
+                                                        policy_t *policy, u_int32_t reqid, bool use_natt);
 
 #endif /*CHILD_SA_H_*/
index e5a77edadbe6d52c48eff310a2ef9a5a0063dd3f..91ee4be0b04d565a86a23f9a28013117af5a7bf1 100644 (file)
 #include <sys/time.h>
 #include <string.h>
 #include <printf.h>
+#include <sys/stat.h>
 
 #include "ike_sa.h"
 
 #include <library.h>
 #include <daemon.h>
 #include <utils/linked_list.h>
+#include <utils/lexparser.h>
 #include <crypto/diffie_hellman.h>
 #include <crypto/prf_plus.h>
 #include <crypto/crypters/crypter.h>
 #include <encoding/payloads/transform_substructure.h>
 #include <encoding/payloads/transform_attribute.h>
 #include <encoding/payloads/ts_payload.h>
-#include <sa/transactions/transaction.h>
-#include <sa/transactions/ike_sa_init.h>
-#include <sa/transactions/delete_ike_sa.h>
-#include <sa/transactions/create_child_sa.h>
-#include <sa/transactions/delete_child_sa.h>
-#include <sa/transactions/dead_peer_detection.h>
-#include <sa/transactions/rekey_ike_sa.h>
-#include <queues/jobs/retransmit_request_job.h>
+#include <sa/task_manager.h>
+#include <sa/tasks/ike_init.h>
+#include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_auth.h>
+#include <sa/tasks/ike_config.h>
+#include <sa/tasks/ike_cert.h>
+#include <sa/tasks/ike_rekey.h>
+#include <sa/tasks/ike_delete.h>
+#include <sa/tasks/ike_dpd.h>
+#include <sa/tasks/child_create.h>
+#include <sa/tasks/child_delete.h>
+#include <sa/tasks/child_rekey.h>
+#include <queues/jobs/retransmit_job.h>
 #include <queues/jobs/delete_ike_sa_job.h>
 #include <queues/jobs/send_dpd_job.h>
 #include <queues/jobs/send_keepalive_job.h>
 #include <queues/jobs/route_job.h>
 #include <queues/jobs/initiate_job.h>
 
+
+#ifndef RESOLV_CONF
+#define RESOLV_CONF "/etc/resolv.conf"
+#endif
+
 ENUM(ike_sa_state_names, IKE_CREATED, IKE_DELETING,
        "CREATED",
        "CONNECTING",
@@ -82,15 +94,30 @@ struct private_ike_sa_t {
         */
        ike_sa_id_t *ike_sa_id;
        
+       /**
+        * unique numerical ID for this IKE_SA.
+        */
+       u_int32_t unique_id;
+       
        /**
         * Current state of the IKE_SA
         */
-       ike_sa_state_t state;
+       ike_sa_state_t state;   
        
        /**
-        * Name of the connection used by this IKE_SA
+        * connection used to establish this IKE_SA.
         */
-       char *name;
+       connection_t *connection;
+       
+       /**
+        * Peer and authentication information to establish IKE_SA.
+        */
+       policy_t *policy;
+       
+       /**
+        * Juggles tasks to process messages
+        */
+       task_manager_t *task_manager;
        
        /**
         * Address of local host
@@ -157,11 +184,6 @@ struct private_ike_sa_t {
         */
        prf_t *auth_verify;
        
-       /**
-        * NAT hasher.
-        */
-       hasher_t *nat_hasher;
-       
        /**
         * NAT status of local host.
         */
@@ -173,14 +195,19 @@ struct private_ike_sa_t {
        bool nat_there;
        
        /**
-        * message ID for next outgoung request
+        * Virtual IP on local host, if any
         */
-       u_int32_t message_id_out;
-
+       host_t *my_virtual_ip;
+       
+       /**
+        * Virtual IP on remote host, if any
+        */
+       host_t *other_virtual_ip;
+       
        /**
-        * will the IKE_SA be fully reauthenticated or rekeyed only?
+        * List of DNS servers installed by us
         */
-       bool reauth;
+       linked_list_t *dns_servers;
 
        /**
         * Timestamps for this IKE_SA
@@ -197,51 +224,12 @@ struct private_ike_sa_t {
                /** when IKE_SA gets deleted */
                u_int32_t delete;
        } time;
-       
-       /**
-        * interval to send DPD liveness check
-        */
-       time_t dpd_delay;
-       
-       /**
-        * number of retransmit sequences to go through before giving up (keyingtries)
-        */
-       u_int32_t retrans_sequences;
-       
-       /**
-        * List of queued transactions to process
-        */
-       linked_list_t *transaction_queue;
-       
-       /**
-        * Transaction currently initiated
-        * (only one supported yet, window size = 1)
-        */
-       transaction_t *transaction_out;
-       
-       /**
-        * last transaction initiated by peer processed.
-        * (only one supported yet, window size = 1)
-        * Stored for retransmission.
-        */
-       transaction_t *transaction_in;
-       
-       /**
-        * Next incoming transaction expected. Used to
-        * do multi transaction operations.
-        */
-       transaction_t *transaction_in_next;
-       
-       /**
-        * Transaction which rekeys this IKE_SA, used do detect simultaneus rekeying
-        */
-       transaction_t *rekeying_transaction;
 };
 
 /**
  * get the time of the latest traffic processed by the kernel
  */
-static time_t get_kernel_time(private_ike_sa_t* this, bool inbound)
+static time_t get_use_time(private_ike_sa_t* this, bool inbound)
 {
        iterator_t *iterator;
        child_sa_t *child_sa;
@@ -257,49 +245,68 @@ static time_t get_kernel_time(private_ike_sa_t* this, bool inbound)
        }
        iterator->destroy(iterator);
        
-       return latest;
+       if (inbound)
+       {
+               return max(this->time.inbound, latest);
+       }
+       else
+       {
+               return max(this->time.outbound, latest);
+       }
 }
 
 /**
- * get the time of the latest received traffice
+ * Implementation of ike_sa_t.get_unique_id
  */
-static time_t get_time_inbound(private_ike_sa_t *this)
+static u_int32_t get_unique_id(private_ike_sa_t *this)
 {
-       return max(this->time.inbound, get_kernel_time(this, TRUE));
+       return this->unique_id;
 }
 
 /**
- * get the time of the latest sent traffic
+ * Implementation of ike_sa_t.get_name.
  */
-static time_t get_time_outbound(private_ike_sa_t *this)
+static char *get_name(private_ike_sa_t *this)
 {
-       return max(this->time.outbound, get_kernel_time(this, FALSE));
+       if (this->connection)
+       {
+               return this->connection->get_name(this->connection);
+       }
+       return "(unnamed)";
 }
 
 /**
- * Implementation of ike_sa_t.get_name.
+ * Implementation of ike_sa_t.get_connection
  */
-static char *get_name(private_ike_sa_t *this)
+static connection_t* get_connection(private_ike_sa_t *this)
 {
-       return this->name;
+       return this->connection;
 }
 
 /**
- * Implementation of ike_sa_t.set_name.
+ * Implementation of ike_sa_t.set_connection
  */
-static void set_name(private_ike_sa_t *this, char* name)
+static void set_connection(private_ike_sa_t *this, connection_t *connection)
 {
-       free(this->name);
-       this->name = strdup(name);
+       this->connection = connection;
+       connection->get_ref(connection);
 }
 
 /**
- * Implementation of ike_sa_t.apply_connection.
+ * Implementation of ike_sa_t.get_policy
  */
-static void apply_connection(private_ike_sa_t *this, connection_t *connection)
+static policy_t *get_policy(private_ike_sa_t *this)
 {
-       this->dpd_delay = connection->get_dpd_delay(connection);
-       this->retrans_sequences = connection->get_retrans_seq(connection);
+       return this->policy;
+}
+
+/**
+ * Implementation of ike_sa_t.set_policy
+ */
+static void set_policy(private_ike_sa_t *this, policy_t *policy)
+{
+       policy->get_ref(policy);
+       this->policy = policy;
 }
 
 /**
@@ -341,35 +348,6 @@ static void set_other_host(private_ike_sa_t *this, host_t *other)
  */
 static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
 {
-       /*
-        * Quoting RFC 4306:
-        *
-        * 2.11.  Address and Port Agility
-        * 
-        *    IKE runs over UDP ports 500 and 4500, and implicitly sets up ESP and
-        *    AH associations for the same IP addresses it runs over.  The IP
-        *    addresses and ports in the outer header are, however, not themselves
-        *    cryptographically protected, and IKE is designed to work even through
-        *    Network Address Translation (NAT) boxes.  An implementation MUST
-        *    accept incoming requests even if the source port is not 500 or 4500,
-        *    and MUST respond to the address and port from which the request was
-        *    received.  It MUST specify the address and port at which the request
-        *    was received as the source address and port in the response.  IKE
-        *    functions identically over IPv4 or IPv6.
-        *
-        *    [...]
-        *
-        *    There are cases where a NAT box decides to remove mappings that
-        *    are still alive (for example, the keepalive interval is too long,
-        *    or the NAT box is rebooted).  To recover in these cases, hosts
-        *    that are not behind a NAT SHOULD send all packets (including
-        *    retransmission packets) to the IP address and port from the last
-        *    valid authenticated packet from the other end (i.e., dynamically
-        *    update the address).  A host behind a NAT SHOULD NOT do this
-        *    because it opens a DoS attack possibility.  Any authenticated IKE
-        *    packet or any authenticated UDP-encapsulated ESP packet can be
-        *    used to detect that the IP address or the port has changed.
-        */
        iterator_t *iterator = NULL;
        child_sa_t *child_sa = NULL;
        host_diff_t my_diff, other_diff;
@@ -425,399 +403,149 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
        {
                child_sa->update_hosts(child_sa, this->my_host, this->other_host, 
                                                           my_diff, other_diff);
-               /* TODO: what to do if update fails? Delete CHILD_SA? */
        }
        iterator->destroy(iterator);
 }
 
 /**
- * called when the peer is not responding anymore
+ * Implementation of ike_sa_t.retransmit.
  */
-static void dpd_detected(private_ike_sa_t *this)
+static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
 {
-       connection_t *connection = NULL;
-       policy_t *policy;
-       linked_list_t *my_ts, *other_ts;
-       child_sa_t* child_sa;
-       dpd_action_t action;
-       job_t *job;
-       
-       DBG2(DBG_IKE, "dead peer detected, handling CHILD_SAs dpd action");
-       
-       /* check for childrens with dpdaction = hold */
-       while(this->child_sas->remove_first(this->child_sas,
-                                                                               (void**)&child_sa) == SUCCESS)
+       this->time.outbound = time(NULL);
+       if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
        {
-               /* get the policy which belongs to this CHILD */
-               my_ts = child_sa->get_my_traffic_selectors(child_sa);
-               other_ts = child_sa->get_other_traffic_selectors(child_sa);
-               policy = charon->policies->get_policy(charon->policies,
-                                                                                         this->my_id, this->other_id,
-                                                                                         my_ts, other_ts,
-                                                                                         this->my_host, this->other_host);
-               if (policy == NULL)
-               {
-                       DBG1(DBG_IKE, "no policy for CHILD to handle DPD");
-                       continue;
-               }
+               connection_t *connection = NULL;
+               policy_t *policy;
+               linked_list_t *my_ts, *other_ts;
+               child_sa_t* child_sa;
+               dpd_action_t action;
+               job_t *job;
                
-               action = policy->get_dpd_action(policy);
-               /* get a connection for further actions */
-               if (connection == NULL &&
-                       (action == DPD_ROUTE || action == DPD_RESTART))
+               DBG2(DBG_IKE, "dead peer detected, handling CHILD_SAs dpd action");
+               
+               /* check for childrens with dpdaction = hold */
+               while(this->child_sas->remove_first(this->child_sas,
+                                                                                       (void**)&child_sa) == SUCCESS)
                {
-                       connection = charon->connections->get_connection_by_hosts(
-                                                                                       charon->connections,
-                                                                                       this->my_host, this->other_host);
-                       if (connection == NULL)
+                       /* get the policy which belongs to this CHILD */
+                       my_ts = child_sa->get_my_traffic_selectors(child_sa);
+                       other_ts = child_sa->get_other_traffic_selectors(child_sa);
+                       policy = charon->policies->get_policy(charon->policies,
+                                                                                                 this->my_id, this->other_id,
+                                                                                                 my_ts, other_ts,
+                                                                                                 this->my_host, this->other_host);
+                       if (policy == NULL)
                        {
-                               SIG(IKE_UP_FAILED, "no connection found to handle DPD");
-                               break;
+                               DBG1(DBG_IKE, "no policy for CHILD to handle DPD");
+                               continue;
+                       }
+                       
+                       action = policy->get_dpd_action(policy);
+                       /* get a connection for further actions */
+                       if (connection == NULL &&
+                               (action == DPD_ROUTE || action == DPD_RESTART))
+                       {
+                               connection = charon->connections->get_connection_by_hosts(
+                                                                                               charon->connections,
+                                                                                               this->my_host, this->other_host);
+                               if (connection == NULL)
+                               {
+                                       SIG(IKE_UP_FAILED, "no connection found to handle DPD");
+                                       break;
+                               }
                        }
+                       
+                       DBG1(DBG_IKE, "dpd action for %s is %N",
+                                policy->get_name(policy), dpd_action_names, action);
+                       
+                       switch (action)
+                       {
+                               case DPD_ROUTE:
+                                       connection->get_ref(connection);
+                                       job = (job_t*)route_job_create(connection, policy, TRUE);
+                                       charon->job_queue->add(charon->job_queue, job);
+                                       break;
+                               case DPD_RESTART:
+                                       connection->get_ref(connection);
+                                       job = (job_t*)initiate_job_create(connection, policy);
+                                       charon->job_queue->add(charon->job_queue, job);
+                                       break;
+                               default:
+                                       policy->destroy(policy);
+                                       break;
+                       }
+                       child_sa->destroy(child_sa);
                }
                
-               DBG1(DBG_IKE, "dpd action for %s is %N",
-                        policy->get_name(policy), dpd_action_names, action);
-               
-               switch (action)
+               /* send a proper signal to brief interested bus listeners */
+               switch (this->state)
                {
-                       case DPD_ROUTE:
-                               connection->get_ref(connection);
-                               job = (job_t*)route_job_create(connection, policy, TRUE);
-                               charon->job_queue->add(charon->job_queue, job);
+                       case IKE_CONNECTING:
+                               SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
+                               break;
+                       case IKE_REKEYING:
+                               SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
                                break;
-                       case DPD_RESTART:
-                               connection->get_ref(connection);
-                               job = (job_t*)initiate_job_create(connection, NULL, policy);
-                               charon->job_queue->add(charon->job_queue, job);
+                       case IKE_DELETING:
+                               SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
                                break;
                        default:
-                               policy->destroy(policy);
                                break;
                }
-               child_sa->destroy(child_sa);
-       }
-       
-       /* send a proper signal to brief interested bus listeners */
-       switch (this->state)
-       {
-               case IKE_CONNECTING:
-                       SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
-                       break;
-               case IKE_REKEYING:
-                       SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
-                       break;
-               case IKE_DELETING:
-                       SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
-                       break;
-               default:
-                       break;
-       }
-       
-       DESTROY_IF(connection);
-}
-
-/**
- * send a request and schedule retransmission
- */
-static status_t transmit_request(private_ike_sa_t *this)
-{
-       message_t *request;
-       packet_t *packet;
-       status_t status;
-       retransmit_request_job_t *job;
-       u_int32_t transmitted;
-       u_int32_t timeout;
-       transaction_t *transaction = this->transaction_out;
-       u_int32_t message_id;
-       
-       transmitted = transaction->requested(transaction);
-       timeout = charon->configuration->get_retransmit_timeout(charon->configuration,
-                                                                                                                       transmitted,
-                                                                                                                       this->retrans_sequences);
-       if (timeout == 0)
-       {
-               DBG1(DBG_IKE, "giving up after %d retransmits, deleting IKE_SA",
-                        transmitted - 1);
-               dpd_detected(this);
+               
+               DESTROY_IF(connection);
                return DESTROY_ME;
        }
-       
-       status = transaction->get_request(transaction, &request);
-       if (status != SUCCESS)
-       {
-               /* generating request failed */
-               return status;
-       }
-       message_id = transaction->get_message_id(transaction);
-       /* if we retransmit, the request is already generated */
-       if (transmitted == 0)
-       {
-               status = request->generate(request, this->crypter_out, this->signer_out, &packet);
-               if (status != SUCCESS)
-               {
-                       DBG1(DBG_IKE, "request generation failed. transaction discarded");
-                       return FAILED;
-               }
-       }
-       else
-       {
-               DBG1(DBG_IKE, "sending retransmit %d for %N request with messageID %d",
-                       transmitted, exchange_type_names, request->get_exchange_type(request),
-                       message_id);
-               packet = request->get_packet(request);
-       }
-       /* finally send */
-       charon->send_queue->add(charon->send_queue, packet);
-       this->time.outbound = time(NULL);
-       
-       /* schedule retransmission job */
-       job = retransmit_request_job_create(message_id, this->ike_sa_id);
-       charon->event_queue->add_relative(charon->event_queue, (job_t*)job, timeout);
        return SUCCESS;
 }
 
 /**
- * Implementation of ike_sa.retransmit_request.
+ * Implementation of ike_sa_t.generate
  */
-static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id)
+static status_t generate_message(private_ike_sa_t *this, message_t *message,
+                                                                packet_t **packet)
 {
-       if (this->transaction_out == NULL ||
-               this->transaction_out->get_message_id(this->transaction_out) != message_id)
-       {
-               /* no retransmit necessary, transaction did already complete */
-               return SUCCESS;
-       }
-       return transmit_request(this);
-}
-
-/**
- * Check for transactions in the queue and initiate the first transaction found.
- */
-static status_t process_transaction_queue(private_ike_sa_t *this)
-{
-       if (this->transaction_out)
-       {
-               /* already a transaction in progress */
-               return SUCCESS;
-       }
-       
-       while (TRUE)
-       {
-               if (this->transaction_queue->remove_first(this->transaction_queue,
-                       (void**)&this->transaction_out) != SUCCESS)
-               {
-                       /* transaction queue empty */
-                       return SUCCESS;
-               }
-               switch (transmit_request(this))
-               {
-                       case SUCCESS:
-                               return SUCCESS;
-                       case DESTROY_ME:
-                               /* critical, IKE_SA unusable, destroy immediately */
-                               return DESTROY_ME;
-                       default:
-                               /* discard transaction, process next one */
-                               this->transaction_out->destroy(this->transaction_out);
-                               this->transaction_out = NULL;
-                               /* handle next transaction */
-                               continue;
-               }
-       }
-}
-
-/**
- * Queue a new transaction and execute the next outstanding transaction
- */
-static status_t queue_transaction(private_ike_sa_t *this, transaction_t *transaction, bool prefer)
-{
-       /* inject next transaction */
-       if (transaction)
-       {
-               if (prefer)
-               {
-                       this->transaction_queue->insert_first(this->transaction_queue, transaction);
-               }
-               else
-               {
-                       this->transaction_queue->insert_last(this->transaction_queue, transaction);
-               }
-       }
-       /* process a transaction */
-       return process_transaction_queue(this);
-}
-
-/**
- * process an incoming request.
- */
-static status_t process_request(private_ike_sa_t *this, message_t *request)
-{
-       transaction_t *last, *current = NULL;
-       message_t *response;
-       packet_t *packet;
-       u_int32_t request_mid;
-       status_t status;
-       
-       request_mid = request->get_message_id(request);
-       last = this->transaction_in;
-       
-       /* check if message ID is correct */
-       if (last)
-       {
-               u_int32_t last_mid = last->get_message_id(last);
-               
-               if (last_mid == request_mid)
-               {
-                       /* retransmit detected */
-                       DBG1(DBG_IKE, "received retransmitted request for message "
-                                "ID %d, retransmitting response", request_mid);
-                       last->get_response(last, request, &response, &this->transaction_in_next);
-                       packet = response->get_packet(response);
-                       charon->send_queue->add(charon->send_queue, packet);
-                       this->time.outbound = time(NULL);
-                       return SUCCESS;
-               }
-               
-               if (last_mid > request_mid)
-               {
-                       /* something seriously wrong here, message id may not decrease */
-                       DBG1(DBG_IKE, "received request with message ID %d, "
-                                "excepted %d, ingored", request_mid, last_mid + 1);
-                       return FAILED;
-               }
-               /* we allow jumps in message IDs, as long as they are incremental */
-               if (last_mid + 1 < request_mid)
-               {
-                       DBG1(DBG_IKE, "received request with message ID %d, excepted %d",
-                                request_mid, last_mid + 1);
-               }
-       }
-       else
-       {
-               if (request_mid != 0)
-               {
-                       /* warn, but allow it */
-                       DBG1(DBG_IKE, "first received request has message ID %d, "
-                                "excepted 0", request_mid);
-               }
-       }
-       
-       /* check if we already have a pre-created transaction for this request */
-       if (this->transaction_in_next)
-       {
-               current = this->transaction_in_next;
-               this->transaction_in_next = NULL;
-       }
-       else
-       {
-               current = transaction_create(&this->public, request);
-               if (current == NULL)
-               {
-                       DBG1(DBG_IKE, "no idea how to handle received message (exchange"
-                                " type %d), ignored", request->get_exchange_type(request));
-                       return FAILED;
-               }
-       }
-       
-       /* send message. get_request() always gives a valid response */
-       status = current->get_response(current, request, &response, &this->transaction_in_next);
-       if (response->generate(response, this->crypter_out, this->signer_out, &packet) != SUCCESS)
-       {
-               DBG1(DBG_IKE, "response generation failed, discarding transaction");
-               current->destroy(current);
-               return FAILED;
-       }
-       
-       charon->send_queue->add(charon->send_queue, packet);
        this->time.outbound = time(NULL);
-       /* act depending on transaction result */
-       switch (status)
-       {
-               case DESTROY_ME:
-                       /* transactions says we should destroy the IKE_SA, so do it */
-                       current->destroy(current);
-                       return DESTROY_ME;
-               default:
-                       /* store for retransmission, destroy old transaction */
-                       this->transaction_in = current;
-                       if (last)
-                       {
-                               last->destroy(last);
-                       }
-                       return SUCCESS;
-       }
-}
-
-/**
- * process an incoming response
- */
-static status_t process_response(private_ike_sa_t *this, message_t *response)
-{
-       transaction_t *current, *new = NULL;
-       
-       current = this->transaction_out;
-       /* check if message ID is that of our currently active transaction */
-       if (current == NULL ||
-               current->get_message_id(current) != response->get_message_id(response))
-       {
-               DBG1(DBG_IKE, "received response with message ID %d "
-                        "not requested, ignored", response->get_message_id(response));
-               return FAILED;
-       }
-       
-       switch (current->conclude(current, response, &new))
-       {
-               case DESTROY_ME:
-                       /* state requested to destroy IKE_SA */
-                       return DESTROY_ME;
-               default:
-                       /* discard transaction, process next one */
-                       break;
-       }
-       /* transaction comleted, remove */
-       current->destroy(current);
-       this->transaction_out = NULL;
-       
-       /* queue new transaction */
-       return queue_transaction(this, new, TRUE);
+       message->set_ike_sa_id(message, this->ike_sa_id);
+       message->set_destination(message, this->other_host->clone(this->other_host));
+       message->set_source(message, this->my_host->clone(this->my_host));
+       return message->generate(message, this->crypter_out, this->signer_out, packet);
 }
 
 /**
  * send a notify back to the sender
  */
-static void send_notify_response(private_ike_sa_t *this,
-                                                                message_t *request,
+static void send_notify_response(private_ike_sa_t *this, message_t *request,
                                                                 notify_type_t type)
 {
-       notify_payload_t *notify;
        message_t *response;
-       host_t *src, *dst;
        packet_t *packet;
        
        response = message_create();
-       dst = request->get_source(request);
-       src = request->get_destination(request);
-       response->set_source(response, src->clone(src));
-       response->set_destination(response, dst->clone(dst));
        response->set_exchange_type(response, request->get_exchange_type(request));
        response->set_request(response, FALSE);
        response->set_message_id(response, request->get_message_id(request));
-       response->set_ike_sa_id(response, this->ike_sa_id);
-       notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
-       response->add_payload(response, (payload_t *)notify);
-       if (response->generate(response, this->crypter_out, this->signer_out, &packet) != SUCCESS)
+       response->add_notify(response, FALSE, type, chunk_empty);
+       if (this->my_host->is_anyaddr(this->my_host))
        {
-               response->destroy(response);
-               return;
+               this->my_host->destroy(this->my_host);
+               this->my_host = request->get_destination(request);
+               this->my_host = this->my_host->clone(this->my_host);
+       }
+       if (this->other_host->is_anyaddr(this->other_host))
+       {
+               this->other_host->destroy(this->other_host);
+               this->other_host = request->get_source(request);
+               this->other_host = this->other_host->clone(this->other_host);
+       }
+       if (generate_message(this, response, &packet) == SUCCESS)
+       {
+               charon->send_queue->add(charon->send_queue, packet);
        }
-       charon->send_queue->add(charon->send_queue, packet);
-       this->time.outbound = time(NULL);
        response->destroy(response);
-       return;
 }
 
-
 /**
  * Implementation of ike_sa_t.process_message.
  */
@@ -875,27 +603,66 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
                         exchange_type_names, message->get_exchange_type(message),
                         message->get_request(message) ? "request" : "response",
                         message->get_message_id(message));
+               return status;
        }
        else
        {
+               host_t *me, *other;
+               
+               me = message->get_destination(message);
+               other = message->get_source(message);
+       
+               /* if this IKE_SA is virgin, we check for a connection */
+               if (this->connection == NULL)
+               {
+                       this->connection = charon->connections->get_connection_by_hosts(
+                                                                                               charon->connections, me, other);
+                       if (this->connection == NULL)
+                       {
+                               /* no connection found for these hosts, destroy */
+                               send_notify_response(this, message, NO_PROPOSAL_CHOSEN);
+                               return DESTROY_ME;
+                       }
+               }
+       
                /* check if message is trustworthy, and update connection information */
                if (this->state == IKE_CREATED ||
                        message->get_exchange_type(message) != IKE_SA_INIT)
                {
-                       update_hosts(this, message->get_destination(message),
-                                                          message->get_source(message));
+                       update_hosts(this, me, other);
                        this->time.inbound = time(NULL);
                }
-               if (is_request)
-               {
-                       status = process_request(this, message);
-               }
-               else
-               {
-                       status = process_response(this, message);
-               }
+               return this->task_manager->process_message(this->task_manager, message);
+       }
+}
+
+/**
+ * apply the connection/policy information to this IKE_SA
+ */
+static void apply_config(private_ike_sa_t *this,
+                                                connection_t *connection, policy_t *policy)
+{
+       host_t *me, *other;
+       identification_t *my_id, *other_id;
+       
+       if (this->connection == NULL && this->policy == NULL)
+       {
+               this->connection = connection;
+               connection->get_ref(connection);
+               this->policy = policy;
+               policy->get_ref(policy);
+               
+               me = connection->get_my_host(connection);
+               other = connection->get_other_host(connection);
+               my_id = policy->get_my_id(policy);
+               other_id = policy->get_other_id(policy);
+               set_my_host(this, me->clone(me));
+               set_other_host(this, other->clone(other));
+               DESTROY_IF(this->my_id);
+               DESTROY_IF(this->other_id);
+               this->my_id = my_id->clone(my_id);
+               this->other_id = other_id->clone(other_id);
        }
-       return status;
 }
 
 /**
@@ -904,77 +671,29 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
 static status_t initiate(private_ike_sa_t *this,
                                                 connection_t *connection, policy_t *policy)
 {
-       switch (this->state)
+       task_t *task;
+       
+       if (this->state == IKE_CREATED)
        {
-               case IKE_CREATED:
-               {
-                       /* in state CREATED, we must do the ike_sa_init
-                        * and ike_auth transactions. Along with these,
-                        * a CHILD_SA with the supplied policy is set up.
-                        */
-                       ike_sa_init_t *ike_sa_init;
-                       
-                       DBG2(DBG_IKE, "initiating new IKE_SA for CHILD_SA");
-                       if (this->my_host->is_anyaddr(this->my_host))
-                       {
-                               this->my_host->destroy(this->my_host);
-                               this->my_host = connection->get_my_host(connection);
-                               this->my_host = this->my_host->clone(this->my_host);
-                       }
-                       if (this->other_host->is_anyaddr(this->other_host))
-                       {
-                               this->other_host->destroy(this->other_host);
-                               this->other_host = connection->get_other_host(connection);
-                               this->other_host = this->other_host->clone(this->other_host);
-                       }
-                       if (this->other_host->is_anyaddr(this->other_host))
-                       {
-                               SIG(IKE_UP_START, "establishing new IKE_SA for CHILD_SA");
-                               SIG(IKE_UP_FAILED, "can not initiate a connection to %%any, aborting");
-                               policy->destroy(policy);
-                               connection->destroy(connection);
-                               return DESTROY_ME;
-                       }
-                       
-                       this->retrans_sequences = connection->get_retrans_seq(connection);
-                       this->dpd_delay = connection->get_dpd_delay(connection);
-                       
-                       this->message_id_out = 1;
-                       ike_sa_init = ike_sa_init_create(&this->public);
-                       ike_sa_init->set_config(ike_sa_init, connection, policy);
-                       return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
-               }
-               case IKE_DELETING:
-               case IKE_REKEYING:
-               {
-                       /* if we are in DELETING/REKEYING, we deny set up of a policy.
-                        * TODO: would it make sense to queue the transaction and adopt
-                        * all transactions to the new IKE_SA? */
-                       SIG(IKE_UP_START, "creating CHILD_SA in existing IKE_SA");
-                       SIG(IKE_UP_FAILED, "creating CHILD_SA discarded, as IKE_SA is in state %N",
-                               ike_sa_state_names, this->state);
-                       policy->destroy(policy);
-                       connection->destroy(connection);
-                       return FAILED;
-               }
-               case IKE_CONNECTING:
-               case IKE_ESTABLISHED:
-               {
-                       /* if we are ESTABLISHED or CONNECTING, we queue the
-                        * transaction to create the CHILD_SA. It gets processed
-                        * when the IKE_SA is ready to do so. We don't need the
-                        * connection, as the IKE_SA is already established/establishing.
-                        */
-                       create_child_sa_t *create_child;
-                       
-                       DBG1(DBG_IKE, "creating CHILD_SA in existing IKE_SA");
-                       connection->destroy(connection);
-                       create_child = create_child_sa_create(&this->public);
-                       create_child->set_policy(create_child, policy);
-                       return queue_transaction(this, (transaction_t*)create_child, FALSE);
-               }
-       }
-       return FAILED;
+               /* if we aren't established/establishing, do so */
+               apply_config(this, connection, policy);
+               
+               task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_natd_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_cert_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_config_create(&this->public, policy);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_auth_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+       }
+       
+       task = (task_t*)child_create_create(&this->public, policy);
+       this->task_manager->queue_task(this->task_manager, task);
+       
+       return this->task_manager->initiate(this->task_manager);
 }
 
 /**
@@ -982,11 +701,11 @@ static status_t initiate(private_ike_sa_t *this,
  */
 static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
 {
-       connection_t *connection;
        policy_t *policy;
        iterator_t *iterator;
        child_sa_t *current, *child_sa = NULL;
-       linked_list_t *my_ts, *other_ts;
+       task_t *task;
+       child_create_t *child_create;
        
        if (this->state == IKE_DELETING)
        {
@@ -1001,79 +720,41 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
        while (iterator->iterate(iterator, (void**)&current))
        {
                if (current->get_reqid(current) == reqid)
-               {
-                       child_sa = current;
-                       break;
-               }
-       }
-       iterator->destroy(iterator);
-       if (!child_sa)
-       {
-               SIG(CHILD_UP_START, "acquiring CHILD_SA on kernel request");
-               SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
-                       "CHILD_SA not found", reqid);
-               return FAILED;
-       }
-       my_ts = child_sa->get_my_traffic_selectors(child_sa);
-       other_ts = child_sa->get_other_traffic_selectors(child_sa);
-       
-       policy = charon->policies->get_policy(charon->policies, 
-                                                                                 this->my_id, this->other_id, 
-                                                                                 my_ts, other_ts, 
-                                                                                 this->my_host, this->other_host);
-       if (policy == NULL)
-       {
-               SIG(CHILD_UP_START, "acquiring CHILD_SA with reqid %d", reqid);
-               SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
-                       "no policy found", reqid);
-               return FAILED;
-       }
-       
-       switch (this->state)
-       {
-               case IKE_CREATED:
-               {
-                       ike_sa_init_t *ike_sa_init;
-                       
-                       connection = charon->connections->get_connection_by_hosts(
-                                       charon->connections, this->my_host, this->other_host);
-                       
-                       if (connection == NULL)
-                       {
-                               SIG(CHILD_UP_START, "acquiring CHILD_SA with reqid %d", reqid);
-                               SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
-                                       "no connection found to establsih IKE_SA", reqid);
-                               policy->destroy(policy);
-                               return FAILED;
-                       }
-                       
-                       DBG1(DBG_IKE, "establishing IKE_SA to acquire CHILD_SA "
-                                "with reqid %d", reqid);
-                       
-                       this->message_id_out = 1;
-                       ike_sa_init = ike_sa_init_create(&this->public);
-                       ike_sa_init->set_config(ike_sa_init, connection, policy);
-                       /* reuse existing reqid */
-                       ike_sa_init->set_reqid(ike_sa_init, reqid);
-                       return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
-               }
-               case IKE_CONNECTING:
-               case IKE_ESTABLISHED:
-               {
-                       create_child_sa_t *create_child;
-                       
-                       DBG1(DBG_CHD, "acquiring CHILD_SA with reqid %d", reqid);
-                       
-                       create_child = create_child_sa_create(&this->public);
-                       create_child->set_policy(create_child, policy);
-                       /* reuse existing reqid */
-                       create_child->set_reqid(create_child, reqid);
-                       return queue_transaction(this, (transaction_t*)create_child, FALSE);
-               }
-               default:
+               {
+                       child_sa = current;
                        break;
+               }
        }
-       return FAILED;
+       iterator->destroy(iterator);
+       if (!child_sa)
+       {
+               SIG(CHILD_UP_START, "acquiring CHILD_SA on kernel request");
+               SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
+                       "CHILD_SA not found", reqid);
+               return FAILED;
+       }
+       
+       policy = child_sa->get_policy(child_sa);
+       
+       if (this->state == IKE_CREATED)
+       {
+               task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_natd_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_cert_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_config_create(&this->public, policy);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_auth_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+       }
+       
+       child_create = child_create_create(&this->public, policy);
+       child_create->use_reqid(child_create, reqid);
+       this->task_manager->queue_task(this->task_manager, (task_t*)child_create);
+       
+       return this->task_manager->initiate(this->task_manager);
 }
 
 /**
@@ -1148,55 +829,25 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t
        
        switch (this->state)
        {
+               case IKE_DELETING:
+               case IKE_REKEYING:
+                       SIG(CHILD_ROUTE_FAILED,
+                               "unable to route CHILD_SA, as its IKE_SA gets deleted");
+                       return FAILED;
                case IKE_CREATED:
-               case IKE_CONNECTING:
-                       /* we update IKE_SA information as good as possible,
-                        * this allows us to set up the SA later when an acquire comes in. */
-                       if (this->my_id->get_type(this->my_id) == ID_ANY)
-                       {
-                               this->my_id->destroy(this->my_id);
-                               this->my_id = policy->get_my_id(policy);
-                               this->my_id = this->my_id->clone(this->my_id);
-                       }
-                       if (this->other_id->get_type(this->other_id) == ID_ANY)
-                       {
-                               this->other_id->destroy(this->other_id);
-                               this->other_id = policy->get_other_id(policy);
-                               this->other_id = this->other_id->clone(this->other_id);
-                       }
-                       if (this->my_host->is_anyaddr(this->my_host))
-                       {
-                               this->my_host->destroy(this->my_host);
-                               this->my_host = connection->get_my_host(connection);
-                               this->my_host = this->my_host->clone(this->my_host);
-                       }
-                       if (this->other_host->is_anyaddr(this->other_host))
-                       {
-                               this->other_host->destroy(this->other_host);
-                               this->other_host = connection->get_other_host(connection);
-                               this->other_host = this->other_host->clone(this->other_host);
-                       }
-                       set_name(this, connection->get_name(connection));
-                       this->retrans_sequences = connection->get_retrans_seq(connection);
-                       this->dpd_delay = connection->get_dpd_delay(connection);
+                       /* apply connection information, we need it to acquire */
+                       apply_config(this, connection, policy);
                        break;
+               case IKE_CONNECTING:
                case IKE_ESTABLISHED:
-               case IKE_REKEYING:
-                       /* nothing to do. We allow it for rekeying, as it will be
-                        * adopted by the new IKE_SA */
+               default:
                        break;
-               case IKE_DELETING:
-                       /* TODO: hanlde this case, create a new IKE_SA and route CHILD_SA */
-                       SIG(CHILD_ROUTE_FAILED, "unable to route CHILD_SA, as its IKE_SA gets deleted");
-                       return FAILED;
        }
 
-       child_sa = child_sa_create(0, this->my_host, this->other_host,
-                                                          this->my_id, this->other_id,
-                                                          0, 0,
-                                                          NULL, policy->get_hostaccess(policy),
-                                                          FALSE);
-       child_sa->set_name(child_sa, policy->get_name(policy));
+       /* install kernel policies */
+       child_sa = child_sa_create(this->my_host, this->other_host,
+                                                          this->my_id, this->other_id, policy, FALSE, 0);
+       
        my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
        other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
        status = child_sa->add_policies(child_sa, my_ts, other_ts,
@@ -1269,40 +920,45 @@ static status_t unroute(private_ike_sa_t *this, policy_t *policy)
 static status_t send_dpd(private_ike_sa_t *this)
 {
        send_dpd_job_t *job;
-       time_t diff;
+       time_t diff, delay;
        
-       if (this->dpd_delay == 0)
+       delay = this->connection->get_dpd_delay(this->connection);
+       
+       if (delay == 0)
        {
                /* DPD disabled */
                return SUCCESS;
        }
        
-       if (this->transaction_out)
+       if (this->task_manager->busy(this->task_manager))
        {
-               /* there is a transaction in progress. Come back later */
+               /* an exchange is in the air, no need to start a DPD check */
                diff = 0;
        }
        else
        {
                /* check if there was any inbound traffic */
                time_t last_in, now;
-               last_in = get_time_inbound(this);
+               last_in = get_use_time(this, TRUE);
                now = time(NULL);
                diff = now - last_in;
-               if (diff >= this->dpd_delay)
+               if (diff >= delay)
                {
                        /* to long ago, initiate dead peer detection */
-                       dead_peer_detection_t *dpd;
-                       DBG1(DBG_IKE, "sending DPD request");
-                       dpd = dead_peer_detection_create(&this->public);
-                       queue_transaction(this, (transaction_t*)dpd, FALSE);
+                       task_t *task;
+                       
+                       task = (task_t*)ike_dpd_create(TRUE);
                        diff = 0;
+                       DBG1(DBG_IKE, "sending DPD request");
+                       
+                       this->task_manager->queue_task(this->task_manager, task);
+                       this->task_manager->initiate(this->task_manager);
                }
        }
        /* recheck in "interval" seconds */
        job = send_dpd_job_create(this->ike_sa_id);
        charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
-                                                                         (this->dpd_delay - diff) * 1000);
+                                                                         (delay - diff) * 1000);
        return SUCCESS;
 }
 
@@ -1314,7 +970,7 @@ static void send_keepalive(private_ike_sa_t *this)
        send_keepalive_job_t *job;
        time_t last_out, now, diff, interval;
        
-       last_out = get_time_outbound(this);
+       last_out = get_use_time(this, FALSE);
        now = time(NULL);
        
        diff = now - last_out;
@@ -1360,9 +1016,37 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
        
        if (state == IKE_ESTABLISHED)
        {
-               this->time.established = time(NULL);
+               job_t *job;
+               u_int32_t now = time(NULL);
+               u_int32_t soft, hard;
+               bool reauth;
+       
+               this->time.established = now;
                /* start DPD checks */
                send_dpd(this);
+               
+               /* schedule rekeying/reauthentication */
+               soft = this->connection->get_soft_lifetime(this->connection);
+               hard = this->connection->get_hard_lifetime(this->connection);
+               reauth = this->connection->get_reauth(this->connection);
+               DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds",
+                        reauth ? "reauthentication": "rekeying", soft, hard);
+                        
+               if (soft)
+               {
+                       this->time.rekey = now + soft;
+                       job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
+                       charon->event_queue->add_relative(charon->event_queue, job,
+                                                                                         soft * 1000);
+               }
+               
+               if (hard)
+               {
+                       this->time.delete = now + hard;
+                       job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
+                       charon->event_queue->add_relative(charon->event_queue, job,
+                                                                                         hard * 1000);
+               }
        }
        
        this->state = state;
@@ -1446,12 +1130,12 @@ static void set_other_id(private_ike_sa_t *this, identification_t *other)
  * Implementation of ike_sa_t.derive_keys.
  */
 static status_t derive_keys(private_ike_sa_t *this,
-                                                       proposal_t *proposal, diffie_hellman_t *dh,
+                                                       proposal_t *proposal, chunk_t secret,
                                                        chunk_t nonce_i, chunk_t nonce_r,
                                                        bool initiator, prf_t *child_prf, prf_t *old_prf)
 {
        prf_plus_t *prf_plus;
-       chunk_t skeyseed, secret, key, nonces, prf_plus_seed;
+       chunk_t skeyseed, key, nonces, prf_plus_seed;
        algorithm_t *algo;
        size_t key_size;
        crypter_t *crypter_i, *crypter_r;
@@ -1475,7 +1159,6 @@ static status_t derive_keys(private_ike_sa_t *this,
                return FAILED;
        }
        
-       dh->get_shared_secret(dh, &secret);
        DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
        nonces = chunk_cat("cc", nonce_i, nonce_r);
        *((u_int64_t*)spi_i.ptr) = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
@@ -1639,28 +1322,6 @@ static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
        this->child_sas->insert_last(this->child_sas, child_sa);
 }
 
-/**
- * Implementation of ike_sa_t.has_child_sa.
- */
-static bool has_child_sa(private_ike_sa_t *this, u_int32_t reqid)
-{
-       iterator_t *iterator;
-       child_sa_t *current;
-       bool found = FALSE;
-       
-       iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
-       while (iterator->iterate(iterator, (void**)&current))
-       {
-               if (current->get_reqid(current) == reqid)
-               {
-                       found = TRUE;
-                       break;
-               }
-       }
-       iterator->destroy(iterator);
-       return found;
-}
-
 /**
  * Implementation of ike_sa_t.get_child_sa.
  */
@@ -1672,7 +1333,7 @@ static child_sa_t* get_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
        
        iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
        while (iterator->iterate(iterator, (void**)&current))
-       {;
+       {
                if (current->get_spi(current, inbound) == spi &&
                        current->get_protocol(current) == protocol)
                {
@@ -1696,18 +1357,17 @@ static iterator_t* create_child_sa_iterator(private_ike_sa_t *this)
  */
 static status_t rekey_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
 {
-       create_child_sa_t *rekey;
        child_sa_t *child_sa;
+       child_rekey_t *child_rekey;
        
        child_sa = get_child_sa(this, protocol, spi, TRUE);
-       if (child_sa == NULL)
+       if (child_sa)
        {
-               return NOT_FOUND;
+               child_rekey = child_rekey_create(&this->public, child_sa);
+               this->task_manager->queue_task(this->task_manager, &child_rekey->task);
+               return this->task_manager->initiate(this->task_manager);
        }
-       
-       rekey = create_child_sa_create(&this->public);
-       rekey->rekeys_child(rekey, child_sa);
-       return queue_transaction(this, (transaction_t*)rekey, FALSE);
+       return FAILED;
 }
 
 /**
@@ -1715,24 +1375,24 @@ static status_t rekey_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u
  */
 static status_t delete_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
 {
-       delete_child_sa_t *del;
        child_sa_t *child_sa;
+       child_delete_t *child_delete;
        
        child_sa = get_child_sa(this, protocol, spi, TRUE);
-       if (child_sa == NULL)
+       if (child_sa)
        {
-               return NOT_FOUND;
+               child_delete = child_delete_create(&this->public, child_sa);
+               this->task_manager->queue_task(this->task_manager, &child_delete->task);
+               return this->task_manager->initiate(this->task_manager);
        }
-       
-       del = delete_child_sa_create(&this->public);
-       del->set_child_sa(del, child_sa);
-       return queue_transaction(this, (transaction_t*)del, FALSE);
+       return FAILED;
 }
 
 /**
  * Implementation of ike_sa_t.destroy_child_sa.
  */
-static status_t destroy_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
+static status_t destroy_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
+                                                                u_int32_t spi)
 {
        iterator_t *iterator;
        child_sa_t *child_sa;
@@ -1754,70 +1414,28 @@ static status_t destroy_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
        return status;
 }
 
-/**
- * Implementation of ike_sa_t.set_lifetimes.
- */
-static void set_lifetimes(private_ike_sa_t *this, bool reauth,
-                                                 u_int32_t soft_lifetime, u_int32_t hard_lifetime)
-{
-       job_t *job;
-       u_int32_t now = time(NULL);
-
-       this->reauth = reauth;
-
-       if (soft_lifetime)
-       {
-               this->time.rekey = now + soft_lifetime;
-               job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
-               charon->event_queue->add_relative(charon->event_queue, job,
-                                                                                 soft_lifetime * 1000);
-       }
-       
-       if (hard_lifetime)
-       {
-               this->time.delete = now + hard_lifetime;
-               job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
-               charon->event_queue->add_relative(charon->event_queue, job,
-                                                                                 hard_lifetime * 1000);
-       }
-}
-
 /**
  * Implementation of public_ike_sa_t.delete.
  */
 static status_t delete_(private_ike_sa_t *this)
 {
+       ike_delete_t *ike_delete;
+
        switch (this->state)
        {
-               case IKE_CONNECTING:
-               {
-                       /* this may happen if a half open IKE_SA gets closed after a
-                        * timeout. We signal here UP_FAILED to complete the SIG schema */
-                       SIG(IKE_UP_FAILED, "half open IKE_SA deleted after timeout");
-                       return DESTROY_ME;
-               }
                case IKE_ESTABLISHED:
-               {
-                       delete_ike_sa_t *delete_ike_sa;
-                       if (this->transaction_out)
-                       {
-                               /* already a transaction in progress. As this may hang
-                               * around a while, we don't inform the other peer. */
-                               return DESTROY_ME;
-                       }
-                       delete_ike_sa = delete_ike_sa_create(&this->public);
-                       return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
-               }
-               case IKE_CREATED:
-               case IKE_DELETING:
+                       DBG1(DBG_IKE, "deleting IKE_SA");
+                       /* do not log when rekeyed */
+               case IKE_REKEYING:
+                       ike_delete = ike_delete_create(&this->public, TRUE);
+                       this->task_manager->queue_task(this->task_manager, &ike_delete->task);
+                       return this->task_manager->initiate(this->task_manager);
                default:
-               {
-                       SIG(IKE_DOWN_START, "closing IKE_SA");
-                       SIG(IKE_DOWN_SUCCESS, "IKE_SA closed between %H[%D]...%H[%D]",
-                               this->my_host, this->my_id, this->other_host, this->other_id);
-                       return DESTROY_ME;
-               }
+                       DBG1(DBG_IKE, "destroying IKE_SA in state %N without notification",
+                                ike_sa_state_names, this->state);
+                       break;
        }
+       return DESTROY_ME;
 }
 
 /**
@@ -1825,139 +1443,344 @@ static status_t delete_(private_ike_sa_t *this)
  */
 static status_t rekey(private_ike_sa_t *this)
 {
-       rekey_ike_sa_t *rekey_ike_sa;
+       ike_rekey_t *ike_rekey;
        
-       DBG1(DBG_IKE, "rekeying IKE_SA between %H[%D]..%H[%D]",
-                this->my_host, this->my_id, this->other_host, this->other_id);
-       
-       if (this->state != IKE_ESTABLISHED)
-       {
-               SIG(IKE_REKEY_START, "rekeying IKE_SA");
-               SIG(IKE_REKEY_FAILED, "unable to rekey IKE_SA in state %N",
-                       ike_sa_state_names, this->state);
-               return FAILED;
-       }
+       ike_rekey = ike_rekey_create(&this->public, TRUE);
        
-       rekey_ike_sa = rekey_ike_sa_create(&this->public);
-       return queue_transaction(this, (transaction_t*)rekey_ike_sa, FALSE);
+       this->task_manager->queue_task(this->task_manager, &ike_rekey->task);
+       return this->task_manager->initiate(this->task_manager);
 }
 
 /**
- * Implementation of ike_sa_t.reauth.
+ * Implementation of ike_sa_t.reestablish
  */
-static status_t reauth(private_ike_sa_t *this)
+static void reestablish(private_ike_sa_t *this)
 {
-       connection_t *connection;
-       child_sa_t *child_sa;
+       ike_sa_id_t *other_id;
+       private_ike_sa_t *other;
        iterator_t *iterator;
+       child_sa_t *child_sa;
+       policy_t *policy;
+       task_t *task;
+       job_t *job;
        
-       DBG1(DBG_IKE, "reauthenticating IKE_SA between %H[%D]..%H[%D]",
-                this->my_host, this->my_id, this->other_host, this->other_id); 
+       other_id =  ike_sa_id_create(0, 0, TRUE);
+       other = (private_ike_sa_t*)charon->ike_sa_manager->checkout(
+                                                                                       charon->ike_sa_manager, other_id);
+       other_id->destroy(other_id);
        
-       /* get a connection to initiate */
-       connection = charon->connections->get_connection_by_hosts(charon->connections,
-                                                                                               this->my_host, this->other_host);
-       if (connection == NULL)
+       apply_config(other, this->connection, this->policy);
+               
+       if (this->state == IKE_ESTABLISHED)
        {
-               DBG1(DBG_IKE, "no connection found to reauthenticate"); 
-               return FAILED;
+               task = (task_t*)ike_init_create(&other->public, TRUE, NULL);
+               other->task_manager->queue_task(other->task_manager, task);
+               task = (task_t*)ike_natd_create(&other->public, TRUE);
+               other->task_manager->queue_task(other->task_manager, task);
+               task = (task_t*)ike_cert_create(&other->public, TRUE);
+               other->task_manager->queue_task(other->task_manager, task);
+               task = (task_t*)ike_config_create(&other->public, other->policy);
+               other->task_manager->queue_task(other->task_manager, task);
+               task = (task_t*)ike_auth_create(&other->public, TRUE);
+               other->task_manager->queue_task(other->task_manager, task);
        }
        
-       /* queue CREATE_CHILD_SA transactions to set up all CHILD_SAs */
+       other->task_manager->adopt_tasks(other->task_manager, this->task_manager);
+       
+       /* Create task for established children, adopt routed children directly */
        iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
-       while (iterator->iterate(iterator, (void**)&child_sa))
+       while(iterator->iterate(iterator, (void**)&child_sa))
        {
-               job_t *job;
-               policy_t *policy;
-               linked_list_t *my_ts, *other_ts;
-               host_t *other;
-               
-               my_ts = child_sa->get_my_traffic_selectors(child_sa);
-               other_ts = child_sa->get_other_traffic_selectors(child_sa);
-               policy = charon->policies->get_policy(charon->policies,
-                                               this->my_id, this->other_id, my_ts, other_ts,
-                                               this->my_host, this->other_host);
-               if (policy == NULL)
+               switch (child_sa->get_state(child_sa))
                {
-                       DBG1(DBG_IKE, "policy not found to recreate CHILD_SA, skipped");
-                       continue;
+                       case CHILD_ROUTED:
+                       {
+                               iterator->remove(iterator);
+                               other->child_sas->insert_first(other->child_sas, child_sa);
+                               break;
+                       }
+                       default:
+                       {
+                               policy = child_sa->get_policy(child_sa);
+                               task = (task_t*)child_create_create(&other->public, policy);
+                               other->task_manager->queue_task(other->task_manager, task);
+                               break;
+                       }
                }
-               connection->get_ref(connection);
-               other = this->other_host->clone(this->other_host);
-               job = (job_t*)initiate_job_create(connection, other, policy);
-               charon->job_queue->add(charon->job_queue, job);
        }
        iterator->destroy(iterator);
-       connection->destroy(connection);
        
-       /* delete the old IKE_SA
-        * TODO: we should delay the delete to avoid connectivity gaps?! */
-       return delete_(this);
+       other->task_manager->initiate(other->task_manager);
+       
+       charon->ike_sa_manager->checkin(charon->ike_sa_manager, &other->public);
+       
+       job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
+       charon->job_queue->add(charon->job_queue, job);
 }
 
 /**
- * Implementation of ike_sa_t.get_rekeying_transaction.
+ * Implementation of ike_sa_t.inherit.
  */
-static transaction_t* get_rekeying_transaction(private_ike_sa_t *this)
+static void inherit(private_ike_sa_t *this, private_ike_sa_t *other)
 {
-       return this->rekeying_transaction;
+       child_sa_t *child_sa;
+       host_t *ip;
+       
+       /* apply hosts and ids */
+       this->my_host->destroy(this->my_host);
+       this->other_host->destroy(this->other_host);
+       this->my_id->destroy(this->my_id);
+       this->other_id->destroy(this->other_id);
+       this->my_host = other->my_host->clone(other->my_host);
+       this->other_host = other->other_host->clone(other->other_host);
+       this->my_id = other->my_id->clone(other->my_id);
+       this->other_id = other->other_id->clone(other->other_id);
+       
+       /* apply virtual assigned IPs... */
+       if (other->my_virtual_ip)
+       {
+               this->my_virtual_ip = other->my_virtual_ip;
+               other->my_virtual_ip = NULL;
+       }
+       if (other->other_virtual_ip)
+       {
+               this->other_virtual_ip = other->other_virtual_ip;
+               other->other_virtual_ip = NULL;
+       }
+       
+       /* ... and DNS servers */
+       while (other->dns_servers->remove_last(other->dns_servers, 
+                                                                                  (void**)&ip) == SUCCESS)
+       {
+               this->dns_servers->insert_first(this->dns_servers, ip);
+       }
+       
+       /* adopt all children */
+       while (other->child_sas->remove_last(other->child_sas,
+                                                                                (void**)&child_sa) == SUCCESS)
+       {
+               this->child_sas->insert_first(this->child_sas, (void*)child_sa);
+       }
 }
 
 /**
- * Implementation of ike_sa_t.set_rekeying_transaction.
+ * Implementation of ike_sa_t.is_natt_enabled.
  */
-static void set_rekeying_transaction(private_ike_sa_t *this, transaction_t *rekey)
+static bool is_natt_enabled(private_ike_sa_t *this)
 {
-       this->rekeying_transaction = rekey;
+       return this->nat_here || this->nat_there;
 }
 
 /**
- * Implementation of ike_sa_t.adopt_children.
+ * Implementation of ike_sa_t.enable_natt.
  */
-static void adopt_children(private_ike_sa_t *this, private_ike_sa_t *other)
+static void enable_natt(private_ike_sa_t *this, bool local)
 {
-       child_sa_t *child_sa;
-       
-       while (other->child_sas->remove_last(other->child_sas,
-                                                                                (void**)&child_sa) == SUCCESS)
+       if (local)
        {
-               this->child_sas->insert_first(this->child_sas, (void*)child_sa);
+               DBG1(DBG_IKE, "local host is behind NAT, scheduling keep alives");
+               this->nat_here = TRUE;
+               send_keepalive(this);
+       }
+       else
+       {
+               DBG1(DBG_IKE, "remote host is behind NAT");
+               this->nat_there = TRUE;
        }
 }
 
 /**
- * Implementation of ike_sa_t.get_next_message_id.
+ * Implementation of ike_sa_t.reset
  */
-static u_int32_t get_next_message_id (private_ike_sa_t *this)
+static void reset(private_ike_sa_t *this)
 {
-       return this->message_id_out++;
+       /*  the responder ID is reset, as peer may choose another one */
+       if (this->ike_sa_id->is_initiator(this->ike_sa_id))
+       {
+               this->ike_sa_id->set_responder_spi(this->ike_sa_id, 0);
+       }
+       
+       set_state(this, IKE_CREATED);
+       
+       this->task_manager->reset(this->task_manager);
 }
 
 /**
- * Implementation of ike_sa_t.is_natt_enabled.
+ * Implementation of ike_sa_t.set_virtual_ip
  */
-static bool is_natt_enabled(private_ike_sa_t *this)
+static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
 {
-       return this->nat_here || this->nat_there;
+       if (local)
+       {
+               DBG1(DBG_IKE, "installing new virtual IP %H", ip);
+               if (this->my_virtual_ip)
+               {
+                       DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
+                       charon->kernel_interface->del_ip(charon->kernel_interface,
+                                                                                        this->my_virtual_ip,
+                                                                                        this->other_host);
+                       this->my_virtual_ip->destroy(this->my_virtual_ip);
+               }
+               if (charon->kernel_interface->add_ip(charon->kernel_interface, ip,
+                                                                                        this->other_host) == SUCCESS)
+               {
+                       this->my_virtual_ip = ip->clone(ip);
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "installing virtual IP %H failed", ip);
+                       this->my_virtual_ip = NULL;
+               }
+       }
+       else
+       {
+               DESTROY_IF(this->other_virtual_ip);
+               this->other_virtual_ip = ip->clone(ip);
+       }
 }
 
 /**
- * Implementation of ike_sa_t.enable_natt.
+ * Implementation of ike_sa_t.get_virtual_ip
  */
-static void enable_natt(private_ike_sa_t *this, bool local)
+static host_t* get_virtual_ip(private_ike_sa_t *this, bool local)
 {
        if (local)
        {
-               DBG1(DBG_IKE, "local host is behind NAT, using NAT-T, "
-                       "scheduled keep alives");
-               this->nat_here = TRUE;
-               send_keepalive(this);
+               return this->my_virtual_ip;
        }
        else
        {
-               DBG1(DBG_IKE, "remote host is behind NAT, using NAT-T");
-               this->nat_there = TRUE;
+               return this->other_virtual_ip;
+       }
+}
+
+/**
+ * Implementation of ike_sa_t.remove_dns_server
+ */
+static void remove_dns_servers(private_ike_sa_t *this)
+{
+       FILE *file;
+       struct stat stats;
+       chunk_t contents, line, orig_line, token;
+       char string[INET6_ADDRSTRLEN];
+       host_t *ip;
+       iterator_t *iterator;
+       
+       if (this->dns_servers->get_count(this->dns_servers) == 0)
+       {
+               /* don't touch anything if we have no nameservers installed */
+               return;
+       }
+       
+       file = fopen(RESOLV_CONF, "r");
+       if (file == NULL || stat(RESOLV_CONF, &stats) != 0)
+       {
+               DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+               return;
+       }
+       
+       contents = chunk_alloca((size_t)stats.st_size);
+       
+       if (fread(contents.ptr, 1, contents.len, file) != contents.len)
+       {
+               DBG1(DBG_IKE, "unable to read DNS configuration file: %m");
+               fclose(file);
+               return;
+       }
+       
+       fclose(file);
+       file = fopen(RESOLV_CONF, "w");
+       if (file == NULL)
+       {
+               DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+               return;
+       }
+       
+       iterator = this->dns_servers->create_iterator(this->dns_servers, TRUE);
+       while (fetchline(&contents, &line))
+       {
+               bool found = FALSE;
+               orig_line = line;
+               if (extract_token(&token, ' ', &line) &&
+                       strncasecmp(token.ptr, "nameserver", token.len) == 0)
+               {
+                       if (!extract_token(&token, ' ', &line))
+                       {
+                               token = line;
+                       }
+                       iterator->reset(iterator);
+                       while (iterator->iterate(iterator, (void**)&ip))
+                       {
+                               snprintf(string, sizeof(string), "%H", ip);
+                               if (strlen(string) == token.len &&
+                                       strncmp(token.ptr, string, token.len) == 0)
+                               {
+                                       iterator->remove(iterator);
+                                       ip->destroy(ip);
+                                       found = TRUE;
+                                       break;
+                               }
+                       }
+               }               
+               
+               if (!found)
+               {       
+                       /* write line untouched back to file */
+                       fwrite(orig_line.ptr, orig_line.len, 1, file);
+                       fprintf(file, "\n");
+               }
+       }
+       iterator->destroy(iterator);
+       fclose(file);
+}
+
+/**
+ * Implementation of ike_sa_t.add_dns_server
+ */
+static void add_dns_server(private_ike_sa_t *this, host_t *dns)
+{
+       FILE *file;
+       struct stat stats;
+       chunk_t contents;
+
+       DBG1(DBG_IKE, "installing DNS server %H", dns);
+       
+       file = fopen(RESOLV_CONF, "a+");
+       if (file == NULL || stat(RESOLV_CONF, &stats) != 0)
+       {
+               DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+               return;
+       }
+
+       contents = chunk_alloca(stats.st_size);
+       
+       if (fread(contents.ptr, 1, contents.len, file) != contents.len)
+       {
+               DBG1(DBG_IKE, "unable to read DNS configuration file: %m");
+               fclose(file);
+               return;
+       }
+       
+       fclose(file);
+       file = fopen(RESOLV_CONF, "w");
+       if (file == NULL)
+       {
+               DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+               return;
+       }
+       
+       if (fprintf(file, "nameserver %H   # added by strongSwan, assigned by %D\n",
+               dns, this->other_id) < 0)
+       {
+               DBG1(DBG_IKE, "unable to write DNS configuration: %m");
        }
+       else
+       {
+               this->dns_servers->insert_last(this->dns_servers, dns->clone(dns));
+       }
+       fwrite(contents.ptr, contents.len, 1, file);
+       
+       fclose(file);   
 }
 
 /**
@@ -1967,19 +1790,26 @@ static int print(FILE *stream, const struct printf_info *info,
                                 const void *const *args)
 {
        int written = 0;
+       bool reauth = FALSE;
        private_ike_sa_t *this = *((private_ike_sa_t**)(args[0]));
        
+       if (this->connection)
+       {
+               reauth = this->connection->get_reauth(this->connection);
+       }
+       
        if (this == NULL)
        {
                return fprintf(stream, "(null)");
        }
        
-       written = fprintf(stream, "%12s: %N, %H[%D]...%H[%D]",
-                                         this->name, ike_sa_state_names, this->state,
-                                         this->my_host, this->my_id, this->other_host, this->other_id);
-       written += fprintf(stream, "\n%12s: IKE SPIs: %J, %s in %ds",
-                                         this->name, this->ike_sa_id,
-                                         this->reauth? "reauthentication":"rekeying",
+       written = fprintf(stream, "%12s[%d]: %N, %H[%D]...%H[%D]", get_name(this),
+                                         this->unique_id, ike_sa_state_names, this->state,
+                                         this->my_host, this->my_id, this->other_host,
+                                         this->other_id);
+       written += fprintf(stream, "\n%12s[%d]: IKE SPIs: %J, %s in %ds",
+                                         get_name(this), this->unique_id, this->ike_sa_id, 
+                                         this->connection && reauth? "reauthentication":"rekeying",
                                          this->time.rekey - time(NULL));
 
        if (info->alt)
@@ -2003,11 +1833,7 @@ static void __attribute__ ((constructor))print_register()
 static void destroy(private_ike_sa_t *this)
 {
        this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy));
-       this->transaction_queue->destroy_offset(this->transaction_queue, offsetof(transaction_t, destroy));
        
-       DESTROY_IF(this->transaction_in);
-       DESTROY_IF(this->transaction_in_next);
-       DESTROY_IF(this->transaction_out);
        DESTROY_IF(this->crypter_in);
        DESTROY_IF(this->crypter_out);
        DESTROY_IF(this->signer_in);
@@ -2017,13 +1843,27 @@ static void destroy(private_ike_sa_t *this)
        DESTROY_IF(this->auth_verify);
        DESTROY_IF(this->auth_build);
        
+       if (this->my_virtual_ip)
+       {
+               charon->kernel_interface->del_ip(charon->kernel_interface,
+                                                                                this->my_virtual_ip, this->other_host);
+               this->my_virtual_ip->destroy(this->my_virtual_ip);
+       }
+       DESTROY_IF(this->other_virtual_ip);
+       
+       remove_dns_servers(this);
+       this->dns_servers->destroy_offset(this->dns_servers, offsetof(host_t, destroy));
+       
        DESTROY_IF(this->my_host);
        DESTROY_IF(this->other_host);
        DESTROY_IF(this->my_id);
        DESTROY_IF(this->other_id);
        
-       free(this->name);
+       DESTROY_IF(this->connection);
+       DESTROY_IF(this->policy);
+       
        this->ike_sa_id->destroy(this->ike_sa_id);
+       this->task_manager->destroy(this->task_manager);
        free(this);
 }
 
@@ -2033,17 +1873,21 @@ static void destroy(private_ike_sa_t *this)
 ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
 {
        private_ike_sa_t *this = malloc_thing(private_ike_sa_t);
+       static u_int32_t unique_id = 0;
        
        /* Public functions */
        this->public.get_state = (ike_sa_state_t(*)(ike_sa_t*)) get_state;
        this->public.set_state = (void(*)(ike_sa_t*,ike_sa_state_t)) set_state;
        this->public.get_name = (char*(*)(ike_sa_t*))get_name;
-       this->public.set_name = (void(*)(ike_sa_t*,char*))set_name;
        this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
        this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) initiate;
        this->public.route = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) route;
        this->public.unroute = (status_t(*)(ike_sa_t*,policy_t*)) unroute;
        this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire;
+       this->public.get_connection = (connection_t*(*)(ike_sa_t*))get_connection;
+       this->public.set_connection = (void(*)(ike_sa_t*,connection_t*))set_connection;
+       this->public.get_policy = (policy_t*(*)(ike_sa_t*))get_policy;
+       this->public.set_policy = (void(*)(ike_sa_t*,policy_t*))set_policy;
        this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
        this->public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
        this->public.set_my_host = (void(*)(ike_sa_t*,host_t*)) set_my_host;
@@ -2053,8 +1897,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.set_my_id = (void(*)(ike_sa_t*,identification_t*)) set_my_id;
        this->public.get_other_id = (identification_t*(*)(ike_sa_t*)) get_other_id;
        this->public.set_other_id = (void(*)(ike_sa_t*,identification_t*)) set_other_id;
-       this->public.get_next_message_id = (u_int32_t(*)(ike_sa_t*)) get_next_message_id;
-       this->public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request;
+       this->public.retransmit = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit;
        this->public.delete = (status_t(*)(ike_sa_t*))delete_;
        this->public.destroy = (void(*)(ike_sa_t*))destroy;
        this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd;
@@ -2063,9 +1906,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.get_child_prf = (prf_t *(*) (ike_sa_t *)) get_child_prf;
        this->public.get_auth_verify = (prf_t *(*) (ike_sa_t *)) get_auth_verify;
        this->public.get_auth_build = (prf_t *(*) (ike_sa_t *)) get_auth_build;
-       this->public.derive_keys = (status_t (*) (ike_sa_t *,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
+       this->public.derive_keys = (status_t (*) (ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
        this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa;
-       this->public.has_child_sa = (bool(*)(ike_sa_t*,u_int32_t)) has_child_sa;
        this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa;
        this->public.create_child_sa_iterator = (iterator_t* (*)(ike_sa_t*)) create_child_sa_iterator;
        this->public.rekey_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa;
@@ -2073,20 +1915,21 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
        this->public.enable_natt = (void(*)(ike_sa_t*, bool)) enable_natt;
        this->public.is_natt_enabled = (bool(*)(ike_sa_t*)) is_natt_enabled;
-       this->public.set_lifetimes = (void(*)(ike_sa_t*,bool,u_int32_t,u_int32_t))set_lifetimes;
-       this->public.apply_connection = (void(*)(ike_sa_t*,connection_t*))apply_connection;
        this->public.rekey = (status_t(*)(ike_sa_t*))rekey;
-       this->public.reauth = (status_t(*)(ike_sa_t*))reauth;
-       this->public.get_rekeying_transaction = (transaction_t*(*)(ike_sa_t*))get_rekeying_transaction;
-       this->public.set_rekeying_transaction = (void(*)(ike_sa_t*,transaction_t*))set_rekeying_transaction;
-       this->public.adopt_children = (void(*)(ike_sa_t*,ike_sa_t*))adopt_children;
+       this->public.reestablish = (void(*)(ike_sa_t*))reestablish;
+       this->public.inherit = (void(*)(ike_sa_t*,ike_sa_t*))inherit;
+       this->public.generate_message = (status_t(*)(ike_sa_t*,message_t*,packet_t**))generate_message;
+       this->public.reset = (void(*)(ike_sa_t*))reset;
+       this->public.get_unique_id = (u_int32_t(*)(ike_sa_t*))get_unique_id;
+       this->public.set_virtual_ip = (void(*)(ike_sa_t*,bool,host_t*))set_virtual_ip;
+       this->public.get_virtual_ip = (host_t*(*)(ike_sa_t*,bool))get_virtual_ip;
+       this->public.add_dns_server = (void(*)(ike_sa_t*,host_t*))add_dns_server;
        
        /* initialize private fields */
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
-       this->name = strdup("(uninitialized)");
        this->child_sas = linked_list_create();
-       this->my_host = host_create_from_string("0.0.0.0", 0);
-       this->other_host = host_create_from_string("0.0.0.0", 0);
+       this->my_host = host_create_any(AF_INET);
+       this->other_host = host_create_any(AF_INET);
        this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty);
        this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty);
        this->crypter_in = NULL;
@@ -2099,21 +1942,18 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->child_prf = NULL;
        this->nat_here = FALSE;
        this->nat_there = FALSE;
-       this->transaction_queue = linked_list_create();
-       this->transaction_in = NULL;
-       this->transaction_in_next = NULL;
-       this->transaction_out = NULL;
-       this->rekeying_transaction = NULL;
        this->state = IKE_CREATED;
-       this->message_id_out = 0;
-       /* set to NOW, as when we rekey an existing IKE_SA no message is exchanged
-        * and inbound therefore uninitialized */
        this->time.inbound = this->time.outbound = time(NULL);
        this->time.established = 0;
        this->time.rekey = 0;
        this->time.delete = 0;
-       this->dpd_delay = 0;
-       this->retrans_sequences = 0;
+       this->connection = NULL;
+       this->policy = NULL;
+       this->task_manager = task_manager_create(&this->public);
+       this->unique_id = ++unique_id;
+       this->my_virtual_ip = NULL;
+       this->other_virtual_ip = NULL;
+       this->dns_servers = linked_list_create();
        
        return &this->public;
 }
index 433e37292330a6303ff37be927533a7cb8fa9ed3..2ba9313ab69f6a3d9a1c6c207e5487856908be68 100644 (file)
@@ -33,7 +33,7 @@ typedef struct ike_sa_t ike_sa_t;
 #include <encoding/payloads/proposal_substructure.h>
 #include <sa/ike_sa_id.h>
 #include <sa/child_sa.h>
-#include <sa/transactions/transaction.h>
+#include <sa/tasks/task.h>
 #include <config/configuration.h>
 #include <utils/randomizer.h>
 #include <crypto/prfs/prf.h>
@@ -121,7 +121,7 @@ extern enum_name_t *ike_sa_state_names;
  * An IKE_SA contains crypto information related to a connection
  * with a peer. It contains multiple IPsec CHILD_SA, for which
  * it is responsible. All traffic is handled by an IKE_SA, using
- * transactions.
+ * the task manager and its tasks.
  *
  * @b Constructors:
  * - ike_sa_create()
@@ -140,6 +140,14 @@ struct ike_sa_t {
         */
        ike_sa_id_t* (*get_id) (ike_sa_t *this);
        
+       /**
+        * @brief Get the numerical ID uniquely defining this IKE_SA.
+        *
+        * @param this                  calling object
+        * @return                              unique ID
+        */
+       u_int32_t (*get_unique_id) (ike_sa_t *this);
+       
        /**
         * @brief Get the state of the IKE_SA.
         *
@@ -164,14 +172,6 @@ struct ike_sa_t {
         */
        char* (*get_name) (ike_sa_t *this);
        
-       /**
-        * @brief Set the name of the connection this IKE_SA uses.
-        *
-        * @param this                  calling object
-        * @param name                  name, gets cloned
-        */
-       void (*set_name) (ike_sa_t *this, char* name);
-       
        /**
         * @brief Get the own host address.
         * 
@@ -235,6 +235,38 @@ struct ike_sa_t {
         * @param other                 identification
         */
        void (*set_other_id) (ike_sa_t *this, identification_t *other);
+       
+       /**
+        * @brief Get the connection used by this IKE_SA.
+        * 
+        * @param this                  calling object
+        * @return                              connection
+        */
+       connection_t* (*get_connection) (ike_sa_t *this);
+       
+       /**
+        * @brief Set the connection to use with this IKE_SA.
+        * 
+        * @param this                  calling object
+        * @param connection    connection to use
+        */
+       void (*set_connection) (ike_sa_t *this, connection_t* connection);
+
+       /**
+        * @brief Get the policy used by this IKE_SA.
+        * 
+        * @param this                  calling object
+        * @return                              policy
+        */
+       policy_t* (*get_policy) (ike_sa_t *this);
+       
+       /**
+        * @brief Set the policy to use with this IKE_SA.
+        * 
+        * @param this                  calling object
+        * @param policy                policy to use
+        */
+       void (*set_policy) (ike_sa_t *this, policy_t *policy);
 
        /**
         * @brief Initiate a new connection.
@@ -308,17 +340,6 @@ struct ike_sa_t {
         */
        status_t (*delete) (ike_sa_t *this);
        
-       /**
-        * @brief Retransmits a request.
-        * 
-        * @param this                  calling object
-        * @param message_id    ID of the request to retransmit
-        * @return
-        *                                              - SUCCESS
-        *                                              - NOT_FOUND if request doesn't have to be retransmited
-        */
-       status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id);
-       
        /**
         * @brief Processes a incoming IKEv2-Message.
         *
@@ -327,7 +348,7 @@ struct ike_sa_t {
         * destroy the IKE_SA immediatly, as it is unusable.
         * 
         * @param this                  calling object
-        * @param[in] message   message to process
+        * @param message       message to process
         * @return                              
         *                                              - SUCCESS
         *                                              - FAILED
@@ -336,44 +357,33 @@ struct ike_sa_t {
        status_t (*process_message) (ike_sa_t *this, message_t *message);
        
        /**
-        * @brief Get the next message ID for a request.
-        *
+        * @brief Generate a IKE message to send it to the peer.
+        * 
+        * This method generates all payloads in the message and encrypts/signs
+        * the packet.
+        * 
         * @param this                  calling object
-        * @return                              the next message id
+        * @param message               message to generate
+        * @param packet                generated output packet
+        * @return                              
+        *                                              - SUCCESS
+        *                                              - FAILED
+        *                                              - DESTROY_ME if this IKE_SA MUST be deleted
         */
-       u_int32_t (*get_next_message_id) (ike_sa_t *this);
+       status_t (*generate_message) (ike_sa_t *this, message_t *message,
+                                                                 packet_t **packet);
        
        /**
-        * @brief Check if NAT traversal is enabled for this IKE_SA.
-        *
-        * @param this                  calling object
-        * @return                              TRUE if NAT traversal enabled
-        */
-       bool (*is_natt_enabled) (ike_sa_t *this);
-
-       /**
-        * @brief Enable NAT detection for this IKE_SA.
-        *
-        * If a Network address translation is detected with
-        * NAT_DETECTION notifys, a SA must switch to ports
-        * 4500. To enable this behavior, call enable_natt().
-        * It is relevant which peer is NATted, this is specified
-        * with the "local" parameter. Call it twice when both
-        * are NATted.
-        *
-        * @param this                  calling object
-        * @param local                 TRUE, if we are NATted, FALSE if other
-        */
-       void (*enable_natt) (ike_sa_t *this, bool local);
-
-       /**
-        * @brief Apply connection parameters for this IKE_SA.
+        * @brief Retransmits a request.
         * 
-        * @param this                  calling object
-        * @param connection    connection definition
+        * @param this                  calling object
+        * @param message_id    ID of the request to retransmit
+        * @return
+        *                                              - SUCCESS
+        *                                              - NOT_FOUND if request doesn't have to be retransmited
         */
-       void (*apply_connection) (ike_sa_t *this, connection_t *connection);
-
+       status_t (*retransmit) (ike_sa_t *this, u_int32_t message_id);
+       
        /**
         * @brief Sends a DPD request to the peer.
         *
@@ -399,6 +409,29 @@ struct ike_sa_t {
         * @param this                  calling object
         */
        void (*send_keepalive) (ike_sa_t *this);
+       
+       /**
+        * @brief Check if NAT traversal is enabled for this IKE_SA.
+        *
+        * @param this                  calling object
+        * @return                              TRUE if NAT traversal enabled
+        */
+       bool (*is_natt_enabled) (ike_sa_t *this);
+
+       /**
+        * @brief Enable NAT detection for this IKE_SA.
+        *
+        * If a Network address translation is detected with
+        * NAT_DETECTION notifys, a SA must switch to ports
+        * 4500. To enable this behavior, call enable_natt().
+        * It is relevant which peer is NATted, this is specified
+        * with the "local" parameter. Call it twice when both
+        * are NATted.
+        *
+        * @param this                  calling object
+        * @param local                 TRUE, if we are NATted, FALSE if other
+        */
+       void (*enable_natt) (ike_sa_t *this, bool local);
 
        /**
         * @brief Derive all keys and create the transforms for IKE communication.
@@ -411,15 +444,14 @@ struct ike_sa_t {
         *
         * @param this                  calling object
         * @param proposal              proposal which contains algorithms to use
-        * @param dh                    diffie hellman object with shared secret
+        * @param secret                secret derived from DH exchange, gets freed
         * @param nonce_i               initiators nonce
         * @param nonce_r               responders nonce
         * @param initiator             TRUE if initiator, FALSE otherwise
         * @param child_prf             PRF with SK_d key when rekeying, NULL otherwise
         * @param old_prf               general purpose PRF of old SA when rekeying
         */
-       status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal,
-                                                       diffie_hellman_t *dh,
+       status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal, chunk_t secret,
                                                        chunk_t nonce_i, chunk_t nonce_r,
                                                        bool initiator, prf_t *child_prf, prf_t *old_prf);
        
@@ -463,15 +495,6 @@ struct ike_sa_t {
         */
        void (*add_child_sa) (ike_sa_t *this, child_sa_t *child_sa);
        
-       /**
-        * @brief Check if an IKE_SA has one or more CHILD_SAs with a given reqid.
-        * 
-        * @param this                  calling object
-        * @param reqid                 reqid of the CHILD
-        * @return                              TRUE if it has such a CHILD, FALSE if not
-        */
-       bool (*has_child_sa) (ike_sa_t *this, u_int32_t reqid);
-       
        /**
         * @brief Get a CHILD_SA identified by protocol and SPI.
         * 
@@ -536,22 +559,6 @@ struct ike_sa_t {
         */
        status_t (*destroy_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
 
-       /**
-        * @brief Set lifetimes of an IKE_SA.
-        *
-        * Two lifetimes are specified. The soft_lifetime says, when rekeying should
-        * be initiated. The hard_lifetime says, when the IKE_SA has been expired
-        * and must be deleted. Normally, hard_lifetime > soft_lifetime, and 
-        * hard_lifetime is only reached when rekeying at soft_lifetime fails.
-        *
-        * @param this                  calling object
-        * @param reauth                use full reauthentication instead of rekeying.
-        * @param soft_lifetime soft_lifetime
-        * @param hard_lifetime hard_lifetime
-        */
-       void (*set_lifetimes) (ike_sa_t *this, bool reauth,
-                                                  u_int32_t soft_lifetime, u_int32_t hard_lifetime);
-
        /**
         * @brief Rekey the IKE_SA.
         *
@@ -563,42 +570,60 @@ struct ike_sa_t {
        status_t (*rekey) (ike_sa_t *this);
 
        /**
-        * @brief Reauthentication the IKE_SA.
+        * @brief Restablish the IKE_SA.
         *
         * Create a completely new IKE_SA with authentication, recreates all children
-        * within the IKE_SA and shuts the old SA down.
+        * within the IKE_SA, but lets the old IKE_SA untouched.
         *
         * @param this                  calling object
-        * @return                              - SUCCESS, if IKE_SA rekeying initiated
         */
-       status_t (*reauth) (ike_sa_t *this);
-
+       void (*reestablish) (ike_sa_t *this);
+       
        /**
-        * @brief Get the transaction which rekeys this IKE_SA.
+        * @brief Set the virtual IP to use for this IKE_SA and its children.
+        *
+        * The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same
+        * lifetime as the IKE_SA.
         *
         * @param this                  calling object
-        * @return                              rekey_ike_sa_t transaction or NULL
         */
-       transaction_t* (*get_rekeying_transaction) (ike_sa_t *this);
-
+       void (*set_virtual_ip) (ike_sa_t *this, bool local, host_t *ip);
+       
        /**
-        * @brief Set the transaction which rekeys this IKE_SA.
+        * @brief Get the virtual IP configured.
         *
         * @param this                  calling object
-        * @param rekey                 rekey_ike_sa_t transaction or NULL
+        * @param local                 TRUE to get local virtual IP, FALSE for remote
         */
-       void (*set_rekeying_transaction) (ike_sa_t *this, transaction_t *rekey);
-
+       host_t* (*get_virtual_ip) (ike_sa_t *this, bool local);
+       
+       /**
+        * @brief Add a DNS server to the system.
+        *
+        * An IRAS may send a DNS server. To use it, it is installed on the
+        * system. The DNS entry has a lifetime until the IKE_SA gets closed.
+        *
+        * @param this                  calling object
+        * @param dns                   DNS server to install on the system
+        */
+       void (*add_dns_server) (ike_sa_t *this, host_t *dns);
+       
        /**
-        * @brief Move all children from other IKE_SA to this IKE_SA.
+        * @brief Inherit all attributes of other to this after rekeying.
         *
-        * After rekeying completes, all children are switched over to the
-        * newly created IKE_SA.
+        * When rekeying is completed, all CHILD_SAs, the virtual IP and all
+        * outstanding tasks are moved from other to this.
+        *
+        * @param this                  calling object
+        */
+       void (*inherit) (ike_sa_t *this, ike_sa_t *other);
+               
+       /**
+        * @brief Reset the IKE_SA, useable when initiating fails
         *
-        * @param this                  stepfather
-        * @param other                 deceased (rekeyed) IKE_SA
+        * @param this                  calling object
         */
-       void (*adopt_children) (ike_sa_t *this, ike_sa_t *other);
+       void (*reset) (ike_sa_t *this);
        
        /**
         * @brief Destroys a ike_sa_t object.
@@ -611,8 +636,6 @@ struct ike_sa_t {
 /**
  * @brief Creates an ike_sa_t object with a specific ID.
  *
- * The ID gets cloned internally.
- *
  * @param ike_sa_id    ike_sa_id_t object to associate with new IKE_SA
  * @return                             ike_sa_t object
  * 
index 31972e0bcbe22c1aba8d13f4d7954c7f83c93910..6e9d867fdf124d7ea5a9a6dabca9f5a7eae1f6f9 100644 (file)
@@ -296,14 +296,135 @@ static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
        return spi;
 }
 
+/**
+ * Implementation of of ike_sa_manager.checkout.
+ */
+static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
+{
+       bool responder_spi_set;
+       bool initiator_spi_set;
+       bool original_initiator;
+       ike_sa_t *ike_sa = NULL;
+       
+       DBG2(DBG_MGR, "checkout IKE_SA: %J", ike_sa_id);
+       
+       DBG2(DBG_MGR,  "%d IKE_SAs in manager",
+                this->ike_sa_list->get_count(this->ike_sa_list));
+       
+       /* each access is locked */
+       pthread_mutex_lock(&(this->mutex));
+       
+       responder_spi_set = ike_sa_id->get_responder_spi(ike_sa_id);
+       initiator_spi_set = ike_sa_id->get_initiator_spi(ike_sa_id);
+       original_initiator = ike_sa_id->is_initiator(ike_sa_id);
+       
+       if ((initiator_spi_set && responder_spi_set) ||
+               ((initiator_spi_set && !responder_spi_set) && (original_initiator)))
+       {
+               /* we SHOULD have an IKE_SA for these SPIs in the list,
+                * if not, we can't handle the request...
+                */
+               entry_t *entry;
+               /* look for the entry */
+               if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+               {
+                       if (wait_for_entry(this, entry))
+                       {
+                               DBG2(DBG_MGR, "IKE_SA successfully checked out");
+                               /* ok, this IKE_SA is finally ours */
+                               entry->checked_out = TRUE;
+                               ike_sa = entry->ike_sa;
+                               /* update responder SPI when it's not set */
+                               if (entry->ike_sa_id->get_responder_spi(entry->ike_sa_id) == 0)
+                               {
+                                       ike_sa_id_t *ike_sa_ike_sa_id = ike_sa->get_id(ike_sa);
+                                       u_int64_t spi = ike_sa_id->get_responder_spi(ike_sa_id);
+                                       
+                                       ike_sa_ike_sa_id->set_responder_spi(ike_sa_ike_sa_id, spi);
+                                       entry->ike_sa_id->set_responder_spi(entry->ike_sa_id, spi);
+                               }
+                       }
+                       else
+                       {
+                               DBG2(DBG_MGR, "IKE_SA found, but not allowed to check it out");
+                       }
+               }
+               else
+               {
+                       DBG2(DBG_MGR, "IKE_SA not stored in list");
+                       /* looks like there is no such IKE_SA, better luck next time... */
+               }
+       }
+       else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
+       {
+               /* an IKE_SA_INIT from an another endpoint,
+                * he is the initiator.
+                * For simplicity, we do NOT check for retransmitted
+                * IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
+                * Request (even a retransmitted one) will result in a
+                * IKE_SA. This could be improved...
+                */
+               u_int64_t responder_spi;
+               entry_t *new_entry;
+               
+               /* set SPIs, we are the responder */
+               responder_spi = get_next_spi(this);
+               
+               /* we also set arguments spi, so its still valid */
+               ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
+               
+               /* create entry */
+               new_entry = entry_create(ike_sa_id);
+               
+               this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
+               
+               /* check ike_sa out */
+               DBG2(DBG_MGR,  "IKE_SA added to list of known IKE_SAs");
+               new_entry->checked_out = TRUE;
+               ike_sa = new_entry->ike_sa;
+       }
+       else if (!initiator_spi_set && !responder_spi_set)
+       {
+               /* checkout of a new and unused IKE_SA, used for rekeying */
+               entry_t *new_entry;
+               
+               if (original_initiator)
+               {
+                       ike_sa_id->set_initiator_spi(ike_sa_id, get_next_spi(this));
+               }
+               else
+               {
+                       ike_sa_id->set_responder_spi(ike_sa_id, get_next_spi(this));
+               }
+               /* create entry */
+               new_entry = entry_create(ike_sa_id);
+               DBG2(DBG_MGR, "created IKE_SA: %J", ike_sa_id);
+                       
+               this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
+               
+               /* check ike_sa out */
+               new_entry->checked_out = TRUE;
+               ike_sa = new_entry->ike_sa;
+       }
+       else
+       {
+               /* responder set, initiator not: here is something seriously wrong! */
+               DBG2(DBG_MGR, "invalid IKE_SA SPIs");
+       }
+       
+       pthread_mutex_unlock(&(this->mutex));
+       
+       charon->bus->set_sa(charon->bus, ike_sa);
+       return ike_sa;
+}
+
 /**
  * Implementation of of ike_sa_manager.checkout_by_id.
  */
-static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this,
-                                                                  host_t *my_host,
-                                                                  host_t *other_host,
-                                                                  identification_t *my_id,
-                                                                  identification_t *other_id)
+static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this,
+                                                                 host_t *my_host, host_t *other_host,
+                                                                 identification_t *my_id,
+                                                                 identification_t *other_id)
 {
        iterator_t *iterator;
        entry_t *entry;
@@ -387,105 +508,53 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this,
 }
 
 /**
- * Implementation of of ike_sa_manager.checkout.
+ * Implementation of of ike_sa_manager.checkout_by_id.
  */
-static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
+static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
+                                                               bool child)
 {
-       bool responder_spi_set;
-       bool initiator_spi_set;
-       bool original_initiator;
+       iterator_t *iterator, *children;
+       entry_t *entry;
        ike_sa_t *ike_sa = NULL;
+       child_sa_t *child_sa;
        
-       DBG2(DBG_MGR, "checkout IKE_SA: %J", ike_sa_id);
-       
-       DBG2(DBG_MGR,  "%d IKE_SAs in manager",
-                this->ike_sa_list->get_count(this->ike_sa_list));
-       
-       /* each access is locked */
        pthread_mutex_lock(&(this->mutex));
        
-       responder_spi_set = ike_sa_id->get_responder_spi(ike_sa_id);
-       initiator_spi_set = ike_sa_id->get_initiator_spi(ike_sa_id);
-       original_initiator = ike_sa_id->is_initiator(ike_sa_id);
-       
-       if ((initiator_spi_set && responder_spi_set) ||
-               ((initiator_spi_set && !responder_spi_set) && (original_initiator)))
+       iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+       while (iterator->iterate(iterator, (void**)&entry))
        {
-               /* we SHOULD have an IKE_SA for these SPIs in the list,
-                * if not, we can't handle the request...
-                */
-               entry_t *entry;
-               /* look for the entry */
-               if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+               if (wait_for_entry(this, entry))
                {
-                       if (wait_for_entry(this, entry))
+                       /* look for a child with such a reqid ... */
+                       if (child)
                        {
-                               DBG2(DBG_MGR, "IKE_SA successfully checked out");
-                               /* ok, this IKE_SA is finally ours */
-                               entry->checked_out = TRUE;
-                               ike_sa = entry->ike_sa;
+                               children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
+                               while (children->iterate(children, (void**)&child_sa))
+                               {
+                                       if (child_sa->get_reqid(child_sa) == id)
+                                       {
+                                               ike_sa = entry->ike_sa;
+                                               break;
+                                       }               
+                               }
+                               children->destroy(children);
                        }
-                       else
+                       else /* ... or for a IKE_SA with such a unique id */
                        {
-                               DBG2(DBG_MGR, "IKE_SA found, but not allowed to check it out");
+                               if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
+                               {
+                                       ike_sa = entry->ike_sa;
+                               }
+                       }
+                       /* got one, return */
+                       if (ike_sa)
+                       {
+                               entry->checked_out = TRUE;
+                               break;
                        }
-               }
-               else
-               {
-                       DBG2(DBG_MGR, "IKE_SA not stored in list");
-                       /* looks like there is no such IKE_SA, better luck next time... */
                }
        }
-       else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
-       {
-               /* an IKE_SA_INIT from an another endpoint,
-                * he is the initiator.
-                * For simplicity, we do NOT check for retransmitted
-                * IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
-                * Request (even a retransmitted one) will result in a
-                * IKE_SA. This could be improved...
-                */
-               u_int64_t responder_spi;
-               entry_t *new_entry;
-               
-               /* set SPIs, we are the responder */
-               responder_spi = get_next_spi(this);
-               
-               /* we also set arguments spi, so its still valid */
-               ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
-               
-               /* create entry */
-               new_entry = entry_create(ike_sa_id);
-               
-               this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
-               
-               /* check ike_sa out */
-               DBG2(DBG_MGR,  "IKE_SA added to list of known IKE_SAs");
-               new_entry->checked_out = TRUE;
-               ike_sa = new_entry->ike_sa;
-       }
-       else if (!initiator_spi_set && !responder_spi_set && original_initiator)
-       {
-               /* checkout of a new and unused IKE_SA, used for rekeying */
-               entry_t *new_entry;
-               
-               ike_sa_id->set_initiator_spi(ike_sa_id, get_next_spi(this));
-               /* create entry */
-               new_entry = entry_create(ike_sa_id);
-               DBG2(DBG_MGR, "created IKE_SA: %J", ike_sa_id);
-                       
-               this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
-               
-               /* check ike_sa out */
-               new_entry->checked_out = TRUE;
-               ike_sa = new_entry->ike_sa;
-       }
-       else
-       {
-               /* responder set, initiator not: here is something seriously wrong! */
-               DBG2(DBG_MGR, "invalid IKE_SA SPIs");
-       }
-       
+       iterator->destroy(iterator);
        pthread_mutex_unlock(&(this->mutex));
        
        charon->bus->set_sa(charon->bus, ike_sa);
@@ -493,14 +562,15 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id
 }
 
 /**
- * Implementation of of ike_sa_manager.checkout_by_child.
+ * Implementation of of ike_sa_manager.checkout_by_name.
  */
-static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
-                                                                  u_int32_t reqid)
+static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
+                                                                 bool child)
 {
-       iterator_t *iterator;
+       iterator_t *iterator, *children;
        entry_t *entry;
        ike_sa_t *ike_sa = NULL;
+       child_sa_t *child_sa;
        
        pthread_mutex_lock(&(this->mutex));
        
@@ -509,12 +579,31 @@ static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
        {
                if (wait_for_entry(this, entry))
                {
-                       /* ok, access is exclusive for us, check for child */
-                       if (entry->ike_sa->has_child_sa(entry->ike_sa, reqid))
+                       /* look for a child with such a policy name ... */
+                       if (child)
+                       {
+                               children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
+                               while (children->iterate(children, (void**)&child_sa))
+                               {
+                                       if (streq(child_sa->get_name(child_sa), name))
+                                       {
+                                               ike_sa = entry->ike_sa;
+                                               break;
+                                       }               
+                               }
+                               children->destroy(children);
+                       }
+                       else /* ... or for a IKE_SA with such a connection name */
+                       {
+                               if (streq(entry->ike_sa->get_name(entry->ike_sa), name))
+                               {
+                                       ike_sa = entry->ike_sa;
+                               }
+                       }
+                       /* got one, return */
+                       if (ike_sa)
                        {
-                               /* match */
                                entry->checked_out = TRUE;
-                               ike_sa = entry->ike_sa;
                                break;
                        }
                }
@@ -529,9 +618,16 @@ static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
 /**
  * Iterator hook for iterate, gets ike_sas instead of entries
  */
-static void* iterator_hook(void *value)
+static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
+                                                 ike_sa_t **out)
 {
-       return ((entry_t*)value)->ike_sa;
+       /* check out entry */
+       if (wait_for_entry(this, in))
+       {
+               *out = in->ike_sa;
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /**
@@ -540,9 +636,9 @@ static void* iterator_hook(void *value)
 static iterator_t *create_iterator(private_ike_sa_manager_t* this)
 {
        iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
-                                                               this->ike_sa_list, &this->mutex);
+                                                                                       this->ike_sa_list, &this->mutex);
        /* register hook to iterator over ike_sas, not entries */
-       iterator->set_iterator_hook(iterator, iterator_hook);
+       iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
        return iterator;
 }
 
@@ -633,170 +729,6 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
        return retval;
 }
 
-/**
- * Implementation of ike_sa_manager_t.delete.
- */
-static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
-{
-       /* deletion is a bit complex, we must garant that no thread is waiting for
-        * this SA.
-        * We take this SA from the list, and start signaling while threads
-        * are in the condvar.
-        */
-       entry_t *entry;
-       status_t retval;
-       
-       DBG2(DBG_MGR, "delete IKE_SA: %J", ike_sa_id);
-       
-       pthread_mutex_lock(&(this->mutex));
-       
-       if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
-       {
-               /* we try a delete. If it succeeds, our job is done here. The
-                * other peer will reply, and the IKE SA gets the finally deleted...
-                */
-               if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS)
-               {
-                       DBG2(DBG_MGR, "initiated delete for IKE_SA");
-               }
-               /* but if the IKE SA is not in a state where the deletion is 
-                * negotiated with the other peer, we can destroy the IKE SA on our own. 
-                */
-               else
-               {
-                       
-               }
-               retval = SUCCESS;
-       }
-       else
-       {
-               DBG2(DBG_MGR, "tried to delete nonexisting IKE_SA");
-               retval = NOT_FOUND;
-       }
-
-       pthread_mutex_unlock(&(this->mutex));
-       return retval;
-}
-
-/**
- * Implementation of ike_sa_manager_t.delete_by_name.
- */
-static status_t delete_by_name(private_ike_sa_manager_t *this, char *name)
-{
-       iterator_t *iterator;
-       iterator_t *child_iter;
-       entry_t *entry;
-       size_t name_len = strlen(name);
-       
-       pthread_mutex_lock(&(this->mutex));
-       
-       iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
-       while (iterator->iterate(iterator, (void**)&entry))
-       {
-               if (wait_for_entry(this, entry))
-               {
-                       /* delete ike_sa if:
-                        * name{x} matches completely
-                        * name{} matches by name
-                        * name matches by name
-                        */
-                       bool del = FALSE;
-                       char *ike_name;
-                       char *child_name;
-                       child_sa_t *child_sa;
-                       
-                       ike_name = entry->ike_sa->get_name(entry->ike_sa);
-                       /* check if "name{x}" matches completely */
-                       if (strcmp(name, ike_name) == 0)
-                       {
-                               del = TRUE;
-                       }
-                       /* check if name is in form of "name{}" and matches to ike_name */
-                       else if (name_len > 1 &&
-                                        name[name_len - 2] == '{' && name[name_len - 1] == '}' &&
-                                        strlen(ike_name) > name_len &&
-                                        ike_name[name_len - 2] == '{' &&
-                                        strncmp(name, ike_name, name_len - 2) == 0)
-                       {
-                               del = TRUE;
-                       }
-                       /* finally, check if name is "name" and matches ike_name */
-                       else if (name_len == strchr(ike_name, '{') - ike_name &&
-                                        strncmp(name, ike_name, name_len) == 0)
-                       {
-                               del = TRUE;
-                       }
-                       
-                       if (del)
-                       {
-                               if (entry->ike_sa->delete(entry->ike_sa) == DESTROY_ME)
-                               {
-                                       delete_entry(this, entry);
-                                       iterator->reset(iterator);
-                               }
-                               /* no need to check children, as we delete all */
-                               continue;
-                       }
-                       
-                       /* and now the same game for all children. delete child_sa if:
-                        * name[x] matches completely
-                        * name[] matches by name
-                        * name matches by name
-                        */
-                       child_iter = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
-                       while (child_iter->iterate(child_iter, (void**)&child_sa))
-                       {
-                               /* skip ROUTED children, they have their "unroute" command */
-                               if (child_sa->get_state(child_sa) == CHILD_ROUTED)
-                               {
-                                       continue;
-                               }
-                               
-                               child_name = child_sa->get_name(child_sa);
-                               del = FALSE;
-                               /* check if "name[x]" matches completely */
-                               if (strcmp(name, child_name) == 0)
-                               {
-                                       del = TRUE;
-                               }
-                               /* check if name is in form of "name[]" and matches to child_name */
-                               else if (name_len > 1 &&
-                                                name[name_len - 2] == '[' && name[name_len - 1] == ']' &&
-                                                strlen(child_name) > name_len &&
-                                                child_name[name_len - 2] == '[' &&
-                                                strncmp(name, child_name, name_len - 2) == 0)
-                               {
-                                       del = TRUE;
-                               }
-                               /* finally, check if name is "name" and matches child_name */
-                               else if (name_len == strchr(child_name, '[') - child_name &&
-                                                strncmp(name, child_name, name_len) == 0)
-                               {
-                                       del = TRUE;
-                               }
-                               if (del)
-                               {
-                                       if (entry->ike_sa->delete_child_sa(entry->ike_sa,
-                                               child_sa->get_protocol(child_sa),
-                                               child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME)
-                                       {
-                                               /* when a fatal error occurs, we are responsible to
-                                                * remove the IKE_SA */
-                                               delete_entry(this, entry);
-                                               iterator->reset(iterator);
-                                               break;
-                                       }
-                               }
-                       }
-                       child_iter->destroy(child_iter);
-               }
-       }
-       iterator->destroy(iterator);
-       pthread_mutex_unlock(&(this->mutex));
-       
-       return SUCCESS;
-}
-
 /**
  * Implementation of ike_sa_manager_t.destroy.
  */
@@ -859,19 +791,18 @@ ike_sa_manager_t *ike_sa_manager_create()
 
        /* assign public functions */
        this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
-       this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,host_t*,host_t*,identification_t*,identification_t*))checkout_by_id;
        this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
-       this->public.checkout_by_child = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t))checkout_by_child;
+       this->public.checkout_by_peer = (ike_sa_t*(*)(ike_sa_manager_t*,host_t*,host_t*,identification_t*,identification_t*))checkout_by_peer;
+       this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
+       this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
        this->public.create_iterator = (iterator_t*(*)(ike_sa_manager_t*))create_iterator;
        this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
-       this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete_;
-       this->public.delete_by_name = (status_t(*)(ike_sa_manager_t*,char*))delete_by_name;
        this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
        
        /* initialize private variables */
        this->ike_sa_list = linked_list_create();
-       pthread_mutex_init(&(this->mutex), NULL);
+       pthread_mutex_init(&this->mutex, NULL);
        this->randomizer = randomizer_create();
        
-       return (ike_sa_manager_t*)this;
+       return &this->public;
 }
index 671062c4e41af201075dd446e36048358bf940b1..ecd3db15695aeed11e8a946f554546a2d0eba00c 100644 (file)
@@ -59,7 +59,7 @@ struct ike_sa_manager_t {
         * result in a deadlock!
         * 
         * @param this                          the manager object
-        * @param[in/out] ike_sa_id     the SA identifier, will be updated
+        * @param ike_sa_id                     the SA identifier, will be updated
         * @returns                                     
         *                                                      - checked out IKE_SA if found
         *                                                      - NULL, if no such IKE_SA available
@@ -82,25 +82,44 @@ struct ike_sa_manager_t {
         * @param other_id                      ID used by remote
         * @return                                      checked out/created IKE_SA
         */
-       ike_sa_t* (*checkout_by_id) (ike_sa_manager_t* this,
-                                                                host_t *my_host, host_t* other_host,
-                                                                identification_t *my_id, 
-                                                                identification_t *other_id);
+       ike_sa_t* (*checkout_by_peer) (ike_sa_manager_t* this,
+                                                                  host_t *my_host, host_t* other_host,
+                                                                  identification_t *my_id, 
+                                                                  identification_t *other_id);
        
        /**
-        * @brief Check out an IKE_SA by protocol and SPI of one of its CHILD_SA.
+        * @brief Check out an IKE_SA a unique ID.
         *
-        * The kernel sends us expire messages for IPsec SAs. To fullfill
-        * this request, we must check out the IKE SA which contains the
-        * CHILD_SA the kernel wants to modify.
+        * Every IKE_SA and every CHILD_SA is uniquely identified by an ID. 
+        * These checkout function uses, depending
+        * on the child parameter, the unique ID of the IKE_SA or the reqid
+        * of one of a IKE_SAs CHILD_SA.
         *
         * @param this                          the manager object
-        * @param reqid                         reqid of the CHILD_SA
+        * @param id                            unique ID of the object
+        * @param child                         TRUE to use CHILD, FALSE to use IKE_SA
         * @return
         *                                                      - checked out IKE_SA, if found
         *                                                      - NULL, if not found
         */
-       ike_sa_t* (*checkout_by_child) (ike_sa_manager_t* this, u_int32_t reqid);
+       ike_sa_t* (*checkout_by_id) (ike_sa_manager_t* this, u_int32_t id,
+                                                                bool child);
+       
+       /**
+        * @brief Check out an IKE_SA by the policy/connection name.
+        *
+        * Check out the IKE_SA by the connections name or by a CHILD_SAs policy
+        * name.
+        *
+        * @param this                          the manager object
+        * @param name                          name of the connection/policy
+        * @param child                         TRUE to use policy name, FALSE to use conn name
+        * @return
+        *                                                      - checked out IKE_SA, if found
+        *                                                      - NULL, if not found
+        */
+       ike_sa_t* (*checkout_by_name) (ike_sa_manager_t* this, char *name,
+                                                                  bool child);
        
        /**
         * @brief Create an iterator over all stored IKE_SAs.
@@ -121,55 +140,14 @@ struct ike_sa_manager_t {
         * The SA must be checked out again!
         *  
         * @param this                          the manager object
-        * @param[in/out] ike_sa_id     the SA identifier, will be updated
-        * @param[out] ike_sa           checked out SA
+        * @param ike_sa_id                     the SA identifier, will be updated
+        * @param ike_sa                        checked out SA
         * @returns                             
         *                                                      - SUCCESS if checked in
         *                                                      - NOT_FOUND when not found (shouldn't happen!)
         */
        status_t (*checkin) (ike_sa_manager_t* this, ike_sa_t *ike_sa);
        
-       /**
-        * @brief Delete a SA, which was not checked out.
-        *
-        * If the state allows it, the IKE SA is destroyed immediately. If it is
-        * in the state ESTABLSIHED, a delete message
-        * is sent to the remote peer, which has to be acknowledged.
-        *
-        * @warning do not use this when the SA is already checked out, this will
-        * deadlock!
-        *
-        * @param this                          the manager object
-        * @param[in/out] ike_sa_id     the SA identifier
-        * @returns                             
-        *                                                      - SUCCESS if found
-        *                                                      - NOT_FOUND when no such SA is available
-        */
-       status_t (*delete) (ike_sa_manager_t* this, ike_sa_id_t *ike_sa_id);
-       
-       /**
-        * @brief Delete a SA identified by its name, which was not checked out.
-        *
-        * Using delete_by_name allows the delete of IKE_SAs and CHILD_SAs.
-        * The supplied name may have one of the following format:
-        *
-        * name{x}              => delete IKE_SA with "name" and unique id "x"
-        * name{}               => delete all IKE_SAs with "name"
-        * name[x]              => delete CHILD_SA with "name" and unique id "x"
-        * name[]               => delete all CHILD_SAs with "name"
-        * name                 => delete all CHILD_SAs or IKE_SAs with "name"
-        *
-        * @warning do not use this when the SA is already checked out, this will
-        * deadlock!
-        *
-        * @param this                          the manager object
-        * @param name                          name in one of the format described above
-        * @returns                             
-        *                                                      - SUCCESS if found
-        *                                                      - NOT_FOUND when no such SA is available
-        */
-       status_t (*delete_by_name) (ike_sa_manager_t* this, char *name);
-       
        /**
         * @brief Destroy a checked out SA.
         *
diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c
new file mode 100644 (file)
index 0000000..061b023
--- /dev/null
@@ -0,0 +1,780 @@
+/**
+ * @file task_manager.c
+ *
+ * @brief Implementation of task_manager_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "task_manager.h"
+
+#include <daemon.h>
+#include <sa/tasks/ike_init.h>
+#include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_auth.h>
+#include <sa/tasks/ike_cert.h>
+#include <sa/tasks/ike_rekey.h>
+#include <sa/tasks/ike_delete.h>
+#include <sa/tasks/ike_config.h>
+#include <sa/tasks/ike_dpd.h>
+#include <sa/tasks/child_create.h>
+#include <sa/tasks/child_rekey.h>
+#include <sa/tasks/child_delete.h>
+#include <encoding/payloads/delete_payload.h>
+#include <queues/jobs/retransmit_job.h>
+
+typedef struct exchange_t exchange_t;
+
+/**
+ * An exchange in the air, used do detect and handle retransmission
+ */
+struct exchange_t {
+
+       /**
+        * Message ID used for this transaction
+        */
+       u_int32_t mid;
+
+       /**
+        * generated packet for retransmission
+        */
+       packet_t *packet;
+};
+
+typedef struct private_task_manager_t private_task_manager_t;
+
+/**
+ * private data of the task manager
+ */
+struct private_task_manager_t {
+
+       /**
+        * public functions
+        */
+       task_manager_t public;
+
+       /**
+        * associated IKE_SA we are serving
+        */
+       ike_sa_t *ike_sa;
+
+       /**
+        * Exchange we are currently handling as responder
+        */
+       struct {
+               /**
+                * Message ID of the exchange
+                */
+               u_int32_t mid;
+
+               /**
+                * packet for retransmission
+                */
+               packet_t *packet;
+               
+       } responding;
+
+       /**
+        * Exchange we are currently handling as initiator
+        */
+       struct {
+               /**
+                * Message ID of the exchange
+                */
+               u_int32_t mid;
+               
+               /**
+                * how many times we have retransmitted so far
+                */
+               u_int retransmitted;
+
+               /**
+                * packet for retransmission
+                */
+               packet_t *packet;
+               
+               /**
+                * type of the initated exchange
+                */
+               exchange_type_t type;
+       
+       } initiating;
+
+       /**
+        * List of queued tasks not yet in action
+        */
+       linked_list_t *queued_tasks;
+
+       /**
+        * List of active tasks, initiated by ourselve
+        */
+       linked_list_t *active_tasks;
+
+       /**
+        * List of tasks initiated by peer
+        */
+       linked_list_t *passive_tasks;
+       
+       /**
+        * ike_sa_init message we sent, stored here for later authentication
+        */
+       packet_t *ike_sa_init;
+};
+
+/**
+ * move a task of a specific type from the queue to the active list
+ */
+static bool activate_task(private_task_manager_t *this, task_type_t type)
+{
+       iterator_t *iterator;
+       task_t *task;
+       bool found = FALSE;
+       
+       iterator = this->queued_tasks->create_iterator(this->queued_tasks, TRUE);
+       while (iterator->iterate(iterator, (void**)&task))
+       {
+               if (task->get_type(task) == type)
+               {
+                       DBG2(DBG_IKE, "  activating %N task", task_type_names, type);
+                       iterator->remove(iterator);
+                       this->active_tasks->insert_last(this->active_tasks, task);
+                       found = TRUE;
+                       break;
+               }
+       }
+       iterator->destroy(iterator);
+       return found;
+}
+
+/**
+ * Implementation of task_manager_t.retransmit
+ */
+static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
+{
+       if (message_id == this->initiating.mid)
+       {
+               u_int32_t timeout;
+               job_t *job;
+
+               timeout = charon->configuration->get_retransmit_timeout(
+                                               charon->configuration, this->initiating.retransmitted);
+               if (timeout == 0)
+               {
+                       DBG1(DBG_IKE, "giving up after %d retransmits",
+                                this->initiating.retransmitted - 1);
+                       return DESTROY_ME;
+               }
+               
+               if (this->initiating.retransmitted)
+               {
+                       DBG1(DBG_IKE, "retransmit %d of request with message ID %d",
+                                this->initiating.retransmitted, message_id);
+               }
+               this->initiating.retransmitted++;
+               
+               charon->send_queue->add(charon->send_queue,
+                                       this->initiating.packet->clone(this->initiating.packet));
+               job = (job_t*)retransmit_job_create(this->initiating.mid,
+                                                                                       this->ike_sa->get_id(this->ike_sa));
+               charon->event_queue->add_relative(charon->event_queue, job, timeout);
+       }
+       return SUCCESS;
+}
+
+/**
+ * build a request using the active task list
+ * Implementation of task_manager_t.initiate
+ */
+static status_t build_request(private_task_manager_t *this)
+{
+       iterator_t *iterator;
+       task_t *task;
+       message_t *message;
+       status_t status;
+       exchange_type_t exchange = 0;
+       
+       if (this->active_tasks->get_count(this->active_tasks) == 0)
+       {
+               DBG2(DBG_IKE, "activating new tasks");
+               switch (this->ike_sa->get_state(this->ike_sa))
+               {
+                       case IKE_CREATED:
+                               if (activate_task(this, IKE_INIT))
+                               {
+                                       exchange = IKE_SA_INIT;
+                                       activate_task(this, IKE_NATD);
+                                       activate_task(this, IKE_CERT);
+                                       activate_task(this, IKE_AUTHENTICATE);
+                                       activate_task(this, IKE_CONFIG);
+                                       activate_task(this, CHILD_CREATE);
+                               }
+                               break;
+                       case IKE_ESTABLISHED:
+                               if (activate_task(this, CHILD_CREATE))
+                               {
+                                       exchange = CREATE_CHILD_SA;
+                                       activate_task(this, IKE_CONFIG);
+                                       break;
+                               }
+                               if (activate_task(this, CHILD_DELETE))
+                               {
+                                       exchange = INFORMATIONAL;
+                                       break;
+                               }
+                               if (activate_task(this, CHILD_REKEY))
+                               {
+                                       exchange = CREATE_CHILD_SA;
+                                       break;
+                               }
+                               if (activate_task(this, IKE_DELETE))
+                               {
+                                       exchange = INFORMATIONAL;
+                                       break;
+                               }
+                               if (activate_task(this, IKE_REKEY))
+                               {
+                                       exchange = CREATE_CHILD_SA;
+                                       break;
+                               }
+                               if (activate_task(this, IKE_DEADPEER))
+                               {
+                                       exchange = INFORMATIONAL;
+                                       break;
+                               }
+                       case IKE_REKEYING:
+                               if (activate_task(this, IKE_DELETE))
+                               {
+                                       exchange = INFORMATIONAL;
+                                       break;
+                               }
+                       case IKE_DELETING:
+                       default:
+                               break;
+               }
+       }
+       else
+       {
+               DBG2(DBG_IKE, "reinitiating already active tasks");
+               iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+               while (iterator->iterate(iterator, (void**)&task))
+               {
+                       DBG2(DBG_IKE, "  %N task", task_type_names, task->get_type(task));
+                       switch (task->get_type(task))
+                       {
+                               case IKE_INIT:
+                                       exchange = IKE_SA_INIT;
+                                       break;
+                               case IKE_AUTHENTICATE:
+                                       exchange = IKE_AUTH;
+                                       break;
+                               default:
+                                       continue;
+                       }
+                       break;
+               }
+               iterator->destroy(iterator);
+       }
+       
+       if (exchange == 0)
+       {
+               DBG2(DBG_IKE, "nothing to initiate");
+               /* nothing to do yet... */
+               return SUCCESS;
+       }
+       
+       message = message_create();
+       message->set_message_id(message, this->initiating.mid);
+       message->set_exchange_type(message, exchange);
+       this->initiating.type = exchange;
+       this->initiating.retransmitted = 0;
+
+       iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+       while (iterator->iterate(iterator, (void*)&task))
+       {
+           switch (task->build(task, message))
+           {
+               case SUCCESS:
+                   /* task completed, remove it */
+                   iterator->remove(iterator);
+                   task->destroy(task);
+                   break;
+               case NEED_MORE:
+                   /* processed, but task needs another exchange */
+                   break;
+               case FAILED:
+               default:
+                   /* critical failure, destroy IKE_SA */
+                   iterator->destroy(iterator);
+                               message->destroy(message);
+                   return DESTROY_ME;
+           }
+       }
+       iterator->destroy(iterator);
+
+       DESTROY_IF(this->initiating.packet);
+       status = this->ike_sa->generate_message(this->ike_sa, message,
+                                                                                       &this->initiating.packet);
+       message->destroy(message);
+       if (status != SUCCESS)
+       {
+           /* message generation failed. There is nothing more to do than to
+                * close the SA */
+           return DESTROY_ME;
+       }                                               
+       
+       return retransmit(this, this->initiating.mid);
+}
+
+/**
+ * handle an incoming response message
+ */
+static status_t process_response(private_task_manager_t *this,
+                                                                message_t *message)
+{
+       iterator_t *iterator;
+       task_t *task;
+       
+       if (message->get_exchange_type(message) != this->initiating.type)
+       {
+               DBG1(DBG_IKE, "received %N response, but expected %N",
+                        exchange_type_names, message->get_exchange_type(message),
+                        exchange_type_names, this->initiating.type);
+               return DESTROY_ME;
+       }
+
+       iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+       while (iterator->iterate(iterator, (void*)&task))
+       {
+           switch (task->process(task, message))
+           {
+               case SUCCESS:
+                   /* task completed, remove it */
+                   iterator->remove(iterator);
+                   task->destroy(task);
+                   break;
+               case NEED_MORE:
+                   /* processed, but task needs another exchange */
+                   break;
+               case FAILED:
+               default:
+                   /* critical failure, destroy IKE_SA */
+                   iterator->destroy(iterator);
+                   return DESTROY_ME;
+           }
+       }
+       iterator->destroy(iterator);
+       
+       this->initiating.mid++;
+
+       return build_request(this);
+}
+
+/**
+ * build a response depending on the "passive" task list
+ */
+static status_t build_response(private_task_manager_t *this,
+                                                          exchange_type_t exchange)
+{
+       iterator_t *iterator;
+       task_t *task;
+       message_t *message;
+       bool delete = FALSE;
+       status_t status;
+
+       message = message_create();
+       message->set_exchange_type(message, exchange);
+       message->set_message_id(message, this->responding.mid);
+       message->set_request(message, FALSE);
+
+       iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE);
+       while (iterator->iterate(iterator, (void*)&task))
+       {
+           switch (task->build(task, message))
+           {
+               case SUCCESS:
+                   /* task completed, remove it */
+                   iterator->remove(iterator);
+                   task->destroy(task);
+                   break;
+               case NEED_MORE:
+                   /* processed, but task needs another exchange */
+                   break;
+               case FAILED:
+               default:
+                   /* destroy IKE_SA, but SEND response first */
+                   delete = TRUE;
+                   break;
+           }
+           if (delete)
+           {
+               break;
+           }
+       }
+       iterator->destroy(iterator);
+
+       /* message complete, send it */
+       DESTROY_IF(this->responding.packet);
+       status = this->ike_sa->generate_message(this->ike_sa, message,
+                                                                                       &this->responding.packet);
+       message->destroy(message);
+       if (status != SUCCESS)
+       {
+           return DESTROY_ME;
+       }
+       
+       charon->send_queue->add(charon->send_queue,
+                                                       this->responding.packet->clone(this->responding.packet));
+       if (delete)
+       {
+               return DESTROY_ME;
+       }
+       return SUCCESS;
+}
+
+/**
+ * handle an incoming request message
+ */
+static status_t process_request(private_task_manager_t *this,
+                                                               message_t *message)
+{
+       iterator_t *iterator;
+       task_t *task = NULL;
+       exchange_type_t exchange;
+       payload_t *payload;
+       notify_payload_t *notify;
+
+       exchange = message->get_exchange_type(message);
+
+       /* create tasks depending on request type */
+       switch (exchange)
+       {
+               case IKE_SA_INIT:
+               {
+                       task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)ike_natd_create(this->ike_sa, FALSE);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)ike_cert_create(this->ike_sa, FALSE);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)ike_config_create(this->ike_sa, NULL);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)child_create_create(this->ike_sa, NULL);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       break;
+               }
+               case CREATE_CHILD_SA:
+               {
+                       bool notify_found = FALSE, ts_found = FALSE;
+                       iterator = message->get_payload_iterator(message);
+                       while (iterator->iterate(iterator, (void**)&payload))
+                       {
+                               switch (payload->get_type(payload))
+                               {
+                                       case NOTIFY:
+                                       {
+                                               /* if we find a rekey notify, its CHILD_SA rekeying */
+                                               notify = (notify_payload_t*)payload;
+                                               if (notify->get_notify_type(notify) == REKEY_SA &&
+                                                       (notify->get_protocol_id(notify) == PROTO_AH ||
+                                                        notify->get_protocol_id(notify) == PROTO_ESP))
+                                               {
+                                                       notify_found = TRUE;
+                                               }
+                                               break;
+                                       }
+                                       case TRAFFIC_SELECTOR_INITIATOR:
+                                       case TRAFFIC_SELECTOR_RESPONDER:
+                                       {
+                                               /* if we don't find a TS, its IKE rekeying */
+                                               ts_found = TRUE;
+                                               break;
+                                       }
+                                       default:
+                                               break;
+                               }
+                       }
+                       iterator->destroy(iterator);
+               
+                       if (ts_found)
+                       {
+                               if (notify_found)
+                               {
+                                       task = (task_t*)child_rekey_create(this->ike_sa, NULL);
+                               }
+                               else
+                               {
+                                       task = (task_t*)child_create_create(this->ike_sa, NULL);
+                               }
+                       }
+                       else
+                       {
+                               task = (task_t*)ike_rekey_create(this->ike_sa, FALSE);
+                       }
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       
+                       break;
+               }
+               case INFORMATIONAL:
+               {
+                       delete_payload_t *delete;
+                       
+                       delete = (delete_payload_t*)message->get_payload(message, DELETE);
+                       if (delete)
+                       {
+                               if (delete->get_protocol_id(delete) == PROTO_IKE)
+                               {
+                                       task = (task_t*)ike_delete_create(this->ike_sa, FALSE);
+                                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                               }
+                               else
+                               {
+                                       task = (task_t*)child_delete_create(this->ike_sa, NULL);
+                                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                               }
+                       }
+                       else
+                       {
+                               task = (task_t*)ike_dpd_create(FALSE);
+                               this->passive_tasks->insert_last(this->passive_tasks, task);
+                       }
+                       break;
+               }
+               default:
+                       break;
+       }
+
+       /* let the tasks process the message */
+       iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE);
+       while (iterator->iterate(iterator, (void*)&task))
+       {
+           switch (task->process(task, message))
+           {
+               case SUCCESS:
+                   /* task completed, remove it */
+                   iterator->remove(iterator);
+                   task->destroy(task);
+                   break;
+               case NEED_MORE:
+                   /* processed, but task needs at least another call to build() */
+                   break;
+               case FAILED:
+               default:
+                   /* critical failure, destroy IKE_SA */
+                   iterator->destroy(iterator);
+                   return DESTROY_ME;
+           }
+       }
+       iterator->destroy(iterator);
+
+       return build_response(this, exchange);
+}
+
+/**
+ * Implementation of task_manager_t.process_message
+ */
+static status_t process_message(private_task_manager_t *this, message_t *msg)
+{
+       u_int32_t mid = msg->get_message_id(msg);
+
+       if (msg->get_request(msg))
+       {
+               if (mid == this->responding.mid)
+               {
+                       if (process_request(this, msg) != SUCCESS)
+                       {
+                               return DESTROY_ME;
+                       }
+                       this->responding.mid++;
+               }
+               else if ((mid == this->responding.mid - 1) && this->responding.packet)
+               {
+                       DBG1(DBG_IKE, "received retransmit of request with ID %d, "
+                                "retransmitting response", mid);
+                       charon->send_queue->add(charon->send_queue,
+                                                                       this->responding.packet->clone(
+                                                                                                       this->responding.packet));
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "received message ID %d, excepted %d. Ignored",
+                                mid, this->responding.mid);
+               }
+       }
+       else
+       {
+               if (mid == this->initiating.mid)
+               {
+                       if (process_response(this, msg) != SUCCESS)
+                       {
+                               return DESTROY_ME;
+                       }
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "received message ID %d, excepted %d. Ignored",
+                                mid, this->initiating.mid);
+                       return SUCCESS;
+               }
+       }
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_manager_t.queue_task
+ */
+static void queue_task(private_task_manager_t *this, task_t *task)
+{
+       DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task));
+       this->queued_tasks->insert_last(this->queued_tasks, task);
+}
+
+/**
+ * Implementation of task_manager_t.adopt_tasks
+ */
+static void adopt_tasks(private_task_manager_t *this, private_task_manager_t *other)
+{
+       task_t *task;
+
+       /* move queued tasks from other to this */
+       while (other->queued_tasks->remove_last(other->queued_tasks,
+                                                                                               (void**)&task) == SUCCESS)
+       {
+               task->migrate(task, this->ike_sa);
+               this->queued_tasks->insert_first(this->queued_tasks, task);
+       }
+       
+       /* reset active tasks and move them to others queued tasks */
+       while (other->active_tasks->remove_last(other->active_tasks,
+                                                                                               (void**)&task) == SUCCESS)
+       {
+               task->migrate(task, this->ike_sa);
+               this->queued_tasks->insert_first(this->queued_tasks, task);
+       }
+}
+
+/**
+ * Implementation of task_manager_t.busy
+ */
+static bool busy(private_task_manager_t *this)
+{
+       return (this->active_tasks->get_count(this->active_tasks) > 0);
+}
+
+/**
+ * Implementation of task_manager_t.reset
+ */
+static void reset(private_task_manager_t *this)
+{
+       task_t *task;
+       
+       /* reset message counters and retransmit packets */
+       DESTROY_IF(this->responding.packet);
+       DESTROY_IF(this->initiating.packet);
+       DESTROY_IF(this->ike_sa_init);
+       this->responding.packet = NULL;
+       this->initiating.packet = NULL;
+       this->ike_sa_init = NULL;
+       this->responding.mid = 0;
+       this->initiating.mid = -1;
+       
+       /* reset active tasks */
+       while (this->active_tasks->remove_last(this->active_tasks,
+                                                                                  (void**)&task) == SUCCESS)
+       {
+               task->migrate(task, this->ike_sa);
+               this->queued_tasks->insert_first(this->queued_tasks, task);
+       }
+}
+
+/**
+ * Implementation of task_manager_t.destroy
+ */
+static void destroy(private_task_manager_t *this)
+{
+       task_t *task;
+       
+       this->queued_tasks->destroy_offset(this->queued_tasks, 
+                                                                          offsetof(task_t, destroy));
+       this->passive_tasks->destroy_offset(this->passive_tasks,
+                                                                               offsetof(task_t, destroy));
+       
+       /* emmit outstanding signals for tasks */
+       while (this->active_tasks->remove_last(this->active_tasks,
+                                                                                  (void**)&task) == SUCCESS)
+       {
+               switch (task->get_type(task))
+               {
+                       case IKE_AUTH:
+                               SIG(IKE_UP_FAILED, "establishing IKE_SA failed");
+                               break;
+                       case IKE_DELETE:
+                               SIG(IKE_DOWN_FAILED, "deleteing IKE_SA properly failed");
+                               break;
+                       case IKE_REKEY:
+                               SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed");
+                               break;
+                       case CHILD_CREATE:
+                               SIG(CHILD_UP_FAILED, "establishing CHILD_SA failed");
+                               break;
+                       case CHILD_DELETE:
+                               SIG(CHILD_DOWN_FAILED, "deleting CHILD_SA failed");
+                               break;
+                       case CHILD_REKEY:
+                               SIG(IKE_REKEY_FAILED, "rekeying CHILD_SA failed");
+                               break;
+                       default:
+                               break;
+               }
+               task->destroy(task);
+       }
+       this->active_tasks->destroy(this->active_tasks);
+       DESTROY_IF(this->responding.packet);
+       DESTROY_IF(this->initiating.packet);
+       DESTROY_IF(this->ike_sa_init);
+       free(this);
+}
+
+/*
+ * see header file
+ */
+task_manager_t *task_manager_create(ike_sa_t *ike_sa)
+{
+       private_task_manager_t *this = malloc_thing(private_task_manager_t);
+
+       this->public.process_message = (status_t(*)(task_manager_t*,message_t*))process_message;
+       this->public.queue_task = (void(*)(task_manager_t*,task_t*))queue_task;
+       this->public.initiate = (status_t(*)(task_manager_t*))build_request;
+       this->public.retransmit = (status_t(*)(task_manager_t*,u_int32_t))retransmit;
+       this->public.reset = (void(*)(task_manager_t*))reset;
+       this->public.adopt_tasks = (void(*)(task_manager_t*,task_manager_t*))adopt_tasks;
+       this->public.busy = (bool(*)(task_manager_t*))busy;
+       this->public.destroy = (void(*)(task_manager_t*))destroy;
+
+       this->ike_sa = ike_sa;
+       this->responding.packet = NULL;
+       this->initiating.packet = NULL;
+       this->responding.mid = 0;
+       this->initiating.mid = 0;
+       this->queued_tasks = linked_list_create();
+       this->active_tasks = linked_list_create();
+       this->passive_tasks = linked_list_create();
+       this->ike_sa_init = NULL;
+
+       return &this->public;
+}
diff --git a/src/charon/sa/task_manager.h b/src/charon/sa/task_manager.h
new file mode 100644 (file)
index 0000000..c766d4a
--- /dev/null
@@ -0,0 +1,144 @@
+/**
+ * @file task_manager.h
+ * 
+ * @brief Interface of task_manager_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef TASK_MANAGER_H_
+#define TASK_MANAGER_H_
+
+typedef struct task_manager_t task_manager_t;
+
+#include <library.h>
+#include <encoding/message.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief The task manager, juggles task and handles message exchanges.
+ *
+ * On incoming requests, the task manager creates new tasks on demand and
+ * juggles the request through all available tasks. Each task inspects the
+ * request and adds payloads as necessary to the response.
+ * On outgoing requests, the task manager delivers the request through the tasks
+ * to build it, the response gets processed by each task to complete.
+ * The task manager has an internal Queue to store task which should get
+ * completed.
+ * For the initial IKE_SA setup, several tasks are queued: One for the
+ * unauthenticated IKE_SA setup, one for authentication, one for CHILD_SA setup
+ * and maybe one for virtual IP assignement.
+ *
+ * @b Constructors:
+ *  - task_manager_create()
+ * 
+ * @ingroup sa
+ */
+struct task_manager_t {
+
+       /**
+        * @brief Process an incoming message.
+        * 
+        * @param this                  calling object
+        * @param message               message to add payloads to
+        * @return
+        *                                              - DESTROY_ME if IKE_SA must be closed
+        *                                              - SUCCESS otherwise
+        */
+       status_t (*process_message) (task_manager_t *this, message_t *message);
+
+       /**
+        * @brief Initiate an exchange with the currently queued tasks.
+        *
+        * @param this                  calling object
+        */
+       status_t (*initiate) (task_manager_t *this);
+
+       /**
+        * @brief Queue a task in the manager.
+        *
+        * @param this                  calling object
+        * @param task                  task to queue
+        */
+       void (*queue_task) (task_manager_t *this, task_t *task);
+
+       /**
+        * @brief Retransmit a request if it hasn't been acknowledged yet.
+        *
+        * A return value of INVALID_STATE means that the message was already
+        * acknowledged and has not to be retransmitted. A return value of SUCCESS
+        * means retransmission was required and the message has been resent.
+        * 
+        * @param this                  calling object
+        * @param message_id    ID of the message to retransmit
+        * @return
+        *                                              - INVALID_STATE if retransmission not required
+        *                                              - SUCCESS if retransmission sent
+        */
+       status_t (*retransmit) (task_manager_t *this, u_int32_t message_id);
+
+       /**
+        * @brief Migrate all tasks from other to this.
+        *
+        * To rekey or reestablish an IKE_SA completely, all queued or active
+        * tasks should get migrated to the new IKE_SA.
+        * 
+        * @param this                  manager which gets all tasks
+        * @param other                 manager which gives away its tasks
+        */
+       void (*adopt_tasks) (task_manager_t *this, task_manager_t *other);
+       
+       /**
+        * @brief Reset message ID counters of the task manager.
+        *
+        * The IKEv2 protocol requires to restart exchanges with message IDs
+        * reset to zero (INVALID_KE_PAYLOAD, COOKIES, ...). The reset() method
+        * resets the message IDs and resets all active tasks using the migrate()
+        * method.
+        * 
+        * @param this                  calling object
+        * @param other                 manager which gives away its tasks
+        */
+       void (*reset) (task_manager_t *this);
+       
+       /**
+        * @brief Check if we are currently waiting for a reply.
+        *
+        * @param this                  calling object
+        * @return                              TRUE if we are waiting, FALSE otherwise
+        */
+       bool (*busy) (task_manager_t *this);
+       
+       /**
+        * @brief Destroy the task_manager_t.
+        *
+        * @param this                  calling object
+        */
+       void (*destroy) (task_manager_t *this);
+};
+
+/**
+ * @brief Create an instance of the task manager.
+ *
+ * @param ike_sa               IKE_SA to manage.
+ *
+ * @ingroup sa
+ */
+task_manager_t *task_manager_create(ike_sa_t *ike_sa);
+
+#endif /* TASK_MANAGER_H_ */
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c
new file mode 100644 (file)
index 0000000..165baa4
--- /dev/null
@@ -0,0 +1,718 @@
+/**
+ * @file child_create.c
+ *
+ * @brief Implementation of the child_create task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "child_create.h"
+
+#include <daemon.h>
+#include <crypto/diffie_hellman.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ts_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <encoding/payloads/notify_payload.h>
+
+
+typedef struct private_child_create_t private_child_create_t;
+
+/**
+ * Private members of a child_create_t task.
+ */
+struct private_child_create_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       child_create_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * nonce chosen by us
+        */
+       chunk_t my_nonce;
+       
+       /**
+        * nonce chosen by peer
+        */
+       chunk_t other_nonce;
+       
+       /**
+        * policy to create the CHILD_SA from
+        */
+       policy_t *policy;
+       
+       /**
+        * list of proposal candidates
+        */
+       linked_list_t *proposals;
+       
+       /**
+        * selected proposal to use for CHILD_SA
+        */
+       proposal_t *proposal;
+       
+       /**
+        * traffic selectors for initiators side
+        */
+       linked_list_t *tsi;
+       
+       /**
+        * traffic selectors for responders side
+        */
+       linked_list_t *tsr;
+       
+       /**
+        * mode the new CHILD_SA uses (transport/tunnel/beet)
+        */
+       mode_t mode;
+       
+       /**
+        * reqid to use if we are rekeying
+        */
+       u_int32_t reqid;
+       
+       /**
+        * CHILD_SA which gets established
+        */
+       child_sa_t *child_sa;
+};
+
+/**
+ * get the nonce from a message
+ */
+static status_t get_nonce(message_t *message, chunk_t *nonce)
+{
+       nonce_payload_t *payload;
+       
+       payload = (nonce_payload_t*)message->get_payload(message, NONCE);
+       if (payload == NULL)
+       {
+               return FAILED;
+       }
+       *nonce = payload->get_nonce(payload);
+       return NEED_MORE;
+}
+
+/**
+ * generate a new nonce to include in a CREATE_CHILD_SA message
+ */
+static status_t generate_nonce(chunk_t *nonce)
+{
+       status_t status;
+       randomizer_t *randomizer = randomizer_create();
+       
+       status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
+                                                                                                         nonce);
+       randomizer->destroy(randomizer);
+       if (status != SUCCESS)
+       {
+               DBG1(DBG_IKE, "error generating random nonce value");
+               return FAILED;
+       }
+       return SUCCESS;
+}
+
+/**
+ * Check a list of traffic selectors if any selector belongs to host
+ */
+static bool ts_list_is_host(linked_list_t *list, host_t *host)
+{
+       traffic_selector_t *ts;
+       bool is_host = TRUE;
+       iterator_t *iterator = list->create_iterator(list, TRUE);
+       
+       while (is_host && iterator->iterate(iterator, (void**)&ts))
+       {
+               is_host = is_host && ts->is_host(ts, host);
+       }
+       iterator->destroy(iterator);
+       return is_host;
+}
+
+/**
+ * Install a CHILD_SA for usage
+ */
+static status_t select_and_install(private_child_create_t *this)
+{
+       prf_plus_t *prf_plus;
+       status_t status;
+       chunk_t nonce_i, nonce_r, seed;
+       linked_list_t *my_ts, *other_ts;
+       host_t *me, *other, *other_vip, *my_vip;
+       
+       if (this->proposals == NULL || this->tsi == NULL || this->tsr == NULL)
+       {
+               SIG(CHILD_UP_FAILED, "SA/TS payloads missing in message");
+               return FAILED;
+       }
+       
+       if (this->initiator)
+       {
+               nonce_i = this->my_nonce;
+               nonce_r = this->other_nonce;
+               my_ts = this->tsi;
+               other_ts = this->tsr;
+       }
+       else
+       {
+               nonce_r = this->my_nonce;
+               nonce_i = this->other_nonce;
+               my_ts = this->tsr;
+               other_ts = this->tsi;
+       }
+       
+       me = this->ike_sa->get_my_host(this->ike_sa);
+       other = this->ike_sa->get_other_host(this->ike_sa);
+       my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
+       other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
+
+       this->proposal = this->policy->select_proposal(this->policy, this->proposals);
+       
+       if (this->initiator && my_vip)
+       {       /* if we have a virtual IP, shorten our TS to the minimum */
+               my_ts = this->policy->select_my_traffic_selectors(this->policy, my_ts,
+                                                                                                                       my_vip);
+       }
+       else
+       {       /* shorten in the host2host case only */
+               my_ts = this->policy->select_my_traffic_selectors(this->policy, 
+                                                                                                                       my_ts, me);
+       }
+       if (other_vip)
+       {       /* if other has a virtual IP, shorten it's traffic selectors to it */
+               other_ts = this->policy->select_other_traffic_selectors(this->policy,
+                                                                                                                       other_ts, other_vip);
+       }
+       else
+       {       /* use his host for the host2host case */
+               other_ts = this->policy->select_other_traffic_selectors(this->policy,
+                                                                                                                       other_ts, other);
+       }
+       this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
+       this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
+       if (this->initiator)
+       {
+               this->tsi = my_ts;
+               this->tsr = other_ts;
+       }
+       else
+       {
+               this->tsr = my_ts;
+               this->tsi = other_ts;
+       }
+       
+       if (this->proposal == NULL ||
+               this->tsi->get_count(this->tsi) == 0 ||
+               this->tsr->get_count(this->tsr) == 0)
+       {
+               SIG(CHILD_UP_FAILED, "no acceptable proposal found");
+               return FAILED;
+       }
+       
+       if (!this->initiator)
+       {
+               /* check if requested mode is acceptable, downgrade if required */
+               switch (this->mode)
+               {
+                       case MODE_TRANSPORT:
+                               if (!ts_list_is_host(this->tsi, other) ||
+                                       !ts_list_is_host(this->tsr, me))
+                               {
+                                       this->mode = MODE_TUNNEL;
+                                       DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
+                               }
+                               else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+                               {
+                                       this->mode = MODE_TUNNEL;
+                                       DBG1(DBG_IKE, "not using tranport mode, connection NATed");
+                               }
+                               break;
+                       case MODE_BEET:
+                               if (!ts_list_is_host(this->tsi, NULL) ||
+                                       !ts_list_is_host(this->tsr, NULL))
+                               {
+                                       this->mode = MODE_TUNNEL;
+                                       DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
+                               }
+                               break;
+                       default:
+                               break;
+               }
+       }
+       
+       seed = chunk_cata("cc", nonce_i, nonce_r);
+       prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
+       
+       if (this->initiator)
+       {
+               status = this->child_sa->update(this->child_sa, this->proposal,
+                                                                               this->mode, prf_plus);
+       }
+       else
+       {
+               status = this->child_sa->add(this->child_sa, this->proposal,
+                                                                        this->mode, prf_plus);
+       }
+       prf_plus->destroy(prf_plus);
+       
+       if (status != SUCCESS)
+       {
+               SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel");
+               return status;
+       }
+       
+       status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
+                                                                                 this->mode);
+                                                                                 
+       if (status != SUCCESS)
+       {       
+               SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel");
+               return status;
+       }
+       /* add to IKE_SA, and remove from task */
+       this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
+       this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+       this->child_sa = NULL;
+       return SUCCESS;
+}
+
+/**
+ * build the payloads for the message
+ */
+static void build_payloads(private_child_create_t *this, message_t *message)
+{
+       sa_payload_t *sa_payload;
+       ts_payload_t *ts_payload;
+       nonce_payload_t *nonce_payload;
+
+       /* add SA payload */
+       if (this->initiator)
+       {
+               sa_payload = sa_payload_create_from_proposal_list(this->proposals);
+       }
+       else
+       {
+               sa_payload = sa_payload_create_from_proposal(this->proposal);
+       }
+       message->add_payload(message, (payload_t*)sa_payload);
+       
+       /* add TSi/TSr payloads */
+       ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
+       message->add_payload(message, (payload_t*)ts_payload);
+       ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
+       message->add_payload(message, (payload_t*)ts_payload);
+       
+       /* add nonce payload if not in IKE_AUTH */
+       if (message->get_exchange_type(message) == CREATE_CHILD_SA)
+       {
+               nonce_payload = nonce_payload_create();
+               nonce_payload->set_nonce(nonce_payload, this->my_nonce);
+               message->add_payload(message, (payload_t*)nonce_payload);
+       }
+       
+       /* add a notify if we are not in tunnel mode */
+       switch (this->mode)
+       {
+               case MODE_TRANSPORT:
+                       message->add_notify(message, FALSE, USE_TRANSPORT_MODE, chunk_empty);
+                       break;
+               case MODE_BEET:
+                       message->add_notify(message, FALSE, USE_BEET_MODE, chunk_empty);
+                       break;
+               default:
+                       break;
+       }
+}
+
+/**
+ * Read payloads from message
+ */
+static void process_payloads(private_child_create_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+       sa_payload_t *sa_payload;
+       ts_payload_t *ts_payload;
+       notify_payload_t *notify_payload;
+       
+       /* defaults to TUNNEL mode */
+       this->mode = MODE_TUNNEL;
+
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               switch (payload->get_type(payload))
+               {
+                       case SECURITY_ASSOCIATION:
+                               sa_payload = (sa_payload_t*)payload;
+                               this->proposals = sa_payload->get_proposals(sa_payload);
+                               break;
+                       case TRAFFIC_SELECTOR_INITIATOR:
+                               ts_payload = (ts_payload_t*)payload;
+                               this->tsi = ts_payload->get_traffic_selectors(ts_payload);
+                               break;  
+                       case TRAFFIC_SELECTOR_RESPONDER:
+                               ts_payload = (ts_payload_t*)payload;
+                               this->tsr = ts_payload->get_traffic_selectors(ts_payload);
+                               break;
+                       case NOTIFY:
+                               notify_payload = (notify_payload_t*)payload;
+                               switch (notify_payload ->get_notify_type(notify_payload ))
+                               {
+                                       case USE_TRANSPORT_MODE:
+                                               this->mode = MODE_TRANSPORT;
+                                               break;
+                                       case USE_BEET_MODE:
+                                               this->mode = MODE_BEET;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               break;
+                       default:
+                               break;
+               }
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_child_create_t *this, message_t *message)
+{
+       host_t *me, *other, *vip;
+
+       switch (message->get_exchange_type(message))
+       {
+               case IKE_SA_INIT:
+                       return get_nonce(message, &this->my_nonce);
+               case CREATE_CHILD_SA:
+                       if (generate_nonce(&this->my_nonce) != SUCCESS)
+                       {
+                               message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+                               return SUCCESS;
+                       }
+                       break;
+               default:
+                       break;
+       }
+       
+       SIG(CHILD_UP_START, "establishing CHILD_SA");
+       
+       me = this->ike_sa->get_my_host(this->ike_sa);
+       other = this->ike_sa->get_other_host(this->ike_sa);
+       vip = this->policy->get_virtual_ip(this->policy, NULL);
+       
+       if (vip)
+       {       /* propose a 0.0.0.0/0 subnet when we use virtual ip */
+               this->tsi = this->policy->get_my_traffic_selectors(this->policy, NULL);
+               vip->destroy(vip);
+       }
+       else
+       {       /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
+               this->tsi = this->policy->get_my_traffic_selectors(this->policy, me);
+       }
+       this->tsr = this->policy->get_other_traffic_selectors(this->policy, other);
+       this->proposals = this->policy->get_proposals(this->policy);
+       this->mode = this->policy->get_mode(this->policy);
+       
+       this->child_sa = child_sa_create(me, other,
+                                                                        this->ike_sa->get_my_id(this->ike_sa),
+                                                                        this->ike_sa->get_other_id(this->ike_sa),
+                                                                        this->policy, this->reqid,
+                                                                        this->ike_sa->is_natt_enabled(this->ike_sa));
+       
+       if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
+       {
+               SIG(CHILD_UP_FAILED, "unable to allocate SPIs from kernel");
+               return FAILED;
+       }
+       
+       build_payloads(this, message);
+       
+       this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
+       this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
+       this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
+       this->tsi = NULL;
+       this->tsr = NULL;
+       this->proposals = NULL;
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_child_create_t *this, message_t *message)
+{
+       switch (message->get_exchange_type(message))
+       {
+               case IKE_SA_INIT:
+                       return get_nonce(message, &this->other_nonce);
+               case CREATE_CHILD_SA:
+                       get_nonce(message, &this->other_nonce);
+                       break;
+               default:
+                       break;
+       }
+
+       process_payloads(this, message);
+       
+       if (this->tsi == NULL || this->tsr == NULL)
+       {
+               DBG1(DBG_IKE, "TS payload missing in message");
+               return NEED_MORE;
+       }
+
+       this->policy = charon->policies->get_policy(charon->policies,
+                                                       this->ike_sa->get_my_id(this->ike_sa),
+                                                       this->ike_sa->get_other_id(this->ike_sa), 
+                                                       this->tsr, this->tsi,
+                                                       this->ike_sa->get_my_host(this->ike_sa),
+                                                       this->ike_sa->get_other_host(this->ike_sa));
+       
+       if (this->policy && this->ike_sa->get_policy(this->ike_sa) == NULL)
+       {
+               this->ike_sa->set_policy(this->ike_sa, this->policy);
+       }
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_child_create_t *this, message_t *message)
+{
+       switch (message->get_exchange_type(message))
+       {
+               case IKE_SA_INIT:
+                       return get_nonce(message, &this->my_nonce);
+               case CREATE_CHILD_SA:
+                       if (generate_nonce(&this->my_nonce) != SUCCESS)
+                       {
+                               message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+                               return SUCCESS;
+                       }
+                       break;
+               default:
+                       break;
+       }
+       
+       if (this->policy == NULL)
+       {
+               SIG(CHILD_UP_FAILED, "received traffic selectors inacceptable");
+               message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
+               return SUCCESS;
+       }
+       
+       this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
+                                                                        this->ike_sa->get_other_host(this->ike_sa),
+                                                                        this->ike_sa->get_my_id(this->ike_sa),
+                                                                        this->ike_sa->get_other_id(this->ike_sa),
+                                                                        this->policy, this->reqid,
+                                                                        this->ike_sa->is_natt_enabled(this->ike_sa));
+       
+       if (select_and_install(this) != SUCCESS)
+       {
+               message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+               return SUCCESS;
+       }
+       
+       build_payloads(this, message);
+       
+       SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
+
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_child_create_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+       status_t status;
+
+       switch (message->get_exchange_type(message))
+       {
+               case IKE_SA_INIT:
+                       return get_nonce(message, &this->other_nonce);
+               case CREATE_CHILD_SA:
+                       get_nonce(message, &this->other_nonce);
+                       break;
+               default:
+                       break;
+       }
+
+       /* check for erronous notifies */
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               if (payload->get_type(payload) == NOTIFY)
+               {
+                       notify_payload_t *notify = (notify_payload_t*)payload;
+                       notify_type_t type = notify->get_notify_type(notify);
+                       
+                       if (type < 16383)
+                       {
+                               SIG(CHILD_UP_FAILED, "received %N notify error",
+                                       notify_type_names, type);
+                               iterator->destroy(iterator);
+                               /* an error in CHILD_SA creation is not critical */
+                               return SUCCESS; 
+                       }
+               }
+       }
+       iterator->destroy(iterator);
+       
+       process_payloads(this, message);
+       
+       status = select_and_install(this);
+       
+       SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
+       
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_child_create_t *this)
+{
+       return CHILD_CREATE;
+}
+
+/**
+ * Implementation of child_create_t.use_reqid
+ */
+static void use_reqid(private_child_create_t *this, u_int32_t reqid)
+{
+       this->reqid = reqid;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
+{
+       chunk_free(&this->my_nonce);
+       chunk_free(&this->other_nonce);
+       if (this->tsi)
+       {
+               this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
+       }
+       if (this->tsr)
+       {
+               this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
+       }
+       DESTROY_IF(this->child_sa);
+       DESTROY_IF(this->proposal);
+       if (this->proposals)
+       {
+               this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
+       }
+       
+       this->ike_sa = ike_sa;
+       this->proposals = NULL;
+       this->tsi = NULL;
+       this->tsr = NULL;
+       this->child_sa = NULL;
+       this->mode = MODE_TUNNEL;
+       this->reqid = 0;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_child_create_t *this)
+{
+       chunk_free(&this->my_nonce);
+       chunk_free(&this->other_nonce);
+       if (this->tsi)
+       {
+               this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
+       }
+       if (this->tsr)
+       {
+               this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
+       }
+       DESTROY_IF(this->child_sa);
+       DESTROY_IF(this->proposal);
+       if (this->proposals)
+       {
+               this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
+       }
+       
+       DESTROY_IF(this->policy);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
+{
+       private_child_create_t *this = malloc_thing(private_child_create_t);
+
+       this->public.use_reqid = (void(*)(child_create_t*,u_int32_t))use_reqid;
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       if (policy)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+               this->initiator = TRUE;
+               policy->get_ref(policy);
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+               this->initiator = FALSE;
+       }
+       
+       this->ike_sa = ike_sa;
+       this->policy = policy;
+       this->my_nonce = chunk_empty;
+       this->other_nonce = chunk_empty;
+       this->proposals = NULL;
+       this->proposal = NULL;
+       this->tsi = NULL;
+       this->tsr = NULL;
+       this->child_sa = NULL;
+       this->mode = MODE_TUNNEL;
+       this->reqid = 0;
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h
new file mode 100644 (file)
index 0000000..1644865
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * @file child_create.h
+ * 
+ * @brief Interface child_create_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef CHILD_CREATE_H_
+#define CHILD_CREATE_H_
+
+typedef struct child_create_t child_create_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+#include <config/policies/policy.h>
+
+/**
+ * @brief Task of type CHILD_CREATE, established a new CHILD_SA.
+ *
+ * This task may be included in the IKE_AUTH message or in a separate 
+ * CREATE_CHILD_SA exchange.
+ *
+ * @b Constructors:
+ *  - child_create_create()
+ * 
+ * @ingroup tasks
+ */
+struct child_create_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+       
+       /**
+        * @brief Use a specific reqid for the CHILD_SA.
+        *
+        * When this task is used for rekeying, the same reqid is used
+        * for the new CHILD_SA. 
+        *
+        * @param this          calling object
+        * @param reqid         reqid to use
+        */
+       void (*use_reqid) (child_create_t *this, u_int32_t reqid);
+};
+
+/**
+ * @brief Create a new child_create task.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param policy               policy if task initiator, NULL if responder
+ * @return                             child_create task to handle by the task_manager
+ */
+child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy);
+
+#endif /* CHILD_CREATE_H_ */
diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c
new file mode 100644 (file)
index 0000000..875f14a
--- /dev/null
@@ -0,0 +1,264 @@
+/**
+ * @file child_delete.c
+ *
+ * @brief Implementation of the child_delete task.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "child_delete.h"
+
+#include <daemon.h>
+#include <encoding/payloads/delete_payload.h>
+
+
+typedef struct private_child_delete_t private_child_delete_t;
+
+/**
+ * Private members of a child_delete_t task.
+ */
+struct private_child_delete_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       child_delete_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * CHILD_SAs which get deleted
+        */
+       linked_list_t *child_sas;
+};
+
+/**
+ * build the delete payloads from the listed child_sas
+ */
+static void build_payloads(private_child_delete_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       delete_payload_t *ah = NULL, *esp = NULL;
+       u_int32_t spi;
+       child_sa_t *child_sa;
+       
+       iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+       while (iterator->iterate(iterator, (void**)&child_sa))
+       {       
+               spi = child_sa->get_spi(child_sa, TRUE);
+               switch (child_sa->get_protocol(child_sa))
+               {
+                       case PROTO_ESP:
+                               if (esp == NULL)
+                               {
+                                       esp = delete_payload_create(PROTO_ESP);
+                                       message->add_payload(message, (payload_t*)esp);
+                               }
+                               esp->add_spi(esp, spi);
+                               break;
+                       case PROTO_AH:
+                               if (ah == NULL)
+                               {
+                                       ah = delete_payload_create(PROTO_AH);
+                                       message->add_payload(message, (payload_t*)ah);
+                               }
+                               ah->add_spi(ah, spi);
+                               break;
+                       default:
+                               break;
+               }
+               child_sa->set_state(child_sa, CHILD_DELETING);
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * read in payloads and find the children to delete
+ */
+static void process_payloads(private_child_delete_t *this, message_t *message)
+{
+       iterator_t *payloads, *spis;
+       payload_t *payload;
+       delete_payload_t *delete_payload;
+       u_int32_t spi;
+       protocol_id_t protocol;
+       child_sa_t *child_sa;
+       
+       payloads = message->get_payload_iterator(message);
+       while (payloads->iterate(payloads, (void**)&payload))
+       {
+               if (payload->get_type(payload) == DELETE)
+               {
+                       delete_payload = (delete_payload_t*)payload;
+                       protocol = delete_payload->get_protocol_id(delete_payload);
+                       if (protocol != PROTO_ESP && protocol != PROTO_AH)
+                       {
+                               continue;
+                       }
+                       spis = delete_payload->create_spi_iterator(delete_payload);
+                       while (spis->iterate(spis, (void**)&spi))
+                       {
+                               child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
+                                                                                                         spi, FALSE);
+                               if (child_sa == NULL)
+                               {
+                                       DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, "
+                                                "but no such SA", protocol_id_names, protocol, ntohl(spi));
+                                       break;
+                               }
+                               
+                               if (child_sa->get_state(child_sa) == CHILD_REKEYING)
+                               {
+                                       /* TODO: handle rekeying */
+                               }
+                               
+                               this->child_sas->insert_last(this->child_sas, child_sa);
+                       }
+                       spis->destroy(spis);
+               }
+       }
+       payloads->destroy(payloads);
+}
+
+/**
+ * destroy the children listed in this->child_sas
+ */
+static void destroy_children(private_child_delete_t *this)
+{
+       iterator_t *iterator;
+       child_sa_t *child_sa;
+       protocol_id_t protocol;
+       u_int32_t spi;
+       
+       iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+       while (iterator->iterate(iterator, (void**)&child_sa))
+       {
+               /* TODO: can we do this more cleanly? */
+               spi = child_sa->get_spi(child_sa, TRUE);
+               protocol = child_sa->get_protocol(child_sa);
+               this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_child_delete_t *this, message_t *message)
+{
+       build_payloads(this, message);
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_child_delete_t *this, message_t *message)
+{
+       /* flush the list before adding new SAs */
+       this->child_sas->destroy(this->child_sas);
+       this->child_sas = linked_list_create();
+       
+       process_payloads(this, message);
+       destroy_children(this);
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_child_delete_t *this, message_t *message)
+{
+       process_payloads(this, message);
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_child_delete_t *this, message_t *message)
+{
+       build_payloads(this, message);
+       destroy_children(this);
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_child_delete_t *this)
+{
+       return CHILD_DELETE;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_child_delete_t *this, ike_sa_t *ike_sa)
+{
+       this->ike_sa = ike_sa;
+       
+       this->child_sas->destroy(this->child_sas);
+       this->child_sas = linked_list_create();
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_child_delete_t *this)
+{
+       this->child_sas->destroy(this->child_sas);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
+{
+       private_child_delete_t *this = malloc_thing(private_child_delete_t);
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       
+       this->ike_sa = ike_sa;
+       this->child_sas = linked_list_create();
+       
+       if (child_sa != NULL)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+               this->initiator = TRUE;
+               this->child_sas->insert_last(this->child_sas, child_sa);
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+               this->initiator = FALSE;
+       }
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/child_delete.h b/src/charon/sa/tasks/child_delete.h
new file mode 100644 (file)
index 0000000..327a2ec
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * @file child_delete.h
+ * 
+ * @brief Interface child_delete_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef CHILD_DELETE_H_
+#define CHILD_DELETE_H_
+
+typedef struct child_delete_t child_delete_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+#include <sa/child_sa.h>
+
+/**
+ * @brief Task of type child_delete, delete a CHILD_SA.
+ *
+ * @b Constructors:
+ *  - child_delete_create()
+ * 
+ * @ingroup tasks
+ */
+struct child_delete_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new child_delete task.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param child_sa             CHILD_SA to delete, or NULL as responder
+ * @return                             child_delete task to handle by the task_manager
+ */
+child_delete_t *child_delete_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
+
+#endif /* CHILD_DELETE_H_ */
diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c
new file mode 100644 (file)
index 0000000..41533b6
--- /dev/null
@@ -0,0 +1,353 @@
+/**
+ * @file child_rekey.c
+ *
+ * @brief Implementation of the child_rekey task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "child_rekey.h"
+
+#include <daemon.h>
+#include <crypto/diffie_hellman.h>
+#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <sa/tasks/child_create.h>
+
+
+typedef struct private_child_rekey_t private_child_rekey_t;
+
+/**
+ * Private members of a child_rekey_t task.
+ */
+struct private_child_rekey_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       child_rekey_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * the CHILD_CREATE task which is reused to simplify rekeying
+        */
+       child_create_t *child_create;
+       
+       /**
+        * CHILD_SA which gets rekeyed
+        */
+       child_sa_t *child_sa;
+       
+       /**
+        * redundandt CHILD_SA created simultaneously
+        */
+       child_sa_t *simultaneous;
+       
+       /**
+        * the lowest nonce compared so far
+        */
+       chunk_t nonce;
+       
+       /**
+        * TRUE if we have the lower nonce
+        */
+       bool winner;
+};
+
+/**
+ * get the nonce from a message, return TRUE if it was lower than this->nonce
+ */
+static bool get_nonce(private_child_rekey_t *this, message_t *message)
+{
+       nonce_payload_t *payload;
+       chunk_t nonce;
+       
+       payload = (nonce_payload_t*)message->get_payload(message, NONCE);
+       if (payload == NULL)
+       {
+               return FALSE;
+       }
+       nonce = payload->get_nonce(payload);
+       
+       if (this->nonce.ptr && memcmp(nonce.ptr, this->nonce.ptr,
+                                                                 min(nonce.len, this->nonce.len)) > 0)
+       {
+               chunk_free(&nonce);
+               return FALSE;
+       }
+       
+       chunk_free(&this->nonce);
+       this->nonce = nonce;
+       return TRUE;
+}
+
+/**
+ * find a child using the REKEY_SA notify
+ */
+static void find_child(private_child_rekey_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+       
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               notify_payload_t *notify;
+               u_int32_t spi;
+               protocol_id_t protocol;
+               
+               if (payload->get_type(payload) != NOTIFY)
+               {
+                       continue;
+               }
+               
+               notify = (notify_payload_t*)payload;
+               protocol = notify->get_protocol_id(notify);
+               spi = notify->get_spi(notify);
+               
+               if (protocol != PROTO_ESP && protocol != PROTO_AH)
+               {
+                       continue;
+               }
+               this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
+                                                                                                       spi, FALSE);
+               break;
+                       
+       }
+       iterator->destroy(iterator);
+}
+
+#if 0
+/**
+ * handle a detected simultaneous rekeying situation as responder
+ */
+static void simultaneous_r(private_child_rekey_t *this, message_t *message)
+{
+       private_child_rekey_t *other = NULL;
+       task_t *task;
+       iterator_t *iterator;
+       
+       this->ike_sa->create_task_iterator(this->ike_sa);
+       while (iterator->iterate(iterator, (void**)&task))
+       {
+               if (task->get_type(task) == CHILD_REKEY)
+               {
+                       other = (private_child_rekey_t*)task;
+                       break;
+               }
+       }
+       iterator->destroy(iterator);
+       
+       if (other)
+       {
+               other->simultaneous = this->child_create->get_child(this->child_create);
+       
+               if (!get_nonce(other, message))
+               {
+                       /* this wins the race, other lost */
+                       other->winner = FALSE;
+               }
+       }
+}
+
+/**
+ * was there a simultaneous rekeying, did we win the nonce compare?
+ */
+static bool simultaneous_i(private_child_rekey_t *this, message_t *message)
+{
+       if (this->winner || get_nonce(this, message))
+       {
+               /* we have the lower nonce and win */
+               return TRUE;
+       }
+       return FALSE;
+}
+#endif
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_child_rekey_t *this, message_t *message)
+{      
+       notify_payload_t *notify;
+       protocol_id_t protocol;
+       u_int32_t spi, reqid;
+
+       /* our CHILD_CREATE task does the hard work for us... */
+       reqid = this->child_sa->get_reqid(this->child_sa);
+       this->child_create->use_reqid(this->child_create, reqid);
+       this->child_create->task.build(&this->child_create->task, message);
+       get_nonce(this, message);
+       
+       /* ... we just need the rekey notify */
+       protocol = this->child_sa->get_protocol(this->child_sa);
+       spi = this->child_sa->get_spi(this->child_sa, TRUE);
+       notify = notify_payload_create_from_protocol_and_type(protocol, REKEY_SA);
+       notify->set_spi(notify, spi);
+       message->add_payload(message, (payload_t*)notify);
+       
+       this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
+
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_child_rekey_t *this, message_t *message)
+{
+       /* let the CHILD_CREATE task process the message */
+       this->child_create->task.process(&this->child_create->task, message);
+       get_nonce(this, message);
+
+       find_child(this, message);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_child_rekey_t *this, message_t *message)
+{
+       u_int32_t reqid;
+
+       if (this->child_sa == NULL ||
+               this->child_sa->get_state(this->child_sa) == CHILD_DELETING)
+       {
+               message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
+               return SUCCESS;
+       }
+       
+       /* let the CHILD_CREATE task build the response */
+       reqid = this->child_sa->get_reqid(this->child_sa);
+       this->child_create->use_reqid(this->child_create, reqid);
+       this->child_create->task.build(&this->child_create->task, message);
+       get_nonce(this, message);
+
+       if (this->child_sa->get_state(this->child_sa) == CHILD_REKEYING)
+       {
+               /* simultaneous_detected(this); */
+       }
+       
+       this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
+       
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_child_rekey_t *this, message_t *message)
+{
+       protocol_id_t protocol;
+       u_int32_t spi;
+       
+       this->child_create->task.process(&this->child_create->task, message);
+       
+       /*if (!simultaneous_won(this, message))
+       {
+               * delete the redundant CHILD_SA, instead of the rekeyed *
+               this->child_sa = this->create_child->get_child(this->create_child);
+       }*/
+       spi = this->child_sa->get_spi(this->child_sa, TRUE);
+       protocol = this->child_sa->get_protocol(this->child_sa);
+       
+       /* TODO: don't delete when rekeying failed */
+       if (this->ike_sa->delete_child_sa(this->ike_sa, protocol, spi) != SUCCESS)
+       {
+               return FAILED;
+       }
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_child_rekey_t *this)
+{
+       return CHILD_REKEY;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_child_rekey_t *this, ike_sa_t *ike_sa)
+{      
+       this->child_create->task.migrate(&this->child_create->task, ike_sa);
+       chunk_free(&this->nonce);
+
+       this->ike_sa = ike_sa;
+       this->winner = TRUE;
+       this->simultaneous = NULL;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_child_rekey_t *this)
+{
+       this->child_create->task.destroy(&this->child_create->task);
+       chunk_free(&this->nonce);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
+{
+       private_child_rekey_t *this = malloc_thing(private_child_rekey_t);
+       policy_t *policy;
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       if (child_sa != NULL)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+               this->initiator = TRUE;
+               policy = child_sa->get_policy(child_sa);
+               this->child_create = child_create_create(ike_sa, policy);
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+               this->initiator = FALSE;
+               this->child_create = child_create_create(ike_sa, NULL);
+       }
+       
+       this->ike_sa = ike_sa;
+       this->child_sa = child_sa;
+       this->nonce = chunk_empty;
+       this->winner = TRUE;
+       this->simultaneous = NULL;
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/child_rekey.h b/src/charon/sa/tasks/child_rekey.h
new file mode 100644 (file)
index 0000000..77297b1
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * @file child_rekey.h
+ * 
+ * @brief Interface child_rekey_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef CHILD_REKEY_H_
+#define CHILD_REKEY_H_
+
+typedef struct child_rekey_t child_rekey_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/child_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type CHILD_REKEY, rekey an established CHILD_SA.
+ *
+ * @b Constructors:
+ *  - child_rekey_create()
+ * 
+ * @ingroup tasks
+ */
+struct child_rekey_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new CHILD_REKEY task.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param child_sa             child_sa to rekey, NULL if responder
+ * @return                             child_rekey task to handle by the task_manager
+ */
+child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa);
+
+#endif /* CHILD_REKEY_H_ */
diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c
new file mode 100644 (file)
index 0000000..2e54b77
--- /dev/null
@@ -0,0 +1,513 @@
+/**
+ * @file ike_auth.c
+ *
+ * @brief Implementation of the ike_auth task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "ike_auth.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <crypto/diffie_hellman.h>
+#include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+
+
+typedef struct private_ike_auth_t private_ike_auth_t;
+
+/**
+ * Private members of a ike_auth_t task.
+ */
+struct private_ike_auth_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       ike_auth_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * Nonce chosen by us in ike_init
+        */
+       chunk_t my_nonce;
+       
+       /**
+        * Nonce chosen by peer in ike_init
+        */
+       chunk_t other_nonce;
+       
+       /**
+        * IKE_SA_INIT message sent by us
+        */
+       packet_t *my_packet;
+       
+       /**
+        * IKE_SA_INIT message sent by peer
+        */
+       packet_t *other_packet;
+       
+       /**
+        * authenticator to authenticate us
+        */
+       authenticator_t *my_auth;
+       
+       /**
+        * authenticator to authenticate peer
+        */
+       authenticator_t *other_auth;
+       
+       /**
+        * has the peer been authenticated successfully?
+        */
+       bool peer_authenticated;
+};
+
+/**
+ * build the payloads for the message
+ */
+static status_t build_payloads(private_ike_auth_t *this, message_t *message)
+{
+       authenticator_t *auth;
+       auth_payload_t *auth_payload;
+       id_payload_t *id_payload;
+       chunk_t ike_sa_init;
+       identification_t *me, *other;
+       policy_t *policy;
+       auth_method_t method = AUTH_RSA;
+       status_t status;
+       
+       /* add own ID payload */
+       me = this->ike_sa->get_my_id(this->ike_sa);
+       other = this->ike_sa->get_other_id(this->ike_sa);
+       
+       id_payload = id_payload_create_from_identification(this->initiator, me);
+       message->add_payload(message, (payload_t*)id_payload);
+       
+       /* as initiator, include other ID if it does not contain wildcards */
+       if (this->initiator && !other->contains_wildcards(other))
+       {
+               id_payload = id_payload_create_from_identification(FALSE, other);
+               message->add_payload(message, (payload_t*)id_payload);
+       }
+       
+       /* create own authenticator and add auth payload */
+       policy = this->ike_sa->get_policy(this->ike_sa);
+       if (policy)
+       {
+               method = policy->get_auth_method(policy);
+       }
+       auth = authenticator_create(this->ike_sa, method);
+       if (auth == NULL)
+       {
+               SIG(IKE_UP_FAILED, "configured authentication method %N not supported",
+                        auth_method_names, method);
+               return FAILED;
+       }
+       
+       ike_sa_init = this->my_packet->get_data(this->my_packet);
+       status = auth->build(auth, ike_sa_init, this->other_nonce, &auth_payload);
+       auth->destroy(auth);
+       if (status != SUCCESS)
+       {
+               SIG(IKE_UP_FAILED, "generating authentication data failed");
+               return FAILED;
+       }
+       message->add_payload(message, (payload_t*)auth_payload);
+       
+       return SUCCESS;
+}
+
+/**
+ * process payloads from message
+ */
+static void process_payloads(private_ike_auth_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+       payload_type_t type;
+       identification_t *idi = NULL, *idr = NULL;
+       auth_payload_t *auth_payload = NULL;
+       authenticator_t *auth;
+       auth_method_t auth_method;
+       status_t status;
+
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               type = payload->get_type(payload);
+               switch (type)
+               {
+                       case ID_INITIATOR:
+                       {
+                               id_payload_t *id_payload = (id_payload_t*)payload;
+                               idi = id_payload->get_identification(id_payload);
+                               break;                  
+                       }
+                       case ID_RESPONDER:
+                       {
+                               id_payload_t *id_payload = (id_payload_t*)payload;
+                               idr = id_payload->get_identification(id_payload);
+                               break;                  
+                       }
+                       case AUTHENTICATION:
+                       {
+                               auth_payload = (auth_payload_t*)payload;
+                               break;
+                       }
+                       default:
+                               break;
+               }
+       }
+       iterator->destroy(iterator);
+       
+       /* apply IDs */
+       if ((this->initiator && idr == NULL) || (!this->initiator && idi == NULL))
+       {
+               SIG(IKE_UP_FAILED, "ID payload missing in message");
+               DESTROY_IF(idr); DESTROY_IF(idi);
+               return;
+       }
+       
+       if (this->initiator)
+       {
+               identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa);
+               if (!idr->matches(idr, other_id, NULL))
+               {
+                       SIG(IKE_UP_FAILED, "received inacceptable id %D, %D required", idr, 
+                               this->ike_sa->get_other_id(this->ike_sa));
+                       DESTROY_IF(idi); DESTROY_IF(idr);
+                       return;
+               }
+               this->ike_sa->set_other_id(this->ike_sa, idr);
+       }
+       else
+       {
+               identification_t *my_id = this->ike_sa->get_other_id(this->ike_sa);
+               if (idr)
+               {
+                       if (!idr->matches(idr, my_id, NULL))
+                       {
+                               SIG(IKE_UP_FAILED, "received inacceptable id %D, %D required",
+                                       idr, this->ike_sa->get_other_id(this->ike_sa));
+                               DESTROY_IF(idi); DESTROY_IF(idr);
+                               return;
+                       }
+                       this->ike_sa->set_my_id(this->ike_sa, idr);
+               }
+               else
+               {
+                       if (my_id->contains_wildcards(my_id))
+                       {
+                               SIG(IKE_UP_FAILED, "own ID (%D) not defined after exchange",
+                                       my_id);
+                               DESTROY_IF(idi);
+                               return;
+                       }
+               }
+               this->ike_sa->set_other_id(this->ike_sa, idi);
+       }
+       
+       /* verify auth payload */
+       if (auth_payload == NULL)
+       {
+               SIG(IKE_UP_FAILED, "AUTH payload missing in message");
+               return;
+       }
+               
+       auth_method = auth_payload->get_auth_method(auth_payload);
+       auth = authenticator_create(this->ike_sa, auth_method);
+       if (auth == NULL)
+       {
+               SIG(IKE_UP_FAILED, "authentication method %N used by %D not "
+                       "supported", auth_method_names, auth_method,
+                       this->ike_sa->get_other_id(this->ike_sa));
+               return;
+       }
+       status = auth->verify(auth, this->other_packet->get_data(this->other_packet), 
+                                                 this->my_nonce, auth_payload);
+       auth->destroy(auth);
+       if (status != SUCCESS)
+       {
+               SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+                        this->ike_sa->get_other_id(this->ike_sa), 
+                        auth_method_names, auth_method);       
+               return;
+       }
+       this->peer_authenticated = TRUE;
+}
+
+/**
+ * collect the needed information in the IKE_SA_INIT exchange from our message
+ */
+static status_t collect_my_init_data(private_ike_auth_t *this, message_t *message)
+{
+       nonce_payload_t *nonce;
+       
+       /* get the nonce that was generated in ike_init */
+       nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
+       if (nonce == NULL)
+       {
+               return FAILED;
+       }
+       this->my_nonce = nonce->get_nonce(nonce);
+       
+       /* pre-generate the message, so we can store it for us */
+       if (this->ike_sa->generate_message(this->ike_sa, message,
+                                                                          &this->my_packet) != SUCCESS)
+       {
+               return FAILED;
+       }
+       return NEED_MORE; 
+}
+
+/**
+ * collect the needed information in the IKE_SA_INIT exchange from others message
+ */
+static status_t collect_other_init_data(private_ike_auth_t *this, message_t *message)
+{
+       /* we collect the needed information in the IKE_SA_INIT exchange */
+       nonce_payload_t *nonce;
+       
+       /* get the nonce that was generated in ike_init */
+       nonce = (nonce_payload_t*)message->get_payload(message, NONCE);
+       if (nonce == NULL)
+       {
+               return FAILED;
+       }
+       this->other_nonce = nonce->get_nonce(nonce);
+       
+       /* pre-generate the message, so we can store it for us */
+       this->other_packet = message->get_packet(message);
+       return NEED_MORE; 
+}
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_ike_auth_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) == IKE_SA_INIT)
+       {
+               return collect_my_init_data(this, message);
+       }
+       
+       if (build_payloads(this, message) == SUCCESS)
+       {
+               return NEED_MORE;
+       }
+       return FAILED;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_ike_auth_t *this, message_t *message)
+{      
+       if (message->get_exchange_type(message) == IKE_SA_INIT)
+       {
+               return collect_other_init_data(this, message);
+       }
+       
+       process_payloads(this, message);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_auth_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) == IKE_SA_INIT)
+       {
+               return collect_my_init_data(this, message);
+       }
+       
+       if (!this->peer_authenticated)
+       {
+               message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
+               return FAILED;
+       }
+
+       if (build_payloads(this, message) == SUCCESS)
+       {
+               this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+               SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
+                       this->ike_sa->get_my_id(this->ike_sa), 
+                       this->ike_sa->get_my_host(this->ike_sa),
+                       this->ike_sa->get_other_host(this->ike_sa),
+                       this->ike_sa->get_other_id(this->ike_sa));
+               return SUCCESS;
+       }
+       return FAILED;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_auth_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+       
+       if (message->get_exchange_type(message) == IKE_SA_INIT)
+       {
+               return collect_other_init_data(this, message);
+       }
+       
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               if (payload->get_type(payload) == NOTIFY)
+               {
+                       notify_payload_t *notify = (notify_payload_t*)payload;
+                       notify_type_t type = notify->get_notify_type(notify);
+                       
+                       switch (type)
+                       {
+                               case NO_PROPOSAL_CHOSEN:
+                               case SINGLE_PAIR_REQUIRED:
+                               case NO_ADDITIONAL_SAS:
+                               case INTERNAL_ADDRESS_FAILURE:
+                               case FAILED_CP_REQUIRED:
+                               case TS_UNACCEPTABLE:
+                               case INVALID_SELECTORS:
+                                       /* these are errors, but are not critical as only the
+                                        * CHILD_SA won't get build, but IKE_SA establishes anyway */
+                                       DBG1(DBG_IKE, "received %N notify, no CHILD_SA built",
+                                                notify_type_names, type);
+                                       iterator->destroy(iterator);
+                                       return SUCCESS; 
+                               default:
+                               {
+                                       if (type < 16383)
+                                       {
+                                               DBG1(DBG_IKE, "received %N notify error",
+                                                        notify_type_names, type);
+                                               iterator->destroy(iterator);
+                                               return FAILED;  
+                                       }
+                               }
+                       }
+               }
+       }
+       iterator->destroy(iterator);
+       
+       process_payloads(this, message);
+
+       if (this->peer_authenticated)
+       {
+               this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+               SIG(IKE_UP_SUCCESS, "IKE_SA established between %D[%H]...[%H]%D",
+                       this->ike_sa->get_my_id(this->ike_sa), 
+                       this->ike_sa->get_my_host(this->ike_sa),
+                       this->ike_sa->get_other_host(this->ike_sa),
+                       this->ike_sa->get_other_id(this->ike_sa));
+               return SUCCESS;
+       }
+       return FAILED;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_auth_t *this)
+{
+       return IKE_AUTHENTICATE;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_auth_t *this, ike_sa_t *ike_sa)
+{
+       chunk_free(&this->my_nonce);
+       chunk_free(&this->other_nonce);
+       DESTROY_IF(this->my_packet);
+       DESTROY_IF(this->other_packet);
+       DESTROY_IF(this->my_auth);
+       DESTROY_IF(this->other_auth);
+       this->my_packet = NULL;
+       this->other_packet = NULL;
+       this->my_auth = NULL;
+       this->other_auth = NULL;
+       this->peer_authenticated = FALSE;
+       this->ike_sa = ike_sa;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_auth_t *this)
+{
+       chunk_free(&this->my_nonce);
+       chunk_free(&this->other_nonce);
+       DESTROY_IF(this->my_packet);
+       DESTROY_IF(this->other_packet);
+       DESTROY_IF(this->my_auth);
+       DESTROY_IF(this->other_auth);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator)
+{
+       private_ike_auth_t *this = malloc_thing(private_ike_auth_t);
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       
+       if (initiator)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+       }
+       
+       this->ike_sa = ike_sa;
+       this->initiator = initiator;
+       this->my_nonce = chunk_empty;
+       this->other_nonce = chunk_empty;
+       this->my_packet = NULL;
+       this->other_packet = NULL;
+       this->my_auth = NULL;
+       this->other_auth = NULL;
+       this->peer_authenticated = FALSE;
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_auth.h b/src/charon/sa/tasks/ike_auth.h
new file mode 100644 (file)
index 0000000..e59e681
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * @file ike_auth.h
+ * 
+ * @brief Interface ike_auth_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef IKE_AUTH_H_
+#define IKE_AUTH_H_
+
+typedef struct ike_auth_t ike_auth_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_auth, authenticates an IKE_SA authenticators.
+ *
+ * The ike_auth task authenticates the IKE_SA using the IKE_AUTH
+ * exchange. 
+ *
+ * @b Constructors:
+ *  - ike_auth_create()
+ * 
+ * @ingroup tasks
+ */
+struct ike_auth_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new task of type IKE_AUTHENTICATE.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param initiator            TRUE if thask is the initator of an exchange
+ * @return                       ike_auth task to handle by the task_manager
+ */
+ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_AUTH_H_ */
diff --git a/src/charon/sa/tasks/ike_cert.c b/src/charon/sa/tasks/ike_cert.c
new file mode 100644 (file)
index 0000000..3cddc00
--- /dev/null
@@ -0,0 +1,361 @@
+/**
+ * @file ike_cert.c
+ *
+ * @brief Implementation of the ike_cert task.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "ike_cert.h"
+
+#include <daemon.h>
+#include <sa/ike_sa.h>
+#include <crypto/hashers/hasher.h>
+#include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/certreq_payload.h>
+
+
+typedef struct private_ike_cert_t private_ike_cert_t;
+
+/**
+ * Private members of a ike_cert_t task.
+ */
+struct private_ike_cert_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       ike_cert_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * list of CA cert hashes requested, items point to 20 byte chunk
+        */
+       linked_list_t *cas;
+};
+
+/**
+ * read certificate requests 
+ */
+static void process_certreqs(private_ike_cert_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+       
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               if (payload->get_type(payload) == CERTIFICATE_REQUEST)
+               {
+                       certreq_payload_t *certreq = (certreq_payload_t*)payload;
+                       cert_encoding_t encoding;
+                       chunk_t keyids, keyid;
+                       
+                       encoding =  certreq->get_cert_encoding(certreq);
+                       if (encoding != CERT_X509_SIGNATURE)
+                       {
+                               DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
+                                        cert_encoding_names, encoding);
+                               continue;
+                       }
+
+                       keyids = certreq->get_data(certreq);
+                                       
+                       while (keyids.len >= HASH_SIZE_SHA1)
+                       {
+                               keyid = chunk_create(keyids.ptr, HASH_SIZE_SHA1);
+                               keyid = chunk_clone(keyid);
+                               this->cas->insert_last(this->cas, keyid.ptr);
+                               keyids = chunk_skip(keyids, HASH_SIZE_SHA1);
+                       }
+               }
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * import certificates
+ */
+static void process_certs(private_ike_cert_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+       
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               if (payload->get_type(payload) == CERTIFICATE)
+               {
+                       cert_encoding_t encoding;
+                       x509_t *cert;
+                       chunk_t cert_data;
+                       bool found;
+                       cert_payload_t *cert_payload = (cert_payload_t*)payload;
+                       
+                       encoding = cert_payload->get_cert_encoding(cert_payload);
+                       if (encoding != CERT_X509_SIGNATURE)
+                       {
+                               DBG1(DBG_IKE, "certificate payload %N not supported, ignored",
+                                        cert_encoding_names, encoding);
+                               continue;
+                       }
+                       
+                       cert_data = cert_payload->get_data_clone(cert_payload);
+                       cert = x509_create_from_chunk(cert_data);
+                       if (cert)
+                       {
+                               if (charon->credentials->verify(charon->credentials,
+                                                                                               cert, &found))
+                               {
+                                       DBG2(DBG_IKE, "received end entity certificate is trusted, "
+                                                "added to store");
+                                       if (!found)
+                                       {
+                                               charon->credentials->add_end_certificate(
+                                                                                                       charon->credentials, cert);
+                                       }
+                                       else
+                                       {
+                                               cert->destroy(cert);
+                                       }
+                               }
+                               else
+                               {
+                                       DBG1(DBG_IKE, "received end entity certificate is not "
+                                                "trusted, discarded");
+                                       cert->destroy(cert);
+                               }
+                       }
+                       else
+                       {
+                               DBG1(DBG_IKE, "parsing of received certificate failed, discarded");
+                               chunk_free(&cert_data);
+                       }
+               }
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * build certificate requests
+ */
+static void build_certreqs(private_ike_cert_t *this, message_t *message)
+{
+       connection_t *connection;
+       policy_t *policy;
+       identification_t *ca;
+       certreq_payload_t *certreq;
+       
+       connection = this->ike_sa->get_connection(this->ike_sa);
+       
+       if (connection->get_certreq_policy(connection) != CERT_NEVER_SEND)
+       {       
+               policy = this->ike_sa->get_policy(this->ike_sa);
+               
+               if (policy)
+               {
+                       ca = policy->get_other_ca(policy);
+                       
+                       if (ca && ca->get_type(ca) != ID_ANY)
+                       {
+                               certreq = certreq_payload_create_from_cacert(ca);
+                       }
+                       else
+                       {
+                               certreq = certreq_payload_create_from_cacerts();
+                       }
+               }
+               else
+               {
+                       certreq = certreq_payload_create_from_cacerts();
+               }
+               
+               if (certreq)
+               {
+                       message->add_payload(message, (payload_t*)certreq);
+               }
+       }
+}
+
+/**
+ * add certificates to message
+ */
+static void build_certs(private_ike_cert_t *this, message_t *message)
+{
+       policy_t *policy;
+       connection_t *connection;
+       x509_t *cert;
+       cert_payload_t *payload;
+       
+       policy = this->ike_sa->get_policy(this->ike_sa);
+       connection = this->ike_sa->get_connection(this->ike_sa);
+
+       if (policy && policy->get_auth_method(policy) == AUTH_RSA)
+       {
+               switch (connection->get_cert_policy(connection))
+               {
+                       case CERT_NEVER_SEND:
+                               break;
+                       case CERT_SEND_IF_ASKED:
+                               if (this->cas->get_count(this->cas) == 0)
+                               {
+                                       break;
+                               }
+                               /* FALL */
+                       case CERT_ALWAYS_SEND:
+                       {
+                               /* TODO: respect CA cert request */
+                               cert = charon->credentials->get_certificate(charon->credentials,
+                                                                                                       policy->get_my_id(policy));
+                               if (cert)
+                               {
+                                       payload = cert_payload_create_from_x509(cert);
+                                       message->add_payload(message, (payload_t*)payload);
+                               }
+                       }       
+               }
+       }
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_cert_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) == IKE_SA_INIT)
+       {
+               return NEED_MORE;
+       }
+               
+       build_certreqs(this, message);
+       build_certs(this, message);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_cert_t *this, message_t *message)
+{      
+       if (message->get_exchange_type(message) == IKE_SA_INIT)
+       {
+               return NEED_MORE;
+       }
+       
+       process_certreqs(this, message);
+       process_certs(this, message);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_cert_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) == IKE_SA_INIT)
+       {
+               build_certreqs(this, message);
+               return NEED_MORE;
+       }
+       
+       build_certs(this, message);
+       
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_cert_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) == IKE_SA_INIT)
+       {
+               process_certreqs(this, message);
+               return NEED_MORE;
+       }
+       
+       process_certs(this, message);
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_cert_t *this)
+{
+       return IKE_CERT;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_cert_t *this, ike_sa_t *ike_sa)
+{
+       this->ike_sa = ike_sa;
+       
+       this->cas->destroy_function(this->cas, free);
+       this->cas = linked_list_create();
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_cert_t *this)
+{
+       this->cas->destroy_function(this->cas, free);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator)
+{
+       private_ike_cert_t *this = malloc_thing(private_ike_cert_t);
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       
+       if (initiator)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+       }
+       
+       this->ike_sa = ike_sa;
+       this->initiator = initiator;
+       this->cas = linked_list_create();
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_cert.h b/src/charon/sa/tasks/ike_cert.h
new file mode 100644 (file)
index 0000000..ba02839
--- /dev/null
@@ -0,0 +1,61 @@
+/**
+ * @file ike_cert.h
+ * 
+ * @brief Interface ike_cert_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef IKE_CERT_H_
+#define IKE_CERT_H_
+
+typedef struct ike_cert_t ike_cert_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_cert, exchanges certificates and 
+ * certificate requests.
+ *
+ * @b Constructors:
+ *  - ike_cert_create()
+ * 
+ * @ingroup tasks
+ */
+struct ike_cert_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new ike_cert task.
+ *
+ * The initiator parameter means the original initiator, not the initiator
+ * of the certificate request.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param initiator            TRUE if thask is the original initator
+ * @return                             ike_cert task to handle by the task_manager
+ */
+ike_cert_t *ike_cert_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_CERT_H_ */
diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c
new file mode 100644 (file)
index 0000000..b6e883b
--- /dev/null
@@ -0,0 +1,421 @@
+/**
+ * @file ike_config.c
+ *
+ * @brief Implementation of the ike_config task.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "ike_config.h"
+
+#include <daemon.h>
+#include <encoding/payloads/cp_payload.h>
+
+typedef struct private_ike_config_t private_ike_config_t;
+
+/**
+ * Private members of a ike_config_t task.
+ */
+struct private_ike_config_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       ike_config_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * associated policy with virtual IP configuration
+        */
+       policy_t *policy;
+       
+       /**
+        * virtual ip
+        */
+       host_t *virtual_ip;
+       
+       /**
+        * list of DNS servers
+        */
+       linked_list_t *dns;
+};
+
+/**
+ * build configuration payloads and attributes
+ */
+static void build_payloads(private_ike_config_t *this, message_t *message,
+                                                  config_type_t type)
+{
+       cp_payload_t *cp;
+       configuration_attribute_t *ca;
+       chunk_t chunk, prefix;
+       
+       if (!this->virtual_ip)
+       {
+               return;
+       }
+
+       cp = cp_payload_create();
+       cp->set_config_type(cp, type);
+
+       ca = configuration_attribute_create();
+       
+       if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
+       {
+               ca->set_type(ca, INTERNAL_IP4_ADDRESS);
+               if (this->virtual_ip->is_anyaddr(this->virtual_ip))
+               {
+                       chunk = chunk_empty;
+               }
+               else
+               {
+                       chunk = this->virtual_ip->get_address(this->virtual_ip);
+               }
+       }
+       else
+       {
+               ca->set_type(ca, INTERNAL_IP6_ADDRESS);
+               if (this->virtual_ip->is_anyaddr(this->virtual_ip))
+               {
+                       chunk = chunk_empty;
+               }
+               else
+               {
+                       prefix = chunk_alloca(1);
+                       *prefix.ptr = 64;
+                       chunk = this->virtual_ip->get_address(this->virtual_ip);
+                       chunk = chunk_cata("cc", chunk, prefix);
+               }
+       }
+       ca->set_value(ca, chunk);
+       cp->add_configuration_attribute(cp, ca);
+       
+       /* we currently always add a DNS request if we request an IP */
+       if (this->initiator)
+       {
+               ca = configuration_attribute_create();
+               if (this->virtual_ip->get_family(this->virtual_ip) == AF_INET)
+               {
+                       ca->set_type(ca, INTERNAL_IP4_DNS);
+               }
+               else
+               {
+                       ca->set_type(ca, INTERNAL_IP6_DNS);
+               }
+               cp->add_configuration_attribute(cp, ca);
+       }
+       else
+       {
+               host_t *ip;
+               iterator_t *iterator = this->dns->create_iterator(this->dns, TRUE);
+               while (iterator->iterate(iterator, (void**)&ip))
+               {
+                       ca = configuration_attribute_create();
+                       if (ip->get_family(ip) == AF_INET)
+                       {
+                               ca->set_type(ca, INTERNAL_IP4_DNS);
+                       }
+                       else
+                       {
+                               ca->set_type(ca, INTERNAL_IP6_DNS);
+                       }
+                       chunk = ip->get_address(ip);
+                       ca->set_value(ca, chunk);
+                       cp->add_configuration_attribute(cp, ca);
+               }
+               iterator->destroy(iterator);
+       }
+       message->add_payload(message, (payload_t*)cp);
+}
+
+/**
+ * process a single configuration attribute
+ */
+static void process_attribute(private_ike_config_t *this,
+                                                         configuration_attribute_t *ca)
+{
+       host_t *ip;
+       chunk_t addr;
+       int family = AF_INET6;
+       
+       switch (ca->get_type(ca))
+       {
+               case INTERNAL_IP4_ADDRESS:
+                       family = AF_INET;
+                       /* fall */
+               case INTERNAL_IP6_ADDRESS:
+               {
+                       addr = ca->get_value(ca);
+                       if (addr.len == 0)
+                       {
+                               ip = host_create_any(family);
+                       }
+                       else
+                       {
+                               /* skip prefix byte in IPv6 payload*/
+                               if (family == AF_INET6)
+                               {
+                                       addr.len--; 
+                               }
+                               ip = host_create_from_chunk(family, addr, 0);
+                       }
+                       if (ip && !this->virtual_ip)
+                       {
+                               this->virtual_ip = ip;
+                       }
+                       break;
+               }
+               case INTERNAL_IP4_DNS:
+                       family = AF_INET;
+                       /* fall */
+               case INTERNAL_IP6_DNS:
+               {
+                       addr = ca->get_value(ca);
+                       if (addr.len == 0)
+                       {
+                               ip = host_create_any(family);
+                       }
+                       else
+                       {
+                               ip = host_create_from_chunk(family, addr, 0);
+                       }
+                       if (ip)
+                       {
+                               this->dns->insert_last(this->dns, ip);
+                       }
+                       break;
+               }
+               case INTERNAL_IP4_NBNS:
+               case INTERNAL_IP6_NBNS:
+                       /* TODO */
+               default:
+                       DBG1(DBG_IKE, "ignoring %N config attribute", 
+                                configuration_attribute_type_names,
+                                ca->get_type(ca));
+                       break;
+       }
+}
+
+/**
+ * Scan for configuration payloads and attributes
+ */
+static void process_payloads(private_ike_config_t *this, message_t *message)
+{
+       iterator_t *iterator, *attributes;
+       payload_t *payload;
+       
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               if (payload->get_type(payload) == CONFIGURATION)
+               {
+                       cp_payload_t *cp = (cp_payload_t*)payload;
+                       configuration_attribute_t *ca;
+                       switch (cp->get_config_type(cp))
+                       {
+                               case CFG_REQUEST:
+                               case CFG_REPLY:
+                               {
+                                       attributes = cp->create_attribute_iterator(cp);
+                                       while (attributes->iterate(attributes, (void**)&ca))
+                                       {
+                                               process_attribute(this, ca);
+                                       }
+                                       attributes->destroy(attributes);
+                                       break;
+                               }
+                               default:
+                                       DBG1(DBG_IKE, "ignoring %N config payload", 
+                                                config_type_names, cp->get_config_type(cp));
+                                       break;
+                       }
+               }
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_config_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) != IKE_SA_INIT)
+       {
+               this->virtual_ip = this->policy->get_virtual_ip(this->policy, NULL);
+               
+               build_payloads(this, message, CFG_REQUEST);
+       }
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_config_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) != IKE_SA_INIT)
+       {
+               process_payloads(this, message);
+       }
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_config_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) != IKE_SA_INIT)
+       {
+               this->policy = this->ike_sa->get_policy(this->ike_sa);
+               
+               if (this->policy && this->virtual_ip)
+               {
+                       host_t *ip;
+                       
+                       DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
+                       ip = this->policy->get_virtual_ip(this->policy, this->virtual_ip);
+                       if (ip == NULL)
+                       {
+                               DBG1(DBG_IKE, "not assigning a virtual IP to peer");
+                               return SUCCESS;
+                       }
+                               DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip);
+                       this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, ip);
+                       
+                       this->virtual_ip->destroy(this->virtual_ip);
+                       this->virtual_ip = ip;
+                       
+                       /* DNS is for testing only */
+                       if (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
+                       {
+                               ip->destroy(ip);
+                               ip = host_create_from_string("10.3.0.1", 0);
+                               this->dns->insert_last(this->dns, ip);
+                               ip = host_create_from_string("10.3.0.2", 0);
+                               this->dns->insert_last(this->dns, ip);
+                       }
+                       
+                       build_payloads(this, message, CFG_REPLY);
+               }
+               return SUCCESS;
+       }
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_config_t *this, message_t *message)
+{
+       if (message->get_exchange_type(message) != IKE_SA_INIT)
+       {
+               host_t *ip;
+               
+               DESTROY_IF(this->virtual_ip);
+               this->virtual_ip = NULL;
+
+               process_payloads(this, message);
+
+               if (this->virtual_ip)
+               {
+                       this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
+                       
+                       while (this->dns->remove_last(this->dns, (void**)&ip) == SUCCESS)
+                       {
+                               this->ike_sa->add_dns_server(this->ike_sa, ip);
+                               ip->destroy(ip);
+                       }
+               }
+               return SUCCESS;
+       }
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_config_t *this)
+{
+       return IKE_CONFIG;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
+{
+       DESTROY_IF(this->virtual_ip);
+       this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
+       
+       this->ike_sa = ike_sa;
+       this->virtual_ip = NULL;
+       this->dns = linked_list_create();
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_config_t *this)
+{
+       DESTROY_IF(this->virtual_ip);
+       this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy)
+{
+       private_ike_config_t *this = malloc_thing(private_ike_config_t);
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       
+       if (policy)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+               this->initiator = TRUE;
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+               this->initiator = FALSE;
+       }
+       
+       this->ike_sa = ike_sa;
+       this->policy = policy;
+       this->virtual_ip = NULL;
+       this->dns = linked_list_create();
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_config.h b/src/charon/sa/tasks/ike_config.h
new file mode 100644 (file)
index 0000000..0c9b961
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * @file ike_config.h
+ * 
+ * @brief Interface ike_config_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef IKE_CONFIG_H_
+#define IKE_CONFIG_H_
+
+typedef struct ike_config_t ike_config_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+#include <config/policies/policy.h>
+
+/**
+ * @brief Task of type IKE_CONFIG, sets up a virtual IP and other
+ * configurations for an IKE_SA.
+ *
+ * @b Constructors:
+ *  - ike_config_create()
+ * 
+ * @ingroup tasks
+ */
+struct ike_config_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new ike_config task.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param policy               policy for the initiator, NULL for the responder
+ * @return                             ike_config task to handle by the task_manager
+ */
+ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy);
+
+#endif /* IKE_CONFIG_H_ */
diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c
new file mode 100644 (file)
index 0000000..b9efc4e
--- /dev/null
@@ -0,0 +1,169 @@
+/**
+ * @file ike_delete.c
+ *
+ * @brief Implementation of the ike_delete task.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "ike_delete.h"
+
+#include <daemon.h>
+#include <encoding/payloads/delete_payload.h>
+
+
+typedef struct private_ike_delete_t private_ike_delete_t;
+
+/**
+ * Private members of a ike_delete_t task.
+ */
+struct private_ike_delete_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       ike_delete_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * are we responding to a delete, but have initated our own?
+        */
+       bool simultaneous;
+};
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_ike_delete_t *this, message_t *message)
+{
+       delete_payload_t *delete_payload;
+
+       delete_payload = delete_payload_create(PROTO_IKE);
+       message->add_payload(message, (payload_t*)delete_payload);
+       
+       this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_delete_t *this, message_t *message)
+{
+       /* completed, delete IKE_SA by returning FAILED */
+       return FAILED;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_ike_delete_t *this, message_t *message)
+{
+       /* we don't even scan the payloads, as the message wouldn't have
+        * come so far without being correct */
+       switch (this->ike_sa->get_state(this->ike_sa))
+       {
+               case IKE_DELETING:
+                       this->simultaneous = TRUE;
+                       break;
+               case IKE_ESTABLISHED:
+                       DBG1(DBG_IKE, "deleting IKE_SA on request");
+                       /* warn only if we are established */
+               default:
+                       this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
+                       break;
+       }
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_delete_t *this, message_t *message)
+{
+       if (this->simultaneous)
+       {
+               /* wait for peers response for our delete request */
+               return SUCCESS;
+       }
+       /* completed, delete IKE_SA by returning FAILED */
+       return FAILED;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_delete_t *this)
+{
+       return IKE_DELETE;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_delete_t *this, ike_sa_t *ike_sa)
+{
+       this->ike_sa = ike_sa;
+       this->simultaneous = FALSE;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_delete_t *this)
+{
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator)
+{
+       private_ike_delete_t *this = malloc_thing(private_ike_delete_t);
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       
+       if (initiator)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+       }
+       
+       this->ike_sa = ike_sa;
+       this->initiator = initiator;
+       this->simultaneous = FALSE;
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_delete.h b/src/charon/sa/tasks/ike_delete.h
new file mode 100644 (file)
index 0000000..e8ec5eb
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file ike_delete.h
+ * 
+ * @brief Interface ike_delete_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef IKE_DELETE_H_
+#define IKE_DELETE_H_
+
+typedef struct ike_delete_t ike_delete_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_delete, delete an IKE_SA.
+ *
+ * @b Constructors:
+ *  - ike_delete_create()
+ * 
+ * @ingroup tasks
+ */
+struct ike_delete_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new ike_delete task.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param initiator            TRUE if we initiate the delete
+ * @return                             ike_delete task to handle by the task_manager
+ */
+ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_DELETE_H_ */
diff --git a/src/charon/sa/tasks/ike_dpd.c b/src/charon/sa/tasks/ike_dpd.c
new file mode 100644 (file)
index 0000000..1cb05c4
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * @file ike_dpd.c
+ *
+ * @brief Implementation of the ike_dpd task.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "ike_dpd.h"
+
+#include <daemon.h>
+
+
+typedef struct private_ike_dpd_t private_ike_dpd_t;
+
+/**
+ * Private members of a ike_dpd_t task.
+ */
+struct private_ike_dpd_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       ike_dpd_t public;
+};
+
+/**
+ * Implementation of task_t.build for initiator
+ * Implementation of task_t.process for responder
+ */
+static status_t return_need_more(private_ike_dpd_t *this, message_t *message)
+{
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ * Implementation of task_t.build for responder
+ */
+static status_t return_success(private_ike_dpd_t *this, message_t *message)
+{
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_dpd_t *this)
+{
+       return IKE_DEADPEER;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_dpd_t *this, ike_sa_t *ike_sa)
+{
+
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_dpd_t *this)
+{
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_dpd_t *ike_dpd_create(bool initiator)
+{
+       private_ike_dpd_t *this = malloc_thing(private_ike_dpd_t);
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       
+       if (initiator)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))return_need_more;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))return_success;
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))return_success;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))return_need_more;
+       }
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_dpd.h b/src/charon/sa/tasks/ike_dpd.h
new file mode 100644 (file)
index 0000000..531b050
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * @file ike_dpd.h
+ * 
+ * @brief Interface ike_dpd_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef IKE_DPD_H_
+#define IKE_DPD_H_
+
+typedef struct ike_dpd_t ike_dpd_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_dpd, detects dead peers.
+ *
+ * The DPD task actually does nothing, as a DPD has no associated payloads.
+ *
+ * @b Constructors:
+ *  - ike_dpd_create()
+ * 
+ * @ingroup tasks
+ */
+struct ike_dpd_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new ike_dpd task.
+ *
+ * @param initiator            TRUE if thask is the original initator
+ * @return                             ike_dpd task to handle by the task_manager
+ */
+ike_dpd_t *ike_dpd_create(bool initiator);
+
+#endif /* IKE_DPD_H_ */
diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c
new file mode 100644 (file)
index 0000000..9149aab
--- /dev/null
@@ -0,0 +1,536 @@
+/**
+ * @file ike_init.c
+ *
+ * @brief Implementation of the ike_init task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "ike_init.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <crypto/diffie_hellman.h>
+#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+
+
+typedef struct private_ike_init_t private_ike_init_t;
+
+/**
+ * Private members of a ike_init_t task.
+ */
+struct private_ike_init_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       ike_init_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * Connection established by this IKE_SA
+        */
+       connection_t *connection;
+       
+       /**
+        * diffie hellman group to use
+        */
+       diffie_hellman_group_t dh_group;
+       
+       /**
+        * Diffie hellman object used to generate public DH value.
+        */
+       diffie_hellman_t *diffie_hellman;
+       
+       /**
+        * nonce chosen by us
+        */
+       chunk_t my_nonce;
+       
+       /**
+        * nonce chosen by peer
+        */
+       chunk_t other_nonce;
+       
+       /**
+        * Negotiated proposal used for IKE_SA
+        */
+       proposal_t *proposal;
+       
+       /**
+        * Old IKE_SA which gets rekeyed
+        */
+       ike_sa_t *old_sa;
+};
+
+/**
+ * build the payloads for the message
+ */
+static void build_payloads(private_ike_init_t *this, message_t *message)
+{
+       sa_payload_t *sa_payload;
+       ke_payload_t *ke_payload;
+       nonce_payload_t *nonce_payload;
+       linked_list_t *proposal_list;
+       ike_sa_id_t *id;
+       proposal_t *proposal;
+       iterator_t *iterator;
+       
+       id = this->ike_sa->get_id(this->ike_sa);
+       
+       this->connection = this->ike_sa->get_connection(this->ike_sa);
+
+       if (this->initiator)
+       {
+               proposal_list = this->connection->get_proposals(this->connection);
+               if (this->old_sa)
+               {       
+                       /* include SPI of new IKE_SA when we are rekeying */
+                       iterator = proposal_list->create_iterator(proposal_list, TRUE);
+                       while (iterator->iterate(iterator, (void**)&proposal))
+                       {
+                               proposal->set_spi(proposal, id->get_initiator_spi(id));
+                       }
+                       iterator->destroy(iterator);
+               }
+               
+               sa_payload = sa_payload_create_from_proposal_list(proposal_list);
+               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
+       }
+       else
+       {
+               if (this->old_sa)
+               {
+                       /* include SPI of new IKE_SA when we are rekeying */
+                       this->proposal->set_spi(this->proposal, id->get_responder_spi(id));
+               }
+               sa_payload = sa_payload_create_from_proposal(this->proposal);
+       }
+       message->add_payload(message, (payload_t*)sa_payload);
+       
+       ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
+       message->add_payload(message, (payload_t*)ke_payload);
+       
+       nonce_payload = nonce_payload_create();
+       nonce_payload->set_nonce(nonce_payload, this->my_nonce);
+       
+       message->add_payload(message, (payload_t*)nonce_payload);
+}
+
+/**
+ * Read payloads from message
+ */
+static void process_payloads(private_ike_init_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               switch (payload->get_type(payload))
+               {
+                       case SECURITY_ASSOCIATION:
+                       {
+                               sa_payload_t *sa_payload = (sa_payload_t*)payload;
+                               linked_list_t *proposal_list;
+       
+                               proposal_list = sa_payload->get_proposals(sa_payload);
+                               this->proposal = this->connection->select_proposal(
+                                                                                         this->connection, proposal_list);
+                               proposal_list->destroy_offset(proposal_list, 
+                                                                                         offsetof(proposal_t, destroy));
+                               break;
+                       }
+                       case KEY_EXCHANGE:
+                       {
+                               ke_payload_t *ke_payload = (ke_payload_t*)payload;
+                               diffie_hellman_group_t dh_group;
+                               chunk_t key_data;
+                               
+                               dh_group = ke_payload->get_dh_group_number(ke_payload);
+                               
+                               if (this->initiator)
+                               {
+                                       if (dh_group != this->dh_group)
+                                       {
+                                               DBG1(DBG_IKE, "received a DH group not requested (%N)",
+                                                        diffie_hellman_group_names, dh_group);
+                                               break;
+                                       }
+                               }
+                               else
+                               {
+                                       this->dh_group = dh_group;
+                                       if (!this->connection->check_dh_group(this->connection, 
+                                                                                                                 dh_group))
+                                       {
+                                               break;
+                                       }
+                                       this->diffie_hellman = diffie_hellman_create(dh_group);
+                               }
+                               if (this->diffie_hellman)
+                               {
+                                       key_data = ke_payload->get_key_exchange_data(ke_payload);
+                                       this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data);
+                               }
+                               break;
+                       }
+                       case NONCE:
+                       {
+                               nonce_payload_t *nonce_payload = (nonce_payload_t*)payload;
+                               this->other_nonce = nonce_payload->get_nonce(nonce_payload);
+                               break;
+                       }
+                       default:
+                               break;
+               }
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_init_t *this, message_t *message)
+{
+       randomizer_t *randomizer;
+       status_t status;
+       
+       this->connection = this->ike_sa->get_connection(this->ike_sa);
+       SIG(IKE_UP_START, "initiating IKE_SA to %H",
+               this->connection->get_other_host(this->connection));
+       this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
+
+       /* if the DH group is set via use_dh_group(), we already have a DH object */
+       if (!this->diffie_hellman)
+       {
+               this->dh_group = this->connection->get_dh_group(this->connection);
+               this->diffie_hellman = diffie_hellman_create(this->dh_group);
+               if (this->diffie_hellman == NULL)
+               {
+                       SIG(IKE_UP_FAILED, "configured DH group %N not supported",
+                               diffie_hellman_group_names, this->dh_group);
+                       return FAILED;
+               }
+       }
+       
+       randomizer = randomizer_create();
+       status = randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
+                                                                                                         &this->my_nonce);
+       randomizer->destroy(randomizer);
+       if (status != SUCCESS)
+       {
+               SIG(IKE_UP_FAILED, "error generating random nonce value");
+               return FAILED;
+       }
+       
+       build_payloads(this, message);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_ike_init_t *this, message_t *message)
+{      
+       randomizer_t *randomizer;
+       
+       this->connection = this->ike_sa->get_connection(this->ike_sa);
+       SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA",
+               message->get_source(message));
+       this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
+
+       randomizer = randomizer_create();
+       if (randomizer->allocate_pseudo_random_bytes(randomizer, NONCE_SIZE,
+                                                                                                &this->my_nonce) != SUCCESS)
+       {
+               DBG1(DBG_IKE, "error generating random nonce value");
+       }
+       randomizer->destroy(randomizer);
+       
+       process_payloads(this, message);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_init_t *this, message_t *message)
+{
+       chunk_t secret;
+       status_t status;
+
+       /* check if we have everything we need */
+       if (this->proposal == NULL ||
+               this->other_nonce.len == 0 || this->my_nonce.len == 0)
+       {
+               SIG(IKE_UP_FAILED, "received proposals inacceptable");
+               message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
+               return FAILED;
+       }
+       
+       if (this->diffie_hellman == NULL ||
+               this->diffie_hellman->get_shared_secret(this->diffie_hellman,
+                                                                                               &secret) != SUCCESS)
+       {
+               chunk_t chunk;
+               u_int16_t dh_enc;
+               
+               SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)",
+                        diffie_hellman_group_names, this->dh_group);
+               this->dh_group = this->connection->get_dh_group(this->connection);
+               dh_enc = htons(this->dh_group);
+               chunk.ptr = (u_int8_t*)&dh_enc;
+               chunk.len = sizeof(dh_enc);
+               message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk);
+               DBG1(DBG_IKE, "requesting DH group %N",
+                        diffie_hellman_group_names, this->dh_group);
+               return FAILED;
+       }
+
+       
+       if (this->old_sa)
+       {
+               ike_sa_id_t *id;
+               prf_t *prf, *child_prf;
+                               
+               /* Apply SPI if we are rekeying */
+               id = this->ike_sa->get_id(this->ike_sa);
+               id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
+       
+               /* setup crypto keys for the rekeyed SA */
+               prf = this->old_sa->get_prf(this->old_sa);
+               child_prf = this->old_sa->get_child_prf(this->old_sa);
+               status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, 
+                                                                                  this->other_nonce, this->my_nonce,
+                                                                                  FALSE, child_prf, prf);
+       }
+       else
+       {
+               /* setup crypto keys */
+               status =  this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, 
+                                                                                   this->other_nonce, this->my_nonce,
+                                                                                   FALSE, NULL, NULL);
+       }
+       if (status != SUCCESS)
+       {
+               SIG(IKE_UP_FAILED, "key derivation failed");
+               message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
+               return FAILED;
+       }
+       
+       build_payloads(this, message);
+
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_init_t *this, message_t *message)
+{
+       chunk_t secret;
+       status_t status;
+       iterator_t *iterator;
+       payload_t *payload;
+
+       /* check for erronous notifies */
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               if (payload->get_type(payload) == NOTIFY)
+               {
+                       notify_payload_t *notify = (notify_payload_t*)payload;
+                       notify_type_t type = notify->get_notify_type(notify);
+                       
+                       switch (type)
+                       {
+                               case INVALID_KE_PAYLOAD:
+                               {
+                                       chunk_t data;
+                                       diffie_hellman_group_t old_dh_group;
+                                       
+                                       old_dh_group = this->dh_group;
+                                       data = notify->get_notification_data(notify);
+                                       this->dh_group = ntohs(*((u_int16_t*)data.ptr));
+                                       
+                                       DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested"
+                                                " %N", diffie_hellman_group_names, old_dh_group,
+                                                diffie_hellman_group_names, this->dh_group);
+                                       if (!this->connection->check_dh_group(this->connection,
+                                                                                                                 this->dh_group))
+                                       {
+                                               SIG(IKE_UP_FAILED, "requested DH group %N not "
+                                                       "acceptable, giving up", diffie_hellman_group_names,
+                                                       this->dh_group);
+                                               iterator->destroy(iterator);
+                                               return FAILED;
+                                       }
+                                       
+                                       this->ike_sa->reset(this->ike_sa);
+                                       
+                                       iterator->destroy(iterator);
+                                       return NEED_MORE;
+                               }
+                               default:
+                               {
+                                       if (type < 16383)
+                                       {
+                                               SIG(IKE_UP_FAILED, "received %N notify error",
+                                                        notify_type_names, type);
+                                               iterator->destroy(iterator);
+                                               return FAILED;  
+                                       }
+                               }
+                       }
+               }
+       }
+       iterator->destroy(iterator);
+       
+       process_payloads(this, message);
+
+       /* check if we have everything */
+       if (this->proposal == NULL ||
+               this->other_nonce.len == 0 || this->my_nonce.len == 0)
+       {
+               SIG(IKE_UP_FAILED, "peers proposal selection invalid");
+               return FAILED;
+       }
+       
+       if (this->diffie_hellman == NULL ||
+               this->diffie_hellman->get_shared_secret(this->diffie_hellman,
+                                                                                               &secret) != SUCCESS)
+       {
+               SIG(IKE_UP_FAILED, "peers DH group selection invalid");
+               return FAILED;
+       }
+       
+       /* Apply SPI if we are rekeying */
+       if (this->old_sa)
+       {
+               ike_sa_id_t *id;
+               prf_t *prf, *child_prf;
+               
+               id = this->ike_sa->get_id(this->ike_sa);
+               id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
+               
+               /* setup crypto keys for the rekeyed SA */
+               prf = this->old_sa->get_prf(this->old_sa);
+               child_prf = this->old_sa->get_child_prf(this->old_sa);
+               status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, 
+                                                                                   this->my_nonce, this->other_nonce,
+                                                                                   TRUE, child_prf, prf);
+       }
+       else
+       {
+               /* setup crypto keys for a new SA */
+               status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, 
+                                                                                  this->my_nonce, this->other_nonce,
+                                                                                  TRUE, NULL, NULL);
+       }
+       if (status != SUCCESS)
+       {
+               SIG(IKE_UP_FAILED, "key derivation failed");
+               return FAILED;
+       }
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_init_t *this)
+{
+       return IKE_INIT;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
+{
+       DESTROY_IF(this->proposal);
+       DESTROY_IF(this->diffie_hellman);
+       chunk_free(&this->my_nonce);
+       chunk_free(&this->other_nonce);
+       
+       this->ike_sa = ike_sa;
+       this->proposal = NULL;
+       this->diffie_hellman = diffie_hellman_create(this->dh_group);
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_init_t *this)
+{
+       DESTROY_IF(this->proposal);
+       DESTROY_IF(this->diffie_hellman);
+       chunk_free(&this->my_nonce);
+       chunk_free(&this->other_nonce);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
+{
+       private_ike_init_t *this = malloc_thing(private_ike_init_t);
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       if (initiator)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+       }
+       
+       this->ike_sa = ike_sa;
+       this->initiator = initiator;
+       this->dh_group = MODP_NONE;
+       this->diffie_hellman = NULL;
+       this->my_nonce = chunk_empty;
+       this->other_nonce = chunk_empty;
+       this->proposal = NULL;
+       this->connection = NULL;
+       this->old_sa = old_sa;
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_init.h b/src/charon/sa/tasks/ike_init.h
new file mode 100644 (file)
index 0000000..290cc46
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * @file ike_init.h
+ * 
+ * @brief Interface ike_init_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef IKE_INIT_H_
+#define IKE_INIT_H_
+
+typedef struct ike_init_t ike_init_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type IKE_INIT, creates an IKE_SA without authentication.
+ *
+ * The authentication of is handle in the ike_auth and/or ike_auth_eap task.
+ *
+ * @b Constructors:
+ *  - ike_init_create()
+ * 
+ * @ingroup tasks
+ */
+struct ike_init_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new IKE_INIT task.
+ *
+ * @param ike_sa               IKE_SA this task works for (new one when rekeying)
+ * @param initiator            TRUE if thask is the original initator
+ * @param old_sa               old IKE_SA when we are rekeying
+ * @return                             ike_init task to handle by the task_manager
+ */
+ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa);
+
+#endif /* IKE_INIT_H_ */
diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c
new file mode 100644 (file)
index 0000000..a25b6e0
--- /dev/null
@@ -0,0 +1,378 @@
+/**
+ * @file ike_natd.c
+ *
+ * @brief Implementation of the ike_natd task.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "ike_natd.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <crypto/hashers/hasher.h>
+#include <encoding/payloads/notify_payload.h>
+
+
+typedef struct private_ike_natd_t private_ike_natd_t;
+
+/**
+ * Private members of a ike_natd_t task.
+ */
+struct private_ike_natd_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       ike_natd_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * Hasher used to build NAT detection hashes
+        */
+       hasher_t *hasher;
+       
+       /**
+        * Did we process any NAT detection notifys for a source address?
+        */
+       bool src_seen;
+       
+       /**
+        * Did we process any NAT detection notifys for a destination address?
+        */
+       bool dst_seen;
+       
+       /**
+        * Have we found a matching source address NAT hash?
+        */
+       bool src_matched;
+       
+       /**
+        * Have we found a matching destination address NAT hash?
+        */
+       bool dst_matched;
+};
+
+
+/**
+ * Build NAT detection hash for a host
+ */
+static chunk_t generate_natd_hash(private_ike_natd_t *this,
+                                                                 ike_sa_id_t *ike_sa_id, host_t *host)
+{
+       chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk;
+       chunk_t natd_hash;
+       u_int64_t spi_i, spi_r;
+       u_int16_t port;
+       
+       /* prepare all requred chunks */
+       spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
+       spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
+       spi_i_chunk.ptr = (void*)&spi_i;
+       spi_i_chunk.len = sizeof(spi_i);
+       spi_r_chunk.ptr = (void*)&spi_r;
+       spi_r_chunk.len = sizeof(spi_r);
+       port = htons(host->get_port(host));
+       port_chunk.ptr = (void*)&port;
+       port_chunk.len = sizeof(port);
+       addr_chunk = host->get_address(host);
+       DBG2(DBG_IKE, "using SPI %J", ike_sa_id);
+               
+       /*  natd_hash = SHA1( spi_i | spi_r | address | port ) */
+       natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk);
+       this->hasher->allocate_hash(this->hasher, natd_chunk, &natd_hash);
+       DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
+       DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
+       
+       chunk_free(&natd_chunk);
+       return natd_hash;
+}
+
+/**
+ * Build a NAT detection notify payload.
+ */
+static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
+                                                                                       notify_type_t type, host_t *host)
+{
+       chunk_t hash;
+       notify_payload_t *notify;       
+       ike_sa_id_t *ike_sa_id; 
+       
+       ike_sa_id = this->ike_sa->get_id(this->ike_sa);
+       notify = notify_payload_create();
+       notify->set_notify_type(notify, type);
+       hash = generate_natd_hash(this, ike_sa_id, host);
+       notify->set_notification_data(notify, hash);
+       chunk_free(&hash);
+       
+       return notify;
+}
+
+/**
+ * read notifys from message and evaluate them
+ */
+static void process_payloads(private_ike_natd_t *this, message_t *message)
+{
+       iterator_t *iterator;
+       payload_t *payload;
+       notify_payload_t *notify;
+       chunk_t hash, src_hash, dst_hash;
+       ike_sa_id_t *ike_sa_id;
+       host_t *me, *other;
+       
+       /* Precompute NAT-D hashes for incoming NAT notify comparison */
+       ike_sa_id = message->get_ike_sa_id(message);
+       me = this->ike_sa->get_my_host(this->ike_sa);
+       other = this->ike_sa->get_other_host(this->ike_sa);
+       dst_hash = generate_natd_hash(this, ike_sa_id, me);
+       src_hash = generate_natd_hash(this, ike_sa_id, other);
+       
+       DBG2(DBG_IKE, "precalculated src_hash %B", &src_hash);
+       DBG2(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
+       
+       iterator = message->get_payload_iterator(message);
+       while (iterator->iterate(iterator, (void**)&payload))
+       {
+               if (payload->get_type(payload) != NOTIFY)
+               {
+                       continue;
+               }
+               notify = (notify_payload_t*)payload;
+               switch (notify->get_notify_type(notify))
+               {
+                       case NAT_DETECTION_DESTINATION_IP:
+                       {
+                               this->dst_seen = TRUE;
+                               if (!this->dst_matched)
+                               {
+                                       hash = notify->get_notification_data(notify);
+                                       DBG2(DBG_IKE, "received dst_hash %B", &hash);
+                                       if (chunk_equals(hash, dst_hash))
+                                       {
+                                               this->dst_matched = TRUE;
+                                       }
+                               }
+                               break;
+                       }
+                       case NAT_DETECTION_SOURCE_IP:
+                       {
+                               this->src_seen = TRUE;
+                               if (!this->src_matched)
+                               {
+                                       hash = notify->get_notification_data(notify);
+                                       DBG2(DBG_IKE, "received src_hash %B", &hash);
+                                       if (chunk_equals(hash, src_hash))
+                                       {
+                                               this->src_matched = TRUE;
+                                       }
+                               }
+                               break;
+                       }
+                       default:
+                               break;
+               }
+       }
+       iterator->destroy(iterator);
+       
+       chunk_free(&src_hash);
+       chunk_free(&dst_hash);
+       
+       if (this->src_seen && this->dst_seen)
+       {
+               if (!this->dst_matched)
+               {
+                       this->ike_sa->enable_natt(this->ike_sa, TRUE);
+               }
+               if (!this->src_matched)
+               {
+                       this->ike_sa->enable_natt(this->ike_sa, FALSE);
+               }
+       }
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_natd_t *this, message_t *message)
+{
+       process_payloads(this, message);
+
+       if (this->ike_sa->is_natt_enabled(this->ike_sa))
+       {
+               host_t *me, *other;
+       
+               me = this->ike_sa->get_my_host(this->ike_sa);
+               me->set_port(me, IKEV2_NATT_PORT);
+               other = this->ike_sa->get_other_host(this->ike_sa);
+               other->set_port(other, IKEV2_NATT_PORT);
+       }
+       
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_natd_t *this, message_t *message)
+{
+       notify_payload_t *notify;
+       linked_list_t *list;
+       host_t *host;
+       
+       /* include one notify if our address is defined, all addresses otherwise */
+       host = this->ike_sa->get_my_host(this->ike_sa);
+       if (host->is_anyaddr(host))
+       {
+               /* TODO: we could get the src address from netlink!? */
+               list = charon->socket->create_local_address_list(charon->socket);
+               while (list->remove_first(list, (void**)&host) == SUCCESS)
+               {
+                       notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
+                       host->destroy(host);
+                       message->add_payload(message, (payload_t*)notify);
+               }
+               list->destroy(list);
+       }
+       else
+       {
+               notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
+               message->add_payload(message, (payload_t*)notify);
+       }
+       
+       host = this->ike_sa->get_other_host(this->ike_sa);
+       notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
+       message->add_payload(message, (payload_t*)notify);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_natd_t *this, message_t *message)
+{
+       notify_payload_t *notify;
+       host_t *me, *other;
+       iterator_t *iterator;
+       u_int count;
+       
+       /* when only one payload is in the message, an error occured.
+        * TODO: find a better hack */
+       iterator = message->get_payload_iterator(message);
+       count = iterator->get_count(iterator);
+       iterator->destroy(iterator);
+       if (count < 3)
+       {
+               return NEED_MORE;
+       }
+
+       if (this->src_seen && this->dst_seen)
+       {
+               /* initiator seems to support NAT detection, add response */
+               me = this->ike_sa->get_my_host(this->ike_sa);
+               notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
+               message->add_payload(message, (payload_t*)notify);
+               
+               other = this->ike_sa->get_other_host(this->ike_sa);
+               notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
+               message->add_payload(message, (payload_t*)notify);
+       }
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_natd_t *this, message_t *message)
+{      
+       process_payloads(this, message);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_natd_t *this)
+{
+       return IKE_NATD;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa)
+{
+       this->ike_sa = ike_sa;
+       this->src_seen = FALSE;
+       this->dst_seen = FALSE;
+       this->src_matched = FALSE;
+       this->dst_matched = FALSE;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_natd_t *this)
+{
+       this->hasher->destroy(this->hasher);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
+{
+       private_ike_natd_t *this = malloc_thing(private_ike_natd_t);
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       
+       if (initiator)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+       }
+       
+       this->ike_sa = ike_sa;
+       this->initiator = initiator;
+       this->hasher = hasher_create(HASH_SHA1);
+       this->src_seen = FALSE;
+       this->dst_seen = FALSE;
+       this->src_matched = FALSE;
+       this->dst_matched = FALSE;
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_natd.h b/src/charon/sa/tasks/ike_natd.h
new file mode 100644 (file)
index 0000000..8d0cb58
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file ike_natd.h
+ * 
+ * @brief Interface ike_natd_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef IKE_NATD_H_
+#define IKE_NATD_H_
+
+typedef struct ike_natd_t ike_natd_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange.
+ *
+ * @b Constructors:
+ *  - ike_natd_create()
+ * 
+ * @ingroup tasks
+ */
+struct ike_natd_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new ike_natd task.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param initiator            TRUE if thask is the original initator
+ * @return                       ike_natd task to handle by the task_manager
+ */
+ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_NATD_H_ */
diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c
new file mode 100644 (file)
index 0000000..bbbd310
--- /dev/null
@@ -0,0 +1,232 @@
+/**
+ * @file ike_rekey.c
+ *
+ * @brief Implementation of the ike_rekey task.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "ike_rekey.h"
+
+#include <daemon.h>
+#include <crypto/diffie_hellman.h>
+#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/nonce_payload.h>
+#include <sa/tasks/ike_init.h>
+#include <queues/jobs/delete_ike_sa_job.h>
+
+
+typedef struct private_ike_rekey_t private_ike_rekey_t;
+
+/**
+ * Private members of a ike_rekey_t task.
+ */
+struct private_ike_rekey_t {
+       
+       /**
+        * Public methods and task_t interface.
+        */
+       ike_rekey_t public;
+       
+       /**
+        * Assigned IKE_SA.
+        */
+       ike_sa_t *ike_sa;
+       
+       /**
+        * New IKE_SA which replaces the current one
+        */
+       ike_sa_t *new_sa;
+       
+       /**
+        * Are we the initiator?
+        */
+       bool initiator;
+       
+       /**
+        * the IKE_INIT task which is reused to simplify rekeying
+        */
+       ike_init_t *ike_init;
+};
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_ike_rekey_t *this, message_t *message)
+{
+       connection_t *connection;
+       policy_t *policy;
+       ike_sa_id_t *id;
+       
+       id = ike_sa_id_create(0, 0, TRUE);
+       this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+       id->destroy(id);
+       
+       connection = this->ike_sa->get_connection(this->ike_sa);
+       policy = this->ike_sa->get_policy(this->ike_sa);
+       this->new_sa->set_connection(this->new_sa, connection);
+       this->new_sa->set_policy(this->new_sa, policy);
+
+       this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
+       this->ike_init->task.build(&this->ike_init->task, message);
+       
+       this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
+
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_r(private_ike_rekey_t *this, message_t *message)
+{
+       connection_t *connection;
+       policy_t *policy;
+       ike_sa_id_t *id;
+       
+       id = ike_sa_id_create(0, 0, FALSE);
+       this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+       id->destroy(id);
+       
+       connection = this->ike_sa->get_connection(this->ike_sa);
+       policy = this->ike_sa->get_policy(this->ike_sa);
+       this->new_sa->set_connection(this->new_sa, connection);
+       this->new_sa->set_policy(this->new_sa, policy);
+       
+       this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa);
+       this->ike_init->task.process(&this->ike_init->task, message);
+       
+       return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_rekey_t *this, message_t *message)
+{
+       if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED)
+       {
+               return SUCCESS;
+       }
+       
+       this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
+       this->new_sa->inherit(this->new_sa, this->ike_sa);
+       this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
+       charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
+       this->new_sa = NULL;
+       
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_rekey_t *this, message_t *message)
+{
+       job_t *job;
+
+       if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED)
+       {
+               return SUCCESS;
+       }
+       
+       this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
+       this->new_sa->inherit(this->new_sa, this->ike_sa);
+       charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
+       this->new_sa = NULL;
+       
+       job = (job_t*)delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa),
+                                                                                  TRUE);
+       
+       charon->job_queue->add(charon->job_queue, job);
+       return SUCCESS;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_rekey_t *this)
+{
+       return IKE_REKEY;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_rekey_t *this, ike_sa_t *ike_sa)
+{
+       if (this->ike_init)
+       {
+               this->ike_init->task.destroy(&this->ike_init->task);
+       }
+       if (this->new_sa)
+       {
+               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+                                                                                                       this->new_sa);
+       }
+
+       this->ike_sa = ike_sa;
+       this->new_sa = NULL;
+       this->ike_init = NULL;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_rekey_t *this)
+{
+       if (this->ike_init)
+       {
+               this->ike_init->task.destroy(&this->ike_init->task);
+       }
+       if (this->new_sa)
+       {
+               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+                                                                                                       this->new_sa);
+       }
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator)
+{
+       private_ike_rekey_t *this = malloc_thing(private_ike_rekey_t);
+
+       this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+       this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+       this->public.task.destroy = (void(*)(task_t*))destroy;
+       if (initiator)
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+       }
+       else
+       {
+               this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+               this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+       }
+       
+       this->ike_sa = ike_sa;
+       this->new_sa = NULL;
+       this->ike_init = NULL;
+       this->initiator = initiator;
+       
+       return &this->public;
+}
diff --git a/src/charon/sa/tasks/ike_rekey.h b/src/charon/sa/tasks/ike_rekey.h
new file mode 100644 (file)
index 0000000..f1caf57
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * @file ike_rekey.h
+ * 
+ * @brief Interface ike_rekey_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef IKE_REKEY_H_
+#define IKE_REKEY_H_
+
+typedef struct ike_rekey_t ike_rekey_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type IKE_REKEY, rekey an established IKE_SA.
+ *
+ * @b Constructors:
+ *  - ike_rekey_create()
+ * 
+ * @ingroup tasks
+ */
+struct ike_rekey_t {
+
+       /**
+        * Implements the task_t interface
+        */
+       task_t task;
+};
+
+/**
+ * @brief Create a new IKE_REKEY task.
+ *
+ * @param ike_sa               IKE_SA this task works for
+ * @param initiator            TRUE for initiator, FALSE for responder
+ * @return                             IKE_REKEY task to handle by the task_manager
+ */
+ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_REKEY_H_ */
diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c
new file mode 100644 (file)
index 0000000..68d8ebf
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * @file task.c
+ * 
+ * @brief Enum values for task types
+ * 
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#include "task.h"
+
+ENUM(task_type_names, IKE_INIT, CHILD_REKEY,
+       "IKE_INIT",
+       "IKE_NATD",
+       "IKE_AUTHENTICATE",
+       "IKE_CERT",
+       "IKE_CONFIG",
+       "IKE_DPD",
+       "IKE_REKEY",
+       "IKE_DELETE",
+       "IKE_DEADPEER",
+       "CHILD_CREATE",
+       "CHILD_DELETE",
+       "CHILD_REKEY",
+);
diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h
new file mode 100644 (file)
index 0000000..128d7db
--- /dev/null
@@ -0,0 +1,151 @@
+/**
+ * @file task.h
+ * 
+ * @brief Interface task_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2006 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * 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.
+ */
+
+#ifndef TASK_H_
+#define TASK_H_
+
+typedef enum task_type_t task_type_t;
+typedef struct task_t task_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <encoding/message.h>
+
+/**
+ * @brief Different kinds of tasks.
+ * 
+ * @ingroup tasks
+ */
+enum task_type_t {
+       /** establish an unauthenticated IKE_SA */
+       IKE_INIT,
+       /** detect NAT situation */
+       IKE_NATD,
+       /** authenticate the initiated IKE_SA */
+       IKE_AUTHENTICATE,
+       /** exchange certificates and requests */
+       IKE_CERT,
+       /** Configuration payloads, virtual IP and such */
+       IKE_CONFIG,
+       /** DPD detection */
+       IKE_DEADPEER,
+       /** rekey an IKE_SA */
+       IKE_REKEY,
+       /** delete an IKE_SA */
+       IKE_DELETE,
+       /** liveness check */
+       IKE_DPD,
+       /** establish a CHILD_SA within an IKE_SA */
+       CHILD_CREATE,
+       /** delete an established CHILD_SA */
+       CHILD_DELETE,
+       /** rekey an CHILD_SA */
+       CHILD_REKEY,
+};
+
+/**
+ * enum names for task_type_t.
+ */
+extern enum_name_t *task_type_names;
+
+/**
+ * @brief Interface for a task, an operation handled within exchanges.
+ *
+ * A task is an elemantary operation. It may be handled by a single or by
+ * multiple exchanges. An exchange may even complete multiple tasks.
+ * A task has a build() and an process() operation. The build() operation 
+ * creates payloads and adds it to the message. The process() operation
+ * inspects a message and handles its payloads. An initiator of an exchange
+ * first calls build() to build the request, and processes the response message
+ * with the process() method.
+ * A responder does the opposite; it calls process() first to handle an incoming
+ * request and secondly calls build() to build an appropriate response.
+ * Both methods return either SUCCESS, NEED_MORE or FAILED. A SUCCESS indicates
+ * that the task completed, even when the task completed unsuccesfully. The
+ * manager then removes the task from the list. A NEED_MORE is returned when
+ * the task needs further build()/process() calls to complete, the manager
+ * leaves the taks in the queue. A returned FAILED indicates a critical failure.
+ * The manager closes the IKE_SA whenever a task returns FAILED.
+ *
+ * @b Constructors:
+ *  - None, use implementations specific constructors
+ * 
+ * @ingroup tasks
+ */
+struct task_t {
+
+       /**
+        * @brief Build a request or response message for this task.
+        * 
+        * @param this                  calling object
+        * @param message               message to add payloads to
+        * @return
+        *                                              - FAILED if a critical error occured
+        *                                              - NEED_MORE if another call to build/process needed
+        *                                              - SUCCESS if task completed
+        */
+       status_t (*build) (task_t *this, message_t *message);
+
+       /**
+        * @brief Process a request or response message for this task.
+        * 
+        * @param this                  calling object
+        * @param message               message to read payloads from
+        * @return
+        *                                              - FAILED if a critical error occured
+        *                                              - NEED_MORE if another call to build/process needed
+        *                                              - SUCCESS if task completed
+        */
+       status_t (*process) (task_t *this, message_t *message);
+
+       /**
+        * @brief Get the type of the task implementation.
+        * 
+        * @param this                  calling object
+        */
+       task_type_t (*get_type) (task_t *this);
+       
+       /**
+        * @brief Migrate a task to a new IKE_SA.
+        *
+        * After migrating a task, it goes back to a state where it can be
+        * used again to initate an exchange. This is useful when a task
+        * has to get migrated to a new IKE_SA.
+        * A special usage is when a INVALID_KE_PAYLOAD is received. A call
+        * to reset resets the task, but uses another DH group for the next
+        * try.
+        * The ike_sa is the new IKE_SA this task belongs to and operates on.
+        *
+        * @param this                  calling object
+        * @param ike_sa                new IKE_SA this task works for
+        */
+       void (*migrate) (task_t *this, ike_sa_t *ike_sa);
+       
+       /**
+        * @brief Destroys a task_t object.
+        *
+        * @param this                  calling object
+        */
+       void (*destroy) (task_t *this);
+};
+
+#endif /* TASK_H_ */
diff --git a/src/charon/sa/transactions/create_child_sa.c b/src/charon/sa/transactions/create_child_sa.c
deleted file mode 100644 (file)
index 67e4d78..0000000
+++ /dev/null
@@ -1,1121 +0,0 @@
-/**
- * @file create_child_sa.c
- *
- * @brief Implementation of create_child_sa_t transaction.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#include "create_child_sa.h"
-
-#include <string.h>
-
-#include <daemon.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-#include <encoding/payloads/ts_payload.h>
-#include <sa/transactions/delete_child_sa.h>
-#include <utils/randomizer.h>
-
-
-typedef struct private_create_child_sa_t private_create_child_sa_t;
-
-/**
- * Private members of a create_child_sa_t object..
- */
-struct private_create_child_sa_t {
-       
-       /**
-        * Public methods and transaction_t interface.
-        */
-       create_child_sa_t public;
-       
-       /**
-        * Assigned IKE_SA.
-        */
-       ike_sa_t *ike_sa;
-       
-       /**
-        * Message sent by our peer, if already generated
-        */
-       message_t *message;
-       
-       /**
-        * Message ID this transaction uses
-        */
-       u_int32_t message_id;
-       
-       /**
-        * Times we did send the request
-        */
-       u_int32_t requested;
-       
-       /**
-        * initiators inbound SPI of the CHILD_SA which gets rekeyed
-        */
-       u_int32_t rekey_spi;
-       
-       /**
-        * reqid to use for new CHILD_SA
-        */
-       u_int32_t reqid;
-       
-       /**
-        * policy definition used
-        */
-       policy_t *policy;
-       
-       /**
-        * Negotiated proposal used for CHILD_SA
-        */
-       proposal_t *proposal;
-       
-       /**
-        * initiator chosen nonce
-        */
-       chunk_t nonce_i;
-       
-       /**
-        * responder chosen nonce
-        */
-       chunk_t nonce_r;
-       
-       /**
-        * lower of the nonces of a simultaneus rekeying request
-        */
-       chunk_t nonce_s;
-       
-       /**
-        * Negotiated traffic selectors for initiator
-        */
-       linked_list_t *tsi;
-       
-       /**
-        * Negotiated traffic selectors for responder
-        */
-       linked_list_t *tsr;
-       
-       /**
-        * CHILD_SA created by this transaction
-        */
-       child_sa_t *child_sa;
-       
-       /**
-        * CHILD_SA rekeyed if we are rekeying
-        */
-       child_sa_t *rekeyed_sa;
-       
-       /**
-        * mode of the CHILD_SA to create: transport/tunnel
-        */
-       mode_t mode;
-       
-       /**
-        * Have we lost the simultaneous rekeying nonce compare?
-        */
-       bool lost;
-       
-       /**
-        * source of randomness
-        */
-       randomizer_t *randomizer;
-       
-       /**
-        * signal to emit when transaction fails. As this transaction is used
-        * for CHILD_SA creation AND rekeying, we must emit different signals.
-        */
-       signal_t failsig;
-};
-
-/**
- * Implementation of transaction_t.get_message_id.
- */
-static u_int32_t get_message_id(private_create_child_sa_t *this)
-{
-       return this->message_id;
-}
-
-/**
- * Implementation of transaction_t.requested.
- */
-static u_int32_t requested(private_create_child_sa_t *this)
-{
-       return this->requested++;
-}
-
-/**
- * Implementation of create_child_sa_t.set_policy.
- */
-static void set_policy(private_create_child_sa_t *this, policy_t *policy)
-{
-       this->policy = policy;
-}
-
-/**
- * Implementation of create_child_sa_t.set_reqid.
- */
-static void set_reqid(private_create_child_sa_t *this, u_int32_t reqid)
-{
-       this->reqid = reqid;
-}
-
-/**
- * Implementation of create_child_sa_t.rekeys_child.
- */
-static void rekeys_child(private_create_child_sa_t *this, child_sa_t *child_sa)
-{
-       this->rekeyed_sa = child_sa;
-       this->failsig = CHILD_REKEY_FAILED;
-}
-
-/**
- * Implementation of create_child_sa_t.cancel.
- */
-static void cancel(private_create_child_sa_t *this)
-{
-       this->rekeyed_sa = NULL;
-       this->lost = TRUE;
-}
-
-/**
- * Build a notify message.
- */
-static void build_notify(notify_type_t type, chunk_t data, message_t *message, bool flush_message)
-{
-       notify_payload_t *notify;
-       
-       if (flush_message)
-       {
-               payload_t *payload;
-               iterator_t *iterator = message->get_payload_iterator(message);
-               while (iterator->iterate(iterator, (void**)&payload))
-               {
-                       payload->destroy(payload);
-                       iterator->remove(iterator);
-               }
-               iterator->destroy(iterator);
-       }
-       
-       notify = notify_payload_create();
-       notify->set_notify_type(notify, type);
-       notify->set_notification_data(notify, data);
-       message->add_payload(message, (payload_t*)notify);
-}
-
-/**
- * Implementation of transaction_t.get_request.
- */
-static status_t get_request(private_create_child_sa_t *this, message_t **result)
-{
-       message_t *request;
-       host_t *me, *other;
-       identification_t *my_id, *other_id;
-       
-       /* check if we already have built a message (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       /* check if we are not already rekeying */
-       if (this->rekeyed_sa)
-       {
-               SIG(CHILD_REKEY_START, "rekeying CHILD_SA");
-               
-               switch (this->rekeyed_sa->get_state(this->rekeyed_sa))
-               {
-                       case CHILD_REKEYING:
-                               SIG(CHILD_REKEY_FAILED,
-                                        "rekeying a CHILD_SA which is already rekeying, aborted");
-                               return FAILED;
-                       case CHILD_DELETING:
-                               SIG(CHILD_REKEY_FAILED,
-                                        "rekeying a CHILD_SA which is deleting, aborted");
-                               return FAILED;
-                       default:
-                               break;
-               }
-               this->rekeyed_sa->set_state(this->rekeyed_sa, CHILD_REKEYING);
-       }
-       else
-       {
-               SIG(CHILD_UP_START, "creating CHILD_SA");
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       my_id = this->ike_sa->get_my_id(this->ike_sa);
-       other_id = this->ike_sa->get_other_id(this->ike_sa);
-       
-       /* build the request */
-       request = message_create();
-       request->set_source(request, me->clone(me));
-       request->set_destination(request, other->clone(other));
-       request->set_exchange_type(request, CREATE_CHILD_SA);
-       request->set_request(request, TRUE);
-       request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
-       *result = request;
-       this->message = request;
-       
-       {       /* build SA payload */
-               sa_payload_t *sa_payload;
-               linked_list_t *proposals;
-               bool use_natt;
-               
-               /* get a policy, if we are rekeying */
-               if (this->rekeyed_sa)
-               {
-                       linked_list_t *my_ts, *other_ts;
-                       identification_t *my_id, *other_id;
-                       
-                       my_ts = this->rekeyed_sa->get_my_traffic_selectors(this->rekeyed_sa);
-                       other_ts = this->rekeyed_sa->get_other_traffic_selectors(this->rekeyed_sa);
-                       my_id = this->ike_sa->get_my_id(this->ike_sa);
-                       other_id = this->ike_sa->get_other_id(this->ike_sa);
-                       
-                       this->policy = charon->policies->get_policy(charon->policies,
-                                                                                                               my_id, other_id,
-                                                                                                               my_ts, other_ts,
-                                                                                                           me, other);
-                       
-                       this->reqid = this->rekeyed_sa->get_reqid(this->rekeyed_sa);
-                       
-                       if (this->policy == NULL)
-                       {
-                               SIG(IKE_REKEY_FAILED, "no policy found to rekey "
-                                        "CHILD_SA with reqid %d", this->reqid);
-                               return FAILED;
-                       }
-               }
-               
-               proposals = this->policy->get_proposals(this->policy);
-               use_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
-               this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
-                                                       this->policy->get_soft_lifetime(this->policy),
-                                                       this->policy->get_hard_lifetime(this->policy),
-                                                       this->policy->get_updown(this->policy),
-                                                       this->policy->get_hostaccess(this->policy),
-                                                       use_natt);
-               this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
-               if (this->child_sa->alloc(this->child_sa, proposals) != SUCCESS)
-               {
-                       SIG(this->failsig, "could not install CHILD_SA, CHILD_SA creation failed");
-                       return FAILED;
-               }
-               sa_payload = sa_payload_create_from_proposal_list(proposals);
-               proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
-               request->add_payload(request, (payload_t*)sa_payload);
-       }
-       
-       /* notify for transport/BEET mode, we propose it 
-        * independent of the traffic selectors */
-       switch (this->policy->get_mode(this->policy))
-       {
-               case MODE_TUNNEL:
-                       /* is the default */
-                       break;
-               case MODE_TRANSPORT:
-                       if (this->ike_sa->is_natt_enabled(this->ike_sa))
-                       {
-                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
-                       }
-                       else
-                       {
-                               build_notify(USE_TRANSPORT_MODE, chunk_empty, request, FALSE);
-                       }
-                       break;
-               case MODE_BEET:
-                       build_notify(USE_BEET_MODE, chunk_empty, request, FALSE);
-                       break;
-       }
-       
-       {       /* build the NONCE payload for us (initiator) */
-               nonce_payload_t *nonce_payload;
-               
-               if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer, 
-                       NONCE_SIZE, &this->nonce_i) != SUCCESS)
-               {
-                       SIG(this->failsig, "could not create nonce, CHILD_SA creation failed");
-                       return FAILED;
-               }
-               nonce_payload = nonce_payload_create();
-               nonce_payload->set_nonce(nonce_payload, this->nonce_i);
-               request->add_payload(request, (payload_t*)nonce_payload);
-       }
-       
-       {       /* build TSi payload */
-               linked_list_t *ts_list;
-               ts_payload_t *ts_payload;
-               
-               ts_list = this->policy->get_my_traffic_selectors(this->policy, me);
-               ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_list);
-               ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
-               request->add_payload(request, (payload_t*)ts_payload);
-       }
-       
-       {       /* build TSr payload */
-               linked_list_t *ts_list;
-               ts_payload_t *ts_payload;
-               
-               ts_list = this->policy->get_other_traffic_selectors(this->policy, other);
-               ts_payload = ts_payload_create_from_traffic_selectors(FALSE, ts_list);
-               ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
-               request->add_payload(request, (payload_t*)ts_payload);
-       }
-       
-       if (this->rekeyed_sa)
-       {       /* add REKEY_SA notify if we are rekeying */
-               notify_payload_t *notify;
-               protocol_id_t protocol;
-               
-               protocol = this->rekeyed_sa->get_protocol(this->rekeyed_sa);
-               notify = notify_payload_create_from_protocol_and_type(protocol, REKEY_SA);
-               notify->set_spi(notify, this->rekeyed_sa->get_spi(this->rekeyed_sa, TRUE));
-               request->add_payload(request, (payload_t*)notify);
-               
-               /* register us as rekeying to detect multiple rekeying */
-               this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa,
-                                                                                                  &this->public.transaction);
-       }
-       
-       this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
-       request->set_message_id(request, this->message_id);
-       
-       return SUCCESS;
-}
-
-/**
- * Handle all kind of notifys
- */
-static status_t process_notifys(private_create_child_sa_t *this, notify_payload_t *notify_payload)
-{
-       notify_type_t notify_type = notify_payload->get_notify_type(notify_payload);
-       
-       DBG2(DBG_IKE, "process notify type %N", notify_type_names, notify_type);
-
-       switch (notify_type)
-       {
-               case SINGLE_PAIR_REQUIRED:
-               {
-                       SIG(this->failsig, "received a SINGLE_PAIR_REQUIRED notify");
-                       return FAILED;
-               }
-               case TS_UNACCEPTABLE:
-               {
-                       SIG(this->failsig, "received TS_UNACCEPTABLE notify");
-                       return FAILED;
-               }
-               case NO_PROPOSAL_CHOSEN:
-               {
-                       SIG(this->failsig, "received NO_PROPOSAL_CHOSEN notify");
-                       return FAILED;
-               }
-               case USE_TRANSPORT_MODE:
-               {
-                       this->mode = MODE_TRANSPORT;
-                       return SUCCESS;
-               }
-               case USE_BEET_MODE:
-               {
-                       this->mode = MODE_BEET;
-                       return SUCCESS;
-               }
-               case REKEY_SA:
-               {
-                       u_int32_t spi;
-                       protocol_id_t protocol;
-                       
-                       protocol = notify_payload->get_protocol_id(notify_payload);
-                       switch (protocol)
-                       {
-                               case PROTO_AH:
-                               case PROTO_ESP:
-                                       spi = notify_payload->get_spi(notify_payload);
-                                       this->rekeyed_sa = this->ike_sa->get_child_sa(this->ike_sa, 
-                                                                                                                                 protocol, spi,
-                                                                                                                                 FALSE);
-                                       this->failsig = CHILD_REKEY_FAILED;
-                                       break;
-                               default:
-                                       break;
-                       }
-                       return SUCCESS;
-               }
-               default:
-               {
-                       if (notify_type < 16383)
-                       {
-                               SIG(this->failsig, "received %N notify error, CHILD_SA "
-                                        "creation failed", notify_type_names, notify_type);
-                               return FAILED;
-                       }
-                       else
-                       {
-                               DBG1(DBG_IKE, "received %N notify, ignored",
-                                        notify_type_names, notify_type);
-                               return SUCCESS;
-                       }
-               }
-       }
-}
-
-/**
- * Check a list of traffic selectors if any selector belongs to host
- */
-static bool ts_list_is_host(linked_list_t *list, host_t *host)
-{
-       traffic_selector_t *ts;
-       bool is_host = TRUE;
-       iterator_t *iterator = list->create_iterator(list, TRUE);
-       
-       while (is_host && iterator->iterate(iterator, (void**)&ts))
-       {
-               is_host = is_host && ts->is_host(ts, host);
-       }
-       iterator->destroy(iterator);
-       return is_host;
-}
-
-/**
- * Install a CHILD_SA for usage
- */
-static status_t install_child_sa(private_create_child_sa_t *this, bool initiator)
-{
-       prf_plus_t *prf_plus;
-       chunk_t seed;
-       status_t status;
-       
-       seed = chunk_alloc(this->nonce_i.len + this->nonce_r.len);
-       memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
-       memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
-       prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
-       chunk_free(&seed);
-       
-       if (initiator)
-       {
-               status = this->child_sa->update(this->child_sa, this->proposal,
-                                                                               this->mode, prf_plus);
-       }
-       else
-       {
-               status = this->child_sa->add(this->child_sa, this->proposal,
-                                                                        this->mode, prf_plus);
-       }
-       prf_plus->destroy(prf_plus);
-       if (status != SUCCESS)
-       {
-               return DESTROY_ME;
-       }
-       if (initiator)
-       {
-               status = this->child_sa->add_policies(this->child_sa, this->tsi,
-                                                                                         this->tsr, this->mode);
-       }
-       else
-       {
-               status = this->child_sa->add_policies(this->child_sa, this->tsr,
-                                                                                         this->tsi, this->mode);
-       }
-       if (status != SUCCESS)
-       {
-               return DESTROY_ME;
-       }
-       
-       /* add to IKE_SA, and remove from transaction */
-       this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
-       this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
-       this->child_sa = NULL;
-       return SUCCESS;
-}
-
-/**
- * Implementation of transaction_t.get_response.
- */
-static status_t get_response(private_create_child_sa_t *this, message_t *request, 
-                                                        message_t **result, transaction_t **next)
-{
-       host_t *me, *other;
-       identification_t *my_id, *other_id;
-       message_t *response;
-       status_t status;
-       iterator_t *payloads;
-       payload_t *payload;
-       sa_payload_t *sa_request = NULL;
-       nonce_payload_t *nonce_request = NULL;
-       ts_payload_t *tsi_request = NULL;
-       ts_payload_t *tsr_request = NULL;
-       nonce_payload_t *nonce_response;
-       
-       /* check if we already have built a response (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       my_id = this->ike_sa->get_my_id(this->ike_sa);
-       other_id = this->ike_sa->get_other_id(this->ike_sa);
-       this->message_id = request->get_message_id(request);
-       
-       /* set up response */
-       response = message_create();
-       response->set_source(response, me->clone(me));
-       response->set_destination(response, other->clone(other));
-       response->set_exchange_type(response, CREATE_CHILD_SA);
-       response->set_request(response, FALSE);
-       response->set_message_id(response, this->message_id);
-       response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
-       this->message = response;
-       *result = response;
-       
-       /* check message type */
-       if (request->get_exchange_type(request) != CREATE_CHILD_SA)
-       {
-               DBG1(DBG_IKE, "CREATE_CHILD_SA response of invalid type, aborted");
-               return FAILED;
-       }
-       
-       /* we do not allow the creation of new CHILDren/rekeying when IKE_SA is
-        * rekeying */
-       if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING ||
-               this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
-       {
-               build_notify(NO_ADDITIONAL_SAS, chunk_empty, response, TRUE);
-               DBG1(DBG_IKE, "unable to create new CHILD_SAs, as rekeying in progress");
-               return FAILED;
-       }
-       
-       /* Iterate over all payloads. */
-       payloads = request->get_payload_iterator(request);
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case SECURITY_ASSOCIATION:
-                               sa_request = (sa_payload_t*)payload;
-                               break;
-                       case NONCE:
-                               nonce_request = (nonce_payload_t*)payload;
-                               break;
-                       case TRAFFIC_SELECTOR_INITIATOR:
-                               tsi_request = (ts_payload_t*)payload;
-                               break;  
-                       case TRAFFIC_SELECTOR_RESPONDER:
-                               tsr_request = (ts_payload_t*)payload;
-                               break;
-                       case KEY_EXCHANGE:
-                       {
-                               u_int8_t dh_buffer[] = {0x00, 0x00}; /* MODP_NONE */
-                               chunk_t group = chunk_from_buf(dh_buffer);
-                               build_notify(INVALID_KE_PAYLOAD, group, response, TRUE);
-                               DBG1(DBG_IKE, "CREATE_CHILD_SA used PFS, sending INVALID_KE_PAYLOAD");
-                               return FAILED;
-                       }
-                       case NOTIFY:
-                       {
-                               status = process_notifys(this, (notify_payload_t*)payload);
-                               if (status != SUCCESS)
-                               {
-                                       payloads->destroy(payloads);
-                                       return status;
-                               }
-                               break;
-                       }
-                       default:
-                       {
-                               DBG1(DBG_IKE, "ignoring %N payload",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       
-       /* after processing the notify payloads, we know if this transaction is
-        * for rekeying or for a new CHILD_SA. We can emit the signals now. */
-       if (this->rekeyed_sa)
-       {
-               SIG(CHILD_REKEY_START, "rekeying CHILD_SA");
-       }
-       else
-       {
-               SIG(CHILD_UP_START, "creating CHILD_SA");
-       }
-       
-       /* check if we have all payloads */
-       if (!(sa_request && nonce_request && tsi_request && tsr_request))
-       {
-               build_notify(INVALID_SYNTAX, chunk_empty, response, TRUE);
-               SIG(this->failsig, "request message incomplete, no CHILD_SA created");
-               return FAILED;
-       }
-       
-       {       /* process nonce payload */
-               this->nonce_i = nonce_request->get_nonce(nonce_request);
-               if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer, 
-                       NONCE_SIZE, &this->nonce_r) != SUCCESS)
-               {
-                       build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
-                       SIG(this->failsig, "nonce generation failed, no CHILD_SA created");
-                       return FAILED;
-               }
-               nonce_response = nonce_payload_create();
-               nonce_response->set_nonce(nonce_response, this->nonce_r);
-       }
-       
-       {       /* get a policy and process traffic selectors */
-               identification_t *my_id, *other_id;
-               linked_list_t *my_ts, *other_ts;
-               
-               my_id = this->ike_sa->get_my_id(this->ike_sa);
-               other_id = this->ike_sa->get_other_id(this->ike_sa);
-               
-               my_ts = tsr_request->get_traffic_selectors(tsr_request);
-               other_ts = tsi_request->get_traffic_selectors(tsi_request);
-               
-               this->policy = charon->policies->get_policy(charon->policies,
-                                                                                                       my_id, other_id,
-                                                                                                       my_ts, other_ts,
-                                                                                                   me, other);
-               if (this->policy)
-               {
-                       this->tsr = this->policy->select_my_traffic_selectors(this->policy, my_ts, me);
-                       this->tsi = this->policy->select_other_traffic_selectors(this->policy, other_ts, other);
-               }
-               my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
-               other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
-               
-               if (this->policy == NULL)
-               {
-                       SIG(this->failsig, "no acceptable policy found, sending TS_UNACCEPTABLE notify");
-                       build_notify(TS_UNACCEPTABLE, chunk_empty, response, TRUE);
-                       return FAILED;
-               }
-       }
-       
-       {       /* process SA payload */
-               linked_list_t *proposal_list;
-               sa_payload_t *sa_response;
-               ts_payload_t *ts_response;
-               bool use_natt;
-               u_int32_t soft_lifetime, hard_lifetime;
-               
-               sa_response = sa_payload_create();
-               /* get proposals from request, and select one with ours */
-               proposal_list = sa_request->get_proposals(sa_request);
-               DBG2(DBG_IKE, "selecting proposals:");
-               this->proposal = this->policy->select_proposal(this->policy, proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-               
-               /* do we have a proposal? */
-               if (this->proposal == NULL)
-               {
-                       SIG(this->failsig, "CHILD_SA proposals unacceptable, sending NO_PROPOSAL_CHOSEN notify");
-                       build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
-                       return FAILED;
-               }
-               /* do we have traffic selectors? */
-               else if (this->tsi->get_count(this->tsi) == 0 || this->tsr->get_count(this->tsr) == 0)
-               {
-                       SIG(this->failsig, "CHILD_SA traffic selectors unacceptable, sending TS_UNACCEPTABLE notify");
-                       build_notify(TS_UNACCEPTABLE, chunk_empty, response, TRUE);
-                       return FAILED;
-               }
-               else
-               {       /* create child sa */
-                       if (this->rekeyed_sa)
-                       {
-                               this->reqid = this->rekeyed_sa->get_reqid(this->rekeyed_sa);
-                       }
-                       soft_lifetime = this->policy->get_soft_lifetime(this->policy);
-                       hard_lifetime = this->policy->get_hard_lifetime(this->policy);
-                       use_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
-                       this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
-                                                                                        soft_lifetime, hard_lifetime,
-                                                                                        this->policy->get_updown(this->policy),
-                                                                                        this->policy->get_hostaccess(this->policy),
-                                                                                        use_natt);
-                       this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
-                       
-                       /* check mode, and include notify into reply */
-                       switch (this->mode)
-                       {
-                               case MODE_TUNNEL:
-                                       /* is the default */
-                                       break;
-                               case MODE_TRANSPORT:
-                                       if (!ts_list_is_host(this->tsi, other) ||
-                                               !ts_list_is_host(this->tsr, me))
-                                       {
-                                               this->mode = MODE_TUNNEL;
-                                               DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
-                                       }
-                                       else if (this->ike_sa->is_natt_enabled(this->ike_sa))
-                                       {
-                                               this->mode = MODE_TUNNEL;
-                                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
-                                       }
-                                       else 
-                                       {
-                                               build_notify(USE_TRANSPORT_MODE, chunk_empty, response, FALSE);
-                                       }
-                                       break;
-                               case MODE_BEET:
-                                       if (!ts_list_is_host(this->tsi, NULL) ||
-                                               !ts_list_is_host(this->tsr, NULL))
-                                       {
-                                               this->mode = MODE_TUNNEL;
-                                               DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
-                                       }
-                                       else
-                                       {
-                                               build_notify(USE_BEET_MODE, chunk_empty, response, FALSE);
-                                       }
-                                       break;
-                       }
-                       
-                       if (install_child_sa(this, FALSE) != SUCCESS)
-                       {
-                               SIG(this->failsig, "installing CHILD_SA failed, sending NO_PROPOSAL_CHOSEN notify");
-                               build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
-                               return FAILED;
-                       }
-                       /* add proposal to sa payload */
-                       sa_response->add_proposal(sa_response, this->proposal);
-               }
-               response->add_payload(response, (payload_t*)sa_response);
-               
-               /* add nonce/ts payload after sa payload */
-               response->add_payload(response, (payload_t *)nonce_response);
-               ts_response = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
-               response->add_payload(response, (payload_t*)ts_response);
-               ts_response = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
-               response->add_payload(response, (payload_t*)ts_response);
-       }
-       /* CHILD_SA successfully created. If another transaction is already rekeying
-        * this SA, our lower nonce must be registered for a later nonce compare. */
-       if (this->rekeyed_sa)
-       {
-               private_create_child_sa_t *other;
-               
-               other = (private_create_child_sa_t*)
-                       this->rekeyed_sa->get_rekeying_transaction(this->rekeyed_sa);
-               if (other)
-               {
-                       /* store our lower nonce in the simultaneus transaction, it 
-                        * will later compare it against its nonces when it calls conclude().
-                        */
-                       if (memcmp(this->nonce_i.ptr, this->nonce_r.ptr,
-                               min(this->nonce_i.len, this->nonce_r.len)) < 0)
-                       {
-                               other->nonce_s = chunk_clone(this->nonce_i);
-                       }
-                       else
-                       {
-                               other->nonce_s = chunk_clone(this->nonce_r);
-                       }
-               }
-               else
-               {
-                       /* we only signal when no other transaction is rekeying */
-                       SIG(CHILD_REKEY_SUCCESS, "CHILD_SA rekeyed");
-               }
-               this->rekeyed_sa->set_state(this->rekeyed_sa, CHILD_REKEYING);
-       }
-       else
-       {
-               SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' created",
-                               this->policy->get_name(this->policy));
-       }
-       return SUCCESS;
-}
-
-/**
- * Implementation of transaction_t.conclude
- */
-static status_t conclude(private_create_child_sa_t *this, message_t *response, 
-                                                transaction_t **next)
-{
-       iterator_t *payloads;
-       payload_t *payload;
-       host_t *me, *other;
-       sa_payload_t *sa_payload = NULL;
-       nonce_payload_t *nonce_payload = NULL;
-       ts_payload_t *tsi_payload = NULL;
-       ts_payload_t *tsr_payload = NULL;
-       status_t status;
-       child_sa_t *new_child = NULL;
-       delete_child_sa_t *delete_child_sa;
-       
-       /* check message type */
-       if (response->get_exchange_type(response) != CREATE_CHILD_SA)
-       {
-               SIG(this->failsig, "CREATE_CHILD_SA response of invalid type, aborting");
-               return FAILED;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       
-       /* Iterate over all payloads to collect them */
-       payloads = response->get_payload_iterator(response);
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case SECURITY_ASSOCIATION:
-                               sa_payload = (sa_payload_t*)payload;
-                               break;
-                       case NONCE:
-                               nonce_payload = (nonce_payload_t*)payload;
-                               break;
-                       case TRAFFIC_SELECTOR_INITIATOR:
-                               tsi_payload = (ts_payload_t*)payload;
-                               break;  
-                       case TRAFFIC_SELECTOR_RESPONDER:
-                               tsr_payload = (ts_payload_t*)payload;
-                               break;
-                       case NOTIFY:
-                       {
-                               status = process_notifys(this, (notify_payload_t*)payload);
-                               if (status != SUCCESS)
-                               {
-                                       payloads->destroy(payloads);
-                                       return status;
-                               }
-                               break;
-                       }
-                       default:
-                       {
-                               DBG1(DBG_IKE, "ignoring %N payload",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       
-       if (!(sa_payload && nonce_payload && tsi_payload && tsr_payload))
-       {
-               SIG(this->failsig, "response message incomplete, no CHILD_SA built");
-               return FAILED;
-       }
-       
-       {       /* process NONCE payload  */
-               this->nonce_r = nonce_payload->get_nonce(nonce_payload);
-       }
-       
-       {       /* process traffic selectors for us */
-               linked_list_t *ts_received = tsi_payload->get_traffic_selectors(tsi_payload);
-               this->tsi = this->policy->select_my_traffic_selectors(this->policy, ts_received, me);
-               ts_received->destroy_offset(ts_received, offsetof(traffic_selector_t, destroy));
-       }
-       
-       {       /* process traffic selectors for other */
-               linked_list_t *ts_received = tsr_payload->get_traffic_selectors(tsr_payload);
-               this->tsr = this->policy->select_other_traffic_selectors(this->policy, ts_received, other);
-               ts_received->destroy_offset(ts_received, offsetof(traffic_selector_t, destroy));
-       }
-       
-       {       /* process sa payload */
-               linked_list_t *proposal_list;
-               
-               proposal_list = sa_payload->get_proposals(sa_payload);
-               /* we have to re-check here if other's selection is valid */
-               this->proposal = this->policy->select_proposal(this->policy, proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-               
-               /* everything fine to create CHILD? */
-               if (this->proposal == NULL ||
-                       this->tsi->get_count(this->tsi) == 0 ||
-                       this->tsr->get_count(this->tsr) == 0)
-               {
-                       SIG(this->failsig, "CHILD_SA negotiation failed, no CHILD_SA built");
-                       return FAILED;
-               }
-               
-               /* check mode if it is acceptable */
-               switch (this->mode)
-               {
-                       case MODE_TUNNEL:
-                               /* is the default */
-                               break;
-                       case MODE_TRANSPORT:
-                               /* TODO: we should close the CHILD_SA if negotiated
-                                * mode is not acceptable for us */
-                               if (!ts_list_is_host(this->tsi, me) ||
-                                       !ts_list_is_host(this->tsr, other))
-                               {
-                                       this->mode = MODE_TUNNEL;
-                                       DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
-                               }
-                               else if (this->ike_sa->is_natt_enabled(this->ike_sa))
-                               {
-                                       this->mode = MODE_TUNNEL;
-                                       DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
-                               }
-                               break;
-                       case MODE_BEET:
-                               if (!ts_list_is_host(this->tsi, NULL) ||
-                                       !ts_list_is_host(this->tsr, NULL))
-                               {
-                                       this->mode = MODE_TUNNEL;
-                                       DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
-                               }
-                               break;
-               }
-               
-               new_child = this->child_sa;
-               if (install_child_sa(this, TRUE) != SUCCESS)
-               {
-                       SIG(this->failsig, "installing CHILD_SA failed, no CHILD_SA built");
-                       return FAILED;
-               }
-       }
-       /* CHILD_SA successfully created. If the other peer initiated rekeying
-        * in the meantime, we detect this by comparing the rekeying_transaction
-        * of the SA. If it changed, we are not alone. Then we must compare the nonces.
-        * If no simultaneous rekeying is going on, we just initiate the delete of
-        * the superseded SA. */
-       if (this->rekeyed_sa)
-       {       
-               /* rekeying finished, update SA status */
-               this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, NULL);
-               
-               if (this->nonce_s.ptr)
-               {       /* simlutaneous rekeying is going on, not so good */
-                       chunk_t this_lowest;
-                       
-                       /* first get our lowest nonce */
-                       if (memcmp(this->nonce_i.ptr, this->nonce_r.ptr, 
-                               min(this->nonce_i.len, this->nonce_r.len)) < 0)
-                       {
-                               this_lowest = this->nonce_i;
-                       }
-                       else
-                       {
-                               this_lowest = this->nonce_r;
-                       }
-                       /* then compare against other lowest nonce */
-                       if (memcmp(this_lowest.ptr, this->nonce_s.ptr, 
-                               min(this_lowest.len, this->nonce_s.len)) < 0)
-                       {
-                               DBG1(DBG_IKE, "detected simultaneous CHILD_SA rekeying, deleting ours");
-                               this->lost = TRUE;
-                       }
-                       else
-                       {
-                               DBG1(DBG_IKE, "detected simultaneous CHILD_SA rekeying, but ours is preferred");
-                       }
-               }
-               /* delete the old SA if we have won the rekeying nonce compare*/
-               if (!this->lost)
-               {
-                       delete_child_sa = delete_child_sa_create(this->ike_sa);
-                       delete_child_sa->set_child_sa(delete_child_sa, this->rekeyed_sa);
-                       *next = (transaction_t*)delete_child_sa;
-               }
-               /* we send a rekey SUCCESS signal in any case. If the other transaction 
-               * detected our transaction, it did not send a signal. We do it for it. */
-               SIG(CHILD_REKEY_SUCCESS, "CHILD_SA rekeyed");
-       }
-       else
-       {
-               SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' created",
-                               this->policy->get_name(this->policy));
-       }
-       if (this->lost)
-       {
-               /* we have lost simlutaneous rekeying, delete the CHILD_SA we just have created */
-               delete_child_sa = delete_child_sa_create(this->ike_sa);
-               delete_child_sa->set_child_sa(delete_child_sa, new_child);
-               *next = (transaction_t*)delete_child_sa;
-       }
-       return SUCCESS;
-}
-
-/**
- * implements transaction_t.destroy
- */
-static void destroy(private_create_child_sa_t *this)
-{
-       DESTROY_IF(this->message);
-       DESTROY_IF(this->proposal);
-       DESTROY_IF(this->child_sa);
-       DESTROY_IF(this->policy);
-       if (this->tsi)
-       {
-               this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
-       }
-       if (this->tsr)
-       {
-               this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
-       }
-       chunk_free(&this->nonce_i);
-       chunk_free(&this->nonce_r);
-       chunk_free(&this->nonce_s);
-       this->randomizer->destroy(this->randomizer);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa)
-{
-       private_create_child_sa_t *this = malloc_thing(private_create_child_sa_t);
-       
-       /* transaction interface functions */
-       this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
-       this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
-       this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
-       this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
-       this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
-       this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
-       
-       /* public functions */
-       this->public.set_policy = (void(*)(create_child_sa_t*,policy_t*))set_policy;
-       this->public.set_reqid = (void(*)(create_child_sa_t*,u_int32_t))set_reqid;
-       this->public.rekeys_child = (void(*)(create_child_sa_t*,child_sa_t*))rekeys_child;
-       this->public.cancel = (void(*)(create_child_sa_t*))cancel;
-       
-       /* private data */
-       this->ike_sa = ike_sa;
-       this->message_id = 0;
-       this->message = NULL;
-       this->requested = 0;
-       this->rekey_spi = 0;
-       this->reqid = 0;
-       this->nonce_i = chunk_empty;
-       this->nonce_r = chunk_empty;
-       this->nonce_s = chunk_empty;
-       this->child_sa = NULL;
-       this->rekeyed_sa = NULL;
-       this->lost = FALSE;
-       this->proposal = NULL;
-       this->policy = NULL;
-       this->tsi = NULL;
-       this->tsr = NULL;
-       this->mode = MODE_TUNNEL;
-       this->randomizer = randomizer_create();
-       this->failsig = CHILD_UP_FAILED;
-       
-       return &this->public;
-}
diff --git a/src/charon/sa/transactions/create_child_sa.h b/src/charon/sa/transactions/create_child_sa.h
deleted file mode 100644 (file)
index 8ce72e1..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * @file create_child_sa.h
- * 
- * @brief Interface of transaction create_child_sa.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#ifndef CREATE_CHILD_SA_H_
-#define CREATE_CHILD_SA_H_
-
-typedef struct create_child_sa_t create_child_sa_t;
-
-#include <sa/transactions/transaction.h>
-#include <sa/ike_sa.h>
-#include <sa/child_sa.h>
-
-/**
- * @brief A transaction to create a new or rekey an existing CHILD_SA.
- *
- * If the CHILD_SA is intended to create a new CHILD_SA, set the policy
- * with set_policy(). If it is intended to rekey an existing CHILD_SA,
- * set the appropriate CHILD_SA with rekeys_child().
- *
- * Rekeying of an CHILD_SA works the same way as creating a new one,
- * but includes an additional REKEY_SA notify and deletes the old
- * one (in a separate transaction).
- * 
- *                     __________  _________
- *                       Cyq     \/    Czq  
- *                     __________/\_________
- *              detect __________  _________ detect
- *                       Czp     \/    Czp  
- * compare nonces, won __________/\_________ compare nonces, lost
- *                                          
- *        delete old   __________           
- *                       Dxq     \__________
- *                                __________
- *                     __________/    Dxp   
- *                                __________ delete created
- *                     __________/    Dzq   
- *                     __________           
- *                       Dzp     \__________
- * 
- *
- * @b Constructors:
- *  - create_child_sa_create()
- *  - transaction_create() with the appropriate message
- *
- * @ingroup transactions
- */
-struct create_child_sa_t {
-       
-       /**
-        * The transaction_t interface.
-        */
-       transaction_t transaction;
-       
-       /**
-        * @brief Set the policy to use for creating a new CHILD_SA.
-        *
-        * @param this          calling object
-        * @param policy        policy for CHILD_SA
-        */
-       void (*set_policy) (create_child_sa_t* this, policy_t *policy);
-
-       /**
-        * @brief Set the reqid used for CHILD_SA setup.
-        *
-        * If we acquire, we must use the same reqid as the
-        * installed policy.
-        * 
-        * @param this                  calling object
-        * @param reqid                 reqid to use for the CHILD_SA
-        */
-       void (*set_reqid) (create_child_sa_t* this, u_int32_t reqid);
-       
-       /**
-        * @brief Set the CHILD_SA which gets rekeyed by the new one.
-        *
-        * @param this          calling object
-        * @param child_sa      CHILD_SA to rekey
-        */
-       void (*rekeys_child) (create_child_sa_t* this, child_sa_t *child_sa);
-       
-       /**
-        * @brief Cancel the request.
-        *
-        * Cancelling the request will set a flag in the transaction. When
-        * the response for the transaction is received, the created CHILD_SA
-        * gets deleted afterwards.
-        *
-        * @param this          calling object
-        * @param child_sa      CHILD_SA to rekey
-        */
-       void (*cancel) (create_child_sa_t* this);
-};
-
-/**
- * @brief Create a new transaction which creates/rekeys CHILD_SAs.
- *
- * @param ike_sa               assigned IKE_SA
- * @return                             created create_child_sa transaction
- *
- * @ingroup transactions
- */
-create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa);
-
-#endif /* CREATE_CHILD_SA_H_ */
diff --git a/src/charon/sa/transactions/dead_peer_detection.c b/src/charon/sa/transactions/dead_peer_detection.c
deleted file mode 100644 (file)
index 390ce34..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/**
- * @file dead_peer_detection.c
- *
- * @brief Implementation of the dead_peer_detection transaction.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#include "dead_peer_detection.h"
-
-#include <daemon.h>
-
-
-typedef struct private_dead_peer_detection_t private_dead_peer_detection_t;
-
-/**
- * Private members of a dead_peer_detection_t object..
- */
-struct private_dead_peer_detection_t {
-       
-       /**
-        * Public methods and transaction_t interface.
-        */
-       dead_peer_detection_t public;
-       
-       /**
-        * Assigned IKE_SA.
-        */
-       ike_sa_t *ike_sa;
-       
-       /**
-        * Message sent by our peer, if already generated
-        */
-       message_t *message;
-       
-       /**
-        * Message ID this transaction uses
-        */
-       u_int32_t message_id;
-       
-       /**
-        * Times we did send the request
-        */
-       u_int32_t requested;
-};
-
-/**
- * Implementation of transaction_t.get_message_id.
- */
-static u_int32_t get_message_id(private_dead_peer_detection_t *this)
-{
-       return this->message_id;
-}
-
-/**
- * Implementation of transaction_t.requested.
- */
-static u_int32_t requested(private_dead_peer_detection_t *this)
-{
-       return this->requested++;
-}
-
-/**
- * Implementation of transaction_t.get_request.
- */
-static status_t get_request(private_dead_peer_detection_t *this, message_t **result)
-{
-       message_t *request;
-       host_t *me, *other;
-       
-       /* check if we already have built a message (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       
-       /* build the request */
-       request = message_create();
-       request->set_source(request, me->clone(me));
-       request->set_destination(request, other->clone(other));
-       request->set_exchange_type(request, INFORMATIONAL);
-       request->set_request(request, TRUE);
-       this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
-       request->set_message_id(request, this->message_id);
-       request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
-       /* apply for caller */
-       *result = request;
-       /* store for retransmission */
-       this->message = request;
-       
-       return SUCCESS;
-}
-
-/**
- * Implementation of transaction_t.get_response.
- */
-static status_t get_response(private_dead_peer_detection_t *this, message_t *request, 
-                                                        message_t **result, transaction_t **next)
-{
-       host_t *me, *other;
-       message_t *response;
-       
-       /* check if we already have built a response (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       this->message_id = request->get_message_id(request);
-       
-       /* set up response */
-       response = message_create();
-       response->set_source(response, me->clone(me));
-       response->set_destination(response, other->clone(other));
-       response->set_exchange_type(response, INFORMATIONAL);
-       response->set_request(response, FALSE);
-       response->set_message_id(response, this->message_id);
-       response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
-       this->message = response;
-       *result = response;
-       
-       return SUCCESS;
-}
-
-
-/**
- * Implementation of transaction_t.conclude
- */
-static status_t conclude(private_dead_peer_detection_t *this, message_t *response, 
-                                                transaction_t **transaction)
-{
-       return SUCCESS;
-}
-
-/**
- * implements transaction_t.destroy
- */
-static void destroy(private_dead_peer_detection_t *this)
-{
-       DESTROY_IF(this->message);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-dead_peer_detection_t *dead_peer_detection_create(ike_sa_t *ike_sa)
-{
-       private_dead_peer_detection_t *this = malloc_thing(private_dead_peer_detection_t);
-       
-       /* transaction interface functions */
-       this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
-       this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
-       this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
-       this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
-       this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
-       this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
-       
-       /* private data */
-       this->ike_sa = ike_sa;
-       this->message_id = 0;
-       this->message = NULL;
-       this->requested = 0;
-       
-       return &this->public;
-}
diff --git a/src/charon/sa/transactions/dead_peer_detection.h b/src/charon/sa/transactions/dead_peer_detection.h
deleted file mode 100644 (file)
index 78d7b9b..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * @file dead_peer_detection.h
- * 
- * @brief Interface of transaction dead_peer_detection.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-
-#ifndef DEAD_PEER_DETECTION_H_
-#define DEAD_PEER_DETECTION_H_
-
-typedef struct dead_peer_detection_t dead_peer_detection_t;
-
-#include <sa/ike_sa.h>
-#include <sa/transactions/transaction.h>
-
-/**
- * @brief A transaction used to detect dead peers.
- *
- * In IKEv2, dead peer detection is done using empty
- * informational messages. These must be acknowledged.
- *
- * @ingroup transactions
- */
-struct dead_peer_detection_t {
-       
-       /**
-        * The transaction_t interface.
-        */
-       transaction_t transaction;
-};
-
-/**
- * @brief Create a new transaction which detects dead peers.
- *
- * @param ike_sa               assigned IKE_SA
- * @return                             created dead_peer_detection transaction
- *
- * @ingroup transactions
- */
-dead_peer_detection_t *dead_peer_detection_create(ike_sa_t *ike_sa);
-
-#endif /* DEAD_PEER_DETECTION_H_ */
diff --git a/src/charon/sa/transactions/delete_child_sa.c b/src/charon/sa/transactions/delete_child_sa.c
deleted file mode 100644 (file)
index 7ec3320..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/**
- * @file delete_child_sa.c
- *
- * @brief Implementation of the delete_child_sa transaction.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#include "delete_child_sa.h"
-
-#include <daemon.h>
-#include <encoding/payloads/delete_payload.h>
-#include <sa/transactions/create_child_sa.h>
-
-
-typedef struct private_delete_child_sa_t private_delete_child_sa_t;
-
-/**
- * Private members of a delete_child_sa_t object..
- */
-struct private_delete_child_sa_t {
-       
-       /**
-        * Public methods and transaction_t interface.
-        */
-       delete_child_sa_t public;
-       
-       /**
-        * Assigned IKE_SA.
-        */
-       ike_sa_t *ike_sa;
-       
-       /**
-        * Message sent by our peer, if already generated
-        */
-       message_t *message;
-       
-       /**
-        * Message ID this transaction uses
-        */
-       u_int32_t message_id;
-       
-       /**
-        * Times we did send the request
-        */
-       u_int32_t requested;
-       
-       /**
-        * CHILD SA to delete
-        */
-       child_sa_t *child_sa;
-};
-
-/**
- * Implementation of transaction_t.get_message_id.
- */
-static u_int32_t get_message_id(private_delete_child_sa_t *this)
-{
-       return this->message_id;
-}
-
-/**
- * Implementation of transaction_t.requested.
- */
-static u_int32_t requested(private_delete_child_sa_t *this)
-{
-       return this->requested++;
-}
-
-/**
- * Implementation of delete_child_sa_t.set_child_sa.
- */
-static void set_child_sa(private_delete_child_sa_t *this, child_sa_t *child_sa)
-{
-       this->child_sa = child_sa;
-}
-
-/**
- * Implementation of transaction_t.get_request.
- */
-static status_t get_request(private_delete_child_sa_t *this, message_t **result)
-{
-       message_t *request;
-       host_t *me, *other;
-       
-       /* check if we already have built a message (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       
-       /* build the request */
-       request = message_create();
-       request->set_source(request, me->clone(me));
-       request->set_destination(request, other->clone(other));
-       request->set_exchange_type(request, INFORMATIONAL);
-       request->set_request(request, TRUE);
-       this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
-       request->set_message_id(request, this->message_id);
-       request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
-       *result = request;
-       this->message = request;
-       
-       {       /* add delete payload */
-               delete_payload_t *delete_payload;
-               protocol_id_t protocol;
-               u_int32_t spi;
-               
-               protocol = this->child_sa->get_protocol(this->child_sa);
-               spi = this->child_sa->get_spi(this->child_sa, TRUE);
-               delete_payload = delete_payload_create(protocol);
-               
-               DBG1(DBG_IKE, "created DELETE payload for %N CHILD_SA with SPI 0x%x",
-                        protocol_id_names, protocol, htonl(spi));
-               delete_payload->add_spi(delete_payload, spi);
-               request->add_payload(request, (payload_t*)delete_payload);
-       }
-       
-       this->child_sa->set_state(this->child_sa, CHILD_DELETING);
-       
-       return SUCCESS;
-}
-
-/**
- * process a delete payload
- */
-static status_t process_delete(private_delete_child_sa_t *this, delete_payload_t *delete_request, message_t *response)
-{
-       protocol_id_t protocol;
-       u_int32_t spi;
-       iterator_t *iterator;
-       delete_payload_t *delete_response = NULL;
-       
-       /* get requested CHILD */
-       protocol = delete_request->get_protocol_id(delete_request);
-       if (protocol != PROTO_ESP && protocol != PROTO_AH)
-       {
-               DBG1(DBG_IKE, "CHILD_SA delete response contained unexpected protocol");
-               return FAILED;
-       }
-       
-       /* prepare response payload */
-       if (response)
-       {
-               delete_response = delete_payload_create(protocol);
-               response->add_payload(response, (payload_t*)delete_response);
-       }
-
-       iterator = delete_request->create_spi_iterator(delete_request);
-       while (iterator->iterate(iterator, (void**)&spi))
-       {
-               child_sa_t *child_sa;
-               
-               child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE);
-               
-               if (child_sa != NULL)
-               {
-                       create_child_sa_t *rekey;
-                       
-                       child_sa->set_state(child_sa, CHILD_DELETING);
-                       
-                       DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, deleting",
-                                protocol_id_names, protocol, ntohl(spi));
-                       
-                       rekey = (create_child_sa_t*)child_sa->get_rekeying_transaction(child_sa);
-                       if (rekey)
-                       {
-                               /* we have received a delete for an SA which we are still rekeying.
-                                * this means we have lost the nonce comparison, and the rekeying
-                                * will fail. We set a flag in the transaction for this special case.
-                                */
-                               rekey->cancel(rekey);
-                       }
-                       /* delete it, with inbound spi */
-                       spi = child_sa->get_spi(child_sa, TRUE);
-                       this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
-                       /* add delete response to message, if we are responding */
-                       if (response)
-                       {
-                               delete_response->add_spi(delete_response, spi);
-                       }
-               }
-               else
-               {
-                       DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, but no such SA",
-                                protocol_id_names, protocol, ntohl(spi));
-               }
-       }
-       iterator->destroy(iterator);
-       return SUCCESS;
-}
-
-/**
- * Implementation of transaction_t.get_response.
- */
-static status_t get_response(private_delete_child_sa_t *this, message_t *request, 
-                                                        message_t **result, transaction_t **next)
-{
-       host_t *me, *other;
-       message_t *response;
-       iterator_t *payloads;
-       payload_t *payload;
-       
-       /* check if we already have built a response (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       this->message_id = request->get_message_id(request);
-       
-       /* set up response */
-       response = message_create();
-       response->set_source(response, me->clone(me));
-       response->set_destination(response, other->clone(other));
-       response->set_exchange_type(response, INFORMATIONAL);
-       response->set_request(response, FALSE);
-       response->set_message_id(response, this->message_id);
-       response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
-       this->message = response;
-       *result = response;
-       
-       if (request->get_exchange_type(request) != INFORMATIONAL)
-       {
-               DBG1(DBG_IKE, "INFORMATIONAL response of invalid type, aborting");
-               return FAILED;
-       }
-       
-       /* we can't handle a delete for a CHILD when we are rekeying. There
-        * is no proper solution for this. We send a empty informational response,
-        * as described in ikev2-clarifications draft */
-       if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING ||
-               this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
-       {
-               DBG1(DBG_IKE, "unable to delete CHILD_SA, as rekeying in progress");
-               return FAILED;
-       }
-       
-       /* iterate over all payloads */
-       payloads = request->get_payload_iterator(request);      
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case DELETE:
-                       {
-                               process_delete(this, (delete_payload_t*)payload, response);
-                               break;
-                       }
-                       default:
-                       {
-                               DBG2(DBG_IKE, "ignoring payload %N",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       return SUCCESS;
-}
-
-/**
- * Implementation of transaction_t.conclude
- */
-static status_t conclude(private_delete_child_sa_t *this, message_t *response, 
-                                                transaction_t **transaction)
-{
-       iterator_t *payloads;
-       payload_t *payload;
-       
-       /* check message type */
-       if (response->get_exchange_type(response) != INFORMATIONAL)
-       {
-               DBG1(DBG_IKE, "INFORMATIONAL response of invalid type, aborting");
-               return FAILED;
-       }
-       
-       /* iterate over all payloads */
-       payloads = response->get_payload_iterator(response);
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case DELETE:
-                       {
-                               process_delete(this, (delete_payload_t*)payload, NULL);
-                               break;
-                       }
-                       default:
-                       {
-                               DBG1(DBG_IKE, "ignoring payload %N",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       return SUCCESS;
-}
-
-/**
- * implements transaction_t.destroy
- */
-static void destroy(private_delete_child_sa_t *this)
-{
-       DESTROY_IF(this->message);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-delete_child_sa_t *delete_child_sa_create(ike_sa_t *ike_sa)
-{
-       private_delete_child_sa_t *this = malloc_thing(private_delete_child_sa_t);
-       
-       /* transaction interface functions */
-       this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
-       this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
-       this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
-       this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
-       this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
-       this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
-       
-       /* publics */
-       this->public.set_child_sa = (void(*)(delete_child_sa_t*,child_sa_t*))set_child_sa;
-       
-       /* private data */
-       this->ike_sa = ike_sa;
-       this->message_id = 0;
-       this->message = NULL;
-       this->requested = 0;
-       
-       return &this->public;
-}
diff --git a/src/charon/sa/transactions/delete_child_sa.h b/src/charon/sa/transactions/delete_child_sa.h
deleted file mode 100644 (file)
index b4cd8ea..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * @file delete_child_sa.h
- * 
- * @brief Interface of transaction delete_child_sa.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-
-#ifndef DELETE_CHILD_SA_H_
-#define DELETE_CHILD_SA_H_
-
-typedef struct delete_child_sa_t delete_child_sa_t;
-
-#include <sa/ike_sa.h>
-#include <sa/transactions/transaction.h>
-
-
-/**
- * @brief A transaction used to delete a CHILD_SA.
- *
- * @b Constructors:
- *  - delete_child_sa_create()
- *  - transaction_create() with the appropriate message
- *
- * @ingroup transactions
- */
-struct delete_child_sa_t {
-       
-       /**
-        * The transaction_t interface.
-        */
-       transaction_t transaction;
-       
-       /**
-        * @brief Set the CHILD_SA to delete.
-        *
-        * @param this          calling object
-        * @param child_sa      CHILD_SA to rekey
-        */
-       void (*set_child_sa) (delete_child_sa_t* this, child_sa_t *child_sa);
-};
-
-/**
- * @brief Create a new transaction which deletes a CHILD_SA.
- *
- * @param ike_sa               assigned IKE_SA
- * @return                             created delete_child_sa transaction
- *
- * @ingroup transactions
- */
-delete_child_sa_t *delete_child_sa_create(ike_sa_t *ike_sa);
-
-#endif /* DELETE_CHILD_SA_H_ */
diff --git a/src/charon/sa/transactions/delete_ike_sa.c b/src/charon/sa/transactions/delete_ike_sa.c
deleted file mode 100644 (file)
index 26817bb..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-/**
- * @file delete_ike_sa.c
- *
- * @brief Implementation of the delete_ike_sa transaction.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#include "delete_ike_sa.h"
-
-#include <daemon.h>
-#include <encoding/payloads/delete_payload.h>
-
-typedef struct private_delete_ike_sa_t private_delete_ike_sa_t;
-
-/**
- * Private members of a delete_ike_sa_t object..
- */
-struct private_delete_ike_sa_t {
-       
-       /**
-        * Public methods and transaction_t interface.
-        */
-       delete_ike_sa_t public;
-       
-       /**
-        * Assigned IKE_SA.
-        */
-       ike_sa_t *ike_sa;
-       
-       /**
-        * Message sent by our peer, if already generated
-        */
-       message_t *message;
-       
-       /**
-        * Message ID this transaction uses
-        */
-       u_int32_t message_id;
-       
-       /**
-        * Times we did send the request
-        */
-       u_int32_t requested;
-       
-       /**
-        * is the IKE_SA redundant and gets deleted without further notification?
-        */
-       bool redundant;
-};
-
-/**
- * Implementation of transaction_t.get_message_id.
- */
-static u_int32_t get_message_id(private_delete_ike_sa_t *this)
-{
-       return this->message_id;
-}
-
-/**
- * Implementation of transaction_t.requested.
- */
-static u_int32_t requested(private_delete_ike_sa_t *this)
-{
-       return this->requested++;
-}
-
-/**
- * Implementation of transaction_t.get_request.
- */
-static status_t get_request(private_delete_ike_sa_t *this, message_t **result)
-{
-       message_t *request;
-       host_t *me, *other;
-       delete_payload_t *delete_payload;
-       
-       /* check if we already have built a message (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       this->redundant = this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING;
-       
-       if (!this->redundant)
-       {
-               SIG(IKE_DOWN_START, "deleting IKE_SA");
-       }
-       
-       /* build the request */
-       request = message_create();
-       request->set_source(request, me->clone(me));
-       request->set_destination(request, other->clone(other));
-       request->set_exchange_type(request, INFORMATIONAL);
-       request->set_request(request, TRUE);
-       this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
-       request->set_message_id(request, this->message_id);
-       request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
-       /* apply for caller */
-       *result = request;
-       /* store for retransmission */
-       this->message = request;
-       
-       delete_payload = delete_payload_create(PROTO_IKE);
-       request->add_payload(request, (payload_t*)delete_payload);
-       
-       /* transit to state SA_DELETING */
-       this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
-       
-       return SUCCESS;
-}
-
-/**
- * Implementation of transaction_t.get_response.
- */
-static status_t get_response(private_delete_ike_sa_t *this, message_t *request, 
-                                                        message_t **result, transaction_t **next)
-{
-       host_t *me, *other;
-       message_t *response;
-       iterator_t *payloads;
-       payload_t *payload;
-       delete_payload_t *delete_request = NULL;
-       
-       /* check if we already have built a response (retransmission) 
-        * this only happens in special simultanous transaction cases,
-        * as we delete the IKE_SA after the response is sent. */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       this->message_id = request->get_message_id(request);
-       this->redundant = this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING;
-       
-       if (!this->redundant)
-       {
-               SIG(IKE_DOWN_START, "deleting IKE_SA");
-       }
-       
-       /* set up response */
-       response = message_create();
-       response->set_source(response, me->clone(me));
-       response->set_destination(response, other->clone(other));
-       response->set_exchange_type(response, INFORMATIONAL);
-       response->set_request(response, FALSE);
-       response->set_message_id(response, this->message_id);
-       response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
-       this->message = response;
-       *result = response;
-       
-       /* check message type */
-       if (request->get_exchange_type(request) != INFORMATIONAL)
-       {
-               if (!this->redundant)
-               {
-                       SIG(IKE_DOWN_FAILED, "INFORMATIONAL response of invalid type, deleting IKE_SA");
-               }
-               return DESTROY_ME;
-       }
-       
-       /* iterate over all payloads */
-       payloads = request->get_payload_iterator(request);      
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case DELETE:
-                       {
-                               delete_request = (delete_payload_t *)payload;
-                               break;
-                       }
-                       default:
-                       {
-                               DBG1(DBG_IKE, "ignoring payload %N",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       
-       if (delete_request && 
-               delete_request->get_protocol_id(delete_request) == PROTO_IKE)
-       {
-               DBG1(DBG_IKE, "DELETE request for IKE_SA received, deleting IKE_SA");
-       }
-       else
-       {
-               /* should not happen, as we preparsed this at transaction construction */
-               DBG1(DBG_IKE, "received a weird DELETE request for IKE_SA, deleting anyway");
-       }
-       if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
-       {
-               /* if we are already deleting an IKE_SA, we do not destroy. We wait
-                * until we get the response for our initiated delete. */
-               return SUCCESS;
-       }
-       this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
-       if (!this->redundant)
-       {
-               SIG(IKE_DOWN_SUCCESS, "IKE_SA deleted on request");
-       }
-       return DESTROY_ME;
-}
-
-
-/**
- * Implementation of transaction_t.conclude
- */
-static status_t conclude(private_delete_ike_sa_t *this, message_t *response, 
-                                                transaction_t **transaction)
-{
-       /* check message type */
-       if (response->get_exchange_type(response) != INFORMATIONAL)
-       {
-               if (!this->redundant)
-               {
-                       SIG(IKE_DOWN_FAILED, "INFORMATIONAL response of invalid type, deleting IKE_SA");
-               }
-               return DESTROY_ME;
-       }
-       /* this is only an acknowledge. We can't do anything here, but delete
-        * the IKE_SA. */
-       if (!this->redundant)
-       {
-               SIG(IKE_DOWN_SUCCESS, "IKE_SA deleted");
-       }
-       return DESTROY_ME;
-}
-
-/**
- * implements transaction_t.destroy
- */
-static void destroy(private_delete_ike_sa_t *this)
-{
-       DESTROY_IF(this->message);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-delete_ike_sa_t *delete_ike_sa_create(ike_sa_t *ike_sa)
-{
-       private_delete_ike_sa_t *this = malloc_thing(private_delete_ike_sa_t);
-       
-       /* transaction interface functions */
-       this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
-       this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
-       this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
-       this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
-       this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
-       this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
-       
-       /* private data */
-       this->ike_sa = ike_sa;
-       this->message_id = 0;
-       this->message = NULL;
-       this->requested = 0;
-       this->redundant = FALSE;
-       
-       return &this->public;
-}
diff --git a/src/charon/sa/transactions/delete_ike_sa.h b/src/charon/sa/transactions/delete_ike_sa.h
deleted file mode 100644 (file)
index 139e65e..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * @file delete_ike_sa.h
- * 
- * @brief Interface of transaction delete_ike_sa.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-
-#ifndef DELETE_IKE_SA_H_
-#define DELETE_IKE_SA_H_
-
-typedef struct delete_ike_sa_t delete_ike_sa_t;
-
-#include <sa/ike_sa.h>
-#include <sa/transactions/transaction.h>
-
-/**
- * @brief A transaction used to delete the IKE_SA.
- *
- * Notation as follows:
- * Mx{D} means: Message, with message ID "x", containing a Delete payload
- *
- * The clarifcation Document says in 5.8, that a IKE_SA delete should not
- * be acknowledged with the same delete. This only makes sense for CHILD_SAs,
- * as they are paired. IKE_SAs are not, there is only one for both ends.
- *
- * Normal case:
- * ----------------
- * Mx{D}  -->
- *       <--      Mx{}
- * Delete request is sent, and we wait for the acknowledge.
- *
- * Special case 1:
- * ---------------
- * Mx{D}  -->
- *       <--      My{D}
- * My{}   -->
- *       <--      Mx{}
- * Both initate a delete at the same time. We ack the delete, but wait for
- * our delete to be acknowledged.
- *
- * @b Constructors:
- *  - delete_ike_sa_create()
- *  - transaction_create() with the appropriate message
- *
- * @ingroup transactions
- */
-struct delete_ike_sa_t {
-       
-       /**
-        * The transaction_t interface.
-        */
-       transaction_t transaction;
-};
-
-/**
- * @brief Create a new transaction which deletes the IKE_SA.
- *
- * @param ike_sa               assigned IKE_SA
- * @return                             created delete_ike_sa transaction
- *
- * @ingroup transactions
- */
-delete_ike_sa_t *delete_ike_sa_create(ike_sa_t *ike_sa);
-
-#endif /* DELETE_IKE_SA_H_ */
diff --git a/src/charon/sa/transactions/ike_auth.c b/src/charon/sa/transactions/ike_auth.c
deleted file mode 100644 (file)
index bf7fd6d..0000000
+++ /dev/null
@@ -1,1562 +0,0 @@
-/**
- * @file ike_auth.c
- *
- * @brief Implementation of ike_auth_t transaction.
- *
- */
-
-/*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#include "ike_auth.h"
-
-#include <string.h>
-
-#include <daemon.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/id_payload.h>
-#include <encoding/payloads/cert_payload.h>
-#include <encoding/payloads/certreq_payload.h>
-#include <encoding/payloads/auth_payload.h>
-#include <encoding/payloads/ts_payload.h>
-#include <sa/authenticators/authenticator.h>
-#include <sa/authenticators/eap_authenticator.h>
-#include <sa/child_sa.h>
-
-
-typedef struct private_ike_auth_t private_ike_auth_t;
-
-/**
- * Private members of a ike_auth_t object..
- */
-struct private_ike_auth_t {
-       
-       /**
-        * Public methods and transaction_t interface.
-        */
-       ike_auth_t public;
-       
-       /**
-        * Assigned IKE_SA.
-        */
-       ike_sa_t *ike_sa;
-       
-       /**
-        * Message sent by our peer, if already generated
-        */
-       message_t *message;
-       
-       /**
-        * Message ID this transaction uses
-        */
-       u_int32_t message_id;
-       
-       /**
-        * Times we did send the request
-        */
-       u_int32_t requested;
-       
-       /**
-        * initiator chosen nonce
-        */
-       chunk_t nonce_i;
-       
-       /**
-        * responder chosen nonce
-        */
-       chunk_t nonce_r;
-       
-       /**
-        * encoded request message of ike_sa_init transaction
-        */
-       chunk_t init_request;
-       
-       /**
-        * encoded response message of ike_sa_init transaction
-        */
-       chunk_t init_response;
-       
-       /**
-        * connection definition used for IKE_SA setup
-        */
-       connection_t *connection;
-       
-       /**
-        * policy definition used CHILD_SA creation
-        */
-       policy_t *policy;
-       
-       /**
-        * Negotiated proposal used for CHILD_SA
-        */
-       proposal_t *proposal;
-       
-       /**
-        * Negotiated traffic selectors for initiator
-        */
-       linked_list_t *tsi;
-       
-       /**
-        * Negotiated traffic selectors for responder
-        */
-       linked_list_t *tsr;
-       
-       /**
-        * CHILD_SA created along with IKE_AUTH
-        */
-       child_sa_t *child_sa;
-       
-       /**
-        * did other peer create a CHILD_SA?
-        */
-       bool build_child;
-       
-       /**
-        * reqid to use for CHILD_SA setup
-        */
-       u_int32_t reqid;
-       
-       /**
-        * List of CA certificates the other peer trusts
-        */
-       linked_list_t *cacerts;
-       
-       /**
-        * EAP uses this authentication, which is passed along multiple ike_auths
-        */
-       eap_authenticator_t *eap_auth;
-       
-       /**
-        * if the client receives a EAP request, it is stored here for later use
-        */
-       eap_payload_t *eap_next;
-       
-       /**
-        * set to TRUE if authentication should be done with EAP only
-        */
-       bool eap_only;
-       
-       /**
-        * has the other peer been authenticated yet?
-        */
-       bool peer_authenticated;
-       
-       /**
-        * mode the CHILD_SA uses: tranport, tunnel, BEET
-        */
-       mode_t mode;
-};
-
-/**
- * Implementation of transaction_t.get_message_id.
- */
-static u_int32_t get_message_id(private_ike_auth_t *this)
-{
-       return this->message_id;
-}
-
-/**
- * Implementation of transaction_t.requested.
- */
-static u_int32_t requested(private_ike_auth_t *this)
-{
-       return this->requested++;
-}
-
-/**
- * Implementation of transaction_t.set_config.
- */
-static void set_config(private_ike_auth_t *this,
-                                          connection_t *connection, policy_t *policy)
-{
-       this->connection = connection;
-       this->policy = policy;
-}
-
-/**
- * Implementation of transaction_t.set_reqid.
- */
-static void set_reqid(private_ike_auth_t *this, u_int32_t reqid)
-{
-       this->reqid = reqid;
-}
-
-/**
- * Implementation of transaction_t.set_nonces.
- */
-static void set_nonces(private_ike_auth_t *this, chunk_t nonce_i, chunk_t nonce_r)
-{
-       this->nonce_i = nonce_i;
-       this->nonce_r = nonce_r;
-}
-
-/**
- * Implementation of transaction_t.set_init_messages.
- */
-static void set_init_messages(private_ike_auth_t *this, chunk_t init_request, chunk_t init_response)
-{
-       this->init_request = init_request;
-       this->init_response = init_response;
-}
-
-/**
- * Build a notify message.
- */
-static void build_notify(notify_type_t type, message_t *message, bool flush_message)
-{
-       notify_payload_t *notify;
-       
-       if (flush_message)
-       {
-               payload_t *payload;
-               iterator_t *iterator = message->get_payload_iterator(message);
-               while (iterator->iterate(iterator, (void**)&payload))
-               {
-                       payload->destroy(payload);
-                       iterator->remove(iterator);
-               }
-               iterator->destroy(iterator);
-       }
-       
-       notify = notify_payload_create();
-       notify->set_notify_type(notify, type);
-       message->add_payload(message, (payload_t*)notify);
-}
-
-/**
- * Implementation of transaction_t.get_request.
- */
-static status_t get_request(private_ike_auth_t *this, message_t **result)
-{
-       message_t *request;
-       host_t *me, *other;
-       identification_t *my_id, *other_id;
-       id_payload_t *my_id_payload;
-       
-       /* check if we already have built a message (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       my_id = this->policy->get_my_id(this->policy);
-       other_id = this->policy->get_other_id(this->policy);
-       
-       /* build the request */
-       request = message_create();
-       request->set_source(request, me->clone(me));
-       request->set_destination(request, other->clone(other));
-       request->set_exchange_type(request, IKE_AUTH);
-       request->set_request(request, TRUE);
-       request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
-       /* apply for caller */
-       *result = request;
-       /* store for retransmission */
-       this->message = request;
-       
-       this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
-       request->set_message_id(request, this->message_id);
-       
-       if (this->eap_auth)
-       {
-               /* we already sent ID, SA, TS in an earlier ike_auth, we now
-                * continiue EAP processing */
-               if (this->eap_next)
-               {
-                       /* if we have another outstanding EAP response, send it */
-                       request->add_payload(request, (payload_t*)this->eap_next);
-                       this->eap_next = NULL;
-                       return SUCCESS;
-               }
-               else
-               {
-                       /* if not, we have received an EAP_SUCCESS, send AUTH payload.
-                        * we only send our data if:
-                        * a) The peer has been authenticated using RSA/PSK, or
-                        * b) The EAP method is mutual and gives us enough security
-                        */
-                       if (this->eap_auth->is_mutual(this->eap_auth) ||
-                               this->peer_authenticated)
-                       {
-                               auth_payload_t *auth_payload;
-                               authenticator_t *authenticator = (authenticator_t*)this->eap_auth;
-                               
-                               if (authenticator->build(authenticator, this->init_request,
-                                                                                this->nonce_r, &auth_payload) != SUCCESS)
-                               {
-                                       SIG(IKE_UP_FAILED,
-                                               "EAP authentication data generation failed, deleting IKE_SA");
-                                       SIG(CHILD_UP_FAILED,
-                                               "initiating CHILD_SA failed, unable to create IKE_SA");
-                                       return DESTROY_ME;
-                               }
-                               request->add_payload(request, (payload_t*)auth_payload);
-                               return SUCCESS;
-                       }
-                       else
-                       {
-                               SIG(IKE_UP_FAILED,
-                                       "peer didn't send authentication data, deleting IKE_SA");
-                               SIG(CHILD_UP_FAILED,
-                                       "initiating CHILD_SA failed, unable to create IKE_SA");
-                               return DESTROY_ME;
-                       }
-               }
-       }
-       /* otherwise we do a normal ike_auth request... */
-       
-       {       /* build ID payload */
-               my_id_payload = id_payload_create_from_identification(TRUE, my_id);
-               request->add_payload(request, (payload_t*)my_id_payload);
-       }
-       
-       /* build certificate request payload */
-       if (this->connection->get_certreq_policy(this->connection) != CERT_NEVER_SEND)
-       {
-               certreq_payload_t *certreq_payload;
-               identification_t *other_ca = this->policy->get_other_ca(this->policy);
-               
-               if (other_ca)
-               {
-                       if (other_ca->get_type(other_ca) == ID_ANY)
-                       {
-                               certreq_payload = certreq_payload_create_from_cacerts();
-                       }
-                       else
-                       {
-                               certreq_payload = certreq_payload_create_from_cacert(other_ca);
-                       }
-                       if (certreq_payload != NULL)
-                       {
-                               request->add_payload(request, (payload_t*)certreq_payload);
-                       }
-               }
-       }
-       
-       /* build certificate payload. TODO: Handle certreq from init_ike_sa. */
-       if (this->policy->get_auth_method(this->policy) == AUTH_RSA &&
-               this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND)
-       {
-               cert_payload_t *cert_payload;
-               
-               x509_t *cert = charon->credentials->get_certificate(charon->credentials, my_id);
-
-               if (cert)
-               {
-                       cert_payload = cert_payload_create_from_x509(cert);
-                       request->add_payload(request, (payload_t*)cert_payload);
-               }
-               else
-               {
-                       DBG1(DBG_IKE, "could not find my certificate, certificate payload omitted");
-               }
-       }
-       
-       {       /* build IDr payload, if other_id defined */
-               id_payload_t *id_payload;
-               if (!other_id->contains_wildcards(other_id))
-               {
-                       id_payload = id_payload_create_from_identification(FALSE, other_id);
-                       request->add_payload(request, (payload_t*)id_payload);
-               }
-       }
-       
-       if (this->policy->get_auth_method(this->policy) != AUTH_EAP)
-       {       /* build auth payload */
-               authenticator_t *authenticator;
-               auth_payload_t *auth_payload;
-               auth_method_t auth_method;
-               status_t status;
-               
-               auth_method = this->policy->get_auth_method(this->policy);
-               authenticator = authenticator_create(this->ike_sa, auth_method);
-               if (authenticator == NULL)
-               {
-                       SIG(IKE_UP_FAILED, "auth method %N not supported, deleting IKE_SA",
-                           auth_method_names, auth_method);
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-               status = authenticator->build(authenticator, this->init_request,
-                                                                         this->nonce_r, &auth_payload);
-               authenticator->destroy(authenticator);
-               if (status != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "could not generate AUTH data, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-               request->add_payload(request, (payload_t*)auth_payload);
-       }
-       else
-       {
-               this->eap_auth = eap_authenticator_create(this->ike_sa);
-               /* include notify that we support EAP only authentication */
-               build_notify(EAP_ONLY_AUTHENTICATION, request, FALSE);
-       }
-       
-       {       /* build SA payload for CHILD_SA */
-               linked_list_t *proposal_list;
-               sa_payload_t *sa_payload;
-               u_int32_t soft_lifetime, hard_lifetime;
-               bool enable_natt;
-               
-               proposal_list = this->policy->get_proposals(this->policy);
-               soft_lifetime = this->policy->get_soft_lifetime(this->policy);
-               hard_lifetime = this->policy->get_hard_lifetime(this->policy);
-               enable_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
-               this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
-                                                                                soft_lifetime, hard_lifetime,
-                                                                                this->policy->get_updown(this->policy),
-                                                                                this->policy->get_hostaccess(this->policy),
-                                                                                enable_natt);
-               this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
-               if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "could not install CHILD_SA, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-               sa_payload = sa_payload_create_from_proposal_list(proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-               request->add_payload(request, (payload_t*)sa_payload);
-       }
-       
-       /* notify for transport/BEET mode, we propose it 
-        * independent of the traffic selectors */
-       switch (this->policy->get_mode(this->policy))
-       {
-               case MODE_TUNNEL:
-                       /* is the default */
-                       break;
-               case MODE_TRANSPORT:
-                       if (this->ike_sa->is_natt_enabled(this->ike_sa))
-                       {
-                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
-                       }
-                       else
-                       {
-                               build_notify(USE_TRANSPORT_MODE, request, FALSE);
-                       }
-                       break;
-               case MODE_BEET:
-                       build_notify(USE_BEET_MODE, request, FALSE);
-                       break;
-       }
-       
-       {       /* build TSi payload */
-               linked_list_t *ts_list;
-               ts_payload_t *ts_payload;
-       
-               ts_list = this->policy->get_my_traffic_selectors(this->policy, me);
-               ts_payload = ts_payload_create_from_traffic_selectors(TRUE, ts_list);
-               ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
-               
-               request->add_payload(request, (payload_t*)ts_payload);
-       }
-       
-       {       /* build TSr payload */
-               linked_list_t *ts_list;
-               ts_payload_t *ts_payload;
-       
-               ts_list = this->policy->get_other_traffic_selectors(this->policy, other);
-               ts_payload = ts_payload_create_from_traffic_selectors(FALSE, ts_list);
-               ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
-               
-               request->add_payload(request, (payload_t*)ts_payload);
-       }
-       
-       return SUCCESS;
-}
-
-/**
- * Handle all kind of notifies
- */
-static status_t process_notifies(private_ike_auth_t *this, notify_payload_t *notify_payload)
-{
-       notify_type_t notify_type = notify_payload->get_notify_type(notify_payload);
-       
-       DBG2(DBG_IKE, "process notify type %N", notify_type_names, notify_type);
-       
-       switch (notify_type)
-       {
-               /* these notifies are not critical. no child_sa is built, but IKE stays alive */
-               case SINGLE_PAIR_REQUIRED:
-               {
-                       SIG(CHILD_UP_FAILED, "received a SINGLE_PAIR_REQUIRED notify");
-                       this->build_child = FALSE;
-                       return SUCCESS;
-               }
-               case TS_UNACCEPTABLE:
-               {
-                       SIG(CHILD_UP_FAILED, "received TS_UNACCEPTABLE notify");
-                       this->build_child = FALSE;
-                       return SUCCESS;
-               }
-               case NO_PROPOSAL_CHOSEN:
-               {
-                       SIG(CHILD_UP_FAILED, "received NO_PROPOSAL_CHOSEN notify");
-                       this->build_child = FALSE;
-                       return SUCCESS;
-               }
-               case EAP_ONLY_AUTHENTICATION:
-               {
-                       DBG1(DBG_IKE, "peer requested EAP_ONLY_AUTHENTICATION");
-                       this->eap_only = TRUE;
-                       return SUCCESS;
-               }
-               case USE_TRANSPORT_MODE:
-               {
-                       this->mode = MODE_TRANSPORT;
-                       return SUCCESS;
-               }
-               case USE_BEET_MODE:
-               {
-                       this->mode = MODE_BEET;
-                       return SUCCESS;
-               }
-               default:
-               {
-                       if (notify_type < 16383)
-                       {
-                               SIG(IKE_UP_FAILED, "received %N notify error, deleting IKE_SA",
-                                       notify_type_names, notify_type);
-                               return DESTROY_ME;      
-                       }
-                       else
-                       {
-                               DBG1(DBG_IKE, "received %N notify, ignored",
-                                        notify_type_names, notify_type);
-                               return SUCCESS;
-                       }
-               }
-       }
-}
-
-/**
- * Import certificate requests from a certreq payload
- */
-static void process_certificate_request(private_ike_auth_t *this,
-                                                                               certreq_payload_t *certreq_payload)
-{
-       chunk_t keyids;
-       cert_encoding_t encoding = certreq_payload->get_cert_encoding(certreq_payload);
-       
-       if (encoding != CERT_X509_SIGNATURE)
-       {
-               DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
-                        cert_encoding_names, encoding);
-               return;
-       }
-       
-       keyids = certreq_payload->get_data(certreq_payload);
-       while (keyids.len >= HASH_SIZE_SHA1)
-       {
-               chunk_t keyid = { keyids.ptr, HASH_SIZE_SHA1};
-               x509_t *cacert = charon->credentials->get_ca_certificate_by_keyid(
-                                                                                                       charon->credentials, keyid);
-               if (cacert)
-               {
-                       DBG2(DBG_IKE, "request for certificate issued by ca '%D'",
-                                cacert->get_subject(cacert));
-                       this->cacerts->insert_last(this->cacerts, cacert);
-               }
-               else
-               {
-                       DBG2(DBG_IKE, "request for certificate issued by unknown ca");
-               }
-               DBG2(DBG_IKE, "  with keyid %#B", &keyid);
-               
-               keyids.ptr += HASH_SIZE_SHA1;
-               keyids.len -= HASH_SIZE_SHA1;
-       }
-}
-
-/**
- * Import a certificate from a cert payload
- */
-static void import_certificate(cert_payload_t *cert_payload)
-{
-       bool found;
-       x509_t *cert;
-       cert_encoding_t encoding;
-       
-       encoding = cert_payload->get_cert_encoding(cert_payload);
-       if (encoding != CERT_X509_SIGNATURE)
-       {
-               DBG1(DBG_IKE, "certificate payload %N not supported, ignored",
-                        cert_encoding_names, encoding);
-               return;
-       }
-       cert = x509_create_from_chunk(cert_payload->get_data_clone(cert_payload));
-       if (cert)
-       {
-               if (charon->credentials->verify(charon->credentials, cert, &found))
-               {
-                       DBG2(DBG_IKE, "received end entity certificate is trusted, added to store");
-                       if (!found)
-                       {
-                               charon->credentials->add_end_certificate(charon->credentials, cert);
-                       }
-                       else
-                       {
-                               cert->destroy(cert);
-                       }
-               }
-               else
-               {
-                       DBG1(DBG_IKE, "received end entity certificate is not trusted, discarded");
-                       cert->destroy(cert);
-               }
-       }
-       else
-       {
-               DBG1(DBG_IKE, "parsing of received certificate failed, discarded");
-       }
-}
-
-/**
- * Check a list of traffic selectors if any selector belongs to host
- */
-static bool ts_list_is_host(linked_list_t *list, host_t *host)
-{
-       traffic_selector_t *ts;
-       bool is_host = TRUE;
-       iterator_t *iterator = list->create_iterator(list, TRUE);
-       
-       while (is_host && iterator->iterate(iterator, (void**)&ts))
-       {
-               is_host = is_host && ts->is_host(ts, host);
-       }
-       iterator->destroy(iterator);
-       return is_host;
-}
-
-/**
- * Install a CHILD_SA for usage
- */
-static status_t install_child_sa(private_ike_auth_t *this, bool initiator)
-{
-       prf_plus_t *prf_plus;
-       chunk_t seed;
-       status_t status;
-       
-       seed = chunk_alloc(this->nonce_i.len + this->nonce_r.len);
-       memcpy(seed.ptr, this->nonce_i.ptr, this->nonce_i.len);
-       memcpy(seed.ptr + this->nonce_i.len, this->nonce_r.ptr, this->nonce_r.len);
-       prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
-       chunk_free(&seed);
-       
-       if (initiator)
-       {
-               status = this->child_sa->update(this->child_sa, this->proposal, 
-                                                                               this->mode, prf_plus);
-       }
-       else
-       {
-               status = this->child_sa->add(this->child_sa, this->proposal, 
-                                                                        this->mode, prf_plus);
-       }
-       prf_plus->destroy(prf_plus);
-       if (status != SUCCESS)
-       {
-               return DESTROY_ME;
-       }
-       if (initiator)
-       {
-               status = this->child_sa->add_policies(this->child_sa, this->tsi,
-                                                                                         this->tsr, this->mode);
-       }
-       else
-       {
-               status = this->child_sa->add_policies(this->child_sa, this->tsr,
-                                                                                         this->tsi, this->mode);
-       }
-       if (status != SUCCESS)
-       {
-               return DESTROY_ME;
-       }
-       
-       /* add to IKE_SA, and remove from transaction */
-       this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
-       this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
-       this->child_sa = NULL;
-       return SUCCESS;
-}
-
-/**
- * create a CHILD SA, install it, and build response message
- */
-static void setup_child_sa(private_ike_auth_t *this, message_t *response)
-{
-       bool use_natt;
-       u_int32_t soft_lifetime, hard_lifetime;
-       host_t *me, *other;
-       identification_t *my_id, *other_id;
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       my_id = this->ike_sa->get_my_id(this->ike_sa);
-       other_id = this->ike_sa->get_other_id(this->ike_sa);
-       
-       soft_lifetime = this->policy->get_soft_lifetime(this->policy);
-       hard_lifetime = this->policy->get_hard_lifetime(this->policy);
-       use_natt = this->ike_sa->is_natt_enabled(this->ike_sa);
-       this->child_sa = child_sa_create(this->reqid, me, other, my_id, other_id,
-                                                                        soft_lifetime, hard_lifetime,
-                                                                        this->policy->get_updown(this->policy),
-                                                                        this->policy->get_hostaccess(this->policy),
-                                                                        use_natt);
-       this->child_sa->set_name(this->child_sa, this->policy->get_name(this->policy));
-    /* check mode, and include notify into reply */
-    switch (this->mode)
-    {
-               case MODE_TUNNEL:
-               /* is the default */
-               break;
-               case MODE_TRANSPORT:
-               if (!ts_list_is_host(this->tsi, other) ||
-                !ts_list_is_host(this->tsr, me))
-               {
-                this->mode = MODE_TUNNEL;
-                DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
-               }
-               else if (this->ike_sa->is_natt_enabled(this->ike_sa))
-               {
-                this->mode = MODE_TUNNEL;
-                DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
-               }
-               else 
-               {
-                build_notify(USE_TRANSPORT_MODE, response, FALSE);
-               }
-               break;
-               case MODE_BEET:
-               if (!ts_list_is_host(this->tsi, NULL) ||
-                !ts_list_is_host(this->tsr, NULL))
-               {
-                this->mode = MODE_TUNNEL;
-                DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
-               }
-               else
-               {
-                build_notify(USE_BEET_MODE, response, FALSE);
-               }
-               break;
-    }
-
-       if (install_child_sa(this, FALSE) != SUCCESS)
-       {
-               SIG(CHILD_UP_FAILED, "installing CHILD_SA %s failed, no CHILD_SA created",
-                       this->policy->get_name(this->policy));
-               DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response");
-               build_notify(NO_PROPOSAL_CHOSEN, response, FALSE);
-       }
-       else
-       {
-               /* build SA and TS payloads */
-               SIG(CHILD_UP_SUCCESS, "CHILD_SA created");
-               ts_payload_t *ts_response;
-               sa_payload_t *sa_response = sa_payload_create();
-               sa_response->add_proposal(sa_response, this->proposal);
-               response->add_payload(response, (payload_t*)sa_response);
-               ts_response = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
-               response->add_payload(response, (payload_t*)ts_response);
-               ts_response = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
-               response->add_payload(response, (payload_t*)ts_response);
-       }
-}
-
-/**
- * clone the transaction to requeue it for EAP handling
- */
-static private_ike_auth_t *clone_for_eap(private_ike_auth_t *this)
-{
-       private_ike_auth_t *clone;
-       clone = (private_ike_auth_t*)ike_auth_create(this->ike_sa);
-       
-       clone->tsi = this->tsi; this->tsi = NULL;
-       clone->tsr = this->tsr; this->tsr = NULL;
-       clone->eap_auth = this->eap_auth; this->eap_auth = NULL;
-       clone->eap_next = this->eap_next; this->eap_next = NULL;
-       clone->build_child = this->build_child;
-       clone->nonce_i = this->nonce_i; this->nonce_i = chunk_empty;
-       clone->nonce_r = this->nonce_r; this->nonce_r = chunk_empty;
-       clone->child_sa = this->child_sa; this->child_sa = NULL;
-       clone->proposal = this->proposal; this->proposal = NULL;
-       clone->peer_authenticated = this->peer_authenticated;
-       clone->connection = this->connection; this->connection = NULL;
-       clone->policy = this->policy; this->policy = NULL;
-       
-       return clone;
-}
-
-/**
- * Implementation of transaction_t.get_response.
- */
-static status_t get_response(private_ike_auth_t *this, message_t *request, 
-                                                        message_t **result, transaction_t **next)
-{
-       host_t *me, *other;
-       identification_t *my_id, *other_id;
-       message_t *response;
-       status_t status;
-       iterator_t *payloads;
-       payload_t *payload;
-       id_payload_t *idi_request = NULL;
-       id_payload_t *idr_request = NULL;
-       auth_payload_t *auth_request = NULL;
-       certreq_payload_t *certreq_request = NULL;
-       cert_payload_t *cert_request = NULL;
-       sa_payload_t *sa_request = NULL;
-       ts_payload_t *tsi_request = NULL;
-       ts_payload_t *tsr_request = NULL;
-       eap_payload_t *eap_request = NULL;
-       id_payload_t *idr_response;
-       
-       /* check if we already have built a response (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       SIG(CHILD_UP_START, "setting up CHILD_SA along with IKE_AUTH");
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       my_id = this->ike_sa->get_my_id(this->ike_sa);
-       other_id = this->ike_sa->get_other_id(this->ike_sa);
-       this->message_id = request->get_message_id(request);
-       
-       /* set up response */
-       response = message_create();
-       response->set_source(response, me->clone(me));
-       response->set_destination(response, other->clone(other));
-       response->set_exchange_type(response, IKE_AUTH);
-       response->set_request(response, FALSE);
-       response->set_message_id(response, this->message_id);
-       response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
-       this->message = response;
-       *result = response;
-       
-       /* check message type */
-       if (request->get_exchange_type(request) != IKE_AUTH)
-       {
-               SIG(IKE_UP_FAILED, "IKE_AUTH response of invalid type, deleting IKE_SA");
-               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-               return DESTROY_ME;
-       }
-
-       /* Iterate over all payloads. */
-       payloads = request->get_payload_iterator(request);
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case ID_INITIATOR:
-                               idi_request = (id_payload_t*)payload;
-                               break;
-                       case ID_RESPONDER:
-                               idr_request = (id_payload_t*)payload;
-                               break;
-                       case AUTHENTICATION:
-                               auth_request = (auth_payload_t*)payload;
-                               break;
-                       case CERTIFICATE_REQUEST:
-                               certreq_request = (certreq_payload_t*)payload;
-                               process_certificate_request(this, certreq_request);
-                               break;
-                       case CERTIFICATE:
-                               cert_request = (cert_payload_t*)payload;
-                               break;
-                       case SECURITY_ASSOCIATION:
-                               sa_request = (sa_payload_t*)payload;
-                               break;
-                       case TRAFFIC_SELECTOR_INITIATOR:
-                               tsi_request = (ts_payload_t*)payload;
-                               break;  
-                       case TRAFFIC_SELECTOR_RESPONDER:
-                               tsr_request = (ts_payload_t*)payload;
-                               break;
-                       case EXTENSIBLE_AUTHENTICATION:
-                               eap_request = (eap_payload_t*)payload;
-                               break;
-                       case NOTIFY:
-                       {
-                               status = process_notifies(this, (notify_payload_t*)payload);
-                               if (status == FAILED)
-                               {
-                                       payloads->destroy(payloads);
-                                       /* we return SUCCESS, returned FAILED means do next transaction */
-                                       return SUCCESS;
-                               }
-                               if (status == DESTROY_ME)
-                               {
-                                       payloads->destroy(payloads);
-                                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                                       return DESTROY_ME;
-                               }
-                               break;
-                       }
-                       default:
-                       {
-                               DBG1(DBG_IKE, "ignoring %N payload",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       
-       /* if message contains an EAP payload, we process it */
-       if (eap_request && this->eap_auth)
-       {
-               eap_payload_t *eap_response;
-               private_ike_auth_t *next_auth;
-               
-               status = this->eap_auth->process(this->eap_auth, eap_request, &eap_response);
-               response->add_payload(response, (payload_t*)eap_response);
-               
-               if (status == FAILED)
-               {
-                       /* shut down if EAP message is EAP_FAILURE */
-                       return DESTROY_ME;
-               }
-               
-               next_auth = clone_for_eap(this);
-               next_auth->message_id = this->message_id + 1;
-               *next = (transaction_t*)next_auth;
-               return SUCCESS;
-       }
-       
-       /* if we do EAP authentication and a AUTH payload comes in, verify it */
-       if (auth_request && this->eap_auth)
-       {
-               auth_payload_t *auth_response;
-               authenticator_t *authenticator = (authenticator_t*)this->eap_auth;
-               
-               if (authenticator->verify(authenticator, this->init_request,
-                                                                 this->nonce_r, auth_request) != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "authentication with EAP failed, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       build_notify(AUTHENTICATION_FAILED, response, TRUE);
-                       return DESTROY_ME;
-               }
-               
-               if (authenticator->build(authenticator, this->init_response,
-                                                                this->nonce_i, &auth_response) != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "EAP authentication data generation failed, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       build_notify(AUTHENTICATION_FAILED, response, TRUE);
-                       return DESTROY_ME;
-               }
-               response->add_payload(response, (payload_t*)auth_response);
-               
-               SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]",
-                       this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id);
-               this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
-               
-               setup_child_sa(this, response);
-               
-               return SUCCESS;
-       }
-       
-       /* check if we have all payloads (AUTH is not checked, not required with EAP) */
-       if (!(idi_request && sa_request && tsi_request && tsr_request))
-       {
-               build_notify(INVALID_SYNTAX, response, TRUE);
-               SIG(IKE_UP_FAILED, "request message incomplete, deleting IKE_SA");
-               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       {       /* process ID payload */
-               other_id = idi_request->get_identification(idi_request);
-               if (idr_request)
-               {
-                       my_id = idr_request->get_identification(idr_request);
-               }
-               else
-               {
-                       my_id = identification_create_from_encoding(ID_ANY, chunk_empty);
-               }
-       }
-       
-       {       /* get a policy and process traffic selectors */
-               linked_list_t *my_ts, *other_ts;
-               
-               my_ts = tsr_request->get_traffic_selectors(tsr_request);
-               other_ts = tsi_request->get_traffic_selectors(tsi_request);
-               
-               this->policy = charon->policies->get_policy(charon->policies,
-                                                                                                       my_id, other_id,
-                                                                                                       my_ts, other_ts,
-                                                                                                   me, other);
-
-               if (this->policy)
-               {
-                       this->tsr = this->policy->select_my_traffic_selectors(this->policy, my_ts, me);
-                       this->tsi = this->policy->select_other_traffic_selectors(this->policy, other_ts, other);
-               }
-               my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
-               other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
-               
-               /* TODO: We should check somehow if we have a policy, but with other
-                * traffic selectors. Then we would create a IKE_SA without a CHILD_SA. */
-               if (this->policy == NULL)
-               {
-                       SIG(IKE_UP_FAILED, "no acceptable policy for IDs %D - %D found, "
-                               "deleting IKE_SA", my_id, other_id);
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       my_id->destroy(my_id);
-                       other_id->destroy(other_id);
-                       build_notify(AUTHENTICATION_FAILED, response, TRUE);
-                       return DESTROY_ME;
-               }
-               my_id->destroy(my_id);
-               
-               /* get my id from policy, which must contain a fully qualified valid id */
-               my_id = this->policy->get_my_id(this->policy);
-               this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id));
-               this->ike_sa->set_other_id(this->ike_sa, other_id);
-               
-               idr_response = id_payload_create_from_identification(FALSE, my_id);
-               response->add_payload(response, (payload_t*)idr_response);
-       }
-       
-       if (this->policy->get_auth_method(this->policy) == AUTH_RSA &&
-               this->connection->get_cert_policy(this->connection) != CERT_NEVER_SEND)
-       {       /* build certificate payload */
-               x509_t *cert;
-               cert_payload_t *cert_payload;
-               
-               cert = charon->credentials->get_certificate(charon->credentials, my_id);
-               if (cert)
-               {
-                       cert_payload = cert_payload_create_from_x509(cert);
-                       response->add_payload(response, (payload_t *)cert_payload);
-               }
-               else
-               {
-                       DBG1(DBG_IKE, "could not find my certificate, cert payload omitted");
-               }
-       }
-       
-       if (cert_request)
-       {       /* process certificate payload */
-               import_certificate(cert_request);
-       }
-       
-       {       /* process SA payload */
-               linked_list_t *proposal_list;
-               
-               /* get proposals from request, and select one with ours */
-               proposal_list = sa_request->get_proposals(sa_request);
-               DBG2(DBG_IKE, "selecting proposals:");
-               this->proposal = this->policy->select_proposal(this->policy, proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-
-               /* do we have a proposal? */
-               if (this->proposal == NULL)
-               {
-                       SIG(CHILD_UP_FAILED, "CHILD_SA proposals unacceptable, no CHILD_SA created");
-                       DBG1(DBG_IKE, "adding NO_PROPOSAL_CHOSEN notify to response");
-                       build_notify(NO_PROPOSAL_CHOSEN, response, FALSE);
-                       this->build_child = FALSE;
-               }
-               /* do we have traffic selectors? */
-               else if (this->tsi->get_count(this->tsi) == 0 || this->tsr->get_count(this->tsr) == 0)
-               {
-                       SIG(CHILD_UP_FAILED, "CHILD_SA traffic selectors unacceptable, no CHILD_SA created");
-                       DBG1(DBG_IKE, "adding TS_UNACCEPTABLE notify to response");
-                       build_notify(TS_UNACCEPTABLE, response, FALSE);
-                       this->build_child = FALSE;
-               }
-       }
-       
-       if (!this->eap_only || this->policy->get_auth_method(this->policy) != AUTH_EAP)
-       {       /* build response AUTH payload when not using a mutual EAP authentication */
-               auth_payload_t *auth_response;
-               authenticator_t *authenticator;
-               auth_method_t auth_method;
-               status_t status;
-               
-               auth_method = this->policy->get_auth_method(this->policy);
-               if (auth_method == AUTH_EAP)
-               {
-                       SIG(IKE_UP_FAILED,
-                               "peer does not support EAP only authentication, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED,
-                               "initiating CHILD_SA failed, unable to create IKE_SA");
-                       build_notify(AUTHENTICATION_FAILED, response, TRUE);
-                       return DESTROY_ME;
-               }
-               
-               authenticator = authenticator_create(this->ike_sa, auth_method);
-               if (authenticator == NULL)
-               {
-                       SIG(IKE_UP_FAILED, "auth method %N not supported, deleting IKE_SA",
-                               auth_method_names, auth_method);
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       build_notify(AUTHENTICATION_FAILED, response, TRUE);
-                       return DESTROY_ME;
-               }
-               status = authenticator->build(authenticator, this->init_response,
-                                                                         this->nonce_i, &auth_response);
-               authenticator->destroy(authenticator);
-               if (status != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "authentication data generation failed, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       build_notify(AUTHENTICATION_FAILED, response, TRUE);
-                       return DESTROY_ME;
-               }
-               response->add_payload(response, (payload_t*)auth_response);
-       }
-       
-       if (auth_request)
-       {       /* process auth payload, if not using EAP */
-               authenticator_t *authenticator;
-               auth_method_t auth_method;
-               status_t status;
-               
-               auth_method = auth_request->get_auth_method(auth_request);
-               authenticator = authenticator_create(this->ike_sa, auth_method);
-               if (authenticator == NULL)
-               {
-                       SIG(IKE_UP_FAILED, "auth method %N not supported, deleting IKE_SA",
-                               auth_method_names, auth_method);
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-               status = authenticator->verify(authenticator, this->init_request,
-                                                                          this->nonce_r, auth_request);
-               authenticator->destroy(authenticator);
-               if (status != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "authentication failed, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       build_notify(AUTHENTICATION_FAILED, response, TRUE);
-                       return DESTROY_ME;
-               }
-               
-               SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]",
-                       this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id);
-               this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
-               
-               /* set up CHILD_SA if negotiation succeded */
-               if (this->build_child)
-               {
-                       setup_child_sa(this, response);
-               }
-               
-               this->peer_authenticated = TRUE;
-       }
-       else
-       {
-               /* if no AUTH payload was included, we start with an EAP exchange.
-                * eap_response is a request in the EAP meaning, but is
-                * contained in a IKEv2 response */
-               eap_payload_t *eap_response;
-               private_ike_auth_t *next_auth;
-               eap_type_t eap_type;
-               
-               eap_type = this->policy->get_eap_type(this->policy);
-               this->eap_auth = eap_authenticator_create(this->ike_sa);
-               status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_response);
-               response->add_payload(response, (payload_t*)eap_response);
-               
-               if (status == FAILED)
-               {
-                       /* EAP initiaton failed, we send the EAP_FAILURE message and quit */
-                       return DESTROY_ME;
-               }
-               /* we send an EAP request. to handle the reply, we reschedule
-                * this transaction, as it knows how to handle the reply */
-               next_auth = clone_for_eap(this);
-               next_auth->message_id = this->message_id + 1;
-               *next = (transaction_t*)next_auth;
-       }
-       return SUCCESS;
-}
-
-/**
- * Implementation of transaction_t.conclude
- */
-static status_t conclude(private_ike_auth_t *this, message_t *response, 
-                                                transaction_t **next)
-{
-       iterator_t *payloads;
-       payload_t *payload;
-       host_t *me, *other;
-       identification_t *other_id, *my_id;
-       ts_payload_t *tsi_payload = NULL;
-       ts_payload_t *tsr_payload = NULL;
-       id_payload_t *idr_payload = NULL;
-       cert_payload_t *cert_payload = NULL;
-       auth_payload_t *auth_payload = NULL;
-       sa_payload_t *sa_payload = NULL;
-       eap_payload_t *eap_payload = NULL;
-       status_t status;
-       
-       /* check message type */
-       if (response->get_exchange_type(response) != IKE_AUTH)
-       {
-               SIG(IKE_UP_FAILED, "IKE_AUTH response of invalid type, deleting IKE_SA");
-               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       my_id = this->ike_sa->get_my_id(this->ike_sa);
-       other_id = this->ike_sa->get_other_id(this->ike_sa);
-       
-       /* Iterate over all payloads to collect them */
-       payloads = response->get_payload_iterator(response);
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case ID_RESPONDER:
-                               idr_payload = (id_payload_t*)payload;
-                               break;
-                       case AUTHENTICATION:
-                               auth_payload = (auth_payload_t*)payload;
-                               break;
-                       case CERTIFICATE:
-                               cert_payload = (cert_payload_t*)payload;
-                               break;
-                       case SECURITY_ASSOCIATION:
-                               sa_payload = (sa_payload_t*)payload;
-                               break;
-                       case TRAFFIC_SELECTOR_INITIATOR:
-                               tsi_payload = (ts_payload_t*)payload;
-                               break;  
-                       case TRAFFIC_SELECTOR_RESPONDER:
-                               tsr_payload = (ts_payload_t*)payload;
-                               break;
-                       case EXTENSIBLE_AUTHENTICATION:
-                               eap_payload = (eap_payload_t*)payload;
-                               break;
-                       case NOTIFY:
-                       {
-                               status = process_notifies(this, (notify_payload_t*)payload);
-                               if (status == FAILED)
-                               {
-                                       payloads->destroy(payloads);
-                                       /* we return SUCCESS, as transaction completet */
-                                       return SUCCESS;
-                               }
-                               if (status == DESTROY_ME)
-                               {
-                                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                                       payloads->destroy(payloads);
-                                       return status;
-                               }
-                               break;
-                       }
-                       default:
-                       {
-                               DBG1(DBG_IKE, "ignoring payload %N",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       
-       if (idr_payload)
-       {       /* process idr payload */
-               identification_t *configured_other_id;
-               int wildcards;
-               
-               other_id = idr_payload->get_identification(idr_payload);
-               configured_other_id = this->policy->get_other_id(this->policy);
-               
-               if (!other_id->matches(other_id, configured_other_id, &wildcards))
-               {
-                       other_id->destroy(other_id);
-                       SIG(IKE_UP_FAILED, "other peer uses unacceptable ID (%D, excepted "
-                                       "%D), deleting IKE_SA", other_id, configured_other_id);
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-               /* update other ID. It was already set, but may contain wildcards */
-               this->ike_sa->set_other_id(this->ike_sa, other_id);
-       }
-       
-       if (cert_payload)
-       {       /* process cert payload */
-               import_certificate(cert_payload);
-       }
-       
-       if (auth_payload && idr_payload)
-       {       /* authenticate peer */
-               authenticator_t *authenticator;
-               auth_method_t auth_method;
-               status_t status;
-               
-               my_id = this->policy->get_my_id(this->policy);
-               auth_method = auth_payload->get_auth_method(auth_payload);
-               authenticator = authenticator_create(this->ike_sa, auth_method);
-               if (authenticator == NULL)
-               {
-                       SIG(IKE_UP_FAILED, "auth method %N not supported, deleting IKE_SA",
-                               auth_method_names, auth_method);
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-               status = authenticator->verify(authenticator, this->init_response,
-                                                                          this->nonce_i, auth_payload);
-               authenticator->destroy(authenticator);
-               if (status != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed, "
-                                       "deleting IKE_SA", other_id, auth_method_names, auth_method);
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;      
-               }
-               this->peer_authenticated = TRUE;
-       }
-       
-       if (eap_payload && this->eap_auth)
-       {
-               switch (this->eap_auth->process(this->eap_auth, eap_payload, &this->eap_next))
-               {
-                       case SUCCESS:
-                       {
-                               /* EAP message was EAP_SUCCESS, send AUTH in next transaction */
-                               DBG2(DBG_IKE, "EAP authentication exchanges completed successful");
-                               this->eap_next = NULL;
-                               /* fall through */
-                       }
-                       case NEED_MORE:
-                       {
-                               /* EAP message was a EAP_REQUEST, handle it in next transaction */
-                               private_ike_auth_t *next_auth = clone_for_eap(this);
-                               next_auth->message_id = this->message_id + 1;
-                               *next = (transaction_t*)next_auth;
-                               return SUCCESS;
-                       }
-                       case FAILED:
-                       default:
-                       {
-                               /* EAP message was EAP_FAILURE */
-                               SIG(IKE_UP_FAILED, "EAP authentication failed, deleting IKE_SA");
-                               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                               return DESTROY_ME;
-                       }
-               }
-       }
-       
-       if (!(auth_payload && sa_payload && tsi_payload && tsr_payload))
-       {
-               SIG(IKE_UP_FAILED, "response message incomplete, deleting IKE_SA");
-               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       /* if we do EAP authentication and a AUTH payload comes in, verify it */
-       if (this->eap_auth &&
-               (this->eap_auth->is_mutual(this->eap_auth) || this->peer_authenticated))
-       {
-               authenticator_t *authenticator = (authenticator_t*)this->eap_auth;
-               
-               if (authenticator->verify(authenticator, this->init_response,
-                                                                 this->nonce_i, auth_payload) != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "authentication with EAP failed, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-               this->peer_authenticated = TRUE;
-       }
-       
-       if (!this->peer_authenticated)
-       {
-               SIG(IKE_UP_FAILED, "server didn't send authentication data, deleting IKE_SA");
-               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       SIG(IKE_UP_SUCCESS, "IKE_SA '%s' established between %H[%D]...%H[%D]",
-               this->ike_sa->get_name(this->ike_sa), me, my_id, other, other_id);
-       this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
-       
-       {       /* process traffic selectors for us */
-               linked_list_t *ts_received = tsi_payload->get_traffic_selectors(tsi_payload);
-               this->tsi = this->policy->select_my_traffic_selectors(this->policy, ts_received, me);
-               ts_received->destroy_offset(ts_received, offsetof(traffic_selector_t, destroy));
-       }
-       
-       {       /* process traffic selectors for other */
-               linked_list_t *ts_received = tsr_payload->get_traffic_selectors(tsr_payload);
-               this->tsr = this->policy->select_other_traffic_selectors(this->policy, ts_received, other);
-               ts_received->destroy_offset(ts_received, offsetof(traffic_selector_t, destroy));
-       }
-       
-       {       /* process sa payload */
-               linked_list_t *proposal_list;
-               
-               proposal_list = sa_payload->get_proposals(sa_payload);
-               /* we have to re-check here if other's selection is valid */
-               this->proposal = this->policy->select_proposal(this->policy, proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-               
-               /* everything fine to create CHILD? */
-               if (this->proposal == NULL ||
-                       this->tsi->get_count(this->tsi) == 0 ||
-                       this->tsr->get_count(this->tsr) == 0 ||
-                       !this->build_child)
-               {
-                       SIG(CHILD_UP_FAILED, "CHILD_SA negotiation failed, no CHILD_SA built");
-               }
-               else
-               {
-                       /* check mode if it is acceptable */
-                       switch (this->mode)
-                       {
-                               case MODE_TUNNEL:
-                                       /* is the default */
-                                       break;
-                               case MODE_TRANSPORT:
-                                       /* TODO: we should close the CHILD_SA if negotiated
-                                        * mode is not acceptable for us */
-                                       if (!ts_list_is_host(this->tsi, me) ||
-                                               !ts_list_is_host(this->tsr, other))
-                                       {
-                                               this->mode = MODE_TUNNEL;
-                                               DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
-                                       }
-                                       else if (this->ike_sa->is_natt_enabled(this->ike_sa))
-                                       {
-                                               this->mode = MODE_TUNNEL;
-                                               DBG1(DBG_IKE, "not using tranport mode, as connection NATed");
-                                       }
-                                       break;
-                               case MODE_BEET:
-                                       if (!ts_list_is_host(this->tsi, NULL) ||
-                                               !ts_list_is_host(this->tsr, NULL))
-                                       {
-                                               this->mode = MODE_TUNNEL;
-                                               DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
-                                       }
-                                       break;
-                       }
-               
-                       if (install_child_sa(this, TRUE) != SUCCESS)
-                       {
-                               SIG(CHILD_UP_FAILED, "installing CHILD_SA '%s' failed, no CHILD_SA built",
-                                               this->policy->get_name(this->policy));
-                               /* TODO: we should send a DELETE for that CHILD to stay
-                                * synchronous with the peer */
-                       }
-                       else
-                       {
-                               SIG(CHILD_UP_SUCCESS, "CHILD_SA '%s' created",
-                                               this->policy->get_name(this->policy));
-                       }
-               }
-       }
-       return SUCCESS;
-}
-
-/**
- * implements transaction_t.destroy
- */
-static void destroy(private_ike_auth_t *this)
-{
-       DESTROY_IF(this->message);
-       DESTROY_IF(this->proposal);
-       DESTROY_IF(this->child_sa);
-       DESTROY_IF(this->policy);
-       DESTROY_IF(this->connection);
-       DESTROY_IF(this->cacerts);
-       if (this->eap_auth)
-       {
-               this->eap_auth->authenticator_interface.destroy(&this->eap_auth->authenticator_interface);
-       }
-       DESTROY_IF(this->eap_next);
-       if (this->tsi)
-       {
-               this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
-       }
-       if (this->tsr)
-       {
-               this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
-       }
-       chunk_free(&this->nonce_i);
-       chunk_free(&this->nonce_r);
-       chunk_free(&this->init_request);
-       chunk_free(&this->init_response);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-ike_auth_t *ike_auth_create(ike_sa_t *ike_sa)
-{
-       private_ike_auth_t *this = malloc_thing(private_ike_auth_t);
-       
-       /* transaction interface functions */
-       this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
-       this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
-       this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
-       this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
-       this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
-       this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
-       
-       /* public functions */
-       this->public.set_config = (void(*)(ike_auth_t*,connection_t*,policy_t*))set_config;
-       this->public.set_reqid = (void(*)(ike_auth_t*,u_int32_t))set_reqid;
-       this->public.set_nonces = (void(*)(ike_auth_t*,chunk_t,chunk_t))set_nonces;
-       this->public.set_init_messages = (void(*)(ike_auth_t*,chunk_t,chunk_t))set_init_messages;
-       
-       /* private data */
-       this->ike_sa = ike_sa;
-       this->message_id = 0;
-       this->message = NULL;
-       this->requested = 0;
-       this->nonce_i = chunk_empty;
-       this->nonce_r = chunk_empty;
-       this->init_request = chunk_empty;
-       this->init_response = chunk_empty;
-       this->child_sa = NULL;
-       this->proposal = NULL;
-       this->policy = NULL;
-       this->connection = NULL;
-       this->tsi = NULL;
-       this->tsr = NULL;
-       this->build_child = TRUE;
-       this->eap_auth = NULL;
-       this->eap_next = NULL;
-       this->eap_only = FALSE;
-       this->peer_authenticated = FALSE;
-       this->reqid = 0;
-       this->cacerts = linked_list_create();
-       this->mode = MODE_TUNNEL;
-       
-       return &this->public;
-}
diff --git a/src/charon/sa/transactions/ike_auth.h b/src/charon/sa/transactions/ike_auth.h
deleted file mode 100644 (file)
index 490359e..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * @file ike_auth.h
- * 
- * @brief Interface of transaction ike_auth.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-
-#ifndef IKE_AUTH_H_
-#define IKE_AUTH_H_
-
-typedef struct ike_auth_t ike_auth_t;
-
-#include <sa/ike_sa.h>
-#include <sa/transactions/transaction.h>
-
-/**
- * @brief A transaction for the second message exchange to authenticate an IKE_SA.
- *
- * The second transaction is encrypted and authenticates the peers. It also
- * sets up a first CHILD_SA.
- *
- * @b Constructors:
- *  - ike_auth_create()
- *  - transaction_create() with the appropriate message
- *
- * @ingroup transactions
- */
-struct ike_auth_t {
-       
-       /**
-        * The transaction_t interface.
-        */
-       transaction_t transaction;
-       
-       /**
-        * @brief Set the config used for the ike_auth exchange.
-        *
-        * The connection definition is used to complete IKE_SA setup, the
-        * policy defines the CHILD_SA which is created along with the ike_auth
-        * exchange.
-        *
-        * @param this                  calling object
-        * @param connection    connection definition
-        * @param policy                policy definition
-        */
-       void (*set_config) (ike_auth_t* this, 
-                                               connection_t *connection, policy_t *policy);
-
-       /**
-        * @brief Set the reqid used for CHILD_SA setup.
-        *
-        * The first two message exchanges may set up an associated
-        * CHILD_SA. If we acquire, we must use the same reqid as the
-        * installed policy.
-        * 
-        * @param this                  calling object
-        * @param reqid                 reqid to use for the CHILD_SA
-        */
-       void (*set_reqid) (ike_auth_t* this, u_int32_t reqid);
-       
-       /**
-        * @brief Set the nonces used in the previous ike_sa_init transaction.
-        * 
-        * The nonces are used to create the authentication data.
-        * 
-        * @param this          calling object
-        * @param nonce_i       initiator chosen nonce
-        * @param nonce_r       responder chosen nonce
-        */
-       void (*set_nonces) (ike_auth_t* this, chunk_t nonce_i, chunk_t nonce_r);
-       
-       /**
-        * @brief Set the messages used in the previous ike_sa_init transaction.
-        * 
-        * The messages are used to create the authentication data.
-        * 
-        * @param this          calling object
-        * @param request       encoded request message as a chunk
-        * @param response      encoded response message as a chunk
-        */
-       void (*set_init_messages) (ike_auth_t* this, chunk_t request, chunk_t response);
-};
-
-/**
- * @brief Create a new transaction which processes IKE_AUTH exchanges.
- *
- * @param ike_sa               assigned IKE_SA
- * @return                             created ike_auth transaction
- *
- * @ingroup transactions
- */
-ike_auth_t *ike_auth_create(ike_sa_t *ike_sa);
-
-#endif /* IKE_AUTH_H_ */
diff --git a/src/charon/sa/transactions/ike_sa_init.c b/src/charon/sa/transactions/ike_sa_init.c
deleted file mode 100644 (file)
index b5728a9..0000000
+++ /dev/null
@@ -1,1121 +0,0 @@
-/**
- * @file ike_sa_init.c
- *
- * @brief Implementation of ike_sa_init_t transaction.
- *
- */
-
-/*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#include "ike_sa_init.h"
-
-#include <string.h>
-
-#include <daemon.h>
-#include <crypto/diffie_hellman.h>
-#include <crypto/hashers/hasher.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/ke_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-#include <sa/transactions/ike_auth.h>
-#include <queues/jobs/delete_ike_sa_job.h>
-#include <queues/jobs/rekey_ike_sa_job.h>
-
-
-typedef struct private_ike_sa_init_t private_ike_sa_init_t;
-
-/**
- * Private members of a ike_sa_init_t object..
- */
-struct private_ike_sa_init_t {
-       
-       /**
-        * Public methods and transaction_t interface.
-        */
-       ike_sa_init_t public;
-       
-       /**
-        * Assigned IKE_SA.
-        */
-       ike_sa_t *ike_sa;
-       
-       /**
-        * Message sent by our peer, if already generated
-        */
-       message_t *message;
-       
-       /**
-        * Message ID this transaction uses
-        */
-       u_int32_t message_id;
-       
-       /**
-        * Times we did send the request
-        */
-       u_int32_t requested;
-       
-       /**
-        * Next transaction followed to this one. May be IKE_AUTH,
-        * or a IKE_SA_INIT retry
-        */
-       transaction_t **next;
-               
-       /**
-        * Diffie hellman object used to generate public DH value.
-        */
-       diffie_hellman_t *diffie_hellman;
-       
-       /**
-        * initiator chosen nonce
-        */
-       chunk_t nonce_i;
-       
-       /**
-        * responder chosen nonce
-        */
-       chunk_t nonce_r;
-       
-       /**
-        * connection definition used for initiation
-        */
-       connection_t *connection;
-       
-       /**
-        * policy definition forwarded to ike_auth transaction
-        */
-       policy_t *policy;
-       
-       /**
-        * Negotiated proposal used for IKE_SA
-        */
-       proposal_t *proposal;
-       
-       /**
-        * Reqid to pass to IKE_AUTH, used for created CHILD_SA
-        */
-       u_int32_t reqid;
-       
-       /**
-        * Unique ID for to enumerate all IKE_SAs in its name
-        */
-       u_int32_t unique_id;
-       
-       /**
-        * Randomizer to generate nonces
-        */
-       randomizer_t *randomizer;
-       
-       /**
-        * Hasher used to build NAT detection hashes
-        */
-       hasher_t *nat_hasher;
-       
-       /**
-        * Precomputed NAT hash for source address
-        */
-       chunk_t natd_src_hash;
-       
-       /**
-        * Precomputed NAT hash for destination address
-        */
-       chunk_t natd_dst_hash;
-       
-       /**
-        * Did we process any NAT detection notifys for a source address?
-        */
-       bool natd_src_seen;
-       
-       /**
-        * Did we process any NAT detection notifys for a destination address?
-        */
-       bool natd_dst_seen;
-       
-       /**
-        * Have we found a matching source address NAT hash?
-        */
-       bool natd_src_matched;
-       
-       /**
-        * Have we found a matching destination address NAT hash?
-        */
-       bool natd_dst_matched;
-};
-
-/**
- * Implementation of ike_sa_init_t.use_dh_group.
- */
-static bool use_dh_group(private_ike_sa_init_t *this, diffie_hellman_group_t dh_group)
-{
-       if (this->connection->check_dh_group(this->connection, dh_group))
-       {
-               this->diffie_hellman = diffie_hellman_create(dh_group);
-               if (this->diffie_hellman)
-               {
-                       return TRUE;
-               }
-       }
-       return FALSE;
-}
-
-/**
- * Implementation of ike_sa_init_t.set_config.
- */
-static void set_config(private_ike_sa_init_t *this,
-                                          connection_t *connection, policy_t *policy)
-{
-       this->connection = connection;
-       this->policy = policy;
-}
-
-/**
- * Implementation of ike_sa_init_t.set_reqid.
- */
-static void set_reqid(private_ike_sa_init_t *this, u_int32_t reqid)
-{
-       this->reqid = reqid;
-}
-
-/**
- * Implementation of transaction_t.get_message_id.
- */
-static u_int32_t get_message_id(private_ike_sa_init_t *this)
-{
-       return this->message_id;
-}
-
-/**
- * Implementation of transaction_t.requested.
- */
-static u_int32_t requested(private_ike_sa_init_t *this)
-{
-       return this->requested++;
-}
-
-/**
- * Build NAT detection hash for a host
- */
-static chunk_t generate_natd_hash(private_ike_sa_init_t *this,
-                                                                 ike_sa_id_t * ike_sa_id, host_t *host)
-{
-       chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk;
-       chunk_t natd_hash;
-       u_int64_t spi_i, spi_r;
-       u_int16_t port;
-       
-       /* prepare all requred chunks */
-       spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
-       spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
-       spi_i_chunk.ptr = (void*)&spi_i;
-       spi_i_chunk.len = sizeof(spi_i);
-       spi_r_chunk.ptr = (void*)&spi_r;
-       spi_r_chunk.len = sizeof(spi_r);
-       port = htons(host->get_port(host));
-       port_chunk.ptr = (void*)&port;
-       port_chunk.len = sizeof(port);
-       addr_chunk = host->get_address(host);
-       
-       /*  natd_hash = SHA1( spi_i | spi_r | address | port ) */
-       natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk);
-       this->nat_hasher->allocate_hash(this->nat_hasher, natd_chunk, &natd_hash);
-       DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
-       DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
-       
-       chunk_free(&natd_chunk);
-       return natd_hash;
-}
-
-/**
- * Build a NAT detection notify payload.
- */
-static notify_payload_t *build_natd_payload(private_ike_sa_init_t *this,
-                                                                                       notify_type_t type, host_t *host)
-{
-       chunk_t hash;
-       notify_payload_t *notify;       
-       ike_sa_id_t *ike_sa_id; 
-       
-       ike_sa_id = this->ike_sa->get_id(this->ike_sa);
-       notify = notify_payload_create();
-       notify->set_notify_type(notify, type);
-       hash = generate_natd_hash(this, ike_sa_id, host);
-       notify->set_notification_data(notify, hash);
-       chunk_free(&hash);
-       
-       return notify;
-}
-
-/**
- * Implementation of transaction_t.get_request.
- */
-static status_t get_request(private_ike_sa_init_t *this, message_t **result)
-{
-       message_t *request;
-       host_t *me, *other;
-       identification_t *my_id, *other_id;
-       char name[64];
-       
-       /* check if we already have built a message (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       
-       /* we already set up the IDs. Mine is already fully qualified, other
-        * will be updated in the ike_auth transaction */
-       my_id = this->policy->get_my_id(this->policy);
-       other_id = this->policy->get_other_id(this->policy);
-       this->ike_sa->set_my_id(this->ike_sa, my_id->clone(my_id));
-       this->ike_sa->set_other_id(this->ike_sa, other_id->clone(other_id));
-       if (snprintf(name, sizeof(name), "%s{%d}",
-                                this->connection->get_name(this->connection),
-                                this->unique_id) > 0)
-       {
-               this->ike_sa->set_name(this->ike_sa, name);
-       }
-       
-       /* setting up a IKE_SA implicitly requires setup of a CHILD_SA */
-       SIG(IKE_UP_START, "initiating IKE_SA '%s' between %H[%D]...%H[%D]",
-               this->connection->get_name(this->connection), me, my_id, other, other_id);
-       SIG(CHILD_UP_START, "establishing CHILD_SA '%s' along with IKE_SA",
-               this->policy->get_name(this->policy));
-       
-       /* build the request */
-       request = message_create();
-       request->set_source(request, me->clone(me));
-       request->set_destination(request, other->clone(other));
-       request->set_exchange_type(request, IKE_SA_INIT);
-       request->set_request(request, TRUE);
-       request->set_message_id(request, this->message_id);
-       request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
-       /* apply for caller */
-       *result = request;
-       /* store for retransmission */
-       this->message = request;
-       
-       /* if the DH group is set via use_dh_group(), we already have a DH object */
-       if (!this->diffie_hellman)
-       {
-               diffie_hellman_group_t dh_group;
-               
-               dh_group = this->connection->get_dh_group(this->connection);
-               this->diffie_hellman = diffie_hellman_create(dh_group);
-               if (this->diffie_hellman == NULL)
-               {
-                       SIG(IKE_UP_FAILED, "DH group %N not supported, aborting",
-                               diffie_hellman_group_names, dh_group);
-                       SIG(CHILD_UP_FAILED,
-                               "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-       }
-       
-       {       /* build the SA payload from proposals */
-               sa_payload_t *sa_payload;
-               linked_list_t *proposal_list;
-               
-               proposal_list = this->connection->get_proposals(this->connection);
-               sa_payload = sa_payload_create_from_proposal_list(proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-               
-               request->add_payload(request, (payload_t*)sa_payload);
-       }
-       
-       {       /* build the KE payload from the DH object */
-               ke_payload_t *ke_payload;
-               
-               ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
-               
-               request->add_payload(request, (payload_t*)ke_payload);
-       }
-       
-       {       /* build the NONCE payload for us (initiator) */
-               nonce_payload_t *nonce_payload;
-               
-               if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer, 
-                       NONCE_SIZE, &this->nonce_i) != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "could not generate nonce, aborting");
-                       SIG(CHILD_UP_FAILED,
-                               "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-               nonce_payload = nonce_payload_create();
-               nonce_payload->set_nonce(nonce_payload, this->nonce_i);
-               
-               request->add_payload(request, (payload_t*)nonce_payload);
-       }
-       
-       {       /* build NAT_DETECTION notifys */
-               notify_payload_t *notify;
-               linked_list_t *list;
-               host_t *host;
-               
-               /* N(NAT_DETECTION_SOURCE_IP)+
-                * we include only one notify if our address is defined, but all
-                * possible if not */
-               host = this->ike_sa->get_my_host(this->ike_sa);
-               if (host->is_anyaddr(host))
-               {
-                       /* TODO: we could get the src address from netlink */
-                       list = charon->socket->create_local_address_list(charon->socket);
-                       while (list->remove_first(list, (void**)&host) == SUCCESS)
-                       {
-                               notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
-                               host->destroy(host);
-                               request->add_payload(request, (payload_t*)notify);
-                       }
-                       list->destroy(list);
-               }
-               else
-               {
-                       notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
-                       request->add_payload(request, (payload_t*)notify);
-               }
-               
-               /* N(NAT_DETECTION_DESTINATION_IP) */
-               notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
-               request->add_payload(request, (payload_t*)notify);
-       }
-       
-       this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
-       return SUCCESS;
-}
-
-/**
- * Handle all kind of notifys
- */
-static status_t process_notifys(private_ike_sa_init_t *this, notify_payload_t *notify_payload)
-{
-       chunk_t notification_data;
-       notify_type_t notify_type = notify_payload->get_notify_type(notify_payload);
-       
-       DBG2(DBG_IKE, "process notify type %N", notify_type_names, notify_type);
-
-       switch (notify_type)
-       {
-               case NO_PROPOSAL_CHOSEN:
-               {
-                       SIG(IKE_UP_FAILED,
-                               "received a NO_PROPOSAL_CHOSEN notify, deleting IKE_SA");
-                       return DESTROY_ME;
-               }
-               case INVALID_MAJOR_VERSION:
-               {
-                       SIG(IKE_UP_FAILED,
-                               "received a INVALID_MAJOR_VERSION notify, deleting IKE_SA");
-                       return DESTROY_ME;
-               }
-               case INVALID_KE_PAYLOAD:
-               {
-                       chunk_t notify_data;
-                       diffie_hellman_group_t dh_group, old_dh_group;
-                       ike_sa_init_t *retry;
-                       
-                       old_dh_group = this->connection->get_dh_group(this->connection);
-                       notify_data = notify_payload->get_notification_data(notify_payload);
-                       dh_group = ntohs(*((u_int16_t*)notify_data.ptr));
-                       
-                       DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested %N",
-                                diffie_hellman_group_names, old_dh_group,
-                                diffie_hellman_group_names, dh_group);
-                       if (!this->connection->check_dh_group(this->connection, dh_group))
-                       {
-                               SIG(IKE_UP_FAILED, "DH group %N not acceptable, aborting",
-                                   diffie_hellman_group_names, dh_group);
-                               return DESTROY_ME;
-                       }
-                       retry = ike_sa_init_create(this->ike_sa);
-                       retry->set_config(retry, this->connection, this->policy);
-                       this->connection = NULL;
-                       this->policy = NULL;
-                       retry->use_dh_group(retry, dh_group);
-                       *this->next = (transaction_t*)retry;
-                       return FAILED;
-               }
-               case NAT_DETECTION_DESTINATION_IP:
-               {
-                       this->natd_dst_seen = TRUE;
-                       if (this->natd_dst_matched)
-                       {
-                               return SUCCESS;
-                       }
-                       notification_data = notify_payload->get_notification_data(notify_payload);
-                       if (chunk_equals(notification_data, this->natd_dst_hash))
-                       {
-                               this->natd_dst_matched = TRUE;
-                               DBG2(DBG_IKE, "NAT-D dst hash match");
-                       }
-                       else
-                       {
-                               DBG2(DBG_IKE, "NAT-D dst hash mismatch");
-                       }
-                       return SUCCESS;
-               }
-               case NAT_DETECTION_SOURCE_IP:
-               {
-                       this->natd_src_seen = TRUE;;
-                       if (this->natd_src_matched)
-                       {
-                               return SUCCESS;
-                       }
-                       notification_data = notify_payload->get_notification_data(notify_payload);
-                       if (chunk_equals(notification_data, this->natd_src_hash))
-                       {
-                               this->natd_src_matched = TRUE;
-                               DBG2(DBG_IKE, "NAT-D src hash match");
-                       }
-                       else
-                       {
-                               DBG2(DBG_IKE, "NAT-D src hash mismatch");
-                       }
-                       return SUCCESS;
-               }
-               default:
-               {
-                       if (notify_type < 16383)
-                       {
-                               SIG(IKE_UP_FAILED, "received %N notify error, deleting IKE_SA",
-                                       notify_type_names, notify_type);
-                               return DESTROY_ME;      
-                       }
-                       else
-                       {
-                               DBG1(DBG_IKE, "received %N notify, ignored",
-                                       notify_type_names, notify_type);
-                               return SUCCESS;
-                       }
-               }
-       }
-}
-
-/**
- * Implementation of transaction_t.get_response.
- */
-static status_t get_response(private_ike_sa_init_t *this, 
-                                                        message_t *request, message_t **result,
-                                                        transaction_t **next)
-{
-       host_t *me, *other;
-       message_t *response;
-       status_t status;
-       iterator_t *payloads;
-       payload_t *payload;
-       sa_payload_t *sa_request = NULL;
-       ke_payload_t *ke_request = NULL;
-       nonce_payload_t *nonce_request = NULL;
-       ike_sa_id_t *ike_sa_id;
-       u_int32_t timeout;
-       char name[64];
-       
-       /* check if we already have built a response (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = request->get_destination(request);
-       other = request->get_source(request);
-       this->message_id = request->get_message_id(request);
-       
-       SIG(IKE_UP_START, "establishing IKE_SA between %H...%H", me, other);
-       
-       /* set up response */
-       response = message_create();
-       response->set_source(response, me->clone(me));
-       response->set_destination(response, other->clone(other));
-       response->set_exchange_type(response, IKE_SA_INIT);
-       response->set_request(response, FALSE);
-       response->set_message_id(response, this->message_id);
-       response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
-       this->message = response;
-       *result = response;
-       
-       /* check message type */
-       if (request->get_exchange_type(request) != IKE_SA_INIT)
-       {
-               SIG(IKE_UP_FAILED, "IKE_SA_INIT request of invalid type, deleting IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       /* this is the first message to process, find a connection for IKE_SA */
-       this->connection = charon->connections->get_connection_by_hosts(
-                       charon->connections, me, other);
-       if (this->connection == NULL)
-       {
-               notify_payload_t *notify = notify_payload_create();
-               notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
-               response->add_payload(response, (payload_t*)notify);
-               
-               SIG(IKE_UP_FAILED, "no connection for hosts %H...%H found, "
-                       "deleting IKE_SA", me, other);
-               return DESTROY_ME;
-       }
-       
-       if (snprintf(name, sizeof(name), "%s{%d}",
-                                this->connection->get_name(this->connection),
-                                this->unique_id) > 0)
-       {
-               this->ike_sa->set_name(this->ike_sa, name);
-       }
-       this->ike_sa->apply_connection(this->ike_sa, this->connection);
-       
-       /* Precompute NAT-D hashes for incoming NAT notify comparison */
-       ike_sa_id = request->get_ike_sa_id(request);
-       this->natd_dst_hash = generate_natd_hash(this, ike_sa_id, me);
-       this->natd_src_hash = generate_natd_hash(this, ike_sa_id, other);
-       
-       /* Iterate over all payloads. */
-       payloads = request->get_payload_iterator(request);
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case SECURITY_ASSOCIATION:
-                               sa_request = (sa_payload_t*)payload;
-                               break;
-                       case KEY_EXCHANGE:
-                               ke_request = (ke_payload_t*)payload;
-                               break;
-                       case NONCE:
-                               nonce_request = (nonce_payload_t*)payload;
-                               break;
-                       case NOTIFY:
-                       {
-                               status = process_notifys(this, (notify_payload_t*)payload);
-                               if (status == FAILED)
-                               {
-                                       payloads->destroy(payloads);
-                                       /* we return SUCCESS, returned FAILED means do next transaction */
-                                       return SUCCESS;
-                               }
-                               if (status == DESTROY_ME)
-                               {
-                                       payloads->destroy(payloads);
-                                       return DESTROY_ME;
-                               }
-                               break;
-                       }
-                       default:
-                       {
-                               DBG2(DBG_IKE, "ignoring %N payload",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       
-       /* check if we have all payloads */
-       if (!(sa_request && ke_request && nonce_request))
-       {
-               notify_payload_t *notify = notify_payload_create();
-               notify->set_notify_type(notify, INVALID_SYNTAX);
-               response->add_payload(response, (payload_t*)notify);
-               SIG(IKE_UP_FAILED, "received request message incomplete, deleting IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       {       /* process SA payload:
-                * -------------------
-                * - extract proposals
-                * - select our most preferred proposal found in extracted
-                *   - if no matches, return NO_PROPOSAL_CHOSEN
-                * - add sa payload with selected proposal
-                */
-               sa_payload_t* sa_response;
-               linked_list_t *proposal_list;
-       
-               proposal_list = sa_request->get_proposals(sa_request);
-               this->proposal = this->connection->select_proposal(this->connection, proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-               if (this->proposal == NULL)
-               {
-                       notify_payload_t *notify = notify_payload_create();
-                       notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
-                       response->add_payload(response, (payload_t*)notify);
-                       SIG(IKE_UP_FAILED, "request did not contain any acceptable "
-                               "proposals, deleting IKE_SA");
-                       return DESTROY_ME;
-               }
-               sa_response = sa_payload_create_from_proposal(this->proposal);  
-               response->add_payload(response, (payload_t *)sa_response);
-       }
-       
-       {       /* process KE payload:
-                * --------------------
-                * - check if used group match the selected proposal
-                *   - if not, stop with INVALID_KE_PAYLOAD
-                * - apply others public value to complete diffie hellman exchange
-                * - add our public value to response
-                */
-               diffie_hellman_group_t used_group;
-               ke_payload_t *ke_response;
-               
-               used_group = ke_request->get_dh_group_number(ke_request);
-               
-               if (!this->connection->check_dh_group(this->connection, used_group) ||
-                       (this->diffie_hellman = diffie_hellman_create(used_group)) == NULL)
-               {
-                       u_int16_t notify_group;
-                       chunk_t notify_chunk;
-                       notify_payload_t *notify;
-                       iterator_t *iterator;
-                       payload_t *payload;
-                       
-                       notify_group = this->connection->get_dh_group(this->connection);
-                       SIG(IKE_UP_FAILED, "request used inacceptable DH group %N, sending "
-                               "INVALID_KE_PAYLOAD with %N, deleting IKE_SA",
-                               diffie_hellman_group_names, used_group,
-                               diffie_hellman_group_names, notify_group);
-                       
-                       /* remove already added payloads */
-                       iterator = response->get_payload_iterator(response);
-                       while (iterator->iterate(iterator, (void**)&payload))
-                       {
-                               iterator->remove(iterator);
-                               payload->destroy(payload);
-                       }
-                       iterator->destroy(iterator);
-                       
-                       notify_group = htons(notify_group);
-                       notify_chunk.ptr = (u_int8_t*)&notify_group;
-                       notify_chunk.len = sizeof(notify_group);
-                       notify = notify_payload_create();
-                       notify->set_notify_type(notify, INVALID_KE_PAYLOAD);
-                       notify->set_notification_data(notify, notify_chunk);
-                       response->add_payload(response, (payload_t*)notify);
-                       return DESTROY_ME;
-               }
-               this->diffie_hellman->set_other_public_value(this->diffie_hellman,
-                               ke_request->get_key_exchange_data(ke_request));
-               
-               /* build response */
-               ke_response = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
-               response->add_payload(response, (payload_t*)ke_response);
-       }
-       
-       {       /* process nonce payload:
-                * ----------------------
-                * - get nonce from payload
-                * - generate own nonce and add to reply
-                */
-               nonce_payload_t *nonce_response;
-               
-               this->nonce_i = nonce_request->get_nonce(nonce_request);
-               
-               /* build response nonce */
-               if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer, 
-                       NONCE_SIZE, &this->nonce_r) != SUCCESS)
-               {
-                       notify_payload_t *notify = notify_payload_create();
-                       notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
-                       response->add_payload(response, (payload_t*)notify);
-                       SIG(IKE_UP_FAILED, "could not create nonce, deleting IKE_SA");
-                       return DESTROY_ME;
-               }
-               nonce_response = nonce_payload_create();
-               nonce_response->set_nonce(nonce_response, this->nonce_r);
-               response->add_payload(response, (payload_t *)nonce_response);
-       }
-
-       {       /* processs NATT stuff:
-                * --------------------
-                * - check if we or other is behind NAT
-                * - enable NATT if so
-                * - build NAT detection notifys for reply
-                */
-               notify_payload_t *notify;
-               
-               if ((!this->natd_src_seen && this->natd_dst_seen) ||
-                   (this->natd_src_seen && !this->natd_dst_seen))
-               {
-                       notify = notify_payload_create();
-                       notify->set_notify_type(notify, INVALID_SYNTAX);
-                       response->add_payload(response, (payload_t*)notify);
-                       SIG(IKE_UP_FAILED, "request contained invalid number of NAT-D"
-                               "payloads, deleting IKE_SA");
-                       return DESTROY_ME;
-               }
-               if (this->natd_dst_seen && !this->natd_dst_matched)
-               {
-                       this->ike_sa->enable_natt(this->ike_sa, TRUE);
-               }
-               if (this->natd_src_seen && !this->natd_src_matched)
-               {
-                       this->ike_sa->enable_natt(this->ike_sa, FALSE);
-               }
-               /* build response NAT DETECTION notifys, if remote supports it */
-               if (this->natd_src_seen || this->natd_dst_seen)
-               {
-                       /* N(NAT_DETECTION_SOURCE_IP) */
-                       notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
-                       response->add_payload(response, (payload_t*)notify);
-                       
-                       /* N(NAT_DETECTION_DESTINATION_IP) */
-                       notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
-                       response->add_payload(response, (payload_t*)notify);
-               }
-       }
-
-       /* derive all the keys used in the IKE_SA */
-       if (this->ike_sa->derive_keys(this->ike_sa, this->proposal, 
-                                                                 this->diffie_hellman, 
-                                                                 this->nonce_i, this->nonce_r,
-                                                                 FALSE, NULL, NULL) != SUCCESS)
-       {
-               notify_payload_t *notify = notify_payload_create();
-               notify->set_notify_type(notify, NO_PROPOSAL_CHOSEN);
-               response->add_payload(response, (payload_t*)notify);
-               SIG(IKE_UP_FAILED, "error creating transforms from proposal, deleting IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       this->ike_sa->set_lifetimes(this->ike_sa,
-                                       this->connection->get_reauth(this->connection),
-                                       this->connection->get_soft_lifetime(this->connection),
-                                       this->connection->get_hard_lifetime(this->connection));
-       
-       {       /* create ike_auth transaction, which will store informations for us */
-               packet_t *response_packet;
-               chunk_t request_chunk, response_chunk;
-               ike_auth_t *ike_auth;
-               
-               /* we normally do not generate the message. But we need the generated message
-                * for authentication in the next state, so we do it here. This is not problematic,
-                * as we don't use a crypter/signer in ike_sa_init... */
-               if (response->generate(response, NULL, NULL, &response_packet) != SUCCESS)
-               {
-                       SIG(IKE_UP_FAILED, "error in response generation, deleting IKE_SA");
-                       return DESTROY_ME;
-               }
-               response_packet->destroy(response_packet);
-               request_chunk = request->get_packet_data(request);
-               response_chunk = response->get_packet_data(response);
-               
-               /* create next transaction, for which we except a message */
-               ike_auth = ike_auth_create(this->ike_sa);
-               ike_auth->set_config(ike_auth, this->connection, this->policy);
-               ike_auth->set_reqid(ike_auth, this->reqid);
-               this->connection = NULL;
-               this->policy = NULL;
-               ike_auth->set_nonces(ike_auth,
-                                                        chunk_clone(this->nonce_i),
-                                                        chunk_clone(this->nonce_r));
-               ike_auth->set_init_messages(ike_auth, request_chunk, response_chunk);
-               *next = (transaction_t*)ike_auth;
-       }
-       
-       /* everything went fine. Now we set a timeout to destroy half initiated IKE_SAs */
-       timeout = charon->configuration->get_half_open_ike_sa_timeout(charon->configuration);
-       if (timeout)
-       {
-               job_t *job = (job_t*)delete_ike_sa_job_create(
-                                               this->ike_sa->get_id(this->ike_sa), FALSE);
-               charon->event_queue->add_relative(charon->event_queue, job, timeout);
-       }
-       /* set new state */
-       this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
-       
-       return SUCCESS;
-}
-
-
-/**
- * Implementation of transaction_t.conclude
- */
-static status_t conclude(private_ike_sa_init_t *this, message_t *response, 
-                                                transaction_t **next)
-{
-       u_int64_t responder_spi;
-       ike_sa_id_t *ike_sa_id;
-       iterator_t *payloads;
-       payload_t *payload;
-       host_t *me, *other;
-       sa_payload_t *sa_payload = NULL;
-       ke_payload_t *ke_payload = NULL;
-       nonce_payload_t *nonce_payload = NULL;
-       status_t status;
-       
-       /* check message type */
-       if (response->get_exchange_type(response) != IKE_SA_INIT)
-       {
-               SIG(IKE_UP_FAILED, "IKE_SA_INIT response of invalid type, deleting IKE_SA");
-               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       /* allow setting of next transaction in other functions */
-       this->next = next;
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       
-       /* check if SPI has been updated, but apply only if all goes ok later */
-       responder_spi = response->get_responder_spi(response);
-       if (responder_spi == 0)
-       {
-               SIG(IKE_UP_FAILED, "response contained a SPI of zero, deleting IKE_SA");
-               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       /* Precompute NAT-D hashes for later comparison */
-       ike_sa_id = response->get_ike_sa_id(response);
-       this->natd_src_hash = generate_natd_hash(this, ike_sa_id, other);
-       this->natd_dst_hash = generate_natd_hash(this, ike_sa_id, me);
-       
-       /* Iterate over all payloads to collect them */
-       payloads = response->get_payload_iterator(response);
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case SECURITY_ASSOCIATION:
-                       {
-                               sa_payload = (sa_payload_t*)payload;
-                               break;
-                       }
-                       case KEY_EXCHANGE:
-                       {
-                               ke_payload = (ke_payload_t*)payload;
-                               break;
-                       }
-                       case NONCE:
-                       {
-                               nonce_payload = (nonce_payload_t*)payload;
-                               break;
-                       }
-                       case NOTIFY:
-                       {
-                               status = process_notifys(this, (notify_payload_t*)payload);
-                               if (status == FAILED)
-                               {
-                                       payloads->destroy(payloads);
-                                       /* we return SUCCESS, returned FAILED means do next transaction */
-                                       return SUCCESS;
-                               }
-                               if (status == DESTROY_ME)
-                               {
-                                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                                       payloads->destroy(payloads);
-                                       return status;
-                               }
-                               break;
-                       }
-                       default:
-                       {
-                               DBG1(DBG_IKE, "ignoring payload %N",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       
-       if (!(nonce_payload && sa_payload && ke_payload))
-       {
-               SIG(IKE_UP_FAILED, "response message incomplete, deleting IKE_SA");
-               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       {       /* process SA payload:
-                * -------------------
-                * - get proposals from it
-                * - check if peer selected a proposal
-                * - verify it's selection againts our set
-                */
-               linked_list_t *proposal_list;
-               
-               /* get the list of selected proposals, the peer has to select only one proposal */
-               proposal_list = sa_payload->get_proposals (sa_payload);
-               if (proposal_list->get_count(proposal_list) != 1)
-               {
-                       SIG(IKE_UP_FAILED, "response did not contain a single proposal, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-                       return DESTROY_ME;
-               }
-               
-               /* we have to re-check if the others selection is valid */
-               this->proposal = this->connection->select_proposal(this->connection, proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-               
-               if (this->proposal == NULL)
-               {
-                       SIG(IKE_UP_FAILED, "peer selected a proposal we did not offer, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-       }
-       
-       {       /* process KE payload:
-                * -------------------
-                * - extract others public value
-                * - complete diffie-hellman exchange
-                */
-               this->diffie_hellman->set_other_public_value(this->diffie_hellman,
-                               ke_payload->get_key_exchange_data(ke_payload));
-       }
-       
-       {       /* process NONCE payload:
-                * ----------------------
-                * - extract nonce used for key derivation */
-               this->nonce_r = nonce_payload->get_nonce(nonce_payload);
-       }
-       
-       {       /* process NATT stuff:
-                * -------------------
-                * - check if we or other is NATted
-                * - switch to port 4500 if so
-                */
-               if ((!this->natd_dst_seen && this->natd_src_seen) ||
-                       (this->natd_dst_seen && !this->natd_src_seen))
-               {
-                       SIG(IKE_UP_FAILED, "request contained invalid number of NAT-D payloads, deleting IKE_SA");
-                       SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-                       return DESTROY_ME;
-               }
-               if (this->natd_src_seen && !this->natd_src_matched)
-               {
-                       this->ike_sa->enable_natt(this->ike_sa, FALSE);
-               }
-               if (this->natd_dst_seen && !this->natd_dst_matched)
-               {
-                       this->ike_sa->enable_natt(this->ike_sa, TRUE);
-               }
-               if (this->ike_sa->is_natt_enabled(this->ike_sa))
-               {
-                       me = this->ike_sa->get_my_host(this->ike_sa);
-                       me->set_port(me, IKEV2_NATT_PORT);
-                       other = this->ike_sa->get_other_host(this->ike_sa);
-                       other->set_port(other, IKEV2_NATT_PORT);
-                       
-                       DBG2(DBG_IKE, "switching to port %d", IKEV2_NATT_PORT);
-               }
-       }
-       
-       /* because we are original initiator we have to update the responder SPI to the new one */
-       ike_sa_id = this->ike_sa->get_id(this->ike_sa);
-       ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
-       
-       /* derive all the keys used in the IKE_SA */
-       if (this->ike_sa->derive_keys(this->ike_sa, this->proposal, 
-                                                                 this->diffie_hellman, 
-                                                                 this->nonce_i, this->nonce_r,
-                                                                 TRUE, NULL, NULL) != SUCCESS)
-       {
-               SIG(IKE_UP_FAILED, "error creating transforms from proposal, deleting IKE_SA");
-               SIG(CHILD_UP_FAILED, "initiating CHILD_SA failed, unable to create IKE_SA");
-               return DESTROY_ME;
-       }
-       
-       this->ike_sa->set_lifetimes(this->ike_sa, 
-                                       this->connection->get_reauth(this->connection),
-                                       this->connection->get_soft_lifetime(this->connection),
-                                       this->connection->get_hard_lifetime(this->connection));
-       
-       {       /* create ike_auth transaction, which will continue IKE_SA setup */
-               chunk_t request_chunk, response_chunk;
-               ike_auth_t *ike_auth;
-               
-               request_chunk = this->message->get_packet_data(this->message);
-               response_chunk = response->get_packet_data(response);
-               
-               /* create next transaction, for which we except a message */
-               ike_auth = ike_auth_create(this->ike_sa);
-               ike_auth->set_config(ike_auth, this->connection, this->policy);
-               ike_auth->set_reqid(ike_auth, this->reqid);
-               this->connection = NULL;
-               this->policy = NULL;
-               ike_auth->set_nonces(ike_auth,
-                                                        chunk_clone(this->nonce_i),
-                                                        chunk_clone(this->nonce_r));
-               ike_auth->set_init_messages(ike_auth, request_chunk, response_chunk);
-               *next = (transaction_t*)ike_auth;
-       }
-       
-       return SUCCESS;
-}
-
-static void destroy(private_ike_sa_init_t *this)
-{
-       DESTROY_IF(this->message);
-       DESTROY_IF(this->diffie_hellman);
-       DESTROY_IF(this->proposal);
-       DESTROY_IF(this->connection);
-       DESTROY_IF(this->policy);
-       chunk_free(&this->nonce_i);
-       chunk_free(&this->nonce_r);
-       this->randomizer->destroy(this->randomizer);
-       this->nat_hasher->destroy(this->nat_hasher);
-       chunk_free(&this->natd_src_hash);
-       chunk_free(&this->natd_dst_hash);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa)
-{
-       static u_int unique_id = 0;
-       private_ike_sa_init_t *this = malloc_thing(private_ike_sa_init_t);
-
-       /* transaction interface functions */
-       this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
-       this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
-       this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
-       this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
-       this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
-       this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
-       
-       /* public functions */
-       this->public.set_config = (void(*)(ike_sa_init_t*,connection_t*,policy_t*))set_config;
-       this->public.set_reqid = (void(*)(ike_sa_init_t*,u_int32_t))set_reqid;
-       this->public.use_dh_group = (bool(*)(ike_sa_init_t*,diffie_hellman_group_t))use_dh_group;
-       
-       /* private data */
-       this->ike_sa = ike_sa;
-       this->message_id = 0;
-       this->message = NULL;
-       this->requested = 0;
-       this->diffie_hellman = NULL;
-       this->nonce_i = chunk_empty;
-       this->nonce_r = chunk_empty;
-       this->connection = NULL;
-       this->policy = NULL;
-       this->proposal = NULL;
-       this->unique_id = ++unique_id;
-       this->reqid = 0;
-       this->randomizer = randomizer_create();
-       this->nat_hasher = hasher_create(HASH_SHA1);
-       this->natd_src_hash = chunk_empty;
-       this->natd_dst_hash = chunk_empty;
-       this->natd_src_seen = FALSE;
-       this->natd_dst_seen = FALSE;
-       this->natd_src_matched = FALSE;
-       this->natd_dst_matched = FALSE;
-       
-       return &this->public;
-}
diff --git a/src/charon/sa/transactions/ike_sa_init.h b/src/charon/sa/transactions/ike_sa_init.h
deleted file mode 100644 (file)
index ab820fe..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * @file ike_sa_init.h
- * 
- * @brief Interface of transaction ike_sa_init.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-
-#ifndef IKE_SA_INIT_H_
-#define IKE_SA_INIT_H_
-
-typedef struct ike_sa_init_t ike_sa_init_t;
-
-#include <sa/ike_sa.h>
-#include <sa/transactions/transaction.h>
-
-/**
- * @brief A transaction for the first message exchange to set up an IKE_SA.
- * 
- * @b Constructors:
- *  - ike_sa_init_create()
- *  - transaction_create() with the appropriate message
- * 
- * @ingroup transactions
- */
-struct ike_sa_init_t {
-       
-       /**
-        * The transaction_t interface.
-        */
-       transaction_t transaction;
-       
-       /**
-        * @brief Set connection & policy to use for initiation.
-        *
-        * The policy is not used directly, but forwarded to the 
-        * ike_auth transaction.
-        * 
-        * @param this                  calling object
-        * @param connection    connection to use for initiation
-        * @param policy                policy used in ike_auth transaction
-        */
-       void (*set_config) (ike_sa_init_t* this, 
-                                               connection_t *connection, policy_t *policy);
-
-       /**
-        * @brief Set the reqid used for CHILD_SA setup.
-        *
-        * The first two message exchanges may set up an associated
-        * CHILD_SA. If we acquire, we must use the same reqid as the
-        * installed policy. This requid is passed to the ike_auth
-        * transaction which creates the CHILD_AS.
-        * 
-        * @param this                  calling object
-        * @param reqid                 reqid to use for the CHILD_SA
-        */
-       void (*set_reqid) (ike_sa_init_t* this, u_int32_t reqid);
-       
-       /**
-        * @brief Set the Diffie Hellman group to use for initiating.
-        * 
-        * If a first exchange fails with a INVALID_KE_PAYLOAD, the second
-        * try uses the DH group proposed by the responder.
-        * 
-        * @param this          calling object
-        * @param dh_group      diffie hellman group to use
-        * @return                      FALSE, if DH group not allowed/supported
-        */
-       bool (*use_dh_group) (ike_sa_init_t* this, diffie_hellman_group_t dh_group);
-};
-
-/**
- * @brief Create a new transaction which processes IKE_SA_INIT exchanges.
- *
- * @param ike_sa               assigned IKE_SA
- * @return                             created ike_sa_init transaction
- *
- * @ingroup transactions
- */
-ike_sa_init_t *ike_sa_init_create(ike_sa_t *ike_sa);
-
-#endif /* IKE_SA_INIT_H_ */
diff --git a/src/charon/sa/transactions/rekey_ike_sa.c b/src/charon/sa/transactions/rekey_ike_sa.c
deleted file mode 100644 (file)
index 23e7e56..0000000
+++ /dev/null
@@ -1,889 +0,0 @@
-/**
- * @file rekey_ike_sa.c
- *
- * @brief Implementation of rekey_ike_sa_t transaction.
- *
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#include "rekey_ike_sa.h"
-
-#include <string.h>
-
-#include <daemon.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-#include <encoding/payloads/ke_payload.h>
-#include <sa/transactions/delete_ike_sa.h>
-#include <utils/randomizer.h>
-
-
-typedef struct private_rekey_ike_sa_t private_rekey_ike_sa_t;
-
-/**
- * Private members of a rekey_ike_sa_t object..
- */
-struct private_rekey_ike_sa_t {
-       
-       /**
-        * Public methods and transaction_t interface.
-        */
-       rekey_ike_sa_t public;
-       
-       /**
-        * Assigned IKE_SA.
-        */
-       ike_sa_t *ike_sa;
-       
-       /**
-        * Message sent by our peer, if already generated
-        */
-       message_t *message;
-       
-       /**
-        * Message ID this transaction uses
-        */
-       u_int32_t message_id;
-       
-       /**
-        * Times we did send the request
-        */
-       u_int32_t requested;
-       
-       /**
-        * IKE_SA we set up, replaces ike_sa
-        */
-       ike_sa_t *new_sa;
-       
-       /**
-        * Connection used to replace IKE_SA
-        */
-       connection_t *connection;
-       
-       /**
-        * initiator chosen nonce
-        */
-       chunk_t nonce_i;
-       
-       /**
-        * responder chosen nonce
-        */
-       chunk_t nonce_r;
-       
-       /**
-        * lower of the nonces of a simultaneus rekeying request
-        */
-       chunk_t nonce_s;
-       
-       /**
-        * Diffie hellman to generate new shared secret
-        */
-       diffie_hellman_t *diffie_hellman;
-       
-       /**
-        * negotiated proposal to use
-        */
-       proposal_t *proposal;
-       
-       /**
-        * Have we lost the simultaneous rekeying nonce compare?
-        */
-       bool lost;
-       
-       /**
-        * source of randomness for nonces
-        */
-       randomizer_t *randomizer;
-       
-       /**
-        * next transaction processed by the IKE_SA
-        */
-       transaction_t **next;
-};
-
-/**
- * Implementation of transaction_t.get_message_id.
- */
-static u_int32_t get_message_id(private_rekey_ike_sa_t *this)
-{
-       return this->message_id;
-}
-
-/**
- * Implementation of transaction_t.requested.
- */
-static u_int32_t requested(private_rekey_ike_sa_t *this)
-{
-       return this->requested++;
-}
-
-
-/**
- * Implementation of rekey_ike_sa_t.use_dh_group.
- */
-static void use_dh_group(private_rekey_ike_sa_t *this, diffie_hellman_group_t dh_group)
-{
-       this->diffie_hellman = diffie_hellman_create(dh_group);
-}
-
-/**
- * Implementation of rekey_ike_sa_t.cancel.
- */
-static void cancel(private_rekey_ike_sa_t *this)
-{
-       this->lost = TRUE;
-}
-
-/**
- * Implementation of transaction_t.get_request.
- */
-static status_t get_request(private_rekey_ike_sa_t *this, message_t **result)
-{
-       message_t *request;
-       host_t *me, *other;
-       
-       /* check if we already have built a message (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       /* check for correct state, except when retrying with another dh group */
-       if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED &&
-           !this->diffie_hellman)
-       {
-               DBG1(DBG_IKE, "tried to rekey in state %N, aborted",
-                        ike_sa_state_names, this->ike_sa->get_state(this->ike_sa));
-               return FAILED;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       
-       /* build the request */
-       request = message_create();
-       request->set_source(request, me->clone(me));
-       request->set_destination(request, other->clone(other));
-       request->set_exchange_type(request, CREATE_CHILD_SA);
-       request->set_request(request, TRUE);
-       request->set_ike_sa_id(request, this->ike_sa->get_id(this->ike_sa));
-       *result = request;
-       this->message = request;
-       
-       {       /* build SA payload */
-               sa_payload_t *sa_payload;
-               linked_list_t *proposals;
-               ike_sa_id_t *ike_sa_id;
-               iterator_t *iterator;
-               proposal_t *proposal;
-               u_int64_t spi;
-               
-               /* get a connection to replace current IKE_SA */
-               this->connection = charon->connections->get_connection_by_name(
-                                                                               charon->connections,
-                                                                               this->ike_sa->get_name(this->ike_sa));
-               /* if connection lookup by name fails, try it with the hosts */
-               if (this->connection == NULL)
-               {
-                       this->connection = charon->connections->get_connection_by_hosts(
-                                                                               charon->connections,
-                                                                               me, other);
-                       if (this->connection == NULL)
-                       {
-                               DBG1(DBG_IKE, "no connection found to rekey IKE_SA");
-                               return FAILED;
-                       }
-               }
-               
-               /* create a new SA */
-               ike_sa_id = ike_sa_id_create(0, 0, TRUE);
-               this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
-                                                                                                               ike_sa_id);
-               spi = ike_sa_id->get_initiator_spi(ike_sa_id);
-               ike_sa_id->destroy(ike_sa_id);
-               
-               proposals = this->connection->get_proposals(this->connection);
-               iterator = proposals->create_iterator(proposals, TRUE);
-               while (iterator->iterate(iterator, (void**)&proposal))
-               {
-                       proposal->set_spi(proposal, spi);
-               }
-               iterator->destroy(iterator);
-               
-               sa_payload = sa_payload_create_from_proposal_list(proposals);
-               proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
-               request->add_payload(request, (payload_t*)sa_payload);
-       }
-       
-       {       /* build the NONCE payload for us (initiator) */
-               nonce_payload_t *nonce_payload;
-               
-               if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer, 
-                       NONCE_SIZE, &this->nonce_i) != SUCCESS)
-               {
-                       return FAILED;
-               }
-               nonce_payload = nonce_payload_create();
-               nonce_payload->set_nonce(nonce_payload, this->nonce_i);
-               request->add_payload(request, (payload_t*)nonce_payload);
-       }
-       
-       /* if the DH group is set via use_dh_group(), we already have a DH object */
-       if (!this->diffie_hellman)
-       {
-               diffie_hellman_group_t dh_group;
-               
-               dh_group = this->connection->get_dh_group(this->connection);
-               this->diffie_hellman = diffie_hellman_create(dh_group);
-               if (this->diffie_hellman == NULL)
-               {
-                       DBG1(DBG_IKE, "DH group %N not supported, aborting",
-                                diffie_hellman_group_names, dh_group);
-                       return FAILED;
-               }
-       }
-       
-       {       /* build the KE payload from the DH object */
-               ke_payload_t *ke_payload;
-               
-               ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
-               request->add_payload(request, (payload_t*)ke_payload);
-       }
-       
-       this->message_id = this->ike_sa->get_next_message_id(this->ike_sa);
-       request->set_message_id(request, this->message_id);
-       
-       /* register us as rekeying to detect multiple rekeying */
-       this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
-       this->ike_sa->set_rekeying_transaction(this->ike_sa, &this->public.transaction);
-       
-       return SUCCESS;
-}
-
-/**
- * Handle all kind of notifys
- */
-static status_t process_notifys(private_rekey_ike_sa_t *this, notify_payload_t *notify_payload)
-{
-       notify_type_t notify_type = notify_payload->get_notify_type(notify_payload);
-       
-       DBG2(DBG_IKE,"process notify type %N", notify_type_names, notify_type);
-
-       switch (notify_type)
-       {
-               case NO_PROPOSAL_CHOSEN:
-               {
-                       DBG1(DBG_IKE, "received a NO_PROPOSAL_CHOSEN notify, IKE_SA rekeying failed");
-                       return FAILED;
-               }
-               case INVALID_KE_PAYLOAD:
-               {
-                       chunk_t notify_data;
-                       diffie_hellman_group_t dh_group, old_dh_group;
-                       rekey_ike_sa_t *retry;
-                       
-                       old_dh_group = this->connection->get_dh_group(this->connection);
-                       notify_data = notify_payload->get_notification_data(notify_payload);
-                       dh_group = ntohs(*((u_int16_t*)notify_data.ptr));
-                       
-                       DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested %N",
-                                diffie_hellman_group_names, old_dh_group,
-                                diffie_hellman_group_names, dh_group);
-                       if (!this->connection->check_dh_group(this->connection, dh_group))
-                       {
-                               DBG1(DBG_IKE, "requested DH group not acceptable, IKE_SA rekeying failed");
-                               return FAILED;
-                       }
-                       retry = rekey_ike_sa_create(this->ike_sa);
-                       retry->use_dh_group(retry, dh_group);
-                       *this->next = (transaction_t*)retry;
-                       return FAILED;
-               }
-               default:
-               {
-                       if (notify_type < 16383)
-                       {
-                               DBG1(DBG_IKE, "received %N notify error, IKE_SA rekeying failed",
-                                        notify_type_names, notify_type);
-                               return FAILED;  
-                       }
-                       else
-                       {
-                               DBG1(DBG_IKE, "received %N notify, ignored",
-                                        notify_type_names, notify_type);
-                               return SUCCESS;
-                       }
-               }
-       }
-}
-
-/**
- * Switch to the newly created IKE_SA
- */
-static status_t switchto_new_sa(private_rekey_ike_sa_t* this, bool initiator)
-{
-       identification_t *my_id, *other_id;
-       host_t *my_host, *other_host;
-       char *name;
-       
-       my_id = this->ike_sa->get_my_id(this->ike_sa);
-       other_id = this->ike_sa->get_other_id(this->ike_sa);
-       my_host = this->ike_sa->get_my_host(this->ike_sa);
-       other_host = this->ike_sa->get_other_host(this->ike_sa);
-       name = this->ike_sa->get_name(this->ike_sa);
-       
-       this->new_sa->set_my_id(this->new_sa, my_id->clone(my_id));
-       this->new_sa->set_other_id(this->new_sa, other_id->clone(other_id));
-       this->new_sa->set_my_host(this->new_sa, my_host->clone(my_host));
-       this->new_sa->set_other_host(this->new_sa, other_host->clone(other_host));
-       this->new_sa->set_name(this->new_sa, name);
-       
-       if (this->new_sa->derive_keys(this->new_sa, this->proposal,
-                                                                 this->diffie_hellman, 
-                                                                 this->nonce_i, this->nonce_r, initiator,
-                                                                 this->ike_sa->get_child_prf(this->ike_sa),
-                                                                 this->ike_sa->get_prf(this->ike_sa)
-                                                                ) != SUCCESS)
-       {
-               return FAILED;
-       }
-       
-       this->new_sa->apply_connection(this->new_sa, this->connection);
-       this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);
-       this->new_sa->set_lifetimes(this->new_sa,
-                                               this->connection->get_reauth(this->connection),
-                                               this->connection->get_soft_lifetime(this->connection),
-                                               this->connection->get_hard_lifetime(this->connection));
-       return SUCCESS;
-}
-
-/**
- * Build a notify message.
- */
-static void build_notify(notify_type_t type, chunk_t data, message_t *message, bool flush_message)
-{
-       notify_payload_t *notify;
-       
-       if (flush_message)
-       {
-               payload_t *payload;
-               iterator_t *iterator = message->get_payload_iterator(message);
-               while (iterator->iterate(iterator, (void**)&payload))
-               {
-                       payload->destroy(payload);
-                       iterator->remove(iterator);
-               }
-               iterator->destroy(iterator);
-       }
-       
-       notify = notify_payload_create();
-       notify->set_notify_type(notify, type);
-       notify->set_notification_data(notify, data);
-       message->add_payload(message, (payload_t*)notify);
-}
-
-/**
- * Implementation of transaction_t.get_response.
- */
-static status_t get_response(private_rekey_ike_sa_t *this, message_t *request, 
-                                                        message_t **result, transaction_t **next)
-{
-       host_t *me, *other;
-       message_t *response;
-       status_t status;
-       iterator_t *payloads, *iterator;
-       payload_t *payload;
-       child_sa_t *child_sa;
-       sa_payload_t *sa_request = NULL;
-       nonce_payload_t *nonce_request = NULL;
-       ke_payload_t *ke_request = NULL;
-       nonce_payload_t *nonce_response;
-       
-       /* check if we already have built a response (retransmission) */
-       if (this->message)
-       {
-               *result = this->message;
-               return SUCCESS;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       this->message_id = request->get_message_id(request);
-       
-       /* set up response */
-       response = message_create();
-       response->set_source(response, me->clone(me));
-       response->set_destination(response, other->clone(other));
-       response->set_exchange_type(response, CREATE_CHILD_SA);
-       response->set_request(response, FALSE);
-       response->set_message_id(response, this->message_id);
-       response->set_ike_sa_id(response, this->ike_sa->get_id(this->ike_sa));
-       this->message = response;
-       *result = response;
-       
-       /* check message type */
-       if (request->get_exchange_type(request) != CREATE_CHILD_SA)
-       {
-               DBG1(DBG_IKE, "CREATE_CHILD_SA response of invalid type, aborted");
-               return FAILED;
-       }
-       
-       /* if we already initiate a delete, we do not allow rekeying */
-       if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
-       {
-               build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
-               DBG1(DBG_IKE, "unable to rekey, as delete in progress. Sending NO_PROPOSAL_CHOSEN");
-               return FAILED;
-       }
-       
-       /* if we have a CHILD which is "half-open", we do not allow rekeying */
-       iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
-       while (iterator->iterate(iterator, (void**)&child_sa))
-       {
-               child_sa_state_t state = child_sa->get_state(child_sa);
-               if (state == CHILD_CREATED ||
-                       state == CHILD_REKEYING ||
-                       state == CHILD_DELETING)
-               {
-                       build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
-                       DBG1(DBG_IKE, "unable to rekey, one CHILD_SA is half open. Sending NO_PROPOSAL_CHOSEN");
-                       iterator->destroy(iterator);
-                       return FAILED;
-               }
-       }
-       iterator->destroy(iterator);
-       
-       /* apply for notify processing */
-       this->next = next;
-       
-       
-       /* get a connection to replace current IKE_SA */
-       this->connection = charon->connections->get_connection_by_name(
-                                       charon->connections, this->ike_sa->get_name(this->ike_sa));
-       /* if connection lookup by name fails, try it with the hosts */
-       if (this->connection == NULL)
-       {
-               this->connection = charon->connections->get_connection_by_hosts(
-                                                               charon->connections, me, other);
-               if (this->connection == NULL)
-               {
-                       DBG1(DBG_IKE, "no connection found to rekey IKE_SA, sending NO_RROPOSAL_CHOSEN");
-                       build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
-                       return FAILED;
-               }
-       }
-       
-       /* Iterate over all payloads. */
-       payloads = request->get_payload_iterator(request);
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case SECURITY_ASSOCIATION:
-                               sa_request = (sa_payload_t*)payload;
-                               break;
-                       case NONCE:
-                               nonce_request = (nonce_payload_t*)payload;
-                               break;
-                       case KEY_EXCHANGE:
-                       {
-                               ke_request = (ke_payload_t*)payload;
-                               break;
-                       }
-                       case NOTIFY:
-                       {
-                               status = process_notifys(this, (notify_payload_t*)payload);
-                               if (status != SUCCESS)
-                               {
-                                       payloads->destroy(payloads);
-                                       return status;
-                               }
-                               break;
-                       }
-                       default:
-                       {
-                               DBG1(DBG_IKE, "ignoring %N payload",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       
-       /* check if we have all payloads */
-       if (!(sa_request && nonce_request && ke_request))
-       {
-               build_notify(INVALID_SYNTAX, chunk_empty, response, TRUE);
-               DBG1(DBG_IKE, "request message incomplete, IKE_SA rekeying failed");
-               return FAILED;
-       }
-       
-       {       /* process nonce payload */
-               this->nonce_i = nonce_request->get_nonce(nonce_request);
-               if (this->randomizer->allocate_pseudo_random_bytes(this->randomizer, 
-                       NONCE_SIZE, &this->nonce_r) != SUCCESS)
-               {
-                       build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
-                       return FAILED;
-               }
-               nonce_response = nonce_payload_create();
-               nonce_response->set_nonce(nonce_response, this->nonce_r);
-       }
-       
-       {       /* process SA payload */
-               linked_list_t *proposal_list;
-               sa_payload_t *sa_response;
-               u_int64_t spi;
-               ike_sa_id_t *ike_sa_id;
-               
-               sa_response = sa_payload_create();
-               /* get proposals from request, and select one with ours */
-               proposal_list = sa_request->get_proposals(sa_request);
-               DBG2(DBG_IKE, "selecting proposals:");
-               this->proposal = this->connection->select_proposal(this->connection, proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-               
-               /* do we have a proposal? */
-               if (this->proposal == NULL)
-               {
-                       DBG1(DBG_IKE, "no proposals acceptable to rekey IKE_SA, sending NO_PROPOSAL_CHOSEN");
-                       build_notify(NO_PROPOSAL_CHOSEN, chunk_empty, response, TRUE);
-                       return FAILED;
-               }
-               
-               /* create IKE_SA with new SPIs */
-               spi = this->proposal->get_spi(this->proposal);
-               ike_sa_id = ike_sa_id_create(spi, 0, FALSE);
-               this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
-                                                                                                               ike_sa_id);
-               spi = ike_sa_id->get_responder_spi(ike_sa_id);
-               ike_sa_id->destroy(ike_sa_id);
-               this->proposal->set_spi(this->proposal, spi);
-               
-               sa_response->add_proposal(sa_response, this->proposal);
-               response->add_payload(response, (payload_t*)sa_response);
-               /* add nonce after sa payload */
-               response->add_payload(response, (payload_t *)nonce_response);
-       }
-       
-       {       /* process KE payload */
-               diffie_hellman_group_t used_group;
-               ke_payload_t *ke_response;
-               
-               used_group = ke_request->get_dh_group_number(ke_request);
-               
-               if (!this->connection->check_dh_group(this->connection, used_group) ||
-                       (this->diffie_hellman = diffie_hellman_create(used_group)) == NULL)
-               {
-                       u_int16_t notify_group;
-                       chunk_t notify_chunk;
-                       
-                       notify_group = this->connection->get_dh_group(this->connection);
-                       DBG1(DBG_IKE, "request used inacceptable DH group %N, sending "
-                                "INVALID_KE_PAYLOAD with %N",
-                                diffie_hellman_group_names, used_group,
-                                diffie_hellman_group_names, notify_group);
-                       
-                       notify_group = htons(notify_group);
-                       notify_chunk.ptr = (u_int8_t*)&notify_group;
-                       notify_chunk.len = sizeof(notify_group);
-                       build_notify(INVALID_KE_PAYLOAD, notify_chunk, response, TRUE);
-                       return FAILED;
-               }
-               this->diffie_hellman->set_other_public_value(this->diffie_hellman,
-                                                               ke_request->get_key_exchange_data(ke_request));
-               
-               /* build response */
-               ke_response = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
-               response->add_payload(response, (payload_t*)ke_response);
-       }
-       
-       status = switchto_new_sa(this, FALSE);
-       if (status != SUCCESS)
-       {
-               return status;
-       }
-       
-       /* IKE_SA successfully created. If another transaction is already rekeying
-        * this SA, our lower nonce must be registered for a later nonce compare. */
-       {
-               private_rekey_ike_sa_t *other;
-               
-               other = (private_rekey_ike_sa_t*)
-                                               this->ike_sa->get_rekeying_transaction(this->ike_sa);
-               if (other)
-               {
-                       /* store our lower nonce in the simultaneus transaction, we 
-                        * will later compare it against his nonces when we calls conclude().
-                        * We do not adopt childrens yet, as we don't know if we'll win
-                        * the race...
-                        */
-                       if (memcmp(this->nonce_i.ptr, this->nonce_r.ptr,
-                               min(this->nonce_i.len, this->nonce_r.len)) < 0)
-                       {
-                               other->nonce_s = chunk_clone(this->nonce_i);
-                       }
-                       else
-                       {
-                               other->nonce_s = chunk_clone(this->nonce_r);
-                       }
-                       /* overwrite "other" in IKE_SA, allows "other" to access "this" */
-                       this->ike_sa->set_rekeying_transaction(this->ike_sa, &this->public.transaction);
-               }
-               else
-               {
-                       /* if we have no simultaneus transaction, we can safely adopt 
-                        * all children and complete. */
-                       this->new_sa->adopt_children(this->new_sa, this->ike_sa);
-                       charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
-                       this->new_sa = NULL;
-               }
-               this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
-       }
-       
-       return SUCCESS;
-}
-
-/**
- * Implementation of transaction_t.conclude
- */
-static status_t conclude(private_rekey_ike_sa_t *this, message_t *response, 
-                                                transaction_t **next)
-{
-       iterator_t *payloads;
-       payload_t *payload;
-       host_t *me, *other;
-       sa_payload_t *sa_payload = NULL;
-       nonce_payload_t *nonce_payload = NULL;
-       ke_payload_t *ke_payload = NULL;
-       private_rekey_ike_sa_t *other_trans;
-       status_t status;
-       
-       /* check message type */
-       if (response->get_exchange_type(response) != CREATE_CHILD_SA)
-       {
-               DBG1(DBG_IKE, "CREATE_CHILD_SA response of invalid type, aborting");
-               return FAILED;
-       }
-       
-       me = this->ike_sa->get_my_host(this->ike_sa);
-       other = this->ike_sa->get_other_host(this->ike_sa);
-       
-       /* apply for notify processing */
-       this->next = next;
-       
-       /* Iterate over all payloads to collect them */
-       payloads = response->get_payload_iterator(response);
-       while (payloads->iterate(payloads, (void**)&payload))
-       {
-               switch (payload->get_type(payload))
-               {
-                       case SECURITY_ASSOCIATION:
-                               sa_payload = (sa_payload_t*)payload;
-                               break;
-                       case NONCE:
-                               nonce_payload = (nonce_payload_t*)payload;
-                               break;
-                       case KEY_EXCHANGE:
-                               ke_payload = (ke_payload_t*)payload;
-                               break;
-                       case NOTIFY:
-                       {
-                               status = process_notifys(this, (notify_payload_t*)payload);
-                               if (status != SUCCESS)
-                               {
-                                       payloads->destroy(payloads);
-                                       return status;
-                               }
-                               break;
-                       }
-                       default:
-                       {
-                               DBG1(DBG_IKE, "ignoring %N payload",
-                                        payload_type_names, payload->get_type(payload));
-                               break;
-                       }
-               }
-       }
-       payloads->destroy(payloads);
-       
-       if (!(sa_payload && nonce_payload && ke_payload))
-       {
-               DBG1(DBG_IKE, "response message incomplete, rekeying IKE_SA failed");
-               return FAILED;
-       }
-       
-       {       /* process NONCE payload  */
-               this->nonce_r = nonce_payload->get_nonce(nonce_payload);
-       }
-       
-       {       /* process SA payload */
-               linked_list_t *proposal_list;
-               ike_sa_id_t *ike_sa_id;
-               u_int64_t spi;
-               
-               proposal_list = sa_payload->get_proposals(sa_payload);
-               /* we have to re-check here if other's selection is valid */
-               this->proposal = this->connection->select_proposal(this->connection, proposal_list);
-               proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
-               
-               if (this->proposal == NULL)
-               {
-                       DBG1(DBG_IKE, "no proposal selected, rekeying IKE_SA failed");
-                       return FAILED;
-               }
-               spi = this->proposal->get_spi(this->proposal);
-               ike_sa_id = this->new_sa->get_id(this->new_sa);
-               ike_sa_id->set_responder_spi(ike_sa_id, spi);   
-       }
-       
-       {       /* process KE payload */
-               this->diffie_hellman->set_other_public_value(this->diffie_hellman,
-                                                       ke_payload->get_key_exchange_data(ke_payload));
-       }
-       
-       if (switchto_new_sa(this, TRUE) != SUCCESS)
-       {
-               /* this should not happen. But if, we destroy the new SAs */
-               this->new_sa->set_state(this->new_sa, IKE_REKEYING);
-               *next = (transaction_t*)delete_ike_sa_create(this->new_sa);
-               return FAILED;
-       }
-       
-       /* IKE_SA successfully created. If the other peer initiated rekeying
-        * in the meantime, we detect this by comparing the rekeying_transaction
-        * of the SA. If it changed, we are not alone. Then we must compare the nonces.
-        * If no simultaneous rekeying is going on, we just initiate the delete of
-        * the superseded SA. */
-       other_trans = (private_rekey_ike_sa_t*)
-                                               this->ike_sa->get_rekeying_transaction(this->ike_sa);
-       this->ike_sa->set_rekeying_transaction(this->ike_sa, NULL);
-       
-       if (this->nonce_s.ptr)
-       {       /* simlutaneous rekeying is going on, not so good */
-               chunk_t this_lowest;
-               
-               /* first get our lowest nonce */
-               if (memcmp(this->nonce_i.ptr, this->nonce_r.ptr,
-                       min(this->nonce_i.len, this->nonce_r.len)) < 0)
-               {
-                       this_lowest = this->nonce_i;
-               }
-               else
-               {
-                       this_lowest = this->nonce_r;
-               }
-               /* then compare against other lowest nonce */
-               if (memcmp(this_lowest.ptr, this->nonce_s.ptr,
-                       min(this_lowest.len, this->nonce_s.len)) < 0)
-               {
-                       DBG1(DBG_IKE, "detected simultaneous IKE_SA rekeying, deleting ours");
-                       this->lost = TRUE;
-               }
-               else
-               {
-                       DBG1(DBG_IKE, "detected simultaneous IKE_SA rekeying, but ours is preferred");
-               }
-               if (this->lost)
-               {
-                       /* the other has won, he gets our children */
-                       other_trans->new_sa->adopt_children(other_trans->new_sa, this->ike_sa);
-                       /* we have lost simlutaneous rekeying, delete the SA we just have created */
-                       this->new_sa->set_state(this->new_sa, IKE_REKEYING);
-                       *next = (transaction_t*)delete_ike_sa_create(this->new_sa);
-               }
-               else
-               {
-                       other_trans->new_sa->set_state(other_trans->new_sa, IKE_REKEYING);
-               }
-               /* other trans' SA is still not checked in, so do it now. It's SA will get
-                * deleted by remote peer. */
-               charon->ike_sa_manager->checkin(charon->ike_sa_manager, other_trans->new_sa);
-               other_trans->new_sa = NULL;
-       }
-       
-       if (!this->lost)
-       {
-               /* we have won. delete old IKE_SA, and migrate all children */
-               this->new_sa->adopt_children(this->new_sa, this->ike_sa);
-               *next = (transaction_t*)delete_ike_sa_create(this->ike_sa);
-       }
-       
-       charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
-       this->new_sa = NULL;
-       
-       return SUCCESS;
-}
-
-/**
- * implements transaction_t.destroy
- */
-static void destroy(private_rekey_ike_sa_t *this)
-{
-       if (this->new_sa)
-       {
-               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
-                                                                                                       this->new_sa);
-       }
-       DESTROY_IF(this->message);
-       DESTROY_IF(this->connection);
-       DESTROY_IF(this->diffie_hellman);
-       DESTROY_IF(this->proposal);
-       chunk_free(&this->nonce_i);
-       chunk_free(&this->nonce_r);
-       chunk_free(&this->nonce_s);
-       this->randomizer->destroy(this->randomizer);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-rekey_ike_sa_t *rekey_ike_sa_create(ike_sa_t *ike_sa)
-{
-       private_rekey_ike_sa_t *this = malloc_thing(private_rekey_ike_sa_t);
-       
-       /* transaction interface functions */
-       this->public.transaction.get_request = (status_t(*)(transaction_t*,message_t**))get_request;
-       this->public.transaction.get_response = (status_t(*)(transaction_t*,message_t*,message_t**,transaction_t**))get_response;
-       this->public.transaction.conclude = (status_t(*)(transaction_t*,message_t*,transaction_t**))conclude;
-       this->public.transaction.get_message_id = (u_int32_t(*)(transaction_t*))get_message_id;
-       this->public.transaction.requested = (u_int32_t(*)(transaction_t*))requested;
-       this->public.transaction.destroy = (void(*)(transaction_t*))destroy;
-       
-       /* public functions */
-       this->public.use_dh_group = (void(*)(rekey_ike_sa_t*,diffie_hellman_group_t))use_dh_group;
-       this->public.cancel = (void(*)(rekey_ike_sa_t*))cancel;
-       
-       /* private data */
-       this->ike_sa = ike_sa;
-       this->message_id = 0;
-       this->message = NULL;
-       this->requested = 0;
-       this->nonce_i = chunk_empty;
-       this->nonce_r = chunk_empty;
-       this->nonce_s = chunk_empty;
-       this->new_sa = NULL;
-       this->lost = FALSE;
-       this->connection = NULL;
-       this->randomizer = randomizer_create();
-       this->diffie_hellman = NULL;
-       this->proposal = NULL;
-       
-       return &this->public;
-}
diff --git a/src/charon/sa/transactions/rekey_ike_sa.h b/src/charon/sa/transactions/rekey_ike_sa.h
deleted file mode 100644 (file)
index dbb6523..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * @file rekey_ike_sa.h
- * 
- * @brief Interface of transaction rekey_ike_sa.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#ifndef REKEY_IKE_SA_H
-#define REKEY_IKE_SA_H
-
-typedef struct rekey_ike_sa_t rekey_ike_sa_t;
-
-#include <sa/ike_sa.h>
-#include <sa/transactions/transaction.h>
-#include <crypto/diffie_hellman.h>
-
-
-/**
- * @brief A transaction to rekey an established IKE_SA
- *
- * @b Constructors:
- *  - rekey_ike_sa_create()
- *  - transaction_create() with the appropriate message
- *
- * @ingroup transactions
- */
-struct rekey_ike_sa_t {
-       
-       /**
-        * The transaction_t interface.
-        */
-       transaction_t transaction;
-       
-       /**
-        * @brief Set the Diffie Hellman group to use for initiating.
-        * 
-        * If a first exchange fails with a INVALID_KE_PAYLOAD, the second
-        * try uses the DH group proposed by the responder.
-        * 
-        * @param this          calling object
-        * @param dh_group      diffie hellman group to use
-        */
-       void (*use_dh_group) (rekey_ike_sa_t* this, diffie_hellman_group_t dh_group);
-       
-       /**
-        * @brief Cancel the request.
-        *
-        * Cancelling the request will set a flag in the transaction. 
-        *
-        * @param this          calling object
-        * @param child_sa      CHILD_SA to rekey
-        */
-       void (*cancel) (rekey_ike_sa_t* this);
-};
-
-/**
- * @brief Create a new transaction to rekey an existing IKE_SA.
- *
- * @param ike_sa               existing IKE_SA
- * @return                             created rekey_ike_sa transaction
- *
- * @ingroup transactions
- */
-rekey_ike_sa_t *rekey_ike_sa_create(ike_sa_t *ike_sa);
-
-#endif /* REKEY_IKE_SA_H */
diff --git a/src/charon/sa/transactions/transaction.c b/src/charon/sa/transactions/transaction.c
deleted file mode 100644 (file)
index d4da1cd..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- * @file transaction.c
- * 
- * @brief Generic contstructor for the different transaction types.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#include "transaction.h"
-
-#include <sa/child_sa.h>
-#include <sa/transactions/ike_sa_init.h>
-#include <sa/transactions/ike_auth.h>
-#include <sa/transactions/delete_ike_sa.h>
-#include <sa/transactions/create_child_sa.h>
-#include <sa/transactions/delete_child_sa.h>
-#include <sa/transactions/dead_peer_detection.h>
-#include <sa/transactions/rekey_ike_sa.h>
-#include <encoding/payloads/ts_payload.h>
-#include <encoding/payloads/sa_payload.h>
-#include <encoding/payloads/nonce_payload.h>
-#include <encoding/payloads/notify_payload.h>
-#include <encoding/payloads/delete_payload.h>
-
-/*
- * see header file
- */
-transaction_t *transaction_create(ike_sa_t *ike_sa, message_t *request)
-{
-       iterator_t *iterator;
-       payload_t *current;
-       transaction_t *transaction = NULL;
-       
-       if (!request->get_request(request))
-       {
-               return NULL;
-       }
-       
-       switch (request->get_exchange_type(request))
-       {
-               case IKE_SA_INIT:
-               {
-                       if (ike_sa->get_state(ike_sa) == IKE_CREATED)
-                       {
-                               transaction = (transaction_t*)ike_sa_init_create(ike_sa);
-                       }
-                       break;
-               }
-               case IKE_AUTH:
-               {
-                       /* IKE_AUTH is always created in IKE_SA_INIT, it never should
-                        * appear alone */
-                       break;
-               }
-               case CREATE_CHILD_SA:
-               {
-                       if (ike_sa->get_state(ike_sa) < IKE_ESTABLISHED)
-                       {
-                               break;
-                       }
-                       /* check protocol of SA payload */
-                       iterator = request->get_payload_iterator(request);
-                       while (iterator->iterate(iterator, (void**)&current))
-                       {
-                               if (current->get_type(current) == SECURITY_ASSOCIATION)
-                               {
-                                       iterator_t *prop_iter;
-                                       proposal_substructure_t *prop_struct;
-                                       sa_payload_t *sa_payload = (sa_payload_t*)current;
-                                       
-                                       prop_iter = sa_payload->create_proposal_substructure_iterator(sa_payload, TRUE);
-                                       if (prop_iter->iterate(prop_iter, (void**)&prop_struct))
-                                       {
-                                               switch (prop_struct->get_protocol_id(prop_struct))
-                                               {
-                                                       case PROTO_IKE:
-                                                               transaction = (transaction_t*)
-                                                                               rekey_ike_sa_create(ike_sa);
-                                                               break;
-                                                       case PROTO_AH:
-                                                       case PROTO_ESP:
-                                                               transaction = (transaction_t*)
-                                                                               create_child_sa_create(ike_sa);
-                                                               break;
-                                                       default:
-                                                               break;
-                                               }
-                                       }
-                                       prop_iter->destroy(prop_iter);
-                               }
-                               if (transaction)
-                               {
-                                       break;
-                               }
-                       }
-                       iterator->destroy(iterator);
-                       break;
-               }
-               case INFORMATIONAL:
-               {
-                       if (ike_sa->get_state(ike_sa) < IKE_ESTABLISHED)
-                       {
-                               break;
-                       }
-                       u_int payload_count = 0;
-                       iterator = request->get_payload_iterator(request);
-                       while (iterator->iterate(iterator, (void**)&current))
-                       {
-                               payload_count++;
-                               switch (current->get_type(current))
-                               {
-                                       case DELETE:
-                                       {
-                                               delete_payload_t *delete_payload = (delete_payload_t*)current;
-                                               switch (delete_payload->get_protocol_id(delete_payload))
-                                               {
-                                                       case PROTO_IKE:
-                                                               transaction = (transaction_t*)
-                                                                               delete_ike_sa_create(ike_sa);
-                                                               break;
-                                                       case PROTO_AH:
-                                                       case PROTO_ESP:
-                                                               transaction = (transaction_t*)
-                                                                               delete_child_sa_create(ike_sa);
-                                                               break;
-                                                       default:
-                                                               break;
-                                               }
-                                               break;
-                                       }
-                                       default:
-                                               break;
-                               }
-                               if (transaction)
-                               {
-                                       break;
-                               }
-                       }
-                       iterator->destroy(iterator);
-                       /* empty informationals are used for dead peer detection in
-                        * IKEv2. We use a special transaction for it. */
-                       if (payload_count == 0)
-                       {
-                               transaction = (transaction_t*)
-                                               dead_peer_detection_create(ike_sa);
-                       }
-                       break;
-               }
-               default:
-                       break;
-       }
-       return transaction;     
-}
diff --git a/src/charon/sa/transactions/transaction.h b/src/charon/sa/transactions/transaction.h
deleted file mode 100644 (file)
index 4a401e1..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/**
- * @file transaction.h
- * 
- * @brief Interface transaction_t.
- * 
- */
-
-/*
- * Copyright (C) 2006 Martin Willi
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * 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.
- */
-
-#ifndef TRANSACTION_H_
-#define TRANSACTION_H_
-
-typedef struct transaction_t transaction_t;
-
-#include <library.h>
-#include <encoding/message.h>
-#include <sa/ike_sa.h>
-
-/**
- * @brief This interface represents a transaction an established IKE_SA can do.
- *
- * To every transaction, a message ID is associated. IKEv2 uses strict message
- * IDs, which are equal for a request/response pair in a transaction.
- * An initiator of a transaction does the following:
- * - create the transaction using a specific constructor
- * - call request() to get the message for initiaton
- * - call conclude() to process received reply
- * The other peer does the following:
- * - create a transanction using the generic transaction constructor
- * - call respond() to get a reply to send
- *
- * The responder must not destroy the transaction, until the 
- * initiator initiates another transaction (or a number of transactions
- * > window size). This allows us to redo a transaction in case of a
- * message loss. The initiator can destroy the the transaction once
- * the conclude() function is called.
- * 
- * @b Constructors:
- *  - transaction_create()
- *  - ike_sa_init_create()
- *  - ike_auth_create()
- * 
- * @ingroup transactions
- */
-struct transaction_t {
-
-       /**
-        * @brief Get the request to use for initiating the transaction.
-        * 
-        * A transaction creates a request only once. The request is stored
-        * internally and may be queried multiple times for retransmission.
-        * The transaction is not responsible for generating/encrypting the
-        * message, this is the job of the caller. But it MAY be already
-        * generated when calling get_request() the second time.
-        *
-        * @param this                  calling object
-        * @param[out] request  resultin request
-        * @return
-        *                                              - FAILED if transaction failed
-        *                                              - DESTROY_ME if transaction failed and IKE SA
-        *                                                must be deleted
-        *                                              - SUCCESS
-        */
-       status_t (*get_request) (transaction_t *this, message_t **request);
-
-       /**
-        * @brief Build the response for a received request.
-        * 
-        * A transaction creates a response only once for a unique request.
-        * This allows the use of get_response multiple times for retransmission
-        * purposes.
-        * The transaction is not responsible for generating/encrypting the
-        * response, nor is it responsible for decrypting/parsing the request.
-        * This is the job of the caller. But the response MAY be already
-        * generated when calling get_request() the second time.
-        * The initiator waits for a response, so we send one in every case. This
-        * means response points always to a valid message. This message
-        * may not be modified or destroyed, it gets destroyed along with the
-        * transaction.
-        * The get_response() function may return a next transaction. This allows
-        * passing of informations from one transaction to a next one.
-        *
-        * @param this                  calling object
-        * @param request               received request
-        * @param[out] response resulting response
-        * @param[out] next             transaction expected as next, or NULL
-        * @return
-        *                                              - FAILED if transaction failed
-        *                                              - DESTROY_ME if transaction failed and IKE SA
-        *                                                must be deleted
-        *                                              - SUCCESS
-        */
-       status_t (*get_response) (transaction_t *this, message_t *request, 
-                                                         message_t **response, transaction_t **next);
-       
-       /**
-        * @brief Conclude an initiated transaction with a received response.
-        *
-        * The response must be decrypted and parsed. The conclude function 
-        * may return a new transaction. This transaction has to be executed
-        * next to complete a multi-exchange scenario. It allows a clean
-        * transaction mechanism, as the transaction knows best whats to do
-        * after it completes. It must only be executed if conclude returns
-        * SUCCESS.
-        * 
-        * @param this                          calling object
-        * @param response                      received response
-        * @param[out] next                     transaction to execute as next, or NULL
-        * @return
-        *                                              - FAILED if transaction failed
-        *                                              - DESTROY_ME if transaction failed and IKE SA
-        *                                                must be deleted
-        *                                              - SUCCESS
-        */
-       status_t (*conclude) (transaction_t *this, message_t *response, 
-                                                 transaction_t **next);
-       
-       /**
-        * @brief Get the message ID associated with this transaction.
-        *
-        * Every transaction consists of a message pair with the same 
-        * message ID. This ID can be queried with get_message_id().
-        * 
-        * @param this                  calling object
-        * @return                              message id
-        */
-       u_int32_t (*get_message_id) (transaction_t *this);
-       
-       /**
-        * @brief Times we already sent the request (retransmitted).
-        *
-        * The transaction stores an internal counter to see how
-        * many times we sent the request. This counter is incremented
-        * each time after a call to requested().
-        *
-        * @param this                  calling object
-        * @return                              message id
-        */
-       u_int32_t (*requested) (transaction_t *this);
-       
-       /**
-        * @brief Destroys a transaction_t object.
-        *
-        * @param this                  calling object
-        */
-       void (*destroy) (transaction_t *this);
-};
-
-/**
- * @brief Create a transaction instance based on a received request.
- *
- * Incoming requests are handled by a transaction. But as we don't
- * know what kind of transaction we use for a specific request, we use
- * a generic constructor. This constructor decides which instance will
- * handle the transaction, and creates it.
- * 
- * @param ike_sa               ike_sa associated with this transaction
- * @param request              received request
- * @return
- *                                             - created transaction, or 
- *                                             - NULL no transaction needed
- * 
- * @ingroup transactions
- */
-transaction_t *transaction_create(ike_sa_t *ike_sa, message_t* request);
-
-#endif /* TRANSACTION_H_ */
index 3ec2bd58e88f1516699035b7226e47717bdcefdc..e595108eef97bede5b3b8b46f87d60e7e30d8ab1 100644 (file)
@@ -6,7 +6,9 @@
  */
 
 /*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
+ * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -36,6 +38,9 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <string.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <ifaddrs.h>
 
 #include "kernel_interface.h"
 
@@ -152,7 +157,21 @@ char* lookup_algorithm(kernel_algorithm_t *kernel_algo,
        return NULL;    
 }
 
+typedef struct rt_refcount_t rt_refcount_t;
 
+struct rt_refcount_t {
+       /** Index of the interface the route is bound to */
+       int if_index;
+
+       /** Source ip of the route */
+       host_t *src_ip;
+
+       /** Destination net */
+       chunk_t dst_net;
+
+       /** Destination net prefixlen */
+       u_int8_t prefixlen;
+};
 
 typedef struct kernel_policy_t kernel_policy_t;
 
@@ -170,15 +189,33 @@ struct kernel_policy_t {
        /** parameters of installed policy */
        struct xfrm_selector sel;
        
+       /** associated route installed for this policy */
+       rt_refcount_t *route;
+       
        /** by how many CHILD_SA's this policy is used */
        u_int refcount;
 };
 
+typedef struct vip_refcount_t vip_refcount_t;
+
+/**
+ * Reference counter for for virtual ips.
+ */
+struct vip_refcount_t {
+       /** Index of the interface the ip is bound to */
+       u_int8_t if_index;
+       
+       /** The ip address */
+       host_t *ip;
+       
+       /** Number of times this ip is used */
+       u_int refcount;
+};
 
 typedef struct private_kernel_interface_t private_kernel_interface_t;
 
 /**
- * Private Variables and Functions of kernel_interface class.
+ * Private variables and functions of kernel_interface class.
  */
 struct private_kernel_interface_t {
        /**
@@ -197,9 +234,14 @@ struct private_kernel_interface_t {
        pthread_mutex_t pol_mutex;
        
        /**
-        * Netlink communication socket.
+        * Netlink communication socket for XFRM IPsec.
         */
-       int socket;
+       int xfrm_socket;
+
+       /**
+        * Netlink communication socket for routing & addresses.
+        */
+       int rt_socket;
        
        /**
         * Process id of kernel thread
@@ -217,9 +259,14 @@ struct private_kernel_interface_t {
        linked_list_t *responses;
        
        /**
-        * Thread which receives messages.
+        * Thread which receives xfrm messages.
+        */
+       pthread_t xfrm_thread;
+
+       /**
+        * Thread which receives rt messages.
         */
-       pthread_t thread;
+       pthread_t rt_thread;
        
        /**
         * Mutex locks access to replies list.
@@ -230,35 +277,56 @@ struct private_kernel_interface_t {
         * Condvar allows signaling of threads waiting for a reply.
         */
        pthread_cond_t condvar;
-};
+       
+       /**
+        * List of reference counter objects for all virtual ips.
+        */
+       linked_list_t *vips;
 
+       /**
+        * Mutex to lock access to vip list.
+        */
+       pthread_mutex_t vip_mutex;
+};
 
 /**
- * Send a message down to the kernel and wait for its response
+ * Sends a message down to the kernel and waits for its response
  */
 static status_t send_message(private_kernel_interface_t *this,
-                                                        struct nlmsghdr *request, struct nlmsghdr **response)
+                                                        struct nlmsghdr *request,
+                                                        struct nlmsghdr **response,
+                                                        int socket)
 {
        size_t length;
        struct sockaddr_nl addr;
        
        request->nlmsg_seq = ++this->seq;
-       request->nlmsg_pid = 0;
+       request->nlmsg_pid = getpid();
        
        memset(&addr, 0, sizeof(struct sockaddr_nl));
        addr.nl_family = AF_NETLINK;
        addr.nl_pid = 0;
        addr.nl_groups = 0;
+
+       /*
+       // set timeout to 10 secs
+       struct timespec tm;
+       tm.tv_sec = 10;
+        */
        
-       length = sendto(this->socket,(void *)request, request->nlmsg_len, 0, 
+       length = sendto(socket,(void *)request, request->nlmsg_len, 0, 
                                        (struct sockaddr *)&addr, sizeof(addr));
+       DBG2(DBG_IKE, "%d bytes sent to kernel", length);
        
        if (length < 0)
        {
+               DBG1(DBG_IKE,"0 byte could be sent");
                return FAILED;
        }
        else if (length != request->nlmsg_len)
        {
+               DBG1(DBG_IKE,"Request length %d does not match the sent bytes %d",
+                               request->nlmsg_len, length);
                return FAILED;
        }
        
@@ -290,6 +358,8 @@ static status_t send_message(private_kernel_interface_t *this,
                        break;
                }
                /* TODO: we should time out, if something goes wrong!??? */
+               //if(pthread_cond_timedwait(&(this->condvar), &(this->rep_mutex), &tm) == ETIMEDOUT)
+               //      return FAILED;
                pthread_cond_wait(&(this->condvar), &(this->rep_mutex));
        }
        
@@ -299,46 +369,73 @@ static status_t send_message(private_kernel_interface_t *this,
 }
 
 /**
- * Implementation of private_kernel_interface_t.receive_messages.
+ * Reads from a netlink socket and returns the message in a buffer.
  */
-static void receive_messages(private_kernel_interface_t *this)
+static void netlink_package_receiver(int socket, unsigned char *response, int response_size)
 {
-       while(TRUE) 
+       while (TRUE)
        {
-               unsigned char response[BUFFER_SIZE];
-               struct nlmsghdr *hdr, *listed_response;
-               while (TRUE)
+               struct sockaddr_nl addr;
+               socklen_t addr_length;
+               size_t length;
+               addr_length = sizeof(addr);
+               
+               length = recvfrom(socket, response, response_size, 0, (struct sockaddr*)&addr, &addr_length);
+               if (length < 0)
                {
-                       struct sockaddr_nl addr;
-                       socklen_t addr_length;
-                       size_t length;
-                       
-                       addr_length = sizeof(addr);
-                       
-                       length = recvfrom(this->socket, &response, sizeof(response), 0, (struct sockaddr*)&addr, &addr_length);
-                       if (length < 0)
-                       {
-                               if (errno == EINTR)
-                               {
-                                       /* interrupted, try again */
-                                       continue;
-                               }
-                               charon->kill(charon, "receiving from netlink socket failed");
-                       }
-                       if (!NLMSG_OK((struct nlmsghdr *)response, length))
+                       if (errno == EINTR)
                        {
-                               /* bad netlink message */
+                               /* interrupted, try again */
                                continue;
                        }
-                       if (addr.nl_pid != 0)
-                       {
-                               /* not from kernel. not interested, try another one */
-                               continue;
-                       }
-                       /* good message, handle it */
-                       break;
+                       charon->kill(charon, "receiving from netlink socket failed\n");
                }
                
+               if (!NLMSG_OK((struct nlmsghdr *)response, length))
+               {
+                       /* bad netlink message */
+                       continue;
+               }
+
+               if (addr.nl_pid != 0)
+               {
+                       /* not from kernel. not interested, try another one */
+                       continue;
+               }
+               /* good message, handle it */
+               return;
+       }
+}
+
+/**
+ * Takes a Netlink package from the response buffer and writes it to this->responses.
+ * Then it signals all waiting threads.
+ */
+static void add_to_package_list(private_kernel_interface_t *this, unsigned char *response)
+{
+       struct nlmsghdr *hdr = (struct nlmsghdr*)response;
+       /* add response to queue */
+       struct nlmsghdr *listed_response = malloc(hdr->nlmsg_len);
+       memcpy(listed_response, response, hdr->nlmsg_len);
+       
+       pthread_mutex_lock(&(this->rep_mutex));
+       this->responses->insert_last(this->responses, (void*)listed_response);
+       pthread_mutex_unlock(&(this->rep_mutex));
+       /* signal ALL waiting threads */
+       pthread_cond_broadcast(&(this->condvar));
+}
+
+/**
+ * Receives packages from this->xfrm_socket and puts them to this->package_list
+ */
+static void receive_xfrm_messages(private_kernel_interface_t *this)
+{
+       while(TRUE) 
+       {
+               unsigned char response[BUFFER_SIZE];
+               struct nlmsghdr *hdr;
+               netlink_package_receiver(this->xfrm_socket, response, sizeof(response));
+               
                /* we handle ACQUIRE and EXPIRE messages directly */
                hdr = (struct nlmsghdr*)response;
                if (hdr->nlmsg_type == XFRM_MSG_ACQUIRE)
@@ -396,28 +493,47 @@ static void receive_messages(private_kernel_interface_t *this)
                        }
                        charon->job_queue->add(charon->job_queue, job);
                }
-               /* NLMSG_ERROR is sent back for acknowledge (or on error), an
-               * XFRM_MSG_NEWSA is returned when we alloc spis and when
-               * updating SAs.
-               * XFRM_MSG_NEWPOLICY is returned when we query a policy.
-               * list these responses for the sender
-               */
-               else if (hdr->nlmsg_type == NLMSG_ERROR ||
-                                hdr->nlmsg_type == XFRM_MSG_NEWSA ||
-                                hdr->nlmsg_type == XFRM_MSG_NEWPOLICY)
+               /* NLMSG_ERROR is sent back for acknowledge (or on error).
+                * XFRM_MSG_NEWSA is returned when we alloc spis and when
+                * updating SAs.
+                * XFRM_MSG_NEWPOLICY is returned when we query a policy.
+                */
+               else if (hdr->nlmsg_type == NLMSG_ERROR
+                                       || hdr->nlmsg_type == XFRM_MSG_NEWSA
+                                       || hdr->nlmsg_type == XFRM_MSG_NEWPOLICY)
                {
-                       /* add response to queue */
-                       listed_response = malloc(hdr->nlmsg_len);
-                       memcpy(listed_response, &response, hdr->nlmsg_len);
-                       
-                       pthread_mutex_lock(&(this->rep_mutex));
-                       this->responses->insert_last(this->responses, (void*)listed_response);
-                       pthread_mutex_unlock(&(this->rep_mutex));
-                       /* signal ALL waiting threads */
-                       pthread_cond_broadcast(&(this->condvar));
+                       add_to_package_list(this, response);
+               }
+               /* we are not interested in anything other.
+                * anyway, move on to the next message
+                */
+               continue;
+       }
+}
+
+/**
+ * Receives packages from this->rt_socket and puts them to this->package_list
+ */
+static void receive_rt_messages(private_kernel_interface_t *this)
+{
+       while(TRUE)
+       {
+               unsigned char response[BUFFER_SIZE];
+               struct nlmsghdr *hdr;
+               netlink_package_receiver(this->rt_socket,response,BUFFER_SIZE);
+               
+               hdr = (struct nlmsghdr*)response;
+               /* NLMSG_ERROR is sent back for acknowledge (or on error).
+                * RTM_NEWROUTE is returned when we add a route.
+                */
+               if (hdr->nlmsg_type == NLMSG_ERROR ||
+                       hdr->nlmsg_type == RTM_NEWROUTE)
+               {
+                       add_to_package_list(this, response);
                }
                /* we are not interested in anything other.
-               * anyway, move on to the next message */
+                * anyway, move on to the next message.
+                */
                continue;
        }
 }
@@ -464,7 +580,7 @@ static status_t get_spi(private_kernel_interface_t *this,
        userspi->min = 0xc0000000;
        userspi->max = 0xcFFFFFFF;
        
-       if (send_message(this, hdr, &response) != SUCCESS)
+       if (send_message(this, hdr, &response, this->xfrm_socket) != SUCCESS)
        {
                DBG1(DBG_KNL, "netlink communication failed");
                return FAILED;
@@ -627,12 +743,12 @@ static status_t add_sa(private_kernel_interface_t *this,
                 *   -> does that mean that NAT-T encap doesn't work in transport mode?
                 * No. The reason the kernel ignores NAT-OA is that it recomputes 
                 * (or, rather, just ignores) the checksum. If packets pass
-                * the IPSec checks it marks them "checksum ok" so OA isn't needed. */
+                * the IPsec checks it marks them "checksum ok" so OA isn't needed. */
                
                rthdr = XFRM_RTA_NEXT(rthdr);
        }
        
-       if (send_message(this, hdr, &response) != SUCCESS)
+       if (send_message(this, hdr, &response, this->xfrm_socket) != SUCCESS)
        {
                DBG1(DBG_KNL, "netlink communication failed");
                return FAILED;
@@ -684,7 +800,7 @@ static status_t update_sa(
        sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
        sa_id->family = dst->get_family(dst);
        
-       if (send_message(this, hdr, &update) != SUCCESS)
+       if (send_message(this, hdr, &update, this->xfrm_socket) != SUCCESS)
        {
                DBG1(DBG_KNL, "netlink communication failed");
                return FAILED;
@@ -744,7 +860,7 @@ static status_t update_sa(
                }
        }
        
-       if (send_message(this, update, &response) != SUCCESS)
+       if (send_message(this, update, &response, this->xfrm_socket) != SUCCESS)
        {
                DBG1(DBG_KNL, "netlink communication failed");
                free(update);
@@ -798,7 +914,7 @@ static status_t query_sa(private_kernel_interface_t *this, host_t *dst,
        sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
        sa_id->family = dst->get_family(dst);
        
-       if (send_message(this, hdr, &response) != SUCCESS)
+       if (send_message(this, hdr, &response, this->xfrm_socket) != SUCCESS)
        {
                DBG1(DBG_KNL, "netlink communication failed");
                return FAILED;
@@ -850,7 +966,7 @@ static status_t del_sa(private_kernel_interface_t *this, host_t *dst,
        sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
        sa_id->family = dst->get_family(dst);
        
-       if (send_message(this, hdr, &response) != SUCCESS)
+       if (send_message(this, hdr, &response, this->xfrm_socket) != SUCCESS)
        {
                DBG1(DBG_KNL, "netlink communication failed");
                return FAILED;
@@ -880,7 +996,7 @@ static void ts2subnet(traffic_selector_t* ts,
        /* there is no way to do this cleanly, as the address range may
         * be anything else but a subnet. We use from_addr as subnet 
         * and try to calculate a usable subnet mask.
-       */
+        */
        int byte, bit;
        bool found = FALSE;
        chunk_t from, to;
@@ -891,7 +1007,8 @@ static void ts2subnet(traffic_selector_t* ts,
        
        *mask = (size * 8);
        /* go trough all bits of the addresses, beginning in the front.
-        * As longer as they equal, the subnet gets larger */
+        * as long as they are equal, the subnet gets larger
+        */
        for (byte = 0; byte < size; byte++)
        {
                for (bit = 7; bit >= 0; bit--)
@@ -962,6 +1079,106 @@ static struct xfrm_selector ts2selector(traffic_selector_t *src,
        return sel;
 }
 
+/**
+ * Tries to find an ip address of a local interface that is included in the
+ * supplied traffic selector.
+ */
+static status_t find_addr_by_ts(traffic_selector_t *ts, host_t **ip)
+{
+       host_t *try = NULL;
+
+#ifdef HAVE_GETIFADDRS
+       struct ifaddrs *list;
+       struct ifaddrs *cur;
+
+       if (getifaddrs(&list) < 0)
+       {
+               return FAILED;
+       }
+
+       for (cur = list; cur != NULL; cur = cur->ifa_next)
+       {
+               if (!(cur->ifa_flags & IFF_UP) || !cur->ifa_addr)
+               {
+                       /* ignore interfaces which are down or have no address assigned */
+                       continue;
+               }
+
+               try = host_create_from_sockaddr(cur->ifa_addr);
+
+               if (try && ts->includes(ts, try))
+               {
+                       if (ip)
+                       {
+                               *ip = try;
+                       }
+                       freeifaddrs(list);
+                       return SUCCESS;
+               }
+
+               DESTROY_IF(try);
+       }
+       freeifaddrs(list);
+       return FAILED;
+#else /* !HAVE_GETIFADDRS */
+
+       /* only IPv4 supported yet */
+       if (ts->get_type != TS_IPV4_ADDR_RANGE)
+       {
+               return FAILED;
+       }
+
+       int skt = socket(PF_INET, SOCK_DGRAM, 0);
+       struct ifconf conf;
+       struct ifreq reqs[16];
+
+       conf.ifc_len = sizeof(reqs);
+       conf.ifc_req = reqs;
+
+       if (ioctl(skt, SIOCGIFCONF, &conf) == -1)
+       {
+               DBG1(DBG_NET, "checking address using ioctl() failed: %m");
+               close(skt);
+               return FAILED;
+       }
+       close(skt);
+
+       while (conf.ifc_len >= sizeof(struct ifreq))
+       {
+               /* only IPv4 supported yet */
+               if (conf.ifc_req->ifr_addr.sa_family != AF_INET)
+               {
+                       continue;
+               }
+
+               try = host_create_from_sockaddr(conf.ifc_req->ifr_addr);
+
+               if (try && ts->includes(ts, try))
+               {
+                       if (ip)
+                       {
+                               *ip = try;
+                       }
+                       
+                       return SUCCESS;
+               }
+
+               DESTROY_IF(try);
+
+               conf.ifc_len -= sizeof(struct ifreq);
+               conf.ifc_req++;
+       }
+       return FAILED;
+#endif /* HAVE_GETIFADDRS */
+}
+
+/**
+ * forward declarations
+ */
+static status_t manage_srcroute(private_kernel_interface_t*,int,int,rt_refcount_t*);
+static int get_iface(private_kernel_interface_t*,host_t*);
+static void rt_refcount_destroy(rt_refcount_t*);
+
 /**
  * Implementation of kernel_interface_t.add_policy.
  */
@@ -980,7 +1197,6 @@ static status_t add_policy(private_kernel_interface_t *this,
        struct nlmsghdr *response;
        struct xfrm_userpolicy_info *policy_info;
        struct nlmsghdr *hdr;
-       status_t status = SUCCESS;
        
        /* create a policy */
        policy = malloc_thing(kernel_policy_t);
@@ -1075,7 +1291,7 @@ static status_t add_policy(private_kernel_interface_t *this,
        host2xfrm(src, &tmpl->saddr);
        host2xfrm(dst, &tmpl->id.daddr);
        
-       if (send_message(this, hdr, &response) != SUCCESS)
+       if (send_message(this, hdr, &response, this->xfrm_socket) != SUCCESS)
        {
                DBG1(DBG_KNL, "netlink communication failed");
                return FAILED;
@@ -1083,17 +1299,45 @@ static status_t add_policy(private_kernel_interface_t *this,
        else if (response->nlmsg_type != NLMSG_ERROR)
        {
                DBG1(DBG_KNL, "netlink request XFRM_MSG_UPDPOLICY not acknowledged");
-               status = FAILED;
+               free(response);
+               return FAILED;
        }
        else if (((struct nlmsgerr*)NLMSG_DATA(response))->error)
        {
                DBG1(DBG_KNL, "netlink request XFRM_MSG_UPDPOLICY got an error: %s",
                         strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error));
-               status = FAILED;
+               free(response);
+               return FAILED;
        }
        
+       
+       if (direction == POLICY_FWD)
+       {
+               policy->route = malloc_thing(rt_refcount_t);
+               if (find_addr_by_ts(dst_ts, &policy->route->src_ip) == SUCCESS)
+               {
+                       policy->route->if_index = get_iface(this, src);
+                       policy->route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16);
+                       memcpy(policy->route->dst_net.ptr, &policy->sel.saddr, policy->route->dst_net.len);
+                       policy->route->prefixlen = policy->sel.prefixlen_s;
+                       
+                       if (manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL,
+                                                               policy->route) != SUCCESS)
+                       {
+                               DBG1(DBG_KNL, "error installing route");
+                               rt_refcount_destroy(policy->route);
+                               policy->route = NULL;
+                       }
+               }
+               else
+               {
+                       free(policy->route);
+                       policy->route = NULL;
+               }
+       }
+
        free(response);
-       return status;
+       return SUCCESS;
 }
 
 /**
@@ -1124,7 +1368,7 @@ static status_t query_policy(private_kernel_interface_t *this,
        policy_id->sel = ts2selector(src_ts, dst_ts);
        policy_id->dir = direction;
 
-       if (send_message(this, hdr, &response) != SUCCESS)
+       if (send_message(this, hdr, &response, this->xfrm_socket) != SUCCESS)
        {
                DBG1(DBG_KNL, "netlink communication failed");
                return FAILED;
@@ -1166,12 +1410,12 @@ static status_t del_policy(private_kernel_interface_t *this,
                                                   policy_dir_t direction)
 {
        kernel_policy_t *current, policy, *to_delete = NULL;
+       rt_refcount_t *route;
        unsigned char request[BUFFER_SIZE];
        struct nlmsghdr *response;
        struct nlmsghdr *hdr;
        struct xfrm_userpolicy_id *policy_id;
        iterator_t *iterator;
-       status_t status = SUCCESS;
        
        DBG2(DBG_KNL, "deleting policy");
        
@@ -1221,9 +1465,10 @@ static status_t del_policy(private_kernel_interface_t *this,
        policy_id->sel = to_delete->sel;
        policy_id->dir = direction;
        
+       route = to_delete->route;
        free(to_delete);
        
-       if (send_message(this, hdr, &response) != SUCCESS)
+       if (send_message(this, hdr, &response, this->xfrm_socket) != SUCCESS)
        {
                DBG1(DBG_KNL, "netlink communication failed");
                return FAILED;
@@ -1231,27 +1476,347 @@ static status_t del_policy(private_kernel_interface_t *this,
        else if (response->nlmsg_type != NLMSG_ERROR)
        {
                DBG1(DBG_KNL, "netlink request XFRM_MSG_DELPOLICY not acknowledged");
-               status = FAILED;
+               free(response);
+               return FAILED;
        }
        else if (((struct nlmsgerr*)NLMSG_DATA(response))->error)
        {
                DBG1(DBG_KNL, "netlink request XFRM_MSG_DELPOLICY got an error: %s",
                         strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error));
-               status = FAILED;
+               free(response);
+               return FAILED;
+       }
+
+       if (route)
+       {
+               if (manage_srcroute(this, RTM_DELROUTE, 0, route) != SUCCESS)
+               {
+                       DBG1(DBG_KNL, "error uninstalling route");
+               }               
+               rt_refcount_destroy(route);
        }
        
        free(response);
-       return status;
+       return SUCCESS;
+}
+
+/**
+ * Sends an RT_NETLINK request to the kernel. 
+ */
+static status_t send_rtrequest(private_kernel_interface_t *this, struct nlmsghdr *hdr)
+{
+       struct nlmsghdr *response;
+
+       if (send_message(this, hdr, &response, this->rt_socket) != SUCCESS)
+       {
+               DBG1(DBG_KNL, "netlink communication failed");
+               return FAILED;
+       }
+       else if (((struct nlmsgerr*)NLMSG_DATA(response))->error)
+       {
+               DBG1(DBG_KNL, "netlink request got an error: %s (%d)",
+                       strerror(-((struct nlmsgerr*)NLMSG_DATA(response))->error),
+                       -((struct nlmsgerr*)NLMSG_DATA(response))->error);
+               free(response);
+               return FAILED;
+       }
+
+       free(response);
+       return SUCCESS;
+}
+
+/**
+ * Creates an rtattr and adds it to the netlink message.
+ */
+static status_t add_rtattr(struct nlmsghdr *hdr, int max_len,
+                                       int rta_type, void *data, int data_len)
+{
+       struct rtattr *rta;
+       
+       if (NLMSG_ALIGN(hdr->nlmsg_len) + RTA_ALIGN(data_len) > max_len)
+       {
+               DBG1(DBG_KNL, "netlink message exceeded bound of %d", max_len);
+               return FAILED;
+       }
+       
+       rta = (struct rtattr*)(((char*)hdr) + NLMSG_ALIGN(hdr->nlmsg_len));
+
+       rta->rta_type = rta_type;
+       rta->rta_len = RTA_LENGTH(data_len);
+       memcpy(RTA_DATA(rta), data, data_len);
+       
+       hdr->nlmsg_len = NLMSG_ALIGN(hdr->nlmsg_len) + rta->rta_len;
+       return SUCCESS;
+}
+
+/**
+ * Manages the creation and deletion of ip addresses on an interface.
+ * By setting the appropriate nlmsg_type, the ip will be set or unset.
+ */
+static status_t manage_ipaddr(private_kernel_interface_t *this, int nlmsg_type,
+                                                         int flags, int if_index, host_t *ip)
+{
+       unsigned char request[BUFFER_SIZE];
+       struct nlmsghdr *hdr;
+       struct ifaddrmsg *msg;
+       chunk_t chunk;
+
+       DBG2(DBG_KNL, "adding virtual IP %H to interface %d", ip, if_index);
+       
+       memset(&request, 0, sizeof(request));
+       
+       chunk = ip->get_address(ip);
+    
+    hdr = (struct nlmsghdr*)request;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+       hdr->nlmsg_type = nlmsg_type; 
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+       
+       msg = (struct ifaddrmsg*)NLMSG_DATA(hdr);
+    msg->ifa_family = ip->get_family(ip);
+    msg->ifa_flags = 0;
+    msg->ifa_prefixlen = 8 * chunk.len;
+    msg->ifa_scope = RT_SCOPE_UNIVERSE;
+    msg->ifa_index = if_index;
+       
+       if (add_rtattr(hdr, sizeof(request), IFA_LOCAL,
+                                  chunk.ptr, chunk.len) != SUCCESS)
+       {
+               return FAILED;
+       }
+
+       return send_rtrequest(this, hdr);
+}
+
+static int get_iface(private_kernel_interface_t *this, host_t* ip)
+{
+       unsigned char request[BUFFER_SIZE];
+       struct nlmsghdr *hdr;
+       struct rtmsg *msg;
+       struct rtattr* rta;
+       chunk_t chunk;
+       int ifindex = 0;
+
+       DBG2(DBG_KNL, "getting interface for %H", ip);
+       
+       memset(&request, 0, sizeof(request));
+       
+       chunk = ip->get_address(ip);
+    
+    hdr = (struct nlmsghdr*)request;
+       hdr->nlmsg_flags = NLM_F_REQUEST;
+       hdr->nlmsg_type = RTM_GETROUTE; 
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+       
+       msg = (struct rtmsg*)NLMSG_DATA(hdr);
+       msg->rtm_family = ip->get_family(ip);
+       msg->rtm_table = 0;
+       msg->rtm_protocol = 0;
+       msg->rtm_scope = 0;
+       msg->rtm_type = 0;
+       msg->rtm_src_len = 0;
+       msg->rtm_dst_len = 8 * chunk.len;
+       msg->rtm_tos = 0;
+       msg->rtm_flags = RT_TABLE_UNSPEC | RTPROT_UNSPEC;
+
+       if (add_rtattr(hdr, sizeof(request), RTA_DST,
+                                  chunk.ptr, chunk.len) != SUCCESS)
+       {
+               return 0;
+       }
+
+       if(send_message(this, hdr, &hdr, this->rt_socket) != SUCCESS)
+       {
+               return 0;
+       }
+       rta = (struct rtattr*)(NLMSG_DATA(hdr) + NLMSG_LENGTH(sizeof(struct rtmsg)));
+
+       while(RTA_OK(rta, hdr->nlmsg_len))
+       {
+               if(rta->rta_type == RTA_OIF)
+               {
+                       ifindex = *((int*)RTA_DATA(rta));
+                       break;
+               }
+               rta = RTA_NEXT(rta, hdr->nlmsg_len);
+       }
+       free(hdr);
+       if (ifindex == 0)
+       {
+               DBG1(DBG_KNL, "address %H not reachable, unable to get interface", ip);
+       }
+       return ifindex;
+}
+
+/**
+ * Manages source routes in the routing table.
+ * By setting the appropriate nlmsg_type, the route will be set or unset.
+ */
+static status_t manage_srcroute(private_kernel_interface_t *this,
+                                       int nlmsg_type, int flags, rt_refcount_t *route)
+{
+       struct nlmsghdr *hdr;
+       struct rtmsg *msg;
+       unsigned char request[BUFFER_SIZE];
+       chunk_t src;
+       
+       memset(&request, 0, sizeof(request));
+
+       hdr = (struct nlmsghdr*)request;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;
+       hdr->nlmsg_type = nlmsg_type;
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+
+       msg = (struct rtmsg*)NLMSG_DATA(hdr);
+       msg->rtm_family = route->src_ip->get_family(route->src_ip);
+       msg->rtm_dst_len = route->prefixlen;
+       msg->rtm_table = RT_TABLE_MAIN;
+       msg->rtm_protocol = RTPROT_STATIC;
+       msg->rtm_type = RTN_UNICAST;
+       msg->rtm_scope = RT_SCOPE_UNIVERSE;
+
+       src = route->src_ip->get_address(route->src_ip);
+
+       if (add_rtattr(hdr, sizeof(request), RTA_DST,
+                                  route->dst_net.ptr, route->dst_net.len) != SUCCESS)
+       {
+               return FAILED;
+       }
+
+       if (add_rtattr(hdr, sizeof(request), RTA_PREFSRC,
+                                  src.ptr, src.len) != SUCCESS)
+       {
+               return FAILED;
+       }
+
+       if (add_rtattr(hdr, sizeof(request), RTA_OIF,
+                                  &route->if_index, sizeof(route->if_index)) != SUCCESS)
+       {
+               return FAILED;
+       }
+
+       return send_rtrequest(this, hdr);
+}
+
+/**
+ * destroy an rt_refcount object
+ */
+static void rt_refcount_destroy(rt_refcount_t *this)
+{
+       this->src_ip->destroy(this->src_ip);
+       chunk_free(&this->dst_net);
+       free(this);
+}
+
+/**
+ * destroy a vip_refcount object
+ */
+static void vip_refcount_destroy(vip_refcount_t *this)
+{
+       this->ip->destroy(this->ip);
+       free(this);
+}
+
+/**
+ * Implementation of kernel_interface_t.add_ip.
+ */
+static status_t add_ip(private_kernel_interface_t *this, 
+                                               host_t *virtual_ip, host_t *dst_ip)
+{
+       int targetif;
+       vip_refcount_t *listed;
+       iterator_t *iterator;
+
+       DBG2(DBG_KNL, "adding ip addr: %H", virtual_ip);
+
+       targetif = get_iface(this, dst_ip);
+       if (targetif == 0)
+       {
+               return FAILED;
+       }
+
+       /* beware of deadlocks (e.g. send/receive packets while holding the lock) */
+       iterator = this->vips->create_iterator_locked(this->vips, &(this->vip_mutex));
+       while (iterator->iterate(iterator, (void**)&listed))
+       {
+               if (listed->if_index == targetif &&
+                       virtual_ip->ip_equals(virtual_ip, listed->ip))
+               {
+                       listed->refcount++;
+                       iterator->destroy(iterator);
+                       return SUCCESS;
+               }
+       }
+       iterator->destroy(iterator);
+
+       if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
+                               targetif, virtual_ip) == SUCCESS)
+       {
+               listed = malloc_thing(vip_refcount_t);
+               listed->ip = virtual_ip->clone(virtual_ip);
+               listed->if_index = targetif;
+               listed->refcount = 1;
+               this->vips->insert_last(this->vips, listed);
+               return SUCCESS;
+       }
+       
+       return FAILED;
+}
+
+/**
+ * Implementation of kernel_interface_t.del_ip.
+ */
+static status_t del_ip(private_kernel_interface_t *this,
+                                               host_t *virtual_ip, host_t *dst_ip)
+{
+       int targetif;
+       vip_refcount_t *listed;
+       iterator_t *iterator;
+
+       DBG2(DBG_KNL, "deleting ip addr: %H", virtual_ip);
+
+       targetif = get_iface(this, dst_ip);
+       if (targetif == 0)
+       {
+               return FAILED;
+       }
+
+       /* beware of deadlocks (e.g. send/receive packets while holding the lock) */
+       iterator = this->vips->create_iterator_locked(this->vips, &(this->vip_mutex));
+       while (iterator->iterate(iterator, (void**)&listed))
+       {
+               if (listed->if_index == targetif &&
+                       virtual_ip->ip_equals(virtual_ip, listed->ip))
+               {
+                       listed->refcount--;
+                       if (listed->refcount == 0)
+                       {
+                               iterator->remove(iterator);
+                               vip_refcount_destroy(listed);
+                               iterator->destroy(iterator);
+                               return manage_ipaddr(this, RTM_DELADDR, 0, targetif, virtual_ip);
+                       }
+                       iterator->destroy(iterator);
+                       return SUCCESS;
+               }
+       }
+       iterator->destroy(iterator);
+       return FAILED;
 }
 
 /**
  * Implementation of kernel_interface_t.destroy.
  */
 static void destroy(private_kernel_interface_t *this)
-{      
-       pthread_cancel(this->thread);
-       pthread_join(this->thread, NULL);
-       close(this->socket);
+{
+       pthread_cancel(this->xfrm_thread);
+       pthread_join(this->xfrm_thread, NULL);
+       pthread_cancel(this->rt_thread);
+       pthread_join(this->rt_thread, NULL);
+       close(this->xfrm_socket);
+       close(this->rt_socket);
+       this->vips->destroy_function(this->vips, (void*)vip_refcount_destroy);
        this->responses->destroy(this->responses);
        this->policies->destroy(this->policies);
        free(this);
@@ -1262,7 +1827,8 @@ static void destroy(private_kernel_interface_t *this)
  */
 kernel_interface_t *kernel_interface_create()
 {
-       struct sockaddr_nl addr;
+       struct sockaddr_nl addr_xfrm;
+       struct sockaddr_nl addr_rt;
        private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t);
        
        /* public functions */
@@ -1274,45 +1840,88 @@ kernel_interface_t *kernel_interface_create()
        this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t,bool))add_policy;
        this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy;
        this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy;
+       this->public.add_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) add_ip;
+       this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) del_ip;
        this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
 
        /* private members */
        this->pid = getpid();
        this->responses = linked_list_create();
+       this->vips = linked_list_create();
        this->policies = linked_list_create();
        pthread_mutex_init(&(this->rep_mutex),NULL);
        pthread_mutex_init(&(this->pol_mutex),NULL);
+       pthread_mutex_init(&(this->vip_mutex),NULL);
        pthread_cond_init(&(this->condvar),NULL);
        this->seq = 0;
        
-       /* open netlink socket */
-       this->socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_XFRM);
-       if (this->socket <= 0)
+       /* open xfrm netlink socket */
+       this->xfrm_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_XFRM);
+       if (this->xfrm_socket <= 0)
        {
-               this->responses->destroy(this->responses);
-               free(this);
-               charon->kill(charon, "Unable to create netlink socket");        
+               DBG1(DBG_KNL, "Unable to create xfrm netlink socket");
+               goto kill;
        }
        
-       /* bind the socket and reqister for ACQUIRE & EXPIRE */
-       addr.nl_family = AF_NETLINK;
-       addr.nl_pid = getpid();
-       addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;
-       if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)) != 0)
+       /* bind the xfrm socket and reqister for ACQUIRE & EXPIRE */
+       addr_xfrm.nl_family = AF_NETLINK;
+       addr_xfrm.nl_pid = getpid();
+       addr_xfrm.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;
+       if (bind(this->xfrm_socket, (struct sockaddr*)&addr_xfrm, sizeof(addr_xfrm)))
        {
-               this->responses->destroy(this->responses);
-               close(this->socket);
-               free(this);
-               charon->kill(charon, "Unable to bind netlink socket");  
+               DBG1(DBG_KNL, "Unable to bind xfrm netlink socket");
+               goto kill_xfrm;
        }
        
-       if (pthread_create(&this->thread, NULL, (void*(*)(void*))receive_messages, this) != 0)
+       if (pthread_create(&this->xfrm_thread, NULL,
+                                          (void*(*)(void*))receive_xfrm_messages, this))
+       {
+               DBG1(DBG_KNL, "Unable to create xfrm netlink thread");
+               goto kill_xfrm;
+       }
+
+       /* open rt netlink socket */
+       this->rt_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       if (this->rt_socket <= 0)
+       {
+               DBG1(DBG_KNL, "Unable to create rt netlink socket");
+               goto kill_xfrm_all;
+       }
+
+       /* bind the socket_rt */
+       addr_rt.nl_family = AF_NETLINK;
+       addr_rt.nl_pid = getpid();
+       addr_rt.nl_groups = 0;
+       if (bind(this->rt_socket, (struct sockaddr*)&addr_rt, sizeof(addr_rt)))
        {
-               this->responses->destroy(this->responses);
-               close(this->socket);
-               free(this);
-               charon->kill(charon, "Unable to create netlink thread");
+               DBG1(DBG_KNL, "Unable to bind rt netlink socket");
+               goto kill_rt;
        }
        
+       if (pthread_create(&this->rt_thread, NULL, 
+                                          (void*(*)(void*))receive_rt_messages, this))
+       {
+               DBG1(DBG_KNL, "Unable to create rt netlink thread");
+               goto kill_rt;
+       }
+
        return &this->public;
+
+kill_rt:
+       close(this->rt_socket);
+kill_xfrm_all:
+       pthread_cancel(this->xfrm_thread);
+       pthread_join(this->xfrm_thread, NULL);
+kill_xfrm:
+       close(this->xfrm_socket);
+kill:
+       this->responses->destroy(this->responses);
+       this->policies->destroy(this->policies);
+       this->vips->destroy(this->vips);
+       free(this);
+       charon->kill(charon, "Unable to create kernel_interface");
+       return NULL;
 }
+
+/* vim: set ts=4 sw=4 noet: */
+
index 991d8e17c51d9536545322fb02b289f87f98b410..805a2b89d3435c0e91ed1966aa4ce72d38a37388 100644 (file)
@@ -263,6 +263,40 @@ struct kernel_interface_t {
                                                        traffic_selector_t *dst_ts,
                                                        policy_dir_t direction);
        
+       /**
+        * @brief Add a virtual IP to an interface.
+        *
+        * Virtual IPs are attached to an interface. If an IP is added multiple
+        * times, the IP is refcounted and not removed until del_ip() was called
+        * as many times as add_ip().
+        * The virtual IP is attached to the interface used to reach a specified
+        * destination host.
+        *
+        * @param this                  calling object
+        * @param virtual_ip    virtual ip address to assign
+        * @param dst_ip                destination host to select outgoing interface
+        * @return
+        *                                              - SUCCESS
+        *                                              - FAILED if kernel comm failed
+        */
+       status_t (*add_ip) (kernel_interface_t *this, host_t *virtual_ip,
+                                               host_t *dst_ip);
+       
+       /**
+        * @brief Remove a virtual IP from an interface.
+        *
+        * The kernel interface uses refcounting, see add_ip().
+        *
+        * @param this                  calling object
+        * @param virtual_ip    virtual ip address to assign
+        * @param dst_ip                destination host to select outgoing interface
+        * @return
+        *                                              - SUCCESS
+        *                                              - FAILED if kernel comm failed
+        */
+       status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip,
+                                               host_t *dst_ip);
+       
        /**
         * @brief Destroys a kernel_interface object.
         *
index a4ae033014d29079623430082ddec2b32717e1b3..c491be9754f85f3248120e2d112d9c5285769677 100755 (executable)
@@ -197,6 +197,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
        bool my_ca_same = FALSE;
        bool other_ca_same =FALSE;
        host_t *my_host, *other_host, *my_subnet, *other_subnet;
+       host_t *my_vip = NULL, *other_vip = NULL;
        proposal_t *proposal;
        traffic_selector_t *my_ts, *other_ts;
        
@@ -205,6 +206,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
        pop_string(msg, &msg->add_conn.other.address);
        pop_string(msg, &msg->add_conn.me.subnet);
        pop_string(msg, &msg->add_conn.other.subnet);
+       pop_string(msg, &msg->add_conn.me.sourceip);
+       pop_string(msg, &msg->add_conn.other.sourceip);
        pop_string(msg, &msg->add_conn.me.id);
        pop_string(msg, &msg->add_conn.other.id);
        pop_string(msg, &msg->add_conn.me.cert);
@@ -223,6 +226,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
        DBG2(DBG_CFG, "  right=%s", msg->add_conn.other.address);
        DBG2(DBG_CFG, "  leftsubnet=%s", msg->add_conn.me.subnet);
        DBG2(DBG_CFG, "  rightsubnet=%s", msg->add_conn.other.subnet);
+       DBG2(DBG_CFG, "  leftsourceip=%s", msg->add_conn.me.sourceip);
+       DBG2(DBG_CFG, "  rightsourceip=%s", msg->add_conn.other.sourceip);
        DBG2(DBG_CFG, "  leftid=%s", msg->add_conn.me.id);
        DBG2(DBG_CFG, "  rightid=%s", msg->add_conn.other.id);
        DBG2(DBG_CFG, "  leftcert=%s", msg->add_conn.me.cert);
@@ -303,7 +308,13 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
                my_subnet->destroy(my_subnet);
                goto destroy_ids;
        }
-                               
+       
+       if (msg->add_conn.me.virtual_ip)
+       {
+               my_vip = host_create_from_string(msg->add_conn.me.sourceip, 0);
+       }
+       other_vip = host_create_from_string(msg->add_conn.other.sourceip, 0);
+               
        my_ts = traffic_selector_create_from_subnet(my_subnet,
                                msg->add_conn.me.subnet ?  msg->add_conn.me.subnet_mask : 0,
                                msg->add_conn.me.protocol, msg->add_conn.me.port);
@@ -429,7 +440,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
                connection->add_proposal(connection, proposal);
        }
        
-       policy = policy_create(msg->add_conn.name, my_id, other_id,
+       policy = policy_create(msg->add_conn.name, my_id, other_id, my_vip, other_vip,
                                                   msg->add_conn.auth_method, msg->add_conn.eap_type,
                                                   msg->add_conn.rekey.ipsec_lifetime,
                                                   msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin,
@@ -559,16 +570,7 @@ static void stroke_initiate(stroke_msg_t *msg, FILE *out)
                return;
        }
        
-       job = initiate_job_create(connection, NULL, policy);
-       /*
-       if (msg->output_verbosity < 0)
-       {
-       TODO: detach immediately if verbosity is SILENT. Local credential store
-       is not threadsave yet, so this would cause crashes!!
-               charon->job_queue->add(charon->job_queue, (job_t*)job);
-               return;
-}*/
-       
+       job = initiate_job_create(connection, policy);
        charon->bus->set_listen_state(charon->bus, TRUE);
        charon->job_queue->add(charon->job_queue, (job_t*)job);
        while (TRUE)
@@ -664,10 +666,100 @@ static void stroke_route(stroke_msg_t *msg, FILE *out, bool route)
  */
 static void stroke_terminate(stroke_msg_t *msg, FILE *out)
 {
+       char *string, *pos = NULL, *name = NULL;
+       u_int32_t id = 0;
+       bool child;
+       int len;
+       status_t status = SUCCESS;;
+       ike_sa_t *ike_sa;
+       
        pop_string(msg, &(msg->terminate.name));
-       DBG1(DBG_CFG, "received stroke: terminate '%s'", msg->terminate.name);
+       string = msg->terminate.name;
+       DBG1(DBG_CFG, "received stroke: terminate '%s'", string);
        
-       charon->ike_sa_manager->delete_by_name(charon->ike_sa_manager, msg->terminate.name);
+       len = strlen(string);
+       if (len < 1)
+       {
+               DBG1(DBG_CFG, "error parsing string");
+               return;
+       }
+       switch (string[len-1])
+       {
+               case '}':
+                       child = TRUE;
+                       pos = strchr(string, '{');
+                       break;
+               case ']':
+                       child = FALSE;
+                       pos = strchr(string, '[');
+                       break;
+               default:
+                       name = string;
+                       child = FALSE;
+                       break;
+       }
+       
+       if (name)
+       {       /* must be a single name */
+               DBG1(DBG_CFG, "check out by single name '%s'", name);
+               ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
+                                                                                                                 name, child);
+       }
+       else if (pos == string + len - 2)
+       {       /* must be name[] or name{} */
+               string[len-2] = '\0';
+               DBG1(DBG_CFG, "check out by name '%s'", string);
+               ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager,
+                                                                                                                 string, child);
+       }
+       else
+       {       /* must be name[123] or name{23} */
+               string[len-1] = '\0';
+               id = atoi(pos + 1);
+               if (id == 0)
+               {
+                       DBG1(DBG_CFG, "error parsing string");
+                       return;
+               }
+               DBG1(DBG_CFG, "check out by id '%d'", id);
+               ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                               id, child);
+       }
+       if (ike_sa == NULL)
+       {
+               DBG1(DBG_CFG, "no such IKE_SA found");
+               return;
+       }
+       
+       if (!child)
+       {
+               status = ike_sa->delete(ike_sa);
+       }
+       else
+       {
+               child_sa_t *child_sa;
+               iterator_t *iterator = ike_sa->create_child_sa_iterator(ike_sa);
+               while (iterator->iterate(iterator, (void**)&child_sa))
+               {
+                       if ((id && id == child_sa->get_reqid(child_sa)) ||
+                               (string && streq(string, child_sa->get_name(child_sa))))
+                       {
+                               u_int32_t spi = child_sa->get_spi(child_sa, TRUE);
+                               protocol_id_t proto = child_sa->get_protocol(child_sa);
+                               
+                               status = ike_sa->delete_child_sa(ike_sa, proto, spi);
+                               break;
+                       }
+               }
+               iterator->destroy(iterator);
+       }
+       if (status == DESTROY_ME)
+       {
+               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+                                                                                                       ike_sa);
+               return;
+       }
+       charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
 }
 
 /**
index f9be454fa191d0f682eb0ed0e3a254e36bb6b4a8..8cbfd6ab8fd60fca48e95217694424f0520ce4ac 100644 (file)
@@ -6,7 +6,8 @@
  */
 
 /*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -45,7 +46,7 @@ struct private_host_t {
        union {
                /** generic type */
                struct sockaddr address;
-               /** maximux sockaddr size */
+               /** maximum sockaddr size */
                struct sockaddr_storage address_max;
                /** IPv4 address */
                struct sockaddr_in address4;
@@ -495,3 +496,31 @@ host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
        free(this);
        return NULL;
 }
+
+/*
+ * Described in header.
+ */
+host_t *host_create_any(int family)
+{
+       private_host_t *this = host_create_empty();
+       
+       memset(&this->address_max, 0, sizeof(struct sockaddr_storage));
+       this->address.sa_family = family;
+       
+       switch (family)
+       {
+               case AF_INET:
+               {
+                       this->socklen = sizeof(struct sockaddr_in);
+                       return &(this->public);
+               }
+               case AF_INET6:
+               {
+                       this->socklen = sizeof(struct sockaddr_in6);
+                       return &this->public;
+               }
+               default:
+                       break;
+       }
+       return NULL;
+}
index 20b5c6345968a2275ed670b35e2e27eb4712d3f7..4613004381577c52b1078894b08399a5c41de275 100644 (file)
@@ -6,7 +6,8 @@
  */
 
 /*
- * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
+ * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -216,4 +217,16 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port);
  */
 host_t *host_create_from_sockaddr(sockaddr_t *sockaddr);
 
+/**
+ * @brief Create a host without an address, a "any" host.
+ *
+ * @param family               family of the any host
+ * @return                             
+ *                                             - host_t object 
+ *                                             - NULL, if family not supported.
+ * 
+ * @ingroup network
+ */
+host_t *host_create_any(int family);
+
 #endif /*HOST_H_*/
index 6c77b41e8e2a4f8e5b559924c93fbf3e5c1ed11d..341af39c052d7d99999b7bb0b8f59232fcda58cb 100644 (file)
@@ -497,7 +497,10 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
        bool next_a, next_b;
 
        /* initialize wildcard counter */
-       *wildcards = 0;
+       if (wildcards)
+       {
+               *wildcards = 0;
+       }
 
        /* initialize DN parsing */
        if (init_rdn(a, &rdn_a, &attribute_a, &next_a) != SUCCESS
@@ -522,7 +525,10 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
                /* does rdn_b contain a wildcard? */
                if (value_b.len == 1 && *value_b.ptr == '*')
                {
-                       (*wildcards)++;
+                       if (wildcards)
+                       {
+                               (*wildcards)++;
+                       }
                        continue;
                }
                /* same lengths for values */
@@ -549,7 +555,10 @@ bool match_dn(chunk_t a, chunk_t b, int *wildcards)
        }
 
        /* the two DNs match! */
-       *wildcards = min(*wildcards, MAX_WILDCARDS);
+       if (wildcards)
+       {
+               *wildcards = min(*wildcards, MAX_WILDCARDS);
+       }
        return TRUE;
 }
 
@@ -750,10 +759,16 @@ static bool matches_binary(private_identification_t *this,
 {
        if (other->type == ID_ANY)
        {
-               *wildcards = MAX_WILDCARDS;
+               if (wildcards)
+               {
+                       *wildcards = MAX_WILDCARDS;
+               }
                return TRUE;
        }
-       *wildcards = 0;
+       if (wildcards)
+       {
+               *wildcards = 0;
+       }
        return this->type == other->type &&
                                                        chunk_equals(this->encoded, other->encoded);
 }
@@ -769,7 +784,10 @@ static bool matches_string(private_identification_t *this,
        
        if (other->type == ID_ANY)
        {
-               *wildcards = MAX_WILDCARDS;
+               if (wildcards)
+               {
+                       *wildcards = MAX_WILDCARDS;
+               }
                return TRUE;
        }
        
@@ -779,7 +797,10 @@ static bool matches_string(private_identification_t *this,
        /* try a binary comparison first */
        if (equals_binary(this, other))
        {
-               *wildcards = 0;
+               if (wildcards)
+               {
+                       *wildcards = 0;
+               }
                return TRUE;
        }
        
@@ -789,7 +810,10 @@ static bool matches_string(private_identification_t *this,
        /* check for single wildcard at the head of the string */
        if (*other->encoded.ptr == '*')
        {
-               *wildcards = 1;
+               if (wildcards)
+               {
+                       *wildcards = 1;
+               }
 
                /* single asterisk matches any string */
                if (len-- == 1)
@@ -809,7 +833,10 @@ static bool matches_string(private_identification_t *this,
 static bool matches_any(private_identification_t *this,
                                                private_identification_t *other, int *wildcards)
 {
-       *wildcards = 0;
+       if (wildcards)
+       {
+               *wildcards = 0;
+       }
        return other->type == ID_ANY;
 }
 
@@ -822,7 +849,10 @@ static bool matches_dn(private_identification_t *this,
 {
        if (other->type == ID_ANY)
        {
-               *wildcards = MAX_WILDCARDS;
+               if (wildcards)
+               {
+                       *wildcards = MAX_WILDCARDS;
+               }
                return TRUE;
        }
        
index 80fc27d7c9ecfb742d78885ffd5d357e2020a033..59c568eaf8e03b0bdce3635ce5e56305689cad2f 100644 (file)
@@ -182,7 +182,7 @@ struct identification_t {
         * 
         * @param this          the ID without wildcard
         * @param other         the ID containing a wildcard
-        * @param wildcards     returns the number of wildcards
+        * @param wildcards     returns the number of wildcards, may be NULL
         * @return                      TRUE if match is found
         */
        bool (*matches) (identification_t *this, identification_t *other, int *wildcards);
index 51a8d6061336f4a1c0315c22ac8a2a3f91adea0f..02a15c534a649a05bc9a5baaaba2de97fff08b46 100644 (file)
 #ifndef ITERATOR_H_
 #define ITERATOR_H_
 
+#include <library.h>
+
+/**
+ * @brief Iterator hook function prototype.
+ *
+ * @param param                user supplied parameter
+ * @param in           the value the hook receives from the iterator
+ * @param out          the value supplied as a result to the iterator
+ * @return                     TRUE to return "out", FALSE to skip this value
+ */
+typedef bool (iterator_hook_t)(void *param, void *in, void **out);
+
+
 typedef struct iterator_t iterator_t;
 
 /**
@@ -76,8 +89,10 @@ struct iterator_t {
         * 
         * @param this                  calling object
         * @param hook                  iterator hook which manipulates the iterated value
+        * @param param                 user supplied parameter to pass back to the hook
         */
-       void (*set_iterator_hook) (iterator_t *this, void*(*hook)(void*));
+       void (*set_iterator_hook) (iterator_t *this, iterator_hook_t *hook,
+                                                          void *param);
        
        /**
         * @brief Inserts a new item before the given iterator position.
index 8c50688701904fad9b6b3338aadc703d4084da34..de043a02e59599c8ae36e7f85c56495ad9ab2c6b 100644 (file)
@@ -132,7 +132,12 @@ struct private_iterator_t {
        /**
         * iteration hook
         */
-       void* (*hook)(void*);
+       iterator_hook_t *hook;
+       
+       /**
+        * user parameter for iterator hook
+        */
+       void *hook_param;
 };
 
 /**
@@ -146,23 +151,27 @@ static int get_list_count(private_iterator_t *this)
 /**
  * default iterator hook which does nothing
  */
-static void *iterator_hook(void *value)
+static bool iterator_hook(void *param, void *in, void **out)
 {
-       return value;
+       *out = in;
+       return TRUE;
 }
 
 /**
  * Implementation of iterator_t.set_iterator_hook.
  */
-static void set_iterator_hook(private_iterator_t *this, void*(*hook)(void*))
+static void set_iterator_hook(private_iterator_t *this, iterator_hook_t *hook,
+                                                         void* param)
 {
        if (hook == NULL)
        {
                this->hook = iterator_hook;
+               this->hook_param = NULL;
        }
        else
        {
                this->hook = hook;
+               this->hook_param = param;
        }
 }
 
@@ -178,7 +187,10 @@ static bool iterate(private_iterator_t *this, void** value)
        if (this->current == NULL)
        {
                this->current = (this->forward) ? this->list->first : this->list->last;
-               *value = this->hook(this->current->value);
+               if (!this->hook(this->hook_param, this->current->value, value))
+               {
+                       return iterate(this, value);
+               }
                return TRUE;
        }
        if (this->forward)
@@ -188,16 +200,21 @@ static bool iterate(private_iterator_t *this, void** value)
                        return FALSE;
                }
                this->current = this->current->next;
-               *value = this->hook(this->current->value);
+               if (!this->hook(this->hook_param, this->current->value, value))
+               {
+                       return iterate(this, value);
+               }
                return TRUE;
        }
-       /* backward */
        if (this->current->previous == NULL)
        {
                return FALSE;
        }
        this->current = this->current->previous;
-       *value = this->hook(this->current->value);
+       if (!this->hook(this->hook_param, this->current->value, value))
+       {
+               return iterate(this, value);
+       }
        return TRUE;
 }
 
@@ -225,11 +242,15 @@ static status_t remove_(private_iterator_t *this)
        {
                return NOT_FOUND;
        }
-       /* find out the new iterator position */
-       if (this->current->previous != NULL)
+       /* find out the new iterator position, depending on iterator direction */
+       if (this->forward && this->current->previous != NULL)
        {
                new_current = this->current->previous;
        }
+       else if (!this->forward && this->current->next != NULL)
+       {
+               new_current = this->current->next;
+       }
        else
        {
                new_current = NULL;
@@ -679,7 +700,7 @@ static iterator_t *create_iterator(private_linked_list_t *linked_list, bool forw
        
        this->public.get_count = (int (*) (iterator_t*)) get_list_count;
        this->public.iterate = (bool (*) (iterator_t*, void **value)) iterate;
-       this->public.set_iterator_hook = (void(*)(iterator_t*, void*(*)(void*)))set_iterator_hook;
+       this->public.set_iterator_hook = (void(*)(iterator_t*, iterator_hook_t*, void*))set_iterator_hook;
        this->public.insert_before = (void (*) (iterator_t*, void *item)) insert_before;
        this->public.insert_after = (void (*) (iterator_t*, void *item)) insert_after;
        this->public.replace = (status_t (*) (iterator_t*, void **, void *)) replace;
index 9f14533947700aaaa23e4c698560b6e83dc22e0b..9e83581fa85e24e9d69d38b4a02659af5862954d 100644 (file)
@@ -252,7 +252,8 @@ kw_end(starter_conn_t *conn, starter_end_t *end, kw_token_t token
                        plog("# natip and sourceip cannot be defined at the same time");
                        goto err;
                }
-               if (streq(value, "%modeconfig") || streq(value, "%modecfg"))
+               if (streq(value, "%modeconfig") || streq(value, "%modecfg") ||
+                       streq(value, "%config") || streq(value, "%cfg"))
                {
                        end->modecfg = TRUE;
                }
index 28d777a21a90b4076c94d10ef2a8abf6655fa70f..79ad33f618a3c67cacefae89fc98bd28f13b2c96 100644 (file)
@@ -166,6 +166,9 @@ static void starter_stroke_add_end(stroke_msg_t *msg, stroke_end_t *msg_end, sta
        msg_end->hostaccess = conn_end->hostaccess;
        msg_end->protocol = conn_end->protocol;
        msg_end->port = conn_end->port;
+       msg_end->virtual_ip = conn_end->modecfg;
+       ip_address2string(&conn_end->srcip, buffer, sizeof(buffer));
+       msg_end->sourceip = push_string(msg, buffer);
 }
 
 int starter_stroke_add_conn(starter_conn_t *conn)
index 3d186bd0cf743d6a64147e21af53198ad3acf978..1fed6e281b167c54cda7197e01f9b9768b67f448 100644 (file)
@@ -127,6 +127,8 @@ static int add_connection(char *name,
        msg.add_conn.me.address = push_string(&msg, my_addr);
        msg.add_conn.me.subnet = push_string(&msg, my_net);
        msg.add_conn.me.subnet_mask = my_netmask;
+       msg.add_conn.me.sourceip = NULL;
+       msg.add_conn.me.virtual_ip = 0;
        msg.add_conn.me.cert = NULL;
        msg.add_conn.me.ca = NULL;
        msg.add_conn.me.sendcert = 1;
@@ -138,6 +140,8 @@ static int add_connection(char *name,
        msg.add_conn.other.address = push_string(&msg, other_addr);
        msg.add_conn.other.subnet = push_string(&msg, other_net);
        msg.add_conn.other.subnet_mask = other_netmask;
+       msg.add_conn.other.sourceip = NULL;
+       msg.add_conn.other.virtual_ip = 0;
        msg.add_conn.other.cert = NULL;
        msg.add_conn.other.ca = NULL;
        msg.add_conn.other.sendcert = 1;
index ced655583451c9c0b5590ee7f8f3c0ad5ae091fb..57ddf29be0bfb87e9cb33bbfbea31e34f8b13c9c 100644 (file)
@@ -100,6 +100,8 @@ struct stroke_end_t {
        char *ca;
        char *updown;
        char *address;
+       char *sourceip;
+       u_int8_t virtual_ip;
        char *subnet;
        int subnet_mask;
        int sendcert;