WIP: Rewrite package with napi-go #18

Draft
Sirherobrine23 wants to merge 3 commits from go-napi into main
35 changed files with 320 additions and 5030 deletions

View File

@@ -1,34 +0,0 @@
FROM ubuntu:latest
ARG DEBIAN_FRONTEND="noninteractive"
ARG GOVERSION="1.22.0"
ARG ZIGVERSION="0.11.0"
RUN apt update && apt list --upgradable -a && apt upgrade -y
RUN apt update && apt install -y xz-utils software-properties-common cmake make build-essential git curl wget jq sudo procps zsh tar screen ca-certificates procps lsb-release gnupg gnupg2 gpg apt-transport-https python3-pip apt-file attr bash-completion bc bison clang command-not-found dialog dos2unix ed flex gawk gperf htop libresolv-wrapper lld llvm lsof man neofetch neovim rhash tree tshark unbound unzip xxhash openssh-server openssh-client
STOPSIGNAL SIGSTOP
CMD [ "zsh" ]
WORKDIR /root
# Nodejs
RUN curl https://deb.nodesource.com/setup_lts.x | bash && apt install nodejs -y
# Go (golang)
RUN wget -qO- "https://go.dev/dl/go${GOVERSION}.linux-$(dpkg --print-architecture).tar.gz" | tar -C /usr/local -xzv && ln -s /usr/local/go/bin/go /usr/bin/go && ln -s /usr/local/go/bin/gofmt /usr/bin/gofmt
# Install Github CLI (gh)
RUN (wget -q "$(wget -qO- https://api.github.com/repos/cli/cli/releases/latest | grep 'browser_download_url' | grep '.deb' | cut -d \" -f 4 | grep $(dpkg --print-architecture))" -O /tmp/gh.deb && dpkg -i /tmp/gh.deb && rm /tmp/gh.deb) || echo "Fail Install gh"
# Zig
RUN wget -qO- "https://ziglang.org/download/${ZIGVERSION}/zig-linux-$(uname -m)-${ZIGVERSION}.tar.xz" | tar -xvJ -C /usr/local/ && \
mv -v /usr/local/zig* /usr/local/zig && \
ln -s /usr/local/zig/zig /usr/bin/zig
ARG USERNAME="devcontainer"
ARG USER_UID="1000"
ARG USER_GID=$USER_UID
# Add non root user and Install oh my zsh
RUN addgroup --gid "${USER_GID}" "${USERNAME}"; useradd --uid "${USER_UID}" --gid "${USER_GID}" --groups sudo -m --shell /usr/bib/zsh "${USERNAME}" -p test
USER $USERNAME
WORKDIR /home/$USERNAME
RUN git clone https://github.com/Sirherobrine23/dotfiles.git dotfiles && cd dotfiles && ./install; cd /home/$USERNAME; rm -rf dotfiles

View File

@@ -1,28 +0,0 @@
{
"name": "wg.js devcontainer",
"updateRemoteUserUID": false,
"containerUser": "develop",
"remoteUser": "develop",
"runArgs": [
"--init"
],
"privileged": true,
"customizations": {
"vscode": {
"extensions": [
"github.vscode-github-actions",
"ms-vscode.cpptools",
"eamodio.gitlens",
"euskadi31.json-pretty-printer",
"redhat.vscode-yaml"
]
}
},
"build": {
"dockerfile": "Dockerfile",
"args": {
"USERNAME": "develop",
"USER_UID": "1000"
}
}
}

View File

@@ -1,46 +0,0 @@
{
"configurations": [
{
"name": "Mac",
"includePath": [
"/usr/local/include/node",
"/usr/local/lib/zig//libc/include/any-linux-any",
"${workspaceFolder}/node_modules/node-addon-api",
"${workspaceFolder}/**",
"${workspaceFolder}/addon"
],
"defines": [
"AF_NETLINK=16"
],
"macFrameworkPath": [
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
],
"compilerPath": "/usr/bin/clang",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "macos-clang-x64"
},
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/node_modules/node-addon-api",
"/usr/include/node",
"${workspaceFolder}/**",
"${workspaceFolder}/addon"
]
},
{
"name": "Win32",
"includePath": [
"${env:appdata}/../.cache/rebory/latest/node/include/node",
"${workspaceFolder}/node_modules/node-addon-api",
"${workspaceFolder}/addon"
],
"defines": [],
"intelliSenseMode": "windows-msvc-x64",
"cStandard": "c17",
"cppStandard": "c++17"
}
],
"version": 4
}

View File

@@ -1,9 +0,0 @@
{
"recommendations": [
"github.vscode-github-actions",
"ms-vscode.cpptools",
"eamodio.gitlens",
"euskadi31.json-pretty-printer",
"redhat.vscode-yaml"
]
}

109
.vscode/settings.json vendored
View File

@@ -12,112 +12,5 @@
},
"files.exclude": {
"**/node_modules/": true
},
"terminal.integrated.env.windows": {
"PATH": "${workspaceFolder}/node_modules/.bin;${env:PATH}"
},
"terminal.integrated.env.linux": {
"PATH": "${workspaceFolder}/node_modules/.bin:${env:PATH}"
},
"terminal.integrated.env.osx": {
"PATH": "${workspaceFolder}/node_modules/.bin:${env:PATH}"
},
"files.associations": {
"*.dsc": "ini",
"*.gyp": "python",
"random": "cpp",
"limits": "cpp",
"xstring": "cpp",
"__bit_reference": "cpp",
"__bits": "cpp",
"__config": "cpp",
"__debug": "cpp",
"__errc": "cpp",
"__hash_table": "cpp",
"__locale": "cpp",
"__mutex_base": "cpp",
"__node_handle": "cpp",
"__nullptr": "cpp",
"__split_buffer": "cpp",
"__string": "cpp",
"__threading_support": "cpp",
"__tree": "cpp",
"__tuple": "cpp",
"array": "cpp",
"atomic": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"exception": "cpp",
"initializer_list": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"locale": "cpp",
"map": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"numeric": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"variant": "cpp",
"vector": "cpp",
"algorithm": "cpp",
"bit": "cpp",
"charconv": "cpp",
"codecvt": "cpp",
"format": "cpp",
"forward_list": "cpp",
"functional": "cpp",
"iomanip": "cpp",
"iterator": "cpp",
"list": "cpp",
"stop_token": "cpp",
"thread": "cpp",
"utility": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp",
"fstream": "cpp",
"deque": "cpp",
"stack": "cpp"
}
}
}

View File

@@ -1,7 +1,3 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#folder-specific-settings
{
"remove_trailing_whitespace_on_save": true,
"ensure_final_newline_on_save": true,
@@ -27,12 +23,6 @@
},
"Go": {
"format_on_save": "on"
},
"C++": {
"hard_tabs": false
},
"C": {
"hard_tabs": false
}
}
}

View File

@@ -1,90 +0,0 @@
cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW)
cmake_policy(SET CMP0042 NEW)
project (wg)
add_compile_definitions(NAPI_VERSION=8 NAPI_CPP_EXCEPTIONS)
set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 17)
execute_process(COMMAND node -p "require('node-addon-api').include"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE NODE_ADDON_API_DIR
)
string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
include_directories(PRIVATE ${NODE_ADDON_API_DIR})
include_directories(${CMAKE_JS_INC})
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/addon")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/addon/genKey")
if(UNIX)
add_definitions(-fpermissive -fexceptions -w -fpermissive -fPIC)
endif()
file(GLOB SOURCE_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/addon/main.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/addon/genKey/wgkeys.cpp"
)
if(MSVC)
file(GLOB SOURCE_FILES ${SOURCE_FILES} "${CMAKE_CURRENT_SOURCE_DIR}/addon/win/wginterface.cpp")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/addon/win")
add_compile_definitions(_HAS_EXCEPTIONS=1 ONSTARTADDON)
target_link_libraries(${PROJECT_NAME}
"wbemuuid.lib"
"bcrypt.lib"
"crypt32.lib"
"iphlpapi.lib"
"kernel32.lib"
"ntdll.lib"
"ws2_32.lib"
"setupapi.lib"
)
elseif(UNIX AND NOT APPLE OR ANDROID)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/addon/linux")
file(GLOB SOURCE_FILES ${SOURCE_FILES}
"${CMAKE_CURRENT_SOURCE_DIR}/addon/linux/wireguard.c"
"${CMAKE_CURRENT_SOURCE_DIR}/addon/linux/wginterface.cpp"
)
else()
message(STATUS "Buiding go Userspace")
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/addon/userspace/wg-go.o)
file(REMOVE_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/addon/userspace/wg-go.o)
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/addon/userspace/wg-go.h)
file(REMOVE_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/addon/userspace/wg-go.h)
endif()
set(ENV{CGO_ENABLED} 1)
set(ENV{LDFLAGS} -w)
# Remove CXX and CC envs to CGO
set(ENV{DCXX} ENV{CXX})
set(ENV{DCC} ENV{CC})
set(ENV{CXX})
set(ENV{CC})
execute_process(
COMMAND go build -trimpath -v -o ../wg-go.o -buildmode c-archive .
# COMMAND env
RESULT_VARIABLE GOCODE
OUTPUT_VARIABLE GOBUILDLOG
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/addon/userspace/go
)
set(ENV{CXX} ENV{DCXX})
set(ENV{CC} ENV{DCC})
if(NOT GOCODE EQUAL "0")
message(FATAL_ERROR "cannot build go userspace code exit ${GOCODE}\n${GOBUILDLOG}")
endif()
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/addon/userspace")
set(USERSPACEOBJ ${CMAKE_CURRENT_SOURCE_DIR}/addon/userspace/wg-go.o)
file(GLOB SOURCE_FILES ${SOURCE_FILES} "${CMAKE_CURRENT_SOURCE_DIR}/addon/userspace/wginterface.cpp")
endif()
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC})
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
target_link_libraries(${PROJECT_NAME} ${USERSPACEOBJ} ${CMAKE_JS_LIB})
if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)
# Generate node.lib
execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS})
endif()

View File

