WIP: Test - Update addon #9

Closed
Sirherobrine23 wants to merge 1 commits from new_set_config into main
13 changed files with 325 additions and 360 deletions

@ -2,20 +2,19 @@
node_modules/ node_modules/
/*.tgz /*.tgz
# Addon
build/**/*
!build/**/*.node
# Typescript # Typescript
src/**/*_test.* src/**/*test*
src/**/*.ts src/**/*.ts
!src/**/*.d.ts !src/**/*.d.ts
# vscode # vscode
.devcontainer/ .devcontainer/
.vscode/ .vscode/
.vscode-ctags
# Github and Git # Github, Gitlab, Git
.github/ .github/
.git* .git*
# Project
.vscode-ctags*
*.addrs.json

64
.vscode/settings.json vendored

@ -23,8 +23,70 @@
"PATH": "${workspaceFolder}/node_modules/.bin:${env:PATH}" "PATH": "${workspaceFolder}/node_modules/.bin:${env:PATH}"
}, },
"files.associations": { "files.associations": {
"*.dsc": "ini",
"*.gyp": "python",
"random": "cpp", "random": "cpp",
"limits": "cpp", "limits": "cpp",
"xstring": "cpp" "xstring": "cpp",
"__bit_reference": "cpp",
"__bits": "cpp",
"__config": "cpp",
"__debug": "cpp",
"__errc": "cpp",
"__hash_table": "cpp",
"__locale": "cpp",
"__mutex_base": "cpp",
"__node_handle": "cpp",
"__nullptr": "cpp",
"__split_buffer": "cpp",
"__string": "cpp",
"__threading_support": "cpp",
"__tree": "cpp",
"__tuple": "cpp",
"array": "cpp",
"atomic": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"exception": "cpp",
"initializer_list": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"locale": "cpp",
"map": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"variant": "cpp",
"vector": "cpp"
} }
} }

@ -1,15 +1,16 @@
#include <napi.h> #include <napi.h>
#include <wginterface.hh> #include <wginterface.hh>
unsigned long maxName() { unsigned long SetupAddon::maxName() {
return 16; return 16;
} }
std::string versionDrive() { std::string SetupAddon::versionDrive() {
return "Userspace"; return "Userspace";
} }
void listDevices::Execute() {} void listDevices::Execute() {}
void deleteInterface::Execute() {} void deleteInterface::Execute() {}
void setConfig::Execute() {}
void getConfig::Execute() {} void ConfigBase::getWireguardConfig() {}
void ConfigBase::setWireguardConfig() {}

@ -33,11 +33,11 @@ std::string getKernelMesage(int errStatus) {
return message; return message;
} }
unsigned long maxName() { unsigned long SetupAddon::maxName() {
return IFNAMSIZ; return IFNAMSIZ;
} }
std::string versionDrive() { std::string SetupAddon::versionDrive() {
return "Kernel"; return "Kernel";
} }
@ -67,22 +67,17 @@ class List {
void listDevices::Execute() { void listDevices::Execute() {
List l; List l;
try {
l.getAll(); l.getAll();
for (auto ifname : l.devs) { for (auto ifname : l.devs) {
listInfo setInfo; listInfo setInfo;
setInfo.tunType = "kernel"; setInfo.tunType = "kernel";
deviceNames[ifname] = setInfo; deviceNames[ifname] = setInfo;
} }
} catch (std::string err) {
SetError(err);
}
l.~List();
} }
void deleteInterface::Execute() { void deleteInterface::Execute() {
int status = wg_del_device(wgName.c_str()); int status = wg_del_device(wgName.c_str());
if (status < 0) SetError(std::string("Cannot delete interface, code status: ").append(std::to_string(status))); if (status < 0) throw std::string("Cannot delete interface, code status: ").append(std::to_string(status));
} }
int createInterface(std::string &wgName) { int createInterface(std::string &wgName) {
@ -102,11 +97,10 @@ int createInterface(std::string &wgName) {
return 0; return 0;
} }
void setConfig::Execute() { void ConfigBase::setWireguardConfig() {
int res = createInterface(wgName); int res = createInterface(wgName);
if (res < 0) { if (res < 0) {
SetError(std::string("Cannot create wireguard interface, Code: ").append(std::to_string(res))); throw std::string("Cannot create wireguard interface, Code: ").append(std::to_string(res));
return;
} }
// Set device struct // Set device struct
@ -139,7 +133,7 @@ void setConfig::Execute() {
if (replacePeers) deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_REPLACE_PEERS); if (replacePeers) deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_REPLACE_PEERS);
unsigned int peerIndex = 0; unsigned int peerIndex = 0;
for (auto it = peersVector.begin(); it != peersVector.end(); ++it) { for (auto it = this->Peers.begin(); it != this->Peers.end(); ++it) {
const std::string peerPubKey = it->first; const std::string peerPubKey = it->first;
auto peerConfig = it->second; auto peerConfig = it->second;
peerIndex++; peerIndex++;
@ -175,13 +169,13 @@ void setConfig::Execute() {
end = strchr(Endpoint, ']'); end = strchr(Endpoint, ']');
if (!end) { if (!end) {
free(Endpoint); free(Endpoint);
SetError("Unable to find matching brace of endpoint"); throw std::string("Unable to find matching brace of endpoint");
return; return;
} }
*end++ = '\0'; *end++ = '\0';
if (*end++ != ':' || !*end) { if (*end++ != ':' || !*end) {
free(Endpoint); free(Endpoint);
SetError("Unable to find port of endpoint"); throw std::string("Unable to find port of endpoint");
return; return;
} }
} else { } else {
@ -189,7 +183,7 @@ void setConfig::Execute() {
end = strrchr(Endpoint, ':'); end = strrchr(Endpoint, ':');
if (!end || !*(end + 1)) { if (!end || !*(end + 1)) {
free(Endpoint); free(Endpoint);
SetError("Unable to find port of endpoint"); throw std::string("Unable to find port of endpoint");
return; return;
} }
*end++ = '\0'; *end++ = '\0';
@ -211,7 +205,7 @@ void setConfig::Execute() {
(retries >= 0 && !retries--)) { (retries >= 0 && !retries--)) {
free(Endpoint); free(Endpoint);
fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), peerConfig.endpoint.c_str()); fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), peerConfig.endpoint.c_str());
SetError("Unable to resolve endpoint"); throw std::string("Unable to resolve endpoint");
return; return;
} }
fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), peerConfig.endpoint.c_str(), timeout / 1000000.0); fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), peerConfig.endpoint.c_str(), timeout / 1000000.0);
@ -232,7 +226,7 @@ void setConfig::Execute() {
} else { } else {
freeaddrinfo(resolved); freeaddrinfo(resolved);
free(Endpoint); free(Endpoint);
SetError("Neither IPv4 nor IPv6 address found"); throw std::string("Neither IPv4 nor IPv6 address found");
return; return;
} }
freeaddrinfo(resolved); freeaddrinfo(resolved);
@ -275,7 +269,7 @@ void setConfig::Execute() {
} }
// Set interface config // Set interface config
if ((res = wg_set_device(deviceStruct)) < 0) SetError(getKernelMesage(res)); if ((res = wg_set_device(deviceStruct)) < 0) throw std::string(getKernelMesage(res));
} }
const char* getHostAddress(bool addPort, const sockaddr* addr) { const char* getHostAddress(bool addPort, const sockaddr* addr) {
@ -304,10 +298,10 @@ std::string keyTo64(const uint8_t *key) {
return strKey; return strKey;
} }
void getConfig::Execute() { void ConfigBase::getWireguardConfig() {
int res; wg_device *device; int res; wg_device *device;
if ((res = wg_get_device(&device, strdup(wgName.c_str()))) < 0) { if ((res = wg_get_device(&device, strdup(wgName.c_str()))) < 0) {
SetError(std::string("Device not exists or cannot get config from this interface!, code error: ").append(std::to_string(res))); throw std::string("Device not exists or cannot get config from this interface!, code error: ").append(std::to_string(res));
return; return;
} }
@ -348,6 +342,6 @@ void getConfig::Execute() {
} }
} }
peersVector[keyTo64(peer->public_key)] = PeerConfig; this->Peers[keyTo64(peer->public_key)] = PeerConfig;
} }
} }

