/** * @file peer_cfg.c * * @brief Implementation of peer_cfg_t. * */ /* * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * * 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 #include #include "peer_cfg.h" #include #include ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND, "CERT_ALWAYS_SEND", "CERT_SEND_IF_ASKED", "CERT_NEVER_SEND" ); ENUM(dpd_action_names, DPD_NONE, DPD_RESTART, "DPD_NONE", "DPD_CLEAR", "DPD_ROUTE", "DPD_RESTART" ); typedef struct private_peer_cfg_t private_peer_cfg_t; /** * Private data of an peer_cfg_t object */ struct private_peer_cfg_t { /** * Public part */ peer_cfg_t public; /** * Number of references hold by others to this peer_cfg */ refcount_t refcount; /** * Name of the peer_cfg, used to query it */ char *name; /** * IKE version to use for initiation */ u_int ike_version; /** * IKE config associated to this peer config */ ike_cfg_t *ike_cfg; /** * list of child configs associated to this peer config */ linked_list_t *child_cfgs; /** * mutex to lock access to list of child_cfgs */ pthread_mutex_t mutex; /** * id to use to identify us */ identification_t *my_id; /** * allowed id for other */ identification_t *other_id; /** * we have a cert issued by this CA */ identification_t *my_ca; /** * we require the other end to have a cert issued by this CA */ identification_t *other_ca; /** * should we send a certificate */ cert_policy_t cert_policy; /** * Method to use for own authentication data */ auth_method_t auth_method; /** * EAP type to use for peer authentication */ eap_type_t eap_type; /** * number of tries after giving up if peer does not respond */ u_int32_t keyingtries; /** * user reauthentication instead of rekeying */ bool use_reauth; /** * Time before an SA gets invalid */ u_int32_t lifetime; /** * Time before an SA gets rekeyed */ u_int32_t rekeytime; /** * Time, which specifies the range of a random value * substracted from lifetime. */ u_int32_t jitter; /** * What to do with an SA when other peer seams to be dead? */ bool dpd_delay; /** * What to do with CHILDren when other peer seams to be dead? */ bool dpd_action; /** * virtual IP to use locally */ host_t *my_virtual_ip; /** * virtual IP to use remotly */ host_t *other_virtual_ip; }; /** * Implementation of peer_cfg_t.get_name */ static char *get_name(private_peer_cfg_t *this) { return this->name; } /** * Implementation of peer_cfg_t.get_ike_version */ static u_int get_ike_version(private_peer_cfg_t *this) { return this->ike_version; } /** * Implementation of peer_cfg_t.get_ike_cfg */ static ike_cfg_t* get_ike_cfg(private_peer_cfg_t *this) { return this->ike_cfg; } /** * Implementation of peer_cfg_t.add_child_cfg. */ static void add_child_cfg(private_peer_cfg_t *this, child_cfg_t *child_cfg) { pthread_mutex_lock(&this->mutex); this->child_cfgs->insert_last(this->child_cfgs, child_cfg); pthread_mutex_unlock(&this->mutex); } /** * Implementation of peer_cfg_t.create_child_cfg_iterator. */ static iterator_t* create_child_cfg_iterator(private_peer_cfg_t *this) { return this->child_cfgs->create_iterator_locked(this->child_cfgs, &this->mutex); } /** * Check if child_cfg contains traffic selectors */ static bool contains_ts(child_cfg_t *child, bool mine, linked_list_t *ts, host_t *host) { linked_list_t *selected; bool contains = FALSE; selected = child->get_traffic_selectors(child, mine, ts, host); contains = selected->get_count(selected); selected->destroy_offset(selected, offsetof(traffic_selector_t, destroy)); return contains; } /** * Implementation of peer_cfg_t.select_child_cfg */ static child_cfg_t* select_child_cfg(private_peer_cfg_t *this, linked_list_t *my_ts, linked_list_t *other_ts, host_t *my_host, host_t *other_host) { child_cfg_t *current, *found = NULL; iterator_t *iterator; iterator = create_child_cfg_iterator(this); while (iterator->iterate(iterator, (void**)¤t)) { if (contains_ts(current, TRUE, my_ts, my_host) && contains_ts(current, FALSE, other_ts, other_host)) { found = current; found->get_ref(found); break; } } iterator->destroy(iterator); return found; } /** * Implementation of peer_cfg_t.get_my_id */ static identification_t *get_my_id(private_peer_cfg_t *this) { return this->my_id; } /** * Implementation of peer_cfg_t.get_other_id */ static identification_t *get_other_id(private_peer_cfg_t *this) { return this->other_id; } /** * Implementation of peer_cfg_t.get_my_ca */ static identification_t *get_my_ca(private_peer_cfg_t *this) { return this->my_ca; } static identification_t *get_other_ca(private_peer_cfg_t *this) { return this->other_ca; } /** * Implementation of peer_cfg_t.get_cert_policy. */ static cert_policy_t get_cert_policy(private_peer_cfg_t *this) { return this->cert_policy; } /** * Implementation of connection_t.auth_method_t. */ static auth_method_t get_auth_method(private_peer_cfg_t *this) { return this->auth_method; } /** * Implementation of connection_t.get_eap_type. */ static eap_type_t get_eap_type(private_peer_cfg_t *this) { return this->eap_type; } /** * Implementation of connection_t.get_keyingtries. */ static u_int32_t get_keyingtries(private_peer_cfg_t *this) { return this->keyingtries; } /** * Implementation of peer_cfg_t.get_soft_lifetime */ static u_int32_t get_lifetime(private_peer_cfg_t *this, bool rekey) { if (rekey) { if (this->jitter == 0) { return this->rekeytime; } return this->rekeytime - (random() % this->jitter); } return this->lifetime; } /** * Implementation of peer_cfg_t.use_reauth. */ static bool use_reauth(private_peer_cfg_t *this, bool rekey) { return this->use_reauth; } /** * Implements peer_cfg_t.get_dpd_delay */ static u_int32_t get_dpd_delay(private_peer_cfg_t *this) { return this->dpd_delay; } /** * Implements peer_cfg_t.get_dpd_action */ static dpd_action_t get_dpd_action(private_peer_cfg_t *this) { return this->dpd_action; } /** * Implementation of peer_cfg_t.get_my_virtual_ip. */ static host_t* get_my_virtual_ip(private_peer_cfg_t *this) { if (this->my_virtual_ip == NULL) { return NULL; } return this->my_virtual_ip->clone(this->my_virtual_ip); } /** * Implementation of peer_cfg_t.get_other_virtual_ip. */ static host_t* get_other_virtual_ip(private_peer_cfg_t *this, host_t *suggestion) { if (this->other_virtual_ip == NULL) { /* disallow */ return NULL; } if (!this->other_virtual_ip->is_anyaddr(this->other_virtual_ip)) { /* force own configuration */ return this->other_virtual_ip->clone(this->other_virtual_ip); } if (suggestion == NULL || suggestion->is_anyaddr(suggestion)) { return NULL; } return suggestion->clone(suggestion); } /** * Implements peer_cfg_t.get_ref. */ static void get_ref(private_peer_cfg_t *this) { ref_get(&this->refcount); } /** * Implements peer_cfg_t.destroy. */ static void destroy(private_peer_cfg_t *this) { if (ref_put(&this->refcount)) { this->ike_cfg->destroy(this->ike_cfg); this->child_cfgs->destroy_offset(this->child_cfgs, offsetof(child_cfg_t, destroy)); this->my_id->destroy(this->my_id); this->other_id->destroy(this->other_id); DESTROY_IF(this->my_ca); DESTROY_IF(this->other_ca); DESTROY_IF(this->my_virtual_ip); DESTROY_IF(this->other_virtual_ip); free(this->name); free(this); } } /* * Described in header-file */ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, identification_t *my_id, identification_t *other_id, identification_t *my_ca, identification_t *other_ca, cert_policy_t cert_policy, auth_method_t auth_method, eap_type_t eap_type, u_int32_t keyingtries, u_int32_t lifetime, u_int32_t rekeytime, u_int32_t jitter, bool reauth, u_int32_t dpd_delay, dpd_action_t dpd_action, host_t *my_virtual_ip, host_t *other_virtual_ip) { private_peer_cfg_t *this = malloc_thing(private_peer_cfg_t); /* public functions */ this->public.get_name = (char* (*) (peer_cfg_t *))get_name; this->public.get_ike_version = (u_int(*) (peer_cfg_t *))get_ike_version; this->public.get_ike_cfg = (ike_cfg_t* (*) (peer_cfg_t *))get_ike_cfg; this->public.add_child_cfg = (void (*) (peer_cfg_t *, child_cfg_t*))add_child_cfg; this->public.create_child_cfg_iterator = (iterator_t* (*) (peer_cfg_t *))create_child_cfg_iterator; this->public.select_child_cfg = (child_cfg_t* (*) (peer_cfg_t *,linked_list_t*,linked_list_t*,host_t*,host_t*))select_child_cfg; this->public.get_my_id = (identification_t* (*)(peer_cfg_t*))get_my_id; this->public.get_other_id = (identification_t* (*)(peer_cfg_t *))get_other_id; this->public.get_my_ca = (identification_t* (*)(peer_cfg_t *))get_my_ca; this->public.get_other_ca = (identification_t* (*)(peer_cfg_t *))get_other_ca; this->public.get_cert_policy = (cert_policy_t (*) (peer_cfg_t *))get_cert_policy; this->public.get_auth_method = (auth_method_t (*) (peer_cfg_t *))get_auth_method; this->public.get_eap_type = (eap_type_t (*) (peer_cfg_t *))get_eap_type; this->public.get_keyingtries = (u_int32_t (*) (peer_cfg_t *))get_keyingtries; this->public.get_lifetime = (u_int32_t (*) (peer_cfg_t *, bool rekey))get_lifetime; this->public.use_reauth = (bool (*) (peer_cfg_t *))use_reauth; this->public.get_dpd_delay = (u_int32_t (*) (peer_cfg_t *))get_dpd_delay; this->public.get_dpd_action = (dpd_action_t (*) (peer_cfg_t *))get_dpd_action; this->public.get_my_virtual_ip = (host_t* (*) (peer_cfg_t *))get_my_virtual_ip; this->public.get_other_virtual_ip = (host_t* (*) (peer_cfg_t *, host_t *))get_other_virtual_ip; this->public.get_ref = (void(*)(peer_cfg_t *))get_ref; this->public.destroy = (void(*)(peer_cfg_t *))destroy; /* apply init values */ this->name = strdup(name); this->ike_version = ike_version; this->ike_cfg = ike_cfg; this->child_cfgs = linked_list_create(); pthread_mutex_init(&this->mutex, NULL); this->my_id = my_id; this->other_id = other_id; this->my_ca = my_ca; this->other_ca = other_ca; this->cert_policy = cert_policy; this->auth_method = auth_method; this->eap_type = eap_type; this->keyingtries = keyingtries; this->lifetime = lifetime; this->rekeytime = rekeytime; this->jitter = jitter; this->use_reauth = reauth; this->dpd_delay = dpd_delay; this->dpd_action = dpd_action; this->my_virtual_ip = my_virtual_ip; this->other_virtual_ip = other_virtual_ip; this->refcount = 1; return &this->public; }