@@ -1,347 +0,0 @@
#include "wgkeys.hh"
#include <cstdio>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <random>
#include <sstream>
#include <string.h>
#ifdef __linux__
#include <sys/socket.h>
#include <unistd.h>
#elif _WIN32 || defined(__CYGWIN__)
#include <windows.h>
#endif
static void encode_base64(char dest[4], const uint8_t src[3]) {
const uint8_t input[] = {
static_cast<uint8_t>((src[0] >> 2) & 63),
static_cast<uint8_t>(((src[0] << 4) | (src[1] >> 4)) & 63),
static_cast<uint8_t>(((src[1] << 2) | (src[2] >> 6)) & 63),
static_cast<uint8_t>(src[2] & 63)};
unsigned int i;
for (i = 0; i < 4; ++i)
dest[i] = input[i] + 'A' + (((25 - input[i]) >> 8) & 6) -
(((51 - input[i]) >> 8) & 75) - (((61 - input[i]) >> 8) & 15) +
(((62 - input[i]) >> 8) & 3);
}
void keyToBase64(wg_key_b64_string base64, const wg_key key) {
unsigned int i;
for (i = 0; i < 32 / 3; ++i)
encode_base64(&base64[i * 4], &key[i * 3]);
const uint8_t tempKey[3] = {key[i * 3 + 0], key[i * 3 + 1], 0};
encode_base64(&base64[i * 4], tempKey);
base64[sizeof(wg_key_b64_string) - 2] = '=';
base64[sizeof(wg_key_b64_string) - 1] = '\0';
}
static int decodeBase64(const char src[4]) {
int val = 0;
unsigned int i;
for (i = 0; i < 4; ++i)
val |=
(-1 +
((((('A' - 1) - src[i]) & (src[i] - ('Z' + 1))) >> 8) &
(src[i] - 64)) +
((((('a' - 1) - src[i]) & (src[i] - ('z' + 1))) >> 8) &
(src[i] - 70)) +
((((('0' - 1) - src[i]) & (src[i] - ('9' + 1))) >> 8) & (src[i] + 5)) +
((((('+' - 1) - src[i]) & (src[i] - ('+' + 1))) >> 8) & 63) +
((((('/' - 1) - src[i]) & (src[i] - ('/' + 1))) >> 8) & 64))
<< (18 - 6 * i);
return val;
}
#ifdef _WIN32
static volatile void *(*memset_func)(void *, int, size_t) =
(volatile void *(*)(void *, int, size_t)) & memset;
void memzero_explicit(void *s, size_t count) { memset_func(s, 0, count); }
#else
static __attribute__((noinline)) void memzero_explicit(void *s, size_t count) {
memset(s, 0, count);
__asm__ __volatile__("" : : "r"(s) : "memory");
}
#endif
static void carry(fe o) {
int i;
for (i = 0; i < 16; ++i) {
o[(i + 1) % 16] += (i == 15 ? 38 : 1) * (o[i] >> 16);
o[i] &= 0xffff;
}
}
static void cswap(fe p, fe q, int b) {
int i;
int64_t t, c = ~(b - 1);
for (i = 0; i < 16; ++i) {
t = c & (p[i] ^ q[i]);
p[i] ^= t;
q[i] ^= t;
}
memzero_explicit(&t, sizeof(t));
memzero_explicit(&c, sizeof(c));
memzero_explicit(&b, sizeof(b));
}
static void pack(uint8_t *o, const fe n) {
int i, j, b;
fe m, t;
memcpy(t, n, sizeof(t));
carry(t);
carry(t);
carry(t);
for (j = 0; j < 2; ++j) {
m[0] = t[0] - 0xffed;
for (i = 1; i < 15; ++i) {
m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
m[i - 1] &= 0xffff;
}
m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
b = (m[15] >> 16) & 1;
m[14] &= 0xffff;
cswap(t, m, 1 - b);
}
for (i = 0; i < 16; ++i) {
o[2 * i] = t[i] & 0xff;
o[2 * i + 1] = t[i] >> 8;
}
memzero_explicit(m, sizeof(m));
memzero_explicit(t, sizeof(t));
memzero_explicit(&b, sizeof(b));
}
static void add(fe o, const fe a, const fe b) {
int i;
for (i = 0; i < 16; ++i)
o[i] = a[i] + b[i];
}
static void subtract(fe o, const fe a, const fe b) {
int i;
for (i = 0; i < 16; ++i)
o[i] = a[i] - b[i];
}
static void multmod(fe o, const fe a, const fe b) {
int i, j;
int64_t t[31] = {0};
for (i = 0; i < 16; ++i) {
for (j = 0; j < 16; ++j)
t[i + j] += a[i] * b[j];
}
for (i = 0; i < 15; ++i)
t[i] += 38 * t[i + 16];
memcpy(o, t, sizeof(fe));
carry(o);
carry(o);
memzero_explicit(t, sizeof(t));
}
static void invert(fe o, const fe i) {
fe c;
int a;
memcpy(c, i, sizeof(c));
for (a = 253; a >= 0; --a) {
multmod(c, c, c);
if (a != 2 && a != 4)
multmod(c, c, i);
}
memcpy(o, c, sizeof(fe));
memzero_explicit(c, sizeof(c));
}
void wgKeys::generatePreshared(wg_key preshared_key) {
#if _WIN32 || defined(__CYGWIN__)
HCRYPTPROV hCryptProv;
BOOL winStatus;
if ((winStatus = CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)))
winStatus =
CryptGenRandom(hCryptProv, sizeof(wg_key), (BYTE *)preshared_key);
CryptReleaseContext(hCryptProv, 0);
if (winStatus)
return;
#elif defined(__OpenBSD__) || \
(defined(__APPLE__) && \
MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12) || \
(defined(__GLIBC__) && \
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)))
if (!getentropy(preshared_key, sizeof(wg_key)))
return;
#elif defined(__NR_getrandom) && defined(__linux__)
if (syscall(__NR_getrandom, preshared_key, sizeof(wg_key), 0) ==
sizeof(wg_key))
return;
#elif __linux__ || _ANDROID__ || __termux__
size_t ret, i;
int fd;
fd = open("/dev/urandom", O_RDONLY);
if (fd <= 0);
for (i = 0; i < sizeof(wg_key); i += ret) {
ret = read(fd, preshared_key + i, sizeof(wg_key) - i);
if (ret < 0);
}
close(fd);
return;
#endif
std::random_device rd;
for (uint8_t i = 0; i < sizeof(wg_key); ++i) {
std::mt19937 mt(rd());
std::uniform_int_distribution<int> dist(1, 429496729);
preshared_key[i] = dist(mt) * rand();
}
return;
}
static void clamp_key(uint8_t *z) {
z[31] = (z[31] & 127) | 64;
z[0] &= 248;
}
void wgKeys::generatePrivate(wg_key private_key) {
wgKeys::generatePreshared(private_key);
clamp_key(private_key);
}
void wgKeys::generatePublic(wg_key public_key, const wg_key private_key) {
int i, r;
uint8_t z[32];
fe a = {1}, b = {9}, c = {0}, d = {1}, e, f;
memcpy(z, private_key, sizeof(z));
clamp_key(z);
for (i = 254; i >= 0; --i) {
r = (z[i >> 3] >> (i & 7)) & 1;
cswap(a, b, r);
cswap(c, d, r);
add(e, a, c);
subtract(a, a, c);
add(c, b, d);
subtract(b, b, d);
multmod(d, e, e);
multmod(f, a, a);
multmod(a, c, a);
multmod(c, b, e);
add(e, a, c);
subtract(a, a, c);
multmod(b, a, a);
subtract(c, d, f);
const fe abc = {0xdb41, 1};
multmod(a, c, abc);
add(a, a, d);
multmod(c, c, a);
multmod(a, d, f);
const fe abc2 = {9};
multmod(d, b, abc2);
multmod(b, e, e);
cswap(a, b, r);
cswap(c, d, r);
}
invert(c, c);
multmod(a, a, c);
pack(public_key, a);
memzero_explicit(&r, sizeof(r));
memzero_explicit(z, sizeof(z));
memzero_explicit(a, sizeof(a));
memzero_explicit(b, sizeof(b));
memzero_explicit(c, sizeof(c));
memzero_explicit(d, sizeof(d));
memzero_explicit(e, sizeof(e));
memzero_explicit(f, sizeof(f));
}
std::string wgKeys::generatePublic(const std::string &private_key) {
wg_key public_key;
wg_key private_key_;
stringToKey(private_key_, private_key);
generatePublic(public_key, private_key_);
return toString(public_key);
}
bool key_is_zero(const uint8_t key[32]) {
volatile uint8_t acc = 0;
for (unsigned int i = 0; i < 32; ++i) {
acc |= key[i];
// asm volatile("" : "=r"(acc) : "0"(acc));
}
return !!(1 & ((acc - 1) >> 8));
}
void wgKeys::stringToKey(wg_key key, std::string keyBase64) {
const char* base64 = keyBase64.c_str();
if (keyBase64.length() != B64_WG_KEY_LENGTH ||
base64[B64_WG_KEY_LENGTH - 1] != '=')
throw std::string("invalid key, length: ")
.append(std::to_string(keyBase64.length()));
unsigned int i;
int val;
volatile uint8_t ret = 0;
for (i = 0; i < 32 / 3; ++i) {
val = decodeBase64(&base64[i * 4]);
ret |= (uint32_t)val >> 31;
key[i * 3 + 0] = (val >> 16) & 0xff;
key[i * 3 + 1] = (val >> 8) & 0xff;
key[i * 3 + 2] = val & 0xff;
}
const char tempDecode[4] = {base64[i * 4 + 0], base64[i * 4 + 1],
base64[i * 4 + 2], 'A'};
val = decodeBase64(tempDecode);
ret |= ((uint32_t)val >> 31) | (val & 0xff);
key[i * 3 + 0] = (val >> 16) & 0xff;
key[i * 3 + 1] = (val >> 8) & 0xff;
int status = EINVAL & ~((ret - 1) >> 8);
if (status != 0)
throw std::string("Cannot decode key, ret code: ")
.append(std::to_string(status));
}
std::string wgKeys::toString(const wg_key key) {
wg_key_b64_string base64;
unsigned int i;
for (i = 0; i < 32 / 3; ++i) encode_base64(&base64[i * 4], &key[i * 3]);
const uint8_t tempKey[3] = {key[i * 3 + 0], key[i * 3 + 1], 0};
encode_base64(&base64[i * 4], tempKey);
base64[sizeof(wg_key_b64_string) - 2] = '=';
base64[sizeof(wg_key_b64_string) - 1] = '\0';
return std::string(base64);
}
std::string wgKeys::toHex(const std::string &keyBase64) {
wg_key key;
wgKeys::stringToKey(key, keyBase64);
char hex[65];
// for (int i = 0; i < 32; ++i) sprintf(hex + i * 2, "%02x", key[i]);
for (int i = 0; i < 32; ++i) snprintf(hex + i * 2, 3, "%02x", key[i]);
hex[64] = '\0';
return std::string(hex);
}
std::string wgKeys::HextoBase64(const std::string &s_hex) {
wg_key key;
for(unsigned i = 0, uchr; i < s_hex.length(); i += 2) {
sscanf(s_hex.c_str() + i, "%2x", &uchr); // conversion
key[i/2] = uchr; // save as char
}
return wgKeys::toString(key);
}

View File

@@ -1,37 +0,0 @@
#ifndef _WGKEY_
#define _WGKEY_
#include <string>
const int WG_KEY_LENGTH = 32, B64_WG_KEY_LENGTH = ((WG_KEY_LENGTH + 2) / 3) * 4;
const int wgKeyLength = 32, Base64WgKeyLength = ((wgKeyLength + 2) / 3) * 4, HexWgKeyLength = wgKeyLength * 2;
typedef unsigned char wg_key[wgKeyLength];
typedef char wg_key_b64_string[Base64WgKeyLength + 1];
typedef long long fe[16];
namespace wgKeys {
// Convert wg_key to std::string in base64
std::string toString(const wg_key key);
// Convert base64 to hex key
std::string toHex(const std::string &keyBase64);
// Convert hex to base64
std::string HextoBase64(const std::string &keyHex);
// Convert base64 to wg_key
void stringToKey(wg_key key, std::string keyBase64);
// Generate preshared key
void generatePreshared(wg_key key);
// Generate private key
void generatePrivate(wg_key private_key);
// Get public key from private key
void generatePublic(wg_key public_key, const wg_key private_key);
std::string generatePublic(const std::string &private_key);
}
#endif

View File