@ -43,10 +43,6 @@ static WIREGUARD_SET_ADAPTER_STATE_FUNC *WireGuardSetAdapterState;
static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration; static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration;
static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration; static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration;
unsigned long maxName() {
return IFNAMSIZ;
}
std::string getErrorString(DWORD errorMessageID) { std::string getErrorString(DWORD errorMessageID) {
if (errorMessageID == 0 || errorMessageID < 0) std::string("Error code: ").append(std::to_string(errorMessageID)); if (errorMessageID == 0 || errorMessageID < 0) std::string("Error code: ").append(std::to_string(errorMessageID));
LPSTR messageBuffer = nullptr; LPSTR messageBuffer = nullptr;
@ -60,7 +56,7 @@ std::string getErrorString(DWORD errorMessageID) {
return std::string("Error code: ").append(std::to_string(errorMessageID)).append(", Message: ").append(message); return std::string("Error code: ").append(std::to_string(errorMessageID)).append(", Message: ").append(message);
} }
std::string startAddon(const Napi::Env env, Napi::Object exports) { std::string SetupAddon::startAddon(const Napi::Env env, Napi::Object exports) {
if (!IsRunAsAdmin()) return "Run nodejs with administrator privilegies"; if (!IsRunAsAdmin()) return "Run nodejs with administrator privilegies";
auto DLLPATH = exports.Get("WIN32DLLPATH"); auto DLLPATH = exports.Get("WIN32DLLPATH");
if (!(DLLPATH.IsString())) return "Require WIREGUARD_DLL_PATH in addon load!"; if (!(DLLPATH.IsString())) return "Require WIREGUARD_DLL_PATH in addon load!";
@ -81,7 +77,11 @@ std::string startAddon(const Napi::Env env, Napi::Object exports) {
return ""; return "";
} }
std::string versionDrive() { unsigned long SetupAddon::maxName() {
return IFNAMSIZ;
}
std::string SetupAddon::versionDrive() {
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"getWgVersion", L"Wireguard-tools.js", NULL); WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"getWgVersion", L"Wireguard-tools.js", NULL);
DWORD Version = WireGuardGetRunningDriverVersion(); DWORD Version = WireGuardGetRunningDriverVersion();
if (Version == 0) { if (Version == 0) {
@ -116,11 +116,13 @@ void listDevices::Execute() {
deviceNames[std::string(iface)] = setInfo; deviceNames[std::string(iface)] = setInfo;
} while (FindNextFile(find_handle, &find_data)); } while (FindNextFile(find_handle, &find_data));
FindClose(find_handle); FindClose(find_handle);
if (ret < 0) return SetError(std::string("Erro code: ").append(std::to_string(ret))); if (ret < 0) {
throw std::string(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); 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"); if (dev_info == INVALID_HANDLE_VALUE) throw std::string("Cannot get devices");
for (DWORD i = 0;; ++i) { for (DWORD i = 0;; ++i) {
DWORD buf_len; DWORD buf_len;
@ -161,8 +163,8 @@ void listDevices::Execute() {
void deleteInterface::Execute() { void deleteInterface::Execute() {
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName));
if (!Adapter) return SetError("This interface not exists in Wireguard-Tools.js addon!"); if (!Adapter) throw std::string("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()))); if (!(WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_DOWN))) throw std::string("Failed to set down interface, ").append(getErrorString(GetLastError()));
WireGuardCloseAdapter(Adapter); WireGuardCloseAdapter(Adapter);
} }
@ -178,15 +180,16 @@ template <typename T, typename C> C* changePoint(T *x) {
return reinterpret_cast<C*>(((char*)x) + sizeof(T)); return reinterpret_cast<C*>(((char*)x) + sizeof(T));
} }
void getConfig::Execute() {
void ConfigBase::getWireguardConfig() {
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName));
if (!Adapter) return SetError("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; NET_LUID InterfaceLuid;
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
try { try {
for (auto aip : getIpAddr(InterfaceLuid)) Address.push_back(aip); for (auto aip : getIpAddr(InterfaceLuid)) Address.push_back(aip);
} catch (std::string err) { } catch (std::string err) {
return SetError(err); throw std::string(err);
} }
DWORD buf_len = 0; DWORD buf_len = 0;
@ -194,9 +197,9 @@ void getConfig::Execute() {
while (!(WireGuardGetConfiguration(Adapter, wg_iface, &buf_len))) { while (!(WireGuardGetConfiguration(Adapter, wg_iface, &buf_len))) {
free(wg_iface); free(wg_iface);
if (GetLastError() != ERROR_MORE_DATA) return SetError((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); 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) 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_PRIVATE_KEY) privateKey = wgKeys::toString(wg_iface->PrivateKey);
@ -231,24 +234,24 @@ void getConfig::Execute() {
++wg_aip; ++wg_aip;
} }
wg_peer = reinterpret_cast<WIREGUARD_PEER*>(wg_aip); wg_peer = reinterpret_cast<WIREGUARD_PEER*>(wg_aip);
peersVector[pubKey] = peerConfig; this->Peers[pubKey] = peerConfig;
} }
free(wg_iface); free(wg_iface);
} }
void setConfig::Execute() { void ConfigBase::setWireguardConfig() {
DWORD buf_len = sizeof(WIREGUARD_INTERFACE); DWORD buf_len = sizeof(WIREGUARD_INTERFACE);
for (auto peer : peersVector) { for (auto peer : this->Peers) {
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER)) return SetError("Buffer overflow"); if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER)) throw std::string("Buffer overflow");
buf_len += sizeof(WIREGUARD_PEER); buf_len += sizeof(WIREGUARD_PEER);
for (auto aip : peer.second.allowedIPs) { for (auto aip : peer.second.allowedIPs) {
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP)) return SetError("Buffer overflow"); if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP)) throw std::string("Buffer overflow");
buf_len += sizeof(WIREGUARD_ALLOWED_IP); buf_len += sizeof(WIREGUARD_ALLOWED_IP);
} }
} }
WIREGUARD_INTERFACE *wg_iface = reinterpret_cast<WIREGUARD_INTERFACE*>(calloc(1, buf_len)); WIREGUARD_INTERFACE *wg_iface = reinterpret_cast<WIREGUARD_INTERFACE*>(calloc(1, buf_len));
if (!wg_iface) return SetError("Cannot alloc buff"); if (!wg_iface) throw std::string("Cannot alloc buff");
wg_iface->PeersCount = 0; wg_iface->PeersCount = 0;
wgKeys::stringToKey(wg_iface->PrivateKey, privateKey); wgKeys::stringToKey(wg_iface->PrivateKey, privateKey);
@ -261,13 +264,13 @@ void setConfig::Execute() {
WIREGUARD_ALLOWED_IP *wg_aip; WIREGUARD_ALLOWED_IP *wg_aip;
WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface); WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface);
for (auto __peer : peersVector) { for (auto __peer : this->Peers) {
auto peerPublicKey = __peer.first; auto peerConfig = __peer.second; auto peerPublicKey = __peer.first; auto peerConfig = __peer.second;
try { try {
wgKeys::stringToKey(wg_peer->PublicKey, peerPublicKey); wgKeys::stringToKey(wg_peer->PublicKey, peerPublicKey);
} catch (std::string &err) { } catch (std::string &err) {
SetError(err);
free(wg_iface); free(wg_iface);
throw std::string(err);
return; return;
} }
wg_peer->Flags = WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PUBLIC_KEY; wg_peer->Flags = WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PUBLIC_KEY;
@ -283,8 +286,8 @@ void setConfig::Execute() {
wgKeys::stringToKey(wg_peer->PresharedKey, peerConfig.presharedKey); wgKeys::stringToKey(wg_peer->PresharedKey, peerConfig.presharedKey);
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY); wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY);
} catch (std::string &err) { } catch (std::string &err) {
SetError(err);
free(wg_iface); free(wg_iface);
throw std::string(err);
return; return;
} }
} }
@ -297,8 +300,8 @@ void setConfig::Execute() {
insertEndpoint(&wg_peer->Endpoint, peerConfig.endpoint.c_str()); insertEndpoint(&wg_peer->Endpoint, peerConfig.endpoint.c_str());
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT); wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT);
} catch (std::string &err) { } catch (std::string &err) {
SetError(std::string("Cannot parse endpoint, ").append(err));
free(wg_iface); free(wg_iface);
throw std::string(std::string("Cannot parse endpoint, ").append(err));
return; return;
} }
} }
@ -327,15 +330,21 @@ void setConfig::Execute() {
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName));
if (!Adapter) Adapter = WireGuardCreateAdapter(toLpcwstr(wgName), L"Wireguard-tools.js", NULL); if (!Adapter) Adapter = WireGuardCreateAdapter(toLpcwstr(wgName), L"Wireguard-tools.js", NULL);
if (!Adapter) SetError(std::string("Failed to create adapter, ").append(getErrorString(GetLastError()))); if (!Adapter) {
else if (!WireGuardSetConfiguration(Adapter, reinterpret_cast<WIREGUARD_INTERFACE*>(wg_iface), buf_len)) { free(wg_iface);
throw std::string(std::string("Failed to create adapter, ").append(getErrorString(GetLastError())));
} else if (!WireGuardSetConfiguration(Adapter, reinterpret_cast<WIREGUARD_INTERFACE*>(wg_iface), buf_len)) {
free(wg_iface);
auto status = GetLastError(); auto status = GetLastError();
SetError(std::string("Failed to set interface config, ").append(getErrorString(status))); auto err = std::string(std::string("Failed to set interface config, ").append(getErrorString(status)));
WireGuardCloseAdapter(Adapter); WireGuardCloseAdapter(Adapter);
throw err;
} else if (!WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP)) { } else if (!WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP)) {
free(wg_iface);
auto status = GetLastError(); auto status = GetLastError();
SetError(std::string("Failed to set interface up, ").append(getErrorString(status))); auto err = std::string(std::string("Failed to set interface up, ").append(getErrorString(status)));
WireGuardCloseAdapter(Adapter); WireGuardCloseAdapter(Adapter);
throw err;
} else { } else {
if (Address.size() > 0) { if (Address.size() > 0) {
std::string IPv4, IPv6; std::string IPv4, IPv6;
@ -355,7 +364,10 @@ void setConfig::Execute() {
NET_LUID InterfaceLuid; NET_LUID InterfaceLuid;
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
auto setStatus = insertIpAddr(InterfaceLuid, IPv4, IPv6); auto setStatus = insertIpAddr(InterfaceLuid, IPv4, IPv6);
if (setStatus.size() > 0) SetError(setStatus); if (setStatus.size() > 0) {
free(wg_iface);
throw std::string(setStatus);
}
} }
} }
} }

