aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libcharon/bus/bus.c33
-rw-r--r--src/libcharon/bus/bus.h37
-rw-r--r--src/libcharon/bus/listeners/listener.h15
-rw-r--r--src/libcharon/sa/tasks/child_create.c43
4 files changed, 123 insertions, 5 deletions
diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c
index 6a9fcce02..97d09c40a 100644
--- a/src/libcharon/bus/bus.c
+++ b/src/libcharon/bus/bus.c
@@ -640,6 +640,38 @@ METHOD(bus_t, authorize, bool,
return success;
}
+METHOD(bus_t, narrow, void,
+ private_bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
+ linked_list_t *local, linked_list_t *remote)
+{
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ entry_t *entry;
+ bool keep;
+
+ ike_sa = this->thread_sa->get(this->thread_sa);
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->listeners->create_enumerator(this->listeners);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->calling || !entry->listener->narrow)
+ {
+ continue;
+ }
+ entry->calling++;
+ keep = entry->listener->narrow(entry->listener, ike_sa, child_sa,
+ type, local, remote);
+ entry->calling--;
+ if (!keep)
+ {
+ unregister_listener(this, entry, enumerator);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+}
+
METHOD(bus_t, destroy, void,
private_bus_t *this)
{
@@ -676,6 +708,7 @@ bus_t *bus_create()
.child_updown = _child_updown,
.child_rekey = _child_rekey,
.authorize = _authorize,
+ .narrow = _narrow,
.destroy = _destroy,
},
.listeners = linked_list_create(),
diff --git a/src/libcharon/bus/bus.h b/src/libcharon/bus/bus.h
index 8cf392eae..df555d83e 100644
--- a/src/libcharon/bus/bus.h
+++ b/src/libcharon/bus/bus.h
@@ -22,6 +22,7 @@
#define BUS_H_
typedef enum alert_t alert_t;
+typedef enum narrow_hook_t narrow_hook_t;
typedef struct bus_t bus_t;
#include <stdarg.h>
@@ -86,6 +87,31 @@ enum alert_t {
};
/**
+ * Kind of narrow hook.
+ *
+ * There is a non-authenticated (IKE_AUTH) and a authenticated
+ * (CREATE_CHILD_SA) narrowing hook for the initiator. Only one of these
+ * hooks is invoked before the exchange.
+ * To verify the traffic selectors negotiated, each PRE hook has a POST
+ * counterpart that follows. POST hooks are invoked with an authenticated peer.
+ * It is usually not a good idea to narrow in the POST hooks,
+ * as the resulting traffic selector is not negotiated and results
+ * in non-matching policies.
+ */
+enum narrow_hook_t {
+ /** invoked as initiator before exchange, peer is not yet authenticated */
+ NARROW_INITIATOR_PRE_NOAUTH,
+ /** invoked as initiator before exchange, peer is authenticated */
+ NARROW_INITIATOR_PRE_AUTH,
+ /** invoked as responder during exchange, peer is authenticated */
+ NARROW_RESPONDER,
+ /** invoked as initiator after exchange, follows a INITIATOR_PRE_NOAUTH */
+ NARROW_INITIATOR_POST_NOAUTH,
+ /** invoked as initiator after exchange, follows a INITIATOR_PRE_AUTH */
+ NARROW_INITIATOR_POST_AUTH,
+};
+
+/**
* The bus receives events and sends them to all registered listeners.
*
* Any events sent to are delivered to all registered listeners. Threads
@@ -217,6 +243,17 @@ struct bus_t {
bool (*authorize)(bus_t *this, bool final);
/**
+ * CHILD_SA traffic selector narrowing hook.
+ *
+ * @param child_sa CHILD_SA set up with these traffic selectors
+ * @param type type of hook getting invoked
+ * @param local list of local traffic selectors to narrow
+ * @param remote list of remote traffic selectors to narrow
+ */
+ void (*narrow)(bus_t *this, child_sa_t *child_sa, narrow_hook_t type,
+ linked_list_t *local, linked_list_t *remote);
+
+ /**
* IKE_SA keymat hook.
*
* @param ike_sa IKE_SA this keymat belongs to
diff --git a/src/libcharon/bus/listeners/listener.h b/src/libcharon/bus/listeners/listener.h
index 9a51a2ef4..45c61c0c0 100644
--- a/src/libcharon/bus/listeners/listener.h
+++ b/src/libcharon/bus/listeners/listener.h
@@ -173,6 +173,21 @@ struct listener_t {
*/
bool (*authorize)(listener_t *this, ike_sa_t *ike_sa,
bool final, bool *success);
+
+ /**
+ * CHILD_SA traffic selector narrowing hook.
+ *
+ * This hook is invoked for each CHILD_SA and allows plugins to modify
+ * the traffic selector list negotiated for this CHILD_SA.
+ *
+ * @param ike_sa IKE_SA the created CHILD_SA is created in
+ * @param child_sa CHILD_SA set up with these traffic selectors
+ * @param type type of hook getting invoked
+ * @param local list of local traffic selectors to narrow
+ * @param remote list of remote traffic selectors to narrow
+ */
+ bool (*narrow)(listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+ narrow_hook_t type, linked_list_t *local, linked_list_t *remote);
};
#endif /** LISTENER_H_ @}*/
diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c
index ed468ec9c..992811040 100644
--- a/src/libcharon/sa/tasks/child_create.c
+++ b/src/libcharon/sa/tasks/child_create.c
@@ -273,7 +273,8 @@ static void schedule_inactivity_timeout(private_child_create_t *this)
* - INVALID_ARG: diffie hellman group inacceptable
* - NOT_FOUND: TS inacceptable
*/
-static status_t select_and_install(private_child_create_t *this, bool no_dh)
+static status_t select_and_install(private_child_create_t *this,
+ bool no_dh, bool ike_auth)
{
status_t status, status_i, status_o;
chunk_t nonce_i, nonce_r;
@@ -364,6 +365,25 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts,
other_vip);
+ if (this->initiator)
+ {
+ if (ike_auth)
+ {
+ charon->bus->narrow(charon->bus, this->child_sa,
+ NARROW_INITIATOR_POST_NOAUTH, my_ts, other_ts);
+ }
+ else
+ {
+ charon->bus->narrow(charon->bus, this->child_sa,
+ NARROW_INITIATOR_POST_AUTH, my_ts, other_ts);
+ }
+ }
+ else
+ {
+ charon->bus->narrow(charon->bus, this->child_sa,
+ NARROW_RESPONDER, my_ts, other_ts);
+ }
+
if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0)
{
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
@@ -848,6 +868,17 @@ static status_t build_i(private_child_create_t *this, message_t *message)
add_ipcomp_notify(this, message, IPCOMP_DEFLATE);
}
+ if (message->get_exchange_type(message) == IKE_AUTH)
+ {
+ charon->bus->narrow(charon->bus, this->child_sa,
+ NARROW_INITIATOR_PRE_NOAUTH, this->tsi, this->tsr);
+ }
+ else
+ {
+ charon->bus->narrow(charon->bus, this->child_sa,
+ NARROW_INITIATOR_PRE_AUTH, this->tsi, this->tsr);
+ }
+
build_payloads(this, message);
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
@@ -914,7 +945,7 @@ static status_t build_r(private_child_create_t *this, message_t *message)
peer_cfg_t *peer_cfg;
payload_t *payload;
enumerator_t *enumerator;
- bool no_dh = TRUE;
+ bool no_dh = TRUE, ike_auth = FALSE;
switch (message->get_exchange_type(message))
{
@@ -934,6 +965,7 @@ static status_t build_r(private_child_create_t *this, message_t *message)
{ /* wait until all authentication round completed */
return NEED_MORE;
}
+ ike_auth = TRUE;
default:
break;
}
@@ -1016,7 +1048,7 @@ static status_t build_r(private_child_create_t *this, message_t *message)
}
}
- switch (select_and_install(this, no_dh))
+ switch (select_and_install(this, no_dh, ike_auth))
{
case SUCCESS:
break;
@@ -1064,7 +1096,7 @@ static status_t process_i(private_child_create_t *this, message_t *message)
{
enumerator_t *enumerator;
payload_t *payload;
- bool no_dh = TRUE;
+ bool no_dh = TRUE, ike_auth = FALSE;
switch (message->get_exchange_type(message))
{
@@ -1079,6 +1111,7 @@ static status_t process_i(private_child_create_t *this, message_t *message)
{ /* wait until all authentication round completed */
return NEED_MORE;
}
+ ike_auth = TRUE;
default:
break;
}
@@ -1159,7 +1192,7 @@ static status_t process_i(private_child_create_t *this, message_t *message)
return SUCCESS;
}
- if (select_and_install(this, no_dh) == SUCCESS)
+ if (select_and_install(this, no_dh, ike_auth) == SUCCESS)
{
DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",