@@ -1,437 +0,0 @@
#include "wginterface.hh"
#include "genKey/wgkeys.hh"
extern "C" {
#include "wireguard.h"
}
#include <string>
#include <ifaddrs.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
#include <cstring>
#include <stdlib.h>
#include <stdio.h>
#include <asm/types.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <string.h>
#include <iostream>
#include <sys/ioctl.h>
#include <net/if.h>
#include <filesystem>
#include <fstream>
std::string getWireguardVersion() {
#ifdef WIREGUARD_VERSION
return std::string(WIREGUARD_VERSION);
#endif
std::string version = "Unknown";
// /sys/module/wireguard/version - for kernel module
if (std::filesystem::exists("/sys/module/wireguard/version")) {
std::ifstream file("/sys/module/wireguard/version");
file >> version;
file.close();
}
return version;
}
std::string driveLoad(std::map<std::string, std::string> load) {}
void WireguardDevices::getInterfaces() {
size_t len; char *device_name, *devicesList = wg_list_device_names();
if (!devicesList) throw std::string("Unable to get device names");
// Clear list
this->clear();
// Set new devices
for (device_name = devicesList, len = 0; (len = strlen(device_name)); device_name += len + 1) this->push_back(std::string(device_name));
// Free memory
free(devicesList);
}
void WireguardDevices::deleteInterface(std::string wgName) {
// Check if exist, if not skip
if (this->exist(wgName)) {
int status = wg_del_device(wgName.c_str());
if (status < 0) throw std::string("Cannot delete interface, code: ").append(std::to_string(status));
}
}
std::string HostAdresses(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 std::string(buf);
};
void WireguardConfig::getWireguardConfig() {
if (this->name.length() == 0) throw std::string("Set wireguard name!");
else if (this->name.length() > IFNAMSIZ) throw std::string("Wireguard interface name is long, max name length is ").append(std::to_string(IFNAMSIZ));
else if (!(WireguardDevices().exist(this->name))) throw std::string("Wireguard interface not exist");
int status; wg_device *devConfig; wg_peer *peer;
if ((status = wg_get_device(&devConfig, this->name.c_str())) < 0) throw std::string("It was not possible to get the Wireguard interface settings, code: ").append(std::to_string(status));
if (devConfig->flags & WGDEVICE_HAS_PRIVATE_KEY) this->privateKey = wgKeys::toString(devConfig->private_key);
if (devConfig->flags & WGDEVICE_HAS_PUBLIC_KEY) this->publicKey = wgKeys::toString(devConfig->public_key);
if (!!devConfig->listen_port && devConfig->listen_port > 0) this->portListen = devConfig->listen_port;
this->interfaceAddress.GetInInterface(this->name);
for ((peer) = (devConfig)->first_peer; (peer); (peer) = (peer)->next_peer) {
auto PeerConfig = Peer();
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) PeerConfig.presharedKey = wgKeys::toString(peer->preshared_key);
if (peer->endpoint.addr.sa_family == AF_INET||peer->endpoint.addr.sa_family == AF_INET6) PeerConfig.endpoint = HostAdresses(true, &peer->endpoint.addr);
PeerConfig.keepInterval = peer->persistent_keepalive_interval;
PeerConfig.lastHandshake = peer->last_handshake_time.tv_sec*1000;
PeerConfig.rxBytes = peer->rx_bytes;
PeerConfig.txBytes = peer->tx_bytes;
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);
PeerConfig.allowedIPs.push_back(std::string(buf).append("/").append(std::to_string(allowedip->cidr)));
}
this->Peers[wgKeys::toString(peer->public_key)] = PeerConfig;
}
}
void WireguardConfig::setWireguardConfig() {
int status;
if (this->name.length() > IFNAMSIZ) throw std::string("Wireguard interface name is long, max name length is ").append(std::to_string(IFNAMSIZ));
else if (!(WireguardDevices().exist(this->name)) && (status = wg_add_device(this->name.c_str())) < 0) throw std::string("Unable to create Wireguard interface, code: ").append(std::to_string(status));
if (this->privateKey.length() != Base64WgKeyLength) throw std::string("Set Wireguard interface private key!");
auto wgConfig = new wg_device({});
if (!wgConfig) throw std::string("Cannot alloc memory to set interface configuration!");
strncpy(wgConfig->name, this->name.c_str(), this->name.length());
wgConfig->flags = wg_device_flags::WGDEVICE_HAS_PRIVATE_KEY;
wgKeys::stringToKey(wgConfig->private_key, this->privateKey);
if (this->replacePeers) wgConfig->flags = (wg_device_flags)(wgConfig->flags|wg_device_flags::WGDEVICE_REPLACE_PEERS);
if (this->publicKey.length() == Base64WgKeyLength) {
wgConfig->flags = (wg_device_flags)(wgConfig->flags|wg_device_flags::WGDEVICE_HAS_PUBLIC_KEY);
wgKeys::stringToKey(wgConfig->public_key, this->publicKey);
}
if (this->portListen >= 0) {
wgConfig->flags = (wg_device_flags)(wgConfig->flags|wg_device_flags::WGDEVICE_HAS_LISTEN_PORT);
wgConfig->listen_port = this->portListen;
}
if (this->fwmark >= 0) {
wgConfig->flags = (wg_device_flags)(wgConfig->flags|wg_device_flags::WGDEVICE_HAS_FWMARK);
wgConfig->fwmark = this->fwmark;
}
for (auto &PeerConfig : this->Peers) {
auto peer = new wg_peer({});
peer->flags = wg_peer_flags::WGPEER_HAS_PUBLIC_KEY;
wgKeys::stringToKey(peer->public_key, PeerConfig.first);
if (PeerConfig.second.removeMe) peer->flags = (wg_peer_flags)(peer->flags|wg_peer_flags::WGPEER_REMOVE_ME);
else {
if (PeerConfig.second.presharedKey.length() == Base64WgKeyLength) {
peer->flags = (wg_peer_flags)(peer->flags|wg_peer_flags::WGPEER_HAS_PRESHARED_KEY);
wgKeys::stringToKey(peer->preshared_key, PeerConfig.second.presharedKey);
}
if (PeerConfig.second.keepInterval > 0) {
peer->flags = (wg_peer_flags)(peer->flags|wg_peer_flags::WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL);
peer->persistent_keepalive_interval = PeerConfig.second.keepInterval;
}
if (PeerConfig.second.endpoint.length() > 0) {
sockaddr endpoint; int ret, retries;
char *begin, *end, *Endpoint = strdup(PeerConfig.second.endpoint.c_str());
if (Endpoint[0] == '[') {
begin = &Endpoint[1];
end = strchr(Endpoint, ']');
if (!end) {
for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; }
delete wgConfig;
free(Endpoint);
throw std::string("Unable to find matching brace of endpoint");
return;
}
*end++ = '\0';
if (*end++ != ':' || !*end) {
for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; }
delete wgConfig;
free(Endpoint);
throw std::string("Unable to find port of endpoint");
return;
}
} else {
begin = Endpoint;
end = strrchr(Endpoint, ':');
if (!end || !*(end + 1)) {
for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; }
delete wgConfig;
free(Endpoint);
throw std::string("Unable to find port of endpoint");
}
*end++ = '\0';
}
addrinfo *resolved, hints = { ai_family: AF_UNSPEC, ai_socktype: SOCK_DGRAM, ai_protocol: IPPROTO_UDP };
for (unsigned int timeout = 1000000;; timeout = ((20000000) < (timeout * 6 / 5) ? (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--)) {
for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; }
delete wgConfig;
free(Endpoint);
fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), PeerConfig.second.endpoint.c_str());
throw std::string("Unable to resolve endpoint");
return;
}
fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), PeerConfig.second.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(&peer->endpoint.addr, &endpoint, 0, sizeof(peer->endpoint.addr));
if (resolved->ai_family == AF_INET) {
peer->endpoint.addr4.sin_addr.s_addr = ((sockaddr_in *)&endpoint)->sin_addr.s_addr;
peer->endpoint.addr4.sin_port = ((sockaddr_in *)&endpoint)->sin_port;
peer->endpoint.addr4.sin_family = AF_INET;
} else {
peer->endpoint.addr6.sin6_addr = ((struct sockaddr_in6 *)&endpoint)->sin6_addr;
peer->endpoint.addr6.sin6_port = ((struct sockaddr_in6 *)&endpoint)->sin6_port;
peer->endpoint.addr6.sin6_family = AF_INET6;
}
} else {
freeaddrinfo(resolved);
for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; }
delete wgConfig;
free(Endpoint);
throw std::string("Neither IPv4 nor IPv6 address found");
}
freeaddrinfo(resolved);
// Free memory
for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; }
delete wgConfig;
free(Endpoint);
}
for (const auto Ip : PeerConfig.second.allowedIPs.getIpParsed()) {
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS) peer->flags = (wg_peer_flags)(peer->flags|WGPEER_REPLACE_ALLOWEDIPS);
auto newAllowedIP = new wg_allowedip({});
newAllowedIP->cidr = Ip.Mask;
if (Ip.Proto == 6 && inet_pton(AF_INET6, Ip.Address.c_str(), &newAllowedIP->ip6) == 1) newAllowedIP->family = AF_INET6;
else if (Ip.Proto == 4 && inet_pton(AF_INET, Ip.Address.c_str(), &newAllowedIP->ip4) == 1) newAllowedIP->family = AF_INET;
else {
delete newAllowedIP;
continue;
}
if (peer->first_allowedip) newAllowedIP->next_allowedip = peer->first_allowedip;
peer->first_allowedip = newAllowedIP;
}
}
if (wgConfig->first_peer) peer->next_peer = wgConfig->first_peer;
wgConfig->first_peer = peer;
}
// Set config
status = wg_set_device(wgConfig);
// Free memory
for (wg_peer* peer = wgConfig->first_peer; peer; peer = peer->next_peer) {
for (wg_allowedip *newAllowedIP = peer->first_allowedip; newAllowedIP; newAllowedIP = newAllowedIP->next_allowedip) delete newAllowedIP;
delete peer;
}
delete wgConfig;
// Return status to tool
if (status < 0) throw std::string("Unable to configure settings, code: ").append(std::to_string(status));
else {
this->interfaceAddress.SetInInterface(this->name);
}
}
void IpManeger::GetInInterface(std::string interfaceName) {
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, interfaceName.c_str()) != 0) continue;
else if (ptr_entry->ifa_addr->sa_family == AF_INET) this->addIPMask(HostAdresses(false, ptr_entry->ifa_addr));
else if (ptr_entry->ifa_addr->sa_family == AF_INET6) this->addIPMask(HostAdresses(false, ptr_entry->ifa_addr));
}
freeifaddrs(ptr_ifaddrs);
}
}
struct rtnl_handle {
int fd;
struct sockaddr_nl local;
struct sockaddr_nl peer;
__u32 seq;
__u32 dump;
};
typedef struct {
__u8 family;
__u8 bytelen;
__s16 bitlen;
__u32 flags;
__u32 data[8];
} inet_prefix;
// This function is to open the netlink socket as the name suggests.
void netlink_open(struct rtnl_handle* rth) {
int addr_len;
memset(rth, 0, sizeof(rth));
// Creating the netlink socket of family NETLINK_ROUTE
rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (rth->fd < 0) throw std::string("cannot open netlink socket");
memset(&rth->local, 0, sizeof(rth->local));
rth->local.nl_family = AF_NETLINK;
rth->local.nl_groups = 0;
// Binding the netlink socket
if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) throw std::string("cannot bind netlink socket");
addr_len = sizeof(rth->local);
if (getsockname(rth->fd, (struct sockaddr*)&rth->local, (socklen_t*) &addr_len) < 0) throw std::string("cannot getsockname");
if (addr_len != sizeof(rth->local)) throw std::string("wrong address lenght").append(std::to_string(addr_len));
if (rth->local.nl_family != AF_NETLINK) throw std::string("wrong address family").append(std::to_string(rth->local.nl_family));
rth->seq = time(NULL);
}
// This function does the actual reading and writing to the netlink socket
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, unsigned groups, struct nlmsghdr *answer) {
int status;
struct nlmsghdr *h;
struct sockaddr_nl nladdr;
// Forming the iovector with the netlink packet.
struct iovec iov = { (void*)n, n->nlmsg_len };
char buf[8192];
// Forming the message to be sent.
struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 };
// Filling up the details of the netlink socket to be contacted in the
// kernel.
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = peer;
nladdr.nl_groups = groups;
n->nlmsg_seq = ++rtnl->seq;
if (answer == NULL) n->nlmsg_flags |= NLM_F_ACK;
// Actual sending of the message, status contains success/failure
return sendmsg(rtnl->fd, &msg, 0);
// if (status < 0) return -1;
}
// This is the utility function for adding the parameters to the packet.
int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) {
int len = RTA_LENGTH(alen);
struct rtattr *rta;
if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
return -1;
rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
rta->rta_type = type;
rta->rta_len = len;
memcpy(RTA_DATA(rta), data, alen);
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
return 0;
}
void IpManeger::SetInInterface(std::string interfaceName) {
if (this->size() == 0) return;
if (!(WireguardDevices().exist(interfaceName))) throw std::string("Wireguard interface not exists!");
int status;
unsigned int ifa_index;
wg_device *devConfig;
if ((status = wg_get_device(&devConfig, interfaceName.c_str())) < 0) throw std::string("It was not possible to get the Wireguard interface settings, code: ").append(std::to_string(status));
ifa_index = devConfig->ifindex;
free(devConfig);
for (const auto ip : this->getIpParsed()) {
struct rtnl_handle * rth;
rth = (rtnl_handle*)malloc(sizeof(rtnl_handle));
netlink_open(rth);
int err;
inet_prefix lcl;
// structure of the netlink packet.
struct {
struct nlmsghdr n;
struct ifaddrmsg ifa;
char buf[1024];
} req;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_type = RTM_NEWADDR;
req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST;
req.ifa.ifa_family = ip.Proto == 4 ? AF_INET : AF_INET6;
req.ifa.ifa_prefixlen = ip.Mask;
req.ifa.ifa_index = ifa_index ; // get the loopback index
req.ifa.ifa_scope = 0;
memset(&lcl, 0, sizeof(lcl));
lcl.family = req.ifa.ifa_family;
lcl.bytelen = (req.ifa.ifa_family == AF_INET) ? 4 : 16;
lcl.bitlen = (req.ifa.ifa_family == AF_INET) ? 32 : 128;
if (inet_pton(req.ifa.ifa_family, ip.Address.c_str(), &lcl.data) <= 0) throw std::string("Invalid IP address: ").append(ip.Address);
if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = lcl.family;
addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
if ((err = rtnl_talk(rth, &req.n, 0, 0, NULL)) < 0) throw std::string("Cannot set interface IP, code: ").append(std::to_string(err));
}
// Get INET socket
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) throw std::string("Error creating socket to set interface flags");
struct ifreq ifr;
strcpy(ifr.ifr_name, interfaceName.c_str());
// Set interface flags
ifr.ifr_flags = IFF_POINTOPOINT | IFF_NOARP | IFF_UP | IFF_RUNNING;
if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
close(sockfd);
throw std::string("Error setting interface flags");
}
close(sockfd);
}

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -1,71 +0,0 @@
#include "wg.hh"
#include <napi.h>
Napi::Object StartAddon(const Napi::Env env, const Napi::Object exports) {
std::map<std::string, std::string> LoadConfig;
const Napi::Array keysOnLoadsNames = exports.GetPropertyNames();
for (unsigned int keyIndex = 0; keyIndex < keysOnLoadsNames.Length(); keyIndex++) {
if (!(exports.Get(keysOnLoadsNames[keyIndex]).IsString())) continue;
LoadConfig[keysOnLoadsNames[keyIndex].ToString().Utf8Value()] = exports.Get(keysOnLoadsNames[keyIndex]).ToString().Utf8Value();
}
#ifdef _WIN32
std::string statusLoading = driveLoad(LoadConfig);
if (!!(statusLoading.length())) {
Napi::Error::New(env, statusLoading).ThrowAsJavaScriptException();
return exports;
}
#endif
const Napi::Object Constants = Napi::Object::New(env);
if (getWireguardVersion().length() > 0) Constants.Set("driveVersion", getWireguardVersion());
exports.Set("deleteInterface", Napi::Function::New(env, [](const Napi::CallbackInfo &info) -> Napi::Value {
const Napi::Env env = info.Env();
if (!(info[0].IsString())) {
Napi::Error::New(env, "Set interface name").ThrowAsJavaScriptException();
return env.Undefined();
}
try {
DeleteInterface *worker = new DeleteInterface(env, info[0].ToString());
worker->Queue();
return worker->NodePromise.Promise();
} catch (std::string &err) {
Napi::Error::New(env, err).ThrowAsJavaScriptException();
return env.Undefined();
}
}));
exports.Set("setConfig", Napi::Function::New(env, [](const Napi::CallbackInfo &info) -> Napi::Value {
const Napi::Env env = info.Env();
if (!(info[0].IsObject())) Napi::Error::New(env, "Set wireguard config!").ThrowAsJavaScriptException();
try {
SetConfig *worker = new SetConfig(env, info[0].ToObject());
worker->Queue();
return worker->NodePromise.Promise();
} catch (std::string &err) {
Napi::Error::New(env, err).ThrowAsJavaScriptException();
}
return env.Undefined();
}));
exports.Set("getConfig", Napi::Function::New(env, [](const Napi::CallbackInfo &info) -> Napi::Value {
const Napi::Env env = info.Env();
if (!(info[0].IsString())) {
Napi::Error::New(env, "Set interface name in fist argument!").ThrowAsJavaScriptException();
return env.Undefined();
}
try {
GetConfig *worker = new GetConfig(env, info[0].ToString());
worker->Queue();
return worker->NodePromise.Promise();
} catch (std::string &err) {
Napi::Error::New(env, err).ThrowAsJavaScriptException();
return env.Undefined();
}
}));
exports.Set("constants", Constants);
return exports;
}
NODE_API_MODULE(addon, StartAddon);

