summaryrefslogtreecommitdiff
path: root/src/charon/control
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/control')
-rw-r--r--src/charon/control/interface_manager.c656
-rwxr-xr-xsrc/charon/control/interfaces/stroke_interface.c61
-rw-r--r--src/charon/control/interfaces/xml_interface.c273
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,
- &current, &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,
- &current, &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,
- &current, &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 */