diff options
| author | Martin Willi <martin@revosec.ch> | 2014-03-10 14:21:50 +0100 |
|---|---|---|
| committer | Martin Willi <martin@revosec.ch> | 2014-05-07 14:13:37 +0200 |
| commit | 7de35b7ff6062b5082b4ea92ef92f87ed56153eb (patch) | |
| tree | 2799ed5ba729386880614231ded3e4f8314f8ad1 /src/libcharon/plugins | |
| parent | 96071fdb5567e1896b24d9fa75ec06c97cddf8dd (diff) | |
| download | strongswan-7de35b7ff6062b5082b4ea92ef92f87ed56153eb.tar.bz2 strongswan-7de35b7ff6062b5082b4ea92ef92f87ed56153eb.tar.xz | |
vici: Perform specified start_action on connection load, undo it on unload
Diffstat (limited to 'src/libcharon/plugins')
| -rw-r--r-- | src/libcharon/plugins/vici/vici_config.c | 187 |
1 files changed, 185 insertions, 2 deletions
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c index 6f24378e7..82c691f68 100644 --- a/src/libcharon/plugins/vici/vici_config.c +++ b/src/libcharon/plugins/vici/vici_config.c @@ -20,6 +20,7 @@ #include <daemon.h> #include <threading/rwlock.h> +#include <collections/array.h> #include <collections/linked_list.h> #include <stdio.h> @@ -338,8 +339,10 @@ typedef struct { char* updown; bool hostaccess; bool ipcomp; + bool route; ipsec_mode_t mode; action_t dpd_action; + action_t start_action; u_int32_t reqid; u_int32_t tfc; mark_t mark_in; @@ -1164,6 +1167,7 @@ CALLBACK(child_kv, bool, { "life_packets", parse_uint64, &child->lft.packets.life }, { "rand_packets", parse_uint64, &child->lft.packets.jitter }, { "dpd_action", parse_action, &child->dpd_action }, + { "start_action", parse_action, &child->start_action }, { "ipcomp", parse_bool, &child->ipcomp }, { "inactivity", parse_time, &child->inactivity }, { "reqid", parse_uint32, &child->reqid }, @@ -1258,6 +1262,7 @@ CALLBACK(children_sn, bool, .remote_ts = linked_list_create(), .mode = MODE_TUNNEL, .dpd_action = ACTION_NONE, + .start_action = ACTION_NONE, }; child_cfg_t *cfg; proposal_t *proposal; @@ -1288,7 +1293,7 @@ CALLBACK(children_sn, bool, log_child_data(&child, name); cfg = child_cfg_create(name, &child.lft, child.updown, - child.hostaccess, child.mode, ACTION_NONE, + child.hostaccess, child.mode, child.start_action, child.dpd_action, ACTION_NONE, child.ipcomp, child.inactivity, child.reqid, &child.mark_in, &child.mark_out, child.tfc); @@ -1353,6 +1358,180 @@ CALLBACK(peer_sn, bool, } /** + * Find reqid of an existing CHILD_SA + */ +static u_int32_t find_reqid(child_cfg_t *cfg) +{ + enumerator_t *enumerator, *children; + child_sa_t *child_sa; + ike_sa_t *ike_sa; + u_int32_t reqid; + + reqid = charon->traps->find_reqid(charon->traps, cfg); + if (reqid) + { /* already trapped */ + return reqid; + } + + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); + while (!reqid && enumerator->enumerate(enumerator, &ike_sa)) + { + children = ike_sa->create_child_sa_enumerator(ike_sa); + while (children->enumerate(children, &child_sa)) + { + if (streq(cfg->get_name(cfg), child_sa->get_name(child_sa))) + { + reqid = child_sa->get_reqid(child_sa); + break; + } + } + children->destroy(children); + } + enumerator->destroy(enumerator); + return reqid; +} + +/** + * Perform start actions associated to a child config + */ +static void run_start_action(private_vici_config_t *this, peer_cfg_t *peer_cfg, + child_cfg_t *child_cfg) +{ + switch (child_cfg->get_start_action(child_cfg)) + { + case ACTION_RESTART: + DBG1(DBG_CFG, "initiating '%s'", child_cfg->get_name(child_cfg)); + charon->controller->initiate(charon->controller, + peer_cfg->get_ref(peer_cfg), child_cfg->get_ref(child_cfg), + NULL, NULL, 0); + break; + case ACTION_ROUTE: + DBG1(DBG_CFG, "installing '%s'", child_cfg->get_name(child_cfg)); + switch (child_cfg->get_mode(child_cfg)) + { + case MODE_PASS: + case MODE_DROP: + charon->shunts->install(charon->shunts, child_cfg); + break; + default: + charon->traps->install(charon->traps, peer_cfg, child_cfg, + find_reqid(child_cfg)); + break; + } + break; + default: + break; + } +} + +/** + * Undo start actions associated to a child config + */ +static void clear_start_action(private_vici_config_t *this, + child_cfg_t *child_cfg) +{ + enumerator_t *enumerator, *children; + child_sa_t *child_sa; + ike_sa_t *ike_sa; + u_int32_t reqid = 0, *del; + array_t *reqids = NULL; + char *name; + + name = child_cfg->get_name(child_cfg); + switch (child_cfg->get_start_action(child_cfg)) + { + case ACTION_RESTART: + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + children = ike_sa->create_child_sa_enumerator(ike_sa); + while (children->enumerate(children, &child_sa)) + { + reqid = child_sa->get_reqid(child_sa); + array_insert_create(&reqids, ARRAY_TAIL, &reqid); + } + children->destroy(children); + } + enumerator->destroy(enumerator); + + if (array_count(reqids)) + { + while (array_remove(reqids, ARRAY_HEAD, &del)) + { + DBG1(DBG_CFG, "closing '%s' #%u", name, *del); + charon->controller->terminate_child(charon->controller, + *del, NULL, NULL, 0); + } + array_destroy(reqids); + } + break; + case ACTION_ROUTE: + DBG1(DBG_CFG, "uninstalling '%s'", name); + switch (child_cfg->get_mode(child_cfg)) + { + case MODE_PASS: + case MODE_DROP: + charon->shunts->uninstall(charon->shunts, name); + break; + default: + enumerator = charon->traps->create_enumerator(charon->traps); + while (enumerator->enumerate(enumerator, NULL, &child_sa)) + { + if (streq(name, child_sa->get_name(child_sa))) + { + reqid = child_sa->get_reqid(child_sa); + break; + } + } + enumerator->destroy(enumerator); + if (reqid) + { + charon->traps->uninstall(charon->traps, reqid); + } + break; + } + break; + default: + break; + } +} + +/** + * Run start actions associated to all child configs of a peer config + */ +static void run_start_actions(private_vici_config_t *this, peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + child_cfg_t *child_cfg; + + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (enumerator->enumerate(enumerator, &child_cfg)) + { + run_start_action(this, peer_cfg, child_cfg); + } + enumerator->destroy(enumerator); +} + +/** + * Undo start actions associated to all child configs of a peer config + */ +static void clear_start_actions(private_vici_config_t *this, + peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + child_cfg_t *child_cfg; + + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (enumerator->enumerate(enumerator, &child_cfg)) + { + clear_start_action(this, child_cfg); + } + enumerator->destroy(enumerator); +} + +/** * Replace children of a peer config by a new config */ static void replace_children(private_vici_config_t *this, @@ -1365,6 +1544,7 @@ static void replace_children(private_vici_config_t *this, while (enumerator->enumerate(enumerator, &child)) { to->remove_child_cfg(to, enumerator); + clear_start_action(this, child); child->destroy(child); } enumerator->destroy(enumerator); @@ -1374,6 +1554,7 @@ static void replace_children(private_vici_config_t *this, { from->remove_child_cfg(from, enumerator); to->add_child_cfg(to, child); + run_start_action(this, to, child); } enumerator->destroy(enumerator); } @@ -1409,13 +1590,14 @@ static void merge_config(private_vici_config_t *this, peer_cfg_t *peer_cfg) DBG1(DBG_CFG, "replaced vici connection: %s", peer_cfg->get_name(peer_cfg)); this->conns->remove_at(this->conns, enumerator); + clear_start_actions(this, current); current->destroy(current); this->conns->insert_last(this->conns, peer_cfg); + run_start_actions(this, peer_cfg); } merged = TRUE; break; } - } enumerator->destroy(enumerator); @@ -1423,6 +1605,7 @@ static void merge_config(private_vici_config_t *this, peer_cfg_t *peer_cfg) { DBG1(DBG_CFG, "added vici connection: %s", peer_cfg->get_name(peer_cfg)); this->conns->insert_last(this->conns, peer_cfg); + run_start_actions(this, peer_cfg); } this->lock->unlock(this->lock); |