View File

@@ -1,14 +0,0 @@
module sirherobrine23.org/Wireguard/wireguard-tools.js/wg-tun
go 1.23.0
toolchain go1.24.1
require golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
require (
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
)

View File

@@ -1,36 +0,0 @@
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ=
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY=

View File

@@ -1,106 +0,0 @@
package main
import "C"
import (
"fmt"
"runtime/debug"
"strings"
"golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
)
func main() {}
func getCharErr(err error) *C.char {
if err == nil {
return C.CString("")
}
return C.CString(err.Error())
}
// Get wireguard-go version
//
//export wgVersion
func wgVersion() *C.char {
info, ok := debug.ReadBuildInfo()
if !ok {
return C.CString("unknown")
}
for _, dep := range info.Deps {
if dep.Path == "golang.zx2c4.com/wireguard" {
return C.CString(dep.Version)
}
}
return C.CString("unknown")
}
// End process function callbacks
var Tuns = make(map[string]tun.Device)
var Devices = make(map[string]*device.Device)
// List wireguard-go UAPI's sockets
// first\0second\0third\0forth\0last\0\0
//
//export listInternalTuns
func listInternalTuns() *C.char {
var uapis []string
for tun := range Tuns {
uapis = append(uapis, tun)
}
return C.CString(strings.Join(uapis, "\x00") + "\x00")
}
// Delete interface
//
//export stopWg
func stopWg(wgName *C.char) (bool, *C.char) {
tunName := C.GoString(wgName)
if dev, ok := Devices[tunName]; ok {
dev.Close()
delete(Devices, tunName)
if tun, ok := Tuns[tunName]; ok {
if err := tun.Close(); err != nil {
return false, getCharErr(err)
}
delete(Tuns, tunName)
}
return true, nil
}
return false, nil
}
// Set config in tun, if not exist create and add to Tuns
//
//export setWg
func setWg(levelLog int, wgName, wgConfig *C.char) *C.char {
tunName, configString := C.GoString(wgName), C.GoString(wgConfig)
_, okTuns := Tuns[tunName]
_, okDev := Devices[tunName]
if !(okTuns || okDev) {
logger := device.NewLogger(levelLog, fmt.Sprintf("(%s) ", tunName))
// open TUN device (or use supplied fd)
tdev, err := tun.CreateTUN(tunName, device.DefaultMTU)
Tuns[tunName] = tdev
if err != nil {
return getCharErr(err)
}
Devices[tunName] = device.NewDevice(tdev, conn.NewDefaultBind(), logger)
}
dev := Devices[tunName]
return getCharErr(dev.IpcSet(configString))
}
// Get config from Tuns device
//
//export getWg
func getWg(wgName *C.char) (*C.char, *C.char) {
tunName := C.GoString(wgName)
if dev, ok := Devices[tunName]; ok {
config, err := dev.IpcGet()
return C.CString(config), getCharErr(err)
}
return nil, getCharErr(fmt.Errorf("device not exists"))
}

View File