@ -5,34 +5,28 @@
Napi::Object Init(Napi::Env initEnv, Napi::Object exports) { Napi::Object Init(Napi::Env initEnv, Napi::Object exports) {
/// Call Addon /// Call Addon
#ifdef ONSTARTADDON #ifdef ONSTARTADDON
auto status = startAddon(initEnv, exports); auto status = SetupAddon::startAddon(initEnv, exports);
if (status.length() >= 1) { if (status.length() >= 1) {
Napi::Error::New(initEnv, status).ThrowAsJavaScriptException(); Napi::Error::New(initEnv, status).ThrowAsJavaScriptException();
return exports; return exports;
} }
#endif #endif
// Wireguard constants set // Init Objects
const Napi::Object constants = Napi::Object::New(initEnv); const Napi::Object Constant = Napi::Object::New(initEnv), Userspace = Napi::Object::New(initEnv);
// Set wireguard version if present // Set wireguard version if present
constants.Set("driveVersion", versionDrive()); const auto wgVersion = SetupAddon::versionDrive();
if (wgVersion.length() > 0) Constant.Set("driveVersion", wgVersion);
else Constant.Set("driveVersion", initEnv.Null());
// Wireguard max name length // Wireguard max name length
constants.Set("nameLength", maxName()); Constant.Set("nameLength", SetupAddon::maxName());
constants.Set("base64Length", B64_WG_KEY_LENGTH); Userspace.Set("createTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); }));
constants.Set("keyLength", WG_KEY_LENGTH); Userspace.Set("deleteTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); }));
Userspace.Set("checkTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); }));
// Set addon constants Userspace.Set("getTunPath", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); }));
exports.Set("constants", constants);
// Function's
#ifdef USERSPACE_GO
exports.Set("createTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); }));
exports.Set("deleteTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); }));
exports.Set("checkTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); }));
exports.Set("getTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); }));
#endif
#ifdef SETCONFIG #ifdef SETCONFIG
exports.Set("setConfig", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { exports.Set("setConfig", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value {
@ -43,7 +37,7 @@ Napi::Object Init(Napi::Env initEnv, Napi::Object exports) {
if (!(wgName.IsString())) { if (!(wgName.IsString())) {
Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException(); Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException();
return env.Undefined(); return env.Undefined();
} else if (wgName.ToString().Utf8Value().length() >= maxName()) { } else if (wgName.ToString().Utf8Value().length() >= SetupAddon::maxName()) {
Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException(); Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException();
return env.Undefined(); return env.Undefined();
} else if (!(wgConfig.IsObject())) { } else if (!(wgConfig.IsObject())) {
@ -54,7 +48,7 @@ Napi::Object Init(Napi::Env initEnv, Napi::Object exports) {
try { try {
auto worker = new setConfig(env, wgName.ToString().Utf8Value(), wgConfig.ToObject()); auto worker = new setConfig(env, wgName.ToString().Utf8Value(), wgConfig.ToObject());
worker->Queue(); worker->Queue();
return worker->setPromise.Promise(); return worker->Promised.Promise();
} catch (const Napi::Error &err) { } catch (const Napi::Error &err) {
err.ThrowAsJavaScriptException(); err.ThrowAsJavaScriptException();
} }
@ -69,14 +63,14 @@ Napi::Object Init(Napi::Env initEnv, Napi::Object exports) {
if (!(wgName.IsString())) { if (!(wgName.IsString())) {
Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException(); Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException();
return env.Undefined(); return env.Undefined();
} else if (wgName.ToString().Utf8Value().length() >= maxName()) { } else if (wgName.ToString().Utf8Value().length() >= SetupAddon::maxName()) {
Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException(); Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException();
return env.Undefined(); return env.Undefined();
} }
auto worker = new deleteInterface(env, wgName.ToString().Utf8Value()); auto worker = new deleteInterface(env, wgName.ToString().Utf8Value());
worker->Queue(); worker->Queue();
return worker->deletePromise.Promise(); return worker->Promised.Promise();
})); }));
#endif #endif
@ -87,7 +81,7 @@ Napi::Object Init(Napi::Env initEnv, Napi::Object exports) {
if (!(wgName.IsString())) { if (!(wgName.IsString())) {
Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException(); Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException();
return env.Undefined(); return env.Undefined();
} else if (wgName.ToString().Utf8Value().length() >= maxName()) { } else if (wgName.ToString().Utf8Value().length() >= SetupAddon::maxName()) {
Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException(); Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException();
return env.Undefined(); return env.Undefined();
} }
@ -95,7 +89,7 @@ Napi::Object Init(Napi::Env initEnv, Napi::Object exports) {
try { try {
auto worker = new getConfig(env, wgName.ToString().Utf8Value()); auto worker = new getConfig(env, wgName.ToString().Utf8Value());
worker->Queue(); worker->Queue();
return worker->getPromise.Promise(); return worker->Promised.Promise();
} catch (const Napi::Error &err) { } catch (const Napi::Error &err) {
err.ThrowAsJavaScriptException(); err.ThrowAsJavaScriptException();
} }
@ -108,9 +102,12 @@ Napi::Object Init(Napi::Env initEnv, Napi::Object exports) {
const Napi::Env env = info.Env(); const Napi::Env env = info.Env();
auto worker = new listDevices(env); auto worker = new listDevices(env);
worker->Queue(); worker->Queue();
return worker->listDevicesPromise.Promise(); return worker->Promised.Promise();
})); }));
#endif #endif
exports.Set("constant", Constant);
exports.Set("userspace", Userspace);
return exports; return exports;
} }
NODE_API_MODULE(addon, Init); NODE_API_MODULE(addon, Init);

@ -5,6 +5,8 @@
#include <map> #include <map>
#include <wgkeys.hh> #include <wgkeys.hh>
// namespace SetupAddon
namespace SetupAddon {
// Get wireguard max name length // Get wireguard max name length
unsigned long maxName(); unsigned long maxName();
@ -13,23 +15,28 @@ std::string versionDrive();
// On start module call this function // On start module call this function
std::string startAddon(const Napi::Env env, Napi::Object exports); std::string startAddon(const Napi::Env env, Napi::Object exports);
};
class deleteInterface : public Napi::AsyncWorker { class GlobalPromise : public Napi::AsyncWorker {
public:
GlobalPromise(const Napi::Env env): AsyncWorker(env), Promised{env} {}
~GlobalPromise() {}
const Napi::Promise::Deferred Promised;
void OnError(const Napi::Error &e) override {
Napi::HandleScope scope(Env());
Promised.Reject(e.Value());
}
};
class deleteInterface : public GlobalPromise {
private: private:
std::string wgName; std::string wgName;
public: public:
deleteInterface(const Napi::Env env, std::string name): AsyncWorker(env), wgName{name}, deletePromise{env} {} deleteInterface(const Napi::Env env, std::string name): GlobalPromise(env), wgName{name} {}
~deleteInterface() {} ~deleteInterface() {}
const Napi::Promise::Deferred deletePromise;
void OnError(const Napi::Error &e) override {
Napi::HandleScope scope(Env());
deletePromise.Reject(e.Value());
}
void OnOK() override { void OnOK() override {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
deletePromise.Resolve(Env().Undefined()); Promised.Resolve(Env().Undefined());
}; };
// Set platform Execute script // Set platform Execute script
@ -41,19 +48,12 @@ class listInfo {
std::string tunType, pathSock; std::string tunType, pathSock;
}; };
class listDevices : public Napi::AsyncWorker { class listDevices : public GlobalPromise {
private: private:
std::map<std::string, listInfo> deviceNames; std::map<std::string, listInfo> deviceNames;
public: public:
~listDevices() {} ~listDevices() {}
listDevices(const Napi::Env env) : AsyncWorker(env), listDevicesPromise{env} {} listDevices(const Napi::Env env) : GlobalPromise(env) {}
const Napi::Promise::Deferred listDevicesPromise;
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
listDevicesPromise.Reject(e.Value());
}
void OnOK() override { void OnOK() override {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
const Napi::Env env = Env(); const Napi::Env env = Env();
@ -66,7 +66,7 @@ class listDevices : public Napi::AsyncWorker {
if (infoSrc.pathSock.size() > 0) info.Set("path", infoSrc.pathSock); if (infoSrc.pathSock.size() > 0) info.Set("path", infoSrc.pathSock);
deviceArray.Set(deviceArray.Length(), info); deviceArray.Set(deviceArray.Length(), info);
} }
listDevicesPromise.Resolve(deviceArray); Promised.Resolve(deviceArray);
}; };
void Execute() override; void Execute() override;
}; };
@ -118,11 +118,8 @@ class Peer {
int ProtocolVersion = 0; int ProtocolVersion = 0;
}; };
/* class ConfigBase {
Configure uma interface do Wireguard. public:
*/
class setConfig : public Napi::AsyncWorker {
private:
// Wireguard interface name (required) // Wireguard interface name (required)
std::string wgName; std::string wgName;
@ -133,11 +130,11 @@ class setConfig : public Napi::AsyncWorker {
std::string publicKey; std::string publicKey;
// Wireguard port listen // Wireguard port listen
unsigned short portListen = 0; unsigned short portListen;
// FirewallMark specifies a device's firewall mark // FirewallMark specifies a device's firewall mark
// else set to 0, the firewall mark will be cleared. // else set to 0, the firewall mark will be cleared.
int fwmark = -1; int fwmark;
// Interface address'es // Interface address'es
std::vector<std::string> Address; std::vector<std::string> Address;
@ -146,24 +143,39 @@ class setConfig : public Napi::AsyncWorker {
bool replacePeers = false; bool replacePeers = false;
// Wireguard peers, Map: <publicKey(std::string), Peer> // Wireguard peers, Map: <publicKey(std::string), Peer>
std::map<std::string, Peer> peersVector; std::map<std::string, Peer> Peers;
public:
const Napi::Promise::Deferred setPromise;
void OnOK() override { ConfigBase() {
Napi::HandleScope scope(Env()); this->fwmark = 0;
// Callback().Call({ Env().Undefined() }); this->portListen = 0;
setPromise.Resolve(Env().Undefined()); }
}; ~ConfigBase() {
this->Address.clear();
void OnError(const Napi::Error& e) override { this->Peers.clear();
Napi::HandleScope scope(Env());
// Callback().Call({ e.Value() });
setPromise.Reject(e.Value());
} }
/**
* Set configuration in interface
*/
void setWireguardConfig();
/**
* Get configuration from interface and insert in class
*/
void getWireguardConfig();
};
/*
Configure uma interface do Wireguard.
*/
class setConfig : public GlobalPromise, ConfigBase {
public:
void OnOK() override {
Napi::HandleScope scope(Env());
Promised.Resolve(Env().Undefined());
};
~setConfig() {} ~setConfig() {}
setConfig(const Napi::Env env, std::string name, const Napi::Object &config) : AsyncWorker(env), wgName{name}, setPromise{env} { setConfig(const Napi::Env env, std::string name, const Napi::Object &config) : GlobalPromise(env) {
// Wireguard public key // Wireguard public key
const auto sppk = config.Get("publicKey"); const auto sppk = config.Get("publicKey");
if (sppk.IsString()) { if (sppk.IsString()) {
@ -201,14 +213,14 @@ class setConfig : public Napi::AsyncWorker {
// Peers // Peers
const auto speers = config.Get("peers"); const auto speers = config.Get("peers");
if (speers.IsObject()) { if (speers.IsObject()) {
const Napi::Object Peers = speers.ToObject(); const Napi::Object PeersObject = speers.ToObject();
const Napi::Array Keys = Peers.GetPropertyNames(); const Napi::Array Keys = PeersObject.GetPropertyNames();
for (unsigned int peerIndex = 0; peerIndex < Keys.Length(); peerIndex++) { for (unsigned int peerIndex = 0; peerIndex < Keys.Length(); peerIndex++) {
const auto peerPubKey = Keys[peerIndex]; const auto peerPubKey = Keys[peerIndex];
if (peerPubKey.IsString() && Peers.Get(Keys[peerIndex]).IsObject()) { if (peerPubKey.IsString() && PeersObject.Get(Keys[peerIndex]).IsObject()) {
std::string ppkey = peerPubKey.ToString().Utf8Value(); std::string ppkey = peerPubKey.ToString().Utf8Value();
if (ppkey.length() != B64_WG_KEY_LENGTH) throw Napi::Error::New(env, std::string("Set valid peer publicKey, value: ").append(ppkey)); if (ppkey.length() != B64_WG_KEY_LENGTH) throw Napi::Error::New(env, std::string("Set valid peer publicKey, value: ").append(ppkey));
const Napi::Object peerConfigObject = Peers.Get(Keys[peerIndex]).ToObject(); const Napi::Object peerConfigObject = PeersObject.Get(Keys[peerIndex]).ToObject();
Peer peerConfig = Peer(); Peer peerConfig = Peer();
const auto removeMe = peerConfigObject.Get("removeMe"); const auto removeMe = peerConfigObject.Get("removeMe");
@ -240,52 +252,33 @@ class setConfig : public Napi::AsyncWorker {
} }
// Insert peer // Insert peer
peersVector[ppkey] = peerConfig; this->Peers[ppkey] = peerConfig;
} }
} }
} }
} }
// Set platform Execute script // Set platform Execute script
void Execute() override; void Execute() override {
try {
this->setWireguardConfig();
} catch (std::string &err) {
SetError(err);
}
}
}; };
class getConfig : public Napi::AsyncWorker { class getConfig : public GlobalPromise, ConfigBase {
private:
// Wireguard interface name (required)
std::string wgName;
// Wireguard private key (required)
std::string privateKey;
// Wireguard interface publicKey <optional>
std::string publicKey;
// Wireguard port listen
unsigned int portListen;
// FirewallMark specifies a device's firewall mark
// else set to 0, the firewall mark will be cleared.
int fwmark = -1;
// Interface address'es
std::vector<std::string> Address;
/*
Wireguard peers
Map: <publicKey, Peer>
*/
std::map<std::string, Peer> peersVector;
public: public:
~getConfig() {} ~getConfig() {}
getConfig(const Napi::Env env, std::string name): AsyncWorker(env), wgName{name}, getPromise{env} {} getConfig(const Napi::Env env, std::string name): GlobalPromise(env) {}
const Napi::Promise::Deferred getPromise; void Execute() override {
try {
void OnError(const Napi::Error& e) override { this->getWireguardConfig();
Napi::HandleScope scope(Env()); } catch (std::string &err) {
getPromise.Reject(e.Value()); SetError(err);
}
} }
void OnOK() override { void OnOK() override {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
const Napi::Env env = Env(); const Napi::Env env = Env();
@ -303,7 +296,7 @@ class getConfig : public Napi::AsyncWorker {
// Peer object // Peer object
const auto PeersObject = Napi::Object::New(env); const auto PeersObject = Napi::Object::New(env);
for (auto &peer : peersVector) { for (auto &peer : this->Peers) {
const auto PeerObject = Napi::Object::New(env); const auto PeerObject = Napi::Object::New(env);
auto peerConfig = peer.second; auto peerConfig = peer.second;
@ -330,9 +323,6 @@ class getConfig : public Napi::AsyncWorker {
config.Set("peers", PeersObject); config.Set("peers", PeersObject);
// Resolve config json // Resolve config json
getPromise.Resolve(config); Promised.Resolve(config);
}; };
// Set platform Execute script
void Execute() override;
}; };

@ -46,6 +46,6 @@
}, },
"dependencies": { "dependencies": {
"node-addon-api": "^7.1.0", "node-addon-api": "^7.1.0",
"rebory": "^0.1.12" "rebory": "^0.2.4"
} }
} }

@ -1,5 +1,6 @@
export * as key from "./key.js";
export * as wgQuick from "./quick.js"; export * as wgQuick from "./quick.js";
export * as key from "./key.js";
export * from "./wginterface.js"; export * from "./wginterface.js";
export * as wginterface from "./wginterface.js";
export * as default from "./wginterface.js"; export * as default from "./wginterface.js";
export * as wginterface from "./wginterface.js";

@ -1,45 +1,33 @@
import { promises as fs } from "fs";
import { isIPv4, createConnection as netConnection } from "net";
import path from "path"; import path from "path";
import readline from "readline";
import { finished } from "stream/promises";
import rebory from "rebory"; import rebory from "rebory";
import { fileURLToPath } from "url"; import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
const addon = rebory.loadAddon(path.join(__dirname, "../binding.yaml")).wginterface.loadRelease<{ const addon = (await rebory.loadAddon(path.join(__dirname, "../binding.yaml"))).wginterface.load_addon<{
listDevices?: () => Promise<{from: "userspace"|"kernel", name: string, path?: string}[]>;
deleteInterface?: (wgName: string) => Promise<void>;
setConfig?: (wgName: string, config: WgConfigSet) => Promise<void>; setConfig?: (wgName: string, config: WgConfigSet) => Promise<void>;
getConfig?: (wgName: string) => Promise<WgConfigGet>; getConfig?: (wgName: string) => Promise<WgConfigGet>;
listDevices?: () => Promise<string[]>;
deleteInterface?: (wgName: string) => Promise<void>;
/**
* Wireguard addon userspace
*/
userspace: {
createTun?: () => Promise<number|string>; createTun?: () => Promise<number|string>;
deleteTun?: () => void; deleteTun?: () => void;
checkTun?: () => Promise<boolean>; checkTun?: () => Promise<boolean>;
getTun?: () => Promise<number|string>; getTunPath?: () => Promise<number|string>;
};
/** Wireguard addon constants */ /** Wireguard addon constants */
constants: { constants: {
driveVersion: string; driveVersion: string|null;
base64Length: number;
keyLength: number;
nameLength: number; nameLength: number;
}; };
}>({ }>({
WIN32DLLPATH: path.resolve(__dirname, "../addons/tools/win/wireguard-nt/bin", ((process.arch === "x64" && "amd64") || (process.arch === "ia32" && "i386"))||process.arch, "wireguard.dll") WIN32DLLPATH: path.resolve(__dirname, "../addons/tools/win/wireguard-nt/bin", ((process.arch === "x64" && "amd64") || (process.arch === "ia32" && "i386"))||process.arch, "wireguard.dll")
}); });
export const {
constants
} = addon;
/** default location to run socket's */
const defaultPath = (process.env.WIRWGUARD_GO_RUN||"").length > 0 ? path.resolve(process.cwd(), process.env.WIRWGUARD_GO_RUN) : process.platform === "win32" ? "\\\\.\\pipe\\WireGuard" : "/var/run/wireguard";
async function exists(path: string) {
return fs.open(path).then(o => o && (o.close().then(() => true, () => true))||true, () => false);
}
export interface Peer { export interface Peer {
/** Preshared key to peer */ /** Preshared key to peer */
presharedKey?: string; presharedKey?: string;
@ -99,151 +87,71 @@ export interface WgConfigSet extends WgConfigBase<PeerSet> {
export type WgGlobalConfig = WgConfigSet & WgConfigGet; export type WgGlobalConfig = WgConfigSet & WgConfigGet;
/** /**
* Get Wireguard devices and locations * Userspace wireguard
*/ */
export async function listDevices() { export namespace Userspace {
let devices: {from: "userspace"|"kernel", name: string, path?: string}[] = [];
if (typeof addon.listDevices === "function") devices = devices.concat(await addon.listDevices());
if (await exists(defaultPath)) (await fs.readdir(defaultPath)).forEach(file => devices.push({ from: "userspace", name: file.endsWith(".sock") ? file.slice(0, -5) : file, path: path.join("/var/run/wireguard", file) }));
return devices;
}
/** /**
* Delete wireguard interface if present * Set Wireguard interface configuration
* @param wgName - Interface name * @param name - Interface name
* @returns
*/
export async function deleteInterface(wgName: string): Promise<void> {
if (typeof addon.deleteInterface === "function") return addon.deleteInterface(wgName);
const dev = (await listDevices()).find(s => s.name === wgName);
if (dev && dev.path) return fs.rm(dev.path, { force: true });
}
/**
* Add the settings to the Wireguard interface, if it does not exist and the interface will be created automatically.
*
* To update the interface settings, first get the interface settings to update!
*
* @param wgName - Interface name
* @param config - Interface config * @param config - Interface config
*/ */
export async function setConfig(wgName: string, config: WgConfigGet): Promise<void>; export async function SetConfig(name: string, config: WgConfigSet) {}
/** /**
* Add the settings to the Wireguard interface, if it does not exist and the interface will be created automatically. * Get Wireguard interface config if exist
* * @param name - Interface name
* To update the interface settings, first get the interface settings to update!
*
* @param wgName - Interface name
* @param config - Interface config
*/ */
export async function setConfig(wgName: string, config: WgConfigSet): Promise<void> { export async function GetConfig(name: string): Promise<WgConfigGet> { return null; }
if (wgName.length > constants.nameLength) throw new Error("Interface name more then allowed", { cause: constants.nameLength });
if (typeof addon.setConfig === "function") return addon.setConfig(wgName, config);
const client = netConnection(path.join(defaultPath, (wgName).concat(".sock")));
const writel = (...data: any[]) => client.write(data.map(String).join("").concat("\n"));
// Init set config in interface
writel("set=1");
// Port listening /**
if (config.portListen !== undefined && Math.floor(config.portListen) >= 0) writel(("listen_port="), ((Math.floor(config.portListen)))); * List Wireguard userspace devices
* @returns Wireguard userspace devices
*/
export async function ListDevices(): Promise<{name: string, path?: string}[]> { return []; }
// fwmark /**
if (Math.floor(config.fwmark) >= 0) writel(("fwmark="), ((Math.floor(config.fwmark)))); * Delete Wireguard Userspace interface
* @param name - Interface name
// Replace peer's */
if (config.replacePeers) writel("replace_peers=true"); export async function DeleteDevice(name: string) {}
// Keys
if (typeof config.privateKey === "string" && config.privateKey.length > 0) writel(("private_key="), (Buffer.from(config.privateKey, "base64").toString("hex")));
// Mount peer
for (const publicKey of Object.keys(config.peers||{})) {
const { presharedKey, endpoint, keepInterval, removeMe, allowedIPs = [] } = config.peers[publicKey];
// Public key
writel(("public_key="), (Buffer.from(publicKey, "base64").toString("hex")));
if (removeMe) {
writel("remove=true"); // Remove peer
continue;
}
if (typeof endpoint === "string" && endpoint.length > 0) writel(("endpoint="), (endpoint));
if (typeof presharedKey === "string" && presharedKey.length > 3) writel(("preshared_key="), (Buffer.from(presharedKey, "base64").toString("hex")));
if (typeof keepInterval === "number" && Math.floor(keepInterval) > 0) writel(("persistent_keepalive_interval="), (String(Math.floor(keepInterval))));
if (allowedIPs.length > 0) {
writel("replace_allowed_ips=true");
const fixed = allowedIPs.map(i => i.indexOf("/") === -1 ? i.concat("/", (isIPv4(i) ? "32" : "128")) : i)
for (const IIP of fixed) writel(("allowed_ip="), (IIP));
}
}
let payload = "";
client.once("data", function processBuff(buff) {
payload = payload.concat(buff.toString("utf8"));
if (payload[payload.length - 1] === "\n" && payload[payload.length - 2] === "\n") {
client.end(); // Close conenction
return;
}
client.once("data", processBuff);
});
client.write("\n");
await finished(client, { error: true });
const payloadKeys = payload.split("\n").filter(i => i.length > 3).map(line => { const iit = line.indexOf("="); return [ line.slice(0, iit), line.slice(iit+1) ]; })
if (payloadKeys.at(-1)[1] !== "0") {
const err = new Error("Invalid send config, check log");
throw err;
}
} }
/** /**
* Get wireguard interface config * Kernel Wireguard
* @param wgName - Interface name
* @returns
*/ */
export async function getConfig(wgName: string): Promise<WgConfigGet> { export namespace Kernel {
if (typeof addon.getConfig === "function") return addon.getConfig(wgName); export const { constants: { driveVersion, nameLength } } = addon;
const info = (await listDevices()).find(int => int.name === wgName); /**
if (!info) throw new Error("Create interface, not exists"); * Set Wireguard interface configuration and if not exists create
const client = netConnection(path.join(defaultPath, wgName.concat(".sock"))); *
const config: WgConfigGet = Object(); * @param name - Wireguard interface name
let latestPeer: string, previewKey: string; * @param config - Interface configuration
*/
export async function SetConfig(name: string, config: WgConfigSet) {
await addon.setConfig(name, config);
}
const tetrisBreak = readline.createInterface(client); /**
tetrisBreak.on("line", function lineProcess(line) { * Get Wireguard interface configuration
if (line === "") tetrisBreak.removeListener("line", lineProcess).close(); * @param name - Wireguard interface name
const findout = line.indexOf("="), keyName = line.slice(0, findout), value = line.slice(findout+1); */
if (findout <= 0) return; export async function GetConfig(name: string): Promise<WgConfigGet> {
if (keyName === "errno" && value !== "0") throw new Error(("wireguard-go error, code: ").concat(value)); return addon.getConfig(name);
}
// Drop /**
if ((["last_handshake_time_nsec", "protocol_version", "errno"]).includes(keyName)) return; * Lista Wireguard interfaces
else if (keyName === "private_key") config.privateKey = Buffer.from(value, "hex").toString("base64"); * @returns Devices
else if (keyName === "listen_port") config.portListen = Number(value); */
else if (keyName === "endpoint") ((config.peers||(config.peers = {}))[latestPeer]).endpoint = value; export async function ListDevices(): Promise<string[]> {
else if (keyName === "persistent_keepalive_interval") ((config.peers||(config.peers = {}))[latestPeer]).keepInterval = Number(value); return addon.listDevices();
else if (keyName === "rx_bytes") ((config.peers||(config.peers = {}))[latestPeer]).rxBytes = Number(value); }
else if (keyName === "tx_bytes") ((config.peers||(config.peers = {}))[latestPeer]).txBytes = Number(value);
else if (keyName === "last_handshake_time_sec") ((config.peers||(config.peers = {}))[latestPeer]).lastHandshake = new Date(Number(value) * 1000); /**
else if (keyName === "allowed_ip") { * Delete Wireguard interface
if (!value) return; * @param name - Wireguard interface name
((config.peers||(config.peers = {}))[latestPeer]).allowedIPs = (((config.peers||(config.peers = {}))[latestPeer]).allowedIPs||[]).concat(value); */
} else if (keyName === "preshared_key") { export async function DeleteDevice(name: string) {
if (value === "0000000000000000000000000000000000000000000000000000000000000000") return; return addon.deleteInterface(name);
((config.peers||(config.peers = {}))[latestPeer]).presharedKey = Buffer.from(value, "hex").toString("base64");
} else if (keyName === "public_key") {
const keyDecode = Buffer.from(value, "hex").toString("base64");
if (previewKey !== "public_key") (config.peers||(config.peers = {}))[latestPeer] = {};
else {
config.publicKey = latestPeer;
(config.peers||(config.peers = {}))[keyDecode] = (config.peers||(config.peers = {}))[latestPeer];
delete (config.peers||(config.peers = {}))[latestPeer];
latestPeer = keyDecode;
} }
} }
previewKey = keyName;
});
client.write("get=1\n\n");
await new Promise((done, reject) => tetrisBreak.on("error", reject).once("close", done));
await finished(client.end());
return config;
}

@ -1,10 +1,10 @@
import test from "node:test"; import test from "node:test";
import { setConfig, deleteInterface, WgConfigSet, getConfig } from "./wginterface.js"; import { Kernel, Userspace, WgConfigSet } from "./wginterface.js";
import { publicKey } from "./key.js"; import { publicKey } from "./key.js";
import { userInfo } from "os"; import { userInfo } from "os";
if (process.platform === "win32" || process.platform === "linux" && (userInfo().uid === 0)) { if (process.platform === "win32" || process.platform === "linux" && (userInfo().uid === 0)) {
test("Wireguard configuration", async t => { await test(String.prototype.concat("Wireguard kernel (", Kernel.driveVersion, ")"), async t => {
// Config base // Config base
const peer1Key = 'EKgSatFzZtsv1qFJ6gE8HqfuA+tXzW+7vDeVc7Xaa2E=', peer2Key = '4BSvgiM9j5jjuR0Vg3gbqTFD5+CyuOU2K2kJE5+cakQ=', const peer1Key = 'EKgSatFzZtsv1qFJ6gE8HqfuA+tXzW+7vDeVc7Xaa2E=', peer2Key = '4BSvgiM9j5jjuR0Vg3gbqTFD5+CyuOU2K2kJE5+cakQ=',
config: WgConfigSet = { config: WgConfigSet = {
@ -22,11 +22,11 @@ if (process.platform === "win32" || process.platform === "linux" && (userInfo().
} }
await t.test("Set config in interface", async () => { await t.test("Set config in interface", async () => {
await setConfig("wg23", config); await Kernel.SetConfig("wg23", config);
}); });
await t.test("Get config in interface", async () => { await t.test("Get config in interface", async () => {
const __config = await getConfig("wg23"); const __config = await Kernel.GetConfig("wg23");
if (!__config.peers[publicKey(peer1Key)]) throw new Error("Not exist peer 1!"); if (!__config.peers[publicKey(peer1Key)]) throw new Error("Not exist peer 1!");
}); });
@ -38,17 +38,21 @@ if (process.platform === "win32" || process.platform === "linux" && (userInfo().
} }
await t.test("Set config in interface", async () => { await t.test("Set config in interface", async () => {
await setConfig("wg23", config); await Kernel.SetConfig("wg23", config);
}); });
await t.test("Get config in interface", async () => { await t.test("Get config in interface", async () => {
const __config = await getConfig("wg23"); const __config = await Kernel.GetConfig("wg23");
if (__config.peers[publicKey(peer1Key)]) throw new Error("Invalid config get!"); if (__config.peers[publicKey(peer1Key)]) throw new Error("Invalid config get!");
if (!__config.peers[publicKey(peer2Key)]) throw new Error("Not exist peer 2!"); if (!__config.peers[publicKey(peer2Key)]) throw new Error("Not exist peer 2!");
}); });
await t.test("Delete interface", async () => { await t.test("Delete interface", async () => {
await deleteInterface("wg23"); await Kernel.DeleteDevice("wg23");
}); });
}); });
await test("Wireguard Userspace", async t => {
Userspace;
});
} }

@ -18,10 +18,7 @@
] ]
}, },
"exclude": [ "exclude": [
"**/libs/**", "node_modules/"
"**/docs/**",
"node_modules/",
"index.mjs"
], ],
"ts-node": { "ts-node": {
"files": true, "files": true,