child_sa_t *child_sa;
/** TRUE in case of wildcard Transport Mode SA */
bool wildcard;
+ /** TRUE for CHILD_SAs that are externally managed */
+ bool external;
} entry_t;
/**
*/
static void destroy_entry(entry_t *this)
{
- this->child_sa->destroy(this->child_sa);
+ if (!this->external)
+ {
+ this->child_sa->destroy(this->child_sa);
+ }
this->peer_cfg->destroy(this->peer_cfg);
free(this->name);
free(this);
return found;
}
+/**
+ * Install the given trap
+ */
+static status_t install_trap(child_sa_t *child_sa, linked_list_t *local,
+ linked_list_t *remote)
+{
+ linked_list_t *my_ts, *other_ts, *proposals;
+ proposal_t *proposal;
+ child_cfg_t *child;
+ protocol_id_t proto = PROTO_ESP;
+
+ child = child_sa->get_config(child_sa);
+
+ my_ts = child->get_traffic_selectors(child, TRUE, NULL, local, FALSE);
+ other_ts = child->get_traffic_selectors(child, FALSE, NULL, remote, FALSE);
+
+ /* we don't know the finally negotiated protocol (ESP|AH), we install
+ * the SA with the protocol of the first proposal */
+ proposals = child->get_proposals(child, TRUE);
+ if (proposals->get_first(proposals, (void**)&proposal) == SUCCESS)
+ {
+ proto = proposal->get_protocol(proposal);
+ }
+ proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
+
+ child_sa->set_protocol(child_sa, proto);
+ child_sa->set_mode(child_sa, child->get_mode(child));
+
+ child_sa->set_policies(child_sa, my_ts, other_ts);
+ my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
+ other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
+
+ return child_sa->install_policies(child_sa);
+}
+
METHOD(trap_manager_t, install, bool,
private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child)
{
ike_cfg_t *ike_cfg;
child_sa_t *child_sa;
host_t *me, *other;
- linked_list_t *my_ts, *other_ts, *list;
+ linked_list_t *local, *remote;
enumerator_t *enumerator;
status_t status;
- linked_list_t *proposals;
- proposal_t *proposal;
- protocol_id_t proto = PROTO_ESP;
bool result = FALSE, wildcard = FALSE;
/* try to resolve addresses */
enumerator = this->traps->create_enumerator(this->traps);
while (enumerator->enumerate(enumerator, &entry))
{
- if (streq(entry->name, child->get_name(child)) &&
+ if (!entry->external &&
+ streq(entry->name, child->get_name(child)) &&
streq(entry->peer_cfg->get_name(entry->peer_cfg),
peer->get_name(peer)))
{
found = entry;
if (entry->child_sa)
- { /* replace it with an updated version, if already installed */
+ { /* replace it with an updated version if already installed */
this->traps->remove_at(this->traps, enumerator);
}
break;
};
child_sa = child_sa_create(me, other, child, &child_data);
- list = linked_list_create_with_items(me, NULL);
- my_ts = child->get_traffic_selectors(child, TRUE, NULL, list, FALSE);
- list->destroy_offset(list, offsetof(host_t, destroy));
+ local = linked_list_create_with_items(me, NULL);
+ remote = linked_list_create_with_items(other, NULL);
- list = linked_list_create_with_items(other, NULL);
- other_ts = child->get_traffic_selectors(child, FALSE, NULL, list, FALSE);
- list->destroy_offset(list, offsetof(host_t, destroy));
+ status = install_trap(child_sa, local, remote);
- /* We don't know the finally negotiated protocol (ESP|AH), we install
- * the SA with the protocol of the first proposal */
- proposals = child->get_proposals(child, TRUE);
- if (proposals->get_first(proposals, (void**)&proposal) == SUCCESS)
- {
- proto = proposal->get_protocol(proposal);
- }
- proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
- child_sa->set_protocol(child_sa, proto);
- child_sa->set_mode(child_sa, child->get_mode(child));
- child_sa->set_policies(child_sa, my_ts, other_ts);
- status = child_sa->install_policies(child_sa);
- my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
- other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
+ local->destroy_offset(local, offsetof(host_t, destroy));
+ remote->destroy_offset(remote, offsetof(host_t, destroy));
if (status != SUCCESS)
{
DBG1(DBG_CFG, "installing trap failed");
enumerator = this->traps->create_enumerator(this->traps);
while (enumerator->enumerate(enumerator, &entry))
{
- if (streq(entry->name, child) &&
- (!peer || streq(peer, entry->peer_cfg->get_name(entry->peer_cfg))))
+ if (!entry->external &&
+ streq(entry->name, child) &&
+ (!peer || streq(peer, entry->peer_cfg->get_name(entry->peer_cfg))))
+ {
+ this->traps->remove_at(this->traps, enumerator);
+ found = entry;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ if (!found)
+ {
+ return FALSE;
+ }
+ destroy_entry(found);
+ return TRUE;
+}
+
+METHOD(trap_manager_t, install_external, bool,
+ private_trap_manager_t *this, peer_cfg_t *peer, child_sa_t *child,
+ linked_list_t *local, linked_list_t *remote)
+{
+ entry_t *entry;
+
+ this->lock->write_lock(this->lock);
+ if (this->installing == INSTALL_DISABLED)
+ { /* flush() has been called */
+ this->lock->unlock(this->lock);
+ return FALSE;
+ }
+
+ INIT(entry,
+ .name = strdup(child->get_name(child)),
+ .peer_cfg = peer->get_ref(peer),
+ .child_sa = child,
+ .external = TRUE,
+ );
+ this->traps->insert_first(this->traps, entry);
+ this->lock->unlock(this->lock);
+
+ if (install_trap(child, local, remote) != SUCCESS)
+ {
+ DBG1(DBG_CFG, "installing trap failed");
+ this->lock->write_lock(this->lock);
+ this->traps->remove(this->traps, entry, NULL);
+ this->lock->unlock(this->lock);
+ destroy_entry(entry);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+METHOD(trap_manager_t, remove_external, bool,
+ private_trap_manager_t *this, child_sa_t *child)
+{
+ enumerator_t *enumerator;
+ entry_t *entry, *found = NULL;
+
+ this->lock->write_lock(this->lock);
+ enumerator = this->traps->create_enumerator(this->traps);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->external && entry->child_sa == child)
{
this->traps->remove_at(this->traps, enumerator);
found = entry;
while (orig->enumerate(orig, &entry))
{
- if (!entry->child_sa)
- { /* skip entries that are currently being installed */
+ if (!entry->child_sa || entry->external)
+ { /* skip entries that are currently being installed or are managed
+ * externally */
continue;
}
if (peer_cfg)
.public = {
.install = _install,
.uninstall = _uninstall,
+ .install_external = _install_external,
+ .remove_external = _remove_external,
.create_enumerator = _create_enumerator,
.acquire = _acquire,
.flush = _flush,