@@ -1,152 +0,0 @@
#include "wginterface.hh"
#include "userspace/wg-go.h"
#include "genKey/wgkeys.hh"
#include <cstring>
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <vector>
#include <arpa/inet.h>
#include <errno.h>
#include <limits.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
void IpManeger::SetInInterface(std::string interfaceName) {}
void IpManeger::GetInInterface(std::string interfaceName) {}
// Ignore if required to windows
std::string driveLoad(std::map<std::string, std::string> load) { return ""; }
std::string getWireguardVersion() {
return std::string("wireguard-go ").append(wgVersion());
}
void WireguardDevices::getInterfaces() {
size_t len; char *device_name, *devicesList = listInternalTuns();
for (device_name = devicesList, len = 0; (len = strlen(device_name)); device_name += len + 1) this->push_back(std::string(device_name));
}
void WireguardDevices::deleteInterface(std::string wgName) {
auto status = stopWg((char*)wgName.c_str());
if (!!status.r1) throw std::string(status.r1);
}
bool char_is_digit(int c) {
return (unsigned int)(('0' - 1 - c) & (c - ('9' + 1))) >> (sizeof(c) * 8 - 1);
}
void WireguardConfig::setWireguardConfig() {
if (this->name.length() == 0) throw std::string("Set wireguard name!");
std::string userspaceConfig;
if (this->privateKey.length() == Base64WgKeyLength) userspaceConfig = userspaceConfig.append("private_key=").append(wgKeys::toHex(this->privateKey)).append("\n");
if (this->portListen >= 0) userspaceConfig = userspaceConfig.append("listen_port=").append(std::to_string(this->portListen)).append("\n");
if (this->fwmark >= 0) userspaceConfig = userspaceConfig.append("fwmark=").append(std::to_string(this->fwmark)).append("\n");
if (this->replacePeers) userspaceConfig = userspaceConfig.append("replace_peers=true\n");
for (auto peer : this->Peers) {
userspaceConfig = userspaceConfig.append("public_key=").append(wgKeys::toHex(peer.first)).append("\n");
auto config = peer.second;
if (config.removeMe) {
userspaceConfig = userspaceConfig.append("remove=true\n");
continue;
}
if (config.presharedKey.length() == Base64WgKeyLength) userspaceConfig = userspaceConfig.append("preshared_key=").append(wgKeys::toHex(config.presharedKey)).append("\n");
if (config.keepInterval > 0) userspaceConfig = userspaceConfig.append("persistent_keepalive_interval=").append(std::to_string(config.keepInterval)).append("\n");
if (config.endpoint.length() > 0) userspaceConfig = userspaceConfig.append("endpoint=").append(config.endpoint).append("\n");
if (config.allowedIPs.size() > 0) {
userspaceConfig = userspaceConfig.append("replace_allowed_ips=true\n");
for (auto s : config.allowedIPs.getIpParsed()) userspaceConfig = userspaceConfig.append("allowed_ip=").append(s.Address).append("/").append(std::to_string(s.Mask)).append("\n");
}
}
std::string err = setWg(0, (char*)this->name.c_str(), (char*)userspaceConfig.append("\n").c_str());
if (!err.empty()) throw err;
}
std::vector<std::string> splitLines(const std::string& str) {
std::vector<std::string> result;
std::stringstream ss(str);
std::string line;
// Loop until the end of the string
while (std::getline(ss, line)) {
if (!line.empty()) {
result.push_back(line);
}
}
return result;
}
void WireguardConfig::getWireguardConfig() {
auto status = getWg((char*)this->name.c_str());
if (strlen(status.r1) > 0) throw std::string(status.r1, strlen(status.r1));
std::string wgConfig(status.r0, strlen(status.r0));
std::string pubKey;
int ret = 0;
for (auto line : splitLines(wgConfig)) {
std::string key(line.substr(0, line.find("="))), value(line.substr(line.find("=")+1));
if (key == "private_key") {
this->privateKey = wgKeys::HextoBase64(value);
} else if (key == "listen_port") {
this->portListen = (unsigned short)std::strtoul(value.c_str(), NULL, 0);
} else if (key == "public_key") {
// Insert to peer key
pubKey = wgKeys::HextoBase64(value);
this->Peers[pubKey] = Peer{};
} else if (key == "preshared_key" && pubKey.length() > 0) {
this->Peers[pubKey].presharedKey = wgKeys::HextoBase64(value);
} else if (key == "allowed_ip" && pubKey.length() > 0) {
this->Peers[pubKey].allowedIPs.push_back(value);
} else if (key == "persistent_keepalive_interval" && pubKey.length() > 0) {
this->Peers[pubKey].keepInterval = std::stoi(value);
} else if (key == "last_handshake_time_sec" && pubKey.length() > 0) {
} else if (key == "last_handshake_time_nsec" && pubKey.length() > 0) {
this->Peers[pubKey].lastHandshake = ({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = std::strtoull(value.c_str(), &end, 10); if (*end || num > 0x7fffffffffffffffULL) break; num; });
} else if (key == "rx_bytes" && pubKey.length() > 0) {
this->Peers[pubKey].rxBytes = std::stoull(value);
} else if (key == "tx_bytes" && pubKey.length() > 0) {
this->Peers[pubKey].txBytes = std::stoull(value);
} else if (key == "endpoint" && pubKey.length() > 0) {
char *cvalue = strdup(value.c_str());
char *begin, *end;
struct addrinfo *resolved;
struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM, .ai_protocol = IPPROTO_UDP };
if (!value.length()) break;
if (value[0] == '[') {
begin = &value[1];
end = strchr(cvalue, ']');
if (!end) break;
*end++ = '\0';
if (*end++ != ':' || !*end) break;
} else {
begin = cvalue;
end = strrchr(cvalue, ':');
if (!end || !*(end + 1)) break;
*end++ = '\0';
}
if (getaddrinfo(begin, end, &hints, &resolved) != 0) {
ret = ENETUNREACH;
throw std::string("Failed to resolve endpoint");
}
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) || (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6))) this->Peers[pubKey].endpoint = value;
else {
freeaddrinfo(resolved);
break;
}
freeaddrinfo(resolved);
} else if (key == "errno") {
ret = -({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = std::strtoull(value.c_str(), &end, 10); if (*end || num > 0x7fffffffU) break; num; });
break;
} else if (key == "protocol_version") {
}
}
if (ret < 0) throw std::string("Failed to get wireguard config");
}

View File

@@ -1,155 +0,0 @@
#ifndef __WG_NODE__
#define __WG_NODE__
#include "wginterface.hh"
#include <napi.h>
#include <functional>
#include <iostream>
class Promised : public Napi::AsyncWorker {
public:
Napi::Promise::Deferred NodePromise;
Promised(const Napi::Env &env): AsyncWorker(env), NodePromise{env} {}
void OnError(const Napi::Error& e) override {
Napi::HandleScope scope(Env());
NodePromise.Reject(e.Value());
}
void OnOK() override {
Napi::HandleScope scope(Env());
auto call = [&](Napi::Value data) -> void { NodePromise.Resolve(data); };
runOk(call);
}
virtual void runOk(std::function<void(Napi::Value)> callback) {
Napi::HandleScope scope(Env());
callback(Env().Undefined());
};
};
class DeleteInterface : public Promised {
std::string wgName;
public:
DeleteInterface(const Napi::Env &env, const Napi::String &name): Promised(env), wgName{name.Utf8Value()} {}
void Execute() override {
WireguardDevices wgDevs = WireguardDevices();
try {
wgDevs.deleteInterface(wgName);
} catch (std::string &err) { SetError(err); }
}
};
class SetConfig : public WireguardConfig, public Promised {
public:
void Execute() {
try {
this->setWireguardConfig();
} catch (std::string err) {
SetError(err);
}
}
SetConfig(const Napi::Env &env, const Napi::Object config): Promised(env) {
if (!(config.Has("name"))) throw std::string("Set wireguard interface name!");
if (!(config.Has("privateKey") && config.Get("privateKey").IsString())) throw std::string("Set wireguard private key!");
this->name = config.Get("name").ToString().Utf8Value();
this->privateKey = config.Get("privateKey").ToString().Utf8Value();
if (config.Has("publicKey") && config.Get("publicKey").IsString() && config.Get("publicKey").ToString().Utf8Value().length() == Base64WgKeyLength) this->publicKey = config.Get("publicKey").ToString().Utf8Value();
if (config.Has("portListen") && config.Get("portListen").IsNumber() && config.Get("portListen").ToNumber().Int32Value() >= 0) this->portListen = config.Get("portListen").ToNumber().Int32Value();
if (config.Has("fwmark") && config.Get("fwmark").IsNumber() && config.Get("fwmark").ToNumber().Int32Value() >= 0) this->fwmark = config.Get("fwmark").ToNumber().Int32Value();
if (config.Has("replacePeers") && config.Get("replacePeers").IsBoolean()) this->replacePeers = config.Get("replacePeers").ToBoolean().Value();
if (config.Has("address") && config.Get("address").IsArray() && config.Get("address").As<Napi::Array>().Length() > 0) {
const Napi::Array Addrs(config.Get("address").As<Napi::Array>());
for (unsigned int AddrIndex = 0; AddrIndex < Addrs.Length(); AddrIndex++) {
if (!(Addrs[AddrIndex].IsString())) continue;
this->interfaceAddress.addIPMask(Addrs[AddrIndex].ToString().Utf8Value());
}
}
if (config.Has("peers") && config.Get("peers").IsObject()) {
const Napi::Object PeersObject(config.Get("peers").ToObject());
const Napi::Array PeersKeys(PeersObject.GetPropertyNames());
for (unsigned int peerIndex = 0; peerIndex < PeersKeys.Length(); peerIndex++) {
if (!(PeersObject.Get(PeersKeys[peerIndex].ToString()).IsObject())) continue;
const std::string publicKey(PeersKeys[peerIndex].ToString().Utf8Value());
const Napi::Object peerConfig(PeersObject.Get(publicKey).ToObject());
Peer peer;
if (peerConfig.Has("removeMe") && peerConfig.Get("removeMe").IsBoolean() && peerConfig.Get("removeMe").As<Napi::Boolean>().Value()) peer.removeMe = true;
else {
if (peerConfig.Has("presharedKey") && peerConfig.Get("presharedKey").IsString() && peerConfig.Get("presharedKey").ToString().Utf8Value().length() == Base64WgKeyLength) peer.presharedKey = peerConfig.Get("presharedKey").ToString().Utf8Value();
if (peerConfig.Has("keepInterval") && peerConfig.Get("keepInterval").IsNumber() && peerConfig.Get("keepInterval").ToNumber().Int32Value() > 0) peer.keepInterval = peerConfig.Get("keepInterval").ToNumber().Int32Value();
if (peerConfig.Has("endpoint") && peerConfig.Get("endpoint").IsString() && peerConfig.Get("endpoint").ToString().Utf8Value().length() == Base64WgKeyLength) peer.endpoint = peerConfig.Get("endpoint").ToString().Utf8Value();
if (peerConfig.Has("allowedIPs") && peerConfig.Get("allowedIPs").IsArray()) {
const Napi::Array ips = peerConfig.Get("allowedIPs").As<Napi::Array>();
for (unsigned int ipIndex = 0; ipIndex < ips.Length(); ipIndex++) peer.allowedIPs.addIPMask(ips[ipIndex].ToString().Utf8Value());
}
}
// Set peer in map
this->Peers[publicKey] = peer;
}
}
}
};
class GetConfig : public WireguardConfig, public Promised {
public:
GetConfig(const Napi::Env &env, const Napi::String name): Promised(env) {
this->name = name.Utf8Value();
}
void Execute() {
try {
this->getWireguardConfig();
} catch (std::string err) {
SetError(err);
}
}
void runOk(std::function<void(Napi::Value)> callback) {
Napi::HandleScope scope(Env());
const Napi::Env env = Env();
const Napi::Object config = Napi::Object::New(env);
config.Set("name", this->name);
config.Set("privateKey", this->privateKey);
if (this->publicKey.length() == Base64WgKeyLength) config.Set("publicKey", this->publicKey);
if (this->portListen > 0) config.Set("portListen", this->portListen);
if (this->fwmark > 0) config.Set("fwmark", this->fwmark);
// Interface IPs
const Napi::Array ips = Napi::Array::New(env);
for (auto ip : this->interfaceAddress) ips.Set(ips.Length(), ip);
config.Set("address", ips);
// Peers
const Napi::Object peersObj = Napi::Object::New(env);
for (auto &__peer : this->Peers) {
std::string publicKey = __peer.first;
if (publicKey.length() != Base64WgKeyLength) continue;
const Napi::Object peerConfig = Napi::Object::New(env);
const Peer config = __peer.second;
if (config.presharedKey.length() == Base64WgKeyLength) peerConfig.Set("presharedKey", config.presharedKey);
if (config.keepInterval >= 0) peerConfig.Set("keepInterval", config.keepInterval);
if (config.endpoint.length() > 0) peerConfig.Set("endpoint", config.endpoint);
peerConfig.Set("rxBytes", Napi::BigInt::New(env, (uint64_t)config.rxBytes));
peerConfig.Set("txBytes", Napi::BigInt::New(env, (uint64_t)config.txBytes));
peerConfig.Set("lastHandshake", Napi::Date::New(env, config.lastHandshake));
const Napi::Array ips = Napi::Array::New(env);
for (auto &ip : config.allowedIPs) ips.Set(ips.Length(), ip);
peerConfig.Set("allowedIPs", ips);
peersObj.Set(publicKey, peerConfig);
}
config.Set("peers", peersObj);
// Set data
callback(config);
}
};
#endif

