Add clang-format #4

Closed
Sirherobrine23 wants to merge 1 commits from clangFormat into main
10 changed files with 1238 additions and 639 deletions

236
.clang-format Normal file

@ -0,0 +1,236 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseColons: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAfterAttributes: Never
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
KeepEmptyLinesAtEOF: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
...

21
.github/workflows/format.yml vendored Normal file

@ -0,0 +1,21 @@
name: Test
on:
push:
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
name: Checkout
- name: Install dependencies
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt update
sudo apt install -y clang-format
- name: format C/C++ code
run: find addons/ -path addons/tools/linux -prune -o -regex '.*\.\(cpp\|hpp\|cc\|c\|h\)' -exec clang-format -style=file -i {} \;
- run: git diff --exit-code --quiet HEAD~1 -- .

@ -1,11 +1,12 @@
#include <napi.h>
#include "wgkeys.hh" #include "wgkeys.hh"
#include <napi.h>
class privateKeyWorker : public Napi::AsyncWorker { class privateKeyWorker : public Napi::AsyncWorker {
private: private:
std::string pskString; std::string pskString;
Napi::Promise::Deferred genPromise; Napi::Promise::Deferred genPromise;
public:
public:
~privateKeyWorker() {} ~privateKeyWorker() {}
privateKeyWorker(const Napi::Env env) : AsyncWorker(env), genPromise{env} {} privateKeyWorker(const Napi::Env env) : AsyncWorker(env), genPromise{env} {}
Napi::Promise getPromise() { return genPromise.Promise(); } Napi::Promise getPromise() { return genPromise.Promise(); }
@ -18,19 +19,21 @@ class privateKeyWorker : public Napi::AsyncWorker {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
genPromise.Resolve(Napi::String::New(Env(), pskString)); genPromise.Resolve(Napi::String::New(Env(), pskString));
} }
void OnError(const Napi::Error& e) override { void OnError(const Napi::Error &e) override {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
genPromise.Reject(e.Value()); genPromise.Reject(e.Value());
} }
}; };
class publicKeyWorker : public Napi::AsyncWorker { class publicKeyWorker : public Napi::AsyncWorker {
private: private:
std::string privKey, pubString; std::string privKey, pubString;
Napi::Promise::Deferred genPromise; Napi::Promise::Deferred genPromise;
public:
public:
~publicKeyWorker() {} ~publicKeyWorker() {}
publicKeyWorker(const Napi::Env env, std::string privateKey) : AsyncWorker(env), privKey(privateKey), genPromise{env} {} publicKeyWorker(const Napi::Env env, std::string privateKey)
: AsyncWorker(env), privKey(privateKey), genPromise{env} {}
Napi::Promise getPromise() { return genPromise.Promise(); } Napi::Promise getPromise() { return genPromise.Promise(); }
void Execute() override { void Execute() override {
wg_key interfacePrivateKey, interfacePublicKey; wg_key interfacePrivateKey, interfacePublicKey;
@ -46,17 +49,18 @@ class publicKeyWorker : public Napi::AsyncWorker {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
genPromise.Resolve(Napi::String::New(Env(), pubString)); genPromise.Resolve(Napi::String::New(Env(), pubString));
} }
void OnError(const Napi::Error& e) override { void OnError(const Napi::Error &e) override {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
genPromise.Reject(e.Value()); genPromise.Reject(e.Value());
} }
}; };
class presharedKeyWorker : public Napi::AsyncWorker { class presharedKeyWorker : public Napi::AsyncWorker {
private: private:
std::string pskString; std::string pskString;
Napi::Promise::Deferred genPromise; Napi::Promise::Deferred genPromise;
public:
public:
~presharedKeyWorker() {} ~presharedKeyWorker() {}
presharedKeyWorker(const Napi::Env env) : AsyncWorker(env), genPromise{env} {} presharedKeyWorker(const Napi::Env env) : AsyncWorker(env), genPromise{env} {}
Napi::Promise getPromise() { return genPromise.Promise(); } Napi::Promise getPromise() { return genPromise.Promise(); }
@ -69,20 +73,22 @@ class presharedKeyWorker : public Napi::AsyncWorker {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
genPromise.Resolve(Napi::String::New(Env(), pskString)); genPromise.Resolve(Napi::String::New(Env(), pskString));
} }
void OnError(const Napi::Error& e) override { void OnError(const Napi::Error &e) override {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
genPromise.Reject(e.Value()); genPromise.Reject(e.Value());
} }
}; };
class genKeysWorker : public Napi::AsyncWorker { class genKeysWorker : public Napi::AsyncWorker {
private: private:
std::string privateKey, publicKey, presharedKey; std::string privateKey, publicKey, presharedKey;
bool withPreshared = false; bool withPreshared = false;
Napi::Promise::Deferred genPromise; Napi::Promise::Deferred genPromise;
public:
public:
~genKeysWorker() {} ~genKeysWorker() {}
genKeysWorker(const Napi::Env env, bool withPresharedKey) : AsyncWorker(env), withPreshared(withPresharedKey), genPromise{env} {} genKeysWorker(const Napi::Env env, bool withPresharedKey)
: AsyncWorker(env), withPreshared(withPresharedKey), genPromise{env} {}
Napi::Promise getPromise() { return genPromise.Promise(); } Napi::Promise getPromise() { return genPromise.Promise(); }
void Execute() override { void Execute() override {
wg_key keyPriv, preshe, pub; wg_key keyPriv, preshe, pub;
@ -93,7 +99,8 @@ class genKeysWorker : public Napi::AsyncWorker {
wgKeys::generatePublic(pub, keyPriv); wgKeys::generatePublic(pub, keyPriv);
publicKey = wgKeys::toString(pub); publicKey = wgKeys::toString(pub);
if (!withPreshared) return; if (!withPreshared)
return;
wgKeys::generatePreshared(preshe); wgKeys::generatePreshared(preshe);
presharedKey = wgKeys::toString(preshe); presharedKey = wgKeys::toString(preshe);
} }
@ -103,11 +110,12 @@ class genKeysWorker : public Napi::AsyncWorker {
auto keys = Napi::Object::New(env); auto keys = Napi::Object::New(env);
keys.Set("privateKey", privateKey); keys.Set("privateKey", privateKey);
keys.Set("publicKey", publicKey); keys.Set("publicKey", publicKey);
if (withPreshared) keys.Set("presharedKey", presharedKey); if (withPreshared)
keys.Set("presharedKey", presharedKey);
genPromise.Resolve(keys); genPromise.Resolve(keys);
} }
void OnError(const Napi::Error& e) override { void OnError(const Napi::Error &e) override {
Napi::HandleScope scope(Env()); Napi::HandleScope scope(Env());
genPromise.Reject(e.Value()); genPromise.Reject(e.Value());
} }
@ -119,45 +127,56 @@ Napi::Object Init(Napi::Env exportsEnv, Napi::Object exports) {
constants.Set("B64_WG_KEY_LENGTH", B64_WG_KEY_LENGTH); constants.Set("B64_WG_KEY_LENGTH", B64_WG_KEY_LENGTH);
exports.Set("constants", constants); exports.Set("constants", constants);
exports.Set("presharedKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo& info) { exports.Set(
const Napi::Env env = info.Env(); "presharedKey",
Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo &info) {
const Napi::Env env = info.Env();
// Callback function is latest argument // Callback function is latest argument
auto *Gen = new presharedKeyWorker(env); auto *Gen = new presharedKeyWorker(env);
Gen->Queue(); Gen->Queue();
return Gen->getPromise(); return Gen->getPromise();
})); }));
exports.Set("privateKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo& info) { exports.Set(
const Napi::Env env = info.Env(); "privateKey",
Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo &info) {
const Napi::Env env = info.Env();
// Callback function is latest argument // Callback function is latest argument
auto *Gen = new privateKeyWorker(env); auto *Gen = new privateKeyWorker(env);
Gen->Queue(); Gen->Queue();
return Gen->getPromise(); return Gen->getPromise();
})); }));
exports.Set("publicKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo& info) -> Napi::Value { exports.Set(
const Napi::Env env = info.Env(); "publicKey",
if (!(info[0].IsString())) { Napi::Function::New(exportsEnv,
Napi::Error::New(env, "Require private key").ThrowAsJavaScriptException(); [&](const Napi::CallbackInfo &info) -> Napi::Value {
return env.Undefined(); const Napi::Env env = info.Env();
} if (!(info[0].IsString())) {
Napi::Error::New(env, "Require private key")
.ThrowAsJavaScriptException();
return env.Undefined();
}
// Callback function is latest argument // Callback function is latest argument
auto *Gen = new publicKeyWorker(env, info[0].ToString().Utf8Value().c_str()); auto *Gen = new publicKeyWorker(
Gen->Queue(); env, info[0].ToString().Utf8Value().c_str());
return Gen->getPromise(); Gen->Queue();
})); return Gen->getPromise();
}));
exports.Set("genKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo &info) { exports.Set("genKey", Napi::Function::New(
const Napi::Env env = info.Env(); exportsEnv, [&](const Napi::CallbackInfo &info) {
bool withPreshared = false; const Napi::Env env = info.Env();
if (info[0].IsBoolean()) withPreshared = info[0].ToBoolean().Value(); bool withPreshared = false;
auto Gen = new genKeysWorker(env, withPreshared); if (info[0].IsBoolean())
Gen->Queue(); withPreshared = info[0].ToBoolean().Value();
return Gen->getPromise(); auto Gen = new genKeysWorker(env, withPreshared);
})); Gen->Queue();
return Gen->getPromise();
}));
return exports; return exports;
} }
NODE_API_MODULE(addon, Init); NODE_API_MODULE(addon, Init);

