Merge branch 'kernel-libipsec'

Adds a new kernel interface plugin that uses TUN devices and libipsec to
provide IPsec process in userland.

It works on Linux, FreeBSD and Mac OS X.  In particular the latter two
platforms may gain from this approach as their respective kernels don't
provide support for AES-GCM.

kernel-pfroute has been improved (source address lookup) and a second
plugin (osx-attr) installs configuration attributes (currently DNS
servers only) via SystemConfiguration on Mac OS X.
This commit is contained in:
Tobias Brunner
2013-06-21 17:07:41 +02:00
23 changed files with 2039 additions and 42 deletions
+12
View File
@@ -192,6 +192,7 @@ ARG_DISBL_SET([kernel-netlink], [disable the netlink kernel interface.])
ARG_ENABL_SET([kernel-pfkey], [enable the PF_KEY kernel interface.])
ARG_ENABL_SET([kernel-pfroute], [enable the PF_ROUTE kernel interface.])
ARG_ENABL_SET([kernel-klips], [enable the KLIPS kernel interface.])
ARG_ENABL_SET([kernel-libipsec],[enable the libipsec kernel interface.])
ARG_ENABL_SET([libipsec], [enable user space IPsec implementation.])
ARG_DISBL_SET([socket-default], [disable default socket implementation for charon.])
ARG_ENABL_SET([socket-dynamic], [enable dynamic socket implementation for charon])
@@ -224,6 +225,7 @@ ARG_ENABL_SET([gcm], [enables the GCM AEAD wrapper crypto plugin.])
ARG_ENABL_SET([addrblock], [enables RFC 3779 address block constraint support.])
ARG_ENABL_SET([unity], [enables Cisco Unity extension plugin.])
ARG_ENABL_SET([uci], [enable OpenWRT UCI configuration plugin.])
ARG_ENABL_SET([osx-attr], [enable OS X SystemConfiguration attribute handler.])
ARG_ENABL_SET([android-dns], [enable Android specific DNS handler.])
ARG_ENABL_SET([android-log], [enable Android specific logger plugin.])
ARG_ENABL_SET([maemo], [enable Maemo specific plugin.])
@@ -306,6 +308,10 @@ if test x$xauth_generic_given = xfalse -a x$ikev1 = xfalse; then
xauth_generic=false;
fi
if test x$kernel_libipsec = xtrue; then
libipsec=true;
fi
if test x$eap_aka_3gpp2 = xtrue; then
gmp=true;
fi
@@ -1015,6 +1021,7 @@ ADD_PLUGIN([gcm], [s charon scripts nm cmd])
ADD_PLUGIN([attr], [h charon])
ADD_PLUGIN([attr-sql], [h charon])
ADD_PLUGIN([load-tester], [c charon])
ADD_PLUGIN([kernel-libipsec], [c charon cmd])
ADD_PLUGIN([kernel-pfkey], [h charon starter nm cmd])
ADD_PLUGIN([kernel-pfroute], [h charon starter nm cmd])
ADD_PLUGIN([kernel-klips], [h charon starter])
@@ -1060,6 +1067,7 @@ ADD_PLUGIN([tnccs-dynamic], [c charon])
ADD_PLUGIN([medsrv], [c charon])
ADD_PLUGIN([medcli], [c charon])
ADD_PLUGIN([dhcp], [c charon])
ADD_PLUGIN([osx-attr], [c charon cmd])
ADD_PLUGIN([android-dns], [c charon])
ADD_PLUGIN([android-log], [c charon])
ADD_PLUGIN([ha], [c charon])
@@ -1152,6 +1160,7 @@ AM_CONDITIONAL(USE_STROKE, test x$stroke = xtrue)
AM_CONDITIONAL(USE_MEDSRV, test x$medsrv = xtrue)
AM_CONDITIONAL(USE_MEDCLI, test x$medcli = xtrue)
AM_CONDITIONAL(USE_UCI, test x$uci = xtrue)
AM_CONDITIONAL(USE_OSX_ATTR, test x$osx_attr = xtrue)
AM_CONDITIONAL(USE_ANDROID_DNS, test x$android_dns = xtrue)
AM_CONDITIONAL(USE_ANDROID_LOG, test x$android_log = xtrue)
AM_CONDITIONAL(USE_MAEMO, test x$maemo = xtrue)
@@ -1163,6 +1172,7 @@ AM_CONDITIONAL(USE_DHCP, test x$dhcp = xtrue)
AM_CONDITIONAL(USE_UNIT_TESTS, test x$unit_tester = xtrue)
AM_CONDITIONAL(USE_LOAD_TESTER, test x$load_tester = xtrue)
AM_CONDITIONAL(USE_HA, test x$ha = xtrue)
AM_CONDITIONAL(USE_KERNEL_LIBIPSEC, test x$kernel_libipsec = xtrue)
AM_CONDITIONAL(USE_WHITELIST, test x$whitelist = xtrue)
AM_CONDITIONAL(USE_LOOKIP, test x$lookip = xtrue)
AM_CONDITIONAL(USE_ERROR_NOTIFY, test x$error_notify = xtrue)
@@ -1418,6 +1428,7 @@ AC_CONFIG_FILES([
src/libcharon/plugins/unity/Makefile
src/libcharon/plugins/uci/Makefile
src/libcharon/plugins/ha/Makefile
src/libcharon/plugins/kernel_libipsec/Makefile
src/libcharon/plugins/whitelist/Makefile
src/libcharon/plugins/lookip/Makefile
src/libcharon/plugins/error_notify/Makefile
@@ -1427,6 +1438,7 @@ AC_CONFIG_FILES([
src/libcharon/plugins/duplicheck/Makefile
src/libcharon/plugins/coupling/Makefile
src/libcharon/plugins/radattr/Makefile
src/libcharon/plugins/osx_attr/Makefile
src/libcharon/plugins/android_dns/Makefile
src/libcharon/plugins/android_log/Makefile
src/libcharon/plugins/maemo/Makefile
+14
View File
@@ -457,6 +457,13 @@ if MONOLITHIC
endif
endif
if USE_OSX_ATTR
SUBDIRS += plugins/osx_attr
if MONOLITHIC
libcharon_la_LIBADD += plugins/osx_attr/libstrongswan-osx-attr.la
endif
endif
if USE_ANDROID_DNS
SUBDIRS += plugins/android_dns
if MONOLITHIC
@@ -485,6 +492,13 @@ if MONOLITHIC
endif
endif
if USE_KERNEL_LIBIPSEC
SUBDIRS += plugins/kernel_libipsec
if MONOLITHIC
libcharon_la_LIBADD += plugins/kernel_libipsec/libstrongswan-kernel-libipsec.la
endif
endif
if USE_WHITELIST
SUBDIRS += plugins/whitelist
if MONOLITHIC
@@ -0,0 +1,22 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libhydra \
-I$(top_srcdir)/src/libcharon \
-I$(top_srcdir)/src/libipsec
AM_CFLAGS = -rdynamic
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-kernel-libipsec.la
else
plugin_LTLIBRARIES = libstrongswan-kernel-libipsec.la
endif
libstrongswan_kernel_libipsec_la_SOURCES = \
kernel_libipsec_plugin.h kernel_libipsec_plugin.c \
kernel_libipsec_ipsec.h kernel_libipsec_ipsec.c \
kernel_libipsec_router.h kernel_libipsec_router.c
libstrongswan_kernel_libipsec_la_LIBADD = $(top_builddir)/src/libipsec/libipsec.la
libstrongswan_kernel_libipsec_la_LDFLAGS = -module -avoid-version
@@ -0,0 +1,687 @@
/*
* Copyright (C) 2012-2013 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_libipsec_ipsec.h"
#include "kernel_libipsec_router.h"
#include <library.h>
#include <ipsec.h>
#include <hydra.h>
#include <networking/tun_device.h>
#include <threading/mutex.h>
#include <utils/debug.h>
typedef struct private_kernel_libipsec_ipsec_t private_kernel_libipsec_ipsec_t;
struct private_kernel_libipsec_ipsec_t {
/**
* Public libipsec_ipsec interface
*/
kernel_libipsec_ipsec_t public;
/**
* Listener for lifetime expire events
*/
ipsec_event_listener_t ipsec_listener;
/**
* Mutex to lock access to various lists
*/
mutex_t *mutex;
/**
* List of installed policies (policy_entry_t)
*/
linked_list_t *policies;
/**
* List of exclude routes (exclude_route_t)
*/
linked_list_t *excludes;
};
typedef struct exclude_route_t exclude_route_t;
/**
* Exclude route definition
*/
struct exclude_route_t {
/** Destination address to exclude */
host_t *dst;
/** Source address for route */
host_t *src;
/** Nexthop exclude has been installed */
host_t *gtw;
/** References to this route */
int refs;
};
/**
* Clean up an exclude route entry
*/
static void exclude_route_destroy(exclude_route_t *this)
{
this->dst->destroy(this->dst);
this->src->destroy(this->src);
this->gtw->destroy(this->gtw);
free(this);
}
/**
* Find an exclude route entry by destination address
*/
static bool exclude_route_match(exclude_route_t *current,
host_t *dst)
{
return dst->ip_equals(dst, current->dst);
}
typedef struct route_entry_t route_entry_t;
/**
* Installed routing entry
*/
struct route_entry_t {
/** Name of the interface the route is bound to */
char *if_name;
/** Source IP of the route */
host_t *src_ip;
/** Gateway of the route */
host_t *gateway;
/** Destination net */
chunk_t dst_net;
/** Destination net prefixlen */
u_int8_t prefixlen;
/** Reference to exclude route, if any */
exclude_route_t *exclude;
};
/**
* Destroy a route_entry_t object
*/
static void route_entry_destroy(route_entry_t *this)
{
free(this->if_name);
DESTROY_IF(this->src_ip);
DESTROY_IF(this->gateway);
chunk_free(&this->dst_net);
free(this);
}
/**
* Compare two route_entry_t objects
*/
static bool route_entry_equals(route_entry_t *a, route_entry_t *b)
{
if ((!a->src_ip && !b->src_ip) || (a->src_ip && b->src_ip &&
a->src_ip->ip_equals(a->src_ip, b->src_ip)))
{
if ((!a->gateway && !b->gateway) || (a->gateway && b->gateway &&
a->gateway->ip_equals(a->gateway, b->gateway)))
{
return a->if_name && b->if_name && streq(a->if_name, b->if_name) &&
chunk_equals(a->dst_net, b->dst_net) &&
a->prefixlen == b->prefixlen;
}
}
return FALSE;
}
typedef struct policy_entry_t policy_entry_t;
/**
* Installed policy
*/
struct policy_entry_t {
/** Direction of this policy: in, out, forward */
u_int8_t direction;
/** Parameters of installed policy */
struct {
/** Subnet and port */
host_t *net;
/** Subnet mask */
u_int8_t mask;
/** Protocol */
u_int8_t proto;
} src, dst;
/** Associated route installed for this policy */
route_entry_t *route;
/** References to this policy */
int refs;
};
/**
* Create a policy_entry_t object
*/
static policy_entry_t *create_policy_entry(traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t dir)
{
policy_entry_t *this;
INIT(this,
.direction = dir,
);
src_ts->to_subnet(src_ts, &this->src.net, &this->src.mask);
dst_ts->to_subnet(dst_ts, &this->dst.net, &this->dst.mask);
/* src or dest proto may be "any" (0), use more restrictive one */
this->src.proto = max(src_ts->get_protocol(src_ts),
dst_ts->get_protocol(dst_ts));
this->src.proto = this->src.proto ? this->src.proto : 0;
this->dst.proto = this->src.proto;
return this;
}
/**
* Destroy a policy_entry_t object
*/
static void policy_entry_destroy(policy_entry_t *this)
{
if (this->route)
{
route_entry_destroy(this->route);
}
DESTROY_IF(this->src.net);
DESTROY_IF(this->dst.net);
free(this);
}
/**
* Compare two policy_entry_t objects
*/
static inline bool policy_entry_equals(policy_entry_t *a,
policy_entry_t *b)
{
return a->direction == b->direction &&
a->src.proto == b->src.proto &&
a->dst.proto == b->dst.proto &&
a->src.mask == b->src.mask &&
a->dst.mask == b->dst.mask &&
a->src.net->equals(a->src.net, b->src.net) &&
a->dst.net->equals(a->dst.net, b->dst.net);
}
/**
* Expiration callback
*/
static void expire(u_int32_t reqid, u_int8_t protocol, u_int32_t spi, bool hard)
{
hydra->kernel_interface->expire(hydra->kernel_interface, reqid, protocol,
spi, hard);
}
METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
private_kernel_libipsec_ipsec_t *this)
{
return KERNEL_REQUIRE_UDP_ENCAPSULATION;
}
METHOD(kernel_ipsec_t, get_spi, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
{
return ipsec->sas->get_spi(ipsec->sas, src, dst, protocol, reqid, spi);
}
METHOD(kernel_ipsec_t, get_cpi, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
u_int32_t reqid, u_int16_t *cpi)
{
return NOT_SUPPORTED;
}
METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
u_int32_t tfc, 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 initiator, bool encap, bool esn, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
return ipsec->sas->add_sa(ipsec->sas, src, dst, spi, protocol, reqid, mark,
tfc, lifetime, enc_alg, enc_key, int_alg, int_key,
mode, ipcomp, cpi, initiator, encap, esn, inbound,
src_ts, dst_ts);
}
METHOD(kernel_ipsec_t, update_sa, status_t,
private_kernel_libipsec_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)
{
return NOT_SUPPORTED;
}
METHOD(kernel_ipsec_t, query_sa, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes,
u_int64_t *packets, u_int32_t *time)
{
return NOT_SUPPORTED;
}
METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark)
{
return ipsec->sas->del_sa(ipsec->sas, src, dst, spi, protocol, cpi, mark);
}
METHOD(kernel_ipsec_t, flush_sas, status_t,
private_kernel_libipsec_ipsec_t *this)
{
return ipsec->sas->flush_sas(ipsec->sas);
}
/**
* Add an explicit exclude route to a routing entry
*/
static void add_exclude_route(private_kernel_libipsec_ipsec_t *this,
route_entry_t *route, host_t *src, host_t *dst)
{
exclude_route_t *exclude;
host_t *gtw;
if (this->excludes->find_first(this->excludes,
(linked_list_match_t)exclude_route_match,
(void**)&exclude, dst) == SUCCESS)
{
route->exclude = exclude;
exclude->refs++;
}
if (!route->exclude)
{
DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src);
gtw = hydra->kernel_interface->get_nexthop(hydra->kernel_interface,
dst, NULL);
if (gtw)
{
char *if_name = NULL;
if (hydra->kernel_interface->get_interface(
hydra->kernel_interface, src, &if_name) &&
hydra->kernel_interface->add_route(hydra->kernel_interface,
dst->get_address(dst),
dst->get_family(dst) == AF_INET ? 32 : 128,
gtw, src, if_name) == SUCCESS)
{
INIT(exclude,
.dst = dst->clone(dst),
.src = src->clone(src),
.gtw = gtw->clone(gtw),
.refs = 1,
);
route->exclude = exclude;
this->excludes->insert_last(this->excludes, exclude);
}
else
{
DBG1(DBG_KNL, "installing exclude route for %H failed", dst);
}
gtw->destroy(gtw);
free(if_name);
}
else
{
DBG1(DBG_KNL, "gateway lookup for %H failed", dst);
}
}
}
/**
* Remove an exclude route attached to a routing entry
*/
static void remove_exclude_route(private_kernel_libipsec_ipsec_t *this,
route_entry_t *route)
{
char *if_name = NULL;
host_t *dst;
if (!route->exclude || --route->exclude->refs > 0)
{
return;
}
this->excludes->remove(this->excludes, route->exclude, NULL);
dst = route->exclude->dst;
DBG2(DBG_KNL, "uninstalling exclude route for %H src %H",
dst, route->exclude->src);
if (hydra->kernel_interface->get_interface(
hydra->kernel_interface,
route->exclude->src, &if_name) &&
hydra->kernel_interface->del_route(hydra->kernel_interface,
dst->get_address(dst),
dst->get_family(dst) == AF_INET ? 32 : 128,
route->exclude->gtw, route->exclude->src,
if_name) != SUCCESS)
{
DBG1(DBG_KNL, "uninstalling exclude route for %H failed", dst);
}
exclude_route_destroy(route->exclude);
route->exclude = NULL;
free(if_name);
}
/**
* Install a route for the given policy
*
* this->mutex is released by this function
*/
static bool install_route(private_kernel_libipsec_ipsec_t *this,
host_t *src, host_t *dst, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, policy_entry_t *policy)
{
route_entry_t *route, *old;
host_t *src_ip;
bool is_virtual;
if (policy->direction != POLICY_OUT)
{
this->mutex->unlock(this->mutex);
return TRUE;
}
if (hydra->kernel_interface->get_address_by_ts(hydra->kernel_interface,
src_ts, &src_ip, &is_virtual) != SUCCESS)
{
traffic_selector_t *multicast, *broadcast = NULL;
bool ignore = FALSE;
this->mutex->unlock(this->mutex);
switch (src_ts->get_type(src_ts))
{
case TS_IPV4_ADDR_RANGE:
multicast = traffic_selector_create_from_cidr("224.0.0.0/4",
0, 0, 0xffff);
broadcast = traffic_selector_create_from_cidr("255.255.255.255/32",
0, 0, 0xffff);
break;
case TS_IPV6_ADDR_RANGE:
multicast = traffic_selector_create_from_cidr("ff00::/8",
0, 0, 0xffff);
break;
default:
return FALSE;
}
ignore = src_ts->is_contained_in(src_ts, multicast);
ignore |= broadcast && src_ts->is_contained_in(src_ts, broadcast);
multicast->destroy(multicast);
DESTROY_IF(broadcast);
return ignore;
}
INIT(route,
.if_name = router->get_tun_name(router, is_virtual ? src_ip : NULL),
.src_ip = src_ip,
.dst_net = chunk_clone(policy->dst.net->get_address(policy->dst.net)),
.prefixlen = policy->dst.mask,
);
#ifndef __linux__
/* on Linux we cant't install a gateway */
route->gateway = hydra->kernel_interface->get_nexthop(
hydra->kernel_interface, dst, src);
#endif
if (policy->route)
{
old = policy->route;
if (route_entry_equals(old, route))
{ /* such a route already exists */
route_entry_destroy(route);
this->mutex->unlock(this->mutex);
return TRUE;
}
/* uninstall previously installed route */
if (hydra->kernel_interface->del_route(hydra->kernel_interface,
old->dst_net, old->prefixlen, old->gateway,
old->src_ip, old->if_name) != SUCCESS)
{
DBG1(DBG_KNL, "error uninstalling route installed with policy "
"%R === %R %N", src_ts, dst_ts, policy_dir_names,
policy->direction);
}
route_entry_destroy(old);
policy->route = NULL;
}
/* if remote traffic selector covers the IKE peer, add an exclude route */
if (dst_ts->includes(dst_ts, dst))
{
/* add exclude route for peer */
add_exclude_route(this, route, src, dst);
}
DBG2(DBG_KNL, "installing route: %R src %H dev %s",
dst_ts, route->src_ip, route->if_name);
switch (hydra->kernel_interface->add_route(hydra->kernel_interface,
route->dst_net, route->prefixlen, route->gateway,
route->src_ip, route->if_name))
{
case ALREADY_DONE:
/* route exists, do not uninstall */
remove_exclude_route(this, route);
route_entry_destroy(route);
this->mutex->unlock(this->mutex);
return TRUE;
case SUCCESS:
/* cache the installed route */
policy->route = route;
this->mutex->unlock(this->mutex);
return TRUE;
default:
DBG1(DBG_KNL, "installing route failed: %R src %H dev %s",
dst_ts, route->src_ip, route->if_name);
remove_exclude_route(this, route);
route_entry_destroy(route);
this->mutex->unlock(this->mutex);
return FALSE;
}
}
METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_libipsec_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,
policy_priority_t priority)
{
policy_entry_t *policy, *found = NULL;
status_t status;
if (type != POLICY_IPSEC)
{
return SUCCESS;
}
status = ipsec->policies->add_policy(ipsec->policies, src, dst, src_ts,
dst_ts, direction, type, sa, mark, priority);
if (status != SUCCESS)
{
return status;
}
/* we track policies in order to install routes */
policy = create_policy_entry(src_ts, dst_ts, direction);
this->mutex->lock(this->mutex);
if (this->policies->find_first(this->policies,
(linked_list_match_t)policy_entry_equals,
(void**)&found, policy) == SUCCESS)
{
policy_entry_destroy(policy);
policy = found;
}
else
{ /* use the new one, if we have no such policy */
this->policies->insert_last(this->policies, policy);
}
policy->refs++;
if (!install_route(this, src, dst, src_ts, dst_ts, policy))
{
return FAILED;
}
return SUCCESS;
}
METHOD(kernel_ipsec_t, query_policy, status_t,
private_kernel_libipsec_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)
{
return NOT_SUPPORTED;
}
METHOD(kernel_ipsec_t, del_policy, status_t,
private_kernel_libipsec_ipsec_t *this, traffic_selector_t *src_ts,
traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
mark_t mark, policy_priority_t priority)
{
policy_entry_t *policy, *found = NULL;
status_t status;
status = ipsec->policies->del_policy(ipsec->policies, src_ts, dst_ts,
direction, reqid, mark, priority);
policy = create_policy_entry(src_ts, dst_ts, direction);
this->mutex->lock(this->mutex);
if (this->policies->find_first(this->policies,
(linked_list_match_t)policy_entry_equals,
(void**)&found, policy) != SUCCESS)
{
policy_entry_destroy(policy);
this->mutex->unlock(this->mutex);
return status;
}
policy_entry_destroy(policy);
policy = found;
if (--policy->refs > 0)
{ /* policy is still in use */
this->mutex->unlock(this->mutex);
return status;
}
if (policy->route)
{
route_entry_t *route = policy->route;
if (hydra->kernel_interface->del_route(hydra->kernel_interface,
route->dst_net, route->prefixlen, route->gateway, route->src_ip,
route->if_name) != SUCCESS)
{
DBG1(DBG_KNL, "error uninstalling route installed with "
"policy %R === %R %N", src_ts, dst_ts,
policy_dir_names, direction);
}
remove_exclude_route(this, route);
}
this->policies->remove(this->policies, policy, NULL);
policy_entry_destroy(policy);
this->mutex->unlock(this->mutex);
return status;
}
METHOD(kernel_ipsec_t, flush_policies, status_t,
private_kernel_libipsec_ipsec_t *this)
{
policy_entry_t *pol;
status_t status;
status = ipsec->policies->flush_policies(ipsec->policies);
this->mutex->lock(this->mutex);
while (this->policies->remove_first(this->policies, (void*)&pol) == SUCCESS)
{
if (pol->route)
{
route_entry_t *route = pol->route;
hydra->kernel_interface->del_route(hydra->kernel_interface,
route->dst_net, route->prefixlen, route->gateway,
route->src_ip, route->if_name);
remove_exclude_route(this, route);
}
policy_entry_destroy(pol);
}
this->mutex->unlock(this->mutex);
return status;
}
METHOD(kernel_ipsec_t, bypass_socket, bool,
private_kernel_libipsec_ipsec_t *this, int fd, int family)
{
/* we use exclude routes for this */
return NOT_SUPPORTED;
}
METHOD(kernel_ipsec_t, enable_udp_decap, bool,
private_kernel_libipsec_ipsec_t *this, int fd, int family, u_int16_t port)
{
return NOT_SUPPORTED;
}
METHOD(kernel_ipsec_t, destroy, void,
private_kernel_libipsec_ipsec_t *this)
{
ipsec->events->unregister_listener(ipsec->events, &this->ipsec_listener);
this->policies->destroy_function(this->policies, (void*)policy_entry_destroy);
this->excludes->destroy(this->excludes);
this->mutex->destroy(this->mutex);
free(this);
}
/*
* Described in header.
*/
kernel_libipsec_ipsec_t *kernel_libipsec_ipsec_create()
{
private_kernel_libipsec_ipsec_t *this;
INIT(this,
.public = {
.interface = {
.get_features = _get_features,
.get_spi = _get_spi,
.get_cpi = _get_cpi,
.add_sa = _add_sa,
.update_sa = _update_sa,
.query_sa = _query_sa,
.del_sa = _del_sa,
.flush_sas = _flush_sas,
.add_policy = _add_policy,
.query_policy = _query_policy,
.del_policy = _del_policy,
.flush_policies = _flush_policies,
.bypass_socket = _bypass_socket,
.enable_udp_decap = _enable_udp_decap,
.destroy = _destroy,
},
},
.ipsec_listener = {
.expire = expire,
},
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
.policies = linked_list_create(),
.excludes = linked_list_create(),
);
ipsec->events->register_listener(ipsec->events, &this->ipsec_listener);
return &this->public;
};
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2012-2013 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_libipsec_ipsec kernel_libipsec_ipsec
* @{ @ingroup kernel_libipsec
*/
#ifndef KERNEL_LIBIPSEC_IPSEC_H_
#define KERNEL_LIBIPSEC_IPSEC_H_
#include <library.h>
#include <kernel/kernel_ipsec.h>
typedef struct kernel_libipsec_ipsec_t kernel_libipsec_ipsec_t;
/**
* Implementation of the ipsec interface using libipsec
*/
struct kernel_libipsec_ipsec_t {
/**
* Implements kernel_ipsec_t interface
*/
kernel_ipsec_t interface;
};
/**
* Create a libipsec ipsec interface instance.
*
* @return kernel_libipsec_ipsec_t instance
*/
kernel_libipsec_ipsec_t *kernel_libipsec_ipsec_create();
#endif /** KERNEL_LIBIPSEC_IPSEC_H_ @}*/
@@ -0,0 +1,142 @@
/*
* Copyright (C) 2012-2013 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_libipsec_plugin.h"
#include "kernel_libipsec_ipsec.h"
#include "kernel_libipsec_router.h"
#include <daemon.h>
#include <ipsec.h>
#include <networking/tun_device.h>
#define TUN_DEFAULT_MTU 1400
typedef struct private_kernel_libipsec_plugin_t private_kernel_libipsec_plugin_t;
/**
* private data of "kernel" libipsec plugin
*/
struct private_kernel_libipsec_plugin_t {
/**
* implements plugin interface
*/
kernel_libipsec_plugin_t public;
/**
* TUN device created by this plugin
*/
tun_device_t *tun;
/**
* Packet router
*/
kernel_libipsec_router_t *router;
};
METHOD(plugin_t, get_name, char*,
private_kernel_libipsec_plugin_t *this)
{
return "kernel-libipsec";
}
/**
* Create the kernel_libipsec_router_t instance
*/
static bool create_router(private_kernel_libipsec_plugin_t *this,
plugin_feature_t *feature, bool reg, void *arg)
{
if (reg)
{ /* registers as packet handler etc. */
this->router = kernel_libipsec_router_create();
}
else
{
DESTROY_IF(this->router);
}
return TRUE;
}
METHOD(plugin_t, get_features, int,
private_kernel_libipsec_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_CALLBACK(kernel_ipsec_register, kernel_libipsec_ipsec_create),
PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
PLUGIN_CALLBACK((plugin_feature_callback_t)create_router, NULL),
PLUGIN_PROVIDE(CUSTOM, "kernel-libipsec-router"),
PLUGIN_DEPENDS(CUSTOM, "libcharon-receiver"),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_kernel_libipsec_plugin_t *this)
{
if (this->tun)
{
lib->set(lib, "kernel-libipsec-tun", NULL);
this->tun->destroy(this->tun);
}
libipsec_deinit();
free(this);
}
/*
* see header file
*/
plugin_t *kernel_libipsec_plugin_create()
{
private_kernel_libipsec_plugin_t *this;
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.destroy = _destroy,
},
},
);
if (!libipsec_init())
{
DBG1(DBG_LIB, "initialization of libipsec failed");
destroy(this);
return NULL;
}
this->tun = tun_device_create("ipsec%d");
if (!this->tun)
{
DBG1(DBG_KNL, "failed to create TUN device");
destroy(this);
return NULL;
}
if (!this->tun->set_mtu(this->tun, TUN_DEFAULT_MTU) ||
!this->tun->up(this->tun))
{
DBG1(DBG_KNL, "failed to configure TUN device");
destroy(this);
return NULL;
}
lib->set(lib, "kernel-libipsec-tun", this->tun);
/* set TUN device as default to install VIPs */
lib->settings->set_str(lib->settings, "%s.install_virtual_ip_on",
this->tun->get_name(this->tun), charon->name);
return &this->public.plugin;
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2012-2013 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_libipsec kernel_libipsec
* @ingroup cplugins
*
* @defgroup kernel_libipsec_plugin kernel_libipsec_plugin
* @{ @ingroup kernel_libipsec
*/
#ifndef KERNEL_LIBIPSEC_PLUGIN_H_
#define KERNEL_LIBIPSEC_PLUGIN_H_
#include <library.h>
#include <plugins/plugin.h>
typedef struct kernel_libipsec_plugin_t kernel_libipsec_plugin_t;
/**
* libipsec "kernel" interface plugin
*/
struct kernel_libipsec_plugin_t {
/**
* implements plugin interface
*/
plugin_t plugin;
};
#endif /** KERNEL_LIBIPSEC_PLUGIN_H_ @}*/
@@ -0,0 +1,365 @@
/*
* Copyright (C) 2013 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 <unistd.h>
#include <fcntl.h>
#include "kernel_libipsec_router.h"
#include <daemon.h>
#include <hydra.h>
#include <ipsec.h>
#include <collections/hashtable.h>
#include <networking/tun_device.h>
#include <threading/rwlock.h>
#include <threading/thread.h>
#include <processing/jobs/callback_job.h>
typedef struct private_kernel_libipsec_router_t private_kernel_libipsec_router_t;
/**
* Entry in the TUN device map
*/
typedef struct {
/** virtual IP (points to internal data of tun) */
host_t *addr;
/** underlying TUN file descriptor (cached from tun) */
int fd;
/** TUN device */
tun_device_t *tun;
} tun_entry_t;
/**
* Single instance of the router
*/
kernel_libipsec_router_t *router;
/**
* Private data
*/
struct private_kernel_libipsec_router_t {
/**
* Public interface
*/
kernel_libipsec_router_t public;
/**
* Default TUN device if kernel interface does not require separate TUN
* devices per VIP or for tunnels without VIP.
*/
tun_entry_t tun;
/**
* Hashtable that maps virtual IPs to TUN devices (tun_entry_t).
*/
hashtable_t *tuns;
/**
* Lock for TUN device map
*/
rwlock_t *lock;
/**
* Pipe to signal handle_plain() about changes regarding TUN devices
*/
int notify[2];
};
/**
* Hash function for TUN device map
*/
static u_int tun_entry_hash(tun_entry_t *entry)
{
return chunk_hash(entry->addr->get_address(entry->addr));
}
/**
* Comparison function for TUN device map
*/
static bool tun_entry_equals(tun_entry_t *a, tun_entry_t *b)
{
return a->addr->ip_equals(a->addr, b->addr);
}
/**
* Outbound callback
*/
static void send_esp(void *data, esp_packet_t *packet)
{
charon->sender->send_no_marker(charon->sender, (packet_t*)packet);
}
/**
* Receiver callback
*/
static void receiver_esp_cb(void *data, packet_t *packet)
{
ipsec->processor->queue_inbound(ipsec->processor,
esp_packet_create_from_packet(packet));
}
/**
* Inbound callback
*/
static void deliver_plain(private_kernel_libipsec_router_t *this,
ip_packet_t *packet)
{
tun_device_t *tun;
tun_entry_t *entry, lookup = {
.addr = packet->get_destination(packet),
};
this->lock->read_lock(this->lock);
entry = this->tuns->get(this->tuns, &lookup);
tun = entry ? entry->tun : this->tun.tun;
tun->write_packet(tun, packet->get_encoding(packet));
this->lock->unlock(this->lock);
packet->destroy(packet);
}
/**
* Create an FD set covering all TUN devices and the read end of the notify pipe
*/
static int collect_fds(private_kernel_libipsec_router_t *this, fd_set *fds)
{
enumerator_t *enumerator;
tun_entry_t *entry;
int maxfd;
FD_ZERO(fds);
FD_SET(this->notify[0], fds);
maxfd = this->notify[0];
FD_SET(this->tun.fd, fds);
maxfd = max(maxfd, this->tun.fd);
this->lock->read_lock(this->lock);
enumerator = this->tuns->create_enumerator(this->tuns);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
FD_SET(entry->fd, fds);
maxfd = max(maxfd, entry->fd);
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
return maxfd + 1;
}
/**
* Read and process outbound plaintext packet for the given TUN device
*/
static void process_plain(tun_device_t *tun)
{
chunk_t raw;
if (tun->read_packet(tun, &raw))
{
ip_packet_t *packet;
packet = ip_packet_create(raw);
if (packet)
{
ipsec->processor->queue_outbound(ipsec->processor, packet);
}
else
{
DBG1(DBG_KNL, "invalid IP packet read from TUN device");
}
}
}
/**
* Handle waiting data for any TUN device
*/
static void handle_tuns(private_kernel_libipsec_router_t *this, fd_set *fds)
{
enumerator_t *enumerator;
tun_entry_t *entry;
if (FD_ISSET(this->tun.fd, fds))
{
process_plain(this->tun.tun);
}
this->lock->read_lock(this->lock);
enumerator = this->tuns->create_enumerator(this->tuns);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
if (FD_ISSET(entry->fd, fds))
{
process_plain(entry->tun);
}
}
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
}
/**
* Job handling outbound plaintext packets
*/
static job_requeue_t handle_plain(private_kernel_libipsec_router_t *this)
{
bool oldstate;
fd_set fds;
int maxfd;
maxfd = collect_fds(this, &fds);
oldstate = thread_cancelability(TRUE);
if (select(maxfd, &fds, NULL, NULL, NULL) <= 0)
{
thread_cancelability(oldstate);
return JOB_REQUEUE_FAIR;
}
thread_cancelability(oldstate);
if (FD_ISSET(this->notify[0], &fds))
{ /* list of TUN devices changed, read notification data, rebuild FDs */
char buf[1];
while (read(this->notify[0], &buf, sizeof(buf)) == sizeof(buf));
return JOB_REQUEUE_DIRECT;
}
handle_tuns(this, &fds);
return JOB_REQUEUE_DIRECT;
}
METHOD(kernel_listener_t, tun, bool,
private_kernel_libipsec_router_t *this, tun_device_t *tun, bool created)
{
tun_entry_t *entry, lookup;
char buf[] = {0x01};
this->lock->write_lock(this->lock);
if (created)
{
INIT(entry,
.addr = tun->get_address(tun, NULL),
.fd = tun->get_fd(tun),
.tun = tun,
);
this->tuns->put(this->tuns, entry, entry);
}
else
{
lookup.addr = tun->get_address(tun, NULL);
entry = this->tuns->remove(this->tuns, &lookup);
free(entry);
}
/* notify handler thread to recreate FD set */
ignore_result(write(this->notify[1], buf, sizeof(buf)));
this->lock->unlock(this->lock);
return TRUE;
}
METHOD(kernel_libipsec_router_t, get_tun_name, char*,
private_kernel_libipsec_router_t *this, host_t *vip)
{
tun_entry_t *entry, lookup = {
.addr = vip,
};
tun_device_t *tun;
char *name;
if (!vip)
{
return strdup(this->tun.tun->get_name(this->tun.tun));
}
this->lock->read_lock(this->lock);
entry = this->tuns->get(this->tuns, &lookup);
tun = entry ? entry->tun : this->tun.tun;
name = strdup(tun->get_name(tun));
this->lock->unlock(this->lock);
return name;
}
METHOD(kernel_libipsec_router_t, destroy, void,
private_kernel_libipsec_router_t *this)
{
charon->receiver->del_esp_cb(charon->receiver,
(receiver_esp_cb_t)receiver_esp_cb);
ipsec->processor->unregister_outbound(ipsec->processor,
(ipsec_outbound_cb_t)send_esp);
ipsec->processor->unregister_inbound(ipsec->processor,
(ipsec_inbound_cb_t)deliver_plain);
hydra->kernel_interface->remove_listener(hydra->kernel_interface,
&this->public.listener);
this->lock->destroy(this->lock);
this->tuns->destroy(this->tuns);
close(this->notify[0]);
close(this->notify[1]);
router = NULL;
free(this);
}
/**
* Set O_NONBLOCK on the given socket.
*/
static bool set_nonblock(int socket)
{
int flags = fcntl(socket, F_GETFL);
return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1;
}
/*
* See header file
*/
kernel_libipsec_router_t *kernel_libipsec_router_create()
{
private_kernel_libipsec_router_t *this;
INIT(this,
.public = {
.listener = {
.tun = _tun,
},
.get_tun_name = _get_tun_name,
.destroy = _destroy,
},
.tun = {
.tun = lib->get(lib, "kernel-libipsec-tun"),
}
);
if (pipe(this->notify) != 0 ||
!set_nonblock(this->notify[0]) || !set_nonblock(this->notify[1]))
{
DBG1(DBG_KNL, "creating notify pipe for kernel-libipsec router failed");
free(this);
return NULL;
}
this->tun.fd = this->tun.tun->get_fd(this->tun.tun);
this->tuns = hashtable_create((hashtable_hash_t)tun_entry_hash,
(hashtable_equals_t)tun_entry_equals, 4);
this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
hydra->kernel_interface->add_listener(hydra->kernel_interface,
&this->public.listener);
ipsec->processor->register_outbound(ipsec->processor, send_esp, NULL);
ipsec->processor->register_inbound(ipsec->processor,
(ipsec_inbound_cb_t)deliver_plain, this);
charon->receiver->add_esp_cb(charon->receiver,
(receiver_esp_cb_t)receiver_esp_cb, NULL);
lib->processor->queue_job(lib->processor,
(job_t*)callback_job_create((callback_job_cb_t)handle_plain, this,
NULL, (callback_job_cancel_t)return_false));
router = &this->public;
return &this->public;
}
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2013 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_libipsec_router kernel_libipsec_router
* @{ @ingroup kernel_libipsec
*/
#ifndef KERNEL_LIBIPSEC_ROUTER_H_
#define KERNEL_LIBIPSEC_ROUTER_H_
#include <kernel/kernel_listener.h>
typedef struct kernel_libipsec_router_t kernel_libipsec_router_t;
/**
* Class that routes the network packets between TUN device, libipsec and
* charon's IKE socket.
*/
struct kernel_libipsec_router_t {
/**
* Implements kernel_listener_t interface
*/
kernel_listener_t listener;
/**
* Get the name of the TUN device to be used with the given virtual IP.
*
* @param vip virtual IP
* @return allocated name
*/
char *(*get_tun_name)(kernel_libipsec_router_t *this, host_t *vip);
/**
* Destroy the given instance
*/
void (*destroy)(kernel_libipsec_router_t *this);
};
/**
* Single instance of this class, if created
*/
extern kernel_libipsec_router_t *router;
/**
* Create a kernel_libipsec_router_t instance.
*
* @return kernel_libipsec_router_t instance
*/
kernel_libipsec_router_t *kernel_libipsec_router_create();
#endif /** KERNEL_LIBIPSEC_ROUTER_H_ @}*/
@@ -0,0 +1,18 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
-I$(top_srcdir)/src/libcharon
AM_CFLAGS = -rdynamic
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-osx-attr.la
else
plugin_LTLIBRARIES = libstrongswan-osx-attr.la
endif
libstrongswan_osx_attr_la_SOURCES = \
osx_attr_plugin.c osx_attr_plugin.h \
osx_attr_handler.c osx_attr_handler.h
libstrongswan_osx_attr_la_LDFLAGS = -module -avoid-version \
-framework SystemConfiguration -framework CoreFoundation
@@ -0,0 +1,246 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 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 "osx_attr_handler.h"
#include <networking/host.h>
#include <utils/debug.h>
#include <SystemConfiguration/SCDynamicStore.h>
typedef struct private_osx_attr_handler_t private_osx_attr_handler_t;
/**
* Private data of an osx_attr_handler_t object.
*/
struct private_osx_attr_handler_t {
/**
* Public interface
*/
osx_attr_handler_t public;
};
/**
* Create a path to the DNS configuration of the Primary IPv4 Service
*/
static CFStringRef create_dns_path(SCDynamicStoreRef store)
{
CFStringRef service, path = NULL;
CFDictionaryRef dict;
/* get primary service */
dict = SCDynamicStoreCopyValue(store, CFSTR("State:/Network/Global/IPv4"));
if (dict)
{
service = CFDictionaryGetValue(dict, CFSTR("PrimaryService"));
if (service)
{
path = CFStringCreateWithFormat(NULL, NULL,
CFSTR("State:/Network/Service/%@/DNS"), service);
}
else
{
DBG1(DBG_CFG, "SystemConfiguration PrimaryService not known");
}
CFRelease(dict);
}
else
{
DBG1(DBG_CFG, "getting global IPv4 SystemConfiguration failed");
}
return path;
}
/**
* Create a mutable dictionary from path, a new one if not found
*/
static CFMutableDictionaryRef get_dictionary(SCDynamicStoreRef store,
CFStringRef path)
{
CFDictionaryRef dict;
CFMutableDictionaryRef mut = NULL;
dict = SCDynamicStoreCopyValue(store, path);
if (dict)
{
if (CFGetTypeID(dict) == CFDictionaryGetTypeID())
{
mut = CFDictionaryCreateMutableCopy(NULL, 0, dict);
}
CFRelease(dict);
}
if (!mut)
{
mut = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
return mut;
}
/**
* Create a mutable array from dictionary path, a new one if not found
*/
static CFMutableArrayRef get_array_from_dict(CFDictionaryRef dict,
CFStringRef name)
{
CFArrayRef arr;
arr = CFDictionaryGetValue(dict, name);
if (arr && CFGetTypeID(arr) == CFArrayGetTypeID())
{
return CFArrayCreateMutableCopy(NULL, 0, arr);
}
return CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
/**
* Add/Remove a DNS server to the configuration
*/
static bool manage_dns(int family, chunk_t data, bool add)
{
SCDynamicStoreRef store;
CFStringRef path, dns;
CFMutableArrayRef arr;
CFMutableDictionaryRef dict;
CFIndex i;
host_t *server;
char buf[64];
bool success = FALSE;
server = host_create_from_chunk(family, data, 0);
if (!server)
{
return FALSE;
}
snprintf(buf, sizeof(buf), "%H", server);
server->destroy(server);
store = SCDynamicStoreCreate(NULL, CFSTR("osx-attr"), NULL, NULL);
path = create_dns_path(store);
if (path)
{
dict = get_dictionary(store, path);
arr = get_array_from_dict(dict, CFSTR("ServerAddresses"));
dns = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
if (add)
{
DBG1(DBG_CFG, "installing %s as DNS server", buf);
CFArrayInsertValueAtIndex(arr, 0, dns);
}
else
{
i = CFArrayGetFirstIndexOfValue(arr,
CFRangeMake(0, CFArrayGetCount(arr)), dns);
if (i >= 0)
{
DBG1(DBG_CFG, "removing %s from DNS servers (%d)", buf, i);
CFArrayRemoveValueAtIndex(arr, i);
}
}
CFRelease(dns);
CFDictionarySetValue(dict, CFSTR("ServerAddresses"), arr);
CFRelease(arr);
success = SCDynamicStoreSetValue(store, path, dict);
CFRelease(dict);
CFRelease(path);
}
CFRelease(store);
if (!success)
{
DBG1(DBG_CFG, "adding DNS server to SystemConfiguration failed");
}
return success;
}
METHOD(attribute_handler_t, handle, bool,
private_osx_attr_handler_t *this, identification_t *id,
configuration_attribute_type_t type, chunk_t data)
{
switch (type)
{
case INTERNAL_IP4_DNS:
return manage_dns(AF_INET, data, TRUE);
default:
return FALSE;
}
}
METHOD(attribute_handler_t, release, void,
private_osx_attr_handler_t *this, identification_t *server,
configuration_attribute_type_t type, chunk_t data)
{
switch (type)
{
case INTERNAL_IP4_DNS:
manage_dns(AF_INET, data, FALSE);
break;
default:
break;
}
}
METHOD(enumerator_t, enumerate_dns, bool,
enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data)
{
*type = INTERNAL_IP4_DNS;
*data = chunk_empty;
/* stop enumeration */
this->enumerate = (void*)return_false;
return TRUE;
}
METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
private_osx_attr_handler_t *this, identification_t *id,
linked_list_t *vips)
{
enumerator_t *enumerator;
INIT(enumerator,
.enumerate = (void*)_enumerate_dns,
.destroy = (void*)free,
);
return enumerator;
}
METHOD(osx_attr_handler_t, destroy, void,
private_osx_attr_handler_t *this)
{
free(this);
}
/**
* See header
*/
osx_attr_handler_t *osx_attr_handler_create()
{
private_osx_attr_handler_t *this;
INIT(this,
.public = {
.handler = {
.handle = _handle,
.release = _release,
.create_attribute_enumerator = _create_attribute_enumerator,
},
.destroy = _destroy,
},
);
return &this->public;
}
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 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.
*/
/**
* @defgroup osx_attr_handler osx_attr_handler
* @{ @ingroup osx_attr
*/
#ifndef OSX_ATTR_HANDLER_H_
#define OSX_ATTR_HANDLER_H_
#include <attributes/attribute_handler.h>
typedef struct osx_attr_handler_t osx_attr_handler_t;
/**
* OS X specific attribute handler, using SystemConfiguration framework.
*/
struct osx_attr_handler_t {
/**
* Implements attribute_handler_t.
*/
attribute_handler_t handler;
/**
* Destroy a osx_attr_handler_t.
*/
void (*destroy)(osx_attr_handler_t *this);
};
/**
* Create an osx_attr_handler_t instance.
*/
osx_attr_handler_t *osx_attr_handler_create();
#endif /** OSX_ATTR_HANDLER_H_ @}*/
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 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 "osx_attr_plugin.h"
#include "osx_attr_handler.h"
#include <hydra.h>
#include <daemon.h>
typedef struct private_osx_attr_plugin_t private_osx_attr_plugin_t;
/**
* Private data of an osx_attr_plugin_t object.
*/
struct private_osx_attr_plugin_t {
/**
* Public interface
*/
osx_attr_plugin_t public;
/**
* Android specific DNS handler
*/
osx_attr_handler_t *handler;
};
METHOD(plugin_t, get_name, char*,
private_osx_attr_plugin_t *this)
{
return "osx-attr";
}
/**
* Register handler
*/
static bool plugin_cb(private_osx_attr_plugin_t *this,
plugin_feature_t *feature, bool reg, void *cb_data)
{
if (reg)
{
hydra->attributes->add_handler(hydra->attributes,
&this->handler->handler);
}
else
{
hydra->attributes->remove_handler(hydra->attributes,
&this->handler->handler);
}
return TRUE;
}
METHOD(plugin_t, get_features, int,
private_osx_attr_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_CALLBACK((plugin_feature_callback_t)plugin_cb, NULL),
PLUGIN_PROVIDE(CUSTOM, "osx-attr"),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_osx_attr_plugin_t *this)
{
this->handler->destroy(this->handler);
free(this);
}
/**
* See header
*/
plugin_t *osx_attr_plugin_create()
{
private_osx_attr_plugin_t *this;
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.destroy = _destroy,
},
},
.handler = osx_attr_handler_create(),
);
return &this->public.plugin;
}
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 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.
*/
/**
* @defgroup osx_attr osx_attr
* @ingroup cplugins
*
* @defgroup osx_attr_plugin osx_attr_plugin
* @{ @ingroup osx_attr
*/
#ifndef OSX_ATTR_PLUGIN_H_
#define OSX_ATTR_PLUGIN_H_
#include <plugins/plugin.h>
typedef struct osx_attr_plugin_t osx_attr_plugin_t;
/**
* Plugin providing an OS X specific configuration attribute handler.
*/
struct osx_attr_plugin_t {
/**
* Implements plugin interface.
*/
plugin_t plugin;
};
#endif /** OSX_ATTR_PLUGIN_H_ @}*/
+16 -2
View File
@@ -96,6 +96,20 @@ struct private_isakmp_natd_t {
bool dst_matched;
};
/**
* Check if UDP encapsulation has to be forced either by config or required
* by the kernel interface
*/
static bool force_encap(ike_cfg_t *ike_cfg)
{
if (!ike_cfg->force_encap(ike_cfg))
{
return hydra->kernel_interface->get_features(hydra->kernel_interface) &
KERNEL_REQUIRE_UDP_ENCAPSULATION;
}
return TRUE;
}
/**
* Get NAT-D payload type (RFC 3947 or RFC 3947 drafts).
*/
@@ -183,7 +197,7 @@ static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src,
chunk_t hash;
config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (src && config->force_encap(config))
if (src && force_encap(config))
{
hash = generate_natd_hash_faked(this);
}
@@ -297,7 +311,7 @@ static void process_payloads(private_isakmp_natd_t *this, message_t *message)
!this->src_matched);
config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (this->dst_matched && this->src_matched &&
config->force_encap(config))
force_encap(config))
{
this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
}
+16 -3
View File
@@ -78,6 +78,19 @@ struct private_ike_natd_t {
bool mapping_changed;
};
/**
* Check if UDP encapsulation has to be forced either by config or required
* by the kernel interface
*/
static bool force_encap(ike_cfg_t *ike_cfg)
{
if (!ike_cfg->force_encap(ike_cfg))
{
return hydra->kernel_interface->get_features(hydra->kernel_interface) &
KERNEL_REQUIRE_UDP_ENCAPSULATION;
}
return TRUE;
}
/**
* Build NAT detection hash for a host
@@ -147,7 +160,7 @@ static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
ike_sa_id = this->ike_sa->get_id(this->ike_sa);
config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (config->force_encap(config) && type == NAT_DETECTION_SOURCE_IP)
if (force_encap(config) && type == NAT_DETECTION_SOURCE_IP)
{
hash = generate_natd_hash_faked(this);
}
@@ -256,7 +269,7 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
!this->src_matched);
config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (this->dst_matched && this->src_matched &&
config->force_encap(config))
force_encap(config))
{
this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
}
@@ -316,7 +329,7 @@ METHOD(task_t, build_i, status_t,
* 3. Include all possbile addresses
*/
host = message->get_source(message);
if (!host->is_anyaddr(host) || ike_cfg->force_encap(ike_cfg))
if (!host->is_anyaddr(host) || force_encap(ike_cfg))
{ /* 1. or if we force UDP encap, as it doesn't matter if it's %any */
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
if (notify)
+21 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2008-2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2010 revosec AG
@@ -644,6 +644,25 @@ METHOD(kernel_interface_t, roam, void,
this->mutex->unlock(this->mutex);
}
METHOD(kernel_interface_t, tun, void,
private_kernel_interface_t *this, tun_device_t *tun, bool created)
{
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->tun &&
!listener->tun(listener, tun, created))
{
this->listeners->remove_at(this->listeners, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
METHOD(kernel_interface_t, register_algorithm, void,
private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type,
u_int16_t kernel_id, char *kernel_name)
@@ -764,6 +783,7 @@ kernel_interface_t *kernel_interface_create()
.mapping = _mapping,
.migrate = _migrate,
.roam = _roam,
.tun = _tun,
.destroy = _destroy,
},
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+11 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2012 Tobias Brunner
* Copyright (C) 2006-2013 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -67,6 +67,8 @@ enum kernel_feature_t {
KERNEL_ESP_V3_TFC = (1<<0),
/** Networking requires an "exclude" route for IKE/ESP packets */
KERNEL_REQUIRE_EXCLUDE_ROUTE = (1<<1),
/** IPsec implementation requires UDP encapsulation of ESP packets */
KERNEL_REQUIRE_UDP_ENCAPSULATION = (1<<2),
};
/**
@@ -561,6 +563,14 @@ struct kernel_interface_t {
*/
void (*roam)(kernel_interface_t *this, bool address);
/**
* Raise a tun event.
*
* @param tun TUN device
* @param created TRUE if created, FALSE if going to be destroyed
*/
void (*tun)(kernel_interface_t *this, tun_device_t *tun, bool created);
/**
* Register a new algorithm with the kernel interface.
*
+13 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Tobias Brunner
* Copyright (C) 2010-2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -23,9 +23,10 @@
typedef struct kernel_listener_t kernel_listener_t;
#include <kernel/kernel_ipsec.h>
#include <selectors/traffic_selector.h>
#include <networking/host.h>
#include <networking/tun_device.h>
#include <selectors/traffic_selector.h>
#include <kernel/kernel_ipsec.h>
/**
* Interface for components interested in kernel events.
@@ -91,6 +92,15 @@ struct kernel_listener_t {
* @return TRUE to remain registered, FALSE to unregister
*/
bool (*roam)(kernel_listener_t *this, bool address);
/**
* Hook called after a TUN device was created for a virtual IP address, or
* before such a device gets destroyed.
*
* @param tun TUN device
* @param created TRUE if created, FALSE if going to be destroyed
*/
bool (*tun)(kernel_listener_t *this, tun_device_t *tun, bool created);
};
#endif /** KERNEL_LISTENER_H_ @}*/
@@ -265,7 +265,7 @@ static route_entry_t *route_entry_clone(route_entry_t *this)
INIT(route,
.if_name = strdup(this->if_name),
.src_ip = this->src_ip->clone(this->src_ip),
.gateway = this->gateway->clone(this->gateway),
.gateway = this->gateway ? this->gateway->clone(this->gateway) : NULL,
.dst_net = chunk_clone(this->dst_net),
.prefixlen = this->prefixlen,
);
@@ -298,10 +298,14 @@ static u_int route_entry_hash(route_entry_t *this)
*/
static bool route_entry_equals(route_entry_t *a, route_entry_t *b)
{
return a->if_name && b->if_name && streq(a->if_name, b->if_name) &&
a->src_ip->ip_equals(a->src_ip, b->src_ip) &&
a->gateway->ip_equals(a->gateway, b->gateway) &&
chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen;
if (a->if_name && b->if_name && streq(a->if_name, b->if_name) &&
a->src_ip->ip_equals(a->src_ip, b->src_ip) &&
chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen)
{
return (!a->gateway && !b->gateway) || (a->gateway && b->gateway &&
a->gateway->ip_equals(a->gateway, b->gateway));
}
return FALSE;
}
typedef struct net_change_t net_change_t;
@@ -40,6 +40,16 @@
#error Cannot compile this plugin on systems where 'struct sockaddr' has no sa_len member.
#endif
/** properly align sockaddrs */
#ifdef __APPLE__
/* Apple always uses 4 bytes */
#define SA_ALIGN 4
#else
/* while on other platforms like FreeBSD it depends on the architecture */
#define SA_ALIGN sizeof(long)
#endif
#define SA_LEN(len) ((len) > 0 ? (((len)+SA_ALIGN-1) & ~(SA_ALIGN-1)) : SA_ALIGN)
/** delay before firing roam events (ms) */
#define ROAM_DELAY 100
@@ -344,8 +354,9 @@ METHOD(enumerator_t, rt_enumerate, bool,
this->types &= ~type;
*addr = this->addr;
*xtype = i;
this->remaining -= this->addr->sa_len;
this->addr = (void*)this->addr + this->addr->sa_len;
this->remaining -= SA_LEN(this->addr->sa_len);
this->addr = (struct sockaddr*)((char*)this->addr +
SA_LEN(this->addr->sa_len));
return TRUE;
}
}
@@ -510,7 +521,7 @@ static void process_link(private_kernel_pfroute_net_t *this,
{
enumerator_t *enumerator;
iface_entry_t *iface;
bool roam = FALSE, found = FALSE;;
bool roam = FALSE, found = FALSE;
this->lock->write_lock(this->lock);
enumerator = this->ifaces->create_enumerator(this->ifaces);
@@ -812,12 +823,6 @@ METHOD(kernel_net_t, get_interface_name, bool,
return FALSE;
}
METHOD(kernel_net_t, get_source_addr, host_t*,
private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
{
return NULL;
}
METHOD(kernel_net_t, add_ip, status_t,
private_kernel_pfroute_net_t *this, host_t *vip, int prefix,
char *ifname)
@@ -837,7 +842,7 @@ METHOD(kernel_net_t, add_ip, status_t,
{
prefix = vip->get_address(vip).len * 8;
}
if (!tun->set_address(tun, vip, prefix) || !tun->up(tun))
if (!tun->up(tun) || !tun->set_address(tun, vip, prefix))
{
tun->destroy(tun);
return FAILED;
@@ -878,7 +883,10 @@ METHOD(kernel_net_t, add_ip, status_t,
}
}
ifaces->destroy(ifaces);
/* lets do this while holding the lock, thus preventing another thread
* from deleting the TUN device concurrently, hopefully listeneres are quick
* and cause no deadlocks */
hydra->kernel_interface->tun(hydra->kernel_interface, tun, TRUE);
this->lock->unlock(this->lock);
return SUCCESS;
@@ -901,6 +909,8 @@ METHOD(kernel_net_t, del_ip, status_t,
if (addr && addr->ip_equals(addr, vip))
{
this->tuns->remove_at(this->tuns, enumerator);
hydra->kernel_interface->tun(hydra->kernel_interface, tun,
FALSE);
tun->destroy(tun);
found = TRUE;
break;
@@ -942,7 +952,7 @@ static void add_rt_addr(struct rt_msghdr *hdr, int type, host_t *addr)
len = *addr->get_sockaddr_len(addr);
memcpy((char*)hdr + hdr->rtm_msglen, addr->get_sockaddr(addr), len);
hdr->rtm_msglen += len;
hdr->rtm_msglen += SA_LEN(len);
hdr->rtm_addrs |= type;
}
}
@@ -977,7 +987,7 @@ static void add_rt_ifname(struct rt_msghdr *hdr, int type, char *name)
{
memcpy(sdl.sdl_data, name, sdl.sdl_nlen);
memcpy((char*)hdr + hdr->rtm_msglen, &sdl, sdl.sdl_len);
hdr->rtm_msglen += sdl.sdl_len;
hdr->rtm_msglen += SA_LEN(sdl.sdl_len);
hdr->rtm_addrs |= type;
}
}
@@ -1046,13 +1056,14 @@ static status_t manage_route(private_kernel_pfroute_net_t *this, int op,
dst->get_family(dst), prefixlen);
}
break;
case RTAX_GATEWAY:
/* interface name seems to replace gateway on OS X */
case RTAX_IFP:
if (if_name)
{
add_rt_ifname(&msg.hdr, RTA_GATEWAY, if_name);
add_rt_ifname(&msg.hdr, RTA_IFP, if_name);
}
else if (gateway)
break;
case RTAX_GATEWAY:
if (gateway)
{
add_rt_addr(&msg.hdr, RTA_GATEWAY, gateway);
}
@@ -1086,8 +1097,12 @@ METHOD(kernel_net_t, del_route, status_t,
return manage_route(this, RTM_DELETE, dst_net, prefixlen, gateway, if_name);
}
METHOD(kernel_net_t, get_nexthop, host_t*,
private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
/**
* Do a route lookup for dest and return either the nexthop or the source
* address.
*/
static host_t *get_route(private_kernel_pfroute_net_t *this, bool nexthop,
host_t *dest, host_t *src)
{
struct {
struct rt_msghdr hdr;
@@ -1100,7 +1115,7 @@ METHOD(kernel_net_t, get_nexthop, host_t*,
.rtm_seq = ++this->seq,
},
};
host_t *hop = NULL;
host_t *host = NULL;
enumerator_t *enumerator;
struct sockaddr *addr;
int type;
@@ -1116,6 +1131,12 @@ METHOD(kernel_net_t, get_nexthop, host_t*,
case RTAX_IFA:
add_rt_addr(&msg.hdr, RTA_IFA, src);
break;
case RTAX_IFP:
if (!nexthop)
{ /* add an empty IFP to ensure we get a source address */
add_rt_ifname(&msg.hdr, RTA_IFP, "");
}
break;
default:
break;
}
@@ -1144,10 +1165,29 @@ METHOD(kernel_net_t, get_nexthop, host_t*,
sizeof(*this->reply));
while (enumerator->enumerate(enumerator, &type, &addr))
{
if (type == RTAX_GATEWAY)
if (nexthop)
{
hop = host_create_from_sockaddr(addr);
break;
if (type == RTAX_DST && this->reply->rtm_flags & RTF_HOST)
{ /* probably a cloned/cached direct route, only use that
* as fallback if no gateway is found */
host = host ?: host_create_from_sockaddr(addr);
}
if (type == RTAX_GATEWAY)
{ /* could actually be a MAC address */
host_t *gtw = host_create_from_sockaddr(addr);
if (gtw)
{
DESTROY_IF(host);
host = gtw;
}
}
}
else
{
if (type == RTAX_IFA)
{
host = host_create_from_sockaddr(addr);
}
}
}
enumerator->destroy(enumerator);
@@ -1163,7 +1203,24 @@ METHOD(kernel_net_t, get_nexthop, host_t*,
this->condvar->signal(this->condvar);
this->mutex->unlock(this->mutex);
return hop;
if (host)
{
DBG2(DBG_KNL, "using %H as %s to reach %H", host,
nexthop ? "nexthop" : "address", dest);
}
return host;
}
METHOD(kernel_net_t, get_source_addr, host_t*,
private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
{
return get_route(this, FALSE, dest, src);
}
METHOD(kernel_net_t, get_nexthop, host_t*,
private_kernel_pfroute_net_t *this, host_t *dest, host_t *src)
{
return get_route(this, TRUE, dest, src);
}
/**
+17 -2
View File
@@ -225,6 +225,12 @@ METHOD(tun_device_t, write_packet, bool,
{
ssize_t s;
#ifdef __APPLE__
/* UTUN's expect the packets to be prepended by a 32-bit protocol number
* instead of parsing the packet again, we assume IPv4 for now */
u_int32_t proto = htonl(AF_INET);
packet = chunk_cata("cc", chunk_from_thing(proto), packet);
#endif
s = write(this->tunfd, packet.ptr, packet.len);
if (s < 0)
{
@@ -271,6 +277,11 @@ METHOD(tun_device_t, read_packet, bool,
return FALSE;
}
packet->len = len;
#ifdef __APPLE__
/* UTUN's prepend packets with a 32-bit protocol number */
packet->len -= sizeof(u_int32_t);
memmove(packet->ptr, packet->ptr + sizeof(u_int32_t), packet->len);
#endif
return TRUE;
}
@@ -390,14 +401,18 @@ static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
/* this works on FreeBSD and might also work on Linux with older TUN
* driver versions (no IFF_TUN) */
char devname[IFNAMSIZ];
int i;
/* the same process is allowed to open a device again, but that's not what
* we want (unless we previously closed a device, which we don't know at
* this point). therefore, this counter is static so we don't accidentally
* open a device twice */
static int i = -1;
if (name_tmpl)
{
DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported");
}
for (i = 0; i < 256; i++)
for (; ++i < 256; )
{
snprintf(devname, IFNAMSIZ, "/dev/tun%d", i);
this->tunfd = open(devname, O_RDWR);
-1
View File
@@ -474,7 +474,6 @@ METHOD(printf_hook_t, destroy, void,
/* freeing the Vstr_conf of the main thread */
vstr_conf->destroy(vstr_conf);
vstr_conf = NULL;
vstr_free_conf(conf);
vstr_exit();
#endif
free(this);