View File

@@ -1,218 +0,0 @@
#ifndef __WIREGUARD_ADDON__
#define __WIREGUARD_ADDON__
#include "genKey/wgkeys.hh"
#include <string>
#include <vector>
#include <map>
extern const int wgKeyLength;
extern const int Base64WgKeyLength;
std::string getWireguardVersion();
std::string driveLoad(std::map<std::string, std::string> load);
class WireguardDevices : public std::vector<std::string> {
public:
~WireguardDevices() { this->clear(); }
/** Get all interfaces from kernel and insert in vector */
void getInterfaces();
/** Delete interface from kernel network */
void deleteInterface(std::string wgName);
/** Check if exists wireguard interface intterface */
bool exist(std::string name) {
this->getInterfaces();
for (auto wgDev = this->begin(); wgDev != this->end(); ++wgDev) {
if (name == *wgDev) return true;
else {
std::string __nDev = std::string(wgDev->substr(wgDev->find_last_of("/")+1));
if (__nDev.find(".sock") != std::string::npos) __nDev = __nDev.substr(0, __nDev.find(".sock"));
if (__nDev == name) return true;
}
}
return false;
}
/** Find sock */
std::string findSock(std::string name) {
this->getInterfaces();
for (auto wgDev = this->begin(); wgDev != this->end(); ++wgDev) {
if (name == *wgDev) return *wgDev;
else if (wgDev->find_last_of(".sock") != std::string::npos) {
std::string __nDev = std::string(wgDev->substr(wgDev->find_last_of("/")+1));
if (__nDev.find(".sock") != std::string::npos) __nDev = __nDev.substr(0, __nDev.find(".sock"));
if (__nDev == name) return *wgDev;
}
}
return std::string("");
}
};
typedef struct {
std::string Address, Subnet;
int Mask, Proto;
} IpReference;
/** Maneger Interface IPs */
class IpManeger : public std::vector<std::string> {
private:
std::string getSubNet4(int Mask) {
switch (Mask) {
case 1: return "128.0.0.0";
case 2: return "192.0.0.0";
case 3: return "224.0.0.0";
case 4: return "240.0.0.0";
case 5: return "248.0.0.0";
case 6: return "252.0.0.0";
case 7: return "254.0.0.0";
case 8: return "255.0.0.0";
case 9: return "255.128.0.0";
case 10: return "255.192.0.0";
case 11: return "255.224.0.0";
case 12: return "255.240.0.0";
case 13: return "255.248.0.0";
case 14: return "255.252.0.0";
case 15: return "255.254.0.0";
case 16: return "255.255.0.0";
case 17: return "255.255.128.0";
case 18: return "255.255.192.0";
case 19: return "255.255.224.0";
case 20: return "255.255.240.0";
case 21: return "255.255.248.0";
case 22: return "255.255.252.0";
case 23: return "255.255.254.0";
case 24: return "255.255.255.0";
case 25: return "255.255.255.128";
case 26: return "255.255.255.192";
case 27: return "255.255.255.224";
case 28: return "255.255.255.240";
case 29: return "255.255.255.248";
case 30: return "255.255.255.252";
case 31: return "255.255.255.254";
default:
case 32: return "255.255.255.255";
}
}
public:
void SetInInterface(std::string interfaceName);
void GetInInterface(std::string interfaceName);
void addIPMask(std::string ip) {
IpReference xTop;
auto maskStart = ip.find("/");
auto isIPv6 = ip.find(":") != std::string::npos;
if (isIPv6) xTop.Mask = 128;
else xTop.Mask = 32;
if (maskStart == std::string::npos) xTop.Address = ip;
else {
xTop.Address = ip.substr(0, maskStart);
xTop.Mask = std::stoi(ip.substr(maskStart+1).c_str());
if (!isIPv6 && xTop.Mask > 32) throw std::string("Set valid mask to ipv4 address!");
}
xTop.Proto = isIPv6 ? 6 : 4;
if (!isIPv6) xTop.Subnet = this->getSubNet4(xTop.Mask);
this->push_back(xTop.Address.append("/").append(std::to_string(xTop.Mask)));
}
std::vector<IpReference> getIpParsed() {
std::vector<IpReference> xTops;
for (auto ipAddrr = this->begin(); ipAddrr != this->end(); ++ipAddrr) {
IpReference nTop;
auto maskStart = ipAddrr->find("/");
nTop.Address = ipAddrr->substr(0, maskStart);
nTop.Mask = std::stoi(ipAddrr->substr(maskStart+1).c_str());
nTop.Proto = (nTop.Address.find(":") != std::string::npos) ? 6 : 4;
if (nTop.Proto == 6) nTop.Subnet = this->getSubNet4(nTop.Mask);
xTops.push_back(nTop);
}
return xTops;
}
};
/**
* peer class
*/
class Peer {
public:
Peer() {
this->removeMe = false;
this->keepInterval = 0;
this->rxBytes = 0;
this->txBytes = 0;
this->lastHandshake = 0;
}
/** 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;
/** 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;
/** Last peer handshake in milisseconds */
unsigned long long lastHandshake;
/** Peer data received (RX) and transferred (TX) */
unsigned long long rxBytes, txBytes;
/** Peer ips allowed to recive data */
IpManeger allowedIPs;
};
/**
* Set and Get Wireguard configs
*/
class WireguardConfig {
public:
WireguardConfig() {
this->portListen = 0;
this->fwmark = 0;
this->replacePeers = false;
}
/** Wireguard interface name */
std::string name;
/** Wireguard interface private key */
std::string privateKey;
/** Wireguard interface public key */
std::string publicKey;
/** Wireguard port listening or listened */
unsigned short portListen;
/** FirewallMark specifies a device's firewall mark else set to 0, the firewall mark will be cleared */
unsigned int fwmark;
/** Replace Wireguard peers if wireguard interface exists */
bool replacePeers;
/** Wireguard interface IPs */
IpManeger interfaceAddress;
/** Wireguard peers */
std::map<std::string, Peer> Peers;
/** Set wireguard config in interface */
void setWireguardConfig();
/** Get configuration from wireguard */
void getWireguardConfig();
};
#endif

View File

@@ -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.

View File

