diff options
Diffstat (limited to 'src/charon/control')
-rw-r--r-- | src/charon/control/interface_manager.c | 656 | ||||
-rwxr-xr-x | src/charon/control/interfaces/stroke_interface.c | 61 | ||||
-rw-r--r-- | src/charon/control/interfaces/xml_interface.c | 273 |
3 files changed, 604 insertions, 386 deletions
diff --git a/src/charon/control/interface_manager.c b/src/charon/control/interface_manager.c index c71036567..c14903c7d 100644 --- a/src/charon/control/interface_manager.c +++ b/src/charon/control/interface_manager.c @@ -56,18 +56,24 @@ struct private_interface_manager_t { linked_list_t *handles; }; + /** * helper struct to map bus listener callbacks to interface callbacks */ struct interface_bus_listener_t { /** - * bus listener callback function (called) + * public bus listener interface */ - bus_listener_t listener; + bus_listener_t public; + + /** + * status of the operation, return to method callers + */ + status_t status; /** - * IKE_SA to use for message filtering + * IKE SA to filter log output */ ike_sa_t *ike_sa; @@ -82,12 +88,48 @@ struct interface_bus_listener_t { void *param; /** - * caller has cancelled its listening subscription + * child configuration, used for initiate + */ + child_cfg_t *child_cfg; + + /** + * peer configuration, used for initiate + */ + peer_cfg_t *peer_cfg; + + /** + * unique ID, used for various methods + */ + u_int32_t id; +}; + + +typedef struct interface_job_t interface_job_t; + +/** + * job for asynchronous listen operations + */ +struct interface_job_t { + /** + * job interface + */ + job_t public; + + /** + * associated listener */ - bool cancelled; + interface_bus_listener_t listener; }; /** + * Implements the famous nop operation + */ +static void nop(job_t *job) +{ + /* NOP */ +} + +/** * Implementation of interface_manager_t.create_ike_sa_iterator. */ static iterator_t* create_ike_sa_iterator(interface_manager_t *this) @@ -106,17 +148,16 @@ static bool initiate_listener(interface_bus_listener_t *this, signal_t signal, { if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - this->cancelled = TRUE; return FALSE; } switch (signal) { + case CHILD_UP_SUCCESS: + this->status = SUCCESS; + return FALSE; case IKE_UP_FAILED: case CHILD_UP_FAILED: - case CHILD_UP_SUCCESS: - { return FALSE; - } default: break; } @@ -125,112 +166,82 @@ static bool initiate_listener(interface_bus_listener_t *this, signal_t signal, } /** - * listener function for terminate_ike + * execute function for initiate */ -static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) +static status_t initiate_execute(interface_job_t *job) { - if (this->ike_sa == ike_sa) + ike_sa_t *ike_sa; + ike_cfg_t *ike_cfg; + interface_bus_listener_t *listener = &job->listener; + peer_cfg_t *peer_cfg = listener->peer_cfg; + + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager, + ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg), + peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg)); + listener->ike_sa = ike_sa; + + if (ike_sa->get_peer_cfg(ike_sa) == NULL) { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - this->cancelled = TRUE; - return FALSE; - } - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - { - return FALSE; - } - default: - break; - } + ike_sa->set_peer_cfg(ike_sa, peer_cfg); } - return TRUE; -} - -/** - * listener function for terminate_child - */ -static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) -{ - if (this->ike_sa == ike_sa) + peer_cfg->destroy(peer_cfg); + + if (ike_sa->initiate(ike_sa, listener->child_cfg) != SUCCESS) { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - this->cancelled = TRUE; - return FALSE; - } - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - case CHILD_DOWN_FAILED: - case CHILD_DOWN_SUCCESS: - { - return FALSE; - } - default: - break; - } + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - return TRUE; + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } /** - * listener function for route + * Implementation of interface_manager_t.initiate. */ -static bool route_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) +static status_t initiate(private_interface_manager_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + interface_manager_cb_t callback, void *param) { - if (this->ike_sa == ike_sa) + interface_job_t job; + + job.listener.public.signal = (void*)initiate_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.child_cfg = child_cfg; + job.listener.peer_cfg = peer_cfg; + job.public.execute = (void*)initiate_execute; + job.public.destroy = nop; + + if (callback == NULL) { - if (!this->callback(this->param, signal, level, ike_sa, format, args)) - { - this->cancelled = TRUE; - return FALSE; - } - switch (signal) - { - case CHILD_ROUTE_SUCCESS: - case CHILD_ROUTE_FAILED: - { - return FALSE; - } - default: - break; - } + return initiate_execute(&job); } - return TRUE; + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; } /** - * listener function for unroute + * listener function for terminate_ike */ -static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, - level_t level, int thread, ike_sa_t *ike_sa, - char* format, va_list args) +static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) { if (this->ike_sa == ike_sa) { if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - this->cancelled = TRUE; return FALSE; } switch (signal) { - case CHILD_UNROUTE_SUCCESS: - case CHILD_UNROUTE_FAILED: - { + case IKE_DOWN_SUCCESS: + this->status = SUCCESS; + return FALSE; + case IKE_DOWN_FAILED: return FALSE; - } default: break; } @@ -239,102 +250,29 @@ static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, } /** - * remove a previously registered listener from the bus + * execute function for terminate_ike */ -static void remove_listener(interface_bus_listener_t *listener) -{ - charon->bus->remove_listener(charon->bus, &listener->listener); -} - -/** - * Implementation of interface_manager_t.initiate. - */ -static status_t initiate(private_interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param) +static status_t terminate_ike_execute(interface_job_t *job) { ike_sa_t *ike_sa; - ike_cfg_t *ike_cfg; - status_t retval = FAILED; - interface_bus_listener_t listener; + interface_bus_listener_t *listener = &job->listener; - ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager, - ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg), - peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg)); - - if (ike_sa->get_peer_cfg(ike_sa) == NULL) - { - ike_sa->set_peer_cfg(ike_sa, peer_cfg); - } - peer_cfg->destroy(peer_cfg); - - listener.listener.signal = (void*)initiate_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - - /* we listen passively to catch the signals we are raising in - * ike_sa->delete(). */ - if (callback) - { - charon->bus->add_listener(charon->bus, &listener.listener); - } - charon->bus->set_listen_state(charon->bus, TRUE); - if (ike_sa->initiate(ike_sa, child_cfg) != SUCCESS) - { - charon->bus->set_listen_state(charon->bus, FALSE); - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - return FAILED; - } - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - - if (callback == NULL) + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + listener->id, FALSE); + if (ike_sa == NULL) { - /* don't wait for a result if no callback is specified */ - charon->bus->set_listen_state(charon->bus, FALSE); - return NEED_MORE; - } + SIG(IKE_DOWN_FAILED, "unable to terminate, IKE_SA with " + "ID %d not found", listener->id); + return NOT_FOUND; + } + listener->ike_sa = ike_sa; - /* wait until we get a result */ - while (TRUE) + if (ike_sa->delete(ike_sa) == DESTROY_ME) { - level_t level; - signal_t signal; - int thread; - ike_sa_t *current; - char* format; - va_list args; - - /* stop listening if the passive listener returned FALSE */ - if (listener.cancelled) - { - retval = NEED_MORE; - break; - } - pthread_cleanup_push((void*)remove_listener, &listener); - signal = charon->bus->listen(charon->bus, &level, &thread, - ¤t, &format, &args); - pthread_cleanup_pop(0); - /* ike_sa is a valid pointer until we get one of the signals */ - if (ike_sa == current) - { - switch (signal) - { - case CHILD_UP_SUCCESS: - retval = SUCCESS; - case CHILD_UP_FAILED: - case IKE_UP_FAILED: - break; - default: - continue; - } - break; - } + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - charon->bus->set_listen_state(charon->bus, FALSE); - return retval; + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } /** @@ -343,107 +281,78 @@ static status_t initiate(private_interface_manager_t *this, static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id, interface_manager_cb_t callback, void *param) { - ike_sa_t *ike_sa; - status_t status = FAILED;; - interface_bus_listener_t listener; + interface_job_t job; - ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - unique_id, FALSE); - if (ike_sa == NULL) - { - return NOT_FOUND; - } - - /* we listen passively to catch the signals we are raising in - * ike_sa->delete(). */ - listener.listener.signal = (void*)terminate_ike_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - if (callback) - { - charon->bus->add_listener(charon->bus, &listener.listener); - } - charon->bus->set_listen_state(charon->bus, TRUE); - status = ike_sa->delete(ike_sa); - if (status == DESTROY_ME) + job.listener.public.signal = (void*)terminate_ike_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = unique_id; + job.public.execute = (void*)terminate_ike_execute; + job.public.destroy = nop; + + if (callback == NULL) { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + return terminate_ike_execute(&job); } - else + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} +/** + * listener function for terminate_child + */ +static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - - /* wait until IKE_SA is cleanly deleted using a delete message */ - while (TRUE) + if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - level_t level; - signal_t signal; - int thread; - ike_sa_t *current; - char* format; - va_list args; - - /* stop listening if the passive listener returned FALSE */ - if (listener.cancelled) - { - status = NEED_MORE; - break; - } - pthread_cleanup_push((void*)remove_listener, &listener); - signal = charon->bus->listen(charon->bus, &level, &thread, - ¤t, &format, &args); - pthread_cleanup_pop(0); - - /* even if we checked in the IKE_SA, the pointer is valid until - * we get an IKE_DOWN_... */ - if (ike_sa == current) - { - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - { - status = SUCCESS; - break; - } - default: - continue; - } + return FALSE; + } + switch (signal) + { + case CHILD_DOWN_SUCCESS: + case IKE_DOWN_SUCCESS: + this->status = SUCCESS; + return FALSE; + case IKE_DOWN_FAILED: + case CHILD_DOWN_FAILED: + return FALSE; + default: break; - } } } - charon->bus->set_listen_state(charon->bus, FALSE); - - return status; + return TRUE; } /** - * Implementation of interface_manager_t.terminate_child. + * execute function for terminate_child */ -static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param) +static status_t terminate_child_execute(interface_job_t *job) { ike_sa_t *ike_sa; child_sa_t *child_sa; iterator_t *iterator; - status_t status = FAILED; - interface_bus_listener_t listener; + interface_bus_listener_t *listener = &job->listener; ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - reqid, TRUE); + listener->id, TRUE); if (ike_sa == NULL) { + SIG(CHILD_DOWN_FAILED, "unable to terminate, CHILD_SA with " + "ID %d not found", listener->id); return NOT_FOUND; } + listener->ike_sa = ike_sa; iterator = ike_sa->create_child_sa_iterator(ike_sa); while (iterator->iterate(iterator, (void**)&child_sa)) { if (child_sa->get_state(child_sa) != CHILD_ROUTED && - child_sa->get_reqid(child_sa) == reqid) + child_sa->get_reqid(child_sa) == listener->id) { break; } @@ -453,160 +362,203 @@ static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, if (child_sa == NULL) { + SIG(CHILD_DOWN_FAILED, "unable to terminate, established CHILD_SA with " + "ID %d not found", listener->id); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); return NOT_FOUND; } - listener.listener.signal = (void*)terminate_child_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - - /* we listen passively to catch the signals we are raising */ - if (callback) + if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME) { - charon->bus->add_listener(charon->bus, &listener.listener); + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - charon->bus->set_listen_state(charon->bus, TRUE); - status = ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)); - if (status == DESTROY_ME) + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of interface_manager_t.terminate_child. + */ +static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, + interface_manager_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)terminate_child_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = reqid; + job.public.execute = (void*)terminate_child_execute; + job.public.destroy = nop; + + if (callback == NULL) { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + return terminate_child_execute(&job); } - else + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; +} + +/** + * listener function for route + */ +static bool route_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - - /* wait until CHILD_SA is cleanly deleted using a delete message */ - while (TRUE) + if (!this->callback(this->param, signal, level, ike_sa, format, args)) { - level_t level; - signal_t signal; - int thread; - ike_sa_t *current; - char* format; - va_list args; - - /* stop listening if the passive listener returned FALSE */ - if (listener.cancelled) - { - status = NEED_MORE; - break; - } - pthread_cleanup_push((void*)remove_listener, &listener); - signal = charon->bus->listen(charon->bus, &level, &thread, - ¤t, &format, &args); - pthread_cleanup_pop(0); - /* even if we checked in the IKE_SA, the pointer is valid until - * we get an IKE_DOWN_... */ - if (ike_sa == current) - { - switch (signal) - { - case IKE_DOWN_FAILED: - case IKE_DOWN_SUCCESS: - case CHILD_DOWN_FAILED: - case CHILD_DOWN_SUCCESS: - { - status = SUCCESS; - break; - } - default: - continue; - } + return FALSE; + } + switch (signal) + { + case CHILD_ROUTE_SUCCESS: + this->status = SUCCESS; + return FALSE; + case CHILD_ROUTE_FAILED: + return FALSE; + default: break; - } } } - charon->bus->set_listen_state(charon->bus, FALSE); - - return status; + return TRUE; } /** - * Implementation of interface_manager_t.route. + * execute function for route */ -static status_t route(interface_manager_t *this, - peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, - interface_manager_cb_t callback, void *param) +static status_t route_execute(interface_job_t *job) { ike_sa_t *ike_sa; ike_cfg_t *ike_cfg; - status_t status = SUCCESS; + interface_bus_listener_t *listener = &job->listener; + peer_cfg_t *peer_cfg = listener->peer_cfg; ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager, ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg), peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg)); + listener->ike_sa = ike_sa; if (ike_sa->get_peer_cfg(ike_sa) == NULL) { ike_sa->set_peer_cfg(ike_sa, peer_cfg); } - - /* we listen passively only, as routing is done by one thread only */ - if (callback) + if (ike_sa->route(ike_sa, listener->child_cfg) == DESTROY_ME) { - interface_bus_listener_t listener; - - listener.listener.signal = (void*)route_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - charon->bus->add_listener(charon->bus, &listener.listener); + return 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); +} + +/** + * Implementation of interface_manager_t.route. + */ +static status_t route(interface_manager_t *this, + peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, + interface_manager_cb_t callback, void *param) +{ + interface_job_t job; - if (ike_sa->route(ike_sa, child_cfg) != SUCCESS) + job.listener.public.signal = (void*)route_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.peer_cfg = peer_cfg; + job.listener.child_cfg = child_cfg; + job.public.execute = (void*)route_execute; + job.public.destroy = nop; + + if (callback == NULL) { - status = FAILED; + return route_execute(&job); } - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return status; + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; } /** - * Implementation of interface_manager_t.unroute. + * listener function for unroute */ -static status_t unroute(interface_manager_t *this, u_int32_t reqid, - interface_manager_cb_t callback, void *param) +static bool unroute_listener(interface_bus_listener_t *this, signal_t signal, + level_t level, int thread, ike_sa_t *ike_sa, + char* format, va_list args) +{ + if (this->ike_sa == ike_sa) + { + if (!this->callback(this->param, signal, level, ike_sa, format, args)) + { + return FALSE; + } + switch (signal) + { + case CHILD_UNROUTE_SUCCESS: + this->status = SUCCESS; + return FALSE; + case CHILD_UNROUTE_FAILED: + return FALSE; + default: + break; + } + } + return TRUE; +} +/** + * execute function for unroute + */ +static status_t unroute_execute(interface_job_t *job) { ike_sa_t *ike_sa; - status_t status; + interface_bus_listener_t *listener = &job->listener; ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - reqid, TRUE); + listener->id, TRUE); if (ike_sa == NULL) { + SIG(CHILD_DOWN_FAILED, "unable to unroute, CHILD_SA with " + "ID %d not found", listener->id); return NOT_FOUND; } - - /* we listen passively only, as routing is done by one thread only */ - if (callback) + listener->ike_sa = ike_sa; + if (ike_sa->unroute(ike_sa, listener->id) == DESTROY_ME) { - interface_bus_listener_t listener; - - listener.listener.signal = (void*)unroute_listener; - listener.callback = callback; - listener.ike_sa = ike_sa; - listener.param = param; - listener.cancelled = FALSE; - charon->bus->add_listener(charon->bus, &listener.listener); + return charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - status = ike_sa->unroute(ike_sa, reqid); - if (status == DESTROY_ME) - { - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - status = SUCCESS; - } - else + return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); +} + +/** + * Implementation of interface_manager_t.unroute. + */ +static status_t unroute(interface_manager_t *this, u_int32_t reqid, + interface_manager_cb_t callback, void *param) +{ + interface_job_t job; + + job.listener.public.signal = (void*)unroute_listener; + job.listener.ike_sa = NULL; + job.listener.callback = callback; + job.listener.param = param; + job.listener.status = FAILED; + job.listener.id = reqid; + job.public.execute = (void*)unroute_execute; + job.public.destroy = nop; + + if (callback == NULL) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return unroute_execute(&job); } - return status; + charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job); + return job.listener.status; } /** diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c index 66ed423ae..b51d53ebd 100755 --- a/src/charon/control/interfaces/stroke_interface.c +++ b/src/charon/control/interfaces/stroke_interface.c @@ -239,13 +239,13 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) bool other_ca_same =FALSE; host_t *my_host, *other_host, *my_subnet, *other_subnet; host_t *my_vip = NULL, *other_vip = NULL; - linked_list_t *my_groups = linked_list_create(); linked_list_t *other_groups = linked_list_create(); proposal_t *proposal; traffic_selector_t *my_ts, *other_ts; char *interface; bool use_existing = FALSE; iterator_t *iterator; + u_int32_t vendor; pop_string(msg, &msg->add_conn.name); DBG1(DBG_CFG, "received stroke: add connection '%s'", msg->add_conn.name); @@ -262,7 +262,7 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) DBG2(DBG_CFG, " p2p_mediated_by=%s", msg->add_conn.p2p.mediated_by); DBG2(DBG_CFG, " p2p_peerid=%s", msg->add_conn.p2p.peerid); - my_host = msg->add_conn.me.address? + my_host = msg->add_conn.me.address ? host_create_from_string(msg->add_conn.me.address, IKE_PORT) : NULL; if (my_host == NULL) { @@ -365,11 +365,11 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) } } else -#endif /* P2P */ { - // no peer ID supplied, assume right ID + /* no peer ID supplied, assume right ID */ peer_id = other_id->clone(other_id); } +#endif /* P2P */ my_subnet = host_create_from_string(msg->add_conn.me.subnet ? msg->add_conn.me.subnet : msg->add_conn.me.address, IKE_PORT); @@ -544,7 +544,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) && ietfAttr_list_equals(other_groups, peer_cfg->get_groups(peer_cfg)) && peer_cfg->get_ike_version(peer_cfg) == (msg->add_conn.ikev2 ? 2 : 1) && peer_cfg->get_auth_method(peer_cfg) == msg->add_conn.auth_method - && peer_cfg->get_eap_type(peer_cfg) == msg->add_conn.eap_type) + && peer_cfg->get_eap_type(peer_cfg, &vendor) == msg->add_conn.eap_type + && vendor == msg->add_conn.eap_vendor) { DBG1(DBG_CFG, "reusing existing configuration '%s'", peer_cfg->get_name(peer_cfg)); @@ -564,9 +565,8 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) other_host->destroy(other_host); other_id->destroy(other_id); other_ca->destroy(other_ca); - peer_id->destroy(peer_id); + DESTROY_IF(peer_id); DESTROY_IF(mediated_by_cfg); - ietfAttr_list_destroy(my_groups); ietfAttr_list_destroy(other_groups); } else @@ -613,15 +613,25 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) ike_cfg->add_proposal(ike_cfg, proposal); } + u_int32_t rekey = 0, reauth = 0, over, jitter; + + jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100; + over = msg->add_conn.rekey.margin; + if (msg->add_conn.rekey.reauth) + { + reauth = msg->add_conn.rekey.ike_lifetime - over; + } + else + { + rekey = msg->add_conn.rekey.ike_lifetime - over; + } peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1, ike_cfg, my_id, other_id, my_ca, other_ca, other_groups, - msg->add_conn.me.sendcert, - msg->add_conn.auth_method, msg->add_conn.eap_type, - msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime, - msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin, - msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, - msg->add_conn.rekey.reauth, msg->add_conn.mobike, + msg->add_conn.me.sendcert, msg->add_conn.auth_method, + msg->add_conn.eap_type, msg->add_conn.eap_vendor, + msg->add_conn.rekey.tries, rekey, reauth, jitter, over, + msg->add_conn.mobike, msg->add_conn.dpd.delay, msg->add_conn.dpd.action, my_vip, other_vip, msg->add_conn.p2p.mediation, mediated_by_cfg, peer_id); } @@ -1104,9 +1114,8 @@ static void stroke_del_ca(stroke_msg_t *msg, FILE *out) */ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) { - peer_cfg_t *cfg = ike_sa->get_peer_cfg(ike_sa); ike_sa_id_t *id = ike_sa->get_id(ike_sa); - u_int32_t next, now = time(NULL); + u_int32_t rekey, reauth; fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), @@ -1116,21 +1125,26 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) if (all) { - fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s, ", + fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "", id->get_responder_spi(id), id->is_initiator(id) ? "" : "*"); - ike_sa->get_stats(ike_sa, &next); - if (next) + rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME); + reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME); + if (rekey) { - fprintf(out, "%s in %V\n", cfg->use_reauth(cfg) ? - "reauthentication" : "rekeying", &now, &next); + fprintf(out, ", rekeying in %V", &rekey); } - else + if (reauth) { - fprintf(out, "rekeying disabled\n"); + fprintf(out, ", reauthentication in %V", &reauth); } + if (!rekey && !reauth) + { + fprintf(out, ", rekeying disabled"); + } + fprintf(out, "\n"); } } @@ -1188,7 +1202,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) if (rekey) { - fprintf(out, "in %V", &now, &rekey); + fprintf(out, "in %#V", &now, &rekey); } else { @@ -1692,7 +1706,6 @@ static job_requeue_t stroke_process(int *fdp) return JOB_REQUEUE_NONE; } - /** * Implementation of private_stroke_interface_t.stroke_receive. */ diff --git a/src/charon/control/interfaces/xml_interface.c b/src/charon/control/interfaces/xml_interface.c index 02da1064d..aa2a554a0 100644 --- a/src/charon/control/interfaces/xml_interface.c +++ b/src/charon/control/interfaces/xml_interface.c @@ -91,6 +91,9 @@ static void write_id(xmlTextWriterPtr writer, char *element, identification_t *i char *type = ""; while (TRUE) { + case ID_ANY: + type = "any"; + break; case ID_IPV4_ADDR: type = "ipv4"; break; @@ -114,9 +117,6 @@ static void write_id(xmlTextWriterPtr writer, char *element, identification_t *i xmlTextWriterWriteFormatString(writer, "%D", id); break; } - case ID_ANY: - xmlTextWriterWriteAttribute(writer, "type", "any"); - break; default: /* TODO: base64 keyid */ xmlTextWriterWriteAttribute(writer, "type", "keyid"); @@ -146,17 +146,15 @@ static void write_address(xmlTextWriterPtr writer, char *element, host_t *host) } /** - * write a childEnd + * write networks element */ -static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local) +static void write_networks(xmlTextWriterPtr writer, char *element, + linked_list_t *list) { iterator_t *iterator; - linked_list_t *list; traffic_selector_t *ts; - xmlTextWriterWriteFormatElement(writer, "spi", "%lx", - htonl(child->get_spi(child, local))); - xmlTextWriterStartElement(writer, "networks"); - list = child->get_traffic_selectors(child, local); + + xmlTextWriterStartElement(writer, element); iterator = list->create_iterator(list, TRUE); while (iterator->iterate(iterator, (void**)&ts)) { @@ -171,6 +169,19 @@ static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool loca } /** + * write a childEnd + */ +static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool local) +{ + linked_list_t *list; + + xmlTextWriterWriteFormatElement(writer, "spi", "%lx", + htonl(child->get_spi(child, local))); + list = child->get_traffic_selectors(child, local); + write_networks(writer, "networks", list); +} + +/** * write a child_sa_t */ static void write_child(xmlTextWriterPtr writer, child_sa_t *child) @@ -284,6 +295,201 @@ static void request_query_ikesa(xmlTextReaderPtr reader, xmlTextWriterPtr writer } /** + * process a configlist query request message + */ +static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + iterator_t *iterator; + peer_cfg_t *peer_cfg; + + /* <configlist> */ + xmlTextWriterStartElement(writer, "configlist"); + + iterator = charon->backends->create_iterator(charon->backends); + while (iterator->iterate(iterator, (void**)&peer_cfg)) + { + iterator_t *children; + child_cfg_t *child_cfg; + ike_cfg_t *ike_cfg; + linked_list_t *list; + + if (peer_cfg->get_ike_version(peer_cfg) != 2) + { /* only IKEv2 connections yet */ + continue; + } + + /* <peerconfig> */ + xmlTextWriterStartElement(writer, "peerconfig"); + xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg)); + write_id(writer, "local", peer_cfg->get_my_id(peer_cfg)); + write_id(writer, "remote", peer_cfg->get_other_id(peer_cfg)); + + /* <ikeconfig> */ + ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); + xmlTextWriterStartElement(writer, "ikeconfig"); + write_address(writer, "local", ike_cfg->get_my_host(ike_cfg)); + write_address(writer, "remote", ike_cfg->get_other_host(ike_cfg)); + xmlTextWriterEndElement(writer); + /* </ikeconfig> */ + + /* <childconfiglist> */ + xmlTextWriterStartElement(writer, "childconfiglist"); + children = peer_cfg->create_child_cfg_iterator(peer_cfg); + while (children->iterate(children, (void**)&child_cfg)) + { + /* <childconfig> */ + xmlTextWriterStartElement(writer, "childconfig"); + xmlTextWriterWriteElement(writer, "name", + child_cfg->get_name(child_cfg)); + list = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + write_networks(writer, "local", list); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + list = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, NULL); + write_networks(writer, "remote", list); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + xmlTextWriterEndElement(writer); + /* </childconfig> */ + } + children->destroy(children); + /* </childconfiglist> */ + xmlTextWriterEndElement(writer); + /* </peerconfig> */ + xmlTextWriterEndElement(writer); + } + iterator->destroy(iterator); + /* </configlist> */ + xmlTextWriterEndElement(writer); +} + +/** + * callback which logs to a XML writer + */ +static bool xml_callback(xmlTextWriterPtr writer, signal_t signal, level_t level, + ike_sa_t* ike_sa, char* format, va_list args) +{ + if (level <= 1) + { + /* <item> */ + xmlTextWriterStartElement(writer, "item"); + xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level); + xmlTextWriterWriteFormatAttribute(writer, "source", "%N", signal_names, signal); + xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", pthread_self()); + xmlTextWriterWriteVFormatString(writer, format, args); + xmlTextWriterEndElement(writer); + /* </item> */ + } + return TRUE; +} + +/** + * process a *terminate control request message + */ +static void request_control_terminate(xmlTextReaderPtr reader, + xmlTextWriterPtr writer, bool ike) +{ + if (xmlTextReaderRead(reader) && + xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) + { + const char *str; + u_int32_t id; + status_t status; + + str = xmlTextReaderConstValue(reader); + if (str == NULL || !(id = atoi(str))) + { + DBG1(DBG_CFG, "error parsing XML id string"); + return; + } + DBG1(DBG_CFG, "terminating %s_SA %d", ike ? "IKE" : "CHILD", id); + + /* <log> */ + xmlTextWriterStartElement(writer, "log"); + if (ike) + { + status = charon->interfaces->terminate_ike( + charon->interfaces, id, + (interface_manager_cb_t)xml_callback, writer); + } + else + { + status = charon->interfaces->terminate_child( + charon->interfaces, id, + (interface_manager_cb_t)xml_callback, writer); + } + /* </log> */ + xmlTextWriterEndElement(writer); + xmlTextWriterWriteFormatElement(writer, "status", "%d", status); + } +} + +/** + * process a *initiate control request message + */ +static void request_control_initiate(xmlTextReaderPtr reader, + xmlTextWriterPtr writer, bool ike) +{ + if (xmlTextReaderRead(reader) && + xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) + { + const char *str; + status_t status = FAILED; + peer_cfg_t *peer; + child_cfg_t *child = NULL; + iterator_t *iterator; + + str = xmlTextReaderConstValue(reader); + if (str == NULL) + { + DBG1(DBG_CFG, "error parsing XML config name string"); + return; + } + DBG1(DBG_CFG, "initiating %s_SA %s", ike ? "IKE" : "CHILD", str); + + /* <log> */ + xmlTextWriterStartElement(writer, "log"); + peer = charon->backends->get_peer_cfg_by_name(charon->backends, (char*)str); + if (peer) + { + iterator = peer->create_child_cfg_iterator(peer); + if (ike) + { + if (!iterator->iterate(iterator, (void**)&child)) + { + child = NULL; + } + child->get_ref(child); + } + else + { + while (iterator->iterate(iterator, (void**)&child)) + { + if (streq(child->get_name(child), str)) + { + child->get_ref(child); + break; + } + child = NULL; + } + } + iterator->destroy(iterator); + if (child) + { + status = charon->interfaces->initiate(charon->interfaces, + peer, child, (interface_manager_cb_t)xml_callback, + writer); + } + else + { + peer->destroy(peer); + } + } + /* </log> */ + xmlTextWriterEndElement(writer); + xmlTextWriterWriteFormatElement(writer, "status", "%d", status); + } +} + +/** * process a query request */ static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) @@ -299,6 +505,11 @@ static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) request_query_ikesa(reader, writer); break; } + if (streq(xmlTextReaderConstName(reader), "configlist")) + { + request_query_config(reader, writer); + break; + } } } /* </query> */ @@ -306,6 +517,43 @@ static void request_query(xmlTextReaderPtr reader, xmlTextWriterPtr writer) } /** + * process a control request + */ +static void request_control(xmlTextReaderPtr reader, xmlTextWriterPtr writer) +{ + /* <control> */ + xmlTextWriterStartElement(writer, "control"); + while (xmlTextReaderRead(reader)) + { + if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) + { + if (streq(xmlTextReaderConstName(reader), "ikesaterminate")) + { + request_control_terminate(reader, writer, TRUE); + break; + } + if (streq(xmlTextReaderConstName(reader), "childsaterminate")) + { + request_control_terminate(reader, writer, FALSE); + break; + } + if (streq(xmlTextReaderConstName(reader), "ikesainitiate")) + { + request_control_initiate(reader, writer, TRUE); + break; + } + if (streq(xmlTextReaderConstName(reader), "childsainitiate")) + { + request_control_initiate(reader, writer, FALSE); + break; + } + } + } + /* </control> */ + xmlTextWriterEndElement(writer); +} + +/** * process a request message */ static void request(xmlTextReaderPtr reader, char *id, int fd) @@ -337,6 +585,11 @@ static void request(xmlTextReaderPtr reader, char *id, int fd) request_query(reader, writer); break; } + if (streq(xmlTextReaderConstName(reader), "control")) + { + request_control(reader, writer); + break; + } } } /* </message> and close document */ |