Big code refactoring #10

Merged
Sirherobrine23 merged 15 commits from code_refactoring into main 2024-03-15 04:08:27 +00:00
31 changed files with 3 additions and 5085 deletions
Showing only changes of commit 06a2fe3d0d - Show all commits

@ -1,77 +0,0 @@
name: Test
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
test_js:
name: Test Javascript code
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
name: Checkout
- uses: actions/setup-node@v4
name: Setup Node.js
with:
node-version: 20.x
- name: Install dependencies
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt update && sudo apt install -y "build-essential"
npm install --no-save --ignore-scripts
- name: Build addon
run: npm run dev
- name: Run tests
env:
FORCE_COLOR: "true"
run: sudo "$(command -v node)" --no-warnings --loader ts-node/esm src/index_test.ts
build_addon:
runs-on: ubuntu-latest
needs: test_js
strategy:
matrix:
node_version: [ 16.x, 17.x, 18.x, 19.x, 20.x, 21.x ]
steps:
- uses: actions/checkout@v4
name: Checkout
- name: "Setup zig"
uses: korandoru/setup-zig@v1
with:
zig-version: "0.11.0"
- uses: actions/setup-node@v4
name: Setup Node.js
with:
node-version: ${{ matrix.node_version }}
- name: Install dependencies
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt update && sudo apt install -y "build-essential"
npm install --no-save --ignore-scripts
- name: Build addon linux
run: npm run dev -- --target x86_64-linux --target aarch64-linux
- name: Build addon macos
run: npm run dev -- --target x86_64-macos --target aarch64-macos
- name: Build addon windows
run: npm run dev -- --target x86_64-windows --target aarch64-windows
- name: Upload prebuilds interface
uses: actions/upload-artifact@v3
with:
retention-days: 7
name: build-${{ matrix.node_version }}
path: "build/*"

@ -1,21 +0,0 @@
image: node:lts
test:
stage: test
image: ghcr.io/catthehacker/ubuntu:act-latest
script:
- |
echo "Host arch: $(uname -m)"
export DEBIAN_FRONTEND=noninteractive
sudo apt update
wget -qO- https://deb.nodesource.com/setup_current.x | sudo bash -
packages=( "binutils-multiarch" "wget" "curl" "nodejs" "build-essential" );
sudo apt install -y ${packages[@]}
ZIGURL="https://ziglang.org/download/0.11.0/zig-linux-x86_64-0.11.0.tar.xz"
wget -qO- "${ZIGURL}" | sudo tar -xvJ -C /usr/local
sudo mv -v /usr/local/zig-* /usr/local/zig
sudo ln -vs /usr/local/zig/bin/zig /usr/bin/zig
- npm install --no-save --ignore-scripts
- npm run dev
- sudo node --no-warnings --loader ts-node/esm ./src/index_test.ts

@ -1,85 +0,0 @@
{
"version": 4,
"configurations": [
{
"name": "Win32",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-msvc-x64",
"compilerArgs": [
"-fpermissive",
"-fexceptions",
"-w",
"-fpermissive",
"-fPIC",
"-static"
],
"defines": [
"NAPI_DISABLE_CPP_EXCEPTIONS",
"ONSTARTADDON",
"LISTDEV",
"GETCONFIG",
"SETCONFIG",
"DELIFACE"
],
"includePath": [
"${env:appdata}/../Local/node-gyp/Cache/18.17.0/include/node",
"${workspaceFolder}/node_modules/node-addon-api",
"${workspaceFolder}/addons/genKey/**",
"${workspaceFolder}/addons/tools/**"
]
},
{
"name": "Linux",
"compilerPath": "/usr/bin/clang",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "linux-clang-x64",
"compilerArgs": [
"-fpermissive",
"-fexceptions",
"-w",
"-fpermissive",
"-fPIC",
"-static"
],
"defines": [
"NAPI_DISABLE_CPP_EXCEPTIONS"
],
"includePath": [
"/usr/include/node",
"${workspaceFolder}/node_modules/node-addon-api/**",
"${workspaceFolder}/node_modules/**",
"${workspaceFolder}/addons/genKey/**",
"${workspaceFolder}/addons/tools/**"
]
},
{
"name": "Mac",
"includePath": [
"${workspaceFolder}/node_modules/node-addon-api",
"/usr/local/include/node",
"${workspaceFolder}/addons/genKey/**",
"${workspaceFolder}/addons/tools/**"
],
"defines": [
"NAPI_DISABLE_CPP_EXCEPTIONS"
],
"compilerArgs": [
"-fpermissive",
"-fexceptions",
"-w",
"-fpermissive",
"-fPIC",
"-static"
],
"macFrameworkPath": [
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
],
"compilerPath": "/usr/bin/clang",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "macos-clang-x64"
}
]
}

20
.vscode/launch.json vendored

@ -1,20 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"cwd": "${workspaceFolder}",
"program": "node",
"preLaunchTask": {
"type": "npm",
"script": "dev"
},
"args": [
"node_modules/.bin/mocha",
"./"
]
}
]
}

12
.vscode/tasks.json vendored

@ -1,12 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "npm: build",
"detail": "npm run dev",
"type": "npm",
"script": "dev",
"problemMatcher": []
}
]
}

@ -1,26 +1 @@
# Wireguard-tools.js
Efficiently manage your Wireguard interface right from nodejs, no `wg` required.
other tools are wrappers over `wg`, `wireguard-tools.js` is not like that, it is a `C/C++` addon in which you don't need to have `wg` installed, as this module has full compatibility of its own `wg`.
## CommonJS droping support
With a small disappointment I come to inform you that CommonJS will be ignored in the next updates and will be completely an ESM module, if you don't want to migrate to ESM I recommend staying on version `1.8.1` or even `1.8.3`, which will be the last versions but recent in CommonJS.
## Support to:
- Userspace [(wireguard-go)](https://git.zx2c4.com/wireguard-go/about/) support.
- Maneger wireguard interface (linux and windows create if not exist's).
- Generate `preshared`, `private` and `public` keys.
- [wg-quick](https://man7.org/linux/man-pages/man8/wg-quick.8.html) file support.
- More info and example check [`wiki`](https://sirherobrine23.org/Wireguard/Wireguard-tools.js/wiki).
> [!NOTE]
>
> we have pre-copiled files for:
> - `Linux`: x64/amd64, arm64/aarch64
> - `Windows`: x64, arm64
>
> 1. To manage the Wireguard interfaces in linux, root access is required.
> 1. Another system's require `wireguard-go` [(check this page)](https://github.com/WireGuard/wireguard-go)
# Wireguard-tools for Nodejs

@ -1,163 +0,0 @@
#include <napi.h>
#include "wgkeys.hh"
class privateKeyWorker : public Napi::AsyncWorker {
private:
std::string pskString;
Napi::Promise::Deferred genPromise;
public:
~privateKeyWorker() {}
privateKeyWorker(const Napi::Env env) : AsyncWorker(env), genPromise{env} {}
Napi::Promise getPromise() { return genPromise.Promise(); }
void Execute() override {
wg_key keyg;
wgKeys::generatePrivate(keyg);
pskString = wgKeys::toString(keyg);
}
void OnOK() override {
Napi::HandleScope scope(Env());
genPromise.Resolve(Napi::String::New(Env(), pskString));
}
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
genPromise.Reject(e.Value());
}
};
class publicKeyWorker : public Napi::AsyncWorker {
private:
std::string privKey, pubString;
Napi::Promise::Deferred genPromise;
public:
~publicKeyWorker() {}
publicKeyWorker(const Napi::Env env, std::string privateKey) : AsyncWorker(env), privKey(privateKey), genPromise{env} {}
Napi::Promise getPromise() { return genPromise.Promise(); }
void Execute() override {
wg_key interfacePrivateKey, interfacePublicKey;
try {
wgKeys::stringToKey(interfacePrivateKey, privKey);
wgKeys::generatePublic(interfacePublicKey, interfacePrivateKey);
pubString = wgKeys::toString(interfacePublicKey);
} catch (std::string &err) {
SetError(err);
}
}
void OnOK() override {
Napi::HandleScope scope(Env());
genPromise.Resolve(Napi::String::New(Env(), pubString));
}
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
genPromise.Reject(e.Value());
}
};
class presharedKeyWorker : public Napi::AsyncWorker {
private:
std::string pskString;
Napi::Promise::Deferred genPromise;
public:
~presharedKeyWorker() {}
presharedKeyWorker(const Napi::Env env) : AsyncWorker(env), genPromise{env} {}
Napi::Promise getPromise() { return genPromise.Promise(); }
void Execute() override {
wg_key keyg;
wgKeys::generatePreshared(keyg);
pskString = wgKeys::toString(keyg);
}
void OnOK() override {
Napi::HandleScope scope(Env());
genPromise.Resolve(Napi::String::New(Env(), pskString));
}
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
genPromise.Reject(e.Value());
}
};
class genKeysWorker : public Napi::AsyncWorker {
private:
std::string privateKey, publicKey, presharedKey;
bool withPreshared = false;
Napi::Promise::Deferred genPromise;
public:
~genKeysWorker() {}
genKeysWorker(const Napi::Env env, bool withPresharedKey) : AsyncWorker(env), withPreshared(withPresharedKey), genPromise{env} {}
Napi::Promise getPromise() { return genPromise.Promise(); }
void Execute() override {
wg_key keyPriv, preshe, pub;
wgKeys::generatePrivate(keyPriv);
privateKey = wgKeys::toString(keyPriv);
wgKeys::generatePublic(pub, keyPriv);
publicKey = wgKeys::toString(pub);
if (!withPreshared) return;
wgKeys::generatePreshared(preshe);
presharedKey = wgKeys::toString(preshe);
}
void OnOK() override {
Napi::HandleScope scope(Env());
const Napi::Env env = Env();
auto keys = Napi::Object::New(env);
keys.Set("privateKey", privateKey);
keys.Set("publicKey", publicKey);
if (withPreshared) keys.Set("presharedKey", presharedKey);
genPromise.Resolve(keys);
}
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
genPromise.Reject(e.Value());
}
};
Napi::Object Init(Napi::Env exportsEnv, Napi::Object exports) {
auto constants = Napi::Object::New(exportsEnv);
constants.Set("WG_KEY_LENGTH", WG_KEY_LENGTH);
constants.Set("B64_WG_KEY_LENGTH", B64_WG_KEY_LENGTH);
exports.Set("constants", constants);
exports.Set("presharedKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo& info) {
const Napi::Env env = info.Env();
// Callback function is latest argument
auto *Gen = new presharedKeyWorker(env);
Gen->Queue();
return Gen->getPromise();
}));
exports.Set("privateKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo& info) {
const Napi::Env env = info.Env();
// Callback function is latest argument
auto *Gen = new privateKeyWorker(env);
Gen->Queue();
return Gen->getPromise();
}));
exports.Set("publicKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo& info) -> Napi::Value {
const Napi::Env env = info.Env();
if (!(info[0].IsString())) {
Napi::Error::New(env, "Require private key").ThrowAsJavaScriptException();
return env.Undefined();
}
// Callback function is latest argument
auto *Gen = new publicKeyWorker(env, info[0].ToString().Utf8Value().c_str());
Gen->Queue();
return Gen->getPromise();
}));
exports.Set("genKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo &info) {
const Napi::Env env = info.Env();
bool withPreshared = false;
if (info[0].IsBoolean()) withPreshared = info[0].ToBoolean().Value();
auto Gen = new genKeysWorker(env, withPreshared);
Gen->Queue();
return Gen->getPromise();
}));
return exports;
}
NODE_API_MODULE(addon, Init);

@ -1,6 +0,0 @@
#include <vector>
#include <string>
std::string setIps(std::string name, std::vector<std::string> ips) {
return "";
}

File diff suppressed because it is too large Load Diff

