| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- #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>
- #if !_WIN32
- #include <arpa/inet.h>
- #endif // !_WIN32
- 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)~(0xffffffff >> 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_unused)
- {
- 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);
- exitOnWarningLevel(1);
- 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
|