Add a responder narrow() hook to change TS in the kernel, but not on the wire
authorMartin Willi <martin@revosec.ch>
Tue, 24 Jul 2012 10:40:45 +0000 (12:40 +0200)
committerMartin Willi <martin@revosec.ch>
Tue, 11 Sep 2012 14:14:39 +0000 (16:14 +0200)
src/libcharon/bus/bus.h
src/libcharon/sa/ikev1/tasks/quick_mode.c
src/libcharon/sa/ikev2/tasks/child_create.c

index 9f820e6..aba8acd 100644 (file)
@@ -111,6 +111,8 @@ enum narrow_hook_t {
        NARROW_INITIATOR_PRE_AUTH,
        /** invoked as responder during exchange, peer is authenticated */
        NARROW_RESPONDER,
+       /** invoked as responder after exchange, peer is authenticated */
+       NARROW_RESPONDER_POST,
        /** invoked as initiator after exchange, follows a INITIATOR_PRE_NOAUTH */
        NARROW_INITIATOR_POST_NOAUTH,
        /** invoked as initiator after exchange, follows a INITIATOR_PRE_AUTH */
index 73a23f4..8f2d192 100644 (file)
@@ -214,7 +214,7 @@ static bool install(private_quick_mode_t *this)
        else
        {
                charon->bus->narrow(charon->bus, this->child_sa,
-                                                       NARROW_RESPONDER, tsr, tsi);
+                                                       NARROW_RESPONDER_POST, tsr, tsi);
        }
        if (tsi->get_count(tsi) == 0 || tsr->get_count(tsr) == 0)
        {
@@ -419,7 +419,7 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
                                                                                           supplied, host);
        if (list->get_first(list, (void**)&ts) == SUCCESS)
        {
-               if (list->get_count(list) > 1)
+               if (this->initiator && list->get_count(list) > 1)
                {
                        DBG1(DBG_IKE, "configuration has more than one %s traffic selector,"
                                 " using first only", local ? "local" : "remote");
@@ -974,6 +974,24 @@ METHOD(task_t, process_r, status_t,
                                                                        this->ike_sa->get_my_host(this->ike_sa),
                                                                        this->ike_sa->get_other_host(this->ike_sa),
                                                                        this->config, this->reqid, this->udp);
+
+                       tsi = linked_list_create();
+                       tsr = linked_list_create();
+                       tsi->insert_last(tsi, this->tsi);
+                       tsr->insert_last(tsr, this->tsr);
+                       this->tsi = this->tsr = NULL;
+                       charon->bus->narrow(charon->bus, this->child_sa,
+                                                               NARROW_RESPONDER, tsr, tsi);
+                       if (tsi->remove_first(tsi, (void**)&this->tsi) != SUCCESS ||
+                               tsr->remove_first(tsr, (void**)&this->tsr) != SUCCESS)
+                       {
+                               tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+                               tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+                               return send_notify(this, INVALID_ID_INFORMATION);
+                       }
+                       tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+                       tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+
                        return NEED_MORE;
                }
                case QM_NEGOTIATED:
index d7d912f..3520760 100644 (file)
@@ -516,7 +516,32 @@ static status_t select_and_install(private_child_create_t *this,
                return FAILED;
        }
 
-       status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts);
+       if (this->initiator)
+       {
+               status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts);
+       }
+       else
+       {
+               /* use a copy of the traffic selectors, as the POST hook should not
+                * change payloads */
+               my_ts = this->tsr->clone_offset(this->tsr,
+                                                                               offsetof(traffic_selector_t, clone));
+               other_ts = this->tsi->clone_offset(this->tsi,
+                                                                               offsetof(traffic_selector_t, clone));
+               charon->bus->narrow(charon->bus, this->child_sa,
+                                                       NARROW_RESPONDER_POST, my_ts, other_ts);
+               if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0)
+               {
+                       status = FAILED;
+               }
+               else
+               {
+                       status = this->child_sa->add_policies(this->child_sa,
+                                                                                                  my_ts, other_ts);
+               }
+               my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
+               other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
+       }
        if (status != SUCCESS)
        {
                DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");