*/
#include "kernel_utun_ipsec.h"
-#include "kernel_utun_net.h"
#include <errno.h>
#include <fcntl.h>
mutex_t *mutex;
/**
- * Next SPI to allocate
+ * List of tun devices, as tun_device_t
*/
- u_int32_t spi;
+ linked_list_t *tuns;
};
METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
return 0;
}
+/**
+ * Enable IPsec crypt extension on utun device
+ */
+static bool enable_crypto(tun_device_t *tun)
+{
+ utun_crypto_args_t args = {
+ .ver = UTUN_CRYPTO_VER_1,
+ .type = UTUN_CRYPTO_TYPE_IPSEC,
+ .args_ulen = sizeof(utun_crypto_ipsec_args_v1_t),
+ .u = {
+ .ipsec_v1 = {
+ /* nothing to set */
+ },
+ },
+ };
+ if (setsockopt(tun->get_fd(tun), SYSPROTO_CONTROL, UTUN_OPT_ENABLE_CRYPTO,
+ &args, sizeof(args)) < 0)
+ {
+ DBG1(DBG_KNL, "enabling crypto on %s failed: %s",
+ tun->get_name(tun), strerror(errno));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Allocate an SPI on the given tun device
+ */
+static bool alloc_spi(tun_device_t *tun, host_t *src, host_t *dst,
+ u_int32_t reqid, u_int32_t *spi)
+{
+ utun_crypto_keys_idx_args_t args = {
+ .ver = UTUN_CRYPTO_VER_1,
+ .type = UTUN_CRYPTO_TYPE_IPSEC,
+ .dir = UTUN_CRYPTO_DIR_IN,
+ .args_ulen = sizeof(utun_crypto_keys_idx_ipsec_args_v1_t),
+ .u = {
+ .ipsec_v1 = {
+ .proto = IF_UTUN_CRYPTO_IPSEC_PROTO_ESP,
+ .mode = IF_UTUN_CRYPTO_IPSEC_MODE_TUNNEL,
+ .reqid = reqid,
+ .spirange_min = 0xd0000000,
+ .spirange_max = 0xdfffffff,
+ },
+ },
+ };
+ socklen_t len;
+
+ len = sizeof(args);
+ if (getsockopt(tun->get_fd(tun), SYSPROTO_CONTROL,
+ UTUN_OPT_GENERATE_CRYPTO_KEYS_IDX, &args, &len) < 0 ||
+ len != sizeof(args))
+ {
+ DBG1(DBG_KNL, "allocating SPI on %s failed: %s",
+ tun->get_name(tun), strerror(errno));
+ return FALSE;
+ }
+ *spi = htonl(args.u.ipsec_v1.spi);
+ return TRUE;
+}
+
METHOD(kernel_ipsec_t, get_spi, status_t,
private_kernel_utun_ipsec_t *this, host_t *src, host_t *dst,
u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
{
+ tun_device_t *tun;
+
+ if (protocol != IPPROTO_ESP)
+ {
+ return NOT_SUPPORTED;
+ }
+ tun = tun_device_create(NULL);
+ if (!tun)
+ {
+ return FAILED;
+ }
+ if (!enable_crypto(tun) || !alloc_spi(tun, src, dst, reqid, spi))
+ {
+ tun->destroy(tun);
+ return FAILED;
+ }
+
this->mutex->lock(this->mutex);
- *spi = this->spi++;
+ this->tuns->insert_last(this->tuns, tun);
this->mutex->unlock(this->mutex);
return SUCCESS;
.replay = 32,
.key_auth_len = int_key.len * 8,
.key_enc_len = enc_key.len * 8,
- .spi = spi,
+ .spi = ntohl(spi),
.pid = getpid(),
.reqid = reqid,
.lifetime_hard = hard,
}
ts = inbound ? dst_ts : src_ts;
- enumerator = kernel_utun_create_enumerator();
+ this->mutex->lock(this->mutex);
+ enumerator = this->tuns->create_enumerator(this->tuns);
while (enumerator->enumerate(enumerator, &tun))
{
host = tun->get_address(tun, NULL);
}
}
enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
return status;
}
return FALSE;
}
+METHOD(kernel_utun_ipsec_t, add_ip, status_t,
+ private_kernel_utun_ipsec_t *this, host_t *vip, int prefix)
+{
+ tun_device_t *tun;
+ bool added = FALSE;
+
+ if (prefix == -1)
+ {
+ switch (vip->get_family(vip))
+ {
+ case AF_INET:
+ prefix = 32;
+ break;
+ case AF_INET6:
+ prefix = 128;
+ break;
+ default:
+ return NOT_SUPPORTED;
+ }
+ }
+ this->mutex->lock(this->mutex);
+ if (this->tuns->get_last(this->tuns, (void**)&tun) == SUCCESS)
+ {
+ added = tun->set_address(tun, vip, prefix);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (added)
+ {
+ return SUCCESS;
+ }
+ return FAILED;
+}
+
+METHOD(kernel_utun_ipsec_t, del_ip, status_t,
+ private_kernel_utun_ipsec_t *this, host_t *vip, int prefix)
+{
+ enumerator_t *enumerator;
+ tun_device_t *tun;
+ host_t *host;
+ bool found;
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->tuns->create_enumerator(this->tuns);
+ while (enumerator->enumerate(enumerator, &tun))
+ {
+ host = tun->get_address(tun, NULL);
+ if (host && host->ip_equals(host, vip))
+ {
+ this->tuns->remove_at(this->tuns, enumerator);
+ tun->destroy(tun);
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+
+ if (found)
+ {
+ return SUCCESS;
+ }
+ return NOT_FOUND;
+}
+
+/**
+ * Globally referencable instance of kernek_utun_ipsec instance
+ */
+static kernel_utun_ipsec_t *singleton;
+
+/**
+ * See header.
+ */
+kernel_utun_ipsec_t *kernel_utun_ipsec_get()
+{
+ return singleton;
+}
+
METHOD(kernel_ipsec_t, destroy, void,
private_kernel_utun_ipsec_t *this)
{
+ singleton = NULL;
+ this->tuns->destroy_offset(this->tuns, offsetof(tun_device_t, destroy));
this->mutex->destroy(this->mutex);
free(this);
}
.enable_udp_decap = _enable_udp_decap,
.destroy = _destroy,
},
+ .add_ip = _add_ip,
+ .del_ip = _del_ip,
},
+ .tuns = linked_list_create(),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
- /* initialize to "charon-style" SPIs with a leading "c" */
- .spi = 0xc0000000,
);
+ singleton = &this->public;
return &this->public;
}
#include <sys/socket.h>
#include <ifaddrs.h>
#include <errno.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <net/if.h>
-#include <net/if.h>
-#include <net/if_utun.h>
-#include <net/if_utun_crypto.h>
-#include <net/if_utun_crypto_ipsec.h>
-#include <netinet/in_var.h>
-#include <sys/kern_control.h>
#include "kernel_utun_net.h"
+#include "kernel_utun_ipsec.h"
#include <hydra.h>
#include <utils/debug.h>
-#include <collections/linked_list.h>
-#include <threading/mutex.h>
-#include <networking/tun_device.h>
typedef struct private_kernel_utun_net_t private_kernel_utun_net_t;
* Public part of the kernel_utun_net_t object.
*/
kernel_utun_net_t public;
-
- /**
- * Mutex to access tun list
- */
- mutex_t *mutex;
-
- /**
- * List of tun devices, as tun_device_t
- */
- linked_list_t *tuns;
};
METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
return NULL;
}
-/**
- * Enable IPsec crypt extension on utun device
- */
-static bool enable_crypto(tun_device_t *tun)
-{
- utun_crypto_args_t args = {
- .ver = UTUN_CRYPTO_VER_1,
- .type = UTUN_CRYPTO_TYPE_IPSEC,
- .args_ulen = sizeof(utun_crypto_ipsec_args_v1_t),
- .u = {
- .ipsec_v1 = {
- /* nothing to set */
- },
- },
- };
- if (setsockopt(tun->get_fd(tun), SYSPROTO_CONTROL, UTUN_OPT_ENABLE_CRYPTO,
- &args, sizeof(args)) < 0)
- {
- DBG1(DBG_KNL, "enabling crypto on %s failed: %s",
- tun->get_name(tun), strerror(errno));
- return FALSE;
- }
- return TRUE;
-}
-
METHOD(kernel_net_t, add_ip, status_t,
private_kernel_utun_net_t *this, host_t *virtual_ip, int prefix,
char *iface_name)
{
- tun_device_t *tun;
+ kernel_utun_ipsec_t *ipsec;
- if (prefix == -1)
- {
- switch (virtual_ip->get_family(virtual_ip))
- {
- case AF_INET:
- prefix = 32;
- break;
- case AF_INET6:
- prefix = 128;
- break;
- default:
- return NOT_SUPPORTED;
- }
- }
- tun = tun_device_create(NULL);
- if (!tun)
- {
- return FAILED;
- }
- if (!tun->set_address(tun, virtual_ip, prefix) || !enable_crypto(tun))
+ ipsec = kernel_utun_ipsec_get();
+ if (ipsec)
{
- tun->destroy(tun);
- return FAILED;
+ return ipsec->add_ip(ipsec, virtual_ip, prefix);
}
- this->mutex->lock(this->mutex);
- this->tuns->insert_last(this->tuns, tun);
- this->mutex->unlock(this->mutex);
- return SUCCESS;
+ return FAILED;
}
METHOD(kernel_net_t, del_ip, status_t,
private_kernel_utun_net_t *this, host_t *virtual_ip, int prefix,
bool wait)
{
- enumerator_t *enumerator;
- tun_device_t *tun;
- host_t *host;
- bool found;
+ kernel_utun_ipsec_t *ipsec;
- this->mutex->lock(this->mutex);
- enumerator = this->tuns->create_enumerator(this->tuns);
- while (enumerator->enumerate(enumerator, &tun))
+ ipsec = kernel_utun_ipsec_get();
+ if (ipsec)
{
- host = tun->get_address(tun, NULL);
- if (host && host->ip_equals(host, virtual_ip))
- {
- this->tuns->remove_at(this->tuns, enumerator);
- tun->destroy(tun);
- found = TRUE;
- break;
- }
+ return ipsec->del_ip(ipsec, virtual_ip, prefix);
}
- enumerator->destroy(enumerator);
- this->mutex->unlock(this->mutex);
-
- if (found)
- {
- return SUCCESS;
- }
- return NOT_FOUND;
+ return FAILED;
}
METHOD(kernel_net_t, add_route, status_t,
return FAILED;
}
-/**
- * Globally referencable instance of kernek_utun_net instance
- */
-static private_kernel_utun_net_t *singleton;
-
METHOD(kernel_net_t, destroy, void,
private_kernel_utun_net_t *this)
{
- singleton = NULL;
- this->tuns->destroy_offset(this->tuns, offsetof(tun_device_t, destroy));
- this->mutex->destroy(this->mutex);
free(this);
}
-
/*
* Described in header.
*/
.destroy = _destroy,
},
},
- .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
- .tuns = linked_list_create(),
);
- singleton = this;
return &this->public;
}
-
-/**
- * See header.
- */
-enumerator_t *kernel_utun_create_enumerator()
-{
- if (singleton)
- {
- singleton->mutex->lock(singleton->mutex);
- return enumerator_create_cleaner(
- singleton->tuns->create_enumerator(singleton->tuns),
- (void*)singleton->mutex->unlock, singleton->mutex);
- }
- return enumerator_create_empty();
-}