@ -1,105 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/*
* Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#ifndef WIREGUARD_H
#define WIREGUARD_H
#include <net/if.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <time.h>
#include <stdint.h>
#include <stdbool.h>
typedef uint8_t wg_key[32];
typedef char wg_key_b64_string[((sizeof(wg_key) + 2) / 3) * 4 + 1];
/* Cross platform __kernel_timespec */
struct timespec64 {
int64_t tv_sec;
int64_t tv_nsec;
};
typedef struct wg_allowedip {
uint16_t family;
union {
struct in_addr ip4;
struct in6_addr ip6;
};
uint8_t cidr;
struct wg_allowedip *next_allowedip;
} wg_allowedip;
enum wg_peer_flags {
WGPEER_REMOVE_ME = 1U << 0,
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
WGPEER_HAS_PUBLIC_KEY = 1U << 2,
WGPEER_HAS_PRESHARED_KEY = 1U << 3,
WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4
};
typedef union wg_endpoint {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
} wg_endpoint;
typedef struct wg_peer {
enum wg_peer_flags flags;
wg_key public_key;
wg_key preshared_key;
wg_endpoint endpoint;
struct timespec64 last_handshake_time;
uint64_t rx_bytes, tx_bytes;
uint16_t persistent_keepalive_interval;
struct wg_allowedip *first_allowedip, *last_allowedip;
struct wg_peer *next_peer;
} wg_peer;
enum wg_device_flags {
WGDEVICE_REPLACE_PEERS = 1U << 0,
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
WGDEVICE_HAS_FWMARK = 1U << 4
};
typedef struct wg_device {
char name[IFNAMSIZ];
uint32_t ifindex;
enum wg_device_flags flags;
wg_key public_key;
wg_key private_key;
uint32_t fwmark;
uint16_t listen_port;
struct wg_peer *first_peer, *last_peer;
} wg_device;
#define wg_for_each_device_name(__names, __name, __len) for ((__name) = (__names), (__len) = 0; ((__len) = strlen(__name)); (__name) += (__len) + 1)
#define wg_for_each_peer(__dev, __peer) for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer)
#define wg_for_each_allowedip(__peer, __allowedip) for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); (__allowedip) = (__allowedip)->next_allowedip)
int wg_set_device(wg_device *dev);
int wg_get_device(wg_device **dev, const char *device_name);
int wg_add_device(const char *device_name);
int wg_del_device(const char *device_name);
void wg_free_device(wg_device *dev);
char *wg_list_device_names(void); /* first\0second\0third\0forth\0last\0\0 */
void wg_key_to_base64(wg_key_b64_string base64, const wg_key key);
int wg_key_from_base64(wg_key key, const wg_key_b64_string base64);
bool wg_key_is_zero(const wg_key key);
void wg_generate_public_key(wg_key public_key, const wg_key private_key);
void wg_generate_private_key(wg_key private_key);
void wg_generate_preshared_key(wg_key preshared_key);
#endif

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

@ -1,353 +0,0 @@
#include <napi.h>
#include <iostream>
#include <unistd.h>
#include <time.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if_link.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <sys/ioctl.h>
#include <cerrno>
#include <ifaddrs.h>
#include <string>
#include <sysexits.h>
#include <sys/types.h>
#include "wginterface.hh"
#include "linux/set_ip.cpp"
extern "C" {
#include "linux/wireguard.h"
}
std::string getKernelMesage(int errStatus) {
std::string message = std::string("Error code: ").append(std::to_string(errStatus));
return message;
}
unsigned long maxName() {
return IFNAMSIZ;
}
std::string versionDrive() {
return "Kernel";
}
class List {
public:
std::vector<std::string> devs;
List() {}
~List() {
devs.clear();
}
void getAll() {
char *device_name, *devicesList = wg_list_device_names();
if (!devicesList) throw std::string("Unable to get device names");
size_t len;
for ((device_name) = (devicesList), (len) = 0; ((len) = strlen(device_name)); (device_name) += (len) + 1) devs.push_back(std::string(device_name));
free(devicesList);
}
bool exist(std::string ifname) {
this->getAll();
for (auto wg : devs) if (wg == ifname) return true;
return false;
}
};
void listDevices::Execute() {
List l;
try {
l.getAll();
for (auto ifname : l.devs) {
listInfo setInfo;
setInfo.tunType = "kernel";
deviceNames[ifname] = setInfo;
}
} catch (std::string err) {
SetError(err);
}
l.~List();
}
void deleteInterface::Execute() {
int status = wg_del_device(wgName.c_str());
if (status < 0) SetError(std::string("Cannot delete interface, code status: ").append(std::to_string(status)));
}
int createInterface(std::string &wgName) {
bool createInterface = true;
size_t len = 0;
char *device_name, *devicesList = wg_list_device_names();
if (!!devicesList) {
for ((device_name) = (devicesList), (len) = 0; ((len) = strlen(device_name)); (device_name) += (len) + 1) {
if (std::string(device_name) == wgName) {
createInterface = false;
break;
}
}
free(devicesList);
}
if (createInterface) return wg_add_device(wgName.c_str());
return 0;
}
void setConfig::Execute() {
int res = createInterface(wgName);
if (res < 0) {
SetError(std::string("Cannot create wireguard interface, Code: ").append(std::to_string(res)));
return;
}
// Set device struct
auto deviceStruct = new wg_device({});
strncpy(deviceStruct->name, wgName.c_str(), wgName.length());
// Set private key
wg_key_from_base64(deviceStruct->private_key, privateKey.c_str());
deviceStruct->flags = (wg_device_flags)WGDEVICE_HAS_PRIVATE_KEY;
// Set public key
if (publicKey.length() > 0) {
wg_key_from_base64(deviceStruct->public_key, publicKey.c_str());
deviceStruct->flags = (wg_device_flags)WGDEVICE_HAS_PUBLIC_KEY;
}
// Port listenings
if (portListen > 0 && 25565 < portListen) {
deviceStruct->listen_port = portListen;
deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_HAS_LISTEN_PORT);
}
// Linux firewall mark
if (fwmark >= 0) {
deviceStruct->fwmark = fwmark;
deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_HAS_FWMARK);
}
// Replace Peers
if (replacePeers) deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_REPLACE_PEERS);
unsigned int peerIndex = 0;
for (auto it = peersVector.begin(); it != peersVector.end(); ++it) {
const std::string peerPubKey = it->first;
auto peerConfig = it->second;
peerIndex++;
wg_peer *peerStruct = new wg_peer({});
// Set public key
wg_key_from_base64(peerStruct->public_key, peerPubKey.c_str());
peerStruct->flags = (wg_peer_flags)WGPEER_HAS_PUBLIC_KEY;
// Remove Peer
if (peerConfig.removeMe) peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_REMOVE_ME);
else {
// Set preshared key if present
if (peerConfig.presharedKey.length() > 0) {
wg_key_from_base64(peerStruct->preshared_key, peerConfig.presharedKey.c_str());
peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_HAS_PRESHARED_KEY);
}
// Set Keepalive
if (peerConfig.keepInterval > 0) {
peerStruct->persistent_keepalive_interval = peerConfig.keepInterval;
peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL);
}
// Set endpoint
if (peerConfig.endpoint.length() > 0) {
sockaddr endpoint;
int ret, retries;
char *begin, *end;
char *Endpoint = strdup(peerConfig.endpoint.c_str());
if (Endpoint[0] == '[') {
begin = &Endpoint[1];
end = strchr(Endpoint, ']');
if (!end) {
free(Endpoint);
SetError("Unable to find matching brace of endpoint");
return;
}
*end++ = '\0';
if (*end++ != ':' || !*end) {
free(Endpoint);
SetError("Unable to find port of endpoint");
return;
}
} else {
begin = Endpoint;
end = strrchr(Endpoint, ':');
if (!end || !*(end + 1)) {
free(Endpoint);
SetError("Unable to find port of endpoint");
return;
}
*end++ = '\0';
}
addrinfo *resolved;
addrinfo hints = {
ai_family: AF_UNSPEC,
ai_socktype: SOCK_DGRAM,
ai_protocol: IPPROTO_UDP
};
#define min(a, b) ((a) < (b) ? (a) : (b))
for (unsigned int timeout = 1000000;; timeout = min(20000000, timeout * 6 / 5)) {
ret = getaddrinfo(begin, end, &hints, &resolved);
if (!ret) break;
if (ret == EAI_NONAME || ret == EAI_FAIL ||
#ifdef EAI_NODATA
ret == EAI_NODATA ||
#endif
(retries >= 0 && !retries--)) {
free(Endpoint);
fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), peerConfig.endpoint.c_str());
SetError("Unable to resolve endpoint");
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);
usleep(timeout);
}
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(sockaddr_in)) || (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(sockaddr_in6))) {
memcpy(&endpoint, resolved->ai_addr, resolved->ai_addrlen);
memccpy(&peerStruct->endpoint.addr, &endpoint, 0, sizeof(peerStruct->endpoint.addr));
if (resolved->ai_family == AF_INET) {
peerStruct->endpoint.addr4.sin_addr.s_addr = ((sockaddr_in *)&endpoint)->sin_addr.s_addr;
peerStruct->endpoint.addr4.sin_port = ((sockaddr_in *)&endpoint)->sin_port;
peerStruct->endpoint.addr4.sin_family = AF_INET;
} else {
peerStruct->endpoint.addr6.sin6_addr = ((struct sockaddr_in6 *)&endpoint)->sin6_addr;
peerStruct->endpoint.addr6.sin6_port = ((struct sockaddr_in6 *)&endpoint)->sin6_port;
peerStruct->endpoint.addr6.sin6_family = AF_INET6;
}
} else {
freeaddrinfo(resolved);
free(Endpoint);
SetError("Neither IPv4 nor IPv6 address found");
return;
}
freeaddrinfo(resolved);
free(Endpoint);
}
// Set allowed IPs
if (peerConfig.allowedIPs.size() > 0) {
peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_REPLACE_ALLOWEDIPS);
for (unsigned int allowIndex = 0; allowIndex < peerConfig.allowedIPs.size(); allowIndex++) {
auto ip = peerConfig.allowedIPs[allowIndex];
unsigned long cidr = 0;
if (ip.find("/") != std::string::npos) {
cidr = std::stoi(ip.substr(ip.find("/")+1));
ip = ip.substr(0, ip.find("/"));
}
wg_allowedip *newAllowedIP = new wg_allowedip({family: AF_UNSPEC});
if (strchr(ip.c_str(), ':')) {
if (inet_pton(AF_INET6, ip.c_str(), &newAllowedIP->ip6) == 1) {
newAllowedIP->family = AF_INET6;
if (cidr == 0) cidr = 128;
}
} else {
if (inet_pton(AF_INET, ip.c_str(), &newAllowedIP->ip4) == 1) {
newAllowedIP->family = AF_INET;
if (cidr == 0) cidr = 32;
}
}
if (newAllowedIP->family == AF_UNSPEC || cidr <= 0) continue;
newAllowedIP->cidr = cidr;
if (allowIndex > 0) newAllowedIP->next_allowedip = peerStruct->first_allowedip;
peerStruct->first_allowedip = newAllowedIP;
}
}
}
// Add to Peer struct
if (peerIndex > 0) peerStruct->next_peer = deviceStruct->first_peer;
deviceStruct->first_peer = peerStruct;
}
// Set interface config
if ((res = wg_set_device(deviceStruct)) < 0) SetError(getKernelMesage(res));
}
const char* getHostAddress(bool addPort, const sockaddr* addr) {
char host[4096 + 1], service[512 + 1];
static char buf[sizeof(host) + sizeof(service) + 4];
memset(buf, 0, sizeof(buf));
int ret;
socklen_t addr_len = 0;
if (addr->sa_family == AF_INET) addr_len = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6) addr_len = sizeof(struct sockaddr_in6);
ret = getnameinfo(addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST);
if (ret) {
strncpy(buf, gai_strerror(ret), sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
} else {
if (addPort) snprintf(buf, sizeof(buf), (addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service);
else snprintf(buf, sizeof(buf), "%s", host);
}
return buf;
}
std::string keyTo64(const uint8_t *key) {
wg_key_b64_string strKey;
wg_key_to_base64(strKey, key);
return strKey;
}
void getConfig::Execute() {
int res; wg_device *device;
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)));
return;
}
if (device->flags & WGDEVICE_HAS_PRIVATE_KEY) privateKey = keyTo64(device->private_key);
if (device->flags & WGDEVICE_HAS_PUBLIC_KEY) publicKey = keyTo64(device->public_key);
if (device->listen_port > 0) portListen = device->listen_port;
// Set Address array and get interface ip addresses
ifaddrs* ptr_ifaddrs = nullptr;
if(getifaddrs(&ptr_ifaddrs) > 0) {
for (ifaddrs* ptr_entry = ptr_ifaddrs; ptr_entry != nullptr; ptr_entry = ptr_entry->ifa_next) {
if (ptr_entry->ifa_addr == nullptr) continue;
else if (strcmp(ptr_entry->ifa_name, wgName.c_str()) != 0) continue;
else if (ptr_entry->ifa_addr->sa_family == AF_INET) Address.push_back(getHostAddress(false, ptr_entry->ifa_addr));
else if (ptr_entry->ifa_addr->sa_family == AF_INET6) Address.push_back(getHostAddress(false, ptr_entry->ifa_addr));
}
freeifaddrs(ptr_ifaddrs);
}
wg_peer *peer;
for ((peer) = (device)->first_peer; (peer); (peer) = (peer)->next_peer) {
auto PeerConfig = Peer();
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) PeerConfig.presharedKey = keyTo64(peer->preshared_key);
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL && peer->persistent_keepalive_interval > 0) PeerConfig.keepInterval = peer->persistent_keepalive_interval;
if (peer->endpoint.addr.sa_family == AF_INET||peer->endpoint.addr.sa_family == AF_INET6) PeerConfig.endpoint = getHostAddress(true, &peer->endpoint.addr);
if (peer->last_handshake_time.tv_sec > 0) PeerConfig.last_handshake = peer->last_handshake_time.tv_sec*1000;
if (peer->rx_bytes > 0) PeerConfig.rxBytes = peer->rx_bytes;
if (peer->tx_bytes > 0) PeerConfig.txBytes = peer->tx_bytes;
if (peer->first_allowedip) {
wg_allowedip *allowedip;
for ((allowedip) = (peer)->first_allowedip; (allowedip); (allowedip) = (allowedip)->next_allowedip) {
static char buf[INET6_ADDRSTRLEN + 1];
memset(buf, 0, INET6_ADDRSTRLEN + 1);
if (allowedip->family == AF_INET) inet_ntop(AF_INET, &allowedip->ip4, buf, INET6_ADDRSTRLEN);
else if (allowedip->family == AF_INET6) inet_ntop(AF_INET6, &allowedip->ip6, buf, INET6_ADDRSTRLEN);
snprintf(buf + strlen(buf), INET6_ADDRSTRLEN - strlen(buf), "/%d", allowedip->cidr);
PeerConfig.allowedIPs.push_back(buf);
}
}
peersVector[keyTo64(peer->public_key)] = PeerConfig;
}
}

