diff options
Diffstat (limited to 'src/libcharon/kernel')
-rw-r--r-- | src/libcharon/kernel/kernel_interface.c | 386 | ||||
-rw-r--r-- | src/libcharon/kernel/kernel_interface.h | 398 | ||||
-rw-r--r-- | src/libcharon/kernel/kernel_ipsec.c | 29 | ||||
-rw-r--r-- | src/libcharon/kernel/kernel_ipsec.h | 282 | ||||
-rw-r--r-- | src/libcharon/kernel/kernel_net.h | 143 |
5 files changed, 1238 insertions, 0 deletions
diff --git a/src/libcharon/kernel/kernel_interface.c b/src/libcharon/kernel/kernel_interface.c new file mode 100644 index 000000000..64a43a7fc --- /dev/null +++ b/src/libcharon/kernel/kernel_interface.c @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2008-2009 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 <daemon.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; +}; + +METHOD(kernel_interface_t, get_spi, status_t, + private_kernel_interface_t *this, host_t *src, host_t *dst, + protocol_id_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, protocol_id_t protocol, u_int32_t reqid, + 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, + 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, protocol_id_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) +{ + 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); +} + +METHOD(kernel_interface_t, query_sa, status_t, + private_kernel_interface_t *this, host_t *src, host_t *dst, + u_int32_t spi, protocol_id_t protocol, u_int64_t *bytes) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, bytes); +} + +METHOD(kernel_interface_t, del_sa, status_t, + private_kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi, + protocol_id_t protocol, u_int16_t cpi) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->del_sa(this->ipsec, src, dst, spi, protocol, cpi); +} + +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, u_int32_t spi, protocol_id_t protocol, + u_int32_t reqid, ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, + bool routed) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts, + direction, spi, protocol, reqid, mode, ipcomp, cpi, 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, u_int32_t *use_time) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->query_policy(this->ipsec, src_ts, dst_ts, + direction, 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, bool unrouted) +{ + if (!this->ipsec) + { + return NOT_SUPPORTED; + } + return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts, + direction, 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, destroy, void, + private_kernel_interface_t *this) +{ + DESTROY_IF(this->ipsec); + DESTROY_IF(this->net); + 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, + .destroy = _destroy, + }, + ); + + return &this->public; +} + diff --git a/src/libcharon/kernel/kernel_interface.h b/src/libcharon/kernel/kernel_interface.h new file mode 100644 index 000000000..4a62e76b8 --- /dev/null +++ b/src/libcharon/kernel/kernel_interface.h @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2006-2009 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 kernel + */ + +#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 <encoding/payloads/proposal_substructure.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, + protocol_id_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 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, + protocol_id_t protocol, u_int32_t reqid, + 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 + * @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, protocol_id_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); + + /** + * 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[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, protocol_id_t protocol, 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 + * @return SUCCESS if operation completed + */ + status_t (*del_sa) (kernel_interface_t *this, host_t *src, host_t *dst, + u_int32_t spi, protocol_id_t protocol, u_int16_t cpi); + + /** + * 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, POLICY_OUT, POLICY_FWD + * @param spi SPI of SA + * @param protocol protocol to use to protect traffic (AH/ESP) + * @param reqid unique ID of an SA to use to enforce policy + * @param mode mode of SA (tunnel, transport) + * @param ipcomp the IPComp transform used + * @param cpi CPI for IPComp + * @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, u_int32_t spi, + protocol_id_t protocol, u_int32_t reqid, + ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, + 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, POLICY_OUT, POLICY_FWD + * @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, 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, POLICY_OUT, POLICY_FWD + * @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, + 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); + + /** + * 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/libcharon/kernel/kernel_ipsec.c b/src/libcharon/kernel/kernel_ipsec.c new file mode 100644 index 000000000..5b0335b16 --- /dev/null +++ b/src/libcharon/kernel/kernel_ipsec.c @@ -0,0 +1,29 @@ +/* + * 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" +); + diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h new file mode 100644 index 000000000..300464cf6 --- /dev/null +++ b/src/libcharon/kernel/kernel_ipsec.h @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2006-2009 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 kernel + */ + +#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 struct kernel_ipsec_t kernel_ipsec_t; + +#include <utils/host.h> +#include <crypto/prf_plus.h> +#include <config/proposal.h> +#include <config/child_cfg.h> + +/** + * Mode of a CHILD_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; + +/** + * 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, + protocol_id_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 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, + protocol_id_t protocol, u_int32_t reqid, + 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 + * @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, protocol_id_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); + + /** + * 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[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, protocol_id_t protocol, 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 + * @return SUCCESS if operation completed + */ + status_t (*del_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst, + u_int32_t spi, protocol_id_t protocol, u_int16_t cpi); + + /** + * 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, POLICY_OUT, POLICY_FWD + * @param spi SPI of SA + * @param protocol protocol to use to protect traffic (AH/ESP) + * @param reqid unique ID of an SA to use to enforce policy + * @param mode mode of SA (tunnel, transport) + * @param ipcomp the IPComp transform used + * @param cpi CPI for IPComp + * @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, u_int32_t spi, + protocol_id_t protocol, u_int32_t reqid, + ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, + 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, POLICY_OUT, POLICY_FWD + * @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, 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, POLICY_OUT, POLICY_FWD + * @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, + 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/libcharon/kernel/kernel_net.h b/src/libcharon/kernel/kernel_net.h new file mode 100644 index 000000000..efb221f88 --- /dev/null +++ b/src/libcharon/kernel/kernel_net.h @@ -0,0 +1,143 @@ +/* + * 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 kernel + */ + +#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_ @}*/ |