Files
strongswan-ext/Source/charon/config/configuration_manager.c
T
2005-12-02 16:09:04 +00:00

562 lines
16 KiB
C

/**
* @file configuration.c
*
* @brief Configuration class used to store IKE_SA-configurations.
*
* Object of this type represents the configuration for all IKE_SA's and their child_sa's.
*
*/
/*
* Copyright (C) 2005 Jan Hutter, Martin Willi
* 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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 <stdlib.h>
#include "configuration_manager.h"
#include <types.h>
#include <daemon.h>
#include <utils/allocator.h>
typedef struct configuration_entry_t configuration_entry_t;
/* A configuration entry combines a configuration name with a init and sa
* configuration represented as init_config_t and sa_config_t objects.
*/
struct configuration_entry_t {
/**
* Configuration name.
*
*/
char *name;
/**
* Configuration for IKE_SA_INIT exchange.
*/
init_config_t *init_config;
/**
* Configuration for all phases after IKE_SA_INIT exchange.
*/
sa_config_t *sa_config;
/**
* Destroys a configuration_entry_t
*
*
* @param this calling object
*/
void (*destroy) (configuration_entry_t *this);
};
static void configuration_entry_destroy (configuration_entry_t *this)
{
allocator_free(this->name);
allocator_free(this);
}
/**
* Creates a configuration_entry_t object
*
* @param name name of the configuration entry (gets copied)
* @param init_config object of type init_config_t
* @param sa_config object of type sa_config_t
*/
configuration_entry_t * configuration_entry_create(char * name, init_config_t * init_config, sa_config_t * sa_config)
{
configuration_entry_t *entry = allocator_alloc_thing(configuration_entry_t);
/* functions */
entry->destroy = configuration_entry_destroy;
/* private data */
entry->init_config = init_config;
entry->sa_config = sa_config;
entry->name = allocator_alloc(strlen(name) + 1);
strcpy(entry->name,name);
return entry;
}
typedef struct private_configuration_manager_t private_configuration_manager_t;
/**
* Private data of an configuration_t object
*/
struct private_configuration_manager_t {
/**
* Public part of configuration manager.
*/
configuration_manager_t public;
/**
* Holding all configurations.
*/
linked_list_t *configurations;
/**
* Holding all init_configs.
*/
linked_list_t *init_configs;
/**
* Holding all init_configs.
*/
linked_list_t *sa_configs;
/**
* Assigned logger object.
*/
logger_t *logger;
/**
* Max number of retransmitted requests.
*/
u_int32_t max_retransmit_count;
/**
* First retransmit timeout in ms.
*/
u_int32_t first_retransmit_timeout;
/**
* Load default configuration
*
*
* @param this calling object
* @param name name for the configuration
* @param init_config init_config_t object
* @param sa_config sa_config_t object
*/
void (*add_new_configuration) (private_configuration_manager_t *this, char *name, init_config_t *init_config, sa_config_t *sa_config);
/**
* Load default configuration
*
*
* @param this calling object
*/
void (*load_default_config) (private_configuration_manager_t *this);
};
/**
* Implementation of private_configuration_manager_t.load_default_config.
*/
static void load_default_config (private_configuration_manager_t *this)
{
init_config_t *init_config1, *init_config2, *init_config3;
ike_proposal_t proposals[2];
child_proposal_t child_proposals[1];
sa_config_t *sa_config1, *sa_config2, *sa_config3;
traffic_selector_t *ts;
init_config1 = init_config_create("0.0.0.0","152.96.193.131",IKEV2_UDP_PORT,IKEV2_UDP_PORT);
init_config2 = init_config_create("0.0.0.0","152.96.193.130",IKEV2_UDP_PORT,IKEV2_UDP_PORT);
init_config3 = init_config_create("0.0.0.0","127.0.0.1",IKEV2_UDP_PORT,IKEV2_UDP_PORT);
ts = traffic_selector_create_from_string(1, TS_IPV4_ADDR_RANGE, "0.0.0.0", 0, "255.255.255.255", 65535);
proposals[0].encryption_algorithm = ENCR_AES_CBC;
proposals[0].encryption_algorithm_key_length = 16;
proposals[0].integrity_algorithm = AUTH_HMAC_MD5_96;
proposals[0].integrity_algorithm_key_length = 16;
proposals[0].pseudo_random_function = PRF_HMAC_MD5;
proposals[0].pseudo_random_function_key_length = 16;
proposals[0].diffie_hellman_group = MODP_1024_BIT;
proposals[1] = proposals[0];
proposals[1].integrity_algorithm = AUTH_HMAC_SHA1_96;
proposals[1].integrity_algorithm_key_length = 20;
proposals[1].pseudo_random_function = PRF_HMAC_SHA1;
proposals[1].pseudo_random_function_key_length = 20;
init_config1->add_proposal(init_config1,1,proposals[0]);
init_config1->add_proposal(init_config1,1,proposals[1]);
init_config2->add_proposal(init_config2,1,proposals[0]);
init_config2->add_proposal(init_config2,1,proposals[1]);
init_config3->add_proposal(init_config3,1,proposals[0]);
init_config3->add_proposal(init_config3,1,proposals[1]);
sa_config1 = sa_config_create(ID_IPV4_ADDR, "152.96.193.130",
ID_IPV4_ADDR, "152.96.193.131",
SHARED_KEY_MESSAGE_INTEGRITY_CODE);
sa_config1->add_traffic_selector_initiator(sa_config1,ts);
sa_config1->add_traffic_selector_responder(sa_config1,ts);
sa_config2 = sa_config_create(ID_IPV4_ADDR, "152.96.193.131",
ID_IPV4_ADDR, "152.96.193.130",
SHARED_KEY_MESSAGE_INTEGRITY_CODE);
sa_config2->add_traffic_selector_initiator(sa_config2,ts);
sa_config2->add_traffic_selector_responder(sa_config2,ts);
sa_config3 = sa_config_create(ID_IPV4_ADDR, "127.0.0.1",
ID_IPV4_ADDR, "127.0.0.1",
SHARED_KEY_MESSAGE_INTEGRITY_CODE);
sa_config3->add_traffic_selector_initiator(sa_config3,ts);
sa_config3->add_traffic_selector_responder(sa_config3,ts);
ts->destroy(ts);
/* ah and esp prop */
child_proposals[0].ah.is_set = TRUE;
child_proposals[0].ah.integrity_algorithm = AUTH_HMAC_MD5_96;
child_proposals[0].ah.integrity_algorithm_key_size = 16;
child_proposals[0].ah.diffie_hellman_group = MODP_1024_BIT;
child_proposals[0].ah.extended_sequence_numbers = NO_EXT_SEQ_NUMBERS;
child_proposals[0].esp.is_set = TRUE;
child_proposals[0].esp.diffie_hellman_group = MODP_1024_BIT;
child_proposals[0].esp.encryption_algorithm = ENCR_AES_CBC;
child_proposals[0].esp.encryption_algorithm_key_size = 16;
child_proposals[0].esp.integrity_algorithm = AUTH_UNDEFINED;
child_proposals[0].esp.extended_sequence_numbers = NO_EXT_SEQ_NUMBERS;
child_proposals[0].esp.spi[0] = 2;
child_proposals[0].esp.spi[1] = 2;
child_proposals[0].esp.spi[2] = 2;
child_proposals[0].esp.spi[3] = 2;
sa_config1->add_proposal(sa_config1, &child_proposals[0]);
sa_config2->add_proposal(sa_config2, &child_proposals[0]);
sa_config3->add_proposal(sa_config3, &child_proposals[0]);
this->add_new_configuration(this,"pinflb31",init_config1,sa_config1);
this->add_new_configuration(this,"pinflb30",init_config2,sa_config2);
this->add_new_configuration(this,"localhost",init_config3,sa_config3);
}
/**
* Implementation of configuration_manager_t.get_init_config_for_host.
*/
static status_t get_init_config_for_host (private_configuration_manager_t *this, host_t *my_host, host_t *other_host,init_config_t **init_config)
{
iterator_t *iterator;
status_t status = NOT_FOUND;
iterator = this->configurations->create_iterator(this->configurations,TRUE);
this->logger->log(this->logger, CONTROL|MORE, "getting config for hosts %s - %s",
my_host->get_address(my_host), other_host->get_address(other_host));
while (iterator->has_next(iterator))
{
configuration_entry_t *entry;
host_t *config_my_host;
host_t *config_other_host;
iterator->current(iterator,(void **) &entry);
config_my_host = entry->init_config->get_my_host(entry->init_config);
config_other_host = entry->init_config->get_other_host(entry->init_config);
/* first check if ip is equal */
if(config_other_host->ip_is_equal(config_other_host,other_host))
{
this->logger->log(this->logger, CONTROL|MOST, "config entry with remote host %s",
config_other_host->get_address(config_other_host));
/* could be right one, check my_host for default route*/
if (config_my_host->is_default_route(config_my_host))
{
printf("is default route\n");
*init_config = entry->init_config;
status = SUCCESS;
break;
}
/* check now if host informations are the same */
else if (config_my_host->ip_is_equal(config_my_host,my_host))
{
*init_config = entry->init_config;
status = SUCCESS;
break;
}
}
/* Then check for wildcard hosts!
* TODO
* actually its only checked if other host with default route can be found! */
else if (config_other_host->is_default_route(config_other_host))
{
/* could be right one, check my_host for default route*/
if (config_my_host->is_default_route(config_my_host))
{
*init_config = entry->init_config;
status = SUCCESS;
break;
}
/* check now if host informations are the same */
else if (config_my_host->ip_is_equal(config_my_host,my_host))
{
*init_config = entry->init_config;
status = SUCCESS;
break;
}
}
}
iterator->destroy(iterator);
return status;
}
/**
* Implementation of configuration_manager_t.get_init_config_for_name.
*/
static status_t get_init_config_for_name (private_configuration_manager_t *this, char *name, init_config_t **init_config)
{
iterator_t *iterator;
status_t status = NOT_FOUND;
iterator = this->configurations->create_iterator(this->configurations,TRUE);
while (iterator->has_next(iterator))
{
configuration_entry_t *entry;
iterator->current(iterator,(void **) &entry);
if (strcmp(entry->name,name) == 0)
{
/* found configuration */
*init_config = entry->init_config;
status = SUCCESS;
break;
}
}
iterator->destroy(iterator);
return status;
}
/**
* Implementation of configuration_manager_t.get_sa_config_for_name.
*/
static status_t get_sa_config_for_name (private_configuration_manager_t *this, char *name, sa_config_t **sa_config)
{
iterator_t *iterator;
status_t status = NOT_FOUND;
iterator = this->configurations->create_iterator(this->configurations,TRUE);
while (iterator->has_next(iterator))
{
configuration_entry_t *entry;
iterator->current(iterator,(void **) &entry);
if (strcmp(entry->name,name) == 0)
{
/* found configuration */
*sa_config = entry->sa_config;
status = SUCCESS;
break;
}
}
iterator->destroy(iterator);
return status;
}
/**
* Implementation of configuration_manager_t.get_sa_config_for_init_config_and_id.
*/
static status_t get_sa_config_for_init_config_and_id (private_configuration_manager_t *this, init_config_t *init_config, identification_t *other_id, identification_t *my_id,sa_config_t **sa_config)
{
iterator_t *iterator;
status_t status = NOT_FOUND;
iterator = this->configurations->create_iterator(this->configurations,TRUE);
while (iterator->has_next(iterator))
{
configuration_entry_t *entry;
iterator->current(iterator,(void **) &entry);
if (entry->init_config == init_config)
{
identification_t *config_my_id = entry->sa_config->get_my_id(entry->sa_config);
identification_t *config_other_id = entry->sa_config->get_other_id(entry->sa_config);
/* host informations seem to be the same */
if (config_other_id->equals(config_other_id,other_id))
{
/* other ids seems to match */
if (my_id == NULL)
{
/* first matching one is selected */
/* TODO priorize found entries */
*sa_config = entry->sa_config;
status = SUCCESS;
break;
}
if (config_my_id->equals(config_my_id,my_id))
{
*sa_config = entry->sa_config;
status = SUCCESS;
break;
}
}
}
}
iterator->destroy(iterator);
return status;
}
/**
* Implementation of private_configuration_manager_t.add_new_configuration.
*/
static void add_new_configuration (private_configuration_manager_t *this, char *name, init_config_t *init_config, sa_config_t *sa_config)
{
iterator_t *iterator;
bool found;
iterator = this->init_configs->create_iterator(this->init_configs,TRUE);
found = FALSE;
while (iterator->has_next(iterator))
{
init_config_t *found_init_config;
iterator->current(iterator,(void **) &found_init_config);
if (init_config == found_init_config)
{
found = TRUE;
break;
}
}
iterator->destroy(iterator);
if (!found)
{
this->init_configs->insert_first(this->init_configs,init_config);
}
iterator = this->sa_configs->create_iterator(this->sa_configs,TRUE);
found = FALSE;
while (iterator->has_next(iterator))
{
sa_config_t *found_sa_config;
iterator->current(iterator,(void **) &found_sa_config);
if (sa_config == found_sa_config)
{
found = TRUE;
break;
}
}
iterator->destroy(iterator);
if (!found)
{
this->sa_configs->insert_first(this->sa_configs,sa_config);
}
this->configurations->insert_first(this->configurations,configuration_entry_create(name,init_config,sa_config));
}
static status_t get_retransmit_timeout (private_configuration_manager_t *this, u_int32_t retransmit_count, u_int32_t *timeout)
{
if ((retransmit_count > this->max_retransmit_count) && (this->max_retransmit_count != 0))
{
return FAILED;
}
/**
* TODO implement a good retransmit policy
*/
*timeout = this->first_retransmit_timeout * (retransmit_count + 1);
return SUCCESS;
}
/**
* Implementation of configuration_manager_t.destroy.
*/
static void destroy(private_configuration_manager_t *this)
{
this->logger->log(this->logger,CONTROL | MORE, "Going to destroy configuration manager ");
while (this->configurations->get_count(this->configurations) > 0)
{
configuration_entry_t *entry;
this->configurations->remove_first(this->configurations,(void **) &entry);
entry->destroy(entry);
}
/* todo delete all config objects */
this->configurations->destroy(this->configurations);
while (this->sa_configs->get_count(this->sa_configs) > 0)
{
sa_config_t *sa_config;
this->sa_configs->remove_first(this->sa_configs,(void **) &sa_config);
sa_config->destroy(sa_config);
}
this->sa_configs->destroy(this->sa_configs);
while (this->init_configs->get_count(this->init_configs) > 0)
{
init_config_t *init_config;
this->init_configs->remove_first(this->init_configs,(void **) &init_config);
init_config->destroy(init_config);
}
this->init_configs->destroy(this->init_configs);
this->logger->log(this->logger,CONTROL | MOST, "Destroy assigned logger");
charon->logger_manager->destroy_logger(charon->logger_manager,this->logger);
allocator_free(this);
}
/*
* Described in header-file
*/
configuration_manager_t *configuration_manager_create(u_int32_t first_retransmit_timeout,u_int32_t max_retransmit_count)
{
private_configuration_manager_t *this = allocator_alloc_thing(private_configuration_manager_t);
/* public functions */
this->public.destroy = (void(*)(configuration_manager_t*))destroy;
this->public.get_init_config_for_name = (status_t (*) (configuration_manager_t *, char *, init_config_t **)) get_init_config_for_name;
this->public.get_init_config_for_host = (status_t (*) (configuration_manager_t *, host_t *, host_t *,init_config_t **)) get_init_config_for_host;
this->public.get_sa_config_for_name =(status_t (*) (configuration_manager_t *, char *, sa_config_t **)) get_sa_config_for_name;
this->public.get_sa_config_for_init_config_and_id =(status_t (*) (configuration_manager_t *, init_config_t *, identification_t *, identification_t *,sa_config_t **)) get_sa_config_for_init_config_and_id;
this->public.get_retransmit_timeout = (status_t (*) (configuration_manager_t *, u_int32_t retransmit_count, u_int32_t *timeout))get_retransmit_timeout;
/* private functions */
this->load_default_config = load_default_config;
this->add_new_configuration = add_new_configuration;
/* private variables */
this->logger = charon->logger_manager->create_logger(charon->logger_manager,CONFIGURATION_MANAGER,NULL);
this->configurations = linked_list_create();
this->sa_configs = linked_list_create();
this->init_configs = linked_list_create();
this->max_retransmit_count = max_retransmit_count;
this->first_retransmit_timeout = first_retransmit_timeout;
this->load_default_config(this);
return (&this->public);
}