@ -1,363 +0,0 @@
#include <napi.h>
#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <wireguard-nt/include/wireguard.h>
#include <windows.h>
#include <tlhelp32.h>
#include <accctrl.h>
#include <aclapi.h>
#include <stdio.h>
#include <stdbool.h>
#include <fcntl.h>
#include <winsock2.h>
#include <ws2ipdef.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <bcrypt.h>
#include <wincrypt.h>
#include <sysinfoapi.h>
#include <winternl.h>
#include <cstdlib>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <devguid.h>
#include "wginterface.hh"
#include "win/shared.cpp"
#include <wgkeys.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, Napi::Object exports) {
if (!IsRunAsAdmin()) return "Run nodejs with administrator privilegies";
auto DLLPATH = exports.Get("WIN32DLLPATH");
if (!(DLLPATH.IsString())) return "Require WIREGUARD_DLL_PATH in addon load!";
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));
}
void listDevices::Execute() {
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());
listInfo setInfo;
setInfo.tunType = "userspace";
setInfo.pathSock = std::string("\\\\.\\pipe\\").append(preit).append(iface);
deviceNames[std::string(iface)] = setInfo;
} while (FindNextFile(find_handle, &find_data));
FindClose(find_handle);
if (ret < 0) return SetError(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) 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)) {
listInfo setInfo;
setInfo.tunType = "kernel";
deviceNames[std::string(interface_name)] = setInfo;
}
free(interface_name);
}
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);
}
/**
* Change point from calloc or malloc
*
* T: to
* C: From
*/
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 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 (std::string err) {
return SetError(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 = 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;
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.last_handshake = 0;
peerConfig.txBytes = wg_peer->TxBytes;
peerConfig.rxBytes = wg_peer->RxBytes;
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.last_handshake = (wg_peer->LastHandshake / 10000000 - 11644473600LL) * 1000;
WIREGUARD_ALLOWED_IP* wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_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<WIREGUARD_PEER*>(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 = reinterpret_cast<WIREGUARD_INTERFACE*>(calloc(1, buf_len));
if (!wg_iface) return SetError("Cannot alloc buff");
wg_iface->PeersCount = 0;
wgKeys::stringToKey(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 = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface);
for (auto __peer : peersVector) {
auto peerPublicKey = __peer.first; auto peerConfig = __peer.second;
try {
wgKeys::stringToKey(wg_peer->PublicKey, peerPublicKey);
} catch (std::string &err) {
SetError(err);
free(wg_iface);
return;
}
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 = changePoint<WIREGUARD_PEER, WIREGUARD_PEER>(wg_peer);
} else {
if (peerConfig.presharedKey.size() == B64_WG_KEY_LENGTH) {
try {
wgKeys::stringToKey(wg_peer->PresharedKey, peerConfig.presharedKey);
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY);
} catch (std::string &err) {
SetError(err);
free(wg_iface);
return;
}
}
wg_peer->PersistentKeepalive = peerConfig.keepInterval;
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) {
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));
free(wg_iface);
return;
}
}
wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_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 = changePoint<WIREGUARD_ALLOWED_IP, WIREGUARD_ALLOWED_IP>(wg_aip);
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<WIREGUARD_PEER*>(((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<WIREGUARD_INTERFACE*>(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);
}
}
}
free(wg_iface);
}

@ -1,116 +0,0 @@
#include <napi.h>
#include <iostream>
#include "wginterface.hh"
Napi::Object Init(Napi::Env initEnv, Napi::Object exports) {
/// Call Addon
#ifdef ONSTARTADDON
auto status = startAddon(initEnv, exports);
if (status.length() >= 1) {
Napi::Error::New(initEnv, status).ThrowAsJavaScriptException();
return exports;
}
#endif
// Wireguard constants set
const Napi::Object constants = Napi::Object::New(initEnv);
// Set wireguard version if present
constants.Set("driveVersion", versionDrive());
// Wireguard max name length
constants.Set("nameLength", maxName());
constants.Set("base64Length", B64_WG_KEY_LENGTH);
constants.Set("keyLength", WG_KEY_LENGTH);
// Set addon constants
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
exports.Set("setConfig", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value {
const Napi::Env env = info.Env();
const auto wgName = info[0];
const auto wgConfig = info[1];
Napi::Value ret = env.Undefined();
if (!(wgName.IsString())) {
Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException();
return env.Undefined();
} else if (wgName.ToString().Utf8Value().length() >= maxName()) {
Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException();
return env.Undefined();
} else if (!(wgConfig.IsObject())) {
Napi::Error::New(env, "Require wireguard config object").ThrowAsJavaScriptException();
return env.Undefined();
}
try {
auto worker = new setConfig(env, wgName.ToString().Utf8Value(), wgConfig.ToObject());
worker->Queue();
return worker->setPromise.Promise();
} catch (const Napi::Error &err) {
err.ThrowAsJavaScriptException();
}
return ret;
}));
#endif
#ifdef DELIFACE
exports.Set("deleteInterface", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value {
const Napi::Env env = info.Env();
const auto wgName = info[0];
if (!(wgName.IsString())) {
Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException();
return env.Undefined();
} else if (wgName.ToString().Utf8Value().length() >= maxName()) {
Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException();
return env.Undefined();
}
auto worker = new deleteInterface(env, wgName.ToString().Utf8Value());
worker->Queue();
return worker->deletePromise.Promise();
}));
#endif
#ifdef GETCONFIG
exports.Set("getConfig", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value {
const Napi::Env env = info.Env();
const auto wgName = info[0];
if (!(wgName.IsString())) {
Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException();
return env.Undefined();
} else if (wgName.ToString().Utf8Value().length() >= maxName()) {
Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException();
return env.Undefined();
}
try {
auto worker = new getConfig(env, wgName.ToString().Utf8Value());
worker->Queue();
return worker->getPromise.Promise();
} catch (const Napi::Error &err) {
err.ThrowAsJavaScriptException();
}
return env.Undefined();
}));
#endif
#ifdef LISTDEV
exports.Set("listDevices", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value {
const Napi::Env env = info.Env();
auto worker = new listDevices(env);
worker->Queue();
return worker->listDevicesPromise.Promise();
}));
#endif
return exports;
}
NODE_API_MODULE(addon, Init);

@ -1,338 +0,0 @@
#pragma once
#include <napi.h>
#include <string>
#include <vector>
#include <map>
#include <wgkeys.hh>
// Get wireguard max name length
unsigned long maxName();
// Get wireguard version
std::string versionDrive();
// On start module call this function
std::string startAddon(const Napi::Env env, Napi::Object exports);
class deleteInterface : public Napi::AsyncWorker {
private:
std::string wgName;
public:
deleteInterface(const Napi::Env env, std::string name): AsyncWorker(env), wgName{name}, deletePromise{env} {}
~deleteInterface() {}
const Napi::Promise::Deferred deletePromise;
void OnError(const Napi::Error &e) override {
Napi::HandleScope scope(Env());
deletePromise.Reject(e.Value());
}
void OnOK() override {
Napi::HandleScope scope(Env());
deletePromise.Resolve(Env().Undefined());
};
// Set platform Execute script
void Execute() override;
};
class listInfo {
public:
std::string tunType, pathSock;
};
class listDevices : public Napi::AsyncWorker {
private:
std::map<std::string, listInfo> deviceNames;
public:
~listDevices() {}
listDevices(const Napi::Env env) : AsyncWorker(env), listDevicesPromise{env} {}
const Napi::Promise::Deferred listDevicesPromise;
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
listDevicesPromise.Reject(e.Value());
}
void OnOK() override {
Napi::HandleScope scope(Env());
const Napi::Env env = Env();
const auto deviceArray = Napi::Array::New(env);
for (auto it : deviceNames) {
auto name = it.first; auto infoSrc = it.second;
auto info = Napi::Object::New(env);
info.Set("name", name);
info.Set("from", infoSrc.tunType);
if (infoSrc.pathSock.size() > 0) info.Set("path", infoSrc.pathSock);
deviceArray.Set(deviceArray.Length(), info);
}
listDevicesPromise.Resolve(deviceArray);
};
void Execute() override;
};
class Peer {
public:
// Remove specifies if the peer with this public key should be removed
// from a device's peer list.
bool removeMe;
// PresharedKey is an optional preshared key which may be used as an
// additional layer of security for peer communications.
std::string presharedKey;
// Endpoint is the most recent source address used for communication by
// this Peer.
std::string endpoint;
// AllowedIPs specifies which IPv4 and IPv6 addresses this peer is allowed
// to communicate on.
//
// 0.0.0.0/0 indicates that all IPv4 addresses are allowed, and ::/0
// indicates that all IPv6 addresses are allowed.
std::vector<std::string> allowedIPs;
// PersistentKeepaliveInterval specifies how often an "empty" packet is sent
// to a peer to keep a connection alive.
//
// A value of 0 indicates that persistent keepalives are disabled.
unsigned int keepInterval = 0;
// LastHandshakeTime indicates the most recent time a handshake was performed
// with this peer.
//
// A zero-value time.Time indicates that no handshake has taken place with
// this peer.
long long last_handshake = 0;
// rxBytes indicates the number of bytes received from this peer.
unsigned long long rxBytes = 0;
// txBytes indicates the number of bytes transmitted to this peer.
unsigned long long txBytes = 0;
// ProtocolVersion specifies which version of the WireGuard protocol is used
// for this Peer.
//
// A value of 0 indicates that the most recent protocol version will be used.
int ProtocolVersion = 0;
};
/*
Configure uma interface do Wireguard.
*/
class setConfig : public Napi::AsyncWorker {
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 short portListen = 0;
// 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;
// Replace peers
bool replacePeers = false;
// Wireguard peers, Map: <publicKey(std::string), Peer>
std::map<std::string, Peer> peersVector;
public:
const Napi::Promise::Deferred setPromise;
void OnOK() override {
Napi::HandleScope scope(Env());
// Callback().Call({ Env().Undefined() });
setPromise.Resolve(Env().Undefined());
};
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
// Callback().Call({ e.Value() });
setPromise.Reject(e.Value());
}
~setConfig() {}
setConfig(const Napi::Env env, std::string name, const Napi::Object &config) : AsyncWorker(env), wgName{name}, setPromise{env} {
// Wireguard public key
const auto sppk = config.Get("publicKey");
if (sppk.IsString()) {
publicKey = sppk.ToString().Utf8Value();
if (publicKey.length() != B64_WG_KEY_LENGTH) throw Napi::Error::New(env, "Set valid publicKey");
}
// Private key
const auto sprk = config.Get("privateKey");
if (!(sprk.IsString())) throw Napi::Error::New(env, "privateKey is empty");
privateKey = sprk.ToString().Utf8Value();
if (privateKey.length() != B64_WG_KEY_LENGTH) throw Napi::Error::New(env, (std::string("Set valid privateKey ")).append(std::to_string(privateKey.length())));
// Port to listen Wireguard interface
const auto spor = config.Get("portListen");
if (spor.IsNumber() && (spor.ToNumber().Int32Value() >= 0 && spor.ToNumber().Int32Value() <= 65535)) portListen = spor.ToNumber().Int32Value();
// Firewall mark
const auto sfw = config.Get("fwmark");
if (sfw.IsNumber() && (sfw.ToNumber().Uint32Value() >= 0)) fwmark = sfw.ToNumber().Uint32Value();
else fwmark = -1;
const auto setAddress = config.Get("address");
if (setAddress.IsArray()) {
const Napi::Array addrs = setAddress.As<Napi::Array>();
for (unsigned int i = 0; i < addrs.Length(); i++) {
if (addrs.Get(i).IsString()) Address.push_back(addrs.Get(i).ToString().Utf8Value());
}
}
// Replace peers
const auto setReplace = config.Get("replacePeers");
if (setReplace.IsBoolean()) replacePeers = setReplace.ToBoolean().Value();
// Peers
const auto speers = config.Get("peers");
if (speers.IsObject()) {
const Napi::Object Peers = speers.ToObject();
const Napi::Array Keys = Peers.GetPropertyNames();
for (unsigned int peerIndex = 0; peerIndex < Keys.Length(); peerIndex++) {
const auto peerPubKey = Keys[peerIndex];
if (peerPubKey.IsString() && Peers.Get(Keys[peerIndex]).IsObject()) {
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));
const Napi::Object peerConfigObject = Peers.Get(Keys[peerIndex]).ToObject();
Peer peerConfig = Peer();
const auto removeMe = peerConfigObject.Get("removeMe");
if (removeMe.IsBoolean() && removeMe.ToBoolean().Value()) peerConfig.removeMe = true;
else {
// Preshared key
const auto pprekey = peerConfigObject.Get("presharedKey");
if (pprekey.IsString()) {
peerConfig.presharedKey = pprekey.ToString().Utf8Value();
if (peerConfig.presharedKey.length() != B64_WG_KEY_LENGTH) throw Napi::Error::New(env, "Set valid peer presharedKey");
}
// Keep interval
const auto pKeepInterval = peerConfigObject.Get("keepInterval");
if (pKeepInterval.IsNumber() && (pKeepInterval.ToNumber().Int32Value() > 0 && pKeepInterval.ToNumber().Int32Value() <= 65535)) peerConfig.keepInterval = pKeepInterval.ToNumber().Int32Value();
// Peer endpoint
const auto pEndpoint = peerConfigObject.Get("endpoint");
if (pEndpoint.IsString()) peerConfig.endpoint = pEndpoint.ToString().Utf8Value();
// Allowed ip's array
const auto pAllowedIPs = peerConfigObject.Get("allowedIPs");
if (pAllowedIPs.IsArray()) {
const auto AllowedIps = pAllowedIPs.As<Napi::Array>();
for (uint32_t allIndex = 0; allIndex < AllowedIps.Length(); allIndex++) {
if (AllowedIps.Get(allIndex).IsString()) peerConfig.allowedIPs.push_back(AllowedIps.Get(allIndex).ToString().Utf8Value());
}
}
}
// Insert peer
peersVector[ppkey] = peerConfig;
}
}
}
}
// Set platform Execute script
void Execute() override;
};
class getConfig : public Napi::AsyncWorker {
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:
~getConfig() {}
getConfig(const Napi::Env env, std::string name): AsyncWorker(env), wgName{name}, getPromise{env} {}
const Napi::Promise::Deferred getPromise;
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
getPromise.Reject(e.Value());
}
void OnOK() override {
Napi::HandleScope scope(Env());
const Napi::Env env = Env();
const auto config = Napi::Object::New(env);
if (privateKey.length() == B64_WG_KEY_LENGTH) config.Set("privateKey", privateKey);
if (publicKey.length() == B64_WG_KEY_LENGTH) config.Set("publicKey", publicKey);
if (portListen >= 0 && portListen <= 65535) config.Set("portListen", portListen);
if (fwmark >= 0) config.Set("fwmark", fwmark);
if (Address.size() > 0) {
const auto Addrs = Napi::Array::New(env);
for (auto &addr : Address) Addrs.Set(Addrs.Length(), addr);
config.Set("address", Addrs);
}
// Peer object
const auto PeersObject = Napi::Object::New(env);
for (auto &peer : peersVector) {
const auto PeerObject = Napi::Object::New(env);
auto peerConfig = peer.second;
if (peerConfig.presharedKey.length() == B64_WG_KEY_LENGTH) PeerObject.Set("presharedKey", peerConfig.presharedKey);
if (peerConfig.keepInterval > 0 && peerConfig.keepInterval <= 65535) PeerObject.Set("keepInterval", peerConfig.keepInterval);
if (peerConfig.endpoint.length() > 0) PeerObject.Set("endpoint", peerConfig.endpoint);
if (peerConfig.rxBytes >= 0) PeerObject.Set("rxBytes", Napi::BigInt::New(env, (uint64_t)peerConfig.rxBytes));
if (peerConfig.txBytes >= 0) PeerObject.Set("txBytes", Napi::BigInt::New(env, (uint64_t)peerConfig.txBytes));
if (peerConfig.last_handshake >= 0) {
PeerObject.Set("lastHandshake", Napi::Date::New(env, peerConfig.last_handshake));
PeerObject.Set("lastHandshakeBigint", peerConfig.last_handshake); // Debug to windows
}
if (peerConfig.allowedIPs.size() > 0) {
const auto allowedIPs = Napi::Array::New(env);
for (auto &ip : peerConfig.allowedIPs) allowedIPs.Set(allowedIPs.Length(), ip);
PeerObject.Set("allowedIPs", allowedIPs);
}
// const std::string peerPubKey = peer.first;
PeersObject.Set(peer.first, PeerObject);
}
// Set peers to object
config.Set("peers", PeersObject);
// Resolve config json
getPromise.Resolve(config);
};
// Set platform Execute script
void Execute() override;
};