@ -1,6 +1,6 @@
#include "wgkeys.hh" #include "wgkeys.hh"
#include <errno.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <iostream> #include <iostream>
#include <random> #include <random>
@ -15,20 +15,23 @@
static void encode_base64(char dest[4], const uint8_t src[3]) { static void encode_base64(char dest[4], const uint8_t src[3]) {
const uint8_t input[] = { const uint8_t input[] = {
static_cast<uint8_t>((src[0] >> 2) & 63), static_cast<uint8_t>((src[0] >> 2) & 63),
static_cast<uint8_t>(((src[0] << 4) | (src[1] >> 4)) & 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[1] << 2) | (src[2] >> 6)) & 63),
static_cast<uint8_t>(src[2] & 63) static_cast<uint8_t>(src[2] & 63)};
};
unsigned int i; 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); 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) { void keyToBase64(wg_key_b64_string base64, const wg_key key) {
unsigned int i; unsigned int i;
for (i = 0; i < 32 / 3; ++i) encode_base64(&base64[i * 4], &key[i * 3]); for (i = 0; i < 32 / 3; ++i)
const uint8_t tempKey[3] = { key[i * 3 + 0], key[i * 3 + 1], 0 }; 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); encode_base64(&base64[i * 4], tempKey);
base64[sizeof(wg_key_b64_string) - 2] = '='; base64[sizeof(wg_key_b64_string) - 2] = '=';
base64[sizeof(wg_key_b64_string) - 1] = '\0'; base64[sizeof(wg_key_b64_string) - 1] = '\0';
@ -38,19 +41,28 @@ static int decodeBase64(const char src[4]) {
int val = 0; int val = 0;
unsigned int i; 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); 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; return val;
} }
#ifdef _WIN32 #ifdef _WIN32
static volatile void * (*memset_func)(void *, int, size_t) = (volatile void * (*)(void *, int, size_t))&memset; static volatile void *(*memset_func)(void *, int, size_t) =
void memzero_explicit(void *s, size_t count) { (volatile void *(*)(void *, int, size_t)) & memset;
memset_func(s, 0, count); void memzero_explicit(void *s, size_t count) { memset_func(s, 0, count); }
}
#else #else
static __attribute__((noinline)) void memzero_explicit(void *s, size_t count) { static __attribute__((noinline)) void memzero_explicit(void *s, size_t count) {
memset(s, 0, count); memset(s, 0, count);
__asm__ __volatile__("": :"r"(s) :"memory"); __asm__ __volatile__("" : : "r"(s) : "memory");
} }
#endif #endif
@ -109,21 +121,25 @@ static void pack(uint8_t *o, const fe n) {
static void add(fe o, const fe a, const fe b) { static void add(fe o, const fe a, const fe b) {
int i; int i;
for (i = 0; i < 16; ++i) o[i] = a[i] + b[i]; for (i = 0; i < 16; ++i)
o[i] = a[i] + b[i];
} }
static void subtract(fe o, const fe a, const fe b) { static void subtract(fe o, const fe a, const fe b) {
int i; int i;
for (i = 0; i < 16; ++i) o[i] = a[i] - b[i]; for (i = 0; i < 16; ++i)
o[i] = a[i] - b[i];
} }
static void multmod(fe o, const fe a, const fe b) { static void multmod(fe o, const fe a, const fe b) {
int i, j; int i, j;
int64_t t[31] = { 0 }; int64_t t[31] = {0};
for (i = 0; i < 16; ++i) { for (i = 0; i < 16; ++i) {
for (j = 0; j < 16; ++j) t[i + j] += a[i] * b[j]; 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]; for (i = 0; i < 15; ++i)
t[i] += 38 * t[i + 16];
memcpy(o, t, sizeof(fe)); memcpy(o, t, sizeof(fe));
carry(o); carry(o);
carry(o); carry(o);
@ -136,27 +152,39 @@ static void invert(fe o, const fe i) {
memcpy(c, i, sizeof(c)); memcpy(c, i, sizeof(c));
for (a = 253; a >= 0; --a) { for (a = 253; a >= 0; --a) {
multmod(c, c, c); multmod(c, c, c);
if (a != 2 && a != 4) multmod(c, c, i); if (a != 2 && a != 4)
multmod(c, c, i);
} }
memcpy(o, c, sizeof(fe)); memcpy(o, c, sizeof(fe));
memzero_explicit(c, sizeof(c)); memzero_explicit(c, sizeof(c));
} }
void wgKeys::generatePreshared(wg_key preshared_key) { void wgKeys::generatePreshared(wg_key preshared_key) {
#if _WIN32 || defined(__CYGWIN__) #if _WIN32 || defined(__CYGWIN__)
HCRYPTPROV hCryptProv; HCRYPTPROV hCryptProv;
BOOL winStatus; BOOL winStatus;
if ((winStatus = CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))) winStatus = CryptGenRandom(hCryptProv, sizeof(wg_key), (BYTE*)preshared_key); if ((winStatus = CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)))
winStatus =
CryptGenRandom(hCryptProv, sizeof(wg_key), (BYTE *)preshared_key);
CryptReleaseContext(hCryptProv, 0); CryptReleaseContext(hCryptProv, 0);
if (winStatus) return; 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))) #elif defined(__OpenBSD__) || \
if (!getentropy(preshared_key, sizeof(wg_key))) return; (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__) #elif defined(__NR_getrandom) && defined(__linux__)
if (syscall(__NR_getrandom, preshared_key, sizeof(wg_key), 0) == sizeof(wg_key)) return; if (syscall(__NR_getrandom, preshared_key, sizeof(wg_key), 0) ==
sizeof(wg_key))
return;
#elif __linux__ || _ANDROID__ || __termux__ #elif __linux__ || _ANDROID__ || __termux__
size_t ret, i; size_t ret, i;
int fd; int fd;
fd = open("/dev/urandom", O_RDONLY); fd = open("/dev/urandom", O_RDONLY);
@ -167,7 +195,7 @@ void wgKeys::generatePreshared(wg_key preshared_key) {
} }
close(fd); close(fd);
return; return;
#endif #endif
std::random_device rd; std::random_device rd;
for (uint8_t i = 0; i < sizeof(wg_key); ++i) { for (uint8_t i = 0; i < sizeof(wg_key); ++i) {
@ -191,7 +219,7 @@ void wgKeys::generatePrivate(wg_key private_key) {
void wgKeys::generatePublic(wg_key public_key, const wg_key private_key) { void wgKeys::generatePublic(wg_key public_key, const wg_key private_key) {
int i, r; int i, r;
uint8_t z[32]; uint8_t z[32];
fe a = { 1 }, b = { 9 }, c = { 0 }, d = { 1 }, e, f; fe a = {1}, b = {9}, c = {0}, d = {1}, e, f;
memcpy(z, private_key, sizeof(z)); memcpy(z, private_key, sizeof(z));
clamp_key(z); clamp_key(z);
@ -212,12 +240,12 @@ void wgKeys::generatePublic(wg_key public_key, const wg_key private_key) {
subtract(a, a, c); subtract(a, a, c);
multmod(b, a, a); multmod(b, a, a);
subtract(c, d, f); subtract(c, d, f);
const fe abc = { 0xdb41, 1 }; const fe abc = {0xdb41, 1};
multmod(a, c, abc); multmod(a, c, abc);
add(a, a, d); add(a, a, d);
multmod(c, c, a); multmod(c, c, a);
multmod(a, d, f); multmod(a, d, f);
const fe abc2 = { 9 }; const fe abc2 = {9};
multmod(d, b, abc2); multmod(d, b, abc2);
multmod(b, e, e); multmod(b, e, e);
cswap(a, b, r); cswap(a, b, r);
@ -237,8 +265,7 @@ void wgKeys::generatePublic(wg_key public_key, const wg_key private_key) {
memzero_explicit(f, sizeof(f)); memzero_explicit(f, sizeof(f));
} }
bool key_is_zero(const uint8_t key[32]) bool key_is_zero(const uint8_t key[32]) {
{
volatile uint8_t acc = 0; volatile uint8_t acc = 0;
for (unsigned int i = 0; i < 32; ++i) { for (unsigned int i = 0; i < 32; ++i) {
@ -250,7 +277,10 @@ bool key_is_zero(const uint8_t key[32])
void wgKeys::stringToKey(wg_key key, std::string keyBase64) { void wgKeys::stringToKey(wg_key key, std::string keyBase64) {
auto base64 = keyBase64.c_str(); auto 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())); 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; unsigned int i;
int val; int val;
@ -263,21 +293,25 @@ void wgKeys::stringToKey(wg_key key, std::string keyBase64) {
key[i * 3 + 1] = (val >> 8) & 0xff; key[i * 3 + 1] = (val >> 8) & 0xff;
key[i * 3 + 2] = val & 0xff; key[i * 3 + 2] = val & 0xff;
} }
const char tempDecode[4] = {base64[i * 4 + 0], base64[i * 4 + 1], base64[i * 4 + 2], 'A'}; const char tempDecode[4] = {base64[i * 4 + 0], base64[i * 4 + 1],
base64[i * 4 + 2], 'A'};
val = decodeBase64(tempDecode); val = decodeBase64(tempDecode);
ret |= ((uint32_t)val >> 31) | (val & 0xff); ret |= ((uint32_t)val >> 31) | (val & 0xff);
key[i * 3 + 0] = (val >> 16) & 0xff; key[i * 3 + 0] = (val >> 16) & 0xff;
key[i * 3 + 1] = (val >> 8) & 0xff; key[i * 3 + 1] = (val >> 8) & 0xff;
int status = EINVAL & ~((ret - 1) >> 8); int status = EINVAL & ~((ret - 1) >> 8);
if (status != 0) throw std::string("Cannot decode key, ret code: ").append(std::to_string(status)); if (status != 0)
throw std::string("Cannot decode key, ret code: ")
.append(std::to_string(status));
} }
std::string wgKeys::toString(const wg_key key) { std::string wgKeys::toString(const wg_key key) {
wg_key_b64_string base64; wg_key_b64_string base64;
unsigned int i; unsigned int i;
for (i = 0; i < 32 / 3; ++i) encode_base64(&base64[i * 4], &key[i * 3]); for (i = 0; i < 32 / 3; ++i)
const uint8_t tempKey[3] = { key[i * 3 + 0], key[i * 3 + 1], 0 }; 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); encode_base64(&base64[i * 4], tempKey);
base64[sizeof(wg_key_b64_string) - 2] = '='; base64[sizeof(wg_key_b64_string) - 2] = '=';
base64[sizeof(wg_key_b64_string) - 1] = '\0'; base64[sizeof(wg_key_b64_string) - 1] = '\0';

@ -1,14 +1,10 @@
#include <napi.h> #include <napi.h>
#include <wginterface.hh>
#include <net/if.h> #include <net/if.h>
#include <wginterface.hh>
unsigned long maxName() { unsigned long maxName() { return IFNAMSIZ; }
return IFNAMSIZ;
}
std::string versionDrive() { std::string versionDrive() { return "Userspace"; }
return "Userspace";
}
void listDevices::Execute() {} void listDevices::Execute() {}
void deleteInterface::Execute() {} void deleteInterface::Execute() {}

@ -1,31 +1,30 @@
#include <napi.h> #include "linux/set_ip.cpp"
#include <iostream> #include "wginterface.hh"
#include <unistd.h>
#include <time.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <net/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if_link.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <sys/ioctl.h>
#include <cerrno> #include <cerrno>
#include <ifaddrs.h> #include <ifaddrs.h>
#include <iostream>
#include <linux/if_addr.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_link.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <napi.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <string> #include <string>
#include <sysexits.h> #include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include "wginterface.hh" #include <sysexits.h>
#include "linux/set_ip.cpp" #include <time.h>
#include <unistd.h>
extern "C" { extern "C" {
#include "linux/wireguard.h" #include "linux/wireguard.h"
} }
#define SETCONFIG 1 #define SETCONFIG 1
@ -33,19 +32,17 @@ extern "C" {
#define LISTDEV 1 #define LISTDEV 1
#define DELIFACE 1 #define DELIFACE 1
unsigned long maxName() { unsigned long maxName() { return IFNAMSIZ; }
return IFNAMSIZ;
}
std::string versionDrive() { std::string versionDrive() { return "Kernel"; }
return "Kernel";
}
void listDevices::Execute() { void listDevices::Execute() {
char *device_name, *devicesList = wg_list_device_names(); char *device_name, *devicesList = wg_list_device_names();
if (!devicesList) return SetError("Unable to get device names"); if (!devicesList)
return SetError("Unable to get device names");
size_t len; size_t len;
for ((device_name) = (devicesList), (len) = 0; ((len) = strlen(device_name)); (device_name) += (len) + 1) { for ((device_name) = (devicesList), (len) = 0; ((len) = strlen(device_name));
(device_name) += (len) + 1) {
listInfo setInfo; listInfo setInfo;
setInfo.tunType = "kernel"; setInfo.tunType = "kernel";
deviceNames[std::string(device_name)] = setInfo; deviceNames[std::string(device_name)] = setInfo;
@ -58,7 +55,8 @@ int setInterface(std::string wgName) {
char *device_name, *devicesList = wg_list_device_names(); char *device_name, *devicesList = wg_list_device_names();
if (!!devicesList) { if (!!devicesList) {
auto createInterface = true; auto createInterface = true;
for ((device_name) = (devicesList), (len) = 0; ((len) = strlen(device_name)); (device_name) += (len) + 1) { for ((device_name) = (devicesList), (len) = 0;
((len) = strlen(device_name)); (device_name) += (len) + 1) {
if (device_name == wgName.c_str()) { if (device_name == wgName.c_str()) {
createInterface = false; createInterface = false;
break; break;
@ -66,7 +64,8 @@ int setInterface(std::string wgName) {
} }
free(devicesList); free(devicesList);
len = 0; len = 0;
if (createInterface) len = wg_add_device(wgName.c_str()); if (createInterface)
len = wg_add_device(wgName.c_str());
} }
return len; return len;
@ -76,13 +75,17 @@ void deleteInterface::Execute() {
size_t len = 0; size_t len = 0;
char *device_name, *devicesList = wg_list_device_names(); char *device_name, *devicesList = wg_list_device_names();
if (!!devicesList) { if (!!devicesList) {
for ((device_name) = (devicesList), (len) = 0; ((len) = strlen(device_name)); (device_name) += (len) + 1) { for ((device_name) = (devicesList), (len) = 0;
((len) = strlen(device_name)); (device_name) += (len) + 1) {
if (device_name == wgName.c_str()) { if (device_name == wgName.c_str()) {
if ((len = wg_add_device(wgName.c_str())) < 0) { if ((len = wg_add_device(wgName.c_str())) < 0) {
std::string err = "Error code: "; std::string err = "Error code: ";
err = err.append(std::to_string(len)); err = err.append(std::to_string(len));
if (len == -ENOMEM) err = "Out of memory"; if (len == -ENOMEM)
else if (len == -errno) err = ((std::string)"Cannot add device, code: ").append(std::to_string(len)); err = "Out of memory";
else if (len == -errno)
err = ((std::string) "Cannot add device, code: ")
.append(std::to_string(len));
SetError(err); SetError(err);
} }
break; break;
@ -97,8 +100,11 @@ void setConfig::Execute() {
if (res < 0) { if (res < 0) {
std::string err = "Error code: "; std::string err = "Error code: ";
err = err.append(std::to_string(res)); err = err.append(std::to_string(res));
if (res == -ENOMEM) err = "Out of memory"; if (res == -ENOMEM)
else if (res == -errno) err = ((std::string)"Cannot add device, code: ").append(std::to_string(res)); err = "Out of memory";
else if (res == -errno)
err = ((std::string) "Cannot add device, code: ")
.append(std::to_string(res));
SetError(err); SetError(err);
return; return;
} }
@ -120,17 +126,21 @@ void setConfig::Execute() {
// Port listenings // Port listenings
if (portListen > 0 && 25565 < portListen) { if (portListen > 0 && 25565 < portListen) {
deviceStruct->listen_port = portListen; deviceStruct->listen_port = portListen;
deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_HAS_LISTEN_PORT); deviceStruct->flags =
(wg_device_flags)(deviceStruct->flags | WGDEVICE_HAS_LISTEN_PORT);
} }
// Linux firewall mark // Linux firewall mark
if (fwmark >= 0) { if (fwmark >= 0) {
deviceStruct->fwmark = fwmark; deviceStruct->fwmark = fwmark;
deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_HAS_FWMARK); deviceStruct->flags =
(wg_device_flags)(deviceStruct->flags | WGDEVICE_HAS_FWMARK);
} }
// Replace Peers // Replace Peers
if (replacePeers) deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_REPLACE_PEERS); if (replacePeers)
deviceStruct->flags =
(wg_device_flags)(deviceStruct->flags | WGDEVICE_REPLACE_PEERS);
unsigned int peerIndex = 0; unsigned int peerIndex = 0;
for (auto it = peersVector.begin(); it != peersVector.end(); ++it) { for (auto it = peersVector.begin(); it != peersVector.end(); ++it) {
@ -144,18 +154,23 @@ void setConfig::Execute() {
peerStruct->flags = (wg_peer_flags)WGPEER_HAS_PUBLIC_KEY; peerStruct->flags = (wg_peer_flags)WGPEER_HAS_PUBLIC_KEY;
// Remove Peer // Remove Peer
if (peerConfig.removeMe) peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_REMOVE_ME); if (peerConfig.removeMe)
peerStruct->flags = (wg_peer_flags)(peerStruct->flags | WGPEER_REMOVE_ME);
else { else {
// Set preshared key if present // Set preshared key if present
if (peerConfig.presharedKey.length() > 0) { if (peerConfig.presharedKey.length() > 0) {
wg_key_from_base64(peerStruct->preshared_key, peerConfig.presharedKey.c_str()); wg_key_from_base64(peerStruct->preshared_key,
peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_HAS_PRESHARED_KEY); peerConfig.presharedKey.c_str());
peerStruct->flags =
(wg_peer_flags)(peerStruct->flags | WGPEER_HAS_PRESHARED_KEY);
} }
// Set Keepalive // Set Keepalive
if (peerConfig.keepInterval > 0) { if (peerConfig.keepInterval > 0) {
peerStruct->persistent_keepalive_interval = peerConfig.keepInterval; peerStruct->persistent_keepalive_interval = peerConfig.keepInterval;
peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL); peerStruct->flags =
(wg_peer_flags)(peerStruct->flags |
WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL);
} }
// Set endpoint // Set endpoint
@ -190,37 +205,51 @@ void setConfig::Execute() {
} }
addrinfo *resolved; addrinfo *resolved;
addrinfo hints = { addrinfo hints = {
ai_family: AF_UNSPEC, ai_family : AF_UNSPEC,
ai_socktype: SOCK_DGRAM, ai_socktype : SOCK_DGRAM,
ai_protocol: IPPROTO_UDP ai_protocol : IPPROTO_UDP
}; };
#define min(a, b) ((a) < (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b))
for (unsigned int timeout = 1000000;; timeout = min(20000000, timeout * 6 / 5)) { for (unsigned int timeout = 1000000;;
timeout = min(20000000, timeout * 6 / 5)) {
ret = getaddrinfo(begin, end, &hints, &resolved); ret = getaddrinfo(begin, end, &hints, &resolved);
if (!ret) break; if (!ret)
break;
if (ret == EAI_NONAME || ret == EAI_FAIL || if (ret == EAI_NONAME || ret == EAI_FAIL ||
#ifdef EAI_NODATA #ifdef EAI_NODATA
ret == EAI_NODATA || ret == EAI_NODATA ||
#endif #endif
(retries >= 0 && !retries--)) { (retries >= 0 && !retries--)) {
free(Endpoint); free(Endpoint);
fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), peerConfig.endpoint.c_str()); fprintf(stderr, "%s: `%s'\n",
ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret),
peerConfig.endpoint.c_str());
SetError("Unable to resolve endpoint"); SetError("Unable to resolve endpoint");
return; return;
} }
fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), peerConfig.endpoint.c_str(), timeout / 1000000.0); fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n",
ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret),
peerConfig.endpoint.c_str(), timeout / 1000000.0);
usleep(timeout); 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))) { 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); memcpy(&endpoint, resolved->ai_addr, resolved->ai_addrlen);
memccpy(&peerStruct->endpoint.addr, &endpoint, 0, sizeof(peerStruct->endpoint.addr)); memccpy(&peerStruct->endpoint.addr, &endpoint, 0,
sizeof(peerStruct->endpoint.addr));
if (resolved->ai_family == AF_INET) { if (resolved->ai_family == AF_INET) {
peerStruct->endpoint.addr4.sin_addr.s_addr = ((sockaddr_in *)&endpoint)->sin_addr.s_addr; peerStruct->endpoint.addr4.sin_addr.s_addr =
peerStruct->endpoint.addr4.sin_port = ((sockaddr_in *)&endpoint)->sin_port; ((sockaddr_in *)&endpoint)->sin_addr.s_addr;
peerStruct->endpoint.addr4.sin_port =
((sockaddr_in *)&endpoint)->sin_port;
peerStruct->endpoint.addr4.sin_family = AF_INET; peerStruct->endpoint.addr4.sin_family = AF_INET;
} else { } else {
peerStruct->endpoint.addr6.sin6_addr = ((struct sockaddr_in6 *)&endpoint)->sin6_addr; peerStruct->endpoint.addr6.sin6_addr =
peerStruct->endpoint.addr6.sin6_port = ((struct sockaddr_in6 *)&endpoint)->sin6_port; ((struct sockaddr_in6 *)&endpoint)->sin6_addr;
peerStruct->endpoint.addr6.sin6_port =
((struct sockaddr_in6 *)&endpoint)->sin6_port;
peerStruct->endpoint.addr6.sin6_family = AF_INET6; peerStruct->endpoint.addr6.sin6_family = AF_INET6;
} }
} else { } else {
@ -235,36 +264,43 @@ void setConfig::Execute() {
// Set allowed IPs // Set allowed IPs
if (peerConfig.allowedIPs.size() > 0) { if (peerConfig.allowedIPs.size() > 0) {
peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_REPLACE_ALLOWEDIPS); peerStruct->flags =
for (unsigned int allowIndex = 0; allowIndex < peerConfig.allowedIPs.size(); allowIndex++) { (wg_peer_flags)(peerStruct->flags | WGPEER_REPLACE_ALLOWEDIPS);
for (unsigned int allowIndex = 0;
allowIndex < peerConfig.allowedIPs.size(); allowIndex++) {
auto ip = peerConfig.allowedIPs[allowIndex]; auto ip = peerConfig.allowedIPs[allowIndex];
unsigned long cidr = 0; unsigned long cidr = 0;
if (ip.find("/") != std::string::npos) { if (ip.find("/") != std::string::npos) {
cidr = std::stoi(ip.substr(ip.find("/")+1)); cidr = std::stoi(ip.substr(ip.find("/") + 1));
ip = ip.substr(0, ip.find("/")); ip = ip.substr(0, ip.find("/"));
} }
wg_allowedip *newAllowedIP = new wg_allowedip({family: AF_UNSPEC}); wg_allowedip *newAllowedIP = new wg_allowedip({family : AF_UNSPEC});
if (strchr(ip.c_str(), ':')) { if (strchr(ip.c_str(), ':')) {
if (inet_pton(AF_INET6, ip.c_str(), &newAllowedIP->ip6) == 1) { if (inet_pton(AF_INET6, ip.c_str(), &newAllowedIP->ip6) == 1) {
newAllowedIP->family = AF_INET6; newAllowedIP->family = AF_INET6;
if (cidr == 0) cidr = 128; if (cidr == 0)
cidr = 128;
} }
} else { } else {
if (inet_pton(AF_INET, ip.c_str(), &newAllowedIP->ip4) == 1) { if (inet_pton(AF_INET, ip.c_str(), &newAllowedIP->ip4) == 1) {
newAllowedIP->family = AF_INET; newAllowedIP->family = AF_INET;
if (cidr == 0) cidr = 32; if (cidr == 0)
cidr = 32;
} }
} }
if (newAllowedIP->family == AF_UNSPEC || cidr <= 0) continue; if (newAllowedIP->family == AF_UNSPEC || cidr <= 0)
continue;
newAllowedIP->cidr = cidr; newAllowedIP->cidr = cidr;
if (allowIndex > 0) newAllowedIP->next_allowedip = peerStruct->first_allowedip; if (allowIndex > 0)
newAllowedIP->next_allowedip = peerStruct->first_allowedip;
peerStruct->first_allowedip = newAllowedIP; peerStruct->first_allowedip = newAllowedIP;
} }
} }
} }
// Add to Peer struct // Add to Peer struct
if (peerIndex > 0) peerStruct->next_peer = deviceStruct->first_peer; if (peerIndex > 0)
peerStruct->next_peer = deviceStruct->first_peer;
deviceStruct->first_peer = peerStruct; deviceStruct->first_peer = peerStruct;
} }
@ -272,34 +308,47 @@ void setConfig::Execute() {
if ((res = wg_set_device(deviceStruct)) < 0) { if ((res = wg_set_device(deviceStruct)) < 0) {
std::string err = "Set wireguard config Error code: "; std::string err = "Set wireguard config Error code: ";
err = err.append(std::to_string(res)); err = err.append(std::to_string(res));
if (res == -ENODEV) err = "No such device"; if (res == -ENODEV)
else if (res == -EINVAL) err = "Invalid argument"; err = "No such device";
else if (res == -ENOSPC) err = "No space left on device"; else if (res == -EINVAL)
err = "Invalid argument";
else if (res == -ENOSPC)
err = "No space left on device";
SetError(err); SetError(err);
} }
if (res >= 0) { if (res >= 0) {
auto res = setIps(wgName, Address); auto res = setIps(wgName, Address);
if (res.length() > 0) SetError(res); if (res.length() > 0)
SetError(res);
} }
} }
const char* getHostAddress(bool addPort, const sockaddr* addr) { const char *getHostAddress(bool addPort, const sockaddr *addr) {
char host[4096 + 1], service[512 + 1]; char host[4096 + 1], service[512 + 1];
static char buf[sizeof(host) + sizeof(service) + 4]; static char buf[sizeof(host) + sizeof(service) + 4];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
int ret; int ret;
socklen_t addr_len = 0; socklen_t addr_len = 0;
if (addr->sa_family == AF_INET) addr_len = sizeof(struct sockaddr_in); if (addr->sa_family == AF_INET)
else if (addr->sa_family == AF_INET6) addr_len = sizeof(struct sockaddr_in6); 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); ret =
getnameinfo(addr, addr_len, host, sizeof(host), service, sizeof(service),
NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST);
if (ret) { if (ret) {
strncpy(buf, gai_strerror(ret), sizeof(buf) - 1); strncpy(buf, gai_strerror(ret), sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0'; buf[sizeof(buf) - 1] = '\0';
} else { } else {
if (addPort) snprintf(buf, sizeof(buf), (addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service); if (addPort)
else snprintf(buf, sizeof(buf), "%s", host); snprintf(buf, sizeof(buf),
(addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s"
: "%s:%s",
host, service);
else
snprintf(buf, sizeof(buf), "%s", host);
} }
return buf; return buf;
} }
@ -311,7 +360,8 @@ std::string keyTo64(const uint8_t *key) {
} }
void getConfig::Execute() { void getConfig::Execute() {
int res; wg_device *device; int res;
wg_device *device;
if ((res = wg_get_device(&device, strdup(wgName.c_str()))) < 0) { if ((res = wg_get_device(&device, strdup(wgName.c_str()))) < 0) {
std::string err = "Cannot get wireguard device, Error code "; std::string err = "Cannot get wireguard device, Error code ";
err = err.append(std::to_string(res)); err = err.append(std::to_string(res));
@ -319,18 +369,26 @@ void getConfig::Execute() {
return; return;
} }
if (device->flags & WGDEVICE_HAS_PRIVATE_KEY) privateKey = keyTo64(device->private_key); if (device->flags & WGDEVICE_HAS_PRIVATE_KEY)
if (device->flags & WGDEVICE_HAS_PUBLIC_KEY) publicKey = keyTo64(device->public_key); privateKey = keyTo64(device->private_key);
if (device->listen_port > 0) portListen = device->listen_port; if (device->flags & WGDEVICE_HAS_PUBLIC_KEY)
publicKey = keyTo64(device->public_key);
if (device->listen_port > 0)
portListen = device->listen_port;
// Set Address array and get interface ip addresses // Set Address array and get interface ip addresses
ifaddrs* ptr_ifaddrs = nullptr; ifaddrs *ptr_ifaddrs = nullptr;
if(getifaddrs(&ptr_ifaddrs) > 0) { if (getifaddrs(&ptr_ifaddrs) > 0) {
for (ifaddrs* ptr_entry = ptr_ifaddrs; ptr_entry != nullptr; ptr_entry = ptr_entry->ifa_next) { for (ifaddrs *ptr_entry = ptr_ifaddrs; ptr_entry != nullptr;
if (ptr_entry->ifa_addr == nullptr) continue; ptr_entry = ptr_entry->ifa_next) {
else if (strcmp(ptr_entry->ifa_name, wgName.c_str()) != 0) continue; if (ptr_entry->ifa_addr == nullptr)
else if (ptr_entry->ifa_addr->sa_family == AF_INET) Address.push_back(getHostAddress(false, ptr_entry->ifa_addr)); continue;
else if (ptr_entry->ifa_addr->sa_family == AF_INET6) Address.push_back(getHostAddress(false, ptr_entry->ifa_addr)); else if (strcmp(ptr_entry->ifa_name, wgName.c_str()) != 0)
continue;
else if (ptr_entry->ifa_addr->sa_family == AF_INET)
Address.push_back(getHostAddress(false, ptr_entry->ifa_addr));
else if (ptr_entry->ifa_addr->sa_family == AF_INET6)
Address.push_back(getHostAddress(false, ptr_entry->ifa_addr));
} }
freeifaddrs(ptr_ifaddrs); freeifaddrs(ptr_ifaddrs);
} }
@ -338,20 +396,32 @@ void getConfig::Execute() {
wg_peer *peer; wg_peer *peer;
for ((peer) = (device)->first_peer; (peer); (peer) = (peer)->next_peer) { for ((peer) = (device)->first_peer; (peer); (peer) = (peer)->next_peer) {
auto PeerConfig = Peer(); auto PeerConfig = Peer();
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) PeerConfig.presharedKey = keyTo64(peer->preshared_key); if (peer->flags & WGPEER_HAS_PRESHARED_KEY)
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL && peer->persistent_keepalive_interval > 0) PeerConfig.keepInterval = peer->persistent_keepalive_interval; PeerConfig.presharedKey = keyTo64(peer->preshared_key);
if (peer->endpoint.addr.sa_family == AF_INET||peer->endpoint.addr.sa_family == AF_INET6) PeerConfig.endpoint = getHostAddress(true, &peer->endpoint.addr); if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL &&
if (peer->last_handshake_time.tv_sec > 0) PeerConfig.last_handshake = peer->last_handshake_time.tv_sec*1000; peer->persistent_keepalive_interval > 0)
if (peer->rx_bytes > 0) PeerConfig.rxBytes = peer->rx_bytes; PeerConfig.keepInterval = peer->persistent_keepalive_interval;
if (peer->tx_bytes > 0) PeerConfig.txBytes = peer->tx_bytes; if (peer->endpoint.addr.sa_family == AF_INET ||
peer->endpoint.addr.sa_family == AF_INET6)
PeerConfig.endpoint = getHostAddress(true, &peer->endpoint.addr);
if (peer->last_handshake_time.tv_sec > 0)
PeerConfig.last_handshake = peer->last_handshake_time.tv_sec * 1000;
if (peer->rx_bytes > 0)
PeerConfig.rxBytes = peer->rx_bytes;
if (peer->tx_bytes > 0)
PeerConfig.txBytes = peer->tx_bytes;
if (peer->first_allowedip) { if (peer->first_allowedip) {
wg_allowedip *allowedip; wg_allowedip *allowedip;
for ((allowedip) = (peer)->first_allowedip; (allowedip); (allowedip) = (allowedip)->next_allowedip) { for ((allowedip) = (peer)->first_allowedip; (allowedip);
(allowedip) = (allowedip)->next_allowedip) {
static char buf[INET6_ADDRSTRLEN + 1]; static char buf[INET6_ADDRSTRLEN + 1];
memset(buf, 0, INET6_ADDRSTRLEN + 1); memset(buf, 0, INET6_ADDRSTRLEN + 1);
if (allowedip->family == AF_INET) inet_ntop(AF_INET, &allowedip->ip4, buf, INET6_ADDRSTRLEN); if (allowedip->family == AF_INET)
else if (allowedip->family == AF_INET6) inet_ntop(AF_INET6, &allowedip->ip6, buf, INET6_ADDRSTRLEN); inet_ntop(AF_INET, &allowedip->ip4, buf, INET6_ADDRSTRLEN);
snprintf(buf + strlen(buf), INET6_ADDRSTRLEN - strlen(buf), "/%d", allowedip->cidr); else if (allowedip->family == AF_INET6)
inet_ntop(AF_INET6, &allowedip->ip6, buf, INET6_ADDRSTRLEN);
snprintf(buf + strlen(buf), INET6_ADDRSTRLEN - strlen(buf), "/%d",
allowedip->cidr);
PeerConfig.allowedIPs.push_back(buf); PeerConfig.allowedIPs.push_back(buf);
} }
} }

@ -1,41 +1,47 @@
#include <napi.h> #include "wginterface.hh"
#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <wireguard-nt/include/wireguard.h>
#include <win/shared.cpp>
#include <windows.h>
#include <tlhelp32.h>
#include <accctrl.h> #include <accctrl.h>
#include <aclapi.h> #include <aclapi.h>
#include <stdio.h> #include <bcrypt.h>
#include <stdbool.h> #include <cfgmgr32.h>
#include <cstdlib>
#include <devguid.h>
#include <fcntl.h> #include <fcntl.h>
#include <iostream>
#include <iphlpapi.h>
#include <map>
#include <napi.h>
#include <ndisguid.h>
#include <setupapi.h>
#include <stdbool.h>
#include <stdio.h>
#include <string>
#include <sysinfoapi.h>
#include <tlhelp32.h>
#include <vector>
#include <wgkeys.hh>
#include <win/shared.cpp>
#include <wincrypt.h>
#include <windows.h>
#include <winsock2.h> #include <winsock2.h>
#include <winternl.h>
#include <wireguard-nt/include/wireguard.h>
#include <ws2ipdef.h> #include <ws2ipdef.h>
#include <ws2tcpip.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 <ndisguid.h>
#include "wginterface.hh"
#include <wgkeys.hh>
const DEVPROPKEY devpkey_name = { { 0x65726957, 0x7547, 0x7261, { 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79 } }, DEVPROPID_FIRST_USABLE + 1 }; 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 #define IFNAMSIZ MAX_ADAPTER_NAME - 1
static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter; static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter;
static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter; static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter;
static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter; static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter;
static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID; static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID;
static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC *WireGuardGetRunningDriverVersion; static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC
*WireGuardGetRunningDriverVersion;
static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver; static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver;
static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger; static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger;
static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging; static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging;
@ -44,55 +50,84 @@ static WIREGUARD_SET_ADAPTER_STATE_FUNC *WireGuardSetAdapterState;
static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration; static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration;
static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration; static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration;
unsigned long maxName() { unsigned long maxName() { return IFNAMSIZ; }
return IFNAMSIZ;
}
std::string getErrorString(DWORD errorMessageID) { std::string getErrorString(DWORD errorMessageID) {
if (errorMessageID == 0 || errorMessageID < 0) std::string("Error code: ").append(std::to_string(errorMessageID)); if (errorMessageID == 0 || errorMessageID < 0)
std::string("Error code: ").append(std::to_string(errorMessageID));
LPSTR messageBuffer = nullptr; LPSTR messageBuffer = nullptr;
//Ask Win32 to give us the string version of that message ID. // 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). // The parameters we pass in, tell Win32 to create the buffer that holds the
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); // message for us (because we don't yet know how long the message string will
//Copy the error message into a std::string. // 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); std::string message(messageBuffer, size);
//Free the Win32's string's buffer. // Free the Win32's string's buffer.
LocalFree(messageBuffer); LocalFree(messageBuffer);
return std::string("Error code: ").append(std::to_string(errorMessageID)).append(", Message: ").append(message); return std::string("Error code: ")
.append(std::to_string(errorMessageID))
.append(", Message: ")
.append(message);
} }
std::string startAddon(const Napi::Env env) { std::string startAddon(const Napi::Env env) {
if (!IsRunAsAdmin()) return "Run nodejs with administrator privilegies"; if (!IsRunAsAdmin())
return "Run nodejs with administrator privilegies";
auto DLLPATH = env.Global().ToObject().Get("WIREGUARD_DLL_PATH"); auto DLLPATH = env.Global().ToObject().Get("WIREGUARD_DLL_PATH");
if (!(DLLPATH.IsString())) return "Require WIREGUARD_DLL_PATH in Global process"; if (!(DLLPATH.IsString()))
return "Require WIREGUARD_DLL_PATH in Global process";
LPCWSTR dllPath = toLpcwstr(DLLPATH.ToString()); LPCWSTR dllPath = toLpcwstr(DLLPATH.ToString());
HMODULE WireGuardDll = LoadLibraryExW(dllPath, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); HMODULE WireGuardDll = LoadLibraryExW(dllPath, NULL,
if (!WireGuardDll) return ((std::string)"Failed to initialize WireGuardNT, ").append(getErrorString(GetLastError()));; LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
#define X(Name) ((*(FARPROC *)&Name = GetProcAddress(WireGuardDll, #Name)) == NULL) LOAD_LIBRARY_SEARCH_SYSTEM32);
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)) if (!WireGuardDll)
#undef X 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(); DWORD LastError = GetLastError();
FreeLibrary(WireGuardDll); FreeLibrary(WireGuardDll);
SetLastError(LastError); SetLastError(LastError);
return ((std::string)"Failed to set Functions from WireGuardNT DLL, ").append(getErrorString(GetLastError()));; return ((std::string) "Failed to set Functions from WireGuardNT DLL, ")
.append(getErrorString(GetLastError()));
;
} }
return ""; return "";
} }
std::string versionDrive() { std::string versionDrive() {
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"getWgVersion", L"Wireguard-tools.js", NULL); WIREGUARD_ADAPTER_HANDLE Adapter =
WireGuardCreateAdapter(L"getWgVersion", L"Wireguard-tools.js", NULL);
DWORD Version = WireGuardGetRunningDriverVersion(); DWORD Version = WireGuardGetRunningDriverVersion();
if (Version == 0) { if (Version == 0) {
auto statusErr = GetLastError(); auto statusErr = GetLastError();
WireGuardCloseAdapter(Adapter); WireGuardCloseAdapter(Adapter);
if (statusErr == ERROR_FILE_NOT_FOUND) return "Driver not loaded"; if (statusErr == ERROR_FILE_NOT_FOUND)
return ((std::string)"Cannot get version drive, ").append(getErrorString(GetLastError())); return "Driver not loaded";
return ((std::string) "Cannot get version drive, ")
.append(getErrorString(GetLastError()));
} }
WireGuardCloseAdapter(Adapter); WireGuardCloseAdapter(Adapter);
return ((std::string)"WireGuardNT v").append(std::to_string((Version >> 16) & 0xff)).append(".").append(std::to_string((Version >> 0) & 0xff)); return ((std::string) "WireGuardNT v")
.append(std::to_string((Version >> 16) & 0xff))
.append(".")
.append(std::to_string((Version >> 0) & 0xff));
} }
void listDevices::Execute() { void listDevices::Execute() {
@ -105,23 +140,30 @@ void listDevices::Execute() {
for (auto &preit : arrayPrefix) { for (auto &preit : arrayPrefix) {
int ret = 0; int ret = 0;
find_handle = FindFirstFile("\\\\.\\pipe\\*", &find_data); find_handle = FindFirstFile("\\\\.\\pipe\\*", &find_data);
if (find_handle == INVALID_HANDLE_VALUE) continue; if (find_handle == INVALID_HANDLE_VALUE)
continue;
char *iface; char *iface;
do { do {
if (strncmp(preit.c_str(), find_data.cFileName, strlen(preit.c_str()))) continue; if (strncmp(preit.c_str(), find_data.cFileName, strlen(preit.c_str())))
continue;
iface = find_data.cFileName + strlen(preit.c_str()); iface = find_data.cFileName + strlen(preit.c_str());
listInfo setInfo; listInfo setInfo;
setInfo.tunType = "userspace"; setInfo.tunType = "userspace";
setInfo.pathSock = std::string("\\\\.\\pipe\\").append(preit).append(iface); setInfo.pathSock =
std::string("\\\\.\\pipe\\").append(preit).append(iface);
deviceNames[std::string(iface)] = setInfo; deviceNames[std::string(iface)] = setInfo;
} while (FindNextFile(find_handle, &find_data)); } while (FindNextFile(find_handle, &find_data));
FindClose(find_handle); FindClose(find_handle);
if (ret < 0) return SetError(std::string("Erro code: ").append(std::to_string(ret))); if (ret < 0)
return SetError(std::string("Erro code: ").append(std::to_string(ret)));
} }
HDEVINFO dev_info = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"SWD\\WireGuard", NULL, DIGCF_PRESENT, NULL, NULL, NULL); HDEVINFO dev_info =
if (dev_info == INVALID_HANDLE_VALUE) return SetError("Cannot get devices"); SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"SWD\\WireGuard", NULL,
DIGCF_PRESENT, NULL, NULL, NULL);
if (dev_info == INVALID_HANDLE_VALUE)
return SetError("Cannot get devices");
for (DWORD i = 0;; ++i) { for (DWORD i = 0;; ++i) {
DWORD buf_len; DWORD buf_len;
@ -133,24 +175,37 @@ void listDevices::Execute() {
char *interface_name; char *interface_name;
if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) { if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) break; if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
continue; continue;
} }
if (!SetupDiGetDevicePropertyW(dev_info, &dev_info_data, &devpkey_name, &prop_type, (PBYTE)adapter_name, sizeof(adapter_name), NULL, 0) || prop_type != DEVPROP_TYPE_STRING) continue; 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'; adapter_name[_countof(adapter_name) - 1] = L'0';
if (!adapter_name[0]) continue; if (!adapter_name[0])
buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, NULL, 0, NULL, NULL); continue;
if (!buf_len) continue; buf_len =
WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, NULL, 0, NULL, NULL);
if (!buf_len)
continue;
interface_name = (char *)malloc(buf_len); interface_name = (char *)malloc(buf_len);
if (!interface_name) continue; if (!interface_name)
buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, interface_name, buf_len, NULL, NULL); continue;
buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, interface_name,
buf_len, NULL, NULL);
if (!buf_len) { if (!buf_len) {
free(interface_name); free(interface_name);
continue; 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)) { if (CM_Get_DevNode_Status(&status, &problem_code, dev_info_data.DevInst,
0) == CR_SUCCESS &&
(status & (DN_DRIVER_LOADED | DN_STARTED)) ==
(DN_DRIVER_LOADED | DN_STARTED)) {
listInfo setInfo; listInfo setInfo;
setInfo.tunType = "kernel"; setInfo.tunType = "kernel";
deviceNames[std::string(interface_name)] = setInfo; deviceNames[std::string(interface_name)] = setInfo;
@ -162,8 +217,12 @@ void listDevices::Execute() {
void deleteInterface::Execute() { void deleteInterface::Execute() {
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName));
if (!Adapter) return SetError("This interface not exists in Wireguard-Tools.js addon!"); if (!Adapter)
if (!(WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_DOWN))) return SetError(std::string("Failed to set down interface, ").append(getErrorString(GetLastError()))); return SetError("This interface not exists in Wireguard-Tools.js addon!");
if (!(WireGuardSetAdapterState(
Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_DOWN)))
return SetError(std::string("Failed to set down interface, ")
.append(getErrorString(GetLastError())));
WireGuardCloseAdapter(Adapter); WireGuardCloseAdapter(Adapter);
} }
@ -173,19 +232,22 @@ void deleteInterface::Execute() {
* T: to * T: to
* C: From * C: From
*/ */
template <typename T, typename C> C* changePoint(T *x) { template <typename T, typename C> C *changePoint(T *x) {
// reinterpret_cast<WIREGUARD_ALLOWED_IP*>(((char*)x) + sizeof(WIREGUARD_PEER)); // reinterpret_cast<WIREGUARD_ALLOWED_IP*>(((char*)x) +
// std::cout << "Sizeof: " << sizeof(C) << ", " << typeid(T).name() << " -> " << typeid(C).name() << std::endl; // sizeof(WIREGUARD_PEER)); std::cout << "Sizeof: " << sizeof(C) << ", " <<
return reinterpret_cast<C*>(((char*)x) + sizeof(T)); // typeid(T).name() << " -> " << typeid(C).name() << std::endl;
return reinterpret_cast<C *>(((char *)x) + sizeof(T));
} }
void getConfig::Execute() { void getConfig::Execute() {
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName));
if (!Adapter) return SetError("This interface not exists in Wireguard-Tools.js addon!"); if (!Adapter)
return SetError("This interface not exists in Wireguard-Tools.js addon!");
NET_LUID InterfaceLuid; NET_LUID InterfaceLuid;
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
try { try {
for (auto aip : getIpAddr(InterfaceLuid)) Address.push_back(aip); for (auto aip : getIpAddr(InterfaceLuid))
Address.push_back(aip);
} catch (std::string err) { } catch (std::string err) {
return SetError(err); return SetError(err);
} }
@ -195,18 +257,28 @@ void getConfig::Execute() {
while (!(WireGuardGetConfiguration(Adapter, wg_iface, &buf_len))) { while (!(WireGuardGetConfiguration(Adapter, wg_iface, &buf_len))) {
free(wg_iface); free(wg_iface);
if (GetLastError() != ERROR_MORE_DATA) return SetError((std::string("Failed get interface config, code: ")).append(std::to_string(GetLastError()))); if (GetLastError() != ERROR_MORE_DATA)
return SetError((std::string("Failed get interface config, code: "))
.append(std::to_string(GetLastError())));
wg_iface = (WIREGUARD_INTERFACE *)malloc(buf_len); wg_iface = (WIREGUARD_INTERFACE *)malloc(buf_len);
if (!wg_iface) return SetError(((std::string)"Failed get interface config, ").append(std::to_string(-errno))); if (!wg_iface)
return SetError(((std::string) "Failed get interface config, ")
.append(std::to_string(-errno)));
} }
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY) privateKey = wgKeys::toString(wg_iface->PrivateKey); if (wg_iface->Flags &
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PUBLIC_KEY) publicKey = wgKeys::toString(wg_iface->PublicKey); WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY)
privateKey = wgKeys::toString(wg_iface->PrivateKey);
if (wg_iface->Flags &
WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PUBLIC_KEY)
publicKey = wgKeys::toString(wg_iface->PublicKey);
portListen = 0; portListen = 0;
if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT) portListen = wg_iface->ListenPort; if (wg_iface->Flags &
WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT)
portListen = wg_iface->ListenPort;
WIREGUARD_PEER *wg_peer =
WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface); changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface);
for (DWORD i = 0; i < wg_iface->PeersCount; i++) { for (DWORD i = 0; i < wg_iface->PeersCount; i++) {
auto pubKey = wgKeys::toString(wg_peer->PublicKey); auto pubKey = wgKeys::toString(wg_peer->PublicKey);
Peer peerConfig; Peer peerConfig;
@ -214,24 +286,33 @@ void getConfig::Execute() {
peerConfig.txBytes = wg_peer->TxBytes; peerConfig.txBytes = wg_peer->TxBytes;
peerConfig.rxBytes = wg_peer->RxBytes; peerConfig.rxBytes = wg_peer->RxBytes;
if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY) peerConfig.presharedKey = wgKeys::toString(wg_peer->PresharedKey); if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY)
if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT) peerConfig.endpoint = parseEndpoint(&wg_peer->Endpoint); peerConfig.presharedKey = wgKeys::toString(wg_peer->PresharedKey);
if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE) peerConfig.keepInterval = wg_peer->PersistentKeepalive; if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT)
if (wg_peer->LastHandshake > 0) peerConfig.last_handshake = (wg_peer->LastHandshake / 10000000 - 11644473600LL) * 1000; peerConfig.endpoint = parseEndpoint(&wg_peer->Endpoint);
if (wg_peer->Flags &
WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE)
peerConfig.keepInterval = wg_peer->PersistentKeepalive;
if (wg_peer->LastHandshake > 0)
peerConfig.last_handshake =
(wg_peer->LastHandshake / 10000000 - 11644473600LL) * 1000;
WIREGUARD_ALLOWED_IP* wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer); WIREGUARD_ALLOWED_IP *wg_aip =
changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer);
for (DWORD __aip = 0; __aip < wg_peer->AllowedIPsCount; __aip++) { for (DWORD __aip = 0; __aip < wg_peer->AllowedIPsCount; __aip++) {
char saddr[INET6_ADDRSTRLEN]; char saddr[INET6_ADDRSTRLEN];
if (wg_aip->AddressFamily == AF_INET) { if (wg_aip->AddressFamily == AF_INET) {
inet_ntop(AF_INET, &wg_aip->Address.V6, saddr, INET_ADDRSTRLEN); 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))); peerConfig.allowedIPs.push_back(std::string(saddr).append("/").append(
} else if (wg_aip->AddressFamily == AF_INET6) { std::to_string(wg_aip->Cidr)));
} else if (wg_aip->AddressFamily == AF_INET6) {
inet_ntop(AF_INET6, &wg_aip->Address.V6, saddr, INET6_ADDRSTRLEN); 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))); peerConfig.allowedIPs.push_back(std::string(saddr).append("/").append(
} std::to_string(wg_aip->Cidr)));
}
++wg_aip; ++wg_aip;
} }
wg_peer = reinterpret_cast<WIREGUARD_PEER*>(wg_aip); wg_peer = reinterpret_cast<WIREGUARD_PEER *>(wg_aip);
peersVector[pubKey] = peerConfig; peersVector[pubKey] = peerConfig;
} }
@ -241,29 +322,44 @@ void getConfig::Execute() {
void setConfig::Execute() { void setConfig::Execute() {
DWORD buf_len = sizeof(WIREGUARD_INTERFACE); DWORD buf_len = sizeof(WIREGUARD_INTERFACE);
for (auto peer : peersVector) { for (auto peer : peersVector) {
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER)) return SetError("Buffer overflow"); if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER))
buf_len += sizeof(WIREGUARD_PEER); return SetError("Buffer overflow");
for (auto aip : peer.second.allowedIPs) { buf_len += sizeof(WIREGUARD_PEER);
if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP)) return SetError("Buffer overflow"); for (auto aip : peer.second.allowedIPs) {
buf_len += sizeof(WIREGUARD_ALLOWED_IP); if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP))
} return SetError("Buffer overflow");
} buf_len += sizeof(WIREGUARD_ALLOWED_IP);
WIREGUARD_INTERFACE *wg_iface = reinterpret_cast<WIREGUARD_INTERFACE*>(calloc(1, buf_len)); }
if (!wg_iface) return SetError("Cannot alloc buff"); }
WIREGUARD_INTERFACE *wg_iface =
reinterpret_cast<WIREGUARD_INTERFACE *>(calloc(1, buf_len));
if (!wg_iface)
return SetError("Cannot alloc buff");
wg_iface->PeersCount = 0; wg_iface->PeersCount = 0;
wgKeys::stringToKey(wg_iface->PrivateKey, privateKey); wgKeys::stringToKey(wg_iface->PrivateKey, privateKey);
wg_iface->Flags = WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY; wg_iface->Flags =
WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY;
wg_iface->ListenPort = portListen; wg_iface->ListenPort = portListen;
if (portListen >= 0 && 65535 <= portListen) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT); if (portListen >= 0 && 65535 <= portListen)
wg_iface->Flags =
(WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags |
WIREGUARD_INTERFACE_FLAG::
WIREGUARD_INTERFACE_HAS_LISTEN_PORT);
if (replacePeers) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_REPLACE_PEERS); if (replacePeers)
wg_iface->Flags =
(WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags |
WIREGUARD_INTERFACE_FLAG::
WIREGUARD_INTERFACE_REPLACE_PEERS);
WIREGUARD_ALLOWED_IP *wg_aip; WIREGUARD_ALLOWED_IP *wg_aip;
WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface); WIREGUARD_PEER *wg_peer =
changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface);
for (auto __peer : peersVector) { for (auto __peer : peersVector) {
auto peerPublicKey = __peer.first; auto peerConfig = __peer.second; auto peerPublicKey = __peer.first;
auto peerConfig = __peer.second;
try { try {
wgKeys::stringToKey(wg_peer->PublicKey, peerPublicKey); wgKeys::stringToKey(wg_peer->PublicKey, peerPublicKey);
} catch (std::string &err) { } catch (std::string &err) {
@ -275,13 +371,18 @@ void setConfig::Execute() {
wg_iface->PeersCount++; wg_iface->PeersCount++;
if (peerConfig.removeMe) { if (peerConfig.removeMe) {
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REMOVE); wg_peer->Flags =
(WIREGUARD_PEER_FLAG)(wg_peer->Flags |
WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REMOVE);
wg_peer = changePoint<WIREGUARD_PEER, WIREGUARD_PEER>(wg_peer); wg_peer = changePoint<WIREGUARD_PEER, WIREGUARD_PEER>(wg_peer);
} else { } else {
if (peerConfig.presharedKey.size() == B64_WG_KEY_LENGTH) { if (peerConfig.presharedKey.size() == B64_WG_KEY_LENGTH) {
try { try {
wgKeys::stringToKey(wg_peer->PresharedKey, peerConfig.presharedKey); wgKeys::stringToKey(wg_peer->PresharedKey, peerConfig.presharedKey);
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY); wg_peer->Flags =
(WIREGUARD_PEER_FLAG)(wg_peer->Flags |
WIREGUARD_PEER_FLAG::
WIREGUARD_PEER_HAS_PRESHARED_KEY);
} catch (std::string &err) { } catch (std::string &err) {
SetError(err); SetError(err);
goto outEnd; goto outEnd;
@ -289,50 +390,79 @@ void setConfig::Execute() {
} }
wg_peer->PersistentKeepalive = peerConfig.keepInterval; 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.keepInterval >= 0)
wg_peer->Flags =
(WIREGUARD_PEER_FLAG)(wg_peer->Flags |
WIREGUARD_PEER_FLAG::
WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE);
if (peerConfig.endpoint.size() > 0) { if (peerConfig.endpoint.size() > 0) {
try { try {
insertEndpoint(&wg_peer->Endpoint, peerConfig.endpoint.c_str()); insertEndpoint(&wg_peer->Endpoint, peerConfig.endpoint.c_str());
wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT); wg_peer->Flags =
(WIREGUARD_PEER_FLAG)(wg_peer->Flags |
WIREGUARD_PEER_FLAG::
WIREGUARD_PEER_HAS_ENDPOINT);
} catch (std::string &err) { } catch (std::string &err) {
SetError(std::string("Cannot parse endpoint, ").append(err)); SetError(std::string("Cannot parse endpoint, ").append(err));
goto outEnd; goto outEnd;
} }
} }
wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer); wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer);
for (auto aip : peerConfig.allowedIPs) { for (auto aip : peerConfig.allowedIPs) {
unsigned long cidr = 0; unsigned long cidr = 0;
if (aip.find("/") != std::string::npos) { if (aip.find("/") != std::string::npos) {
cidr = std::stoi(aip.substr(aip.find("/")+1)); cidr = std::stoi(aip.substr(aip.find("/") + 1));
aip = aip.substr(0, aip.find("/")); aip = aip.substr(0, aip.find("/"));
} }
aip = aip.substr(0, aip.find("/")); aip = aip.substr(0, aip.find("/"));
wg_aip->AddressFamily = strchr(aip.c_str(), ':') ? AF_INET6 : AF_INET; wg_aip->AddressFamily = strchr(aip.c_str(), ':') ? AF_INET6 : AF_INET;
auto status = wg_aip->AddressFamily == AF_INET6 ? inet_pton(wg_aip->AddressFamily, aip.c_str(), &wg_aip->Address.V6) : inet_pton(wg_aip->AddressFamily, aip.c_str(), &wg_aip->Address.V4); auto status = wg_aip->AddressFamily == AF_INET6
? inet_pton(wg_aip->AddressFamily, aip.c_str(),
&wg_aip->Address.V6)
: inet_pton(wg_aip->AddressFamily, aip.c_str(),
&wg_aip->Address.V4);
if (status == 1) { if (status == 1) {
if (cidr == 0) cidr = wg_aip->AddressFamily == AF_INET6 ? 128 : 32; if (cidr == 0)
} else continue; cidr = wg_aip->AddressFamily == AF_INET6 ? 128 : 32;
} else
continue;
wg_aip->Cidr = cidr; wg_aip->Cidr = cidr;
wg_peer->AllowedIPsCount++; wg_peer->AllowedIPsCount++;
wg_aip = changePoint<WIREGUARD_ALLOWED_IP, WIREGUARD_ALLOWED_IP>(wg_aip); 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); 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)); wg_peer = reinterpret_cast<WIREGUARD_PEER *>(((char *)wg_aip));
} }
} }
WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName));
if (!Adapter) Adapter = WireGuardCreateAdapter(toLpcwstr(wgName), L"Wireguard-tools.js", NULL); if (!Adapter)
if (!Adapter) SetError(((std::string)"Failed to create adapter, ").append(getErrorString(GetLastError()))); Adapter =
else if (!WireGuardSetConfiguration(Adapter, reinterpret_cast<WIREGUARD_INTERFACE*>(wg_iface), buf_len)) { WireGuardCreateAdapter(toLpcwstr(wgName), L"Wireguard-tools.js", NULL);
if (!Adapter)
SetError(((std::string) "Failed to create adapter, ")
.append(getErrorString(GetLastError())));
else if (!WireGuardSetConfiguration(
Adapter, reinterpret_cast<WIREGUARD_INTERFACE *>(wg_iface),
buf_len)) {
auto status = GetLastError(); auto status = GetLastError();
SetError(std::string("Failed to set interface config, ").append(getErrorString(status))); SetError(std::string("Failed to set interface config, ")
.append(getErrorString(status)));
WireGuardCloseAdapter(Adapter); WireGuardCloseAdapter(Adapter);
} else if (!WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP)) { } else if (!WireGuardSetAdapterState(
Adapter,
WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP)) {
auto status = GetLastError(); auto status = GetLastError();
SetError(std::string("Failed to set interface up, ").append(getErrorString(status))); SetError(std::string("Failed to set interface up, ")
.append(getErrorString(status)));
WireGuardCloseAdapter(Adapter); WireGuardCloseAdapter(Adapter);
} else { } else {
if (Address.size() > 0) { if (Address.size() > 0) {
@ -341,11 +471,19 @@ void setConfig::Execute() {
aip = aip.substr(0, aip.find("/")); aip = aip.substr(0, aip.find("/"));
auto family = strchr(aip.c_str(), ':') ? AF_INET6 : AF_INET; auto family = strchr(aip.c_str(), ':') ? AF_INET6 : AF_INET;
SOCKADDR_INET address; SOCKADDR_INET address;
int status = family == AF_INET ? inet_pton(family, aip.c_str(), &address.Ipv4.sin_addr) : inet_pton(family, aip.c_str(), &address.Ipv6.sin6_addr); int status =
if (status != 1) continue; family == AF_INET
? inet_pton(family, aip.c_str(), &address.Ipv4.sin_addr)
: inet_pton(family, aip.c_str(), &address.Ipv6.sin6_addr);
if (status != 1)
continue;
char saddr[INET6_ADDRSTRLEN]; char saddr[INET6_ADDRSTRLEN];
family == AF_INET ? inet_ntop(AF_INET, &address.Ipv4.sin_addr, saddr, INET_ADDRSTRLEN) : inet_ntop(AF_INET6, &address.Ipv6.sin6_addr, saddr, INET6_ADDRSTRLEN); family == AF_INET
if (family == AF_INET) IPv4 = std::string(saddr); ? inet_ntop(AF_INET, &address.Ipv4.sin_addr, saddr, INET_ADDRSTRLEN)
: inet_ntop(AF_INET6, &address.Ipv6.sin6_addr, saddr,
INET6_ADDRSTRLEN);
if (family == AF_INET)
IPv4 = std::string(saddr);
// else IPv6 = std::string(saddr); // else IPv6 = std::string(saddr);
} }
@ -353,10 +491,11 @@ void setConfig::Execute() {
NET_LUID InterfaceLuid; NET_LUID InterfaceLuid;
WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); WireGuardGetAdapterLUID(Adapter, &InterfaceLuid);
auto setStatus = insertIpAddr(InterfaceLuid, IPv4, IPv6); auto setStatus = insertIpAddr(InterfaceLuid, IPv4, IPv6);
if (setStatus.size() > 0) SetError(setStatus); if (setStatus.size() > 0)
SetError(setStatus);
} }
} }
} }
outEnd: outEnd:
free(wg_iface); free(wg_iface);
} }

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

