|
|
|
@ -37,19 +37,33 @@
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
// Create Wireguard adapter
|
|
|
|
|
static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter;
|
|
|
|
|
// Open Wireguard adapter by name if exists
|
|
|
|
|
static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter;
|
|
|
|
|
// Close Wireguard adapter
|
|
|
|
|
static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter;
|
|
|
|
|
// Get Wireguard adapter LUID
|
|
|
|
|
static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID;
|
|
|
|
|
// Get running Wireguard driver version
|
|
|
|
|
static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC *WireGuardGetRunningDriverVersion;
|
|
|
|
|
// Delete Wireguard driver if non exists adapters
|
|
|
|
|
static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver;
|
|
|
|
|
// Set logger for Wireguard adapter
|
|
|
|
|
static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger;
|
|
|
|
|
// Set adapter logging for Wireguard adapter
|
|
|
|
|
static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging;
|
|
|
|
|
// Get adapter state for Wireguard adapter
|
|
|
|
|
static WIREGUARD_GET_ADAPTER_STATE_FUNC *WireGuardGetAdapterState;
|
|
|
|
|
// Set adapter state for Wireguard adapter
|
|
|
|
|
static WIREGUARD_SET_ADAPTER_STATE_FUNC *WireGuardSetAdapterState;
|
|
|
|
|
// Get Wireguard adapter configuration
|
|
|
|
|
static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration;
|
|
|
|
|
// Set Wireguard adapter configuration
|
|
|
|
|
static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration;
|
|
|
|
|
|
|
|
|
|
LPCWSTR WireguardAddonDescription = WireguardAddonDescription;
|
|
|
|
|
|
|
|
|
|
// Function to check if the current user has administrator privileges
|
|
|
|
|
bool IsRunAsAdmin() {
|
|
|
|
|
BOOL fRet = FALSE;
|
|
|
|
@ -92,90 +106,6 @@ std::string parseEndpoint(SOCKADDR_INET *input) {
|
|
|
|
|
return std::string(saddr).append(":").append(std::to_string(htons(input->Ipv4.sin_port)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int parse_dns_retries() {
|
|
|
|
|
unsigned long ret;
|
|
|
|
|
char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end;
|
|
|
|
|
|
|
|
|
|
if (!retries) return 15;
|
|
|
|
|
if (!strcmp(retries, "infinity")) return -1;
|
|
|
|
|
|
|
|
|
|
ret = strtoul(retries, &end, 10);
|
|
|
|
|
if (*end || ret > INT_MAX) {
|
|
|
|
|
fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n", retries);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
return (int)ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void insertEndpoint(SOCKADDR_INET *endpoint, std::string value) {
|
|
|
|
|
int ret, retries = parse_dns_retries();
|
|
|
|
|
char *begin, *end;
|
|
|
|
|
auto mmutable = strdup(value.c_str());
|
|
|
|
|
if (!mmutable) throw std::string("strdup");
|
|
|
|
|
if (!value.size()) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Unable to parse empty endpoint");
|
|
|
|
|
}
|
|
|
|
|
if (mmutable[0] == '[') {
|
|
|
|
|
begin = &mmutable[1];
|
|
|
|
|
end = strchr(mmutable, ']');
|
|
|
|
|
if (!end) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Unable to find matching brace of endpoint: ").append(value);
|
|
|
|
|
}
|
|
|
|
|
*end++ = '\0';
|
|
|
|
|
if (*end++ != ':' || !*end) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Unable to find port of endpoint: ").append(value);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
begin = mmutable;
|
|
|
|
|
end = strrchr(mmutable, ':');
|
|
|
|
|
if (!end || !*(end + 1)) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Unable to find port of endpoint: ").append(value);
|
|
|
|
|
}
|
|
|
|
|
*end++ = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ADDRINFOA *resolved;
|
|
|
|
|
// #define min(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
|
for (unsigned int timeout = 1000000;; timeout = ((20000000) < (timeout * 6 / 5) ? (20000000) : (timeout * 6 / 5))) {
|
|
|
|
|
// ret = getaddrinfo(begin, end, &hints, &resolved);
|
|
|
|
|
ret = getaddrinfo(begin, end, NULL, &resolved);
|
|
|
|
|
if (!ret) break;
|
|
|
|
|
/* The set of return codes that are "permanent failures". All other possibilities are potentially transient.
|
|
|
|
|
*
|
|
|
|
|
* This is according to https://sourceware.org/glibc/wiki/NameResolver which states:
|
|
|
|
|
* "From the perspective of the application that calls getaddrinfo() it perhaps
|
|
|
|
|
* doesn't matter that much since EAI_FAIL, EAI_NONAME and EAI_NODATA are all
|
|
|
|
|
* permanent failure codes and the causes are all permanent failures in the
|
|
|
|
|
* sense that there is no point in retrying later."
|
|
|
|
|
*
|
|
|
|
|
* So this is what we do, except FreeBSD removed EAI_NODATA some time ago, so that's conditional.
|
|
|
|
|
*/
|
|
|
|
|
if (ret == EAI_NONAME || ret == EAI_FAIL ||
|
|
|
|
|
#ifdef EAI_NODATA
|
|
|
|
|
ret == EAI_NODATA ||
|
|
|
|
|
#endif
|
|
|
|
|
(retries >= 0 && !retries--)) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Error code: ").append(std::to_string(ret));
|
|
|
|
|
}
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(timeout));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(SOCKADDR_IN))) memcpy(&endpoint->Ipv4, resolved->ai_addr, resolved->ai_addrlen);
|
|
|
|
|
else if (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(SOCKADDR_IN6)) memcpy(&endpoint->Ipv6, resolved->ai_addr, resolved->ai_addrlen);
|
|
|
|
|
else {
|
|
|
|
|
freeaddrinfo(resolved);
|
|
|
|
|
throw std::string("Neither IPv4 nor IPv6 address found: ").append(value);
|
|
|
|
|
}
|
|
|
|
|
freeaddrinfo(resolved);
|
|
|
|
|
free(mmutable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string getErrorString(DWORD errorMessageID) {
|
|
|
|
|
if (errorMessageID == 0 || errorMessageID < 0) std::string("Error code: ").append(std::to_string(errorMessageID));
|
|
|
|
|
LPSTR messageBuffer = nullptr;
|
|
|
|
@ -211,7 +141,9 @@ std::string driveLoad(std::map<std::string, std::string> load) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string getWireguardVersion() {
|
|
|
|
|
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"getWgVersion", L"Wireguard-tools.js", NULL);
|
|
|
|
|
// Create interface to get version
|
|
|
|
|
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"getWgVersion", WireguardAddonDescription, NULL);
|
|
|
|
|
WireGuardCloseAdapter(Adapter);
|
|
|
|
|
DWORD Version = WireGuardGetRunningDriverVersion();
|
|
|
|
|
if (Version == 0) {
|
|
|
|
|
auto statusErr = GetLastError();
|
|
|
|
@ -219,49 +151,25 @@ std::string getWireguardVersion() {
|
|
|
|
|
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));
|
|
|
|
|
return std::string("WireGuardNT v").append(std::to_string((Version >> 16) & 0xff)).append(".").append(std::to_string((Version >> 0) & 0xff)).append(".").append(std::to_string((Version >> 8) & 0xff));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WireguardDevices::getInterfaces() {
|
|
|
|
|
// std::vector<std::string> arrayPrefix;
|
|
|
|
|
// arrayPrefix.push_back("ProtectedPrefix\\Administrators\\WireGuard\\");
|
|
|
|
|
// arrayPrefix.push_back("WireGuard\\");
|
|
|
|
|
|
|
|
|
|
// WIN32_FIND_DATA find_data;
|
|
|
|
|
// HANDLE find_handle;
|
|
|
|
|
// for (auto &preit : arrayPrefix) {
|
|
|
|
|
// int 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());
|
|
|
|
|
// this->push_back(std::string("\\\\.\\pipe\\").append(preit).append(iface));
|
|
|
|
|
// } while (FindNextFile(find_handle, &find_data));
|
|
|
|
|
// FindClose(find_handle);
|
|
|
|
|
// if (ret < 0) throw std::string("Erro code: ").append(std::to_string(ret));
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
HDEVINFO dev_info = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"SWD\\WireGuard", NULL, DIGCF_PRESENT, NULL, NULL, NULL);
|
|
|
|
|
if (dev_info == INVALID_HANDLE_VALUE) throw ("Cannot get devices");
|
|
|
|
|
|
|
|
|
|
for (DWORD i = 0;; ++i) {
|
|
|
|
|
DWORD buf_len;
|
|
|
|
|
WCHAR adapter_name[MAX_ADAPTER_NAME];
|
|
|
|
|
if (dev_info == INVALID_HANDLE_VALUE) throw std::string("Cannot get devices");
|
|
|
|
|
for (DWORD devIndex = 0;; ++devIndex) {
|
|
|
|
|
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 (!SetupDiEnumDeviceInfo(dev_info, devIndex, &dev_info_data)) {
|
|
|
|
|
if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD buf_len; ULONG status, problem_code;
|
|
|
|
|
WCHAR adapter_name[MAX_ADAPTER_NAME];
|
|
|
|
|
char *interface_name;
|
|
|
|
|
DEVPROPTYPE prop_type;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
@ -281,28 +189,31 @@ void WireguardDevices::getInterfaces() {
|
|
|
|
|
SetupDiDestroyDeviceInfoList(dev_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Delete wireguard interface
|
|
|
|
|
|
|
|
|
|
Current bug from Addon: Set interface down and not delete wireguard interface
|
|
|
|
|
*/
|
|
|
|
|
void WireguardDevices::deleteInterface(std::string wgName) {
|
|
|
|
|
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName));
|
|
|
|
|
if (!Adapter) throw std::string("This interface not exists in Wireguard-Tools.js addon!");
|
|
|
|
|
if (!(WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_DOWN))) throw std::string(std::string("Failed to set down interface, ").append(getErrorString(GetLastError())));
|
|
|
|
|
if (!(WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_DOWN))) throw std::string("Failed to set down interface, ").append(getErrorString(GetLastError()));
|
|
|
|
|
WireGuardCloseAdapter(Adapter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Change point from calloc or malloc
|
|
|
|
|
*
|
|
|
|
|
* T: to
|
|
|
|
|
* C: From
|
|
|
|
|
* Change point from calloc or malloc, T: from, C: to
|
|
|
|
|
*/
|
|
|
|
|
template <typename T, typename C> C* changePoint(T *x) {
|
|
|
|
|
// reinterpret_cast<WIREGUARD_ALLOWED_IP*>(((char*)x) + sizeof(WIREGUARD_PEER));
|
|
|
|
|
// std::cout << "Sizeof: " << sizeof(C) << ", " << typeid(T).name() << " -> " << typeid(C).name() << std::endl;
|
|
|
|
|
return reinterpret_cast<C*>(((char*)x) + sizeof(T));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WireguardConfig::getWireguardConfig() {
|
|
|
|
|
if (this->name.length() == 0) throw std::string("Require interface name!");
|
|
|
|
|
else if (!(WireguardDevices().exist(this->name))) throw std::string("This interface not exists in Wireguard-Tools.js addon!");
|
|
|
|
|
|
|
|
|
|
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(this->name));
|
|
|
|
|
if (!Adapter) throw ("This interface not exists in Wireguard-Tools.js addon!");
|
|
|
|
|
if (!Adapter) throw std::string("This interface not exists in Wireguard-Tools.js addon!");
|
|
|
|
|
NET_LUID InterfaceLuid;
|
|
|
|
|
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
|
|
|
|
|
this->interfaceAddress.GetInInterface(this->name);
|
|
|
|
@ -312,28 +223,27 @@ void WireguardConfig::getWireguardConfig() {
|
|
|
|
|
|
|
|
|
|
while (!(WireGuardGetConfiguration(Adapter, wg_iface, &buf_len))) {
|
|
|
|
|
free(wg_iface);
|
|
|
|
|
if (GetLastError() != ERROR_MORE_DATA) throw ((std::string("Failed get interface config, code: ")).append(std::to_string(GetLastError())));
|
|
|
|
|
if (GetLastError() != ERROR_MORE_DATA) throw std::string("Failed get interface config, code: ").append(std::to_string(GetLastError()));
|
|
|
|
|
wg_iface = (WIREGUARD_INTERFACE *)malloc(buf_len);
|
|
|
|
|
if (!wg_iface) throw std::string("Failed get interface config, ").append(std::to_string(-errno));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY) privateKey = wgKeys::toString(wg_iface->PrivateKey);
|
|
|
|
|
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PUBLIC_KEY) publicKey = wgKeys::toString(wg_iface->PublicKey);
|
|
|
|
|
portListen = 0;
|
|
|
|
|
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT) portListen = wg_iface->ListenPort;
|
|
|
|
|
|
|
|
|
|
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY) this->privateKey = wgKeys::toString(wg_iface->PrivateKey);
|
|
|
|
|
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PUBLIC_KEY) this->publicKey = wgKeys::toString(wg_iface->PublicKey);
|
|
|
|
|
if (wg_iface->ListenPort > 0) this->portListen = wg_iface->ListenPort;
|
|
|
|
|
|
|
|
|
|
WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface);
|
|
|
|
|
for (DWORD i = 0; i < wg_iface->PeersCount; i++) {
|
|
|
|
|
auto pubKey = wgKeys::toString(wg_peer->PublicKey);
|
|
|
|
|
Peer peerConfig;
|
|
|
|
|
|
|
|
|
|
peerConfig.txBytes = wg_peer->TxBytes;
|
|
|
|
|
peerConfig.rxBytes = wg_peer->RxBytes;
|
|
|
|
|
peerConfig.lastHandshake = (wg_peer->LastHandshake - 116444736000000000LL) / (100 / 1000);
|
|
|
|
|
|
|
|
|
|
if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY) peerConfig.presharedKey = wgKeys::toString(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;
|
|
|
|
|
if (wg_peer->LastHandshake > 0) peerConfig.lastHandshake = (wg_peer->LastHandshake - 116444736000000000LL) / (100 / 1000);
|
|
|
|
|
|
|
|
|
|
WIREGUARD_ALLOWED_IP* wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer);
|
|
|
|
|
for (DWORD __aip = 0; __aip < wg_peer->AllowedIPsCount; __aip++) {
|
|
|
|
@ -355,26 +265,28 @@ void WireguardConfig::getWireguardConfig() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WireguardConfig::setWireguardConfig() {
|
|
|
|
|
if (this->name.length() == 0) throw std::string("Require interface name!");
|
|
|
|
|
else if (this->name.length() > IFNAMSIZ) throw std::string("Interface name too long");
|
|
|
|
|
|
|
|
|
|
DWORD buf_len = sizeof(WIREGUARD_INTERFACE);
|
|
|
|
|
for (auto peer : this->Peers) {
|
|
|
|
|
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER)) throw ("Buffer overflow");
|
|
|
|
|
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER)) throw std::string("Buffer overflow");
|
|
|
|
|
buf_len += sizeof(WIREGUARD_PEER);
|
|
|
|
|
for (auto aip : peer.second.allowedIPs) {
|
|
|
|
|
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP)) throw ("Buffer overflow");
|
|
|
|
|
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP)) throw std::string("Buffer overflow");
|
|
|
|
|
buf_len += sizeof(WIREGUARD_ALLOWED_IP);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
WIREGUARD_INTERFACE *wg_iface = reinterpret_cast<WIREGUARD_INTERFACE*>(calloc(1, buf_len));
|
|
|
|
|
if (!wg_iface) throw ("Cannot alloc buff");
|
|
|
|
|
if (!wg_iface) throw std::string("Cannot alloc buff");
|
|
|
|
|
wg_iface->PeersCount = 0;
|
|
|
|
|
|
|
|
|
|
wgKeys::stringToKey(wg_iface->PrivateKey, privateKey);
|
|
|
|
|
wgKeys::stringToKey(wg_iface->PrivateKey, this->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);
|
|
|
|
|
wg_iface->ListenPort = this->portListen;
|
|
|
|
|
if (this->portListen >= 0) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT);
|
|
|
|
|
if (this->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 = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface);
|
|
|
|
@ -398,7 +310,75 @@ void WireguardConfig::setWireguardConfig() {
|
|
|
|
|
if (peerConfig.keepInterval >= 0) wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE);
|
|
|
|
|
|
|
|
|
|
if (peerConfig.endpoint.size() > 0) {
|
|
|
|
|
insertEndpoint(&wg_peer->Endpoint, peerConfig.endpoint.c_str());
|
|
|
|
|
int ret, retries = ([]() -> int {
|
|
|
|
|
unsigned long ret;
|
|
|
|
|
char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end;
|
|
|
|
|
|
|
|
|
|
if (!retries) return 15;
|
|
|
|
|
if (!strcmp(retries, "infinity")) return -1;
|
|
|
|
|
|
|
|
|
|
ret = strtoul(retries, &end, 10);
|
|
|
|
|
if (*end || ret > INT_MAX) {
|
|
|
|
|
fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n", retries);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
return (int)ret;
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
char *begin, *end;
|
|
|
|
|
auto mmutable = strdup(peerConfig.endpoint.c_str());
|
|
|
|
|
if (!mmutable) throw std::string("strdup");
|
|
|
|
|
if (!peerConfig.endpoint.size()) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Unable to parse empty endpoint");
|
|
|
|
|
}
|
|
|
|
|
if (mmutable[0] == '[') {
|
|
|
|
|
begin = &mmutable[1];
|
|
|
|
|
end = strchr(mmutable, ']');
|
|
|
|
|
if (!end) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Unable to find matching brace of endpoint: ").append(peerConfig.endpoint);
|
|
|
|
|
}
|
|
|
|
|
*end++ = '\0';
|
|
|
|
|
if (*end++ != ':' || !*end) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Unable to find port of endpoint: ").append(peerConfig.endpoint);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
begin = mmutable;
|
|
|
|
|
end = strrchr(mmutable, ':');
|
|
|
|
|
if (!end || !*(end + 1)) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Unable to find port of endpoint: ").append(peerConfig.endpoint);
|
|
|
|
|
}
|
|
|
|
|
*end++ = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ADDRINFOA *resolved;
|
|
|
|
|
for (unsigned int timeout = 1000000;; timeout = ((20000000) < (timeout * 6 / 5) ? (20000000) : (timeout * 6 / 5))) {
|
|
|
|
|
// ret = getaddrinfo(begin, end, &hints, &resolved);
|
|
|
|
|
ret = getaddrinfo(begin, end, NULL, &resolved);
|
|
|
|
|
if (!ret) break;
|
|
|
|
|
if (ret == EAI_NONAME || ret == EAI_FAIL ||
|
|
|
|
|
#ifdef EAI_NODATA
|
|
|
|
|
ret == EAI_NODATA ||
|
|
|
|
|
#endif
|
|
|
|
|
(retries >= 0 && !retries--)) {
|
|
|
|
|
free(mmutable);
|
|
|
|
|
throw std::string("Error code: ").append(std::to_string(ret));
|
|
|
|
|
}
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(timeout));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(SOCKADDR_IN))) memcpy(&wg_peer->Endpoint.Ipv4, resolved->ai_addr, resolved->ai_addrlen);
|
|
|
|
|
else if (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(SOCKADDR_IN6)) memcpy(&wg_peer->Endpoint.Ipv6, resolved->ai_addr, resolved->ai_addrlen);
|
|
|
|
|
else {
|
|
|
|
|
freeaddrinfo(resolved);
|
|
|
|
|
throw std::string("Neither IPv4 nor IPv6 address found: ").append(peerConfig.endpoint);
|
|
|
|
|
}
|
|
|
|
|
freeaddrinfo(resolved);
|
|
|
|
|
free(mmutable);
|
|
|
|
|
|
|
|
|
|
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -420,38 +400,74 @@ void WireguardConfig::setWireguardConfig() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(this->name));
|
|
|
|
|
if (!Adapter) Adapter = WireGuardCreateAdapter(toLpcwstr(this->name), L"Wireguard-tools.js", NULL);
|
|
|
|
|
if (!Adapter) Adapter = WireGuardCreateAdapter(toLpcwstr(this->name), WireguardAddonDescription, NULL);
|
|
|
|
|
if (!Adapter) throw std::string("Failed to create adapter, ").append(getErrorString(GetLastError()));
|
|
|
|
|
else if (!WireGuardSetConfiguration(Adapter, reinterpret_cast<WIREGUARD_INTERFACE*>(wg_iface), buf_len)) {
|
|
|
|
|
|
|
|
|
|
auto status = WireGuardSetConfiguration(Adapter, reinterpret_cast<WIREGUARD_INTERFACE*>(wg_iface), buf_len) && WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP);
|
|
|
|
|
free(wg_iface);
|
|
|
|
|
|
|
|
|
|
if (!status) {
|
|
|
|
|
auto status = GetLastError();
|
|
|
|
|
WireGuardCloseAdapter(Adapter);
|
|
|
|
|
throw std::string("Failed to set interface config, ").append(getErrorString(status));
|
|
|
|
|
} else if (!WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP)) {
|
|
|
|
|
auto status = GetLastError();
|
|
|
|
|
WireGuardCloseAdapter(Adapter);
|
|
|
|
|
throw std::string("Failed to set interface up, ").append(getErrorString(status));
|
|
|
|
|
} else {
|
|
|
|
|
this->interfaceAddress.SetInInterface(this->name);
|
|
|
|
|
}
|
|
|
|
|
free(wg_iface);
|
|
|
|
|
|
|
|
|
|
this->interfaceAddress.SetInInterface(this->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IpManeger::GetInInterface(std::string interfaceName) {
|
|
|
|
|
// Define the InterfaceLuid of the network interface you want to query
|
|
|
|
|
NET_IFINDEX ind;
|
|
|
|
|
NET_LUID InterfaceLuid;
|
|
|
|
|
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(interfaceName));
|
|
|
|
|
if (!Adapter) throw std::string("Cannot open wireguard adapter");
|
|
|
|
|
NET_LUID InterfaceLuid;
|
|
|
|
|
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
|
|
|
|
|
if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &ind) != NO_ERROR) throw std::string("Cannot get interface index");
|
|
|
|
|
|
|
|
|
|
ULONG bufferSize = 0; // Initial buffer size
|
|
|
|
|
|
|
|
|
|
// Call GetAdaptersAddresses to get the required buffer size
|
|
|
|
|
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &bufferSize) == ERROR_BUFFER_OVERFLOW) {
|
|
|
|
|
// Allocate memory for the buffer
|
|
|
|
|
PIP_ADAPTER_ADDRESSES addresses = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(bufferSize));
|
|
|
|
|
// Call GetAdaptersAddresses again with the allocated buffer
|
|
|
|
|
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, addresses, &bufferSize) == NO_ERROR) {
|
|
|
|
|
// Iterate through the list of adapters
|
|
|
|
|
for (PIP_ADAPTER_ADDRESSES adapter = addresses; adapter != nullptr; adapter = adapter->Next) {
|
|
|
|
|
// Check if the adapter matches the specified InterfaceLuid
|
|
|
|
|
if (memcmp(&adapter->Luid, &InterfaceLuid, sizeof(NET_LUID)) == 0) {
|
|
|
|
|
// Iterate through the list of IP addresses associated with the adapter
|
|
|
|
|
for (PIP_ADAPTER_UNICAST_ADDRESS address = adapter->FirstUnicastAddress; address != nullptr; address = address->Next) {
|
|
|
|
|
// Access the IP address in the address structure
|
|
|
|
|
sockaddr* sa = address->Address.lpSockaddr;
|
|
|
|
|
char ip[INET6_ADDRSTRLEN];
|
|
|
|
|
if (sa->sa_family == AF_INET) {
|
|
|
|
|
inet_ntop(AF_INET, &reinterpret_cast<sockaddr_in*>(sa)->sin_addr, ip, sizeof(ip));
|
|
|
|
|
} else if (sa->sa_family == AF_INET6) {
|
|
|
|
|
inet_ntop(AF_INET6, &reinterpret_cast<sockaddr_in6*>(sa)->sin6_addr, ip, sizeof(ip));
|
|
|
|
|
} else continue;
|
|
|
|
|
// Print or use the IP address as needed
|
|
|
|
|
this->addIPMask(std::string(ip).append("/").append(std::to_string(address->Address.iSockaddrLength)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Free the allocated buffer
|
|
|
|
|
free(addresses);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-createunicastipaddressentry
|
|
|
|
|
void IpManeger::SetInInterface(std::string interfaceName) {
|
|
|
|
|
if (this->size() == 0) return;
|
|
|
|
|
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(interfaceName));
|
|
|
|
|
if (!Adapter) throw std::string("Cannot open wireguard adapter");
|
|
|
|
|
|
|
|
|
|
NET_LUID InterfaceLuid;
|
|
|
|
|
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
|
|
|
|
|
ULONG bufferSize = 0; // Initial buffer size
|
|
|
|
|
// Call GetAdaptersAddresses to get the required buffer size
|
|
|
|
|
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &bufferSize) == ERROR_BUFFER_OVERFLOW) {
|
|
|
|
|
// Allocate memory for the buffer
|
|
|
|
|
PIP_ADAPTER_ADDRESSES addresses = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(bufferSize));
|
|
|
|
|
// Call GetAdaptersAddresses again with the allocated buffer
|
|
|
|
|
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, addresses, &bufferSize) == NO_ERROR) {
|
|
|
|
|
// Iterate through the list of adapters
|
|
|
|
@ -469,8 +485,19 @@ void IpManeger::GetInInterface(std::string interfaceName) {
|
|
|
|
|
inet_ntop(AF_INET6, &reinterpret_cast<sockaddr_in6*>(sa)->sin6_addr, ip, sizeof(ip));
|
|
|
|
|
} else continue;
|
|
|
|
|
|
|
|
|
|
// Print or use the IP address as needed
|
|
|
|
|
this->addIPMask(std::string(ip).append("/").append(std::to_string(address->Address.iSockaddrLength)));
|
|
|
|
|
// Delete the IP address
|
|
|
|
|
MIB_UNICASTIPADDRESS_ROW row;
|
|
|
|
|
memset(&row, 0, sizeof(row));
|
|
|
|
|
WireGuardGetAdapterLUID(Adapter, &row.InterfaceLuid);
|
|
|
|
|
if (sa->sa_family == AF_INET) {
|
|
|
|
|
row.Address.si_family = AF_INET;
|
|
|
|
|
inet_pton(AF_INET, ip, &row.Address.Ipv4.sin_addr);
|
|
|
|
|
} else if (sa->sa_family == AF_INET6) {
|
|
|
|
|
row.Address.si_family = AF_INET6;
|
|
|
|
|
inet_pton(AF_INET6, ip, &row.Address.Ipv6.sin6_addr);
|
|
|
|
|
} else continue;
|
|
|
|
|
|
|
|
|
|
if (DeleteUnicastIpAddressEntry(&row) != NO_ERROR) throw std::string("Cannot delete IP address from interface");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -479,14 +506,25 @@ void IpManeger::GetInInterface(std::string interfaceName) {
|
|
|
|
|
// Free the allocated buffer
|
|
|
|
|
free(addresses);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IpManeger::SetInInterface(std::string interfaceName) {
|
|
|
|
|
if (this->size() == 0) return;
|
|
|
|
|
NET_IFINDEX interfaceIndex;
|
|
|
|
|
NET_LUID InterfaceLuid;
|
|
|
|
|
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(interfaceName));
|
|
|
|
|
if (!Adapter) throw std::string("Cannot open wireguard adapter");
|
|
|
|
|
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
|
|
|
|
|
if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &interfaceIndex) != NO_ERROR) throw std::string("Cannot get interface index");
|
|
|
|
|
for (auto ip : this->getIpParsed()) {
|
|
|
|
|
MIB_UNICASTIPADDRESS_ROW row;
|
|
|
|
|
memset(&row, 0, sizeof(row));
|
|
|
|
|
memcpy(&row.InterfaceLuid, &InterfaceLuid, sizeof(NET_LUID));
|
|
|
|
|
|
|
|
|
|
row.DadState = NldsPreferred;
|
|
|
|
|
row.ValidLifetime = 0xffffffff;
|
|
|
|
|
row.PreferredLifetime = 0xffffffff;
|
|
|
|
|
|
|
|
|
|
row.OnLinkPrefixLength = ip.Mask;
|
|
|
|
|
if (ip.Proto == 4) {
|
|
|
|
|
row.Address.si_family = AF_INET;
|
|
|
|
|
inet_pton(AF_INET, ip.Address.c_str(), &row.Address.Ipv4.sin_addr);
|
|
|
|
|
} else if (ip.Proto == 6) {
|
|
|
|
|
row.Address.si_family = AF_INET6;
|
|
|
|
|
inet_pton(AF_INET6, ip.Address.c_str(), &row.Address.Ipv6.sin6_addr);
|
|
|
|
|
} else continue;
|
|
|
|
|
|
|
|
|
|
if (CreateUnicastIpAddressEntry(&row) != NO_ERROR) throw std::string("Cannot add IP address to interface");
|
|
|
|
|
}
|
|
|
|
|
}
|