diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-11-28 12:11:49 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-11-28 12:11:49 +0000 |
commit | 7b8b352039efd78338a7bf451a0550644ec8a8da (patch) | |
tree | 62e0548df49dfb3ddacc8cac4309fa10f7b42610 /src/libhydra/kernel | |
parent | 9587b8e553eda7b1b6fd48c77ebe4592e1e3532a (diff) | |
download | vyos-strongswan-7b8b352039efd78338a7bf451a0550644ec8a8da.tar.gz vyos-strongswan-7b8b352039efd78338a7bf451a0550644ec8a8da.zip |
New upstream version.
Diffstat (limited to 'src/libhydra/kernel')
-rw-r--r-- | src/libhydra/kernel/kernel_interface.c | 522 | ||||
-rw-r--r-- | src/libhydra/kernel/kernel_interface.h | 476 | ||||
-rw-r--r-- | src/libhydra/kernel/kernel_ipsec.c | 37 | ||||
-rw-r--r-- | src/libhydra/kernel/kernel_ipsec.h | 368 | ||||
-rw-r--r-- | src/libhydra/kernel/kernel_listener.h | 96 | ||||
-rw-r--r-- | src/libhydra/kernel/kernel_net.h | 145 |
6 files changed, 1644 insertions, 0 deletions
diff --git a/src/libhydra/kernel/kernel_interface.c b/src/libhydra/kernel/kernel_interface.c new file mode 100644 index 000000000..3e6d46205 --- /dev/null +++ b/src/libhydra/kernel/kernel_interface.c @@ -0,0 +1,522 @@ +/* + * Copyright (C) 2008-2010 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * 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 <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 "kernel_interface.h" + +#include <debug.h> +#include <threading/mutex.h> +#include <utils/linked_list.h> + +typedef struct private_kernel_interface_t private_kernel_interface_t; + +/** + * Private data of a kernel_interface_t object. + */ +struct private_kernel_interface_t { + + /** + * Public part of kernel_interface_t object. + */ + kernel_interface_t public; + + /** + * ipsec interface + */ + kernel_ipsec_t *ipsec; + + /** + * network interface + */ + kernel_net_t *net; + + /** + * mutex for listeners + */ + mutex_t *mutex; + + /** + * list of registered listeners + */ + linked_list_t *listeners; +}; + +METHOD(kernel_interface_t, get_spi, status_t, + private_kernel_interface_t *this, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, u_int32_t *spi) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->get_spi(this->ipsec, src, dst, protocol, reqid, spi); +} + +METHOD(kernel_interface_t, get_cpi, status_t, + private_kernel_interface_t *this, host_t *src, host_t *dst, + u_int32_t reqid, u_int16_t *cpi) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->get_cpi(this->ipsec, src, dst, reqid, cpi); +} + +METHOD(kernel_interface_t, add_sa, status_t, + private_kernel_interface_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int32_t reqid, + mark_t mark, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, + u_int16_t cpi, bool encap, bool inbound, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid, + mark, lifetime, enc_alg, enc_key, int_alg, int_key, mode, ipcomp, + cpi, encap, inbound, src_ts, dst_ts); +} + +METHOD(kernel_interface_t, update_sa, status_t, + private_kernel_interface_t *this, u_int32_t spi, u_int8_t protocol, + u_int16_t cpi, host_t *src, host_t *dst, host_t *new_src, host_t *new_dst, + bool encap, bool new_encap, mark_t mark) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->update_sa(this->ipsec, spi, protocol, cpi, src, dst, + new_src, new_dst, encap, new_encap, mark); +} + +METHOD(kernel_interface_t, query_sa, status_t, + private_kernel_interface_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, mark, bytes); +} + +METHOD(kernel_interface_t, del_sa, status_t, + private_kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi, + u_int8_t protocol, u_int16_t cpi, mark_t mark) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->del_sa(this->ipsec, src, dst, spi, protocol, cpi, mark); +} + +METHOD(kernel_interface_t, add_policy, status_t, + private_kernel_interface_t *this, host_t *src, host_t *dst, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, + mark_t mark, bool routed) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts, + direction, type, sa, mark, routed); +} + +METHOD(kernel_interface_t, query_policy, status_t, + private_kernel_interface_t *this, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, + u_int32_t *use_time) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts, + direction, mark, use_time); +} + +METHOD(kernel_interface_t, del_policy, status_t, + private_kernel_interface_t *this, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, + bool unrouted) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts, + direction, mark, unrouted); +} + +METHOD(kernel_interface_t, get_source_addr, host_t*, + private_kernel_interface_t *this, host_t *dest, host_t *src) +{ + if (!this->net) + { + return NULL; + } + return this->net->get_source_addr(this->net, dest, src); +} + +METHOD(kernel_interface_t, get_nexthop, host_t*, + private_kernel_interface_t *this, host_t *dest) +{ + if (!this->net) + { + return NULL; + } + return this->net->get_nexthop(this->net, dest); +} + +METHOD(kernel_interface_t, get_interface, char*, + private_kernel_interface_t *this, host_t *host) +{ + if (!this->net) + { + return NULL; + } + return this->net->get_interface(this->net, host); +} + +METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*, + private_kernel_interface_t *this, bool include_down_ifaces, + bool include_virtual_ips) +{ + if (!this->net) + { + return enumerator_create_empty(); + } + return this->net->create_address_enumerator(this->net, include_down_ifaces, + include_virtual_ips); +} + +METHOD(kernel_interface_t, add_ip, status_t, + private_kernel_interface_t *this, host_t *virtual_ip, host_t *iface_ip) +{ + if (!this->net) + { + return NOT_SUPPORTED; + } + return this->net->add_ip(this->net, virtual_ip, iface_ip); +} + +METHOD(kernel_interface_t, del_ip, status_t, + private_kernel_interface_t *this, host_t *virtual_ip) +{ + if (!this->net) + { + return NOT_SUPPORTED; + } + return this->net->del_ip(this->net, virtual_ip); +} + +METHOD(kernel_interface_t, add_route, status_t, + private_kernel_interface_t *this, chunk_t dst_net, + u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name) +{ + if (!this->net) + { + return NOT_SUPPORTED; + } + return this->net->add_route(this->net, dst_net, prefixlen, gateway, + src_ip, if_name); +} + +METHOD(kernel_interface_t, del_route, status_t, + private_kernel_interface_t *this, chunk_t dst_net, + u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name) +{ + if (!this->net) + { + return NOT_SUPPORTED; + } + return this->net->del_route(this->net, dst_net, prefixlen, gateway, + src_ip, if_name); +} + +METHOD(kernel_interface_t, bypass_socket, bool, + private_kernel_interface_t *this, int fd, int family) +{ + if (!this->ipsec) + { + return FALSE; + } + return this->ipsec->bypass_socket(this->ipsec, fd, family); +} + +METHOD(kernel_interface_t, get_address_by_ts, status_t, + private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip) +{ + enumerator_t *addrs; + host_t *host; + int family; + bool found = FALSE; + + DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts); + + /* if we have a family which includes localhost, we do not + * search for an IP, we use the default */ + family = ts->get_type(ts) == TS_IPV4_ADDR_RANGE ? AF_INET : AF_INET6; + + if (family == AF_INET) + { + host = host_create_from_string("127.0.0.1", 0); + } + else + { + host = host_create_from_string("::1", 0); + } + + if (ts->includes(ts, host)) + { + *ip = host_create_any(family); + host->destroy(host); + DBG2(DBG_KNL, "using host %H", *ip); + return SUCCESS; + } + host->destroy(host); + + addrs = create_address_enumerator(this, TRUE, TRUE); + while (addrs->enumerate(addrs, (void**)&host)) + { + if (ts->includes(ts, host)) + { + found = TRUE; + *ip = host->clone(host); + break; + } + } + addrs->destroy(addrs); + + if (!found) + { + DBG1(DBG_KNL, "no local address found in traffic selector %R", ts); + return FAILED; + } + + DBG2(DBG_KNL, "using host %H", *ip); + return SUCCESS; +} + + +METHOD(kernel_interface_t, add_ipsec_interface, void, + private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor) +{ + if (!this->ipsec) + { + this->ipsec = constructor(); + } +} + +METHOD(kernel_interface_t, remove_ipsec_interface, void, + private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor) +{ + /* TODO: replace if interface currently in use */ +} + +METHOD(kernel_interface_t, add_net_interface, void, + private_kernel_interface_t *this, kernel_net_constructor_t constructor) +{ + if (!this->net) + { + this->net = constructor(); + } +} + +METHOD(kernel_interface_t, remove_net_interface, void, + private_kernel_interface_t *this, kernel_net_constructor_t constructor) +{ + /* TODO: replace if interface currently in use */ +} + +METHOD(kernel_interface_t, add_listener, void, + private_kernel_interface_t *this, kernel_listener_t *listener) +{ + this->mutex->lock(this->mutex); + this->listeners->insert_last(this->listeners, listener); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, remove_listener, void, + private_kernel_interface_t *this, kernel_listener_t *listener) +{ + this->mutex->lock(this->mutex); + this->listeners->remove(this->listeners, listener, NULL); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, acquire, void, + private_kernel_interface_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts) +{ + kernel_listener_t *listener; + enumerator_t *enumerator; + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &listener)) + { + if (listener->acquire && + !listener->acquire(listener, reqid, src_ts, dst_ts)) + { + this->listeners->remove_at(this->listeners, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, expire, void, + private_kernel_interface_t *this, u_int32_t reqid, u_int8_t protocol, + u_int32_t spi, bool hard) +{ + kernel_listener_t *listener; + enumerator_t *enumerator; + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &listener)) + { + if (listener->expire && + !listener->expire(listener, reqid, protocol, spi, hard)) + { + this->listeners->remove_at(this->listeners, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, mapping, void, + private_kernel_interface_t *this, u_int32_t reqid, u_int32_t spi, + host_t *remote) +{ + kernel_listener_t *listener; + enumerator_t *enumerator; + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &listener)) + { + if (listener->mapping && + !listener->mapping(listener, reqid, spi, remote)) + { + this->listeners->remove_at(this->listeners, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, migrate, void, + private_kernel_interface_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t direction, host_t *local, host_t *remote) +{ + kernel_listener_t *listener; + enumerator_t *enumerator; + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &listener)) + { + if (listener->migrate && + !listener->migrate(listener, reqid, src_ts, dst_ts, direction, + local, remote)) + { + this->listeners->remove_at(this->listeners, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +static bool call_roam(kernel_listener_t *listener, bool *roam) +{ + return listener->roam && !listener->roam(listener, *roam); +} + +METHOD(kernel_interface_t, roam, void, + private_kernel_interface_t *this, bool address) +{ + this->mutex->lock(this->mutex); + this->listeners->remove(this->listeners, &address, (void*)call_roam); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, destroy, void, + private_kernel_interface_t *this) +{ + DESTROY_IF(this->ipsec); + DESTROY_IF(this->net); + this->mutex->destroy(this->mutex); + this->listeners->destroy(this->listeners); + free(this); +} + +/* + * Described in header-file + */ +kernel_interface_t *kernel_interface_create() +{ + private_kernel_interface_t *this; + + INIT(this, + .public = { + .get_spi = _get_spi, + .get_cpi = _get_cpi, + .add_sa = _add_sa, + .update_sa = _update_sa, + .query_sa = _query_sa, + .del_sa = _del_sa, + .add_policy = _add_policy, + .query_policy = _query_policy, + .del_policy = _del_policy, + .get_source_addr = _get_source_addr, + .get_nexthop = _get_nexthop, + .get_interface = _get_interface, + .create_address_enumerator = _create_address_enumerator, + .add_ip = _add_ip, + .del_ip = _del_ip, + .add_route = _add_route, + .del_route = _del_route, + .bypass_socket = _bypass_socket, + + .get_address_by_ts = _get_address_by_ts, + .add_ipsec_interface = _add_ipsec_interface, + .remove_ipsec_interface = _remove_ipsec_interface, + .add_net_interface = _add_net_interface, + .remove_net_interface = _remove_net_interface, + + .add_listener = _add_listener, + .remove_listener = _remove_listener, + .acquire = _acquire, + .expire = _expire, + .mapping = _mapping, + .migrate = _migrate, + .roam = _roam, + .destroy = _destroy, + }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .listeners = linked_list_create(), + ); + + return &this->public; +} + diff --git a/src/libhydra/kernel/kernel_interface.h b/src/libhydra/kernel/kernel_interface.h new file mode 100644 index 000000000..8b0c7a296 --- /dev/null +++ b/src/libhydra/kernel/kernel_interface.h @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2006-2010 Tobias Brunner + * Copyright (C) 2006 Daniel Roethlisberger + * Copyright (C) 2005-2006 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 <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. + */ + +/** + * @defgroup kernel_interface kernel_interface + * @{ @ingroup hkernel + */ + +#ifndef KERNEL_INTERFACE_H_ +#define KERNEL_INTERFACE_H_ + +typedef struct kernel_interface_t kernel_interface_t; + +#include <utils/host.h> +#include <crypto/prf_plus.h> + +#include <kernel/kernel_listener.h> +#include <kernel/kernel_ipsec.h> +#include <kernel/kernel_net.h> + +/** + * Constructor function for ipsec kernel interface + */ +typedef kernel_ipsec_t* (*kernel_ipsec_constructor_t)(void); + +/** + * Constructor function for network kernel interface + */ +typedef kernel_net_t* (*kernel_net_constructor_t)(void); + +/** + * Manager and wrapper for different kernel interfaces. + * + * The kernel interface handles the communication with the kernel + * for SA and policy management and interface and IP address management. + */ +struct kernel_interface_t { + + /** + * Get a SPI from the kernel. + * + * @param src source address of SA + * @param dst destination address of SA + * @param protocol protocol for SA (ESP/AH) + * @param reqid unique ID for this SA + * @param spi allocated spi + * @return SUCCESS if operation completed + */ + status_t (*get_spi)(kernel_interface_t *this, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, u_int32_t *spi); + + /** + * Get a Compression Parameter Index (CPI) from the kernel. + * + * @param src source address of SA + * @param dst destination address of SA + * @param reqid unique ID for the corresponding SA + * @param cpi allocated cpi + * @return SUCCESS if operation completed + */ + status_t (*get_cpi)(kernel_interface_t *this, host_t *src, host_t *dst, + u_int32_t reqid, u_int16_t *cpi); + + /** + * Add an SA to the SAD. + * + * add_sa() may update an already allocated + * SPI (via get_spi). In this case, the replace + * flag must be set. + * This function does install a single SA for a + * single protocol in one direction. + * + * @param src source address for this SA + * @param dst destination address for this SA + * @param spi SPI allocated by us or remote peer + * @param protocol protocol for this SA (ESP/AH) + * @param reqid unique ID for this SA + * @param mark optional mark for this SA + * @param lifetime lifetime_cfg_t for this SA + * @param enc_alg Algorithm to use for encryption (ESP only) + * @param enc_key key to use for encryption + * @param int_alg Algorithm to use for integrity protection + * @param int_key key to use for integrity protection + * @param mode mode of the SA (tunnel, transport) + * @param ipcomp IPComp transform to use + * @param cpi CPI for IPComp + * @param encap enable UDP encapsulation for NAT traversal + * @param inbound TRUE if this is an inbound SA + * @param src_ts traffic selector with BEET source address + * @param dst_ts traffic selector with BEET destination address + * @return SUCCESS if operation completed + */ + status_t (*add_sa) (kernel_interface_t *this, + host_t *src, host_t *dst, u_int32_t spi, + u_int8_t protocol, u_int32_t reqid, mark_t mark, + lifetime_cfg_t *lifetime, + u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, + ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, + bool encap, bool inbound, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts); + + /** + * Update the hosts on an installed SA. + * + * We cannot directly update the destination address as the kernel + * requires the spi, the protocol AND the destination address (and family) + * to identify SAs. Therefore if the destination address changed we + * create a new SA and delete the old one. + * + * @param spi SPI of the SA + * @param protocol protocol for this SA (ESP/AH) + * @param cpi CPI for IPComp, 0 if no IPComp is used + * @param src current source address + * @param dst current destination address + * @param new_src new source address + * @param new_dst new destination address + * @param encap current use of UDP encapsulation + * @param new_encap new use of UDP encapsulation + * @param mark optional mark for this SA + * @return SUCCESS if operation completed, NOT_SUPPORTED if + * the kernel interface can't update the SA + */ + status_t (*update_sa)(kernel_interface_t *this, + u_int32_t spi, u_int8_t protocol, u_int16_t cpi, + host_t *src, host_t *dst, + host_t *new_src, host_t *new_dst, + bool encap, bool new_encap, mark_t mark); + + /** + * Query the number of bytes processed by an SA from the SAD. + * + * @param src source address for this SA + * @param dst destination address for this SA + * @param spi SPI allocated by us or remote peer + * @param protocol protocol for this SA (ESP/AH) + * @param mark optional mark for this SA + * @param[out] bytes the number of bytes processed by SA + * @return SUCCESS if operation completed + */ + status_t (*query_sa) (kernel_interface_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, mark_t mark, + u_int64_t *bytes); + + /** + * Delete a previously installed SA from the SAD. + * + * @param src source address for this SA + * @param dst destination address for this SA + * @param spi SPI allocated by us or remote peer + * @param protocol protocol for this SA (ESP/AH) + * @param cpi CPI for IPComp or 0 + * @param mark optional mark for this SA + * @return SUCCESS if operation completed + */ + status_t (*del_sa) (kernel_interface_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int16_t cpi, + mark_t mark); + + /** + * Add a policy to the SPD. + * + * A policy is always associated to an SA. Traffic which matches a + * policy is handled by the SA with the same reqid. + * + * @param src source address of SA + * @param dst dest address of SA + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_(IN|OUT|FWD) + * @param type type of policy, POLICY_(IPSEC|PASS|DROP) + * @param sa details about the SA(s) tied to this policy + * @param mark mark for this policy + * @param routed TRUE, if this policy is routed in the kernel + * @return SUCCESS if operation completed + */ + status_t (*add_policy) (kernel_interface_t *this, + host_t *src, host_t *dst, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, policy_type_t type, + ipsec_sa_cfg_t *sa, mark_t mark, bool routed); + + /** + * Query the use time of a policy. + * + * The use time of a policy is the time the policy was used + * for the last time. + * + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_(IN|OUT|FWD) + * @param mark optional mark + * @param[out] use_time the time of this SA's last use + * @return SUCCESS if operation completed + */ + status_t (*query_policy) (kernel_interface_t *this, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, mark_t mark, + u_int32_t *use_time); + + /** + * Remove a policy from the SPD. + * + * The kernel interface implements reference counting for policies. + * If the same policy is installed multiple times (in the case of rekeying), + * the reference counter is increased. del_policy() decreases the ref counter + * and removes the policy only when no more references are available. + * + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_(IN|OUT|FWD) + * @param mark optional mark + * @param unrouted TRUE, if this policy is unrouted from the kernel + * @return SUCCESS if operation completed + */ + status_t (*del_policy) (kernel_interface_t *this, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, mark_t mark, + bool unrouted); + + /** + * Get our outgoing source address for a destination. + * + * Does a route lookup to get the source address used to reach dest. + * The returned host is allocated and must be destroyed. + * An optional src address can be used to check if a route is available + * for given source to dest. + * + * @param dest target destination address + * @param src source address to check, or NULL + * @return outgoing source address, NULL if unreachable + */ + host_t* (*get_source_addr)(kernel_interface_t *this, + host_t *dest, host_t *src); + + /** + * Get the next hop for a destination. + * + * Does a route lookup to get the next hop used to reach dest. + * The returned host is allocated and must be destroyed. + * + * @param dest target destination address + * @return next hop address, NULL if unreachable + */ + host_t* (*get_nexthop)(kernel_interface_t *this, host_t *dest); + + /** + * Get the interface name of a local address. + * + * @param host address to get interface name from + * @return allocated interface name, or NULL if not found + */ + char* (*get_interface) (kernel_interface_t *this, host_t *host); + + /** + * Creates an enumerator over all local addresses. + * + * This function blocks an internal cached address list until the + * enumerator gets destroyed. + * The hosts are read-only, do not modify of free. + * + * @param include_down_ifaces TRUE to enumerate addresses from down interfaces + * @param include_virtual_ips TRUE to enumerate virtual ip addresses + * @return enumerator over host_t's + */ + enumerator_t *(*create_address_enumerator) (kernel_interface_t *this, + bool include_down_ifaces, bool include_virtual_ips); + + /** + * Add a virtual IP to an interface. + * + * Virtual IPs are attached to an interface. If an IP is added multiple + * times, the IP is refcounted and not removed until del_ip() was called + * as many times as add_ip(). + * The virtual IP is attached to the interface where the iface_ip is found. + * + * @param virtual_ip virtual ip address to assign + * @param iface_ip IP of an interface to attach virtual IP + * @return SUCCESS if operation completed + */ + status_t (*add_ip) (kernel_interface_t *this, host_t *virtual_ip, + host_t *iface_ip); + + /** + * Remove a virtual IP from an interface. + * + * The kernel interface uses refcounting, see add_ip(). + * + * @param virtual_ip virtual ip address to assign + * @return SUCCESS if operation completed + */ + status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip); + + /** + * Add a route. + * + * @param dst_net destination net + * @param prefixlen destination net prefix length + * @param gateway gateway for this route + * @param src_ip sourc ip of the route + * @param if_name name of the interface the route is bound to + * @return SUCCESS if operation completed + * ALREADY_DONE if the route already exists + */ + status_t (*add_route) (kernel_interface_t *this, chunk_t dst_net, + u_int8_t prefixlen, host_t *gateway, host_t *src_ip, + char *if_name); + + /** + * Delete a route. + * + * @param dst_net destination net + * @param prefixlen destination net prefix length + * @param gateway gateway for this route + * @param src_ip sourc ip of the route + * @param if_name name of the interface the route is bound to + * @return SUCCESS if operation completed + */ + status_t (*del_route) (kernel_interface_t *this, chunk_t dst_net, + u_int8_t prefixlen, host_t *gateway, host_t *src_ip, + char *if_name); + + /** + * Set up a bypass policy for a given socket. + * + * @param fd socket file descriptor to setup policy for + * @param family protocol family of the socket + * @return TRUE of policy set up successfully + */ + bool (*bypass_socket)(kernel_interface_t *this, int fd, int family); + + /** + * manager methods + */ + + /** + * Tries to find an ip address of a local interface that is included in the + * supplied traffic selector. + * + * @param ts traffic selector + * @param ip returned ip (has to be destroyed) + * @return SUCCESS if address found + */ + status_t (*get_address_by_ts)(kernel_interface_t *this, + traffic_selector_t *ts, host_t **ip); + + /** + * Register an ipsec kernel interface constructor on the manager. + * + * @param create constructor to register + */ + void (*add_ipsec_interface)(kernel_interface_t *this, + kernel_ipsec_constructor_t create); + + /** + * Unregister an ipsec kernel interface constructor. + * + * @param create constructor to unregister + */ + void (*remove_ipsec_interface)(kernel_interface_t *this, + kernel_ipsec_constructor_t create); + + /** + * Register a network kernel interface constructor on the manager. + * + * @param create constructor to register + */ + void (*add_net_interface)(kernel_interface_t *this, + kernel_net_constructor_t create); + + /** + * Unregister a network kernel interface constructor. + * + * @param create constructor to unregister + */ + void (*remove_net_interface)(kernel_interface_t *this, + kernel_net_constructor_t create); + + /** + * Add a listener to the kernel interface. + * + * @param listener listener to add + */ + void (*add_listener)(kernel_interface_t *this, + kernel_listener_t *listener); + + /** + * Remove a listener from the kernel interface. + * + * @param listener listener to remove + */ + void (*remove_listener)(kernel_interface_t *this, + kernel_listener_t *listener); + + /** + * Raise an acquire event. + * + * @param reqid reqid of the policy to acquire + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + */ + void (*acquire)(kernel_interface_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts); + + /** + * Raise an expire event. + * + * @param reqid reqid of the expired SA + * @param protocol protocol of the expired SA + * @param spi spi of the expired SA + * @param hard TRUE if it is a hard expire, FALSE otherwise + */ + void (*expire)(kernel_interface_t *this, u_int32_t reqid, + u_int8_t protocol, u_int32_t spi, bool hard); + + /** + * Raise a mapping event. + * + * @param reqid reqid of the SA + * @param spi spi of the SA + * @param remote new remote host + */ + void (*mapping)(kernel_interface_t *this, u_int32_t reqid, u_int32_t spi, + host_t *remote); + + /** + * Raise a migrate event. + * + * @param reqid reqid of the policy + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + * @param direction direction of the policy (in|out) + * @param local local host address to be used in the IKE_SA + * @param remote remote host address to be used in the IKE_SA + */ + void (*migrate)(kernel_interface_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t direction, host_t *local, host_t *remote); + + /** + * Raise a roam event. + * + * @param address TRUE if address list, FALSE if routing changed + */ + void (*roam)(kernel_interface_t *this, bool address); + + /** + * Destroys a kernel_interface_manager_t object. + */ + void (*destroy) (kernel_interface_t *this); +}; + +/** + * Creates an object of type kernel_interface_t. + */ +kernel_interface_t *kernel_interface_create(void); + +#endif /** KERNEL_INTERFACE_H_ @}*/ diff --git a/src/libhydra/kernel/kernel_ipsec.c b/src/libhydra/kernel/kernel_ipsec.c new file mode 100644 index 000000000..383685426 --- /dev/null +++ b/src/libhydra/kernel/kernel_ipsec.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * 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 "kernel_ipsec.h" + +ENUM(ipsec_mode_names, MODE_TRANSPORT, MODE_BEET, + "TRANSPORT", + "TUNNEL", + "BEET", +); + +ENUM(policy_dir_names, POLICY_IN, POLICY_FWD, + "in", + "out", + "fwd" +); + +ENUM(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_LZJH, + "IPCOMP_NONE", + "IPCOMP_OUI", + "IPCOMP_DEFLATE", + "IPCOMP_LZS", + "IPCOMP_LZJH" +); + diff --git a/src/libhydra/kernel/kernel_ipsec.h b/src/libhydra/kernel/kernel_ipsec.h new file mode 100644 index 000000000..49d9cc07a --- /dev/null +++ b/src/libhydra/kernel/kernel_ipsec.h @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2006-2010 Tobias Brunner + * Copyright (C) 2006 Daniel Roethlisberger + * Copyright (C) 2005-2006 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 <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. + */ + +/** + * @defgroup kernel_ipsec kernel_ipsec + * @{ @ingroup hkernel + */ + +#ifndef KERNEL_IPSEC_H_ +#define KERNEL_IPSEC_H_ + +typedef enum ipsec_mode_t ipsec_mode_t; +typedef enum policy_dir_t policy_dir_t; +typedef enum policy_type_t policy_type_t; +typedef enum ipcomp_transform_t ipcomp_transform_t; +typedef struct kernel_ipsec_t kernel_ipsec_t; +typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t; +typedef struct lifetime_cfg_t lifetime_cfg_t; +typedef struct mark_t mark_t; + +#include <utils/host.h> +#include <crypto/prf_plus.h> +#include <selectors/traffic_selector.h> + +/** + * Mode of an IPsec SA. + */ +enum ipsec_mode_t { + /** transport mode, no inner address */ + MODE_TRANSPORT = 1, + /** tunnel mode, inner and outer addresses */ + MODE_TUNNEL, + /** BEET mode, tunnel mode but fixed, bound inner addresses */ + MODE_BEET, +}; + +/** + * enum names for ipsec_mode_t. + */ +extern enum_name_t *ipsec_mode_names; + +/** + * Direction of a policy. These are equal to those + * defined in xfrm.h, but we want to stay implementation + * neutral here. + */ +enum policy_dir_t { + /** Policy for inbound traffic */ + POLICY_IN = 0, + /** Policy for outbound traffic */ + POLICY_OUT = 1, + /** Policy for forwarded traffic */ + POLICY_FWD = 2, +}; + +/** + * enum names for policy_dir_t. + */ +extern enum_name_t *policy_dir_names; + +/** + * Type of a policy. + */ +enum policy_type_t { + /** Normal IPsec policy */ + POLICY_IPSEC = 1, + /** Passthrough policy (traffic is ignored by IPsec) */ + POLICY_PASS, + /** Drop policy (traffic is discarded) */ + POLICY_DROP, +}; + +/** + * IPComp transform IDs, as in RFC 4306 + */ +enum ipcomp_transform_t { + IPCOMP_NONE = 0, + IPCOMP_OUI = 1, + IPCOMP_DEFLATE = 2, + IPCOMP_LZS = 3, + IPCOMP_LZJH = 4, +}; + +/** + * enum strings for ipcomp_transform_t. + */ +extern enum_name_t *ipcomp_transform_names; + +/** + * This struct contains details about IPsec SA(s) tied to a policy. + */ +struct ipsec_sa_cfg_t { + /** mode of SA (tunnel, transport) */ + ipsec_mode_t mode; + /** unique ID */ + u_int32_t reqid; + /** details about ESP/AH */ + struct { + /** TRUE if this protocol is used */ + bool use; + /** SPI for ESP/AH */ + u_int32_t spi; + } esp, ah; + /** details about IPComp */ + struct { + /** the IPComp transform used */ + u_int16_t transform; + /** CPI for IPComp */ + u_int16_t cpi; + } ipcomp; +}; + +/** + * A lifetime_cfg_t defines the lifetime limits of an SA. + * + * Set any of these values to 0 to ignore. + */ +struct lifetime_cfg_t { + struct { + /** Limit before the SA gets invalid. */ + u_int64_t life; + /** Limit before the SA gets rekeyed. */ + u_int64_t rekey; + /** The range of a random value subtracted from rekey. */ + u_int64_t jitter; + } time, bytes, packets; +}; + +/** + * A mark_t defines an optional mark in an IPsec SA. + */ +struct mark_t { + /** Mark value */ + u_int32_t value; + /** Mark mask */ + u_int32_t mask; +}; + +/** + * Interface to the ipsec subsystem of the kernel. + * + * The kernel ipsec interface handles the communication with the kernel + * for SA and policy management. It allows setup of these, and provides + * further the handling of kernel events. + * Policy information are cached in the interface. This is necessary to do + * reference counting. The Linux kernel does not allow the same policy + * installed twice, but we need this as CHILD_SA exist multiple times + * when rekeying. Thats why we do reference counting of policies. + */ +struct kernel_ipsec_t { + + /** + * Get a SPI from the kernel. + * + * @param src source address of SA + * @param dst destination address of SA + * @param protocol protocol for SA (ESP/AH) + * @param reqid unique ID for this SA + * @param spi allocated spi + * @return SUCCESS if operation completed + */ + status_t (*get_spi)(kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, u_int32_t *spi); + + /** + * Get a Compression Parameter Index (CPI) from the kernel. + * + * @param src source address of SA + * @param dst destination address of SA + * @param reqid unique ID for the corresponding SA + * @param cpi allocated cpi + * @return SUCCESS if operation completed + */ + status_t (*get_cpi)(kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t reqid, u_int16_t *cpi); + + /** + * Add an SA to the SAD. + * + * add_sa() may update an already allocated + * SPI (via get_spi). In this case, the replace + * flag must be set. + * This function does install a single SA for a + * single protocol in one direction. + * + * @param src source address for this SA + * @param dst destination address for this SA + * @param spi SPI allocated by us or remote peer + * @param protocol protocol for this SA (ESP/AH) + * @param reqid unique ID for this SA + * @param mark mark for this SA + * @param lifetime lifetime_cfg_t for this SA + * @param enc_alg Algorithm to use for encryption (ESP only) + * @param enc_key key to use for encryption + * @param int_alg Algorithm to use for integrity protection + * @param int_key key to use for integrity protection + * @param mode mode of the SA (tunnel, transport) + * @param ipcomp IPComp transform to use + * @param cpi CPI for IPComp + * @param encap enable UDP encapsulation for NAT traversal + * @param inbound TRUE if this is an inbound SA + * @param src_ts traffic selector with BEET source address + * @param dst_ts traffic selector with BEET destination address + * @return SUCCESS if operation completed + */ + status_t (*add_sa) (kernel_ipsec_t *this, + host_t *src, host_t *dst, u_int32_t spi, + u_int8_t protocol, u_int32_t reqid, + mark_t mark, lifetime_cfg_t *lifetime, + u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, + ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, + bool encap, bool inbound, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts); + + /** + * Update the hosts on an installed SA. + * + * We cannot directly update the destination address as the kernel + * requires the spi, the protocol AND the destination address (and family) + * to identify SAs. Therefore if the destination address changed we + * create a new SA and delete the old one. + * + * @param spi SPI of the SA + * @param protocol protocol for this SA (ESP/AH) + * @param cpi CPI for IPComp, 0 if no IPComp is used + * @param src current source address + * @param dst current destination address + * @param new_src new source address + * @param new_dst new destination address + * @param encap current use of UDP encapsulation + * @param new_encap new use of UDP encapsulation + * @param mark optional mark for this SA + * @return SUCCESS if operation completed, NOT_SUPPORTED if + * the kernel interface can't update the SA + */ + status_t (*update_sa)(kernel_ipsec_t *this, + u_int32_t spi, u_int8_t protocol, u_int16_t cpi, + host_t *src, host_t *dst, + host_t *new_src, host_t *new_dst, + bool encap, bool new_encap, mark_t mark); + + /** + * Query the number of bytes processed by an SA from the SAD. + * + * @param src source address for this SA + * @param dst destination address for this SA + * @param spi SPI allocated by us or remote peer + * @param protocol protocol for this SA (ESP/AH) + * @param mark optional mark for this SA + * @param[out] bytes the number of bytes processed by SA + * @return SUCCESS if operation completed + */ + status_t (*query_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, mark_t mark, + u_int64_t *bytes); + + /** + * Delete a previusly installed SA from the SAD. + * + * @param src source address for this SA + * @param dst destination address for this SA + * @param spi SPI allocated by us or remote peer + * @param protocol protocol for this SA (ESP/AH) + * @param cpi CPI for IPComp or 0 + * @param mark optional mark for this SA + * @return SUCCESS if operation completed + */ + status_t (*del_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int16_t cpi, + mark_t mark); + + /** + * Add a policy to the SPD. + * + * A policy is always associated to an SA. Traffic which matches a + * policy is handled by the SA with the same reqid. + * + * @param src source address of SA + * @param dst dest address of SA + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_(IN|OUT|FWD) + * @param type type of policy, POLICY_(IPSEC|PASS|DROP) + * @param sa details about the SA(s) tied to this policy + * @param mark mark for this policy + * @param routed TRUE, if this policy is routed in the kernel + * @return SUCCESS if operation completed + */ + status_t (*add_policy) (kernel_ipsec_t *this, + host_t *src, host_t *dst, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, policy_type_t type, + ipsec_sa_cfg_t *sa, mark_t mark, bool routed); + + /** + * Query the use time of a policy. + * + * The use time of a policy is the time the policy was used for the last + * time. It is not the system time, but a monotonic timestamp as returned + * by time_monotonic. + * + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_(IN|OUT|FWD) + * @param mark optional mark + * @param[out] use_time the monotonic timestamp of this SA's last use + * @return SUCCESS if operation completed + */ + status_t (*query_policy) (kernel_ipsec_t *this, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, mark_t mark, + u_int32_t *use_time); + + /** + * Remove a policy from the SPD. + * + * The kernel interface implements reference counting for policies. + * If the same policy is installed multiple times (in the case of rekeying), + * the reference counter is increased. del_policy() decreases the ref counter + * and removes the policy only when no more references are available. + * + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_(IN|OUT|FWD) + * @param mark optional mark + * @param unrouted TRUE, if this policy is unrouted from the kernel + * @return SUCCESS if operation completed + */ + status_t (*del_policy) (kernel_ipsec_t *this, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, mark_t mark, + bool unrouted); + + /** + * Install a bypass policy for the given socket. + * + * @param fd socket file descriptor to setup policy for + * @param family protocol family of the socket + * @return TRUE of policy set up successfully + */ + bool (*bypass_socket)(kernel_ipsec_t *this, int fd, int family); + + /** + * Destroy the implementation. + */ + void (*destroy) (kernel_ipsec_t *this); +}; + +#endif /** KERNEL_IPSEC_H_ @}*/ diff --git a/src/libhydra/kernel/kernel_listener.h b/src/libhydra/kernel/kernel_listener.h new file mode 100644 index 000000000..6f2dbd23b --- /dev/null +++ b/src/libhydra/kernel/kernel_listener.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 Tobias Brunner + * 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. + */ + +/** + * @defgroup kernel_listener kernel_listener + * @{ @ingroup hkernel + */ + +#ifndef KERNEL_LISTENER_H_ +#define KERNEL_LISTENER_H_ + +typedef struct kernel_listener_t kernel_listener_t; + +#include <kernel/kernel_ipsec.h> +#include <selectors/traffic_selector.h> +#include <utils/host.h> + +/** + * Interface for components interested in kernel events. + * + * All hooks are optional. + */ +struct kernel_listener_t { + + /** + * Hook called if an acquire event for a policy is received. + * + * @param reqid reqid of the policy to acquire + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + * @return TRUE to remain registered, FALSE to unregister + */ + bool (*acquire)(kernel_listener_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts); + + /** + * Hook called if an exire event for an IPsec SA is received. + * + * @param reqid reqid of the expired SA + * @param protocol protocol of the expired SA + * @param spi spi of the expired SA + * @param hard TRUE if it is a hard expire, FALSE otherwise + * @return TRUE to remain registered, FALSE to unregister + */ + bool (*expire)(kernel_listener_t *this, u_int32_t reqid, + u_int8_t protocol, u_int32_t spi, bool hard); + + /** + * Hook called if the NAT mappings of an IPsec SA changed. + * + * @param reqid reqid of the SA + * @param spi spi of the SA + * @param remote new remote host + * @return TRUE to remain registered, FALSE to unregister + */ + bool (*mapping)(kernel_listener_t *this, u_int32_t reqid, u_int32_t spi, + host_t *remote); + + /** + * Hook called if a migrate event for a policy is received. + * + * @param reqid reqid of the policy + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + * @param direction direction of the policy (in|out) + * @param local local host address to be used in the IKE_SA + * @param remote remote host address to be used in the IKE_SA + * @return TRUE to remain registered, FALSE to unregister + */ + bool (*migrate)(kernel_listener_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t direction, host_t *local, host_t *remote); + + /** + * Hook called if changes in the networking layer occured (interfaces + * up/down, routes added/deleted etc.). + * + * @param address TRUE if address list, FALSE if routing changed + * @return TRUE to remain registered, FALSE to unregister + */ + bool (*roam)(kernel_listener_t *this, bool address); +}; + +#endif /** KERNEL_LISTENER_H_ @}*/ diff --git a/src/libhydra/kernel/kernel_net.h b/src/libhydra/kernel/kernel_net.h new file mode 100644 index 000000000..69e01f43f --- /dev/null +++ b/src/libhydra/kernel/kernel_net.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2007 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. + */ + +/** + * @defgroup kernel_net kernel_net + * @{ @ingroup hkernel + */ + +#ifndef KERNEL_NET_H_ +#define KERNEL_NET_H_ + +typedef struct kernel_net_t kernel_net_t; + +#include <utils/enumerator.h> +#include <utils/host.h> + +/** + * Interface to the network subsystem of the kernel. + * + * The kernel network interface handles the communication with the kernel + * for interface and IP address management. + */ +struct kernel_net_t { + + /** + * Get our outgoing source address for a destination. + * + * Does a route lookup to get the source address used to reach dest. + * The returned host is allocated and must be destroyed. + * An optional src address can be used to check if a route is available + * for given source to dest. + * + * @param dest target destination address + * @param src source address to check, or NULL + * @return outgoing source address, NULL if unreachable + */ + host_t* (*get_source_addr)(kernel_net_t *this, host_t *dest, host_t *src); + + /** + * Get the next hop for a destination. + * + * Does a route lookup to get the next hop used to reach dest. + * The returned host is allocated and must be destroyed. + * + * @param dest target destination address + * @return next hop address, NULL if unreachable + */ + host_t* (*get_nexthop)(kernel_net_t *this, host_t *dest); + + /** + * Get the interface name of a local address. + * + * @param host address to get interface name from + * @return allocated interface name, or NULL if not found + */ + char* (*get_interface) (kernel_net_t *this, host_t *host); + + /** + * Creates an enumerator over all local addresses. + * + * This function blocks an internal cached address list until the + * enumerator gets destroyed. + * The hosts are read-only, do not modify of free. + * + * @param include_down_ifaces TRUE to enumerate addresses from down interfaces + * @param include_virtual_ips TRUE to enumerate virtual ip addresses + * @return enumerator over host_t's + */ + enumerator_t *(*create_address_enumerator) (kernel_net_t *this, + bool include_down_ifaces, bool include_virtual_ips); + + /** + * Add a virtual IP to an interface. + * + * Virtual IPs are attached to an interface. If an IP is added multiple + * times, the IP is refcounted and not removed until del_ip() was called + * as many times as add_ip(). + * The virtual IP is attached to the interface where the iface_ip is found. + * + * @param virtual_ip virtual ip address to assign + * @param iface_ip IP of an interface to attach virtual IP + * @return SUCCESS if operation completed + */ + status_t (*add_ip) (kernel_net_t *this, host_t *virtual_ip, + host_t *iface_ip); + + /** + * Remove a virtual IP from an interface. + * + * The kernel interface uses refcounting, see add_ip(). + * + * @param virtual_ip virtual ip address to assign + * @return SUCCESS if operation completed + */ + status_t (*del_ip) (kernel_net_t *this, host_t *virtual_ip); + + /** + * Add a route. + * + * @param dst_net destination net + * @param prefixlen destination net prefix length + * @param gateway gateway for this route + * @param src_ip sourc ip of the route + * @param if_name name of the interface the route is bound to + * @return SUCCESS if operation completed + * ALREADY_DONE if the route already exists + */ + status_t (*add_route) (kernel_net_t *this, chunk_t dst_net, + u_int8_t prefixlen, host_t *gateway, host_t *src_ip, + char *if_name); + + /** + * Delete a route. + * + * @param dst_net destination net + * @param prefixlen destination net prefix length + * @param gateway gateway for this route + * @param src_ip sourc ip of the route + * @param if_name name of the interface the route is bound to + * @return SUCCESS if operation completed + */ + status_t (*del_route) (kernel_net_t *this, chunk_t dst_net, + u_int8_t prefixlen, host_t *gateway, host_t *src_ip, + char *if_name); + + /** + * Destroy the implementation. + */ + void (*destroy) (kernel_net_t *this); +}; + +#endif /** KERNEL_NET_H_ @}*/ |