mirror of https://github.com/Wind4/vlmcsd
parent
9bd3e9c470
commit
af593fc11b
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* TAP-Windows -- A kernel driver to provide virtual tap
|
||||
* device functionality on Windows.
|
||||
*
|
||||
* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
|
||||
*
|
||||
* This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
|
||||
* and is released under the GPL version 2 (see below). This particular file
|
||||
* (tap-windows.h) is also licensed using the MIT license (see COPYRIGHT.MIT).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef __TAP_WIN_H
|
||||
#define __TAP_WIN_H
|
||||
|
||||
/*
|
||||
* =============
|
||||
* TAP IOCTLs
|
||||
* =============
|
||||
*/
|
||||
|
||||
#define TAP_WIN_CONTROL_CODE(request,method) \
|
||||
CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
|
||||
|
||||
/* Present in 8.1 */
|
||||
|
||||
#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED)
|
||||
#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED)
|
||||
|
||||
/* Added in 8.2 */
|
||||
|
||||
/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */
|
||||
#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED)
|
||||
|
||||
/*
|
||||
* =================
|
||||
* Registry keys
|
||||
* =================
|
||||
*/
|
||||
|
||||
#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
||||
|
||||
#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
||||
|
||||
/*
|
||||
* ======================
|
||||
* Filesystem prefixes
|
||||
* ======================
|
||||
*/
|
||||
|
||||
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
|
||||
#define SYSDEVICEDIR "\\Device\\"
|
||||
#define USERDEVICEDIR "\\DosDevices\\Global\\"
|
||||
#define TAP_WIN_SUFFIX ".tap"
|
||||
|
||||
#endif // __TAP_WIN_H
|
||||
|
||||
|
@ -0,0 +1,367 @@
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG
|
||||
#define CONFIG "config.h"
|
||||
#endif // CONFIG
|
||||
#include CONFIG
|
||||
#include "helpers.h"
|
||||
#include "wintap.h"
|
||||
|
||||
#ifndef NO_TAP
|
||||
|
||||
#include "types.h"
|
||||
#include "endian.h"
|
||||
#include "output.h"
|
||||
#include "tap-windows.h"
|
||||
#include <iphlpapi.h>
|
||||
|
||||
static char* szIpAddress = "10.10.10.9";
|
||||
static char* szMask = "30";
|
||||
static char* szTapName;
|
||||
static char *ActiveTapName, *AdapterClass;
|
||||
static char* szLeaseDuration = "1d";
|
||||
static uint32_t IpAddress, Mask, Network, Broadcast, DhcpServer; // These are host-endian (=little-endian) for easier calculations
|
||||
static uint32_t Mtu;
|
||||
static uint_fast8_t Cidr;
|
||||
static HANDLE TapHandle;
|
||||
static TapDriverVersion_t DriverVersion;
|
||||
static IpPacket_t* IpPacket;
|
||||
static uint32_t DhcpLeaseDuration;
|
||||
|
||||
|
||||
static BOOL isAddressAssigned()
|
||||
{
|
||||
PMIB_IPADDRTABLE pIPAddrTable;
|
||||
DWORD dwSize = 0;
|
||||
BOOL result = FALSE;
|
||||
|
||||
pIPAddrTable = (PMIB_IPADDRTABLE)vlmcsd_malloc(sizeof(MIB_IPADDRTABLE));
|
||||
DWORD status = GetIpAddrTable(pIPAddrTable, &dwSize, 0);
|
||||
free(pIPAddrTable);
|
||||
|
||||
if (status != ERROR_INSUFFICIENT_BUFFER) return FALSE;
|
||||
pIPAddrTable = (MIB_IPADDRTABLE *)vlmcsd_malloc(dwSize);
|
||||
|
||||
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0))
|
||||
{
|
||||
free(pIPAddrTable);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PMIB_IPADDRROW row;
|
||||
for (row = pIPAddrTable->table; row < pIPAddrTable->table + pIPAddrTable->dwNumEntries; row++)
|
||||
{
|
||||
if (
|
||||
row->dwAddr == BE32(IpAddress) &&
|
||||
!(row->wType & (MIB_IPADDR_DELETED | MIB_IPADDR_DISCONNECTED | MIB_IPADDR_TRANSIENT))
|
||||
)
|
||||
{
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(pIPAddrTable);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void parseTapArgument(char* argument)
|
||||
{
|
||||
char* equalsignPosition = strchr(argument, (int)'=');
|
||||
char* slashPosition = strchr(argument, (int)'/');
|
||||
char* colonPosition = strchr(argument, (int)':');
|
||||
|
||||
szTapName = argument;
|
||||
|
||||
if (equalsignPosition)
|
||||
{
|
||||
*equalsignPosition = 0;
|
||||
szIpAddress = equalsignPosition + 1;
|
||||
}
|
||||
|
||||
if (slashPosition)
|
||||
{
|
||||
*slashPosition = 0;
|
||||
szMask = slashPosition + 1;
|
||||
}
|
||||
|
||||
if (colonPosition)
|
||||
{
|
||||
*colonPosition = 0;
|
||||
szLeaseDuration = colonPosition + 1;
|
||||
}
|
||||
|
||||
IpAddress = BE32(inet_addr(szIpAddress));
|
||||
|
||||
if (IpAddress == BE32(INADDR_NONE))
|
||||
{
|
||||
printerrorf("Fatal: %s is not a valid IPv4 address\n", szIpAddress);
|
||||
exit(VLMCSD_EINVAL);
|
||||
}
|
||||
|
||||
char* next;
|
||||
Cidr = (uint8_t)strtol(szMask, &next, 10);
|
||||
|
||||
if (*next || Cidr < 8 || Cidr > 30)
|
||||
{
|
||||
printerrorf("Fatal: /%s is not a valid CIDR mask between /8 and /30\n", szMask);
|
||||
exit(VLMCSD_EINVAL);
|
||||
}
|
||||
|
||||
if (!((DhcpLeaseDuration = timeSpanString2Seconds(szLeaseDuration))))
|
||||
{
|
||||
printerrorf("Fatal: No valid time span specified in option -%c.\n", 'O');
|
||||
exit(VLMCSD_EINVAL);
|
||||
}
|
||||
|
||||
Mask = (uint32_t)~(UINT_MAX >> Cidr);
|
||||
Network = IpAddress & Mask;
|
||||
Broadcast = IpAddress | ~Mask;
|
||||
DhcpServer = IpAddress + 1;
|
||||
|
||||
if (IpAddress <= Network || IpAddress + 1 >= Broadcast)
|
||||
{
|
||||
uint32_t lowerIpBE = BE32(Network + 1);
|
||||
uint32_t upperIpBE = BE32(Broadcast - 2);
|
||||
const char* szLower = vlmcsd_strdup(inet_ntoa(*(struct in_addr*)&lowerIpBE));
|
||||
const char* szUpper = vlmcsd_strdup(inet_ntoa(*(struct in_addr*)&upperIpBE));
|
||||
|
||||
printerrorf("Fatal: For this subnet the IPv4 address must be ");
|
||||
|
||||
if (lowerIpBE == upperIpBE)
|
||||
{
|
||||
printerrorf("%s\n", szLower);
|
||||
}
|
||||
else
|
||||
{
|
||||
printerrorf("between %s and %s\n", szLower, szUpper);
|
||||
}
|
||||
|
||||
exit(VLMCSD_EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__noreturn static void WinErrorExit(DWORD error)
|
||||
{
|
||||
printerrorf("Registry read error: %s\n", win_strerror((int)error));
|
||||
exit(error);
|
||||
}
|
||||
|
||||
|
||||
static HANDLE OpenTapHandle()
|
||||
{
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
HKEY regAdapterKey;
|
||||
DWORD regResult;
|
||||
if ((regResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, ®AdapterKey)) != ERROR_SUCCESS)
|
||||
{
|
||||
WinErrorExit(regResult);
|
||||
}
|
||||
|
||||
char subkeyName[TAP_REGISTRY_DATA_SIZE];
|
||||
DWORD i, subKeySize = sizeof(subkeyName);
|
||||
|
||||
for (i = 0; (regResult = RegEnumKeyEx(regAdapterKey, i, subkeyName, &subKeySize, NULL, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS; i++)
|
||||
{
|
||||
HKEY regSubKey;
|
||||
DWORD type, regDataSize;
|
||||
char regData[TAP_REGISTRY_DATA_SIZE];
|
||||
|
||||
if (regResult) WinErrorExit(regResult);
|
||||
|
||||
if ((regResult = RegOpenKeyEx(regAdapterKey, subkeyName, 0, KEY_READ | KEY_WOW64_64KEY, ®SubKey)) == ERROR_SUCCESS)
|
||||
{
|
||||
regDataSize = sizeof(regData);
|
||||
|
||||
if (RegQueryValueEx(regSubKey, "ComponentId", NULL, &type, (LPBYTE)regData, ®DataSize) == ERROR_SUCCESS)
|
||||
{
|
||||
if (
|
||||
type == REG_SZ &&
|
||||
(
|
||||
!strncmp(regData, "tap0801", sizeof(regData)) ||
|
||||
!strncmp(regData, "tap0901", sizeof(regData)) ||
|
||||
!strncmp(regData, "TEAMVIEWERVPN", sizeof(regData))
|
||||
)
|
||||
)
|
||||
{
|
||||
AdapterClass = vlmcsd_strdup(regData);
|
||||
regDataSize = sizeof(regData);
|
||||
|
||||
if (RegQueryValueEx(regSubKey, "NetCfgInstanceId", NULL, &type, (LPBYTE)regData, ®DataSize) == ERROR_SUCCESS && type == REG_SZ)
|
||||
{
|
||||
HKEY connectionKey;
|
||||
char connectionKeyName[TAP_REGISTRY_DATA_SIZE];
|
||||
|
||||
strncpy(connectionKeyName, NETWORK_CONNECTIONS_KEY "\\", sizeof(connectionKeyName));
|
||||
strncat(connectionKeyName, regData, sizeof(connectionKeyName));
|
||||
strncat(connectionKeyName, "\\Connection", sizeof(connectionKeyName));
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, connectionKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &connectionKey) == ERROR_SUCCESS)
|
||||
{
|
||||
char deviceName[TAP_REGISTRY_DATA_SIZE];
|
||||
regDataSize = sizeof(deviceName);
|
||||
|
||||
if (RegQueryValueEx(connectionKey, "Name", NULL, &type, (LPBYTE)deviceName, ®DataSize) == ERROR_SUCCESS && type == REG_SZ)
|
||||
{
|
||||
if (!strcmp(szTapName, ".") || !strncasecmp(szTapName, deviceName, sizeof(deviceName)))
|
||||
{
|
||||
ActiveTapName = vlmcsd_strdup(deviceName);
|
||||
strncpy(deviceName, USERMODEDEVICEDIR, sizeof(deviceName));
|
||||
strncat(deviceName, regData, sizeof(deviceName));
|
||||
strncat(deviceName, strcmp(AdapterClass, "TEAMVIEWERVPN") ? TAP_WIN_SUFFIX : ".dgt", sizeof(deviceName));
|
||||
handle = CreateFile(deviceName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(connectionKey);
|
||||
}
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) free(AdapterClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(regSubKey);
|
||||
subKeySize = sizeof(subkeyName);
|
||||
if (handle != INVALID_HANDLE_VALUE) break;
|
||||
}
|
||||
|
||||
RegCloseKey(regAdapterKey);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printerrorf("Fatal: No compatible VPN adapter");
|
||||
|
||||
if (!strcmp(szTapName, "."))
|
||||
{
|
||||
printerrorf("s");
|
||||
}
|
||||
else
|
||||
{
|
||||
printerrorf(" with name \"%s\"", szTapName);
|
||||
}
|
||||
|
||||
printerrorf(" available for use\n");
|
||||
exit(ERROR_DEVICE_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
static int DevCtl(DWORD code, void* data, DWORD len)
|
||||
{
|
||||
if (!DeviceIoControl(TapHandle, code, data, len, data, len, &len, NULL))
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
printerrorf("Fatal: VPN adapter error: %s\n", win_strerror(error));
|
||||
exit(error);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static DWORD WINAPI TapMirror(LPVOID data)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
DWORD bytesRead, bytesWritten;
|
||||
if (!ReadFile(TapHandle, IpPacket, Mtu, &bytesRead, NULL)) break;
|
||||
|
||||
uint32_t temp = IpPacket->ip_src;
|
||||
IpPacket->ip_src = IpPacket->ip_dst;
|
||||
IpPacket->ip_dst = temp;
|
||||
|
||||
if (!WriteFile(TapHandle, IpPacket, bytesRead, &bytesWritten, NULL)) break;
|
||||
|
||||
# if !defined(NO_LOG) && defined(_PEDANTIC)
|
||||
if (bytesRead != bytesWritten) logger("Warning: VPN device \"%s\": %u bytes could not be written\n", ActiveTapName, bytesRead - bytesWritten);
|
||||
# endif // !defined(NO_LOG) && defined(_PEDANTIC)
|
||||
}
|
||||
|
||||
DWORD error = GetLastError();
|
||||
|
||||
# ifndef NO_LOG
|
||||
logger("Warning: VPN thread for device \"%s\" exiting: %s\n", ActiveTapName, win_strerror(error));
|
||||
# endif // NO_LOG
|
||||
|
||||
free(ActiveTapName);
|
||||
CloseHandle(TapHandle);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void startTap(char* const argument)
|
||||
{
|
||||
if (!strcmp(argument, "-")) return;
|
||||
parseTapArgument(argument);
|
||||
|
||||
TapHandle = OpenTapHandle();
|
||||
|
||||
// Get MTU and driver version
|
||||
DevCtl(TAP_WIN_IOCTL_GET_MTU, &Mtu, sizeof(Mtu));
|
||||
DevCtl(TAP_WIN_IOCTL_GET_VERSION, &DriverVersion, sizeof(DriverVersion));
|
||||
|
||||
// Configure TUN mode
|
||||
TapConfigTun_t tapTunCfg;
|
||||
tapTunCfg.Address.s_addr = BE32(IpAddress);
|
||||
tapTunCfg.Network.s_addr = BE32(Network);
|
||||
tapTunCfg.Mask.s_addr = BE32(Mask);
|
||||
DevCtl(TAP_WIN_IOCTL_CONFIG_TUN, &tapTunCfg, sizeof(tapTunCfg));
|
||||
|
||||
// Setup the drivers internal DHCP server
|
||||
TapConfigDhcp_t tapDhcpCfg;
|
||||
tapDhcpCfg.Address.s_addr = BE32(IpAddress);
|
||||
tapDhcpCfg.Mask.s_addr = BE32(Mask);
|
||||
tapDhcpCfg.DhcpServer.s_addr = BE32(IpAddress + 1);
|
||||
tapDhcpCfg.LeaseDuration = DhcpLeaseDuration;
|
||||
DevCtl(TAP_WIN_IOCTL_CONFIG_DHCP_MASQ, &tapDhcpCfg, sizeof(tapDhcpCfg));
|
||||
|
||||
// Connect the virtual network cable
|
||||
BOOL isCableConnected = TRUE;
|
||||
DevCtl(TAP_WIN_IOCTL_SET_MEDIA_STATUS, &isCableConnected, sizeof(isCableConnected));
|
||||
|
||||
// Allocate buffer and start mirror thread
|
||||
IpPacket = (IpPacket_t*)vlmcsd_malloc(Mtu);
|
||||
HANDLE threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TapMirror, NULL, 0, NULL);
|
||||
|
||||
if (!threadHandle)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
printerrorf("Fatal: Unable to start VPN thread: %s\n", win_strerror(error));
|
||||
exit(error);
|
||||
}
|
||||
|
||||
CloseHandle(threadHandle);
|
||||
|
||||
# ifndef NO_LOG
|
||||
logger("%s %u.%u.%u device \"%s\" started\n", AdapterClass, DriverVersion.Major, DriverVersion.Minor, DriverVersion.Build, ActiveTapName);
|
||||
# endif // NO_LOG
|
||||
|
||||
DWORD i;
|
||||
BOOL isAssigned;
|
||||
|
||||
// Wait up to 4 seconds until the IP address is up and running
|
||||
// so vlmcsd can actually bind to and listen on it
|
||||
for (i = 0; !((isAssigned = isAddressAssigned())) && i < 20; i++) Sleep(200);
|
||||
|
||||
if (!isAssigned)
|
||||
{
|
||||
printerrorf("Warning: IPv4 address %s not assigned\n", szIpAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
# ifndef NO_LOG
|
||||
logger("IPv4 address %s assigned\n", szIpAddress);
|
||||
# endif // NO_LOG
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NO_TAP
|
||||
|
@ -0,0 +1,50 @@
|
||||
#ifndef __WINTAP_H
|
||||
#define __WINTAP_H
|
||||
|
||||
#define TAP_REGISTRY_DATA_SIZE 256
|
||||
|
||||
// Network-Endian (= Big-Endian)
|
||||
typedef struct TapConfigTun
|
||||
{
|
||||
struct in_addr Address;
|
||||
struct in_addr Network;
|
||||
struct in_addr Mask;
|
||||
} TapConfigTun_t, *PTapConfigTun_t;
|
||||
|
||||
// Network-Endian (= Big-Endian), except LeaseDuration
|
||||
typedef struct TapConfigDhcp
|
||||
{
|
||||
struct in_addr Address;
|
||||
struct in_addr Mask;
|
||||
struct in_addr DhcpServer;
|
||||
uint32_t LeaseDuration; // Host-Endian (=Little-Endian). Anything else is Big-Endian
|
||||
} TapConfigDhcp_t, *PTapConfigDhcp_t;
|
||||
|
||||
typedef struct TapDriverVersion
|
||||
{
|
||||
uint32_t Major;
|
||||
uint32_t Minor;
|
||||
uint32_t Build;
|
||||
uint32_t Revision;
|
||||
} TapDriverVersion_t, *PTapDriverVersion_t;
|
||||
|
||||
// Network-Endian (= Big-Endian)
|
||||
typedef struct IpPacket {
|
||||
uint8_t ip_hl : 4, /* header length */
|
||||
ip_v : 4; /* version */
|
||||
uint8_t ip_tos; /* type of service */
|
||||
int16_t ip_len; /* total length */
|
||||
uint16_t ip_id; /* identification */
|
||||
int16_t ip_off; /* fragment offset field */
|
||||
uint8_t ip_ttl; /* time to live */
|
||||
uint8_t ip_p; /* protocol */
|
||||
uint16_t ip_sum; /* checksum */
|
||||
uint32_t ip_src, ip_dst; /* source and dest address */
|
||||
uint8_t payload[0];
|
||||
} IpPacket_t, *PIpPacket_t;
|
||||
|
||||
void startTap(char* const argument);
|
||||
|
||||
#endif //__WINTAP_H
|
||||
|
||||
|
Loading…
Reference in New Issue