From be715344c26b5f7c6bee3912f53ee8026f7d9dba Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Jul 2010 08:39:19 +0200 Subject: Added a hook to narrow traffic selectors for CHILD_SAs --- src/libcharon/bus/bus.c | 33 ++++++++++++++++++++++++++ src/libcharon/bus/bus.h | 37 +++++++++++++++++++++++++++++ src/libcharon/bus/listeners/listener.h | 15 ++++++++++++ src/libcharon/sa/tasks/child_create.c | 43 ++++++++++++++++++++++++++++++---- 4 files changed, 123 insertions(+), 5 deletions(-) (limited to 'src') 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 @@ -85,6 +86,31 @@ enum alert_t { ALERT_SHUTDOWN_SIGNAL, }; +/** + * 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. * @@ -216,6 +242,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. * 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", -- cgit v1.2.3