/* * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "config.h" #include #include typedef struct private_config_t private_config_t; /** * Private data of an config_t object. */ struct private_config_t { /** * Public config_t interface. */ config_t public; /** * List of loaded peer configs */ linked_list_t *configs; }; /** * filter function for ike configs */ static bool ike_filter(void *data, peer_cfg_t **in, ike_cfg_t **out) { *out = (*in)->get_ike_cfg(*in); return TRUE; } METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*, private_config_t *this, host_t *me, host_t *other) { return enumerator_create_filter( this->configs->create_enumerator(this->configs), (void*)ike_filter, NULL, NULL); } METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, private_config_t *this, identification_t *me, identification_t *other) { return this->configs->create_enumerator(this->configs); } METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, private_config_t *this, char *name) { enumerator_t *e1, *e2; peer_cfg_t *current, *found = NULL; child_cfg_t *child; e1 = this->configs->create_enumerator(this->configs); while (e1->enumerate(e1, ¤t)) { e2 = current->create_child_cfg_enumerator(current); while (e2->enumerate(e2, &child)) { if (streq(child->get_name(child), name)) { found = current; found->get_ref(found); break; } } e2->destroy(e2); if (found) { break; } } e1->destroy(e1); return found; } /** * Load IKE config for a given section name */ static ike_cfg_t *load_ike_config(private_config_t *this, settings_t *settings, char *config) { enumerator_t *enumerator; ike_cfg_t *ike_cfg; proposal_t *proposal; char *token; ike_cfg = ike_cfg_create(TRUE, settings->get_bool(settings, "configs.%s.fake_nat", FALSE, config), settings->get_str(settings, "configs.%s.lhost", "%any", config), settings->get_int(settings, "configs.%s.lport", 500, config), settings->get_str(settings, "configs.%s.rhost", "%any", config), settings->get_int(settings, "configs.%s.rport", 500, config)); token = settings->get_str(settings, "configs.%s.proposal", NULL, config); if (token) { enumerator = enumerator_create_token(token, ",", " "); while (enumerator->enumerate(enumerator, &token)) { proposal = proposal_create_from_string(PROTO_IKE, token); if (proposal) { ike_cfg->add_proposal(ike_cfg, proposal); } else { DBG1(DBG_CFG, "parsing proposal '%s' failed, skipped", token); } } enumerator->destroy(enumerator); } else { ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); } return ike_cfg; } /** * Load CHILD config for given section names */ static child_cfg_t *load_child_config(private_config_t *this, settings_t *settings, char *config, char *child) { child_cfg_t *child_cfg; lifetime_cfg_t lifetime = {}; enumerator_t *enumerator; proposal_t *proposal; traffic_selector_t *ts; ipsec_mode_t mode = MODE_TUNNEL; host_t *net; char *token; int bits; u_int32_t tfc; if (settings->get_bool(settings, "configs.%s.%s.transport", FALSE, config, child)) { mode = MODE_TRANSPORT; } tfc = settings->get_int(settings, "configs.%s.%s.tfc_padding", 0, config, child); child_cfg = child_cfg_create(child, &lifetime, NULL, FALSE, mode, ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, 0, 0, NULL, NULL, tfc); token = settings->get_str(settings, "configs.%s.%s.proposal", NULL, config, child); if (token) { enumerator = enumerator_create_token(token, ",", " "); while (enumerator->enumerate(enumerator, &token)) { proposal = proposal_create_from_string(PROTO_ESP, token); if (proposal) { child_cfg->add_proposal(child_cfg, proposal); } else { DBG1(DBG_CFG, "parsing proposal '%s' failed, skipped", token); } } enumerator->destroy(enumerator); } else { child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); } token = settings->get_str(settings, "configs.%s.%s.lts", NULL, config); if (token) { enumerator = enumerator_create_token(token, ",", " "); while (enumerator->enumerate(enumerator, &token)) { net = host_create_from_subnet(token, &bits); if (net) { ts = traffic_selector_create_from_subnet(net, bits, 0, 0); child_cfg->add_traffic_selector(child_cfg, TRUE, ts); } else { DBG1(DBG_CFG, "invalid local ts: %s, skipped", token); } } enumerator->destroy(enumerator); } else { ts = traffic_selector_create_dynamic(0, 0, 65535); child_cfg->add_traffic_selector(child_cfg, TRUE, ts); } token = settings->get_str(settings, "configs.%s.%s.rts", NULL, config); if (token) { enumerator = enumerator_create_token(token, ",", " "); while (enumerator->enumerate(enumerator, &token)) { net = host_create_from_subnet(token, &bits); if (net) { ts = traffic_selector_create_from_subnet(net, bits, 0, 0); child_cfg->add_traffic_selector(child_cfg, FALSE, ts); } else { DBG1(DBG_CFG, "invalid remote ts: %s, skipped", token); } } enumerator->destroy(enumerator); } else { ts = traffic_selector_create_dynamic(0, 0, 65535); child_cfg->add_traffic_selector(child_cfg, FALSE, ts); } return child_cfg; } /** * Load peer config for a given section name */ static peer_cfg_t *load_peer_config(private_config_t *this, settings_t *settings, char *config) { ike_cfg_t *ike_cfg; peer_cfg_t *peer_cfg; auth_cfg_t *auth; child_cfg_t *child_cfg; enumerator_t *enumerator; identification_t *lid, *rid; char *child, *policy; uintptr_t strength; ike_cfg = load_ike_config(this, settings, config); peer_cfg = peer_cfg_create(config, 2, ike_cfg, CERT_ALWAYS_SEND, UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, 0, NULL, NULL, FALSE, NULL, NULL); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); lid = identification_create_from_string( settings->get_str(settings, "configs.%s.lid", "%any", config)); auth->add(auth, AUTH_RULE_IDENTITY, lid); peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); rid = identification_create_from_string( settings->get_str(settings, "configs.%s.rid", "%any", config)); strength = settings->get_int(settings, "configs.%s.rsa_strength", 0); if (strength) { auth->add(auth, AUTH_RULE_RSA_STRENGTH, strength); } strength = settings->get_int(settings, "configs.%s.ecdsa_strength", 0); if (strength) { auth->add(auth, AUTH_RULE_ECDSA_STRENGTH, strength); } policy = settings->get_str(settings, "configs.%s.cert_policy", NULL, config); if (policy) { auth->add(auth, AUTH_RULE_CERT_POLICY, strdup(policy)); } auth->add(auth, AUTH_RULE_IDENTITY, rid); peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); DBG1(DBG_CFG, "loaded config %s: %Y - %Y", config, lid, rid); enumerator = settings->create_section_enumerator(settings, "configs.%s", config); while (enumerator->enumerate(enumerator, &child)) { child_cfg = load_child_config(this, settings, config, child); peer_cfg->add_child_cfg(peer_cfg, child_cfg); } enumerator->destroy(enumerator); return peer_cfg; } METHOD(config_t, load, void, private_config_t *this, settings_t *settings) { enumerator_t *enumerator; char *config; enumerator = settings->create_section_enumerator(settings, "configs"); while (enumerator->enumerate(enumerator, &config)) { this->configs->insert_last(this->configs, load_peer_config(this, settings, config)); } enumerator->destroy(enumerator); } METHOD(config_t, destroy, void, private_config_t *this) { this->configs->destroy_offset(this->configs, offsetof(peer_cfg_t, destroy)); free(this); } /** * See header */ config_t *config_create() { private_config_t *this; INIT(this, .public = { .backend = { .create_ike_cfg_enumerator = _create_ike_cfg_enumerator, .create_peer_cfg_enumerator = _create_peer_cfg_enumerator, .get_peer_cfg_by_name = _get_peer_cfg_by_name, }, .load = _load, .destroy = _destroy, }, .configs = linked_list_create(), ); return &this->public; }