From fb696286c83094d38375bb1d9247c4a28d1f4d35 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Thu, 2 Feb 2023 20:39:38 +0100 Subject: [PATCH] wintun: Plugin implementing Wintun TUN device --- configure.ac | 4 + .../kernel_libipsec/kernel_libipsec_router.c | 10 + src/libstrongswan/Makefile.am | 7 + src/libstrongswan/plugins/wintun/Makefile.am | 19 ++ .../plugins/wintun/wintun_device.c | 275 ++++++++++++++++++ .../plugins/wintun/wintun_device.h | 60 ++++ .../plugins/wintun/wintun_plugin.c | 83 ++++++ .../plugins/wintun/wintun_plugin.h | 43 +++ 8 files changed, 501 insertions(+) create mode 100644 src/libstrongswan/plugins/wintun/Makefile.am create mode 100644 src/libstrongswan/plugins/wintun/wintun_device.c create mode 100644 src/libstrongswan/plugins/wintun/wintun_device.h create mode 100644 src/libstrongswan/plugins/wintun/wintun_plugin.c create mode 100644 src/libstrongswan/plugins/wintun/wintun_plugin.h diff --git a/configure.ac b/configure.ac index 7bca05a832..b27146176e 100644 --- a/configure.ac +++ b/configure.ac @@ -226,6 +226,7 @@ ARG_ENABL_SET([xauth-eap], [enable XAuth backend using EAP methods to verif ARG_ENABL_SET([xauth-pam], [enable XAuth backend using PAM to verify passwords.]) ARG_ENABL_SET([xauth-noauth], [enable XAuth pseudo-backend that does not actually verify or even request any credentials.]) # kernel interfaces / sockets +ARG_ENABL_SET([wintun], [enables the Windows TUN device plugin.]) 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.]) @@ -1587,6 +1588,7 @@ ADD_PLUGIN([winhttp], [s charon pki scripts]) ADD_PLUGIN([soup], [s charon pki scripts nm cmd]) ADD_PLUGIN([mysql], [s charon pool manager medsrv attest]) ADD_PLUGIN([sqlite], [s charon pool manager medsrv attest]) +ADD_PLUGIN([wintun], [s charon]) ADD_PLUGIN([attr], [c charon]) ADD_PLUGIN([attr-sql], [c charon]) ADD_PLUGIN([load-tester], [c charon]) @@ -1750,6 +1752,7 @@ AM_CONDITIONAL(USE_NTRU, test x$ntru = xtrue) AM_CONDITIONAL(USE_NEWHOPE, test x$newhope = xtrue) AM_CONDITIONAL(USE_BLISS, test x$bliss = xtrue) AM_CONDITIONAL(USE_DRBG, test x$drbg = xtrue) +AM_CONDITIONAL(USE_WINTUN, test x$wintun = xtrue) # charon plugins # ---------------- @@ -2034,6 +2037,7 @@ AC_CONFIG_FILES([ src/libstrongswan/plugins/newhope/Makefile src/libstrongswan/plugins/newhope/tests/Makefile src/libstrongswan/plugins/test_vectors/Makefile + src/libstrongswan/plugins/wintun/Makefile src/libstrongswan/tests/Makefile src/libipsec/Makefile src/libipsec/tests/Makefile diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c index 884616345f..476eb2bc79 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c @@ -307,6 +307,7 @@ METHOD(kernel_libipsec_router_t, destroy, void, free(this); } +#ifndef WIN32 /** * Set O_NONBLOCK on the given socket. */ @@ -315,6 +316,7 @@ static bool set_nonblock(int socket) int flags = fcntl(socket, F_GETFL); return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1; } +#endif /* * See header file @@ -322,6 +324,9 @@ static bool set_nonblock(int socket) kernel_libipsec_router_t *kernel_libipsec_router_create() { private_kernel_libipsec_router_t *this; +#ifdef WIN32 + u_long on = 1; +#endif INIT(this, .public = { @@ -336,8 +341,13 @@ kernel_libipsec_router_t *kernel_libipsec_router_create() } ); +#ifdef WIN32 + if (socketpair(AF_INET, SOCK_STREAM, 0, this->notify) != 0 || + ioctlsocket(this->notify[0], FIONBIO, &on) != 0) +#else /* !WIN32 */ if (pipe(this->notify) != 0 || !set_nonblock(this->notify[0]) || !set_nonblock(this->notify[1])) +#endif /* !WIN332 */ { DBG1(DBG_KNL, "creating notify pipe for kernel-libipsec router failed"); free(this); diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index b3e4f777d7..f3a9c3e0fa 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -697,6 +697,13 @@ if MONOLITHIC endif endif +if USE_WINTUN + SUBDIRS += plugins/wintun +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/wintun/libstrongswan-wintun.la +endif +endif + if MONOLITHIC SUBDIRS += . endif diff --git a/src/libstrongswan/plugins/wintun/Makefile.am b/src/libstrongswan/plugins/wintun/Makefile.am new file mode 100644 index 0000000000..2a80d010fc --- /dev/null +++ b/src/libstrongswan/plugins/wintun/Makefile.am @@ -0,0 +1,19 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = \ + $(PLUGIN_CFLAGS) + +noinst_LTLIBRARIES = +if MONOLITHIC +noinst_LTLIBRARIES += libstrongswan-wintun.la +else +plugin_LTLIBRARIES = libstrongswan-wintun.la +endif + +libstrongswan_wintun_la_SOURCES = \ + wintun_plugin.h wintun_plugin.c \ + wintun_device.h wintun_device.c + +libstrongswan_wintun_la_LDFLAGS = -module -avoid-version + diff --git a/src/libstrongswan/plugins/wintun/wintun_device.c b/src/libstrongswan/plugins/wintun/wintun_device.c new file mode 100644 index 0000000000..8b35fd1eac --- /dev/null +++ b/src/libstrongswan/plugins/wintun/wintun_device.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2023 Andreas Steffen + * + * Copyright (C) secunet Security Networks 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 . + * + * 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. + */ + +#ifdef WIN32 +#include +#endif + +#include "wintun_device.h" + +#include + +#ifndef WIN32 + +wintun_device_t *wintun_device_create(const char *name_tmpl) +{ + DBG1(DBG_LIB, "Wintun devices not supported"); + return NULL; +} + +bool wintun_library_init() +{ + DBG1(DBG_LIB, "Wintun library not supported"); + return TRUE; +} + +void wintun_library_deinit() +{ +} + +#else /* WIN32 */ + +/** + * Functions offered by the Wintun dynamic library + */ +static WINTUN_CREATE_ADAPTER_FUNC *WintunCreateAdapter; +static WINTUN_CLOSE_ADAPTER_FUNC *WintunCloseAdapter; +static WINTUN_OPEN_ADAPTER_FUNC *WintunOpenAdapter; +static WINTUN_GET_ADAPTER_LUID_FUNC *WintunGetAdapterLUID; +static WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC *WintunGetRunningDriverVersion; +static WINTUN_DELETE_DRIVER_FUNC *WintunDeleteDriver; +static WINTUN_SET_LOGGER_FUNC *WintunSetLogger; +static WINTUN_START_SESSION_FUNC *WintunStartSession; +static WINTUN_END_SESSION_FUNC *WintunEndSession; +static WINTUN_GET_READ_WAIT_EVENT_FUNC *WintunGetReadWaitEvent; +static WINTUN_RECEIVE_PACKET_FUNC *WintunReceivePacket; +static WINTUN_RELEASE_RECEIVE_PACKET_FUNC *WintunReleaseReceivePacket; +static WINTUN_ALLOCATE_SEND_PACKET_FUNC *WintunAllocateSendPacket; +static WINTUN_SEND_PACKET_FUNC *WintunSendPacket; + +static HMODULE Wintun; + +#define IFNAMSIZ 16 +#define TUN_DEFAULT_MTU 1500 + +typedef struct private_wintun_device_t private_wintun_device_t; + +struct private_wintun_device_t { + + /** + * Public interface + */ + wintun_device_t public; + + /** + * The Wintun device's file descriptor + */ + int tunfd; + + /** + * Name of the Wintun device + */ + char if_name[IFNAMSIZ]; + + /** + * The current MTU + */ + int mtu; + + /** + * Associated address + */ + host_t *address; + + /** + * Netmask for address + */ + uint8_t netmask; + + /* + * Wintun adapter handle + */ + WINTUN_ADAPTER_HANDLE Adapter; + +}; + +METHOD(tun_device_t, set_address, bool, + private_wintun_device_t *this, host_t *addr, uint8_t netmask) +{ + this->address = addr->clone(addr); + this->netmask = netmask; + + return TRUE; +} + +METHOD(tun_device_t, get_address, host_t*, + private_wintun_device_t *this, uint8_t *netmask) +{ + if (netmask && this->address) + { + *netmask = this->netmask; + } + return this->address; +} + +METHOD(tun_device_t, up, bool, + private_wintun_device_t *this) +{ + return TRUE; +} + +METHOD(tun_device_t, set_mtu, bool, + private_wintun_device_t *this, int mtu) +{ + this->mtu = mtu; + + return TRUE; +} + +METHOD(tun_device_t, get_mtu, int, + private_wintun_device_t *this) +{ + return this->mtu; +} + +METHOD(tun_device_t, get_name, char*, + private_wintun_device_t *this) +{ + return this->if_name; +} + +METHOD(tun_device_t, get_fd, int, + private_wintun_device_t *this) +{ + return this->tunfd; +} + +METHOD(tun_device_t, write_packet, bool, + private_wintun_device_t *this, chunk_t packet) +{ + return TRUE; +} + +METHOD(tun_device_t, read_packet, bool, + private_wintun_device_t *this, chunk_t *packet) +{ + return TRUE; +} + +METHOD(tun_device_t, destroy, void, + private_wintun_device_t *this) +{ + WintunCloseAdapter(this->Adapter); + free(this); +} + +/** + * Initialize the Windows TUN device + */ +static bool init_wintun(private_wintun_device_t *this, const char *name_tmpl) +{ + DWORD Version; + GUID Guid; + + Guid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } }; + this->Adapter = WintunCreateAdapter(L"strongSwan", L"Wintun", &Guid); + if (!Adapter) + { + DBG1(DBG_LIB,"could not create Wintun adapter"); + return FALSE; + } + this->ifname = "strongSwan"; + Version = WintunGetRunningDriverVersion(); + DBG1(DBG_LIB, "Wintun adapter v%u.%u loaded", + (Version >> 16) & 0xff, (Version >> 0) & 0xff); + return TRUE; +} + +/* + * Described in header + */ +wintun_device_t *wintun_device_create(const char *name_tmpl) +{ + private_wintun_device_t *this; + + INIT(this, + .public = { + .tun = { + .read_packet = _read_packet, + .write_packet = _write_packet, + .get_mtu = _get_mtu, + .set_mtu = _set_mtu, + .get_name = _get_name, + .get_fd = _get_fd, + .set_address = _set_address, + .get_address = _get_address, + .up = _up, + .destroy = _destroy, + }, + }, + ); + + if (!init_wintun(this, name_tmpl)) + { + free(this); + return NULL; + } + DBG1(DBG_LIB, "created Wintun device: %s", this->if_name); + + return &this->public; +} + +/* + * Described in header + */ +bool wintun_library_init() +{ + Wintun = LoadLibraryExW(L"wintun.dll", NULL, + LOAD_LIBRARY_SEARCH_APPLICATION_DIR | + LOAD_LIBRARY_SEARCH_SYSTEM32); + if (!Wintun) + { + DBG1(DBG_LIB, "failed to load Wintun library"); + return FALSE; + } + +#define X(Name) ((*(FARPROC *)&Name = GetProcAddress(Wintun, #Name)) == NULL) + if (X(WintunCreateAdapter) || X(WintunCloseAdapter) || + X(WintunOpenAdapter) || X(WintunGetAdapterLUID) || + X(WintunGetRunningDriverVersion) || X(WintunDeleteDriver) || + X(WintunSetLogger) || X(WintunStartSession) || + X(WintunEndSession) || X(WintunGetReadWaitEvent) || + X(WintunReceivePacket) || X(WintunReleaseReceivePacket) || + X(WintunAllocateSendPacket) || X(WintunSendPacket)) +#undef X + { + FreeLibrary(Wintun); + DBG1(DBG_LIB, "failed to initialize Wintun library"); + return FALSE; + } + DBG1(DBG_LIB, "Wintun library loaded and initialized"); + return TRUE; +} + +/* + * Described in header + */ +void wintun_library_deinit() +{ + FreeLibrary(Wintun); +} + +#endif /* WIN32 */ diff --git a/src/libstrongswan/plugins/wintun/wintun_device.h b/src/libstrongswan/plugins/wintun/wintun_device.h new file mode 100644 index 0000000000..871c5b439a --- /dev/null +++ b/src/libstrongswan/plugins/wintun/wintun_device.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 Andreas Steffen + * + * Copyright (C) secunet Security Networks 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 . + * + * 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 wintun_device wintun_device + * @{ @ingroup wintun_p + */ + +#ifndef WINTUN_DEVICE_H_ +#define WINTUN_DEVICE_H_ + +#include + +typedef struct wintun_device_t wintun_device_t; + +/** + * Windows TUN device implementation + */ +struct wintun_device_t { + + /** + * Generic tun_device_t interface. + */ + tun_device_t tun; +}; + +/** + * Create a Windows TUN device using the given name template. + * + * @param name_tmpl name template, defaults to "tun%d" if not given + * @return Windows TUN device + */ +wintun_device_t *wintun_device_create(const char *name_tmpl); + +/** + * Initialize wintun library. + * + * @return FALSE if library initialization failed + */ +bool wintun_library_init(); + +/** + * Deinitialize wintun library. + */ +void wintun_library_deinit(); + +#endif /** WINTUN_DEVICE_H_ @}*/ diff --git a/src/libstrongswan/plugins/wintun/wintun_plugin.c b/src/libstrongswan/plugins/wintun/wintun_plugin.c new file mode 100644 index 0000000000..479a885ff9 --- /dev/null +++ b/src/libstrongswan/plugins/wintun/wintun_plugin.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2023 Andreas Steffen + * + * Copyright (C) secunet Security Networks 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 . + * + * 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 "wintun_plugin.h" +#include "wintun_device.h" + +#include + +typedef struct private_wintun_plugin_t private_wintun_plugin_t; + +/** + * Private data of a wintun_plugin_t object. + */ +struct private_wintun_plugin_t { + + /** + * Public interface. + */ + wintun_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_wintun_plugin_t *this) +{ + return "wintun"; +} + +METHOD(plugin_t, get_features, int, + private_wintun_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_REGISTER(TUN_DEVICE, wintun_device_create), + PLUGIN_PROVIDE(TUN_DEVICE), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_wintun_plugin_t *this) +{ + wintun_library_deinit(); + free(this); +} + +/* + * see header file + */ +plugin_t *wintun_plugin_create(void) +{ + private_wintun_plugin_t *this; + + if (!wintun_library_init()) + { + return NULL; + } + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} + diff --git a/src/libstrongswan/plugins/wintun/wintun_plugin.h b/src/libstrongswan/plugins/wintun/wintun_plugin.h new file mode 100644 index 0000000000..ea693fc0eb --- /dev/null +++ b/src/libstrongswan/plugins/wintun/wintun_plugin.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 Andreas Steffen + * + * Copyright (C) secunet Security Networks 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 . + * + * 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 wintun_p wintun + * @ingroup plugins + * + * @defgroup wintun_plugin wintun_plugin + * @{ @ingroup wintun_p + */ + +#ifndef WINTUN_PLUGIN_H_ +#define WINTUN_PLUGIN_H_ + +#include + +typedef struct wintun_plugin_t wintun_plugin_t; + +/** + * Plugin providing a Windows TUN device + */ +struct wintun_plugin_t { + + /** + * Implements plugin interface. + */ + plugin_t plugin; +}; + +#endif /** WINTUN_PLUGIN_H_ @}*/ -- 2.47.2