diff options
Diffstat (limited to 'src/libhydra/kernel/kernel_interface.c')
-rw-r--r-- | src/libhydra/kernel/kernel_interface.c | 223 |
1 files changed, 209 insertions, 14 deletions
diff --git a/src/libhydra/kernel/kernel_interface.c b/src/libhydra/kernel/kernel_interface.c index 573557506..5320ee2e9 100644 --- a/src/libhydra/kernel/kernel_interface.c +++ b/src/libhydra/kernel/kernel_interface.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG @@ -15,14 +15,65 @@ * for more details. */ +/* + * Copyright (c) 2012 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + #include "kernel_interface.h" +#include <hydra.h> #include <debug.h> #include <threading/mutex.h> #include <utils/linked_list.h> typedef struct private_kernel_interface_t private_kernel_interface_t; +typedef struct kernel_algorithm_t kernel_algorithm_t; + +/** + * Mapping of IKE algorithms to kernel-specific algorithm identifiers + */ +struct kernel_algorithm_t { + + /** + * Transform type of the algorithm + */ + transform_type_t type; + + /** + * Identifier specified in IKE + */ + u_int16_t ike; + + /** + * Identifier as defined in pfkeyv2.h + */ + u_int16_t kernel; + + /** + * Name of the algorithm in linux crypto API + */ + char *name; +}; + /** * Private data of a kernel_interface_t object. */ @@ -62,6 +113,28 @@ struct private_kernel_interface_t { * list of registered listeners */ linked_list_t *listeners; + + /** + * mutex for algorithm mappings + */ + mutex_t *mutex_algs; + + /** + * List of algorithm mappings (kernel_algorithm_t*) + */ + linked_list_t *algorithms; + + /** + * List of interface names to include or exclude (char*), NULL if interfaces + * are not filtered + */ + linked_list_t *ifaces_filter; + + /** + * TRUE to exclude interfaces listed in ifaces_filter, FALSE to consider + * only those listed there + */ + bool ifaces_exclude; }; METHOD(kernel_interface_t, get_spi, status_t, @@ -209,35 +282,33 @@ METHOD(kernel_interface_t, get_source_addr, host_t*, } METHOD(kernel_interface_t, get_nexthop, host_t*, - private_kernel_interface_t *this, host_t *dest) + private_kernel_interface_t *this, host_t *dest, host_t *src) { if (!this->net) { return NULL; } - return this->net->get_nexthop(this->net, dest); + return this->net->get_nexthop(this->net, dest, src); } -METHOD(kernel_interface_t, get_interface, char*, - private_kernel_interface_t *this, host_t *host) +METHOD(kernel_interface_t, get_interface, bool, + private_kernel_interface_t *this, host_t *host, char **name) { if (!this->net) { return NULL; } - return this->net->get_interface(this->net, host); + return this->net->get_interface(this->net, host, name); } METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*, - private_kernel_interface_t *this, bool include_down_ifaces, - bool include_virtual_ips) + private_kernel_interface_t *this, kernel_address_type_t which) { if (!this->net) { return enumerator_create_empty(); } - return this->net->create_address_enumerator(this->net, include_down_ifaces, - include_virtual_ips); + return this->net->create_address_enumerator(this->net, which); } METHOD(kernel_interface_t, add_ip, status_t, @@ -294,6 +365,36 @@ METHOD(kernel_interface_t, bypass_socket, bool, return this->ipsec->bypass_socket(this->ipsec, fd, family); } +METHOD(kernel_interface_t, enable_udp_decap, bool, + private_kernel_interface_t *this, int fd, int family, u_int16_t port) +{ + if (!this->ipsec) + { + return FALSE; + } + return this->ipsec->enable_udp_decap(this->ipsec, fd, family, port); +} + +METHOD(kernel_interface_t, is_interface_usable, bool, + private_kernel_interface_t *this, const char *iface) +{ + status_t expected; + + if (!this->ifaces_filter) + { + return TRUE; + } + expected = this->ifaces_exclude ? NOT_FOUND : SUCCESS; + return this->ifaces_filter->find_first(this->ifaces_filter, (void*)streq, + NULL, iface) == expected; +} + +METHOD(kernel_interface_t, all_interfaces_usable, bool, + private_kernel_interface_t *this) +{ + return this->ifaces_filter == NULL; +} + METHOD(kernel_interface_t, get_address_by_ts, status_t, private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip) { @@ -326,7 +427,7 @@ METHOD(kernel_interface_t, get_address_by_ts, status_t, } host->destroy(host); - addrs = create_address_enumerator(this, TRUE, TRUE); + addrs = create_address_enumerator(this, ADDR_TYPE_ALL); while (addrs->enumerate(addrs, (void**)&host)) { if (ts->includes(ts, host)) @@ -362,7 +463,7 @@ METHOD(kernel_interface_t, add_ipsec_interface, void, METHOD(kernel_interface_t, remove_ipsec_interface, void, private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor) { - if (constructor == this->ipsec_constructor) + if (constructor == this->ipsec_constructor && this->ipsec) { this->ipsec->destroy(this->ipsec); this->ipsec = NULL; @@ -382,7 +483,7 @@ METHOD(kernel_interface_t, add_net_interface, void, METHOD(kernel_interface_t, remove_net_interface, void, private_kernel_interface_t *this, kernel_net_constructor_t constructor) { - if (constructor == this->net_constructor) + if (constructor == this->net_constructor && this->net) { this->net->destroy(this->net); this->net = NULL; @@ -500,13 +601,73 @@ METHOD(kernel_interface_t, roam, void, this->mutex->unlock(this->mutex); } +METHOD(kernel_interface_t, register_algorithm, void, + private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type, + u_int16_t kernel_id, char *kernel_name) +{ + kernel_algorithm_t *algorithm; + + INIT(algorithm, + .type = type, + .ike = alg_id, + .kernel = kernel_id, + .name = strdup(kernel_name), + ); + + this->mutex_algs->lock(this->mutex_algs); + this->algorithms->insert_first(this->algorithms, algorithm); + this->mutex_algs->unlock(this->mutex_algs); +} + +METHOD(kernel_interface_t, lookup_algorithm, bool, + private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type, + u_int16_t *kernel_id, char **kernel_name) +{ + kernel_algorithm_t *algorithm; + enumerator_t *enumerator; + bool found = FALSE; + + this->mutex_algs->lock(this->mutex_algs); + enumerator = this->algorithms->create_enumerator(this->algorithms); + while (enumerator->enumerate(enumerator, &algorithm)) + { + if (algorithm->type == type && algorithm->ike == alg_id) + { + if (kernel_id) + { + *kernel_id = algorithm->kernel; + } + if (kernel_name) + { + *kernel_name = algorithm->name; + } + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->mutex_algs->unlock(this->mutex_algs); + return found; +} + METHOD(kernel_interface_t, destroy, void, private_kernel_interface_t *this) { + kernel_algorithm_t *algorithm; + + while (this->algorithms->remove_first(this->algorithms, + (void**)&algorithm) == SUCCESS) + { + free(algorithm->name); + free(algorithm); + } + this->algorithms->destroy(this->algorithms); + this->mutex_algs->destroy(this->mutex_algs); DESTROY_IF(this->ipsec); DESTROY_IF(this->net); - this->mutex->destroy(this->mutex); + DESTROY_FUNCTION_IF(this->ifaces_filter, (void*)free); this->listeners->destroy(this->listeners); + this->mutex->destroy(this->mutex); free(this); } @@ -516,6 +677,7 @@ METHOD(kernel_interface_t, destroy, void, kernel_interface_t *kernel_interface_create() { private_kernel_interface_t *this; + char *ifaces; INIT(this, .public = { @@ -539,7 +701,10 @@ kernel_interface_t *kernel_interface_create() .add_route = _add_route, .del_route = _del_route, .bypass_socket = _bypass_socket, + .enable_udp_decap = _enable_udp_decap, + .is_interface_usable = _is_interface_usable, + .all_interfaces_usable = _all_interfaces_usable, .get_address_by_ts = _get_address_by_ts, .add_ipsec_interface = _add_ipsec_interface, .remove_ipsec_interface = _remove_ipsec_interface, @@ -548,6 +713,8 @@ kernel_interface_t *kernel_interface_create() .add_listener = _add_listener, .remove_listener = _remove_listener, + .register_algorithm = _register_algorithm, + .lookup_algorithm = _lookup_algorithm, .acquire = _acquire, .expire = _expire, .mapping = _mapping, @@ -557,8 +724,36 @@ kernel_interface_t *kernel_interface_create() }, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .listeners = linked_list_create(), + .mutex_algs = mutex_create(MUTEX_TYPE_DEFAULT), + .algorithms = linked_list_create(), ); + ifaces = lib->settings->get_str(lib->settings, + "%s.interfaces_use", NULL, hydra->daemon); + if (!ifaces) + { + this->ifaces_exclude = TRUE; + ifaces = lib->settings->get_str(lib->settings, + "%s.interfaces_ignore", NULL, hydra->daemon); + } + if (ifaces) + { + enumerator_t *enumerator; + char *iface; + + enumerator = enumerator_create_token(ifaces, ",", " "); + while (enumerator->enumerate(enumerator, &iface)) + { + if (!this->ifaces_filter) + { + this->ifaces_filter = linked_list_create(); + } + this->ifaces_filter->insert_last(this->ifaces_filter, + strdup(iface)); + } + enumerator->destroy(enumerator); + } + return &this->public; } |