@ -1,179 +0,0 @@
#include <string>
#include <vector>
#include <wireguard-nt/include/wireguard.h>
#include <windows.h>
#include <ws2ipdef.h>
#include <ws2def.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <netioapi.h>
#include <iphlpapi.h>
#include <chrono>
#include <thread>
#include <iostream>
// Function to check if the current user has administrator privileges
bool IsRunAsAdmin()
{
BOOL fRet = FALSE;
HANDLE hToken = NULL;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
TOKEN_ELEVATION Elevation;
DWORD cbSize = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) {
fRet = Elevation.TokenIsElevated;
}
}
if (hToken) CloseHandle(hToken);
return !!fRet;
}
LPCWSTR toLpcwstr(std::string s) {
wchar_t* wString = new wchar_t[s.length()+1];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), -1, wString, s.length()+1);
return wString;
}
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 parseEndpoint(SOCKADDR_INET *input) {
if (!(input->si_family == AF_INET || input->si_family == AF_INET6)) return "";
char saddr[INET6_ADDRSTRLEN];
input->si_family == AF_INET ? inet_ntop(AF_INET, &input->Ipv4.sin_addr, saddr, INET_ADDRSTRLEN) : inet_ntop(AF_INET6, &input->Ipv6.sin6_addr, saddr, INET6_ADDRSTRLEN);
if (input->si_family == AF_INET6) return std::string("[").append(saddr).append("]:").append(std::to_string(htons(input->Ipv6.sin6_port)));
return std::string(saddr).append(":").append(std::to_string(htons(input->Ipv4.sin_port)));
}
std::string insertIpAddr(NET_LUID InterfaceLuid, std::string IPv4, std::string IPv6) {
NET_IFINDEX ind;
if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &ind) != NO_ERROR) return "Cannot get interface index";
// IPv4
if (IPv4.size() > 0) {
ULONG NTEContext = 0;
ULONG NTEInstance = 0;
UINT iaIPAddress;
inet_pton(AF_INET, IPv4.c_str(), &iaIPAddress);
auto status = AddIPAddress(iaIPAddress, NULL, ind, &NTEContext, &NTEInstance);
if (status != NO_ERROR) {
if (status == 5010) {
} else return std::string("Cannot set IPv4 interface, error code: ").append(std::to_string(status));
}
}
// IPv6
if (IPv6.size() > 0) {
UINT iaIPAddress;
inet_pton(AF_INET6, IPv6.c_str(), &iaIPAddress);
std::cerr << "Current not support IPv6 to set in interface!" << std::endl;
}
return "";
}
std::vector<std::string> getIpAddr(NET_LUID InterfaceLuid) {
NET_IFINDEX ind;
if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &ind) != NO_ERROR) throw std::string("Cannot get interface index");
std::vector<std::string> ips;
IP_ADAPTER_INFO *pAdapterInfo;
ULONG ulOutBufLen;
DWORD dwRetVal;
pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) );
ulOutBufLen = sizeof(IP_ADAPTER_INFO);
if (GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) {
free (pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc ( ulOutBufLen );
}
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) != ERROR_SUCCESS) throw std::string("GetAdaptersInfo call failed with ").append(std::to_string(dwRetVal));
PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
while (pAdapter) {
if (pAdapter->Index == ind) ips.push_back(std::string(pAdapter->IpAddressList.IpAddress.String).append("/32"));
pAdapter = pAdapter->Next;
}
if (pAdapterInfo) free(pAdapterInfo);
return ips;
}

@ -1,84 +0,0 @@
Prebuilt Binaries License
-------------------------
1. DEFINITIONS. "Software" means the precise contents of the "wireguard.dll"
files that are included in the .zip file that contains this document as
downloaded from download.wireguard.com.
2. LICENSE GRANT. WireGuard LLC grants to you a non-exclusive and
non-transferable right to use Software for lawful purposes under certain
obligations and limited rights as set forth in this agreement.
3. RESTRICTIONS. Software is owned and copyrighted by WireGuard LLC. It is
licensed, not sold. Title to Software and all associated intellectual
property rights are retained by WireGuard. You must not:
a. reverse engineer, decompile, disassemble, extract from, or otherwise
modify the Software;
b. modify or create derivative work based upon Software in whole or in
parts, except insofar as only the API interfaces of the "wireguard.h" file
distributed alongside the Software (the "Permitted API") are used;
c. remove any proprietary notices, labels, or copyrights from the Software;
d. resell, redistribute, lease, rent, transfer, sublicense, or otherwise
transfer rights of the Software without the prior written consent of
WireGuard LLC, except insofar as the Software is distributed alongside
other software that uses the Software only via the Permitted API;
e. use the name of WireGuard LLC, the WireGuard project, the WireGuard
project, or the names of its contributors to endorse or promote products
derived from the Software without specific prior written consent.
4. LIMITED WARRANTY. THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF
ANY KIND. WIREGUARD LLC HEREBY EXCLUDES AND DISCLAIMS ALL IMPLIED OR
STATUTORY WARRANTIES, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, QUALITY, NON-INFRINGEMENT, TITLE, RESULTS,
EFFORTS, OR QUIET ENJOYMENT. THERE IS NO WARRANTY THAT THE PRODUCT WILL BE
ERROR-FREE OR WILL FUNCTION WITHOUT INTERRUPTION. YOU ASSUME THE ENTIRE
RISK FOR THE RESULTS OBTAINED USING THE PRODUCT. TO THE EXTENT THAT
WIREGUARD LLC MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW,
THE SCOPE AND DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER
SUCH LAW. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR
A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE
EXTENT THAT THESE DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
5. LIMITATION OF LIABILITY. To the extent not prohibited by law, in no event
WireGuard LLC or any third-party-developer will be liable for any lost
revenue, profit or data or for special, indirect, consequential, incidental
or punitive damages, however caused regardless of the theory of liability,
arising out of or related to the use of or inability to use Software, even
if WireGuard LLC has been advised of the possibility of such damages.
Solely you are responsible for determining the appropriateness of using
Software and accept full responsibility for all risks associated with its
exercise of rights under this agreement, including but not limited to the
risks and costs of program errors, compliance with applicable laws, damage
to or loss of data, programs or equipment, and unavailability or
interruption of operations. The foregoing limitations will apply even if
the above stated warranty fails of its essential purpose. You acknowledge,
that it is in the nature of software that software is complex and not
completely free of errors. In no event shall WireGuard LLC or any
third-party-developer be liable to you under any theory for any damages
suffered by you or any user of Software or for any special, incidental,
indirect, consequential or similar damages (including without limitation
damages for loss of business profits, business interruption, loss of
business information or any other pecuniary loss) arising out of the use or
inability to use Software, even if WireGuard LLC has been advised of the
possibility of such damages and regardless of the legal or quitable theory
(contract, tort, or otherwise) upon which the claim is based.
6. TERMINATION. This agreement is affected until terminated. You may
terminate this agreement at any time. This agreement will terminate
immediately without notice from WireGuard LLC if you fail to comply with
the terms and conditions of this agreement. Upon termination, you must
delete Software and all copies of Software and cease all forms of
distribution of Software.
7. SEVERABILITY. If any provision of this agreement is held to be
unenforceable, this agreement will remain in effect with the provision
omitted, unless omission would frustrate the intent of the parties, in
which case this agreement will immediately terminate.
8. RESERVATION OF RIGHTS. All rights not expressly granted in this agreement
are reserved by WireGuard LLC. For example, WireGuard LLC reserves the
right at any time to cease development of Software, to alter distribution
details, features, specifications, capabilities, functions, licensing
terms, release dates, APIs, ABIs, general availability, or other
characteristics of the Software.

