diff options
-rw-r--r-- | src/charon/control/interface_manager.c | 126 | ||||
-rwxr-xr-x | src/charon/control/interfaces/stroke_interface.c | 68 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 6 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.h | 5 |
4 files changed, 187 insertions, 18 deletions
diff --git a/src/charon/control/interface_manager.c b/src/charon/control/interface_manager.c index 79f412ef7..8d9bdb6ee 100644 --- a/src/charon/control/interface_manager.c +++ b/src/charon/control/interface_manager.c @@ -183,6 +183,62 @@ static bool terminate_child_listener(interface_bus_listener_t *this, signal_t si } /** + * 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) + { + 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 TRUE; +} + +/** + * listener function for unroute + */ +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)) + { + this->cancelled = TRUE; + return FALSE; + } + switch (signal) + { + case CHILD_UNROUTE_SUCCESS: + case CHILD_UNROUTE_FAILED: + { + return FALSE; + } + default: + break; + } + } + return TRUE; +} + +/** * Implementation of interface_manager_t.initiate. */ static status_t initiate(private_interface_manager_t *this, @@ -377,6 +433,7 @@ static status_t terminate_child(interface_manager_t *this, u_int32_t reqid, if (child_sa == NULL) { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); return NOT_FOUND; } @@ -453,7 +510,40 @@ 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) { - return FAILED; + ike_sa_t *ike_sa; + ike_cfg_t *ike_cfg; + status_t status = SUCCESS; + + 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); + } + + /* we listen passively only, as routing is done by one thread only */ + if (callback) + { + 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); + } + + if (ike_sa->route(ike_sa, child_cfg) != SUCCESS) + { + status = FAILED; + } + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return status; } /** @@ -462,7 +552,39 @@ static status_t route(interface_manager_t *this, static status_t unroute(interface_manager_t *this, u_int32_t reqid, interface_manager_cb_t callback, void *param) { - return FAILED; + ike_sa_t *ike_sa; + status_t status; + + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + reqid, TRUE); + if (ike_sa == NULL) + { + return NOT_FOUND; + } + + /* we listen passively only, as routing is done by one thread only */ + if (callback) + { + 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); + } + 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 + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + return status; } /** diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c index 96dcc7651..bbfc6506b 100755 --- a/src/charon/control/interfaces/stroke_interface.c +++ b/src/charon/control/interfaces/stroke_interface.c @@ -755,18 +755,17 @@ static void stroke_initiate(private_stroke_interface_t *this, } /** - * route/unroute a policy (install SPD entries) + * route a policy (install SPD entries) */ static void stroke_route(private_stroke_interface_t *this, - stroke_msg_t *msg, FILE *out, bool route) + stroke_msg_t *msg, FILE *out) { - route_job_t *job; peer_cfg_t *peer_cfg; child_cfg_t *child_cfg; + stroke_log_info_t info; pop_string(msg, &(msg->route.name)); - DBG1(DBG_CFG, "received stroke: %s '%s'", - route ? "route" : "unroute", msg->route.name); + DBG1(DBG_CFG, "received stroke: route '%s'", msg->route.name); peer_cfg = get_peer_cfg_by_name(msg->route.name); if (peer_cfg == NULL) @@ -787,10 +786,57 @@ static void stroke_route(private_stroke_interface_t *this, peer_cfg->destroy(peer_cfg); return; } - fprintf(out, "%s policy '%s'\n", - route ? "routing" : "unrouting", msg->route.name); - job = route_job_create(peer_cfg, child_cfg, route); - charon->job_queue->add(charon->job_queue, (job_t*)job); + + info.out = out; + info.level = msg->output_verbosity; + charon->interfaces->route(charon->interfaces, peer_cfg, child_cfg, + (interface_manager_cb_t)stroke_log, &info); + peer_cfg->destroy(peer_cfg); + child_cfg->destroy(child_cfg); +} + +/** + * unroute a policy + */ +static void stroke_unroute(private_stroke_interface_t *this, + stroke_msg_t *msg, FILE *out) +{ + char *name; + ike_sa_t *ike_sa; + iterator_t *iterator; + stroke_log_info_t info; + + pop_string(msg, &(msg->terminate.name)); + name = msg->terminate.name; + + info.out = out; + info.level = msg->output_verbosity; + + iterator = charon->interfaces->create_ike_sa_iterator(charon->interfaces); + while (iterator->iterate(iterator, (void**)&ike_sa)) + { + child_sa_t *child_sa; + iterator_t *children; + u_int32_t id; + + children = ike_sa->create_child_sa_iterator(ike_sa); + while (children->iterate(children, (void**)&child_sa)) + { + if (child_sa->get_state(child_sa) == CHILD_ROUTED && + streq(name, child_sa->get_name(child_sa))) + { + id = child_sa->get_reqid(child_sa); + children->destroy(children); + iterator->destroy(iterator); + charon->interfaces->unroute(charon->interfaces, id, + (interface_manager_cb_t)stroke_log, &info); + return; + } + } + children->destroy(children); + } + iterator->destroy(iterator); + DBG1(DBG_CFG, "no such SA found"); } /** @@ -1479,10 +1525,10 @@ static void stroke_process(private_stroke_interface_t *this, int strokefd) stroke_initiate(this, msg, out); break; case STR_ROUTE: - stroke_route(this, msg, out, TRUE); + stroke_route(this, msg, out); break; case STR_UNROUTE: - stroke_route(this, msg, out, FALSE); + stroke_unroute(this, msg, out); break; case STR_TERMINATE: stroke_terminate(this, msg, out); diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 16c87bf86..d907f6366 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -935,7 +935,7 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg) /** * Implementation of ike_sa_t.unroute. */ -static status_t unroute(private_ike_sa_t *this, child_cfg_t *child_cfg) +static status_t unroute(private_ike_sa_t *this, u_int32_t reqid) { iterator_t *iterator; child_sa_t *child_sa; @@ -948,7 +948,7 @@ static status_t unroute(private_ike_sa_t *this, child_cfg_t *child_cfg) while (iterator->iterate(iterator, (void**)&child_sa)) { if (child_sa->get_state(child_sa) == CHILD_ROUTED && - streq(child_sa->get_name(child_sa), child_cfg->get_name(child_cfg))) + child_sa->get_reqid(child_sa) == reqid) { iterator->remove(iterator); SIG(CHILD_UNROUTE_SUCCESS, "CHILD_SA unrouted"); @@ -1873,7 +1873,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message; this->public.initiate = (status_t(*)(ike_sa_t*,child_cfg_t*)) initiate; this->public.route = (status_t(*)(ike_sa_t*,child_cfg_t*)) route; - this->public.unroute = (status_t(*)(ike_sa_t*,child_cfg_t*)) unroute; + this->public.unroute = (status_t(*)(ike_sa_t*,u_int32_t)) unroute; this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire; this->public.get_ike_cfg = (ike_cfg_t*(*)(ike_sa_t*))get_ike_cfg; this->public.set_ike_cfg = (void(*)(ike_sa_t*,ike_cfg_t*))set_ike_cfg; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 0f977c7a4..0f015286e 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -333,12 +333,13 @@ struct ike_sa_t { * @brief Unroute a policy in the kernel previously routed. * * @param this calling object - * @param child_cfg child config to unroute + * @param reqid reqid of CHILD_SA to unroute * @return * - SUCCESS if route removed + * - NOT_FOUND if CHILD_SA not found * - DESTROY_ME if last CHILD_SA was unrouted */ - status_t (*unroute) (ike_sa_t *this, child_cfg_t *child_cfg); + status_t (*unroute) (ike_sa_t *this, u_int32_t reqid); /** * @brief Acquire connection setup for an installed kernel policy. |