@@ -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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,530 +0,0 @@
#include "wginterface.hh"
#include "genKey/wgkeys.hh"
#include <win/wireguard.h>
#include <string>
#include <locale>
#include <codecvt>
#include <vector>
#include <map>
#include <iostream>
#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 <ws2def.h>
#include <netioapi.h>
#include <chrono>
#include <thread>
#include <comdef.h>
#include <Wbemidl.h>
#include <stdexcept>
const DEVPROPKEY devpkey_name = { { 0x65726957, 0x7547, 0x7261, { 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79 } }, DEVPROPID_FIRST_USABLE + 1 };
#define IFNAMSIZ MAX_ADAPTER_NAME - 1
// Create Wireguard adapter
static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter;
// Open Wireguard adapter by name if exists
static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter;
// Close Wireguard adapter
static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter;
// Get Wireguard adapter LUID
static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID;
// Get running Wireguard driver version
static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC *WireGuardGetRunningDriverVersion;
// Delete Wireguard driver if non exists adapters
static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver;
// Set logger for Wireguard adapter
static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger;
// Set adapter logging for Wireguard adapter
static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging;
// Get adapter state for Wireguard adapter
static WIREGUARD_GET_ADAPTER_STATE_FUNC *WireGuardGetAdapterState;
// Set adapter state for Wireguard adapter
static WIREGUARD_SET_ADAPTER_STATE_FUNC *WireGuardSetAdapterState;
// Get Wireguard adapter configuration
static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration;
// Set Wireguard adapter configuration
static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration;
LPCWSTR WireguardAddonDescription = WireguardAddonDescription;
// Function to check if the current user has administrator privileges
bool IsRunAsAdmin() {
BOOL fRet = FALSE;
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;
}
std::string convertWcharString(const wchar_t *wideStr) {
// Create a wstring from the wide character string
std::wstring wideString(wideStr);
// Use std::wstring_convert for conversion
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
std::string narrowString = converter.to_bytes(wideString);
// Now narrowString is a std::string containing the converted string
return narrowString;
}
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;
}
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 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 driveLoad(std::map<std::string, std::string> load) {
if (!IsRunAsAdmin()) return "Run nodejs with administrator privilegies";
auto DLLPATH = load["WIN32DLLPATH"];
if (!(DLLPATH.length())) return "Require Wireguard DLL file path!";
LPCWSTR dllPath = toLpcwstr(DLLPATH);
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 getWireguardVersion() {
// Create interface to get version
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"getWgVersion", WireguardAddonDescription, NULL);
WireGuardCloseAdapter(Adapter);
DWORD Version = WireGuardGetRunningDriverVersion();
if (Version == 0) {
auto statusErr = GetLastError();
WireGuardCloseAdapter(Adapter);
if (statusErr == ERROR_FILE_NOT_FOUND) return "Driver not loaded";
return std::string("Cannot get version drive, ").append(getErrorString(GetLastError()));
}
return std::string("WireGuardNT v").append(std::to_string((Version >> 16) & 0xff)).append(".").append(std::to_string((Version >> 0) & 0xff)).append(".").append(std::to_string((Version >> 8) & 0xff));
}
void WireguardDevices::getInterfaces() {
HDEVINFO dev_info = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"SWD\\WireGuard", NULL, DIGCF_PRESENT, NULL, NULL, NULL);
if (dev_info == INVALID_HANDLE_VALUE) throw std::string("Cannot get devices");
for (DWORD devIndex = 0;; ++devIndex) {
SP_DEVINFO_DATA dev_info_data;
dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(dev_info, devIndex, &dev_info_data)) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
continue;
}
DWORD buf_len; ULONG status, problem_code;
WCHAR adapter_name[MAX_ADAPTER_NAME];
char *interface_name;
DEVPROPTYPE prop_type;
if (!SetupDiGetDevicePropertyW(dev_info, &dev_info_data, &devpkey_name, &prop_type, (PBYTE)adapter_name, sizeof(adapter_name), NULL, 0) || prop_type != DEVPROP_TYPE_STRING) continue;
adapter_name[_countof(adapter_name) - 1] = L'0';
if (!adapter_name[0]) continue;
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)) this->push_back(std::string(interface_name));
free(interface_name);
}
SetupDiDestroyDeviceInfoList(dev_info);
}
/*
Delete wireguard interface
Current bug from Addon: Set interface down and not delete wireguard interface
*/
void WireguardDevices::deleteInterface(std::string wgName) {
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName));
if (!Adapter) throw std::string("This interface not exists in Wireguard-Tools.js addon!");
if (!(WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_DOWN))) throw std::string("Failed to set down interface, ").append(getErrorString(GetLastError()));
WireGuardCloseAdapter(Adapter);
}
/**
* Change point from calloc or malloc, T: from, C: to
*/
template <typename T, typename C> C* changePoint(T *x) {
return reinterpret_cast<C*>(((char*)x) + sizeof(T));
}
void WireguardConfig::getWireguardConfig() {
if (this->name.length() == 0) throw std::string("Require interface name!");
else if (!(WireguardDevices().exist(this->name))) throw std::string("This interface not exists in Wireguard-Tools.js addon!");
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(this->name));
if (!Adapter) throw std::string("This interface not exists in Wireguard-Tools.js addon!");
NET_LUID InterfaceLuid;
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
this->interfaceAddress.GetInInterface(this->name);
DWORD buf_len = 0;
WIREGUARD_INTERFACE *wg_iface = nullptr;
while (!(WireGuardGetConfiguration(Adapter, wg_iface, &buf_len))) {
free(wg_iface);
if (GetLastError() != ERROR_MORE_DATA) throw std::string("Failed get interface config, code: ").append(std::to_string(GetLastError()));
wg_iface = (WIREGUARD_INTERFACE *)malloc(buf_len);
if (!wg_iface) throw std::string("Failed get interface config, ").append(std::to_string(-errno));
}
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY) this->privateKey = wgKeys::toString(wg_iface->PrivateKey);
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PUBLIC_KEY) this->publicKey = wgKeys::toString(wg_iface->PublicKey);
if (wg_iface->ListenPort > 0) this->portListen = wg_iface->ListenPort;
WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface);
for (DWORD i = 0; i < wg_iface->PeersCount; i++) {
auto pubKey = wgKeys::toString(wg_peer->PublicKey);
Peer peerConfig;
peerConfig.txBytes = wg_peer->TxBytes;
peerConfig.rxBytes = wg_peer->RxBytes;
peerConfig.lastHandshake = (wg_peer->LastHandshake - 116444736000000000LL) / (100 / 1000);
if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY) peerConfig.presharedKey = wgKeys::toString(wg_peer->PresharedKey);
if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT) peerConfig.endpoint = parseEndpoint(&wg_peer->Endpoint);
if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE) peerConfig.keepInterval = wg_peer->PersistentKeepalive;
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);
this->Peers[pubKey] = peerConfig;
}
free(wg_iface);
}
void WireguardConfig::setWireguardConfig() {
if (this->name.length() == 0) throw std::string("Require interface name!");
else if (this->name.length() > IFNAMSIZ) throw std::string("Interface name too long");
DWORD buf_len = sizeof(WIREGUARD_INTERFACE);
for (auto peer : this->Peers) {
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER)) throw std::string("Buffer overflow");
buf_len += sizeof(WIREGUARD_PEER);
for (auto aip : peer.second.allowedIPs) {
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP)) throw std::string("Buffer overflow");
buf_len += sizeof(WIREGUARD_ALLOWED_IP);
}
}
WIREGUARD_INTERFACE *wg_iface = reinterpret_cast<WIREGUARD_INTERFACE*>(calloc(1, buf_len));
if (!wg_iface) throw std::string("Cannot alloc buff");
wg_iface->PeersCount = 0;
wgKeys::stringToKey(wg_iface->PrivateKey, this->privateKey);
wg_iface->Flags = WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY;
wg_iface->ListenPort = this->portListen;
if (this->portListen >= 0) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT);
if (this->replacePeers) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_REPLACE_PEERS);
WIREGUARD_ALLOWED_IP *wg_aip;
WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface);
for (auto __peer : this->Peers) {
auto peerPublicKey = __peer.first; auto peerConfig = __peer.second;
wgKeys::stringToKey(wg_peer->PublicKey, peerPublicKey);
wg_peer->Flags = WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PUBLIC_KEY;
wg_peer->AllowedIPsCount = 0;
wg_iface->PeersCount++;
if (peerConfig.removeMe) {
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REMOVE);
wg_peer = changePoint<WIREGUARD_PEER, WIREGUARD_PEER>(wg_peer);
} else {
if (peerConfig.presharedKey.size() == B64_WG_KEY_LENGTH) {
wgKeys::stringToKey(wg_peer->PresharedKey, peerConfig.presharedKey);
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY);
}
wg_peer->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) {
int ret, retries = ([]() -> int {
unsigned long ret;
char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end;
if (!retries) return 15;
if (!strcmp(retries, "infinity")) return -1;
ret = strtoul(retries, &end, 10);
if (*end || ret > INT_MAX) {
fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n", retries);
exit(1);
}
return (int)ret;
})();
char *begin, *end;
auto mmutable = strdup(peerConfig.endpoint.c_str());
if (!mmutable) throw std::string("strdup");
if (!peerConfig.endpoint.size()) {
free(mmutable);
throw std::string("Unable to parse empty endpoint");
}
if (mmutable[0] == '[') {
begin = &mmutable[1];
end = strchr(mmutable, ']');
if (!end) {
free(mmutable);
throw std::string("Unable to find matching brace of endpoint: ").append(peerConfig.endpoint);
}
*end++ = '\0';
if (*end++ != ':' || !*end) {
free(mmutable);
throw std::string("Unable to find port of endpoint: ").append(peerConfig.endpoint);
}
} else {
begin = mmutable;
end = strrchr(mmutable, ':');
if (!end || !*(end + 1)) {
free(mmutable);
throw std::string("Unable to find port of endpoint: ").append(peerConfig.endpoint);
}
*end++ = '\0';
}
ADDRINFOA *resolved;
for (unsigned int timeout = 1000000;; timeout = ((20000000) < (timeout * 6 / 5) ? (20000000) : (timeout * 6 / 5))) {
// ret = getaddrinfo(begin, end, &hints, &resolved);
ret = getaddrinfo(begin, end, NULL, &resolved);
if (!ret) break;
if (ret == EAI_NONAME || ret == EAI_FAIL ||
#ifdef EAI_NODATA
ret == EAI_NODATA ||
#endif
(retries >= 0 && !retries--)) {
free(mmutable);
throw std::string("Error code: ").append(std::to_string(ret));
}
std::this_thread::sleep_for(std::chrono::microseconds(timeout));
}
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(SOCKADDR_IN))) memcpy(&wg_peer->Endpoint.Ipv4, resolved->ai_addr, resolved->ai_addrlen);
else if (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(SOCKADDR_IN6)) memcpy(&wg_peer->Endpoint.Ipv6, resolved->ai_addr, resolved->ai_addrlen);
else {
freeaddrinfo(resolved);
throw std::string("Neither IPv4 nor IPv6 address found: ").append(peerConfig.endpoint);
}
freeaddrinfo(resolved);
free(mmutable);
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT);
}
wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer);
for (auto Ip : peerConfig.allowedIPs.getIpParsed()) {
wg_aip->AddressFamily = Ip.Proto == 4 ? AF_INET : AF_INET6;
wg_aip->Cidr = Ip.Mask;
if (Ip.Proto == 6 && inet_pton(AF_INET6, Ip.Address.c_str(), &wg_aip->Address.V6) == 1) wg_aip->AddressFamily = AF_INET6;
else if (Ip.Proto == 4 && inet_pton(AF_INET, Ip.Address.c_str(), &wg_aip->Address.V4) == 1) wg_aip->AddressFamily = AF_INET;
else continue;
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(this->name));
if (!Adapter) Adapter = WireGuardCreateAdapter(toLpcwstr(this->name), WireguardAddonDescription, NULL);
if (!Adapter) throw std::string("Failed to create adapter, ").append(getErrorString(GetLastError()));
auto status = WireGuardSetConfiguration(Adapter, reinterpret_cast<WIREGUARD_INTERFACE*>(wg_iface), buf_len) && WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP);
free(wg_iface);
if (!status) {
auto status = GetLastError();
WireGuardCloseAdapter(Adapter);
throw std::string("Failed to set interface config, ").append(getErrorString(status));
}
this->interfaceAddress.SetInInterface(this->name);
}
void IpManeger::GetInInterface(std::string interfaceName) {
// Define the InterfaceLuid of the network interface you want to query
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(interfaceName));
if (!Adapter) throw std::string("Cannot open wireguard adapter");
NET_LUID InterfaceLuid;
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
ULONG bufferSize = 0; // Initial buffer size
// Call GetAdaptersAddresses to get the required buffer size
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &bufferSize) == ERROR_BUFFER_OVERFLOW) {
// Allocate memory for the buffer
PIP_ADAPTER_ADDRESSES addresses = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(bufferSize));
// Call GetAdaptersAddresses again with the allocated buffer
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, addresses, &bufferSize) == NO_ERROR) {
// Iterate through the list of adapters
for (PIP_ADAPTER_ADDRESSES adapter = addresses; adapter != nullptr; adapter = adapter->Next) {
// Check if the adapter matches the specified InterfaceLuid
if (memcmp(&adapter->Luid, &InterfaceLuid, sizeof(NET_LUID)) == 0) {
// Iterate through the list of IP addresses associated with the adapter
for (PIP_ADAPTER_UNICAST_ADDRESS address = adapter->FirstUnicastAddress; address != nullptr; address = address->Next) {
// Access the IP address in the address structure
sockaddr* sa = address->Address.lpSockaddr;
char ip[INET6_ADDRSTRLEN];
if (sa->sa_family == AF_INET) {
inet_ntop(AF_INET, &reinterpret_cast<sockaddr_in*>(sa)->sin_addr, ip, sizeof(ip));
} else if (sa->sa_family == AF_INET6) {
inet_ntop(AF_INET6, &reinterpret_cast<sockaddr_in6*>(sa)->sin6_addr, ip, sizeof(ip));
} else continue;
// Print or use the IP address as needed
this->addIPMask(std::string(ip).append("/").append(std::to_string(address->Address.iSockaddrLength)));
}
}
}
}
// Free the allocated buffer
free(addresses);
}
}
// https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-createunicastipaddressentry
void IpManeger::SetInInterface(std::string interfaceName) {
if (this->size() == 0) return;
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(interfaceName));
if (!Adapter) throw std::string("Cannot open wireguard adapter");
NET_LUID InterfaceLuid;
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
ULONG bufferSize = 0; // Initial buffer size
// Call GetAdaptersAddresses to get the required buffer size
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &bufferSize) == ERROR_BUFFER_OVERFLOW) {
// Allocate memory for the buffer
PIP_ADAPTER_ADDRESSES addresses = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(bufferSize));
// Call GetAdaptersAddresses again with the allocated buffer
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, addresses, &bufferSize) == NO_ERROR) {
// Iterate through the list of adapters
for (PIP_ADAPTER_ADDRESSES adapter = addresses; adapter != nullptr; adapter = adapter->Next) {
// Check if the adapter matches the specified InterfaceLuid
if (memcmp(&adapter->Luid, &InterfaceLuid, sizeof(NET_LUID)) == 0) {
// Iterate through the list of IP addresses associated with the adapter
for (PIP_ADAPTER_UNICAST_ADDRESS address = adapter->FirstUnicastAddress; address != nullptr; address = address->Next) {
// Access the IP address in the address structure
sockaddr* sa = address->Address.lpSockaddr;
char ip[INET6_ADDRSTRLEN];
if (sa->sa_family == AF_INET) {
inet_ntop(AF_INET, &reinterpret_cast<sockaddr_in*>(sa)->sin_addr, ip, sizeof(ip));
} else if (sa->sa_family == AF_INET6) {
inet_ntop(AF_INET6, &reinterpret_cast<sockaddr_in6*>(sa)->sin6_addr, ip, sizeof(ip));
} else continue;
// Delete the IP address
MIB_UNICASTIPADDRESS_ROW row;
memset(&row, 0, sizeof(row));
WireGuardGetAdapterLUID(Adapter, &row.InterfaceLuid);
if (sa->sa_family == AF_INET) {
row.Address.si_family = AF_INET;
inet_pton(AF_INET, ip, &row.Address.Ipv4.sin_addr);
} else if (sa->sa_family == AF_INET6) {
row.Address.si_family = AF_INET6;
inet_pton(AF_INET6, ip, &row.Address.Ipv6.sin6_addr);
} else continue;
if (DeleteUnicastIpAddressEntry(&row) != NO_ERROR) throw std::string("Cannot delete IP address from interface");
}
}
}
}
// Free the allocated buffer
free(addresses);
}
for (auto ip : this->getIpParsed()) {
MIB_UNICASTIPADDRESS_ROW row;
memset(&row, 0, sizeof(row));
memcpy(&row.InterfaceLuid, &InterfaceLuid, sizeof(NET_LUID));
row.DadState = NldsPreferred;
row.ValidLifetime = 0xffffffff;
row.PreferredLifetime = 0xffffffff;
row.OnLinkPrefixLength = ip.Mask;
if (ip.Proto == 4) {
row.Address.si_family = AF_INET;
inet_pton(AF_INET, ip.Address.c_str(), &row.Address.Ipv4.sin_addr);
} else if (ip.Proto == 6) {
row.Address.si_family = AF_INET6;
inet_pton(AF_INET6, ip.Address.c_str(), &row.Address.Ipv6.sin6_addr);
} else continue;
if (CreateUnicastIpAddressEntry(&row) != NO_ERROR) throw std::string("Cannot add IP address to interface");
}
}