@ -1,336 +0,0 @@
# [WireGuard](https://www.wireguard.com/) for the NT Kernel
### High performance in-kernel WireGuard implementation for Windows
WireGuardNT is an implementation of WireGuard, for the NT Kernel as used in Windows 7, 8, 8.1, 10, and 11, supporting AMD64, x86, ARM64, and ARM processors.
#### Not the droids you're looking for
**If you've come here looking to run [WireGuard on Windows](https://git.zx2c4.com/wireguard-windows/about/), you're in the wrong place. Instead, head on over to the [WireGuard Download Page](https://www.wireguard.com/install/) to download the WireGuard application.** Alternatively, if you've come here looking to embed WireGuard into your Windows program, **you are still in the wrong place**. Instead, head on over to the [embeddable DLL service project](https://git.zx2c4.com/wireguard-windows/about/embeddable-dll-service/README.md), to get everything you need to bake WireGuard into your Windows programs. These projects use WireGuardNT inside.
## Usage
#### Download
WireGuardNT is deployed as a platform-specific `wireguard.dll` file. Install the `wireguard.dll` file side-by-side with your application. Download the dll from [the wireguard-nt download server](https://download.wireguard.com/wireguard-nt/), alongside the header file for your application described below.
#### API
Include the [`wireguard.h` file](https://git.zx2c4.com/wireguard-nt/tree/api/wireguard.h) in your project simply by copying it there and dynamically load the `wireguard.dll` using [`LoadLibraryEx()`](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa) and [`GetProcAddress()`](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress) to resolve each function, using the typedefs provided in the header file. The [`InitializeWireGuardNT` function in the example.c code](https://git.zx2c4.com/wireguard-nt/tree/example/example.c) provides this in a function that you can simply copy and paste.
With the library setup, WireGuardNT can then be used by first creating an adapter, configuring it, and then setting its status to "up". Adapters have names (e.g. "OfficeNet") and types (e.g. "WireGuard").
```C
WIREGUARD_ADAPTER_HANDLE Adapter1 = WireGuardCreateAdapter(L"OfficeNet", L"WireGuard", &SomeFixedGUID1);
WIREGUARD_ADAPTER_HANDLE Adapter2 = WireGuardCreateAdapter(L"HomeNet", L"WireGuard", &SomeFixedGUID2);
WIREGUARD_ADAPTER_HANDLE Adapter3 = WireGuardCreateAdapter(L"Data Center", L"WireGuard", &SomeFixedGUID3);
```
After creating an adapter, we can use it by setting a configuration and setting its status to "up":
```C
struct
{
WIREGUARD_INTERFACE Interface;
WIREGUARD_PEER FirstPeer;
WIREGUARD_ALLOWED_IP FirstPeerAllowedIP1;
WIREGUARD_ALLOWED_IP FirstPeerAllowedIP2;
WIREGUARD_PEER SecondPeer;
WIREGUARD_ALLOWED_IP SecondtPeerAllowedIP1;
} Config = {
.Interface = {
.Flags = WIREGUARD_INTERFACE_HAS_PRIVATE_KEY,
.PrivateKey = ...,
.PeersCount = 2
},
.FirstPeer = {
.Flags = WIREGUARD_PEER_HAS_PUBLIC_KEY | WIREGUARD_PEER_HAS_ENDPOINT,
.PublicKey = ...,
.Endpoint = ...,
.AllowedIPsCount = 2
},
.FirstPeerAllowedIP1 = { ... },
...
};
WireGuardSetConfiguration(Adapter1, &Config.Interface, sizeof(Config));
WireGuardSetAdapterState(Adapter1, WIREGUARD_ADAPTER_STATE_UP);
```
You are *highly encouraged* to read the [**example.c short example**](https://git.zx2c4.com/wireguard-nt/tree/example/example.c) to see how to put together a simple network tunnel. The example one connects to the [demo server](https://demo.wireguard.com/).
The various functions and definitions are [documented in `wireguard.h`](https://git.zx2c4.com/wireguard-nt/tree/api/wireguard.h) as well as in the reference below.
## API Reference
### Type: `WIREGUARD_ADAPTER_HANDLE` - opaque type to an instance of a WireGuard adapter.
### Function: `WireGuardCreateAdapter` - creates a new adapter.
```c
WIREGUARD_ADAPTER_HANDLE WireGuardCreateAdapter(LPCWSTR Name, LPCWSTR TunnelType, const GUID *RequestedGUID);
```
Typedef'd as `WIREGUARD_CREATE_ADAPTER_FUNC`. Returns a `WIREGUARD_ADAPTER_HANDLE` if successful, which must be released with `WireGuardCloseAdapter`; otherwise returns `NULL` and sets LastError.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`LPCWSTR`|Name|The requested name of the adapter. Zero-terminated string of up to `MAX_ADAPTER_NAME-1` characters.|
|`LPCWSTR`|TunnelType|Name of the adapter tunnel type. Zero-terminated string of up to `MAX_ADAPTER_NAME-1` characters.|
|`GUID *`|RequestedGUID|The GUID of the created network adapter, which then influences NLA generation deterministically. If it is set to `NULL`, the GUID is chosen by the system at random, and hence a new NLA entry is created for each new adapter.|
### Function: `WireGuardOpenAdapter` - opens an existing adapter.
```c
WIREGUARD_ADAPTER_HANDLE WireGuardOpenAdapter(LPCWSTR Name);
```
Typedef'd as `WIREGUARD_OPEN_ADAPTER_FUNC`. Returns a `WIREGUARD_ADAPTER_HANDLE` if successful, which must be released with `WireGuardCloseAdapter`; otherwise returns `NULL` and sets LastError.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`LPCWSTR`|Name|The requested name of the adapter. Zero-terminated string of up to `MAX_ADAPTER_NAME-1` characters.|
### Function: `WireGuardCloseAdapter` - closes an open adapter and releases its resources.
```c
VOID WireGuardCloseAdapter(WIREGUARD_ADAPTER_HANDLE Adapter);
```
Typedef'd as `WIREGUARD_CLOSE_ADAPTER_FUNC`. Releases WireGuard adapter resources and, if adapter was created with `WireGuardCreateAdapter`, removes adapter.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_ADAPTER_HANDLE`|Adapter|Adapter handle obtained with `WireGuardCreateAdapter` or `WireGuardOpenAdapter`.|
### Function: `WireGuardGetAdapterLUID` - gets the LUID of an adapter.
```c
VOID WireGuardGetAdapterLUID(WIREGUARD_ADAPTER_HANDLE Adapter, NET_LUID *Luid);
```
Typedef'd as `WIREGUARD_GET_ADAPTER_LUID_FUNC`. Returns the LUID of the adapter into the variable passed as the `Luid` argument.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_ADAPTER_HANDLE`|Adapter|Adapter handle obtained with `WireGuardCreateAdapter` or `WireGuardOpenAdapter`.|
|`NET_LUID *` (out)|Luid|Pointer to receive adapter LUID.|
### Function: `WireGuardGetRunningDriverVersion` - gets the version of the loaded driver.
```c
DWORD WireGuardGetRunningDriverVersion(VOID);
```
Typedef'd as `WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC`. Returns the version of the WireGuardNT driver currently loaded, or zero on error and sets LastError, which is `ERROR_FILE_NOT_FOUND` if WireGuardNT is not currently loaded.
### Function: `WireGuardDeleteDriver` - deletes driver if not in use.
```c
BOOL WireGuardDeleteDriver(VOID);
```
Typedef'd as `WIREGUARD_DELETE_DRIVER_FUNC`. Deletes the WireGuardNT driver if there are no more adapters in use, and returns `TRUE` if successful, or returns `FALSE` if not and sets LastError.
### Enumeration: `WIREGUARD_LOGGER_LEVEL` - determines level of logging.
|Name|Description|
|--|--|
|`WIREGUARD_LOG_INFO`|Informational|
|`WIREGUARD_LOG_WARN`|Warning|
|`WIREGUARD_LOG_ERR`|Error|
### Callback type: `WIREGUARD_LOGGER_CALLBACK` - called for each log message.
```c
VOID WireGuardLoggerCallback(WIREGUARD_LOGGER_LEVEL Level, DWORD64 Timestamp, LPCWSTR Message);
```
Typedef'd as `WIREGUARD_LOGGER_CALLBACK`. Called by the library on each log message.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_LOGGER_LEVEL`|Level|Message level.|
|`DWORD64`|Timestamp|Message timestamp in in 100ns intervals since 1601-01-01 UTC.|
|`LPCWSTR`|Message|Message text.|
### Function: `WireGuardSetLogger` - registers logger callback function.
```c
VOID WireGuardSetLogger(WIREGUARD_LOGGER_CALLBACK NewLogger);
```
Typedef'd as `WIREGUAR_SET_LOGGER_FUNC`. After registration, the callback may be called concurrently by multiple threads. It is up to the supplied callback function, `NewLogger`, to handle synchronization. If `NewLogger` is `NULL`, logging is disabled.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_LOGGER_CALLBACK`|NewLogger|Pointer to callback function to use as a new global logger.|
### Enumeration: `WIREGUARD_ADAPTER_LOG_STATE` - determines adapter log generation.
|Name|Description|
|--|--|
|`WIREGUARD_ADAPTER_LOG_OFF`|No logs are generated from the driver.|
|`WIREGUARD_ADAPTER_LOG_ON`|Logs are generated from the driver.|
|`WIREGUARD_ADAPTER_LOG_ON_WITH_PREFIX`|Logs are generated from the driver, adapter index-prefixed.|
### Function: `WireGuardSetAdapterLogging` - sets whether adapter logs are generated.
```c
BOOL WireGuardSetAdapterLogging(WIREGUARD_ADAPTER_HANDLE Adapter, WIREGUARD_ADAPTER_LOG_STATE LogState);
```
Typedef'd as `WIREGUARD_SET_ADAPTER_LOGGING`. Sets whether and how the specified adapter logs to the logger previously set by `WireGuardSetLogger`. Returns `TRUE` if successful, or returns `FALSE` if not and sets LastError.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_ADAPTER_HANDLE`|Adapter|Adapter handle obtained with `WireGuardCreateAdapter` or `WireGuardOpenAdapter`.|
|`WIREGUARD_ADAPTER_LOG_STATE`|LogState|Adapter logging state.|
### Enumeration: `WIREGUARD_ADAPTER_STATE` - determines adapter state.
|Name|Description|
|--|--|
|`WIREGUARD_ADAPTER_STATE_DOWN`|Down|
|`WIREGUARD_ADAPTER_STATE_UP`|Up|
### Function: `WireGuardSetAdapterState` - sets state of adapter.
```c
BOOL WireGuardSetAdapterState(WIREGUARD_ADAPTER_HANDLE Adapter, WIREGUARD_ADAPTER_STATE State);
```
Typedef'd as `WIREGUARD_SET_ADAPTER_STATE`. Sets the specified adapter up or down. Note that sockets used by the specified adapter are owned by the process that sets the adapter up. Returns `TRUE` if successful, or returns `FALSE` if not and sets LastError.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_ADAPTER_HANDLE`|Adapter|Adapter handle obtained with `WireGuardCreateAdapter` or `WireGuardOpenAdapter`.|
|`WIREGUARD_ADAPTER_STATE`|State|Adapter state.|
### Function: `WireGuardGetAdapterState` - gets state of adapter.
```c
BOOL WireGuardGetAdapterState(WIREGUARD_ADAPTER_HANDLE Adapter, WIREGUARD_ADAPTER_STATE *State);
```
Typedef'd as `WIREGUARD_GET_ADAPTER_STATE`. Gets whether the specified adapter is up or down. Returns `TRUE` if successful, or returns `FALSE` if not and sets LastError.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_ADAPTER_HANDLE`|Adapter|Adapter handle obtained with `WireGuardCreateAdapter` or `WireGuardOpenAdapter`.|
|`WIREGUARD_ADAPTER_STATE` (out)|State|Pointer to adapter state.|
### Structure: `WIREGUARD_INTERFACE` - an interface.
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_INTERFACE_FLAG`|Flags|Bitwise combination of flags.|
|`WORD`|ListenPort|Port for UDP listen socket, or 0 to choose randomly.|
|`BYTE[WIREGUARD_KEY_LENGTH]`|PrivateKey|Private key of interface.|
|`BYTE[WIREGUARD_KEY_LENGTH]`|PublicKey|Corresponding public key of private key (unused on set).|
|`DWORD`|PeersCount|Number of peer structures following this structure.|
### Structure: `WIREGUARD_PEER` - a peer.
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_PEER_FLAG`|Flags|Bitwise combination of flags.|
|`DWORD`|Reserved|Reserved; must be zero.|
|`BYTE[WIREGUARD_KEY_LENGTH]`|PublicKey|Public key, the peer's primary identifier.|
|`BYTE[WIREGUARD_KEY_LENGTH]`|PresharedKey|Preshared key for additional layer of post-quantum resistance.|
|`WORD`|PersistentKeepalive|Persistent keep-alive seconds interval, or 0 to disable.|
|`SOCKADDR_INET`|Endpoint|Endpoint, with IP address and UDP port number.|
|`DWORD64`|TxBytes|Number of bytes transmitted (unused on set).|
|`DWORD64`|RxBytes|Number of bytes received (unused on set).|
|`DWORD64`|LastHandshake|Time of the last handshake, in 100ns intervals since 1601-01-01 UTC (unused on set).|
|`DWORD`|AllowedIPsCount|Number of allowed IP structures following this structure.|
### Structure: `WIREGUARD_ALLOWED_IP` - an IP network range.
|Type|Name|Description|
|--|--|--|
|Union|Address|IP address; the `V4` member is a `IN_ADDR` and the `V6` member is a `IN6_ADDR`.|
|`ADDRESS_FAMILY`|AddressFamily|Address family, either `AF_INET` or `AF_INET6`.|
|`BYTE`|Cidr|The CIDR of the address range.|
### Constant: `WIREGUARD_KEY_LENGTH` - the length of a key.
All WireGuard keys -- public, private, or pre-shared -- are 32 bytes in length.
### Enumeration: `WIREGUARD_INTERFACE_FLAG` - bitwise flags for interfaces.
These values may be or'd together.
|Name|Description|
|--|--|
|`WIREGUARD_INTERFACE_HAS_PUBLIC_KEY`|The PublicKey field is set (unused on set).|
|`WIREGUARD_INTERFACE_HAS_PRIVATE_KEY`|The PrivateKey field is set.|
|`WIREGUARD_INTERFACE_HAS_LISTEN_PORT`|The ListenPort field is set.|
|`WIREGUARD_INTERFACE_REPLACE_PEERS`|Remove all peers before adding new ones (unused on get).|
### Enumeration: `WIREGUARD_PEER_FLAG` - bitwise flags for peers.
These values may be or'd together.
|Name|Description|
|--|--|
|`WIREGUARD_PEER_HAS_PUBLIC_KEY`|The PublicKey field is set.|
|`WIREGUARD_PEER_HAS_PRESHARED_KEY`|The PresharedKey field is set.|
|`WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE`|The PersistentKeepAlive field is set.|
|`WIREGUARD_PEER_HAS_ENDPOINT`|The Endpoint field is set.|
|`WIREGUARD_PEER_REPLACE_ALLOWED_IPS`|Remove all allowed IPs before adding new ones (unused on get).|
|`WIREGUARD_PEER_REMOVE`|Remove specified peer (unused on get).|
|`WIREGUARD_PEER_UPDATE`|Do not add a new peer (unused on get).|
### Function: `WireGuardSetConfiguration` - sets configuration of adapter.
```c
BOOL WireGuardSetConfiguration(WIREGUARD_ADAPTER_HANDLE Adapter, const WIREGUARD_INTERFACE *Config, DWORD Bytes);
```
Typedef'd as `WIREGUARD_SET_CONFIGURATION`. Sets the configuration of the specified adapter. The `Config` argument represents a `WIREGUARD_INTERFACE` structure, immediately followed in memory by zero or more `WIREGUARD_PEER` or `WIREGUARD_ALLOWED_IP` structures. Returns `TRUE` if successful, or returns `FALSE` if not and sets LastError.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_ADAPTER_HANDLE`|Adapter|Adapter handle obtained with `WireGuardCreateAdapter` or `WireGuardOpenAdapter`.|
|`WIREGUARD_INTERFACE *`|Config|Adapter configuration.|
|`DWORD`|Bytes|Number of bytes of `Config` allocation.|
### Function: `WireGuardGetConfiguration` - gets configuration of adapter.
```c
BOOL WireGuardGetConfiguration(WIREGUARD_ADAPTER_HANDLE Adapter, WIREGUARD_INTERFACE *Config, DWORD *Bytes);
```
Typedef'd as `WIREGUARD_GET_CONFIGURATION`. Gets the configuration of the specified adapter. The `Config` argument represents a `WIREGUARD_INTERFACE` structure, immediately followed in memory by zero or more `WIREGUARD_PEER` or `WIREGUARD_ALLOWED_IP` structures. Returns `TRUE` if successful, or returns `FALSE` if not and sets LastError. If LastError is `ERROR_MORE_DATA`, `Bytes` is updated with the number of bytes needed for successful operation. Since that byte value can change, this function should be called in a tight loop until success or until the error is not `ERROR_MORE_DATA`.
#### Parameters
|Type|Name|Description|
|--|--|--|
|`WIREGUARD_ADAPTER_HANDLE`|Adapter|Adapter handle obtained with `WireGuardCreateAdapter` or `WireGuardOpenAdapter`.|
|`WIREGUARD_INTERFACE *` (out)|Config|Adapter configuration.|
|`DWORD *` (in/out)|Bytes|Pointer to number of bytes of `Config` allocation, on input, and is updated when the function returns to the amount of bytes required.|
## Building
**Do not distribute drivers or files named "WireGuard" or "wireguard" or similar, as they will most certainly clash with official deployments. Instead distribute [`wireguard.dll` as downloaded from the wireguard-nt download server](https://download.wireguard.com/wireguard-nt/).**
General requirements:
- [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/) with Windows SDK
- [Windows Driver Kit](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk)
`wireguard-nt.sln` may be opened in Visual Studio for development and building. Be sure to run `bcdedit /set testsigning on` and then reboot before to enable unsigned driver loading. The default run sequence (F5) in Visual Studio will build the example project and its dependencies.
## License
The entire contents of [this repository](https://git.zx2c4.com/wireguard-nt/), including all documentation and example code, is "Copyright © 2018-2021 WireGuard LLC. All Rights Reserved." Source code is licensed under the [GPLv2](COPYING). Prebuilt binaries from [the wireguard-nt download server](https://download.wireguard.com/wireguard-nt/) are released under a more permissive license suitable for more forms of software contained inside of the .zip files distributed there.

@ -1,308 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 OR MIT
*
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#pragma once
#include <winsock2.h>
#include <windows.h>
#include <ipexport.h>
#include <ifdef.h>
#include <ws2ipdef.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ALIGNED
# if defined(_MSC_VER)
# define ALIGNED(n) __declspec(align(n))
# elif defined(__GNUC__)
# define ALIGNED(n) __attribute__((aligned(n)))
# else
# error "Unable to define ALIGNED"
# endif
#endif
/* MinGW is missing this one, unfortunately. */
#ifndef _Post_maybenull_
# define _Post_maybenull_
#endif
#pragma warning(push)
#pragma warning(disable : 4324) /* structure was padded due to alignment specifier */
/**
* A handle representing WireGuard adapter
*/
typedef struct _WIREGUARD_ADAPTER *WIREGUARD_ADAPTER_HANDLE;
/**
* Creates a new WireGuard adapter.
*
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
*
* @param TunnelType Name of the adapter tunnel type. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
*
* @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation deterministically.
* If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is
* created for each new adapter. It is called "requested" GUID because the API it uses is
* completely undocumented, and so there could be minor interesting complications with its usage.
*
* @return If the function succeeds, the return value is the adapter handle. Must be released with
* WireGuardCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
* GetLastError.
*/
typedef _Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WIREGUARD_ADAPTER_HANDLE(WINAPI WIREGUARD_CREATE_ADAPTER_FUNC)
(_In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelType, _In_opt_ const GUID *RequestedGUID);
/**
* Opens an existing WireGuard adapter.
*
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters.
*
* @return If the function succeeds, the return value is the adapter handle. Must be released with
* WireGuardCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
* GetLastError.
*/
typedef _Must_inspect_result_
_Return_type_success_(return != NULL)
_Post_maybenull_
WIREGUARD_ADAPTER_HANDLE(WINAPI WIREGUARD_OPEN_ADAPTER_FUNC)(_In_z_ LPCWSTR Name);
/**
* Releases WireGuard adapter resources and, if adapter was created with WireGuardCreateAdapter, removes adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter.
*/
typedef VOID(WINAPI WIREGUARD_CLOSE_ADAPTER_FUNC)(_In_opt_ WIREGUARD_ADAPTER_HANDLE Adapter);
/**
* Deletes the WireGuard driver if there are no more adapters in use.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_DELETE_DRIVER_FUNC)(VOID);
/**
* Returns the LUID of the adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param Luid Pointer to LUID to receive adapter LUID.
*/
typedef VOID(WINAPI WIREGUARD_GET_ADAPTER_LUID_FUNC)(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
/**
* Determines the version of the WireGuard driver currently loaded.
*
* @return If the function succeeds, the return value is the version number. If the function fails, the return value is
* zero. To get extended error information, call GetLastError. Possible errors include the following:
* ERROR_FILE_NOT_FOUND WireGuard not loaded
*/
typedef _Return_type_success_(return != 0)
DWORD(WINAPI WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC)(VOID);
/**
* Determines the level of logging, passed to WIREGUARD_LOGGER_CALLBACK.
*/
typedef enum
{
WIREGUARD_LOG_INFO, /**< Informational */
WIREGUARD_LOG_WARN, /**< Warning */
WIREGUARD_LOG_ERR /**< Error */
} WIREGUARD_LOGGER_LEVEL;
/**
* Called by internal logger to report diagnostic messages
*
* @param Level Message level.
*
* @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC.
*
* @param Message Message text.
*/
typedef VOID(CALLBACK *WIREGUARD_LOGGER_CALLBACK)(
_In_ WIREGUARD_LOGGER_LEVEL Level,
_In_ DWORD64 Timestamp,
_In_z_ LPCWSTR Message);
/**
* Sets logger callback function.
*
* @param NewLogger Pointer to callback function to use as a new global logger. NewLogger may be called from various
* threads concurrently. Should the logging require serialization, you must handle serialization in
* NewLogger. Set to NULL to disable.
*/
typedef VOID(WINAPI WIREGUARD_SET_LOGGER_FUNC)(_In_ WIREGUARD_LOGGER_CALLBACK NewLogger);
/**
* Whether and how logs from the driver are collected for the callback function.
*/
typedef enum
{
WIREGUARD_ADAPTER_LOG_OFF, /**< No logs are generated from the driver. */
WIREGUARD_ADAPTER_LOG_ON, /**< Logs are generated from the driver. */
WIREGUARD_ADAPTER_LOG_ON_WITH_PREFIX /**< Logs are generated from the driver, index-prefixed. */
} WIREGUARD_ADAPTER_LOG_STATE;
/**
* Sets whether and how the adapter logs to the logger previously set up with WireGuardSetLogger.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param LogState Adapter logging state.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_SET_ADAPTER_LOGGING_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _In_ WIREGUARD_ADAPTER_LOG_STATE LogState);
/**
* Determines the state of the adapter.
*/
typedef enum
{
WIREGUARD_ADAPTER_STATE_DOWN, /**< Down */
WIREGUARD_ADAPTER_STATE_UP, /**< Up */
} WIREGUARD_ADAPTER_STATE;
/**
* Sets the adapter state of the WireGuard adapter. Note: sockets are owned by the process that sets the state to up.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param State Adapter state.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_SET_ADAPTER_STATE_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _In_ WIREGUARD_ADAPTER_STATE State);
/**
* Gets the adapter state of the WireGuard adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param State Pointer to adapter state.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_GET_ADAPTER_STATE_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _Out_ WIREGUARD_ADAPTER_STATE *State);
#define WIREGUARD_KEY_LENGTH 32
typedef struct _WIREGUARD_ALLOWED_IP WIREGUARD_ALLOWED_IP;
struct ALIGNED(8) _WIREGUARD_ALLOWED_IP
{
union
{
IN_ADDR V4;
IN6_ADDR V6;
} Address; /**< IP address */
ADDRESS_FAMILY AddressFamily; /**< Address family, either AF_INET or AF_INET6 */
BYTE Cidr; /**< CIDR of allowed IPs */
};
typedef enum
{
WIREGUARD_PEER_HAS_PUBLIC_KEY = 1 << 0, /**< The PublicKey field is set */
WIREGUARD_PEER_HAS_PRESHARED_KEY = 1 << 1, /**< The PresharedKey field is set */
WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE = 1 << 2, /**< The PersistentKeepAlive field is set */
WIREGUARD_PEER_HAS_ENDPOINT = 1 << 3, /**< The Endpoint field is set */
WIREGUARD_PEER_REPLACE_ALLOWED_IPS = 1 << 5, /**< Remove all allowed IPs before adding new ones */
WIREGUARD_PEER_REMOVE = 1 << 6, /**< Remove specified peer */
WIREGUARD_PEER_UPDATE = 1 << 7 /**< Do not add a new peer */
} WIREGUARD_PEER_FLAG;
typedef struct _WIREGUARD_PEER WIREGUARD_PEER;
struct ALIGNED(8) _WIREGUARD_PEER
{
WIREGUARD_PEER_FLAG Flags; /**< Bitwise combination of flags */
DWORD Reserved; /**< Reserved; must be zero */
BYTE PublicKey[WIREGUARD_KEY_LENGTH]; /**< Public key, the peer's primary identifier */
BYTE PresharedKey[WIREGUARD_KEY_LENGTH]; /**< Preshared key for additional layer of post-quantum resistance */
WORD PersistentKeepalive; /**< Seconds interval, or 0 to disable */
SOCKADDR_INET Endpoint; /**< Endpoint, with IP address and UDP port number*/
DWORD64 TxBytes; /**< Number of bytes transmitted */
DWORD64 RxBytes; /**< Number of bytes received */
DWORD64 LastHandshake; /**< Time of the last handshake, in 100ns intervals since 1601-01-01 UTC */
DWORD AllowedIPsCount; /**< Number of allowed IP structs following this struct */
};
typedef enum
{
WIREGUARD_INTERFACE_HAS_PUBLIC_KEY = (1 << 0), /**< The PublicKey field is set */
WIREGUARD_INTERFACE_HAS_PRIVATE_KEY = (1 << 1), /**< The PrivateKey field is set */
WIREGUARD_INTERFACE_HAS_LISTEN_PORT = (1 << 2), /**< The ListenPort field is set */
WIREGUARD_INTERFACE_REPLACE_PEERS = (1 << 3) /**< Remove all peers before adding new ones */
} WIREGUARD_INTERFACE_FLAG;
typedef struct _WIREGUARD_INTERFACE WIREGUARD_INTERFACE;
struct ALIGNED(8) _WIREGUARD_INTERFACE
{
WIREGUARD_INTERFACE_FLAG Flags; /**< Bitwise combination of flags */
WORD ListenPort; /**< Port for UDP listen socket, or 0 to choose randomly */
BYTE PrivateKey[WIREGUARD_KEY_LENGTH]; /**< Private key of interface */
BYTE PublicKey[WIREGUARD_KEY_LENGTH]; /**< Corresponding public key of private key */
DWORD PeersCount; /**< Number of peer structs following this struct */
};
/**
* Sets the configuration of the WireGuard adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param Config Configuration for the adapter.
*
* @param Bytes Number of bytes in Config allocation.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError.
*/
typedef _Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_SET_CONFIGURATION_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter, _In_reads_bytes_(Bytes) const WIREGUARD_INTERFACE *Config, _In_ DWORD Bytes);
/**
* Gets the configuration of the WireGuard adapter.
*
* @param Adapter Adapter handle obtained with WireGuardCreateAdapter or WireGuardOpenAdapter
*
* @param Config Configuration for the adapter.
*
* @param Bytes Pointer to number of bytes in Config allocation.
*
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
* get extended error information, call GetLastError, which if ERROR_MORE_DATA, Bytes is updated with the
* required size.
*/
typedef _Must_inspect_result_
_Return_type_success_(return != FALSE)
BOOL(WINAPI WIREGUARD_GET_CONFIGURATION_FUNC)
(_In_ WIREGUARD_ADAPTER_HANDLE Adapter,
_Out_writes_bytes_all_(*Bytes) WIREGUARD_INTERFACE *Config,
_Inout_ DWORD *Bytes);
#pragma warning(pop)
#ifdef __cplusplus
}
#endif

0
addons/wginterface.cpp Normal file

0
addons/wginterface.hh Normal file

@ -11,7 +11,7 @@
"license": "GPL-3.0-or-later",
"repository": {
"type": "git",
"url": "git+https://sirherobrine23.org/Wireguard/Wireguard-tools.js.git"
"url": "https://sirherobrine23.org/Wireguard/Wireguard-tools.js.git"
},
"keywords": [
"wireguard",

@ -1,414 +0,0 @@
# Do not edit. File was generated by node-gyp's "configure" step
{
"target_defaults": {
"cflags": [],
"default_configuration": "Release",
"defines": [],
"include_dirs": [],
"libraries": [],
"msbuild_toolset": "v143",
"msvs_windows_target_platform_version": "10.0.22621.0"
},
"variables": {
"asan": 0,
"coverage": "false",
"dcheck_always_on": 0,
"debug_nghttp2": "false",
"debug_node": "false",
"enable_lto": "false",
"enable_pgo_generate": "false",
"enable_pgo_use": "false",
"error_on_warn": "false",
"force_dynamic_crt": 0,
"host_arch": "x64",
"icu_data_in": "..\\..\\deps\\icu-tmp\\icudt73l.dat",
"icu_endianness": "l",
"icu_gyp_path": "tools/icu/icu-generic.gyp",
"icu_path": "deps/icu-small",
"icu_small": "false",
"icu_ver_major": "73",
"is_debug": 0,
"libdir": "lib",
"llvm_version": "0.0",
"napi_build_version": "9",
"nasm_version": "2.16",
"node_builtin_shareable_builtins": [
"deps/cjs-module-lexer/lexer.js",
"deps/cjs-module-lexer/dist/lexer.js",
"deps/undici/undici.js"
],
"node_byteorder": "little",
"node_debug_lib": "false",
"node_enable_d8": "false",
"node_enable_v8_vtunejit": "false",
"node_fipsinstall": "false",
"node_install_corepack": "true",
"node_install_npm": "true",
"node_library_files": [
"lib/_http_agent.js",
"lib/_http_client.js",
"lib/_http_common.js",
"lib/_http_incoming.js",
"lib/_http_outgoing.js",
"lib/_http_server.js",
"lib/_stream_duplex.js",
"lib/_stream_passthrough.js",
"lib/_stream_readable.js",
"lib/_stream_transform.js",
"lib/_stream_wrap.js",
"lib/_stream_writable.js",
"lib/_tls_common.js",
"lib/_tls_wrap.js",
"lib/assert.js",
"lib/assert/strict.js",
"lib/async_hooks.js",
"lib/buffer.js",
"lib/child_process.js",
"lib/cluster.js",
"lib/console.js",
"lib/constants.js",
"lib/crypto.js",
"lib/dgram.js",
"lib/diagnostics_channel.js",
"lib/dns.js",
"lib/dns/promises.js",
"lib/domain.js",
"lib/events.js",
"lib/fs.js",
"lib/fs/promises.js",
"lib/http.js",
"lib/http2.js",
"lib/https.js",
"lib/inspector.js",
"lib/inspector/promises.js",
"lib/internal/abort_controller.js",
"lib/internal/assert.js",
"lib/internal/assert/assertion_error.js",
"lib/internal/assert/calltracker.js",
"lib/internal/async_hooks.js",
"lib/internal/blob.js",
"lib/internal/blocklist.js",
"lib/internal/bootstrap/node.js",
"lib/internal/bootstrap/realm.js",
"lib/internal/bootstrap/switches/does_not_own_process_state.js",
"lib/internal/bootstrap/switches/does_own_process_state.js",
"lib/internal/bootstrap/switches/is_main_thread.js",
"lib/internal/bootstrap/switches/is_not_main_thread.js",
"lib/internal/bootstrap/web/exposed-wildcard.js",
"lib/internal/bootstrap/web/exposed-window-or-worker.js",
"lib/internal/buffer.js",
"lib/internal/child_process.js",
"lib/internal/child_process/serialization.js",
"lib/internal/cli_table.js",
"lib/internal/cluster/child.js",
"lib/internal/cluster/primary.js",
"lib/internal/cluster/round_robin_handle.js",
"lib/internal/cluster/shared_handle.js",
"lib/internal/cluster/utils.js",
"lib/internal/cluster/worker.js",
"lib/internal/console/constructor.js",
"lib/internal/console/global.js",
"lib/internal/constants.js",
"lib/internal/crypto/aes.js",
"lib/internal/crypto/certificate.js",
"lib/internal/crypto/cfrg.js",
"lib/internal/crypto/cipher.js",
"lib/internal/crypto/diffiehellman.js",
"lib/internal/crypto/ec.js",
"lib/internal/crypto/hash.js",
"lib/internal/crypto/hashnames.js",
"lib/internal/crypto/hkdf.js",
"lib/internal/crypto/keygen.js",
"lib/internal/crypto/keys.js",
"lib/internal/crypto/mac.js",
"lib/internal/crypto/pbkdf2.js",
"lib/internal/crypto/random.js",
"lib/internal/crypto/rsa.js",
"lib/internal/crypto/scrypt.js",
"lib/internal/crypto/sig.js",
"lib/internal/crypto/util.js",
"lib/internal/crypto/webcrypto.js",
"lib/internal/crypto/webidl.js",
"lib/internal/crypto/x509.js",
"lib/internal/debugger/inspect.js",
"lib/internal/debugger/inspect_client.js",
"lib/internal/debugger/inspect_repl.js",
"lib/internal/dgram.js",
"lib/internal/dns/callback_resolver.js",
"lib/internal/dns/promises.js",
"lib/internal/dns/utils.js",
"lib/internal/encoding.js",
"lib/internal/error_serdes.js",
"lib/internal/errors.js",
"lib/internal/event_target.js",
"lib/internal/events/symbols.js",
"lib/internal/file.js",
"lib/internal/fixed_queue.js",
"lib/internal/freelist.js",
"lib/internal/freeze_intrinsics.js",
"lib/internal/fs/cp/cp-sync.js",
"lib/internal/fs/cp/cp.js",
"lib/internal/fs/dir.js",
"lib/internal/fs/promises.js",
"lib/internal/fs/read/context.js",
"lib/internal/fs/read/utf8.js",
"lib/internal/fs/recursive_watch.js",
"lib/internal/fs/rimraf.js",
"lib/internal/fs/streams.js",
"lib/internal/fs/sync_write_stream.js",
"lib/internal/fs/utils.js",
"lib/internal/fs/watchers.js",
"lib/internal/heap_utils.js",
"lib/internal/histogram.js",
"lib/internal/http.js",
"lib/internal/http2/compat.js",
"lib/internal/http2/core.js",
"lib/internal/http2/util.js",
"lib/internal/idna.js",
"lib/internal/inspector_async_hook.js",
"lib/internal/js_stream_socket.js",
"lib/internal/legacy/processbinding.js",
"lib/internal/linkedlist.js",
"lib/internal/main/check_syntax.js",
"lib/internal/main/embedding.js",
"lib/internal/main/eval_stdin.js",
"lib/internal/main/eval_string.js",
"lib/internal/main/inspect.js",
"lib/internal/main/mksnapshot.js",
"lib/internal/main/print_help.js",
"lib/internal/main/prof_process.js",
"lib/internal/main/repl.js",
"lib/internal/main/run_main_module.js",
"lib/internal/main/test_runner.js",
"lib/internal/main/watch_mode.js",
"lib/internal/main/worker_thread.js",
"lib/internal/mime.js",
"lib/internal/modules/cjs/loader.js",
"lib/internal/modules/esm/assert.js",
"lib/internal/modules/esm/create_dynamic_module.js",
"lib/internal/modules/esm/fetch_module.js",
"lib/internal/modules/esm/formats.js",
"lib/internal/modules/esm/get_format.js",
"lib/internal/modules/esm/handle_process_exit.js",
"lib/internal/modules/esm/hooks.js",
"lib/internal/modules/esm/initialize_import_meta.js",
"lib/internal/modules/esm/load.js",
"lib/internal/modules/esm/loader.js",
"lib/internal/modules/esm/module_job.js",
"lib/internal/modules/esm/module_map.js",
"lib/internal/modules/esm/package_config.js",
"lib/internal/modules/esm/resolve.js",
"lib/internal/modules/esm/shared_constants.js",
"lib/internal/modules/esm/translators.js",
"lib/internal/modules/esm/utils.js",
"lib/internal/modules/esm/worker.js",
"lib/internal/modules/helpers.js",
"lib/internal/modules/package_json_reader.js",
"lib/internal/modules/run_main.js",
"lib/internal/net.js",
"lib/internal/options.js",
"lib/internal/per_context/domexception.js",
"lib/internal/per_context/messageport.js",
"lib/internal/per_context/primordials.js",
"lib/internal/perf/event_loop_delay.js",
"lib/internal/perf/event_loop_utilization.js",
"lib/internal/perf/nodetiming.js",
"lib/internal/perf/observe.js",
"lib/internal/perf/performance.js",
"lib/internal/perf/performance_entry.js",
"lib/internal/perf/resource_timing.js",
"lib/internal/perf/timerify.js",
"lib/internal/perf/usertiming.js",
"lib/internal/perf/utils.js",
"lib/internal/policy/manifest.js",
"lib/internal/policy/sri.js",
"lib/internal/priority_queue.js",
"lib/internal/process/esm_loader.js",
"lib/internal/process/execution.js",
"lib/internal/process/per_thread.js",
"lib/internal/process/permission.js",
"lib/internal/process/policy.js",
"lib/internal/process/pre_execution.js",
"lib/internal/process/promises.js",
"lib/internal/process/report.js",
"lib/internal/process/signal.js",
"lib/internal/process/task_queues.js",
"lib/internal/process/warning.js",
"lib/internal/process/worker_thread_only.js",
"lib/internal/promise_hooks.js",
"lib/internal/querystring.js",
"lib/internal/readline/callbacks.js",
"lib/internal/readline/emitKeypressEvents.js",
"lib/internal/readline/interface.js",
"lib/internal/readline/promises.js",
"lib/internal/readline/utils.js",
"lib/internal/repl.js",
"lib/internal/repl/await.js",
"lib/internal/repl/history.js",
"lib/internal/repl/utils.js",
"lib/internal/socket_list.js",
"lib/internal/socketaddress.js",
"lib/internal/source_map/prepare_stack_trace.js",
"lib/internal/source_map/source_map.js",
"lib/internal/source_map/source_map_cache.js",
"lib/internal/stream_base_commons.js",
"lib/internal/streams/add-abort-signal.js",
"lib/internal/streams/buffer_list.js",
"lib/internal/streams/compose.js",
"lib/internal/streams/destroy.js",
"lib/internal/streams/duplex.js",
"lib/internal/streams/duplexify.js",
"lib/internal/streams/end-of-stream.js",
"lib/internal/streams/from.js",
"lib/internal/streams/lazy_transform.js",
"lib/internal/streams/legacy.js",
"lib/internal/streams/operators.js",
"lib/internal/streams/passthrough.js",
"lib/internal/streams/pipeline.js",
"lib/internal/streams/readable.js",
"lib/internal/streams/state.js",
"lib/internal/streams/transform.js",
"lib/internal/streams/utils.js",
"lib/internal/streams/writable.js",
"lib/internal/structured_clone.js",
"lib/internal/test/binding.js",
"lib/internal/test/transfer.js",
"lib/internal/test_runner/coverage.js",
"lib/internal/test_runner/harness.js",
"lib/internal/test_runner/mock/mock.js",
"lib/internal/test_runner/mock/mock_timers.js",
"lib/internal/test_runner/reporter/dot.js",
"lib/internal/test_runner/reporter/spec.js",
"lib/internal/test_runner/reporter/tap.js",
"lib/internal/test_runner/reporter/v8-serializer.js",
"lib/internal/test_runner/runner.js",
"lib/internal/test_runner/test.js",
"lib/internal/test_runner/tests_stream.js",
"lib/internal/test_runner/utils.js",
"lib/internal/timers.js",
"lib/internal/tls/secure-context.js",
"lib/internal/tls/secure-pair.js",
"lib/internal/trace_events_async_hooks.js",
"lib/internal/tty.js",
"lib/internal/url.js",
"lib/internal/util.js",
"lib/internal/util/colors.js",
"lib/internal/util/comparisons.js",
"lib/internal/util/debuglog.js",
"lib/internal/util/embedding.js",
"lib/internal/util/inspect.js",
"lib/internal/util/inspector.js",
"lib/internal/util/iterable_weak_map.js",
"lib/internal/util/parse_args/parse_args.js",
"lib/internal/util/parse_args/utils.js",
"lib/internal/util/types.js",
"lib/internal/v8/startup_snapshot.js",
"lib/internal/v8_prof_polyfill.js",
"lib/internal/v8_prof_processor.js",
"lib/internal/validators.js",
"lib/internal/vm.js",
"lib/internal/vm/module.js",
"lib/internal/wasm_web_api.js",
"lib/internal/watch_mode/files_watcher.js",
"lib/internal/watchdog.js",
"lib/internal/webidl.js",
"lib/internal/webstreams/adapters.js",
"lib/internal/webstreams/compression.js",
"lib/internal/webstreams/encoding.js",
"lib/internal/webstreams/queuingstrategies.js",
"lib/internal/webstreams/readablestream.js",
"lib/internal/webstreams/transfer.js",
"lib/internal/webstreams/transformstream.js",
"lib/internal/webstreams/util.js",
"lib/internal/webstreams/writablestream.js",
"lib/internal/worker.js",
"lib/internal/worker/io.js",
"lib/internal/worker/js_transferable.js",
"lib/module.js",
"lib/net.js",
"lib/os.js",
"lib/path.js",
"lib/path/posix.js",
"lib/path/win32.js",
"lib/perf_hooks.js",
"lib/process.js",
"lib/punycode.js",
"lib/querystring.js",
"lib/readline.js",
"lib/readline/promises.js",
"lib/repl.js",
"lib/stream.js",
"lib/stream/consumers.js",
"lib/stream/promises.js",
"lib/stream/web.js",
"lib/string_decoder.js",
"lib/sys.js",
"lib/test.js",
"lib/test/reporters.js",
"lib/timers.js",
"lib/timers/promises.js",
"lib/tls.js",
"lib/trace_events.js",
"lib/tty.js",
"lib/url.js",
"lib/util.js",
"lib/util/types.js",
"lib/v8.js",
"lib/vm.js",
"lib/wasi.js",
"lib/worker_threads.js",
"lib/zlib.js"
],
"node_module_version": 115,
"node_no_browser_globals": "false",
"node_prefix": "\\usr\\local",
"node_release_urlbase": "https://nodejs.org/download/release/",
"node_shared": "false",
"node_shared_brotli": "false",
"node_shared_cares": "false",
"node_shared_http_parser": "false",
"node_shared_libuv": "false",
"node_shared_nghttp2": "false",
"node_shared_nghttp3": "false",
"node_shared_ngtcp2": "false",
"node_shared_openssl": "false",
"node_shared_zlib": "false",
"node_tag": "",
"node_target_type": "executable",
"node_use_bundled_v8": "true",
"node_use_node_code_cache": "true",
"node_use_node_snapshot": "true",
"node_use_openssl": "true",
"node_use_v8_platform": "true",
"node_with_ltcg": "true",
"node_without_node_options": "false",
"openssl_is_fips": "false",
"openssl_quic": "true",
"ossfuzz": "false",
"shlib_suffix": "so.115",
"single_executable_application": "true",
"target_arch": "x64",
"v8_enable_31bit_smis_on_64bit_arch": 0,
"v8_enable_gdbjit": 0,
"v8_enable_hugepage": 0,
"v8_enable_i18n_support": 1,
"v8_enable_inspector": 1,
"v8_enable_javascript_promise_hooks": 1,
"v8_enable_lite_mode": 0,
"v8_enable_object_print": 1,
"v8_enable_pointer_compression": 0,
"v8_enable_shared_ro_heap": 1,
"v8_enable_short_builtin_calls": 1,
"v8_enable_webassembly": 1,
"v8_no_strict_aliasing": 1,
"v8_optimized_debug": 1,
"v8_promise_internal_field_count": 1,
"v8_random_seed": 0,
"v8_trace_maps": 0,
"v8_use_siphash": 1,
"want_separate_host_toolset": 0,
"nodedir": "C:\\Users\\mathe\\AppData\\Local\\node-gyp\\Cache\\20.6.1",
"standalone_static_library": 1,
"msbuild_path": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe"
}
}

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

@ -1,249 +0,0 @@
import { promises as fs } from "fs";
import { isIPv4, createConnection as netConnection } from "net";
import path from "path";
import readline from "readline";
import { finished } from "stream/promises";
import rebory from "rebory";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const addon = rebory.loadAddon(path.join(__dirname, "../binding.yaml")).wginterface.loadRelease<{
listDevices?: () => Promise<{from: "userspace"|"kernel", name: string, path?: string}[]>;
deleteInterface?: (wgName: string) => Promise<void>;
setConfig?: (wgName: string, config: WgConfigSet) => Promise<void>;
getConfig?: (wgName: string) => Promise<WgConfigGet>;
createTun?: () => Promise<number|string>;
deleteTun?: () => void;
checkTun?: () => Promise<boolean>;
getTun?: () => Promise<number|string>;
/** Wireguard addon constants */
constants: {
driveVersion: string;
base64Length: number;
keyLength: 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")
});
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 {
/** Preshared key to peer */
presharedKey?: string;
/** keepInterval specifies the persistent keepalive interval for this peer */
keepInterval?: number;
/** Remote address or hostname to Wireguard connect or endpoint is the most recent source address used for communication by peer. */
endpoint?: string;
/** AllowedIPs specifies a list of allowed IP addresses in CIDR notation (`0.0.0.0/0`, `::/0`) */
allowedIPs?: string[];
};
export interface PeerSet extends Peer {
/** Mark this peer to be removed, any changes remove this option */
removeMe?: boolean;
}
export interface PeerGet extends Peer {
/** ReceiveBytes indicates the number of bytes received from this peer. */
rxBytes?: number;
/** TransmitBytes indicates the number of bytes transmitted to this peer. */
txBytes?: number;
/** Last peer Handshake */
lastHandshake?: Date;
}
export interface WgConfigBase<T extends Peer> {
/** privateKey specifies a private key configuration */
privateKey: string;
/** publicKey specifies a public key configuration */
publicKey?: string;
/** ListenPort specifies a device's listening port, 0 is random */
portListen?: number;
/** FirewallMark specifies a device's firewall mark */
fwmark?: number;
/** Interface IP address'es */
address?: string[];
/** Interface peers */
peers: Record<string, T>;
}
export interface WgConfigGet extends WgConfigBase<PeerGet> {}
export interface WgConfigSet extends WgConfigBase<PeerSet> {
/** this option will remove all peers if `true` and add new peers */
replacePeers?: boolean;
}
export type WgGlobalConfig = WgConfigSet & WgConfigGet;
/**
* Get Wireguard devices and locations
*/
export async function listDevices() {
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
* @param wgName - 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
*/
export async function setConfig(wgName: string, config: WgConfigGet): Promise<void>;
/**
* 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
*/
export async function setConfig(wgName: string, config: WgConfigSet): Promise<void> {
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))));
// fwmark
if (Math.floor(config.fwmark) >= 0) writel(("fwmark="), ((Math.floor(config.fwmark))));
// Replace peer's
if (config.replacePeers) writel("replace_peers=true");
// 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
* @param wgName - Interface name
* @returns
*/
export async function getConfig(wgName: string): Promise<WgConfigGet> {
if (typeof addon.getConfig === "function") return addon.getConfig(wgName);
const info = (await listDevices()).find(int => int.name === wgName);
if (!info) throw new Error("Create interface, not exists");
const client = netConnection(path.join(defaultPath, wgName.concat(".sock")));
const config: WgConfigGet = Object();
let latestPeer: string, previewKey: string;
const tetrisBreak = readline.createInterface(client);
tetrisBreak.on("line", function lineProcess(line) {
if (line === "") tetrisBreak.removeListener("line", lineProcess).close();
const findout = line.indexOf("="), keyName = line.slice(0, findout), value = line.slice(findout+1);
if (findout <= 0) return;
if (keyName === "errno" && value !== "0") throw new Error(("wireguard-go error, code: ").concat(value));
// Drop
if ((["last_handshake_time_nsec", "protocol_version", "errno"]).includes(keyName)) return;
else if (keyName === "private_key") config.privateKey = Buffer.from(value, "hex").toString("base64");
else if (keyName === "listen_port") config.portListen = Number(value);
else if (keyName === "endpoint") ((config.peers||(config.peers = {}))[latestPeer]).endpoint = value;
else if (keyName === "persistent_keepalive_interval") ((config.peers||(config.peers = {}))[latestPeer]).keepInterval = Number(value);
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") {
if (!value) return;
((config.peers||(config.peers = {}))[latestPeer]).allowedIPs = (((config.peers||(config.peers = {}))[latestPeer]).allowedIPs||[]).concat(value);
} else if (keyName === "preshared_key") {
if (value === "0000000000000000000000000000000000000000000000000000000000000000") return;
((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,54 +0,0 @@
import test from "node:test";
import { setConfig, deleteInterface, WgConfigSet, getConfig } from "./wginterface.js";
import { publicKey } from "./key.js";
import { userInfo } from "os";
if (process.platform === "win32" || process.platform === "linux" && (userInfo().uid === 0)) {
test("Wireguard configuration", async t => {
// Config base
const peer1Key = 'EKgSatFzZtsv1qFJ6gE8HqfuA+tXzW+7vDeVc7Xaa2E=', peer2Key = '4BSvgiM9j5jjuR0Vg3gbqTFD5+CyuOU2K2kJE5+cakQ=',
config: WgConfigSet = {
privateKey: "4GTKsUfzodunTXaHtY/u+JhQN1D2CP1Sc+4D1VmpylY=",
address: [
"10.66.124.1/32"
],
peers: {}
};
config.peers[publicKey(peer1Key)] = {
allowedIPs: [
"10.66.124.2"
]
}
await t.test("Set config in interface", async () => {
await setConfig("wg23", config);
});
await t.test("Get config in interface", async () => {
const __config = await getConfig("wg23");
if (!__config.peers[publicKey(peer1Key)]) throw new Error("Not exist peer 1!");
});
config.peers[publicKey(peer1Key)].removeMe = true;
config.peers[publicKey(peer2Key)] = {
allowedIPs: [
"10.66.124.3"
]
}
await t.test("Set config in interface", async () => {
await setConfig("wg23", config);
});
await t.test("Get config in interface", async () => {
const __config = await getConfig("wg23");
if (__config.peers[publicKey(peer1Key)]) throw new Error("Invalid config get!");
if (!__config.peers[publicKey(peer2Key)]) throw new Error("Not exist peer 2!");
});
await t.test("Delete interface", async () => {
await deleteInterface("wg23");
});
});
}