@ -1,36 +1,37 @@
#include <string>
#include <vector>
#include <wireguard-nt/include/wireguard.h>
#include <windows.h>
#include <ws2ipdef.h>
#include <ws2def.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <netioapi.h>
#include <iphlpapi.h>
#include <chrono> #include <chrono>
#include <thread>
#include <iostream> #include <iostream>
#include <iphlpapi.h>
#include <netioapi.h>
#include <string>
#include <thread>
#include <vector>
#include <windows.h>
#include <winsock2.h>
#include <wireguard-nt/include/wireguard.h>
#include <ws2def.h>
#include <ws2ipdef.h>
#include <ws2tcpip.h>
// Function to check if the current user has administrator privileges // Function to check if the current user has administrator privileges
bool IsRunAsAdmin() bool IsRunAsAdmin() {
{
BOOL fRet = FALSE; BOOL fRet = FALSE;
HANDLE hToken = NULL; HANDLE hToken = NULL;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
TOKEN_ELEVATION Elevation; TOKEN_ELEVATION Elevation;
DWORD cbSize = sizeof(TOKEN_ELEVATION); DWORD cbSize = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) { if (GetTokenInformation(hToken, TokenElevation, &Elevation,
sizeof(Elevation), &cbSize)) {
fRet = Elevation.TokenIsElevated; fRet = Elevation.TokenIsElevated;
} }
} }
if (hToken) CloseHandle(hToken); if (hToken)
CloseHandle(hToken);
return !!fRet; return !!fRet;
} }
LPCWSTR toLpcwstr(std::string s) { LPCWSTR toLpcwstr(std::string s) {
wchar_t* wString = new wchar_t[s.length()+1]; wchar_t *wString = new wchar_t[s.length() + 1];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), -1, wString, s.length()+1); MultiByteToWideChar(CP_ACP, 0, s.c_str(), -1, wString, s.length() + 1);
return wString; return wString;
} }
@ -38,98 +39,119 @@ int parse_dns_retries() {
unsigned long ret; unsigned long ret;
char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end; char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end;
if (!retries) return 15; if (!retries)
if (!strcmp(retries, "infinity")) return -1; return 15;
if (!strcmp(retries, "infinity"))
return -1;
ret = strtoul(retries, &end, 10); ret = strtoul(retries, &end, 10);
if (*end || ret > INT_MAX) { if (*end || ret > INT_MAX) {
fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n", retries); fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n",
retries);
exit(1); exit(1);
} }
return (int)ret; return (int)ret;
} }
void insertEndpoint(SOCKADDR_INET *endpoint, std::string value) { void insertEndpoint(SOCKADDR_INET *endpoint, std::string value) {
int ret, retries = parse_dns_retries(); int ret, retries = parse_dns_retries();
char *begin, *end; char *begin, *end;
auto mmutable = strdup(value.c_str()); auto mmutable = strdup(value.c_str());
if (!mmutable) throw std::string("strdup"); if (!mmutable)
if (!value.size()) { throw std::string("strdup");
if (!value.size()) {
free(mmutable); free(mmutable);
throw std::string("Unable to parse empty endpoint"); throw std::string("Unable to parse empty endpoint");
} }
if (mmutable[0] == '[') { if (mmutable[0] == '[') {
begin = &mmutable[1]; begin = &mmutable[1];
end = strchr(mmutable, ']'); end = strchr(mmutable, ']');
if (!end) { if (!end) {
free(mmutable); free(mmutable);
throw std::string("Unable to find matching brace of endpoint: ").append(value); throw std::string("Unable to find matching brace of endpoint: ")
.append(value);
} }
*end++ = '\0'; *end++ = '\0';
if (*end++ != ':' || !*end) { if (*end++ != ':' || !*end) {
free(mmutable); free(mmutable);
throw std::string("Unable to find port of endpoint: ").append(value); throw std::string("Unable to find port of endpoint: ").append(value);
} }
} else { } else {
begin = mmutable; begin = mmutable;
end = strrchr(mmutable, ':'); end = strrchr(mmutable, ':');
if (!end || !*(end + 1)) { if (!end || !*(end + 1)) {
free(mmutable); free(mmutable);
throw std::string("Unable to find port of endpoint: ").append(value); throw std::string("Unable to find port of endpoint: ").append(value);
} }
*end++ = '\0'; *end++ = '\0';
} }
ADDRINFOA *resolved;
ADDRINFOA *resolved; // #define min(a, b) ((a) < (b) ? (a) : (b))
// #define min(a, b) ((a) < (b) ? (a) : (b)) for (unsigned int timeout = 1000000;;
for (unsigned int timeout = 1000000;; timeout = ((20000000) < (timeout * 6 / 5) ? (20000000) : (timeout * 6 / 5))) { timeout =
// ret = getaddrinfo(begin, end, &hints, &resolved); ((20000000) < (timeout * 6 / 5) ? (20000000) : (timeout * 6 / 5))) {
ret = getaddrinfo(begin, end, NULL, &resolved); // ret = getaddrinfo(begin, end, &hints, &resolved);
if (!ret) break; ret = getaddrinfo(begin, end, NULL, &resolved);
/* The set of return codes that are "permanent failures". All other possibilities are potentially transient. if (!ret)
* break;
* This is according to https://sourceware.org/glibc/wiki/NameResolver which states: /* The set of return codes that are "permanent failures". All other
* "From the perspective of the application that calls getaddrinfo() it perhaps *possibilities are potentially transient.
* doesn't matter that much since EAI_FAIL, EAI_NONAME and EAI_NODATA are all *
* permanent failure codes and the causes are all permanent failures in the * This is according to https://sourceware.org/glibc/wiki/NameResolver which
* sense that there is no point in retrying later." *states: "From the perspective of the application that calls getaddrinfo()
* *it perhaps doesn't matter that much since EAI_FAIL, EAI_NONAME and
* So this is what we do, except FreeBSD removed EAI_NODATA some time ago, so that's conditional. *EAI_NODATA are all permanent failure codes and the causes are all
*/ *permanent failures in the sense that there is no point in retrying later."
if (ret == EAI_NONAME || ret == EAI_FAIL || *
#ifdef EAI_NODATA * So this is what we do, except FreeBSD removed EAI_NODATA some time ago,
ret == EAI_NODATA || *so that's conditional.
#endif */
(retries >= 0 && !retries--)) { if (ret == EAI_NONAME || ret == EAI_FAIL ||
free(mmutable); #ifdef EAI_NODATA
throw std::string("Error code: ").append(std::to_string(ret)); 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)); std::this_thread::sleep_for(std::chrono::microseconds(timeout));
} }
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(SOCKADDR_IN))) memcpy(&endpoint->Ipv4, resolved->ai_addr, resolved->ai_addrlen); if ((resolved->ai_family == AF_INET &&
else if (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(SOCKADDR_IN6)) memcpy(&endpoint->Ipv6, resolved->ai_addr, resolved->ai_addrlen); resolved->ai_addrlen == sizeof(SOCKADDR_IN)))
else { memcpy(&endpoint->Ipv4, resolved->ai_addr, resolved->ai_addrlen);
freeaddrinfo(resolved); else if (resolved->ai_family == AF_INET6 &&
throw std::string("Neither IPv4 nor IPv6 address found: ").append(value); resolved->ai_addrlen == sizeof(SOCKADDR_IN6))
} memcpy(&endpoint->Ipv6, resolved->ai_addr, resolved->ai_addrlen);
freeaddrinfo(resolved); else {
freeaddrinfo(resolved);
throw std::string("Neither IPv4 nor IPv6 address found: ").append(value);
}
freeaddrinfo(resolved);
free(mmutable); free(mmutable);
} }
std::string parseEndpoint(SOCKADDR_INET *input) { std::string parseEndpoint(SOCKADDR_INET *input) {
if (!(input->si_family == AF_INET || input->si_family == AF_INET6)) return ""; if (!(input->si_family == AF_INET || input->si_family == AF_INET6))
return "";
char saddr[INET6_ADDRSTRLEN]; 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); 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))); if (input->si_family == AF_INET6)
return std::string(saddr).append(":").append(std::to_string(htons(input->Ipv4.sin_port))); return std::string("[").append(saddr).append("]:").append(
std::to_string(htons(input->Ipv6.sin6_port)));
return std::string(saddr).append(":").append(
std::to_string(htons(input->Ipv4.sin_port)));
} }
std::string insertIpAddr(NET_LUID InterfaceLuid, std::string IPv4, std::string IPv6) { std::string insertIpAddr(NET_LUID InterfaceLuid, std::string IPv4,
std::string IPv6) {
NET_IFINDEX ind; NET_IFINDEX ind;
if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &ind) != NO_ERROR) return "Cannot get interface index"; if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &ind) != NO_ERROR)
return "Cannot get interface index";
// IPv4 // IPv4
if (IPv4.size() > 0) { if (IPv4.size() > 0) {
@ -137,10 +159,13 @@ std::string insertIpAddr(NET_LUID InterfaceLuid, std::string IPv4, std::string I
ULONG NTEInstance = 0; ULONG NTEInstance = 0;
UINT iaIPAddress; UINT iaIPAddress;
inet_pton(AF_INET, IPv4.c_str(), &iaIPAddress); inet_pton(AF_INET, IPv4.c_str(), &iaIPAddress);
auto status = AddIPAddress(iaIPAddress, NULL, ind, &NTEContext, &NTEInstance); auto status =
AddIPAddress(iaIPAddress, NULL, ind, &NTEContext, &NTEInstance);
if (status != NO_ERROR) { if (status != NO_ERROR) {
if (status == 5010) { if (status == 5010) {
} else return std::string("Cannot set IPv4 interface, error code: ").append(std::to_string(status)); } else
return std::string("Cannot set IPv4 interface, error code: ")
.append(std::to_string(status));
} }
} }
@ -155,25 +180,31 @@ std::string insertIpAddr(NET_LUID InterfaceLuid, std::string IPv4, std::string I
std::vector<std::string> getIpAddr(NET_LUID InterfaceLuid) { std::vector<std::string> getIpAddr(NET_LUID InterfaceLuid) {
NET_IFINDEX ind; NET_IFINDEX ind;
if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &ind) != NO_ERROR) throw std::string("Cannot get interface index"); if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &ind) != NO_ERROR)
throw std::string("Cannot get interface index");
std::vector<std::string> ips; std::vector<std::string> ips;
IP_ADAPTER_INFO *pAdapterInfo; IP_ADAPTER_INFO *pAdapterInfo;
ULONG ulOutBufLen; ULONG ulOutBufLen;
DWORD dwRetVal; DWORD dwRetVal;
pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) ); pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
ulOutBufLen = sizeof(IP_ADAPTER_INFO); ulOutBufLen = sizeof(IP_ADAPTER_INFO);
if (GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) { if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) {
free (pAdapterInfo); free(pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc ( ulOutBufLen ); pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
} }
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) != ERROR_SUCCESS) throw std::string("GetAdaptersInfo call failed with ").append(std::to_string(dwRetVal)); if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) != ERROR_SUCCESS)
throw std::string("GetAdaptersInfo call failed with ")
.append(std::to_string(dwRetVal));
PIP_ADAPTER_INFO pAdapter = pAdapterInfo; PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
while (pAdapter) { while (pAdapter) {
if (pAdapter->Index == ind) ips.push_back(std::string(pAdapter->IpAddressList.IpAddress.String).append("/32")); if (pAdapter->Index == ind)
ips.push_back(
std::string(pAdapter->IpAddressList.IpAddress.String).append("/32"));
pAdapter = pAdapter->Next; pAdapter = pAdapter->Next;
} }
if (pAdapterInfo) free(pAdapterInfo); if (pAdapterInfo)
free(pAdapterInfo);
return ips; return ips;
} }

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