#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wginterface.hh" const DEVPROPKEY devpkey_name = { { 0x65726957, 0x7547, 0x7261, { 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79 } }, DEVPROPID_FIRST_USABLE + 1 }; #define IFNAMSIZ MAX_ADAPTER_NAME - 1 static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter; static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter; static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter; static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID; static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC *WireGuardGetRunningDriverVersion; static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver; static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger; static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging; static WIREGUARD_GET_ADAPTER_STATE_FUNC *WireGuardGetAdapterState; static WIREGUARD_SET_ADAPTER_STATE_FUNC *WireGuardSetAdapterState; static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration; static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration; unsigned long maxName() { return IFNAMSIZ; } std::string getErrorString(DWORD errorMessageID) { if (errorMessageID == 0 || errorMessageID < 0) std::string("Error code: ").append(std::to_string(errorMessageID)); LPSTR messageBuffer = nullptr; //Ask Win32 to give us the string version of that message ID. //The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be). size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); //Copy the error message into a std::string. std::string message(messageBuffer, size); //Free the Win32's string's buffer. LocalFree(messageBuffer); return std::string("Error code: ").append(std::to_string(errorMessageID)).append(", Message: ").append(message); } std::string startAddon(const Napi::Env env) { if (!IsRunAsAdmin()) return "Run nodejs with administrator privilegies"; auto DLLPATH = env.Global().ToObject().Get("WIREGUARD_DLL_PATH"); if (!(DLLPATH.IsString())) return "Require WIREGUARD_DLL_PATH in Global process"; LPCWSTR dllPath = toLpcwstr(DLLPATH.ToString()); HMODULE WireGuardDll = LoadLibraryExW(dllPath, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); if (!WireGuardDll) return ((std::string)"Failed to initialize WireGuardNT, ").append(getErrorString(GetLastError()));; #define X(Name) ((*(FARPROC *)&Name = GetProcAddress(WireGuardDll, #Name)) == NULL) if (X(WireGuardCreateAdapter) || X(WireGuardOpenAdapter) || X(WireGuardCloseAdapter) || X(WireGuardGetAdapterLUID) || X(WireGuardGetRunningDriverVersion) || X(WireGuardDeleteDriver) || X(WireGuardSetLogger) || X(WireGuardSetAdapterLogging) || X(WireGuardGetAdapterState) || X(WireGuardSetAdapterState) || X(WireGuardGetConfiguration) || X(WireGuardSetConfiguration)) #undef X { DWORD LastError = GetLastError(); FreeLibrary(WireGuardDll); SetLastError(LastError); return ((std::string)"Failed to set Functions from WireGuardNT DLL, ").append(getErrorString(GetLastError()));; } return ""; } std::string versionDrive() { WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"getWgVersion", L"Wireguard-tools.js", NULL); DWORD Version = WireGuardGetRunningDriverVersion(); if (Version == 0) { auto statusErr = GetLastError(); WireGuardCloseAdapter(Adapter); if (statusErr == ERROR_FILE_NOT_FOUND) return "Driver not loaded"; return ((std::string)"Cannot get version drive, ").append(getErrorString(GetLastError())); } WireGuardCloseAdapter(Adapter); return ((std::string)"WireGuardNT v").append(std::to_string((Version >> 16) & 0xff)).append(".").append(std::to_string((Version >> 0) & 0xff)); } typedef uint8_t wg_key[32]; typedef char wg_key_b64_string[((sizeof(wg_key) + 2) / 3) * 4 + 1]; bool key_is_zero(const uint8_t key[32]) { volatile uint8_t acc = 0; for (unsigned int i = 0; i < 32; ++i) { acc |= key[i]; // asm volatile("" : "=r"(acc) : "0"(acc)); } return !!(1 & ((acc - 1) >> 8)); } static int decodeBase64(const char src[4]) { int val = 0; unsigned int i; for (i = 0; i < 4; ++i) val |= (-1 + ((((('A' - 1) - src[i]) & (src[i] - ('Z' + 1))) >> 8) & (src[i] - 64)) + ((((('a' - 1) - src[i]) & (src[i] - ('z' + 1))) >> 8) & (src[i] - 70)) + ((((('0' - 1) - src[i]) & (src[i] - ('9' + 1))) >> 8) & (src[i] + 5)) + ((((('+' - 1) - src[i]) & (src[i] - ('+' + 1))) >> 8) & 63) + ((((('/' - 1) - src[i]) & (src[i] - ('/' + 1))) >> 8) & 64)) << (18 - 6 * i); return val; } static void encode_base64(char dest[4], const uint8_t src[3]) { const uint8_t input[] = { static_cast((src[0] >> 2) & 63), static_cast(((src[0] << 4) | (src[1] >> 4)) & 63), static_cast(((src[1] << 2) | (src[2] >> 6)) & 63), static_cast(src[2] & 63) }; unsigned int i; for (i = 0; i < 4; ++i) dest[i] = input[i] + 'A' + (((25 - input[i]) >> 8) & 6) - (((51 - input[i]) >> 8) & 75) - (((61 - input[i]) >> 8) & 15) + (((62 - input[i]) >> 8) & 3); } void insertKey(wg_key key, std::string keyBase64) { auto base64 = keyBase64.c_str(); if (keyBase64.length() != WG_KEY_LENGTH || base64[WG_KEY_LENGTH - 1] != '=') throw std::string("invalid key, length: ").append(std::to_string(keyBase64.length())); unsigned int i; int val; volatile uint8_t ret = 0; for (i = 0; i < 32 / 3; ++i) { val = decodeBase64(&base64[i * 4]); ret |= (uint32_t)val >> 31; key[i * 3 + 0] = (val >> 16) & 0xff; key[i * 3 + 1] = (val >> 8) & 0xff; key[i * 3 + 2] = val & 0xff; } const char tempDecode[4] = {base64[i * 4 + 0], base64[i * 4 + 1], base64[i * 4 + 2], 'A'}; val = decodeBase64(tempDecode); ret |= ((uint32_t)val >> 31) | (val & 0xff); key[i * 3 + 0] = (val >> 16) & 0xff; key[i * 3 + 1] = (val >> 8) & 0xff; int status = EINVAL & ~((ret - 1) >> 8); if (status != 0) throw std::string("Cannot decode key, ret code: ").append(std::to_string(status)); } std::string keyToBase64(const wg_key key) { wg_key_b64_string base64; unsigned int i; for (i = 0; i < 32 / 3; ++i) encode_base64(&base64[i * 4], &key[i * 3]); const uint8_t tempKey[3] = { key[i * 3 + 0], key[i * 3 + 1], 0 }; encode_base64(&base64[i * 4], tempKey); base64[sizeof(wg_key_b64_string) - 2] = '='; base64[sizeof(wg_key_b64_string) - 1] = '\0'; return std::string(base64); } void listDevices::Execute() { std::vector arrayPrefix; arrayPrefix.push_back("ProtectedPrefix\\Administrators\\WireGuard\\"); arrayPrefix.push_back("WireGuard\\"); WIN32_FIND_DATA find_data; HANDLE find_handle; int ret = 0; for (auto &preit : arrayPrefix) { ret = 0; find_handle = FindFirstFile("\\\\.\\pipe\\*", &find_data); if (find_handle == INVALID_HANDLE_VALUE) continue; char *iface; do { if (strncmp(preit.c_str(), find_data.cFileName, strlen(preit.c_str()))) continue; iface = find_data.cFileName + strlen(preit.c_str()); deviceNames[std::string(iface)] = "userspace"; } while (FindNextFile(find_handle, &find_data)); FindClose(find_handle); if (ret < 0) { std::string err = "Erro code: "; err = err.append(std::to_string(ret)); return SetError(err); } } HDEVINFO dev_info = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"SWD\\WireGuard", NULL, DIGCF_PRESENT, NULL, NULL, NULL); if (dev_info == INVALID_HANDLE_VALUE) return SetError("Cannot get devices"); for (DWORD i = 0;; ++i) { DWORD buf_len; WCHAR adapter_name[MAX_ADAPTER_NAME]; SP_DEVINFO_DATA dev_info_data; dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA); DEVPROPTYPE prop_type; ULONG status, problem_code; char *interface_name; if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) { if (GetLastError() == ERROR_NO_MORE_ITEMS) break; continue; } if (!SetupDiGetDevicePropertyW(dev_info, &dev_info_data, &devpkey_name, &prop_type, (PBYTE)adapter_name, sizeof(adapter_name), NULL, 0) || prop_type != DEVPROP_TYPE_STRING) continue; adapter_name[_countof(adapter_name) - 1] = L'0'; if (!adapter_name[0]) continue; buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, NULL, 0, NULL, NULL); if (!buf_len) continue; interface_name = (char *)malloc(buf_len); if (!interface_name) continue; buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, interface_name, buf_len, NULL, NULL); if (!buf_len) { free(interface_name); continue; } if (CM_Get_DevNode_Status(&status, &problem_code, dev_info_data.DevInst, 0) == CR_SUCCESS && (status & (DN_DRIVER_LOADED | DN_STARTED)) == (DN_DRIVER_LOADED | DN_STARTED)) deviceNames[std::string(interface_name)] = "kernel"; } SetupDiDestroyDeviceInfoList(dev_info); } void deleteInterface::Execute() { WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); if (!Adapter) return SetError("This interface not exists in Wireguard-Tools.js addon!"); if (!(WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_DOWN))) return SetError(((std::string)"Failed to set down interface, ").append(getErrorString(GetLastError()))); WireGuardCloseAdapter(Adapter); } void getConfig::Execute() { WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); if (!Adapter) return SetError("This interface not exists in Wireguard-Tools.js addon!"); NET_LUID InterfaceLuid; WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); try { for (auto aip : getIpAddr(InterfaceLuid)) Address.push_back(aip); } catch (void* err) {} DWORD buf_len = 0; WIREGUARD_INTERFACE *wg_iface = nullptr; while (!(WireGuardGetConfiguration(Adapter, wg_iface, &buf_len))) { free(wg_iface); if (GetLastError() != ERROR_MORE_DATA) return SetError((std::string("Failed get interface config, code: ")).append(std::to_string(GetLastError()))); wg_iface = (WIREGUARD_INTERFACE *)malloc(buf_len); if (!wg_iface) return SetError(((std::string)"Failed get interface config, ").append(std::to_string(-errno))); } if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY) privateKey = keyToBase64(wg_iface->PrivateKey); if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PUBLIC_KEY) publicKey = keyToBase64(wg_iface->PublicKey); portListen = 0; if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT) portListen = wg_iface->ListenPort; WIREGUARD_PEER *wg_peer = reinterpret_cast(((char*)wg_iface) + sizeof(WIREGUARD_INTERFACE)); for (DWORD i = 0; i < wg_iface->PeersCount; i++) { auto pubKey = keyToBase64(wg_peer->PublicKey); Peer peerConfig; if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY) peerConfig.presharedKey = keyToBase64(wg_peer->PresharedKey); if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT) peerConfig.endpoint = parseEndpoint(&wg_peer->Endpoint); if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE) peerConfig.keepInterval = wg_peer->PersistentKeepalive; peerConfig.rxBytes = wg_peer->RxBytes; peerConfig.txBytes = wg_peer->TxBytes; peerConfig.last_handshake = 0; if (wg_peer->LastHandshake > 0) peerConfig.last_handshake = (wg_peer->LastHandshake / 10000000 - 11644473600LL) * 1000; WIREGUARD_ALLOWED_IP* wg_aip = reinterpret_cast(((char*)wg_peer) + sizeof(WIREGUARD_PEER)); for (DWORD __aip = 0; __aip < wg_peer->AllowedIPsCount; __aip++) { char saddr[INET6_ADDRSTRLEN]; if (wg_aip->AddressFamily == AF_INET) { inet_ntop(AF_INET, &wg_aip->Address.V6, saddr, INET_ADDRSTRLEN); peerConfig.allowedIPs.push_back(std::string(saddr).append("/").append(std::to_string(wg_aip->Cidr))); } else if (wg_aip->AddressFamily == AF_INET6) { inet_ntop(AF_INET6, &wg_aip->Address.V6, saddr, INET6_ADDRSTRLEN); peerConfig.allowedIPs.push_back(std::string(saddr).append("/").append(std::to_string(wg_aip->Cidr))); } ++wg_aip; } wg_peer = reinterpret_cast(wg_aip); peersVector[pubKey] = peerConfig; } free(wg_iface); } void setConfig::Execute() { DWORD buf_len = sizeof(WIREGUARD_INTERFACE); for (auto peer : peersVector) { if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER)) return SetError("Buffer overflow"); buf_len += sizeof(WIREGUARD_PEER); for (auto aip : peer.second.allowedIPs) { if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP)) return SetError("Buffer overflow"); buf_len += sizeof(WIREGUARD_ALLOWED_IP); } } WIREGUARD_INTERFACE *wg_iface = NULL; wg_iface = reinterpret_cast(calloc(1, buf_len)); if (!wg_iface) return SetError("Cannot alloc buff"); wg_iface->PeersCount = 0; insertKey(wg_iface->PrivateKey, privateKey); wg_iface->Flags = WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY; wg_iface->ListenPort = portListen; if (portListen >= 0 && 65535 <= portListen) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT); if (replacePeers) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_REPLACE_PEERS); WIREGUARD_ALLOWED_IP *wg_aip; WIREGUARD_PEER *wg_peer = reinterpret_cast(reinterpret_cast(wg_iface) + sizeof(WIREGUARD_INTERFACE)); for (auto __peer : peersVector) { auto peerPublicKey = __peer.first; auto peerConfig = __peer.second; insertKey(wg_peer->PublicKey, peerPublicKey); wg_peer->Flags = WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PUBLIC_KEY; wg_peer->AllowedIPsCount = 0; wg_iface->PeersCount++; if (peerConfig.removeMe) { wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REMOVE); wg_peer = reinterpret_cast(((char*)wg_peer) + sizeof(WIREGUARD_PEER)); } else { if (peerConfig.presharedKey.size() == WG_KEY_LENGTH) { insertKey(wg_peer->PresharedKey, peerConfig.presharedKey); wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY); } if (peerConfig.keepInterval > 0) { wg_peer->PersistentKeepalive = peerConfig.keepInterval; wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE); } if (peerConfig.endpoint.size() > 0) { try { insertEndpoint(&wg_peer->Endpoint, peerConfig.endpoint.c_str()); wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT); } catch (std::string &err) { SetError(std::string("Cannot parse endpoint, ").append(err)); goto outEnd; } } wg_aip = reinterpret_cast(((char*)wg_peer) + sizeof(WIREGUARD_PEER)); for (auto aip : peerConfig.allowedIPs) { unsigned long cidr = 0; if (aip.find("/") != std::string::npos) { cidr = std::stoi(aip.substr(aip.find("/")+1)); aip = aip.substr(0, aip.find("/")); } aip = aip.substr(0, aip.find("/")); wg_aip->AddressFamily = strchr(aip.c_str(), ':') ? AF_INET6 : AF_INET; auto status = wg_aip->AddressFamily == AF_INET6 ? inet_pton(wg_aip->AddressFamily, aip.c_str(), &wg_aip->Address.V6) : inet_pton(wg_aip->AddressFamily, aip.c_str(), &wg_aip->Address.V4); if (status == 1) { if (cidr == 0) cidr = wg_aip->AddressFamily == AF_INET6 ? 128 : 32; } else continue; wg_aip->Cidr = cidr; wg_peer->AllowedIPsCount++; wg_aip = reinterpret_cast(((char*)wg_aip) + sizeof(WIREGUARD_ALLOWED_IP)); if (!(wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REPLACE_ALLOWED_IPS)) wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REPLACE_ALLOWED_IPS); } wg_peer = reinterpret_cast(((char*)wg_aip)); } } WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); if (!Adapter) Adapter = WireGuardCreateAdapter(toLpcwstr(wgName), L"Wireguard-tools.js", NULL); if (!Adapter) SetError(((std::string)"Failed to create adapter, ").append(getErrorString(GetLastError()))); else if (!WireGuardSetConfiguration(Adapter, reinterpret_cast(wg_iface), buf_len)) { auto status = GetLastError(); SetError(std::string("Failed to set interface config, ").append(getErrorString(status))); WireGuardCloseAdapter(Adapter); } else if (!WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP)) { auto status = GetLastError(); SetError(std::string("Failed to set interface up, ").append(getErrorString(status))); WireGuardCloseAdapter(Adapter); } else { if (Address.size() > 0) { std::string IPv4, IPv6; for (auto aip : Address) { aip = aip.substr(0, aip.find("/")); auto family = strchr(aip.c_str(), ':') ? AF_INET6 : AF_INET; SOCKADDR_INET address; int status = family == AF_INET ? inet_pton(family, aip.c_str(), &address.Ipv4.sin_addr) : inet_pton(family, aip.c_str(), &address.Ipv6.sin6_addr); if (status != 1) continue; char saddr[INET6_ADDRSTRLEN]; family == AF_INET ? inet_ntop(AF_INET, &address.Ipv4.sin_addr, saddr, INET_ADDRSTRLEN) : inet_ntop(AF_INET6, &address.Ipv6.sin6_addr, saddr, INET6_ADDRSTRLEN); if (family == AF_INET) IPv4 = std::string(saddr); // else IPv6 = std::string(saddr); } if (IPv4.size() > 0 || IPv6.size() > 0) { NET_LUID InterfaceLuid; WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); auto setStatus = insertIpAddr(InterfaceLuid, IPv4, IPv6); if (setStatus.size() > 0) SetError(setStatus); } } } outEnd: free(wg_iface); }