View File

@@ -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

Binary file not shown.

View File

@@ -1,6 +0,0 @@
-std=c++17
-Iaddon/
-Iaddon/genKey
-Inode_modules/node-addon-api
-I/usr/local/include/node
-I/opt/local/include/node

22
go.mod Normal file
View File

@@ -0,0 +1,22 @@
module sirherobrine23.com.br/Wireguard/Wireguard-tools.js
go 1.24.2
require (
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.2-0.20250428221559-379bd75a8e14
)
require (
github.com/google/go-cmp v0.6.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/mdlayher/genetlink v1.3.2 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
)

40
go.sum Normal file
View File

@@ -0,0 +1,40 @@
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdIg1ozBNLgPy4SLT84nfcBjr6rhGtXYtrkWLU=
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ=
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ=
gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.1 h1:qbAry0o+aR4ZPWqGu1LP2MzcAHL/JcwsOLK64ekLsFM=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.1/go.mod h1:ou35usxSZyinNvaeRHPlnxglSrmc9Wg9cfJ4mE5/9kA=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.2-0.20250428163922-3668cf5c7a3a h1:4DODPfHJMwvHzzNaldOuuUtsWG9zCKSPOEPypyy4KxA=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.2-0.20250428163922-3668cf5c7a3a/go.mod h1:ou35usxSZyinNvaeRHPlnxglSrmc9Wg9cfJ4mE5/9kA=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.2-0.20250428194608-42a0c9998ddd h1:bIfQ7cHjiRPX8BCne/tqhVAqOAZJcjwCEurGO6CfWu4=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.2-0.20250428194608-42a0c9998ddd/go.mod h1:ou35usxSZyinNvaeRHPlnxglSrmc9Wg9cfJ4mE5/9kA=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.2-0.20250428221559-379bd75a8e14 h1:UMNGes46f1fIZfC4S59lXJ2/pBl/pj8HJHkEBrkFJeQ=
sirherobrine23.com.br/Sirherobrine23/napi-go v0.1.2-0.20250428221559-379bd75a8e14/go.mod h1:ou35usxSZyinNvaeRHPlnxglSrmc9Wg9cfJ4mE5/9kA=

5
main.go Normal file
View File

@@ -0,0 +1,5 @@
package main
import _ "sirherobrine23.com.br/Wireguard/Wireguard-tools.js/wg_addon"
func main() {}

View File

@@ -33,22 +33,21 @@
"node": ">=16.0.0"
},
"binary": {
"napi_versions": [8]
"napi_versions": [
8
]
},
"scripts": {
"install": "cmake-js compile",
"build": "cmake-js rebuild",
"test": "cmake-js compile && node --no-warnings --loader ts-node/esm src/index_test.js",
"go": "go build -buildmode=c-shared -o wg.node .",
"prepack": "tsc --build --clean && tsc --build",
"postpack": "tsc --build --clean"
},
"devDependencies": {
"@types/node": "^20.14.10",
"@types/node": "^20.17.30",
"ts-node": "^10.9.2",
"typescript": "^5.5.3"
"typescript": "^5.8.3"
},
"dependencies": {
"cmake-js": "^7.3.0",
"node-addon-api": "^8.0.0"
"node-addon-api": "^8.3.1"
}
}

55
wg_addon/addon.go Normal file
View File

@@ -0,0 +1,55 @@
package wg_addon
import (
"net"
"net/netip"
"time"
_ "unsafe"
"sirherobrine23.com.br/Sirherobrine23/napi-go"
_ "sirherobrine23.com.br/Sirherobrine23/napi-go/entry"
)
//go:linkname wg sirherobrine23.com.br/Sirherobrine23/napi-go/entry.Register
func wg(env napi.EnvType, export *napi.Object) {
getConfig, err := napi.GoFuncOf(env, GetInterface)
if err != nil {
panic(err)
}
export.Set("getConfig", getConfig)
setConfig, err := napi.GoFuncOf(env, SetInterface)
if err != nil {
panic(err)
}
export.Set("setConfig", setConfig)
// deleteInterface, _ := napi.CreateFunction(env, "deleteInterface", DeleteInterface)
// export.Set("deleteInterface", deleteInterface)
}
// Peer info
type Peer struct {
PresharedKey string `napi:"presharedKey"`
KeepInterval int `napi:"keepInterval"`
Endpoint string `napi:"endpoint"`
AllowedIPs []net.IPNet `napi:"allowedIPs"`
RemoveMe bool `napi:"removeMe"`
RxByte int `napi:"rxBytes"`
TxByte int `napi:"txBytes"`
LastHandshake time.Time `napi:"lastHandshake"`
}
// Wireguard interface configs
type Config struct {
Name string `napi:"name"`
PrivateKey string `napi:"privateKey"`
PublicKey string `napi:"publicKey"`
PortListen int `napi:"portListen"`
Fwmark int `napi:"fwmark"`
ReplacePeers bool `napi:"replacePeers"`
Address []netip.Addr `napi:"address"`
Peers map[string]*Peer `napi:"peers"`
}

32
wg_addon/unix.go Normal file
View File

@@ -0,0 +1,32 @@
//go:build unix && !linux
package wg_addon
import (
_ "golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
"sirherobrine23.com.br/Sirherobrine23/napi-go"
)
// Interface tunnels
var Tuns = map[string]*Tun{}
// Tunnel device
type Tun struct {
Tun tun.Device
Dev *device.Device
}
var GetConfig = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
return nil, nil
})
var SetConfig = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
return nil, nil
})
var DeleteInterface = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
return nil, nil
})

158
wg_addon/wgctrl.go Normal file
View File

@@ -0,0 +1,158 @@
//go:build linux || windows
package wg_addon
import (
"fmt"
"net"
"strings"
"time"
"sirherobrine23.com.br/Sirherobrine23/napi-go"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
func SetInterface(wgDevConfig Config) error {
if wgDevConfig.Name == "" {
return fmt.Errorf("set wireguard config")
}
devInfo, err := wgDevConfig.WgConfig()
if err != nil {
return err
}
// Get client to wireguard
client, err := wgctrl.New()
if err != nil {
return err
}
defer client.Close()
// Set Config
if err := client.ConfigureDevice(wgDevConfig.Name, devInfo); err != nil {
return err
}
return nil
}
func GetInterface(interfaceName string) (config *Config, err error) {
if interfaceName = strings.TrimSpace(interfaceName); interfaceName == "" {
return nil, fmt.Errorf("set interface name")
}
// Get client to wireguard
var client *wgctrl.Client
if client, err = wgctrl.New(); err != nil {
return nil, err
}
defer client.Close()
// Get config
var dev *wgtypes.Device
if dev, err = client.Device(interfaceName); err != nil {
return nil, err
}
config = &Config{}
config.FromWg(dev)
return
}
var DeleteInterface = napi.Callback(func(env napi.EnvType, this napi.ValueType, args []napi.ValueType) (napi.ValueType, error) {
if len(args) == 0 {
return nil, fmt.Errorf("set interface name")
}
interfaceName := napi.ToString(args[0])
typeof, err := interfaceName.Type()
if !(err == nil || typeof == napi.TypeString) {
return nil, fmt.Errorf("set interface name")
}
{
// interfaceName, _ := interfaceName.Utf8Value()
// // Get client to wireguard
// var client *wgctrl.Client
// if client, err = wgctrl.New(); err != nil {
// return nil, err
// }
// defer client.Close()
}
return nil, nil
})
func pointValue[T any](v T) *T { return &v }
func (cfg Config) WgConfig() (wgtypes.Config, error) {
config := wgtypes.Config{
ListenPort: pointValue(cfg.PortListen),
FirewallMark: pointValue(cfg.Fwmark),
ReplacePeers: cfg.ReplacePeers,
Peers: []wgtypes.PeerConfig{},
}
pk, err := wgtypes.ParseKey(cfg.PrivateKey)
if err != nil {
return config, err
}
config.PrivateKey = pointValue(pk)
for peerKey, peerInfo := range cfg.Peers {
pb, err := wgtypes.ParseKey(peerKey)
if err != nil {
return config, err
}
if peerInfo.RemoveMe {
config.Peers = append(config.Peers, wgtypes.PeerConfig{
PublicKey: pb,
Remove: true,
})
} else {
peer := wgtypes.PeerConfig{PublicKey: pb, AllowedIPs: peerInfo.AllowedIPs}
if peerInfo.PresharedKey != "" {
pr, err := wgtypes.ParseKey(peerInfo.PresharedKey)
if err != nil {
return config, err
}
peer.PresharedKey = pointValue(pr)
}
if peerInfo.Endpoint != "" {
if peer.Endpoint, err = net.ResolveUDPAddr("udp", peerInfo.Endpoint); err != nil {
return config, err
}
}
peer.PersistentKeepaliveInterval = pointValue(time.Duration(peerInfo.KeepInterval))
// Append to config
config.Peers = append(config.Peers, peer)
}
}
return config, nil
}
func (cfg *Config) FromWg(dev *wgtypes.Device) {
cfg.PublicKey = dev.PublicKey.String()
cfg.PrivateKey = dev.PrivateKey.String()
cfg.PortListen = dev.ListenPort
cfg.Fwmark = dev.FirewallMark
cfg.Peers = map[string]*Peer{}
for _, peer := range dev.Peers {
cfg.Peers[peer.PublicKey.String()] = &Peer{
PresharedKey: peer.PresharedKey.String(),
LastHandshake: peer.LastHandshakeTime,
KeepInterval: int(peer.PersistentKeepaliveInterval.Seconds()),
TxByte: int(peer.TransmitBytes),
RxByte: int(peer.ReceiveBytes),
AllowedIPs: peer.AllowedIPs,
}
if peer.Endpoint != nil {
cfg.Peers[peer.PublicKey.String()].Endpoint = peer.Endpoint.String()
}
}
}