Big code refactoring #10
							
								
								
									
										11
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,11 +0,0 @@ | |||||||
| version: 2 |  | ||||||
| updates: |  | ||||||
|   - directory: / |  | ||||||
|     package-ecosystem: "github-actions" |  | ||||||
|     schedule: |  | ||||||
|       interval: daily |  | ||||||
|  |  | ||||||
|   - directory: / |  | ||||||
|     package-ecosystem: npm |  | ||||||
|     schedule: |  | ||||||
|       interval: monthly |  | ||||||
							
								
								
									
										49
									
								
								.github/workflows/test.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								.github/workflows/test.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | name: Test | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |   pull_request: | ||||||
|  |     branches: | ||||||
|  |       - main | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   test_linux: | ||||||
|  |     name: Test Linux | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     strategy: | ||||||
|  |       matrix: | ||||||
|  |         node-version: [ 16.x, 18.x, 20.x, latest ] | ||||||
|  |     steps: | ||||||
|  |       - name: Disable sudo PATH replace | ||||||
|  |         run: | | ||||||
|  |           sudo cat /etc/sudoers | grep -v "secure_path=" > /tmp/.sudoers.tmp | ||||||
|  |           cat /tmp/.sudoers.tmp | sudo tee /etc/sudoers | ||||||
|  |           rm /tmp/.sudoers.tmp | ||||||
|  |  | ||||||
|  |       - name: Checkout | ||||||
|  |         uses: actions/checkout@v4 | ||||||
|  |  | ||||||
|  |       - name: Set up Node.js | ||||||
|  |         uses: actions/setup-node@v4 | ||||||
|  |         with: | ||||||
|  |           node-version: ${{ matrix.node-version }} | ||||||
|  |  | ||||||
|  |       - uses: actions/setup-go@v4 | ||||||
|  |         with: | ||||||
|  |           go-version-file: addon/userspace/go/go.mod | ||||||
|  |           go-version: ">=1.22.0" | ||||||
|  |  | ||||||
|  |       - name: "Setup zig" | ||||||
|  |         uses: korandoru/setup-zig@v1 | ||||||
|  |         with: | ||||||
|  |           zig-version: "master" | ||||||
|  |  | ||||||
|  |       - name: Install build dependencies | ||||||
|  |         run: sudo apt update && sudo apt install -y build-essential | ||||||
|  |  | ||||||
|  |       - name: Install node dependencies | ||||||
|  |         run: npm install --no-save --no-audit --no-fund --ignore-scripts | ||||||
|  |  | ||||||
|  |       - name: Run tests | ||||||
|  |         run: ./node_modules/.bin/rebory build && sudo node --no-warnings --loader ts-node/esm src/index_test.js | ||||||
							
								
								
									
										77
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										77
									
								
								.github/workflows/test.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,77 +0,0 @@ | |||||||
| name: Test |  | ||||||
| on: |  | ||||||
|   push: |  | ||||||
|     branches: |  | ||||||
|     - main |  | ||||||
|   pull_request: |  | ||||||
|     branches: |  | ||||||
|     - main |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   test_js: |  | ||||||
|     name: Test Javascript code |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     steps: |  | ||||||
|     - uses: actions/checkout@v4 |  | ||||||
|       name: Checkout |  | ||||||
|  |  | ||||||
|     - uses: actions/setup-node@v4 |  | ||||||
|       name: Setup Node.js |  | ||||||
|       with: |  | ||||||
|         node-version: 20.x |  | ||||||
|  |  | ||||||
|     - name: Install dependencies |  | ||||||
|       run: | |  | ||||||
|         export DEBIAN_FRONTEND=noninteractive |  | ||||||
|         sudo apt update && sudo apt install -y "build-essential" |  | ||||||
|         npm install --no-save --ignore-scripts |  | ||||||
|  |  | ||||||
|     - name: Build addon |  | ||||||
|       run: npm run dev |  | ||||||
|  |  | ||||||
|     - name: Run tests |  | ||||||
|       env: |  | ||||||
|         FORCE_COLOR: "true" |  | ||||||
|       run: sudo "$(command -v node)" --no-warnings --loader ts-node/esm src/index_test.ts |  | ||||||
|  |  | ||||||
|   build_addon: |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     needs: test_js |  | ||||||
|     strategy: |  | ||||||
|       matrix: |  | ||||||
|         node_version: [ 16.x, 17.x, 18.x, 19.x, 20.x, 21.x ] |  | ||||||
|     steps: |  | ||||||
|     - uses: actions/checkout@v4 |  | ||||||
|       name: Checkout |  | ||||||
|  |  | ||||||
|     - name: "Setup zig" |  | ||||||
|       uses: korandoru/setup-zig@v1 |  | ||||||
|       with: |  | ||||||
|         zig-version: "0.11.0" |  | ||||||
|  |  | ||||||
|     - uses: actions/setup-node@v4 |  | ||||||
|       name: Setup Node.js |  | ||||||
|       with: |  | ||||||
|         node-version: ${{ matrix.node_version }} |  | ||||||
|  |  | ||||||
|     - name: Install dependencies |  | ||||||
|       run: | |  | ||||||
|         export DEBIAN_FRONTEND=noninteractive |  | ||||||
|         sudo apt update && sudo apt install -y "build-essential" |  | ||||||
|         npm install --no-save --ignore-scripts |  | ||||||
|  |  | ||||||
|     - name: Build addon linux |  | ||||||
|       run: npm run dev -- --target x86_64-linux --target aarch64-linux |  | ||||||
|  |  | ||||||
|     - name: Build addon macos |  | ||||||
|       run: npm run dev -- --target x86_64-macos --target aarch64-macos |  | ||||||
|  |  | ||||||
|     - name: Build addon windows |  | ||||||
|       run: npm run dev -- --target x86_64-windows --target aarch64-windows |  | ||||||
|  |  | ||||||
|     - name: Upload prebuilds interface |  | ||||||
|       uses: actions/upload-artifact@v3 |  | ||||||
|       with: |  | ||||||
|         retention-days: 7 |  | ||||||
|         name: build-${{ matrix.node_version }} |  | ||||||
|         path: "build/*" |  | ||||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -11,6 +11,9 @@ node_modules/ | |||||||
| .DS_Store | .DS_Store | ||||||
| *.log | *.log | ||||||
|  |  | ||||||
|  | # Addon | ||||||
|  | addon/userspace/wg-go.* | ||||||
|  |  | ||||||
| # Typescript | # Typescript | ||||||
| *.tsbuildinfo | *.tsbuildinfo | ||||||
| src/**/*.d.ts | src/**/*.d.ts | ||||||
|   | |||||||
| @@ -1,21 +0,0 @@ | |||||||
| image: node:lts |  | ||||||
| test: |  | ||||||
|   stage: test |  | ||||||
|   image: ghcr.io/catthehacker/ubuntu:act-latest |  | ||||||
|   script: |  | ||||||
|     - | |  | ||||||
|       echo "Host arch: $(uname -m)" |  | ||||||
|       export DEBIAN_FRONTEND=noninteractive |  | ||||||
|       sudo apt update |  | ||||||
|       wget -qO- https://deb.nodesource.com/setup_current.x | sudo bash - |  | ||||||
|       packages=( "binutils-multiarch" "wget" "curl" "nodejs" "build-essential" ); |  | ||||||
|       sudo apt install -y ${packages[@]} |  | ||||||
|  |  | ||||||
|       ZIGURL="https://ziglang.org/download/0.11.0/zig-linux-x86_64-0.11.0.tar.xz" |  | ||||||
|       wget -qO- "${ZIGURL}" | sudo tar -xvJ -C /usr/local |  | ||||||
|       sudo mv -v /usr/local/zig-* /usr/local/zig |  | ||||||
|       sudo ln -vs /usr/local/zig/bin/zig /usr/bin/zig |  | ||||||
|  |  | ||||||
|     - npm install --no-save --ignore-scripts |  | ||||||
|     - npm run dev |  | ||||||
|     - sudo node --no-warnings --loader ts-node/esm ./src/index_test.ts |  | ||||||
							
								
								
									
										95
									
								
								.vscode/c_cpp_properties.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										95
									
								
								.vscode/c_cpp_properties.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,77 +1,16 @@ | |||||||
| { | { | ||||||
|   "version": 4, |  | ||||||
|   "configurations": [ |   "configurations": [ | ||||||
|     { |  | ||||||
|       "name": "Win32", |  | ||||||
|       "cStandard": "c17", |  | ||||||
|       "cppStandard": "c++17", |  | ||||||
|       "intelliSenseMode": "windows-msvc-x64", |  | ||||||
|       "compilerArgs": [ |  | ||||||
|         "-fpermissive", |  | ||||||
|         "-fexceptions", |  | ||||||
|         "-w", |  | ||||||
|         "-fpermissive", |  | ||||||
|         "-fPIC", |  | ||||||
|         "-static" |  | ||||||
|       ], |  | ||||||
|       "defines": [ |  | ||||||
|         "NAPI_DISABLE_CPP_EXCEPTIONS", |  | ||||||
|         "ONSTARTADDON", |  | ||||||
|         "LISTDEV", |  | ||||||
|         "GETCONFIG", |  | ||||||
|         "SETCONFIG", |  | ||||||
|         "DELIFACE" |  | ||||||
|       ], |  | ||||||
|       "includePath": [ |  | ||||||
|         "${env:appdata}/../Local/node-gyp/Cache/18.17.0/include/node", |  | ||||||
|         "${workspaceFolder}/node_modules/node-addon-api", |  | ||||||
|         "${workspaceFolder}/addons/genKey/**", |  | ||||||
|         "${workspaceFolder}/addons/tools/**" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       "name": "Linux", |  | ||||||
|       "compilerPath": "/usr/bin/clang", |  | ||||||
|       "cStandard": "c17", |  | ||||||
|       "cppStandard": "c++17", |  | ||||||
|       "intelliSenseMode": "linux-clang-x64", |  | ||||||
|       "compilerArgs": [ |  | ||||||
|         "-fpermissive", |  | ||||||
|         "-fexceptions", |  | ||||||
|         "-w", |  | ||||||
|         "-fpermissive", |  | ||||||
|         "-fPIC", |  | ||||||
|         "-static" |  | ||||||
|       ], |  | ||||||
|       "defines": [ |  | ||||||
|         "NAPI_DISABLE_CPP_EXCEPTIONS" |  | ||||||
|       ], |  | ||||||
|       "includePath": [ |  | ||||||
|         "/usr/include/node", |  | ||||||
|         "${workspaceFolder}/node_modules/node-addon-api/**", |  | ||||||
|         "${workspaceFolder}/node_modules/**", |  | ||||||
|         "${workspaceFolder}/addons/genKey/**", |  | ||||||
|         "${workspaceFolder}/addons/tools/**" |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     { |     { | ||||||
|       "name": "Mac", |       "name": "Mac", | ||||||
|       "includePath": [ |       "includePath": [ | ||||||
|         "${workspaceFolder}/node_modules/node-addon-api", |  | ||||||
|         "/usr/local/include/node", |         "/usr/local/include/node", | ||||||
|         "${workspaceFolder}/addons/genKey/**", |         "/usr/local/lib/zig//libc/include/any-linux-any", | ||||||
|         "${workspaceFolder}/addons/tools/**" |         "${workspaceFolder}/node_modules/node-addon-api", | ||||||
|  |         "${workspaceFolder}/**", | ||||||
|  |         "${workspaceFolder}/addon" | ||||||
|       ], |       ], | ||||||
|       "defines": [ |       "defines": [ | ||||||
|         "NAPI_DISABLE_CPP_EXCEPTIONS" |         "AF_NETLINK=16" | ||||||
|       ], |  | ||||||
|       "compilerArgs": [ |  | ||||||
|         "-fpermissive", |  | ||||||
|         "-fexceptions", |  | ||||||
|         "-w", |  | ||||||
|         "-fpermissive", |  | ||||||
|         "-fPIC", |  | ||||||
|         "-static" |  | ||||||
|       ], |       ], | ||||||
|       "macFrameworkPath": [ |       "macFrameworkPath": [ | ||||||
|         "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" |         "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" | ||||||
| @@ -80,6 +19,28 @@ | |||||||
|       "cStandard": "c17", |       "cStandard": "c17", | ||||||
|       "cppStandard": "c++17", |       "cppStandard": "c++17", | ||||||
|       "intelliSenseMode": "macos-clang-x64" |       "intelliSenseMode": "macos-clang-x64" | ||||||
|     } |     }, | ||||||
|  |     { | ||||||
|  |       "name": "Linux", | ||||||
|  |       "includePath": [ | ||||||
|  |         "${workspaceFolder}/node_modules/node-addon-api", | ||||||
|  |         "/usr/include/node", | ||||||
|  |         "${workspaceFolder}/**", | ||||||
|  |         "${workspaceFolder}/addon" | ||||||
|       ] |       ] | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "name": "Win32", | ||||||
|  |       "includePath": [ | ||||||
|  |         "${env:appdata}/../.cache/rebory/latest/node/include/node", | ||||||
|  |         "${workspaceFolder}/node_modules/node-addon-api", | ||||||
|  |         "${workspaceFolder}/addon" | ||||||
|  |       ], | ||||||
|  |       "defines": [], | ||||||
|  |       "intelliSenseMode": "windows-msvc-x64", | ||||||
|  |       "cStandard": "c17", | ||||||
|  |       "cppStandard": "c++17" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "version": 4 | ||||||
| } | } | ||||||
							
								
								
									
										20
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,20 +0,0 @@ | |||||||
| { |  | ||||||
|   "version": "0.2.0", |  | ||||||
|   "configurations": [ |  | ||||||
|     { |  | ||||||
|       "type": "lldb", |  | ||||||
|       "request": "launch", |  | ||||||
|       "name": "Debug", |  | ||||||
|       "cwd": "${workspaceFolder}", |  | ||||||
|       "program": "node", |  | ||||||
|       "preLaunchTask": { |  | ||||||
|         "type": "npm", |  | ||||||
|         "script": "dev" |  | ||||||
|       }, |  | ||||||
|       "args": [ |  | ||||||
|         "node_modules/.bin/mocha", |  | ||||||
|         "./" |  | ||||||
|       ] |  | ||||||
|     } |  | ||||||
|   ] |  | ||||||
| } |  | ||||||
							
								
								
									
										93
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										93
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -23,8 +23,99 @@ | |||||||
|     "PATH": "${workspaceFolder}/node_modules/.bin:${env:PATH}" |     "PATH": "${workspaceFolder}/node_modules/.bin:${env:PATH}" | ||||||
|   }, |   }, | ||||||
|   "files.associations": { |   "files.associations": { | ||||||
|  |     "*.dsc": "ini", | ||||||
|  |     "*.gyp": "python", | ||||||
|     "random": "cpp", |     "random": "cpp", | ||||||
|     "limits": "cpp", |     "limits": "cpp", | ||||||
|     "xstring": "cpp" |     "xstring": "cpp", | ||||||
|  |     "__bit_reference": "cpp", | ||||||
|  |     "__bits": "cpp", | ||||||
|  |     "__config": "cpp", | ||||||
|  |     "__debug": "cpp", | ||||||
|  |     "__errc": "cpp", | ||||||
|  |     "__hash_table": "cpp", | ||||||
|  |     "__locale": "cpp", | ||||||
|  |     "__mutex_base": "cpp", | ||||||
|  |     "__node_handle": "cpp", | ||||||
|  |     "__nullptr": "cpp", | ||||||
|  |     "__split_buffer": "cpp", | ||||||
|  |     "__string": "cpp", | ||||||
|  |     "__threading_support": "cpp", | ||||||
|  |     "__tree": "cpp", | ||||||
|  |     "__tuple": "cpp", | ||||||
|  |     "array": "cpp", | ||||||
|  |     "atomic": "cpp", | ||||||
|  |     "bitset": "cpp", | ||||||
|  |     "cctype": "cpp", | ||||||
|  |     "chrono": "cpp", | ||||||
|  |     "clocale": "cpp", | ||||||
|  |     "cmath": "cpp", | ||||||
|  |     "compare": "cpp", | ||||||
|  |     "complex": "cpp", | ||||||
|  |     "concepts": "cpp", | ||||||
|  |     "cstdarg": "cpp", | ||||||
|  |     "cstddef": "cpp", | ||||||
|  |     "cstdint": "cpp", | ||||||
|  |     "cstdio": "cpp", | ||||||
|  |     "cstdlib": "cpp", | ||||||
|  |     "cstring": "cpp", | ||||||
|  |     "ctime": "cpp", | ||||||
|  |     "cwchar": "cpp", | ||||||
|  |     "cwctype": "cpp", | ||||||
|  |     "exception": "cpp", | ||||||
|  |     "initializer_list": "cpp", | ||||||
|  |     "ios": "cpp", | ||||||
|  |     "iosfwd": "cpp", | ||||||
|  |     "iostream": "cpp", | ||||||
|  |     "istream": "cpp", | ||||||
|  |     "locale": "cpp", | ||||||
|  |     "map": "cpp", | ||||||
|  |     "memory": "cpp", | ||||||
|  |     "mutex": "cpp", | ||||||
|  |     "new": "cpp", | ||||||
|  |     "numeric": "cpp", | ||||||
|  |     "optional": "cpp", | ||||||
|  |     "ostream": "cpp", | ||||||
|  |     "ratio": "cpp", | ||||||
|  |     "sstream": "cpp", | ||||||
|  |     "stdexcept": "cpp", | ||||||
|  |     "streambuf": "cpp", | ||||||
|  |     "string": "cpp", | ||||||
|  |     "string_view": "cpp", | ||||||
|  |     "system_error": "cpp", | ||||||
|  |     "tuple": "cpp", | ||||||
|  |     "type_traits": "cpp", | ||||||
|  |     "typeinfo": "cpp", | ||||||
|  |     "unordered_map": "cpp", | ||||||
|  |     "variant": "cpp", | ||||||
|  |     "vector": "cpp", | ||||||
|  |     "algorithm": "cpp", | ||||||
|  |     "bit": "cpp", | ||||||
|  |     "charconv": "cpp", | ||||||
|  |     "codecvt": "cpp", | ||||||
|  |     "format": "cpp", | ||||||
|  |     "forward_list": "cpp", | ||||||
|  |     "functional": "cpp", | ||||||
|  |     "iomanip": "cpp", | ||||||
|  |     "iterator": "cpp", | ||||||
|  |     "list": "cpp", | ||||||
|  |     "stop_token": "cpp", | ||||||
|  |     "thread": "cpp", | ||||||
|  |     "utility": "cpp", | ||||||
|  |     "xfacet": "cpp", | ||||||
|  |     "xhash": "cpp", | ||||||
|  |     "xiosbase": "cpp", | ||||||
|  |     "xlocale": "cpp", | ||||||
|  |     "xlocbuf": "cpp", | ||||||
|  |     "xlocinfo": "cpp", | ||||||
|  |     "xlocmes": "cpp", | ||||||
|  |     "xlocmon": "cpp", | ||||||
|  |     "xlocnum": "cpp", | ||||||
|  |     "xloctime": "cpp", | ||||||
|  |     "xmemory": "cpp", | ||||||
|  |     "xtr1common": "cpp", | ||||||
|  |     "xtree": "cpp", | ||||||
|  |     "xutility": "cpp", | ||||||
|  |     "fstream": "cpp" | ||||||
|   } |   } | ||||||
| } | } | ||||||
							
								
								
									
										12
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,12 +0,0 @@ | |||||||
| { |  | ||||||
| 	"version": "2.0.0", |  | ||||||
| 	"tasks": [ |  | ||||||
| 		{ |  | ||||||
| 			"label": "npm: build", |  | ||||||
| 			"detail": "npm run dev", |  | ||||||
| 			"type": "npm", |  | ||||||
| 			"script": "dev", |  | ||||||
| 			"problemMatcher": [] |  | ||||||
| 		} |  | ||||||
| 	] |  | ||||||
| } |  | ||||||
							
								
								
									
										29
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,26 +1,17 @@ | |||||||
| # Wireguard-tools.js | # Wireguard-tools for Nodejs | ||||||
|  |  | ||||||
| Efficiently manage your Wireguard interface right from nodejs, no `wg` required. | Manage your Wireguard interfaces directly from Node.js without any wrappers over `wg` or `wg-quick` | ||||||
|  |  | ||||||
| other tools are wrappers over `wg`, `wireguard-tools.js` is not like that, it is a `C/C++` addon in which you don't need to have `wg` installed, as this module has full compatibility of its own `wg`. | ```js | ||||||
|  |  | ||||||
| ## CommonJS droping support | ``` | ||||||
|  |  | ||||||
| With a small disappointment I come to inform you that CommonJS will be ignored in the next updates and will be completely an ESM module, if you don't want to migrate to ESM I recommend staying on version `1.8.1` or even `1.8.3`, which will be the last versions but recent in CommonJS. | ## Licences | ||||||
|  |  | ||||||
| ## Support to: | - `Wireguard-tools.js`: GPL-3.0 | ||||||
|  |  | ||||||
| - Userspace [(wireguard-go)](https://git.zx2c4.com/wireguard-go/about/) support. | ### Wireguard | ||||||
| - Maneger wireguard interface (linux and windows create if not exist's). |  | ||||||
| - Generate `preshared`, `private` and `public` keys. |  | ||||||
| - [wg-quick](https://man7.org/linux/man-pages/man8/wg-quick.8.html) file support. |  | ||||||
| - More info and example check [`wiki`](https://sirherobrine23.org/Wireguard/Wireguard-tools.js/wiki). |  | ||||||
|  |  | ||||||
| > [!NOTE] | - `Embeddable-wg-library`: LGPL-2.1+. | ||||||
| > | - `Wireguard-nt`: GPL-2.0 | ||||||
| > we have pre-copiled files for: | - `Wireguard-go`: MIT | ||||||
| > - `Linux`: x64/amd64, arm64/aarch64 |  | ||||||
| > - `Windows`: x64, arm64 |  | ||||||
| > |  | ||||||
| > 1. To manage the Wireguard interfaces in linux, root access is required. |  | ||||||
| > 1. Another system's require `wireguard-go` [(check this page)](https://github.com/WireGuard/wireguard-go) |  | ||||||
| @@ -1,8 +1,6 @@ | |||||||
| #include "wgkeys.hh" | #include "wgkeys.hh" | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <assert.h> |  | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <iostream> |  | ||||||
| #include <random> | #include <random> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| 
 | 
 | ||||||
| @@ -18,17 +16,20 @@ static void encode_base64(char dest[4], const uint8_t src[3]) { | |||||||
|       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 +39,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 +119,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,38 +150,50 @@ 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); | ||||||
|   assert(fd >= 0); |   if (fd <= 0); | ||||||
|   for (i = 0; i < sizeof(wg_key); i += ret) { |   for (i = 0; i < sizeof(wg_key); i += ret) { | ||||||
|     ret = read(fd, preshared_key + i, sizeof(wg_key) - i); |     ret = read(fd, preshared_key + i, sizeof(wg_key) - i); | ||||||
|     assert(ret > 0); |     if (ret < 0); | ||||||
|   } |   } | ||||||
|   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 +217,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 +238,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 +263,15 @@ 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]) | std::string wgKeys::generatePublic(const std::string private_key) { | ||||||
| { |   wg_key public_key; | ||||||
|  |   wg_key private_key_; | ||||||
|  |   stringToKey(private_key_, private_key); | ||||||
|  |   generatePublic(public_key, private_key_); | ||||||
|  |   return toString(public_key); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool key_is_zero(const uint8_t key[32]) { | ||||||
|   volatile uint8_t acc = 0; |   volatile uint8_t acc = 0; | ||||||
| 
 | 
 | ||||||
|   for (unsigned int i = 0; i < 32; ++i) { |   for (unsigned int i = 0; i < 32; ++i) { | ||||||
| @@ -250,7 +283,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,24 +299,43 @@ 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'; | ||||||
| 
 | 
 | ||||||
|   return std::string(base64); |   return std::string(base64); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | std::string wgKeys::toHex(const std::string keyBase64) { | ||||||
|  |   wg_key key; | ||||||
|  |   wgKeys::stringToKey(key, keyBase64); | ||||||
|  |   char hex[65]; | ||||||
|  |   for (int i = 0; i < 32; ++i) sprintf(hex + i * 2, "%02x", key[i]); | ||||||
|  |   hex[64] = '\0'; | ||||||
|  |   return std::string(hex); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string wgKeys::HextoBase64(const std::string keyHex) { | ||||||
|  |   wg_key key; | ||||||
|  |   for (int i = 0; i < 32; ++i) sscanf(keyHex.c_str() + i * 2, "%02x", &key[i]); | ||||||
|  |   return wgKeys::toString(key); | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								addon/genKey/wgkeys.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								addon/genKey/wgkeys.hh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | #ifndef _WGKEY_ | ||||||
|  | #define _WGKEY_ | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | const int WG_KEY_LENGTH = 32, B64_WG_KEY_LENGTH = ((WG_KEY_LENGTH + 2) / 3) * 4; | ||||||
|  | const int wgKeyLength = 32, Base64WgKeyLength = ((wgKeyLength + 2) / 3) * 4, HexWgKeyLength = wgKeyLength * 2; | ||||||
|  |  | ||||||
|  | typedef unsigned char wg_key[wgKeyLength]; | ||||||
|  | typedef char wg_key_b64_string[Base64WgKeyLength + 1]; | ||||||
|  | typedef long long fe[16]; | ||||||
|  |  | ||||||
|  | namespace wgKeys { | ||||||
|  |   // Convert wg_key to std::string in base64 | ||||||
|  |   std::string toString(const wg_key key); | ||||||
|  |  | ||||||
|  |   // Convert base64 to hex key | ||||||
|  |   std::string toHex(const std::string keyBase64); | ||||||
|  |  | ||||||
|  |   // Convert hex to base64 | ||||||
|  |   std::string HextoBase64(const std::string keyHex); | ||||||
|  |  | ||||||
|  |   // Convert base64 to wg_key | ||||||
|  |   void stringToKey(wg_key key, std::string keyBase64); | ||||||
|  |  | ||||||
|  |   // Generate preshared key | ||||||
|  |   void generatePreshared(wg_key key); | ||||||
|  |  | ||||||
|  |   // Generate private key | ||||||
|  |   void generatePrivate(wg_key private_key); | ||||||
|  |  | ||||||
|  |   // Get public key from private key | ||||||
|  |   void generatePublic(wg_key public_key, const wg_key private_key); | ||||||
|  |  | ||||||
|  |   std::string generatePublic(const std::string private_key); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										437
									
								
								addon/linux/wginterface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										437
									
								
								addon/linux/wginterface.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,437 @@ | |||||||
|  | #include "wginterface.hh" | ||||||
|  | #include "genKey/wgkeys.hh" | ||||||
|  | extern "C" { | ||||||
|  | #include "wireguard.h" | ||||||
|  | } | ||||||
|  | #include <string> | ||||||
|  | #include <ifaddrs.h> | ||||||
|  | #include <sys/socket.h> | ||||||
|  | #include <netdb.h> | ||||||
|  | #include <arpa/inet.h> | ||||||
|  | #include <time.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <cstring> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <asm/types.h> | ||||||
|  | #include <netinet/in.h> | ||||||
|  | #include <linux/netlink.h> | ||||||
|  | #include <linux/rtnetlink.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <iostream> | ||||||
|  | #include <sys/ioctl.h> | ||||||
|  | #include <net/if.h> | ||||||
|  | #include <filesystem> | ||||||
|  | #include <fstream> | ||||||
|  |  | ||||||
|  | std::string getWireguardVersion() { | ||||||
|  |   #ifdef WIREGUARD_VERSION | ||||||
|  |   return std::string(WIREGUARD_VERSION); | ||||||
|  |   #endif | ||||||
|  |  | ||||||
|  |   std::string version = "Unknown"; | ||||||
|  |    | ||||||
|  |   // /sys/module/wireguard/version - for kernel module | ||||||
|  |   if (std::filesystem::exists("/sys/module/wireguard/version")) { | ||||||
|  |     std::ifstream file("/sys/module/wireguard/version"); | ||||||
|  |     file >> version; | ||||||
|  |     file.close(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return version; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string driveLoad(std::map<std::string, std::string> load) {} | ||||||
|  |  | ||||||
|  | void WireguardDevices::getInterfaces() { | ||||||
|  |   size_t len; char *device_name, *devicesList = wg_list_device_names(); | ||||||
|  |  | ||||||
|  |   if (!devicesList) throw std::string("Unable to get device names"); | ||||||
|  |  | ||||||
|  |   // Clear list | ||||||
|  |   this->clear(); | ||||||
|  |  | ||||||
|  |   // Set new devices | ||||||
|  |   for (device_name = devicesList, len = 0; (len = strlen(device_name)); device_name += len + 1) this->push_back(std::string(device_name)); | ||||||
|  |  | ||||||
|  |   // Free memory | ||||||
|  |   free(devicesList); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WireguardDevices::deleteInterface(std::string wgName) { | ||||||
|  |   // Check if exist, if not skip | ||||||
|  |   if (this->exist(wgName)) { | ||||||
|  |     int status = wg_del_device(wgName.c_str()); | ||||||
|  |     if (status < 0) throw std::string("Cannot delete interface, code: ").append(std::to_string(status)); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string HostAdresses(bool addPort, const sockaddr* addr) { | ||||||
|  |   char host[4096 + 1], service[512 + 1]; | ||||||
|  |   static char buf[sizeof(host) + sizeof(service) + 4]; | ||||||
|  |   memset(buf, 0, sizeof(buf)); | ||||||
|  |   int ret; | ||||||
|  |   socklen_t addr_len = 0; | ||||||
|  |   if (addr->sa_family == AF_INET) addr_len = sizeof(struct sockaddr_in); | ||||||
|  |   else if (addr->sa_family == AF_INET6) addr_len = sizeof(struct sockaddr_in6); | ||||||
|  |  | ||||||
|  |   ret = getnameinfo(addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST); | ||||||
|  |   if (ret) { | ||||||
|  |     strncpy(buf, gai_strerror(ret), sizeof(buf) - 1); | ||||||
|  |     buf[sizeof(buf) - 1] = '\0'; | ||||||
|  |   } else { | ||||||
|  |     if (addPort) snprintf(buf, sizeof(buf), (addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service); | ||||||
|  |     else snprintf(buf, sizeof(buf), "%s", host); | ||||||
|  |   } | ||||||
|  |   return std::string(buf); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void WireguardConfig::getWireguardConfig() { | ||||||
|  |   if (this->name.length() == 0) throw std::string("Set wireguard name!"); | ||||||
|  |   else if (this->name.length() > IFNAMSIZ) throw std::string("Wireguard interface name is long, max name length is ").append(std::to_string(IFNAMSIZ)); | ||||||
|  |   else if (!(WireguardDevices().exist(this->name))) throw std::string("Wireguard interface not exist"); | ||||||
|  |   int status; wg_device *devConfig; wg_peer *peer; | ||||||
|  |   if ((status = wg_get_device(&devConfig, this->name.c_str())) < 0) throw std::string("It was not possible to get the Wireguard interface settings, code: ").append(std::to_string(status)); | ||||||
|  |   if (devConfig->flags & WGDEVICE_HAS_PRIVATE_KEY) this->privateKey = wgKeys::toString(devConfig->private_key); | ||||||
|  |   if (devConfig->flags & WGDEVICE_HAS_PUBLIC_KEY) this->publicKey = wgKeys::toString(devConfig->public_key); | ||||||
|  |   if (!!devConfig->listen_port && devConfig->listen_port > 0) this->portListen = devConfig->listen_port; | ||||||
|  |   this->interfaceAddress.GetInInterface(this->name); | ||||||
|  |  | ||||||
|  |   for ((peer) = (devConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { | ||||||
|  |     auto PeerConfig = Peer(); | ||||||
|  |     if (peer->flags & WGPEER_HAS_PRESHARED_KEY) PeerConfig.presharedKey = wgKeys::toString(peer->preshared_key); | ||||||
|  |     if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) PeerConfig.keepInterval = peer->persistent_keepalive_interval; | ||||||
|  |     if (peer->endpoint.addr.sa_family == AF_INET||peer->endpoint.addr.sa_family == AF_INET6) PeerConfig.endpoint = HostAdresses(true, &peer->endpoint.addr); | ||||||
|  |  | ||||||
|  |     PeerConfig.lastHandshake = peer->last_handshake_time.tv_sec*1000; | ||||||
|  |     PeerConfig.rxBytes = peer->rx_bytes; | ||||||
|  |     PeerConfig.txBytes = peer->tx_bytes; | ||||||
|  |  | ||||||
|  |     wg_allowedip *allowedip; | ||||||
|  |     for ((allowedip) = (peer)->first_allowedip; (allowedip); (allowedip) = (allowedip)->next_allowedip) { | ||||||
|  |       static char buf[INET6_ADDRSTRLEN + 1]; | ||||||
|  |       memset(buf, 0, INET6_ADDRSTRLEN + 1); | ||||||
|  |       if (allowedip->family == AF_INET) inet_ntop(AF_INET, &allowedip->ip4, buf, INET6_ADDRSTRLEN); | ||||||
|  |       else if (allowedip->family == AF_INET6) inet_ntop(AF_INET6, &allowedip->ip6, buf, INET6_ADDRSTRLEN); | ||||||
|  |       PeerConfig.allowedIPs.push_back(std::string(buf).append("/").append(std::to_string(allowedip->cidr))); | ||||||
|  |     } | ||||||
|  |     this->Peers[wgKeys::toString(peer->public_key)] = PeerConfig; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WireguardConfig::setWireguardConfig() { | ||||||
|  |   int status; | ||||||
|  |   if (this->name.length() > IFNAMSIZ) throw std::string("Wireguard interface name is long, max name length is ").append(std::to_string(IFNAMSIZ)); | ||||||
|  |   else if (!(WireguardDevices().exist(this->name)) && (status = wg_add_device(this->name.c_str())) < 0) throw std::string("Unable to create Wireguard interface, code: ").append(std::to_string(status)); | ||||||
|  |   if (this->privateKey.length() != Base64WgKeyLength) throw std::string("Set Wireguard interface private key!"); | ||||||
|  |  | ||||||
|  |   auto wgConfig = new wg_device({}); | ||||||
|  |   if (!wgConfig) throw std::string("Cannot alloc memory to set interface configuration!"); | ||||||
|  |   strncpy(wgConfig->name, this->name.c_str(), this->name.length()); | ||||||
|  |  | ||||||
|  |   wgConfig->flags = wg_device_flags::WGDEVICE_HAS_PRIVATE_KEY; | ||||||
|  |   wgKeys::stringToKey(wgConfig->private_key, this->privateKey); | ||||||
|  |  | ||||||
|  |   if (this->replacePeers) wgConfig->flags = (wg_device_flags)(wgConfig->flags|wg_device_flags::WGDEVICE_REPLACE_PEERS); | ||||||
|  |  | ||||||
|  |   if (this->publicKey.length() == Base64WgKeyLength) { | ||||||
|  |     wgConfig->flags = (wg_device_flags)(wgConfig->flags|wg_device_flags::WGDEVICE_HAS_PUBLIC_KEY); | ||||||
|  |     wgKeys::stringToKey(wgConfig->public_key, this->publicKey); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->portListen >= 0) { | ||||||
|  |     wgConfig->flags = (wg_device_flags)(wgConfig->flags|wg_device_flags::WGDEVICE_HAS_LISTEN_PORT); | ||||||
|  |     wgConfig->listen_port = this->portListen; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->fwmark >= 0) { | ||||||
|  |     wgConfig->flags = (wg_device_flags)(wgConfig->flags|wg_device_flags::WGDEVICE_HAS_FWMARK); | ||||||
|  |     wgConfig->fwmark = this->fwmark; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (auto &PeerConfig : this->Peers) { | ||||||
|  |     auto peer = new wg_peer({}); | ||||||
|  |     peer->flags = wg_peer_flags::WGPEER_HAS_PUBLIC_KEY; | ||||||
|  |     wgKeys::stringToKey(peer->public_key, PeerConfig.first); | ||||||
|  |     if (PeerConfig.second.removeMe) peer->flags = (wg_peer_flags)(peer->flags|wg_peer_flags::WGPEER_REMOVE_ME); | ||||||
|  |     else { | ||||||
|  |       if (PeerConfig.second.presharedKey.length() == Base64WgKeyLength) { | ||||||
|  |         peer->flags = (wg_peer_flags)(peer->flags|wg_peer_flags::WGPEER_HAS_PRESHARED_KEY); | ||||||
|  |         wgKeys::stringToKey(peer->preshared_key, PeerConfig.second.presharedKey); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (PeerConfig.second.keepInterval > 0) { | ||||||
|  |         peer->flags = (wg_peer_flags)(peer->flags|wg_peer_flags::WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL); | ||||||
|  |         peer->persistent_keepalive_interval = PeerConfig.second.keepInterval; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (PeerConfig.second.endpoint.length() > 0) { | ||||||
|  |         sockaddr endpoint; int ret, retries; | ||||||
|  |         char *begin, *end, *Endpoint = strdup(PeerConfig.second.endpoint.c_str()); | ||||||
|  |         if (Endpoint[0] == '[') { | ||||||
|  |           begin = &Endpoint[1]; | ||||||
|  |           end = strchr(Endpoint, ']'); | ||||||
|  |           if (!end) { | ||||||
|  |             for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; } | ||||||
|  |             delete wgConfig; | ||||||
|  |             free(Endpoint); | ||||||
|  |             throw std::string("Unable to find matching brace of endpoint"); | ||||||
|  |             return; | ||||||
|  |           } | ||||||
|  |           *end++ = '\0'; | ||||||
|  |           if (*end++ != ':' || !*end) { | ||||||
|  |             for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; } | ||||||
|  |             delete wgConfig; | ||||||
|  |             free(Endpoint); | ||||||
|  |             throw std::string("Unable to find port of endpoint"); | ||||||
|  |             return; | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           begin = Endpoint; | ||||||
|  |           end = strrchr(Endpoint, ':'); | ||||||
|  |           if (!end || !*(end + 1)) { | ||||||
|  |             for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; } | ||||||
|  |             delete wgConfig; | ||||||
|  |             free(Endpoint); | ||||||
|  |             throw std::string("Unable to find port of endpoint"); | ||||||
|  |           } | ||||||
|  |           *end++ = '\0'; | ||||||
|  |         } | ||||||
|  |         addrinfo *resolved, hints = { ai_family: AF_UNSPEC, ai_socktype: SOCK_DGRAM, ai_protocol: IPPROTO_UDP }; | ||||||
|  |         for (unsigned int timeout = 1000000;; timeout = ((20000000) < (timeout * 6 / 5) ? (20000000) : (timeout * 6 / 5))) { | ||||||
|  |           ret = getaddrinfo(begin, end, &hints, &resolved); | ||||||
|  |           if (!ret) break; | ||||||
|  |           if (ret == EAI_NONAME || ret == EAI_FAIL || | ||||||
|  |             #ifdef EAI_NODATA | ||||||
|  |               ret == EAI_NODATA || | ||||||
|  |             #endif | ||||||
|  |           (retries >= 0 && !retries--)) { | ||||||
|  |             for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; } | ||||||
|  |             delete wgConfig; | ||||||
|  |             free(Endpoint); | ||||||
|  |             fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), PeerConfig.second.endpoint.c_str()); | ||||||
|  |             throw std::string("Unable to resolve endpoint"); | ||||||
|  |             return; | ||||||
|  |           } | ||||||
|  |           fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), PeerConfig.second.endpoint.c_str(), timeout / 1000000.0); | ||||||
|  |           usleep(timeout); | ||||||
|  |         } | ||||||
|  |         if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(sockaddr_in)) || (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(sockaddr_in6))) { | ||||||
|  |           memcpy(&endpoint, resolved->ai_addr, resolved->ai_addrlen); | ||||||
|  |           memccpy(&peer->endpoint.addr, &endpoint, 0, sizeof(peer->endpoint.addr)); | ||||||
|  |           if (resolved->ai_family == AF_INET) { | ||||||
|  |             peer->endpoint.addr4.sin_addr.s_addr = ((sockaddr_in *)&endpoint)->sin_addr.s_addr; | ||||||
|  |             peer->endpoint.addr4.sin_port = ((sockaddr_in *)&endpoint)->sin_port; | ||||||
|  |             peer->endpoint.addr4.sin_family = AF_INET; | ||||||
|  |           } else { | ||||||
|  |             peer->endpoint.addr6.sin6_addr = ((struct sockaddr_in6 *)&endpoint)->sin6_addr; | ||||||
|  |             peer->endpoint.addr6.sin6_port = ((struct sockaddr_in6 *)&endpoint)->sin6_port; | ||||||
|  |             peer->endpoint.addr6.sin6_family = AF_INET6; | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           freeaddrinfo(resolved); | ||||||
|  |           for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; } | ||||||
|  |           delete wgConfig; | ||||||
|  |           free(Endpoint); | ||||||
|  |           throw std::string("Neither IPv4 nor IPv6 address found"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         freeaddrinfo(resolved); | ||||||
|  |         // Free memory | ||||||
|  |         for ((peer) = (wgConfig)->first_peer; (peer); (peer) = (peer)->next_peer) { delete peer; } | ||||||
|  |         delete wgConfig; | ||||||
|  |         free(Endpoint); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       for (const auto Ip : PeerConfig.second.allowedIPs.getIpParsed()) { | ||||||
|  |         if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS) peer->flags = (wg_peer_flags)(peer->flags|WGPEER_REPLACE_ALLOWEDIPS); | ||||||
|  |         auto newAllowedIP = new wg_allowedip({}); | ||||||
|  |         newAllowedIP->cidr = Ip.Mask; | ||||||
|  |         if (Ip.Proto == 6 && inet_pton(AF_INET6, Ip.Address.c_str(), &newAllowedIP->ip6) == 1) newAllowedIP->family = AF_INET6; | ||||||
|  |         else if (Ip.Proto == 4 && inet_pton(AF_INET, Ip.Address.c_str(), &newAllowedIP->ip4) == 1) newAllowedIP->family = AF_INET; | ||||||
|  |         else { | ||||||
|  |           delete newAllowedIP; | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (peer->first_allowedip) newAllowedIP->next_allowedip = peer->first_allowedip; | ||||||
|  |         peer->first_allowedip = newAllowedIP; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (wgConfig->first_peer) peer->next_peer = wgConfig->first_peer; | ||||||
|  |     wgConfig->first_peer = peer; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Set config | ||||||
|  |   status = wg_set_device(wgConfig); | ||||||
|  |  | ||||||
|  |   // Free memory | ||||||
|  |   for (wg_peer* peer = wgConfig->first_peer; peer; peer = peer->next_peer) { | ||||||
|  |     for (wg_allowedip *newAllowedIP = peer->first_allowedip; newAllowedIP; newAllowedIP = newAllowedIP->next_allowedip) delete newAllowedIP; | ||||||
|  |     delete peer; | ||||||
|  |   } | ||||||
|  |   delete wgConfig; | ||||||
|  |  | ||||||
|  |   // Return status to tool | ||||||
|  |   if (status < 0) throw std::string("Unable to configure settings, code: ").append(std::to_string(status)); | ||||||
|  |   else { | ||||||
|  |     this->interfaceAddress.SetInInterface(this->name); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IpManeger::GetInInterface(std::string interfaceName) { | ||||||
|  |   ifaddrs* ptr_ifaddrs = nullptr; | ||||||
|  |   if(getifaddrs(&ptr_ifaddrs) >= 0) { | ||||||
|  |     for (ifaddrs* ptr_entry = ptr_ifaddrs; ptr_entry != nullptr; ptr_entry = ptr_entry->ifa_next) { | ||||||
|  |       if (ptr_entry->ifa_addr == nullptr) continue; | ||||||
|  |       else if (strcmp(ptr_entry->ifa_name, interfaceName.c_str()) != 0) continue; | ||||||
|  |       else if (ptr_entry->ifa_addr->sa_family == AF_INET) this->addIPMask(HostAdresses(false, ptr_entry->ifa_addr)); | ||||||
|  |       else if (ptr_entry->ifa_addr->sa_family == AF_INET6) this->addIPMask(HostAdresses(false, ptr_entry->ifa_addr)); | ||||||
|  |     } | ||||||
|  |     freeifaddrs(ptr_ifaddrs); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct rtnl_handle { | ||||||
|  |   int fd; | ||||||
|  |   struct sockaddr_nl local; | ||||||
|  |   struct sockaddr_nl peer; | ||||||
|  |   __u32 seq; | ||||||
|  |   __u32 dump; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |   __u8 family; | ||||||
|  |   __u8 bytelen; | ||||||
|  |   __s16 bitlen; | ||||||
|  |   __u32 flags; | ||||||
|  |   __u32 data[8]; | ||||||
|  | } inet_prefix; | ||||||
|  |  | ||||||
|  | // This function is to open the netlink socket as the name suggests. | ||||||
|  | void netlink_open(struct rtnl_handle* rth) { | ||||||
|  |   int addr_len; | ||||||
|  |   memset(rth, 0, sizeof(rth)); | ||||||
|  |  | ||||||
|  |   // Creating the netlink socket of family NETLINK_ROUTE | ||||||
|  |  | ||||||
|  |   rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | ||||||
|  |   if (rth->fd < 0) throw std::string("cannot open netlink socket"); | ||||||
|  |   memset(&rth->local, 0, sizeof(rth->local)); | ||||||
|  |   rth->local.nl_family = AF_NETLINK; | ||||||
|  |   rth->local.nl_groups = 0; | ||||||
|  |  | ||||||
|  |   // Binding the netlink socket | ||||||
|  |   if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) throw std::string("cannot bind netlink socket"); | ||||||
|  |  | ||||||
|  |   addr_len = sizeof(rth->local); | ||||||
|  |   if (getsockname(rth->fd, (struct sockaddr*)&rth->local, (socklen_t*) &addr_len) < 0) throw std::string("cannot getsockname"); | ||||||
|  |   if (addr_len != sizeof(rth->local)) throw std::string("wrong address lenght").append(std::to_string(addr_len)); | ||||||
|  |   if (rth->local.nl_family != AF_NETLINK) throw std::string("wrong address family").append(std::to_string(rth->local.nl_family)); | ||||||
|  |  | ||||||
|  |   rth->seq = time(NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // This function does the actual reading and writing to the netlink socket | ||||||
|  | int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, unsigned groups, struct nlmsghdr *answer) { | ||||||
|  |   int status; | ||||||
|  |   struct nlmsghdr *h; | ||||||
|  |   struct sockaddr_nl nladdr; | ||||||
|  |   // Forming the iovector with the netlink packet. | ||||||
|  |   struct iovec iov = { (void*)n, n->nlmsg_len }; | ||||||
|  |   char buf[8192]; | ||||||
|  |   // Forming the message to be sent. | ||||||
|  |   struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; | ||||||
|  |   // Filling up the details of the netlink socket to be contacted in the | ||||||
|  |   // kernel. | ||||||
|  |   memset(&nladdr, 0, sizeof(nladdr)); | ||||||
|  |   nladdr.nl_family = AF_NETLINK; | ||||||
|  |   nladdr.nl_pid = peer; | ||||||
|  |   nladdr.nl_groups = groups; | ||||||
|  |   n->nlmsg_seq = ++rtnl->seq; | ||||||
|  |   if (answer == NULL) n->nlmsg_flags |= NLM_F_ACK; | ||||||
|  |   // Actual sending of the message, status contains success/failure | ||||||
|  |   return sendmsg(rtnl->fd, &msg, 0); | ||||||
|  |   // if (status < 0) return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // This is the utility function for adding the parameters to the packet. | ||||||
|  | int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) { | ||||||
|  |   int len = RTA_LENGTH(alen); | ||||||
|  |   struct rtattr *rta; | ||||||
|  |  | ||||||
|  |   if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) | ||||||
|  |     return -1; | ||||||
|  |   rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); | ||||||
|  |   rta->rta_type = type; | ||||||
|  |   rta->rta_len = len; | ||||||
|  |   memcpy(RTA_DATA(rta), data, alen); | ||||||
|  |   n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IpManeger::SetInInterface(std::string interfaceName) { | ||||||
|  |   if (this->size() == 0) return; | ||||||
|  |   if (!(WireguardDevices().exist(interfaceName))) throw std::string("Wireguard interface not exists!"); | ||||||
|  |   int status; | ||||||
|  |   unsigned int ifa_index; | ||||||
|  |   wg_device *devConfig; | ||||||
|  |  | ||||||
|  |   if ((status = wg_get_device(&devConfig, interfaceName.c_str())) < 0) throw std::string("It was not possible to get the Wireguard interface settings, code: ").append(std::to_string(status)); | ||||||
|  |  | ||||||
|  |   ifa_index = devConfig->ifindex; | ||||||
|  |   free(devConfig); | ||||||
|  |  | ||||||
|  |   for (const auto ip : this->getIpParsed()) { | ||||||
|  |     struct rtnl_handle * rth; | ||||||
|  |     rth = (rtnl_handle*)malloc(sizeof(rtnl_handle)); | ||||||
|  |     netlink_open(rth); | ||||||
|  |     int err; | ||||||
|  |     inet_prefix lcl; | ||||||
|  |  | ||||||
|  |     // structure of the netlink packet. | ||||||
|  |     struct { | ||||||
|  |       struct nlmsghdr n; | ||||||
|  |       struct ifaddrmsg ifa; | ||||||
|  |       char buf[1024]; | ||||||
|  |     } req; | ||||||
|  |  | ||||||
|  |     memset(&req, 0, sizeof(req)); | ||||||
|  |     req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); | ||||||
|  |     req.n.nlmsg_type = RTM_NEWADDR; | ||||||
|  |     req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST; | ||||||
|  |  | ||||||
|  |     req.ifa.ifa_family = ip.Proto == 4 ? AF_INET : AF_INET6; | ||||||
|  |     req.ifa.ifa_prefixlen = ip.Mask; | ||||||
|  |     req.ifa.ifa_index = ifa_index ; // get the loopback index | ||||||
|  |     req.ifa.ifa_scope = 0; | ||||||
|  |  | ||||||
|  |     memset(&lcl, 0, sizeof(lcl)); | ||||||
|  |     lcl.family = req.ifa.ifa_family; | ||||||
|  |     lcl.bytelen = (req.ifa.ifa_family == AF_INET) ? 4 : 16; | ||||||
|  |     lcl.bitlen = (req.ifa.ifa_family == AF_INET) ? 32 : 128; | ||||||
|  |  | ||||||
|  |     if (inet_pton(req.ifa.ifa_family, ip.Address.c_str(), &lcl.data) <= 0) throw std::string("Invalid IP address: ").append(ip.Address); | ||||||
|  |     if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = lcl.family; | ||||||
|  |  | ||||||
|  |     addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); | ||||||
|  |     if ((err = rtnl_talk(rth, &req.n, 0, 0, NULL)) < 0) throw std::string("Cannot set interface IP, code: ").append(std::to_string(err)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Get INET socket | ||||||
|  |   int sockfd = socket(AF_INET, SOCK_DGRAM, 0); | ||||||
|  |   if (sockfd < 0) throw std::string("Error creating socket to set interface flags"); | ||||||
|  |  | ||||||
|  |   struct ifreq ifr; | ||||||
|  |   strcpy(ifr.ifr_name, interfaceName.c_str()); | ||||||
|  |  | ||||||
|  |   // Set interface flags | ||||||
|  |   ifr.ifr_flags = IFF_POINTOPOINT | IFF_NOARP | IFF_UP | IFF_RUNNING; | ||||||
|  |   if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { | ||||||
|  |     close(sockfd); | ||||||
|  |     throw std::string("Error setting interface flags"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   close(sockfd); | ||||||
|  | } | ||||||
							
								
								
									
										83
									
								
								addon/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								addon/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | #include "wg.hh" | ||||||
|  | #include <napi.h> | ||||||
|  |  | ||||||
|  | Napi::Object StartAddon(const Napi::Env env, const Napi::Object exports) { | ||||||
|  |   std::map<std::string, std::string> LoadConfig; | ||||||
|  |   const Napi::Array keysOnLoadsNames = exports.GetPropertyNames(); | ||||||
|  |   for (unsigned int keyIndex = 0; keyIndex < keysOnLoadsNames.Length(); keyIndex++) { | ||||||
|  |     if (!(exports.Get(keysOnLoadsNames[keyIndex]).IsString())) continue; | ||||||
|  |     LoadConfig[keysOnLoadsNames[keyIndex].ToString().Utf8Value()] = exports.Get(keysOnLoadsNames[keyIndex]).ToString().Utf8Value(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   #ifdef _WIN32 | ||||||
|  |   std::string statusLoading = driveLoad(LoadConfig); | ||||||
|  |   if (!!(statusLoading.length())) { | ||||||
|  |     Napi::Error::New(env, statusLoading).ThrowAsJavaScriptException(); | ||||||
|  |     return exports; | ||||||
|  |   } | ||||||
|  |   #endif | ||||||
|  |  | ||||||
|  |   const Napi::Object Constants = Napi::Object::New(env); | ||||||
|  |   if (getWireguardVersion().length() > 0) Constants.Set("driveVersion", getWireguardVersion()); | ||||||
|  |  | ||||||
|  |   exports.Set("deleteInterface", Napi::Function::New(env, [](const Napi::CallbackInfo &info) -> Napi::Value { | ||||||
|  |     const Napi::Env env = info.Env(); | ||||||
|  |     if (!(info[0].IsString())) { | ||||||
|  |       Napi::Error::New(env, "Set interface name").ThrowAsJavaScriptException(); | ||||||
|  |       return env.Undefined(); | ||||||
|  |     } | ||||||
|  |     try { | ||||||
|  |       DeleteInterface *worker = new DeleteInterface(env, info[0].ToString()); | ||||||
|  |       worker->Queue(); | ||||||
|  |       return worker->NodePromise.Promise(); | ||||||
|  |     } catch (std::string &err) { | ||||||
|  |       Napi::Error::New(env, err).ThrowAsJavaScriptException(); | ||||||
|  |       return env.Undefined(); | ||||||
|  |     } | ||||||
|  |   })); | ||||||
|  |  | ||||||
|  |   exports.Set("listDevices", Napi::Function::New(env, [](const Napi::CallbackInfo &info) -> Napi::Value { | ||||||
|  |     const Napi::Env env = info.Env(); | ||||||
|  |     try { | ||||||
|  |       ListDevices *worker = new ListDevices(env); | ||||||
|  |       worker->Queue(); | ||||||
|  |       return worker->NodePromise.Promise(); | ||||||
|  |     } catch (std::string &err) { | ||||||
|  |       Napi::Error::New(env, err).ThrowAsJavaScriptException(); | ||||||
|  |       return env.Undefined(); | ||||||
|  |     } | ||||||
|  |   })); | ||||||
|  |  | ||||||
|  |   exports.Set("setConfig", Napi::Function::New(env, [](const Napi::CallbackInfo &info) -> Napi::Value { | ||||||
|  |     const Napi::Env env = info.Env(); | ||||||
|  |     if (!(info[0].IsObject())) Napi::Error::New(env, "Set wireguard config!").ThrowAsJavaScriptException(); | ||||||
|  |     try { | ||||||
|  |       SetConfig *worker = new SetConfig(env, info[0].ToObject()); | ||||||
|  |       worker->Queue(); | ||||||
|  |       return worker->NodePromise.Promise(); | ||||||
|  |     } catch (std::string &err) { | ||||||
|  |       Napi::Error::New(env, err).ThrowAsJavaScriptException(); | ||||||
|  |     } | ||||||
|  |     return env.Undefined(); | ||||||
|  |   })); | ||||||
|  |  | ||||||
|  |   exports.Set("getConfig", Napi::Function::New(env, [](const Napi::CallbackInfo &info) -> Napi::Value { | ||||||
|  |     const Napi::Env env = info.Env(); | ||||||
|  |     if (!(info[0].IsString())) { | ||||||
|  |       Napi::Error::New(env, "Set interface name in fist argument!").ThrowAsJavaScriptException(); | ||||||
|  |       return env.Undefined(); | ||||||
|  |     } | ||||||
|  |     try { | ||||||
|  |       GetConfig *worker = new GetConfig(env, info[0].ToString()); | ||||||
|  |       worker->Queue(); | ||||||
|  |       return worker->NodePromise.Promise(); | ||||||
|  |     } catch (std::string &err) { | ||||||
|  |       Napi::Error::New(env, err).ThrowAsJavaScriptException(); | ||||||
|  |       return env.Undefined(); | ||||||
|  |     } | ||||||
|  |   })); | ||||||
|  |  | ||||||
|  |   exports.Set("constants", Constants); | ||||||
|  |   return exports; | ||||||
|  | } | ||||||
|  | NODE_API_MODULE(addon, StartAddon); | ||||||
							
								
								
									
										14
									
								
								addon/userspace/go/go.mod
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								addon/userspace/go/go.mod
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | module sirherobrine23.org/Wireguard/wireguard-tools.js/wg-tun | ||||||
|  |  | ||||||
|  | go 1.21.6 | ||||||
|  |  | ||||||
|  | require ( | ||||||
|  | 	golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | require ( | ||||||
|  | 	golang.org/x/sys v0.12.0 // indirect | ||||||
|  | 	golang.org/x/crypto v0.13.0 // indirect | ||||||
|  | 	golang.org/x/net v0.15.0 // indirect | ||||||
|  | 	golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect | ||||||
|  | ) | ||||||
							
								
								
									
										16
									
								
								addon/userspace/go/go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								addon/userspace/go/go.sum
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= | ||||||
|  | github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= | ||||||
|  | golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= | ||||||
|  | golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= | ||||||
|  | golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= | ||||||
|  | golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= | ||||||
|  | golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= | ||||||
|  | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= | ||||||
|  | golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||||
|  | golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= | ||||||
|  | golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= | ||||||
|  | golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= | ||||||
|  | golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= | ||||||
|  | gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259 h1:TbRPT0HtzFP3Cno1zZo7yPzEEnfu8EjLfl6IU9VfqkQ= | ||||||
|  | gvisor.dev/gvisor v0.0.0-20230927004350-cbd86285d259/go.mod h1:AVgIgHMwK63XvmAzWG9vLQ41YnVHN0du0tEC46fI7yY= | ||||||
							
								
								
									
										211
									
								
								addon/userspace/go/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								addon/userspace/go/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,211 @@ | |||||||
|  | package main | ||||||
|  |  | ||||||
|  | import "C" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"os" | ||||||
|  | 	"os/signal" | ||||||
|  | 	"runtime/debug" | ||||||
|  | 	"strings" | ||||||
|  | 	"syscall" | ||||||
|  |  | ||||||
|  | 	"golang.zx2c4.com/wireguard/conn" | ||||||
|  | 	"golang.zx2c4.com/wireguard/device" | ||||||
|  | 	"golang.zx2c4.com/wireguard/ipc" | ||||||
|  | 	"golang.zx2c4.com/wireguard/tun" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const levelLog = device.LogLevelError | ||||||
|  |  | ||||||
|  | // End process function callbacks | ||||||
|  | var TunsEndProcess = make(map[string]func()) | ||||||
|  |  | ||||||
|  | //export callEndProcess | ||||||
|  | func callEndProcess() { | ||||||
|  | 	for _, f := range TunsEndProcess { | ||||||
|  | 		f() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func main() {} | ||||||
|  | func init() { | ||||||
|  | 	c := make(chan os.Signal, 1) | ||||||
|  | 	signal.Notify(c, os.Interrupt, syscall.SIGTERM) | ||||||
|  | 	go func() { | ||||||
|  | 		<-c | ||||||
|  | 		callEndProcess() | ||||||
|  | 	}() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Get wireguard-go version | ||||||
|  | // | ||||||
|  | //export wgVersion | ||||||
|  | func wgVersion() *C.char { | ||||||
|  | 	info, ok := debug.ReadBuildInfo() | ||||||
|  | 	if !ok { | ||||||
|  | 		return C.CString("unknown") | ||||||
|  | 	} | ||||||
|  | 	for _, dep := range info.Deps { | ||||||
|  | 		if dep.Path == "golang.zx2c4.com/wireguard" { | ||||||
|  | 			return C.CString(dep.Version) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return C.CString("unknown") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Check if tunnel exist | ||||||
|  | // | ||||||
|  | //export existTun | ||||||
|  | func existTun(tunName string) bool { | ||||||
|  | 	Files, err := os.ReadDir(socketDirectory) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	for _, file := range Files { | ||||||
|  | 		if file.IsDir() { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		splits := strings.Split(file.Name(), "/") | ||||||
|  | 		splits[len(splits)-1] = strings.TrimSuffix(splits[len(splits)-1], ".sock") | ||||||
|  | 		if splits[len(splits)-1] == tunName { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Delete wireguard tunnel if exist | ||||||
|  | // | ||||||
|  | //export deleteTun | ||||||
|  | func deleteTun(_tunName *C.char) *C.char { | ||||||
|  | 	tunName := C.GoString(_tunName) | ||||||
|  | 	if !existTun(tunName) { | ||||||
|  | 		return C.CString("Tun does not exist") | ||||||
|  | 	} | ||||||
|  | 	Files, err := os.ReadDir(socketDirectory) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return C.CString("Tun does not exist") | ||||||
|  | 	} | ||||||
|  | 	for _, file := range Files { | ||||||
|  | 		if file.IsDir() { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		splits := strings.Split(file.Name(), "/") | ||||||
|  | 		splits[len(splits)-1] = strings.TrimSuffix(splits[len(splits)-1], ".sock") | ||||||
|  | 		if splits[len(splits)-1] == tunName { | ||||||
|  | 			os.Remove(strings.Join(([]string{socketDirectory, file.Name()}), "/")) | ||||||
|  | 			return C.CString("") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return C.CString("Tun does not exist") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Create wireguard tunnel | ||||||
|  | // | ||||||
|  | //export createTun | ||||||
|  | func createTun(_tunName *C.char) *C.char { | ||||||
|  | 	interfaceName := C.GoString(_tunName) | ||||||
|  | 	if existTun(interfaceName) { | ||||||
|  | 		errStr := C.GoString(deleteTun(_tunName)) | ||||||
|  | 		if errStr != "" { | ||||||
|  | 			return C.CString(errStr) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	logger := device.NewLogger(levelLog, fmt.Sprintf("(%s) ", interfaceName)) | ||||||
|  |  | ||||||
|  | 	// open TUN device (or use supplied fd) | ||||||
|  | 	tdev, err := tun.CreateTUN(interfaceName, device.DefaultMTU) | ||||||
|  | 	if err == nil { | ||||||
|  | 		realInterfaceName, err2 := tdev.Name() | ||||||
|  | 		if err2 == nil { | ||||||
|  | 			interfaceName = realInterfaceName | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		return C.CString(fmt.Sprintf("Failed to create TUN device: %v", err)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// open UAPI file (or use supplied fd) | ||||||
|  | 	fileUAPI, err := ipc.UAPIOpen(interfaceName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		tdev.Close() | ||||||
|  | 		return C.CString(fmt.Sprintf("Failed to open UAPI file: %v", err)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// create device | ||||||
|  | 	dev := device.NewDevice(tdev, conn.NewDefaultBind(), logger) | ||||||
|  |  | ||||||
|  | 	uapi, err := ipc.UAPIListen(interfaceName, fileUAPI) | ||||||
|  | 	if err != nil { | ||||||
|  | 		dev.Close() | ||||||
|  | 		tdev.Close() | ||||||
|  | 		return C.CString(fmt.Sprintf("Failed to listen on UAPI file: %v", err)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// UAPI Listener | ||||||
|  | 	uapiListened := uapi.Addr().String() | ||||||
|  |  | ||||||
|  | 	clean := func() { | ||||||
|  | 		logger.Verbosef("Shutting down") | ||||||
|  |  | ||||||
|  | 		uapi.Close() | ||||||
|  | 		dev.Close() | ||||||
|  | 		tdev.Close() | ||||||
|  | 		if uapiListened[:1] == "/" { | ||||||
|  | 			os.Remove(uapiListened) | ||||||
|  | 		} | ||||||
|  | 		delete(TunsEndProcess, uapiListened) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	TunsEndProcess[uapiListened] = clean | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
|  | 		for { | ||||||
|  | 			conn, err := uapi.Accept() | ||||||
|  | 			if err != nil { | ||||||
|  | 				logger.Verbosef("UAPI listener closed") | ||||||
|  | 				clean() | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 			logger.Verbosef("UAPI recive message") | ||||||
|  | 			go dev.IpcHandle(conn) | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
|  | 		logger.Verbosef("Device started") | ||||||
|  | 		<-dev.Wait() | ||||||
|  | 		logger.Verbosef("Device closing") | ||||||
|  | 		clean() | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	// Wait for device listener socket to be ready | ||||||
|  | 	for { | ||||||
|  | 		_, err := os.Stat(uapiListened) | ||||||
|  | 		if err == nil { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return C.CString("") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // List wireguard-go UAPI's sockets | ||||||
|  | // first\0second\0third\0forth\0last\0\0 | ||||||
|  | // | ||||||
|  | //export listUapis | ||||||
|  | func listUapis() *C.char { | ||||||
|  | 	Files, err := os.ReadDir(socketDirectory) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return C.CString("") | ||||||
|  | 	} | ||||||
|  | 	var uapis []string | ||||||
|  | 	for _, file := range Files { | ||||||
|  | 		if file.IsDir() { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		uapis = append(uapis, strings.Join(([]string{socketDirectory, file.Name()}), "/")) | ||||||
|  | 	} | ||||||
|  | 	return C.CString(strings.Join(uapis, "\x00") + "\x00") | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								addon/userspace/go/main_unix.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								addon/userspace/go/main_unix.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | //go:build linux || darwin || freebsd || openbsd | ||||||
|  |  | ||||||
|  | package main | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	_ "golang.zx2c4.com/wireguard/ipc" | ||||||
|  | 	_ "unsafe" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | //go:linkname socketDirectory golang.xz2c4.com/wireguard/ipc.socketDirectory | ||||||
|  | var socketDirectory = "/var/run/wireguard" | ||||||
							
								
								
									
										5
									
								
								addon/userspace/go/main_windows.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								addon/userspace/go/main_windows.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | //go:build windows | ||||||
|  |  | ||||||
|  | package main | ||||||
|  |  | ||||||
|  | var socketDirectory = `\\.\pipe\ProtectedPrefix\Administrators\WireGuard` | ||||||
							
								
								
									
										54
									
								
								addon/userspace/ipc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								addon/userspace/ipc.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <dirent.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <sys/socket.h> | ||||||
|  | #include <sys/stat.h> | ||||||
|  | #include <sys/un.h> | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | FILE *interfaceFile(std::string sockPath) { | ||||||
|  |   struct stat sbuf; | ||||||
|  |   struct sockaddr_un addr = { .sun_family = AF_UNIX }; | ||||||
|  |   int fd = -1, ret; | ||||||
|  |   FILE *f = NULL; | ||||||
|  |  | ||||||
|  |   errno = EINVAL; | ||||||
|  |   ret = snprintf(addr.sun_path, sizeof(addr.sun_path), sockPath.c_str()); | ||||||
|  |   if (ret < 0) | ||||||
|  |     goto out; | ||||||
|  |  | ||||||
|  |   ret = stat(addr.sun_path, &sbuf); | ||||||
|  |   if (ret < 0) | ||||||
|  |     goto out; | ||||||
|  |  | ||||||
|  |   errno = EBADF; | ||||||
|  |   if (!S_ISSOCK(sbuf.st_mode)) | ||||||
|  |     goto out; | ||||||
|  |  | ||||||
|  |   ret = fd = socket(AF_UNIX, SOCK_STREAM, 0); | ||||||
|  |   if (ret < 0) | ||||||
|  |     goto out; | ||||||
|  |  | ||||||
|  |   ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); | ||||||
|  |   if (ret < 0) { | ||||||
|  |     if (errno == ECONNREFUSED) /* If the process is gone, we try to clean up the socket. */ | ||||||
|  |       unlink(addr.sun_path); | ||||||
|  |     goto out; | ||||||
|  |   } | ||||||
|  |   f = fdopen(fd, "r+"); | ||||||
|  |   if (f) | ||||||
|  |     errno = 0; | ||||||
|  | out: | ||||||
|  |   ret = -errno; | ||||||
|  |   if (ret) { | ||||||
|  |     if (fd >= 0) | ||||||
|  |       close(fd); | ||||||
|  |     errno = -ret; | ||||||
|  |     return NULL; | ||||||
|  |   } | ||||||
|  |   return f; | ||||||
|  | } | ||||||
							
								
								
									
										176
									
								
								addon/userspace/wginterface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								addon/userspace/wginterface.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,176 @@ | |||||||
|  | #include "wginterface.hh" | ||||||
|  | #include "userspace/wg-go.h" | ||||||
|  | #include "userspace/ipc.cpp" | ||||||
|  | #include "genKey/wgkeys.hh" | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | #include <arpa/inet.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <limits.h> | ||||||
|  | #include <net/if.h> | ||||||
|  | #include <netdb.h> | ||||||
|  | #include <netinet/in.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <sys/socket.h> | ||||||
|  |  | ||||||
|  | // Ignore if required to windows | ||||||
|  | std::string driveLoad(std::map<std::string, std::string> load) {} | ||||||
|  |  | ||||||
|  | std::string getWireguardVersion() { | ||||||
|  |   return std::string(wgVersion()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WireguardDevices::getInterfaces() { | ||||||
|  |   size_t len; char *device_name, *devicesList = listUapis(); | ||||||
|  |   for (device_name = devicesList, len = 0; (len = strlen(device_name)); device_name += len + 1) this->push_back(std::string(device_name)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WireguardDevices::deleteInterface(std::string wgName) { | ||||||
|  |   std::string deleteStatus = deleteTun((char*)wgName.c_str()); | ||||||
|  |   if (!deleteStatus.empty()) throw deleteStatus; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool char_is_digit(int c) { | ||||||
|  | 	return (unsigned int)(('0' - 1 - c) & (c - ('9' + 1))) >> (sizeof(c) * 8 - 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WireguardConfig::getWireguardConfig() { | ||||||
|  |   if (this->name.length() == 0) throw std::string("Set wireguard name!"); | ||||||
|  |   else if (!(WireguardDevices().exist(this->name))) throw std::string("Wireguard interface not exist"); | ||||||
|  |   size_t line_buffer_len = 0, line_len; | ||||||
|  | 	char *key = NULL, *value; | ||||||
|  | 	int ret = -EPROTO; | ||||||
|  | 	FILE *f = interfaceFile(WireguardDevices().findSock(this->name).c_str()); | ||||||
|  |   if (!f) throw std::string("Failed to open interface file"); | ||||||
|  |   fprintf(f, "get=1\n\n"); | ||||||
|  |   fflush(f); | ||||||
|  |   std::string peerPubKey; | ||||||
|  |   bool peer = false; | ||||||
|  |  | ||||||
|  |   while (getline(&key, &line_buffer_len, f) > 0) { | ||||||
|  |     line_len = strlen(key); | ||||||
|  | 		if (line_len == 1 && key[0] == '\n') return; | ||||||
|  | 		value = strchr(key, '='); | ||||||
|  | 		if (!value || line_len == 0 || key[line_len - 1] != '\n') break; | ||||||
|  | 		*value++ = key[--line_len] = '\0'; | ||||||
|  |  | ||||||
|  | 		if (this->Peers.size() == 0 && !strcmp(key, "private_key")) { | ||||||
|  | 			this->privateKey = wgKeys::HextoBase64(value); | ||||||
|  | 			this->publicKey = wgKeys::generatePublic(this->privateKey); | ||||||
|  | 		} else if (this->Peers.size() == 0 && !strcmp(key, "listen_port")) this->portListen = ({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = strtoull(value, &end, 10); if (*end || num > 0xffffU) break; num; }); | ||||||
|  |     else if (this->Peers.size() == 0 && !strcmp(key, "fwmark")) this->fwmark = ({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = strtoull(value, &end, 10); if (*end || num > 0xffffffffU) break; num; }); | ||||||
|  |     else if (!strcmp(key, "public_key")) { | ||||||
|  | 			Peer new_peer; | ||||||
|  |       peerPubKey = wgKeys::HextoBase64(value); | ||||||
|  |       this->Peers[peerPubKey] = new_peer; | ||||||
|  |       peer = true; | ||||||
|  | 		} else if (peer && !strcmp(key, "preshared_key")) { | ||||||
|  | 			if (std::string(value) == "0000000000000000000000000000000000000000000000000000000000000000") continue; | ||||||
|  |       if (strlen(value) == HexWgKeyLength) this->Peers[peerPubKey].presharedKey = wgKeys::HextoBase64(value); | ||||||
|  | 		} else if (peer && !strcmp(key, "persistent_keepalive_interval")) this->Peers[peerPubKey].keepInterval = ({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = strtoull(value, &end, 10); if (*end || num > 0xffffU) break; num; }); | ||||||
|  |     else if (peer && !strcmp(key, "allowed_ip")) this->Peers[peerPubKey].allowedIPs.push_back(value); | ||||||
|  |     else if (peer && !strcmp(key, "last_handshake_time_sec")) {} | ||||||
|  | 		else if (peer && !strcmp(key, "last_handshake_time_nsec")) this->Peers[peerPubKey].lastHandshake = ({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = strtoull(value, &end, 10); if (*end || num > 0x7fffffffffffffffULL) break; num; }); | ||||||
|  | 		else if (peer && !strcmp(key, "rx_bytes")) this->Peers[peerPubKey].rxBytes = ({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = strtoull(value, &end, 10); if (*end || num > 0xffffffffffffffffULL) break; num; }); | ||||||
|  | 		else if (peer && !strcmp(key, "tx_bytes")) this->Peers[peerPubKey].txBytes = ({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = strtoull(value, &end, 10); if (*end || num > 0xffffffffffffffffULL) break; num; }); | ||||||
|  | 		else if (!strcmp(key, "errno")) ret = -({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = strtoull(value, &end, 10); if (*end || num > 0x7fffffffU) break; num; }); | ||||||
|  |     else if (peer && !strcmp(key, "endpoint")) { | ||||||
|  | 			char *begin, *end; | ||||||
|  | 			struct addrinfo *resolved; | ||||||
|  | 			struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM, .ai_protocol = IPPROTO_UDP }; | ||||||
|  | 			if (!strlen(value)) break; | ||||||
|  | 			if (value[0] == '[') { | ||||||
|  | 				begin = &value[1]; | ||||||
|  | 				end = strchr(value, ']'); | ||||||
|  | 				if (!end) break; | ||||||
|  | 				*end++ = '\0'; | ||||||
|  | 				if (*end++ != ':' || !*end) break; | ||||||
|  | 			} else { | ||||||
|  | 				begin = value; | ||||||
|  | 				end = strrchr(value, ':'); | ||||||
|  | 				if (!end || !*(end + 1)) break; | ||||||
|  | 				*end++ = '\0'; | ||||||
|  | 			} | ||||||
|  | 			if (getaddrinfo(begin, end, &hints, &resolved) != 0) { | ||||||
|  | 				ret = ENETUNREACH; | ||||||
|  | 				throw std::string("Failed to resolve endpoint"); | ||||||
|  | 			} | ||||||
|  | 			if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) || (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6))) this->Peers[peerPubKey].endpoint = value; | ||||||
|  | 			else { | ||||||
|  | 				freeaddrinfo(resolved); | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 			freeaddrinfo(resolved); | ||||||
|  | 		} | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   free(key); | ||||||
|  |   fclose(f); | ||||||
|  |   if (ret < 0) throw std::string("Failed to get wireguard config"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WireguardConfig::setWireguardConfig() { | ||||||
|  |   if (this->name.length() == 0) throw std::string("Set wireguard name!"); | ||||||
|  |   else if (!(WireguardDevices().exist(this->name))) { | ||||||
|  |     std::string PathError = createTun((char*)this->name.c_str()); | ||||||
|  |     if (PathError.size() > 0) throw PathError; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FILE* f = interfaceFile(WireguardDevices().findSock(this->name)); | ||||||
|  |   fprintf(f, "set=1\n"); | ||||||
|  |  | ||||||
|  |   if (this->privateKey.length() == Base64WgKeyLength) fprintf(f, "private_key=%s\n", wgKeys::toHex(this->privateKey).c_str()); | ||||||
|  |   if (this->portListen >= 0) fprintf(f, "listen_port=%u\n", this->portListen); | ||||||
|  |   if (this->fwmark >= 0) fprintf(f, "fwmark=%u\n", this->fwmark); | ||||||
|  |   if (this->replacePeers) fprintf(f, "replace_peers=true\n"); | ||||||
|  |  | ||||||
|  |   for (auto peer : this->Peers) { | ||||||
|  |     fprintf(f, "public_key=%s\n", wgKeys::toHex(peer.first).c_str()); | ||||||
|  |     if (peer.second.removeMe) { | ||||||
|  |       fprintf(f, "remove=true\n"); | ||||||
|  | 		  continue; | ||||||
|  |     } | ||||||
|  |     if (peer.second.presharedKey.length() == Base64WgKeyLength) fprintf(f, "preshared_key=%s\n", wgKeys::toHex(peer.second.presharedKey).c_str()); | ||||||
|  |     if (peer.second.keepInterval) fprintf(f, "persistent_keepalive_interval=%u\n", peer.second.keepInterval); | ||||||
|  |     if (peer.second.endpoint.length() > 2) fprintf(f, "endpoint=%s\n", peer.second.endpoint.c_str()); | ||||||
|  |     if (peer.second.allowedIPs.size() > 0) { | ||||||
|  |       fprintf(f, "replace_allowed_ips=true\n"); | ||||||
|  |       for (auto s : peer.second.allowedIPs.getIpParsed()) fprintf(f, "allowed_ip=%s/%d\n", s.Address.c_str(), s.Mask); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   fprintf(f, "\n"); | ||||||
|  |   fflush(f); | ||||||
|  |  | ||||||
|  |   int ret, set_errno = -EPROTO; | ||||||
|  | 	size_t line_buffer_len = 0, line_len; | ||||||
|  | 	char *key = NULL, *value; | ||||||
|  |   while (getline(&key, &line_buffer_len, f) > 0) { | ||||||
|  |     line_len = strlen(key); | ||||||
|  |     ret = set_errno; | ||||||
|  |     if (line_len == 1 && key[0] == '\n') break; | ||||||
|  |     value = strchr(key, '='); | ||||||
|  |     if (!value || line_len == 0 || key[line_len - 1] != '\n') break; | ||||||
|  |     *value++ = key[--line_len] = '\0'; | ||||||
|  |  | ||||||
|  |     if (!strcmp(key, "errno")) { | ||||||
|  |       long long num; | ||||||
|  |       char *end; | ||||||
|  |       if (value[0] != '-' && !char_is_digit(value[0])) break; | ||||||
|  |       num = strtoll(value, &end, 10); | ||||||
|  |       if (*end || num > INT_MAX || num < INT_MIN) break; | ||||||
|  |       set_errno = num; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   free(key); | ||||||
|  |   fclose(f); | ||||||
|  |   ret = -(errno ? -errno : -EPROTO); | ||||||
|  |   if (ret < 0) throw std::string("Cannot set configuration, code: ").append(std::to_string(ret)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IpManeger::SetInInterface(std::string interfaceName) {} | ||||||
|  | void IpManeger::GetInInterface(std::string interfaceName) {} | ||||||
							
								
								
									
										175
									
								
								addon/wg.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								addon/wg.hh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | |||||||
|  | #ifndef __WG_NODE__ | ||||||
|  | #define __WG_NODE__ | ||||||
|  | #include "wginterface.hh" | ||||||
|  | #include <napi.h> | ||||||
|  | #include <functional> | ||||||
|  | #include <iostream> | ||||||
|  |  | ||||||
|  | class Promised : public Napi::AsyncWorker { | ||||||
|  |   public: | ||||||
|  |   Napi::Promise::Deferred NodePromise; | ||||||
|  |   Promised(const Napi::Env &env): AsyncWorker(env), NodePromise{env} {} | ||||||
|  |  | ||||||
|  |   void OnError(const Napi::Error& e) override { | ||||||
|  |     Napi::HandleScope scope(Env()); | ||||||
|  |     NodePromise.Reject(e.Value()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void OnOK() override { | ||||||
|  |     Napi::HandleScope scope(Env()); | ||||||
|  |     auto call = [&](Napi::Value data) -> void { NodePromise.Resolve(data); }; | ||||||
|  |     runOk(call); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   virtual void runOk(std::function<void(Napi::Value)> callback) { | ||||||
|  |     Napi::HandleScope scope(Env()); | ||||||
|  |     callback(Env().Undefined()); | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class DeleteInterface : public Promised { | ||||||
|  |   std::string wgName; | ||||||
|  |   public: | ||||||
|  |   DeleteInterface(const Napi::Env &env, const Napi::String &name): Promised(env), wgName{name.Utf8Value()} {} | ||||||
|  |  | ||||||
|  |   void Execute() override { | ||||||
|  |     WireguardDevices wgDevs = WireguardDevices(); | ||||||
|  |     try { | ||||||
|  |       wgDevs.deleteInterface(wgName); | ||||||
|  |     } catch (std::string &err) { SetError(err); } | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class ListDevices : public Promised { | ||||||
|  |   WireguardDevices wgDevs; | ||||||
|  |   public: | ||||||
|  |   ListDevices(const Napi::Env &env): Promised(env), wgDevs{} {} | ||||||
|  |  | ||||||
|  |   void Execute() override { | ||||||
|  |     try { | ||||||
|  |       wgDevs.getInterfaces(); | ||||||
|  |     } catch (std::string &err) { SetError(err); } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void runOk(std::function<void(Napi::Value)> callback) override { | ||||||
|  |     Napi::HandleScope scope(Env()); | ||||||
|  |     const Napi::Env env = Env(); | ||||||
|  |     const Napi::Array interf = Napi::Array::New(env); | ||||||
|  |     for (auto &ip : wgDevs) interf.Set(interf.Length(), ip); | ||||||
|  |     callback(interf); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class SetConfig : public WireguardConfig, public Promised { | ||||||
|  |   public: | ||||||
|  |   void Execute() { | ||||||
|  |     try { | ||||||
|  |       this->setWireguardConfig(); | ||||||
|  |     } catch (std::string err) { | ||||||
|  |       SetError(err); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   SetConfig(const Napi::Env &env, const Napi::Object config): Promised(env) { | ||||||
|  |     if (!(config.Has("name"))) throw std::string("Set wireguard interface name!"); | ||||||
|  |     if (!(config.Has("privateKey") && config.Get("privateKey").IsString())) throw std::string("Set wireguard private key!"); | ||||||
|  |     this->name = config.Get("name").ToString().Utf8Value(); | ||||||
|  |     this->privateKey = config.Get("privateKey").ToString().Utf8Value(); | ||||||
|  |     if (config.Has("publicKey") && config.Get("publicKey").IsString() && config.Get("publicKey").ToString().Utf8Value().length() == Base64WgKeyLength) this->publicKey = config.Get("publicKey").ToString().Utf8Value(); | ||||||
|  |     if (config.Has("portListen") && config.Get("portListen").IsNumber() && config.Get("portListen").ToNumber().Int32Value() >= 0) this->portListen = config.Get("portListen").ToNumber().Int32Value(); | ||||||
|  |     if (config.Has("fwmark") && config.Get("fwmark").IsNumber() && config.Get("fwmark").ToNumber().Int32Value() >= 0) this->fwmark = config.Get("fwmark").ToNumber().Int32Value(); | ||||||
|  |     if (config.Has("replacePeers") && config.Get("replacePeers").IsBoolean()) this->replacePeers = config.Get("replacePeers").ToBoolean().Value(); | ||||||
|  |  | ||||||
|  |     if (config.Has("address") && config.Get("address").IsArray() && config.Get("address").As<Napi::Array>().Length() > 0) { | ||||||
|  |       const Napi::Array Addrs(config.Get("address").As<Napi::Array>()); | ||||||
|  |       for (unsigned int AddrIndex = 0; AddrIndex < Addrs.Length(); AddrIndex++) { | ||||||
|  |         if (!(Addrs[AddrIndex].IsString())) continue; | ||||||
|  |         this->interfaceAddress.addIPMask(Addrs[AddrIndex].ToString().Utf8Value()); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (config.Has("peers") && config.Get("peers").IsObject()) { | ||||||
|  |       const Napi::Object PeersObject(config.Get("peers").ToObject()); | ||||||
|  |       const Napi::Array PeersKeys(PeersObject.GetPropertyNames()); | ||||||
|  |       for (unsigned int peerIndex = 0; peerIndex < PeersKeys.Length(); peerIndex++) { | ||||||
|  |         if (!(PeersObject.Get(PeersKeys[peerIndex].ToString()).IsObject())) continue; | ||||||
|  |         const std::string publicKey(PeersKeys[peerIndex].ToString().Utf8Value()); | ||||||
|  |         const Napi::Object peerConfig(PeersObject.Get(publicKey).ToObject()); | ||||||
|  |         Peer peer; | ||||||
|  |  | ||||||
|  |         if (peerConfig.Has("removeMe") && peerConfig.Get("removeMe").IsBoolean() && peerConfig.Get("removeMe").As<Napi::Boolean>().Value()) peer.removeMe = true; | ||||||
|  |         else { | ||||||
|  |           if (peerConfig.Has("presharedKey") && peerConfig.Get("presharedKey").IsString() && peerConfig.Get("presharedKey").ToString().Utf8Value().length() == Base64WgKeyLength) peer.presharedKey = peerConfig.Get("presharedKey").ToString().Utf8Value(); | ||||||
|  |           if (peerConfig.Has("keepInterval") && peerConfig.Get("keepInterval").IsNumber() && peerConfig.Get("keepInterval").ToNumber().Int32Value() > 0) peer.keepInterval = peerConfig.Get("keepInterval").ToNumber().Int32Value(); | ||||||
|  |           if (peerConfig.Has("endpoint") && peerConfig.Get("endpoint").IsString() && peerConfig.Get("endpoint").ToString().Utf8Value().length() == Base64WgKeyLength) peer.endpoint = peerConfig.Get("endpoint").ToString().Utf8Value(); | ||||||
|  |           if (peerConfig.Has("allowedIPs") && peerConfig.Get("allowedIPs").IsArray()) { | ||||||
|  |             const Napi::Array ips = peerConfig.Get("allowedIPs").As<Napi::Array>(); | ||||||
|  |             for (unsigned int ipIndex = 0; ipIndex < ips.Length(); ipIndex++) peer.allowedIPs.addIPMask(ips[ipIndex].ToString().Utf8Value()); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Set peer in map | ||||||
|  |         this->Peers[publicKey] = peer; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class GetConfig : public WireguardConfig, public Promised { | ||||||
|  |   public: | ||||||
|  |   GetConfig(const Napi::Env &env, const Napi::String name): Promised(env) { | ||||||
|  |     this->name = name.Utf8Value(); | ||||||
|  |   } | ||||||
|  |   void Execute() { | ||||||
|  |     try { | ||||||
|  |       this->getWireguardConfig(); | ||||||
|  |     } catch (std::string err) { | ||||||
|  |       SetError(err); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void runOk(std::function<void(Napi::Value)> callback) { | ||||||
|  |     Napi::HandleScope scope(Env()); | ||||||
|  |     const Napi::Env env = Env(); | ||||||
|  |     const Napi::Object config = Napi::Object::New(env); | ||||||
|  |     config.Set("name", this->name); | ||||||
|  |     config.Set("privateKey", this->privateKey); | ||||||
|  |     if (this->publicKey.length() == Base64WgKeyLength) config.Set("publicKey", this->publicKey); | ||||||
|  |     if (this->portListen > 0) config.Set("portListen", this->portListen); | ||||||
|  |     if (this->fwmark > 0) config.Set("fwmark", this->fwmark); | ||||||
|  |  | ||||||
|  |     // Interface IPs | ||||||
|  |     const Napi::Array ips = Napi::Array::New(env); | ||||||
|  |     for (auto ip : this->interfaceAddress) ips.Set(ips.Length(), ip); | ||||||
|  |     config.Set("address", ips); | ||||||
|  |  | ||||||
|  |     // Peers | ||||||
|  |     const Napi::Object peersObj = Napi::Object::New(env); | ||||||
|  |     for (auto &__peer : this->Peers) { | ||||||
|  |       std::string publicKey = __peer.first; | ||||||
|  |       if (publicKey.length() != Base64WgKeyLength) continue; | ||||||
|  |       const Napi::Object peerConfig = Napi::Object::New(env); | ||||||
|  |       const Peer config = __peer.second; | ||||||
|  |  | ||||||
|  |       if (config.presharedKey.length() == Base64WgKeyLength) peerConfig.Set("presharedKey", config.presharedKey); | ||||||
|  |       if (config.keepInterval >= 0) peerConfig.Set("keepInterval", config.keepInterval); | ||||||
|  |       if (config.endpoint.length() > 0) peerConfig.Set("endpoint", config.endpoint); | ||||||
|  |  | ||||||
|  |       peerConfig.Set("rxBytes", Napi::BigInt::New(env, (uint64_t)config.rxBytes)); | ||||||
|  |       peerConfig.Set("txBytes", Napi::BigInt::New(env, (uint64_t)config.txBytes)); | ||||||
|  |       peerConfig.Set("lastHandshake", Napi::Date::New(env, config.lastHandshake)); | ||||||
|  |  | ||||||
|  |       const Napi::Array ips = Napi::Array::New(env); | ||||||
|  |       for (auto &ip : config.allowedIPs) ips.Set(ips.Length(), ip); | ||||||
|  |       peerConfig.Set("allowedIPs", ips); | ||||||
|  |  | ||||||
|  |       peersObj.Set(publicKey, peerConfig); | ||||||
|  |     } | ||||||
|  |     config.Set("peers", peersObj); | ||||||
|  |  | ||||||
|  |     // Set data | ||||||
|  |     callback(config); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										237
									
								
								addon/wginterface.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								addon/wginterface.hh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | |||||||
|  | #ifndef __WIREGUARD_ADDON__ | ||||||
|  | #define __WIREGUARD_ADDON__ | ||||||
|  | #include "genKey/wgkeys.hh" | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | #include <map> | ||||||
|  |  | ||||||
|  | extern const int wgKeyLength; | ||||||
|  | extern const int Base64WgKeyLength; | ||||||
|  |  | ||||||
|  | std::string getWireguardVersion(); | ||||||
|  | std::string driveLoad(std::map<std::string, std::string> load); | ||||||
|  |  | ||||||
|  | class WireguardDevices : public std::vector<std::string> { | ||||||
|  |   public: | ||||||
|  |   ~WireguardDevices() { this->clear(); } | ||||||
|  |  | ||||||
|  |   /** Get all interfaces from kernel and insert in vector */ | ||||||
|  |   void getInterfaces(); | ||||||
|  |  | ||||||
|  |   /** Delete interface from kernel network */ | ||||||
|  |   void deleteInterface(std::string wgName); | ||||||
|  |  | ||||||
|  |   /** Check if exists wireguard interface intterface */ | ||||||
|  |   bool exist(std::string name) { | ||||||
|  |     this->getInterfaces(); | ||||||
|  |     for (auto wgDev = this->begin(); wgDev != this->end(); ++wgDev)  { | ||||||
|  |       if (name == *wgDev) return true; | ||||||
|  |       else { | ||||||
|  |         std::string __nDev = std::string(wgDev->substr(wgDev->find_last_of("/")+1)); | ||||||
|  |         if (__nDev.find(".sock") != std::string::npos) __nDev = __nDev.substr(0, __nDev.find(".sock")); | ||||||
|  |         if (__nDev == name) return true; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** Find sock */ | ||||||
|  |   std::string findSock(std::string name) { | ||||||
|  |     this->getInterfaces(); | ||||||
|  |     for (auto wgDev = this->begin(); wgDev != this->end(); ++wgDev)  { | ||||||
|  |       if (name == *wgDev) return *wgDev; | ||||||
|  |       else if (wgDev->find_last_of(".sock") != std::string::npos) { | ||||||
|  |         std::string __nDev = std::string(wgDev->substr(wgDev->find_last_of("/")+1)); | ||||||
|  |         if (__nDev.find(".sock") != std::string::npos) __nDev = __nDev.substr(0, __nDev.find(".sock")); | ||||||
|  |         if (__nDev == name) return *wgDev; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return std::string(""); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |   std::string Address, Subnet; | ||||||
|  |   int Mask, Proto; | ||||||
|  | } IpReference; | ||||||
|  |  | ||||||
|  | /** Maneger Interface IPs */ | ||||||
|  | class IpManeger : public std::vector<std::string> { | ||||||
|  |   private: | ||||||
|  |   std::string getSubNet4(int Mask) { | ||||||
|  |     switch (Mask) { | ||||||
|  |       case 1:	return "128.0.0.0"; | ||||||
|  |       case 2:	return "192.0.0.0"; | ||||||
|  |       case 3:	return "224.0.0.0"; | ||||||
|  |       case 4:	return "240.0.0.0"; | ||||||
|  |       case 5:	return "248.0.0.0"; | ||||||
|  |       case 6:	return "252.0.0.0"; | ||||||
|  |       case 7:	return "254.0.0.0"; | ||||||
|  |       case 8:	return "255.0.0.0"; | ||||||
|  |       case 9:	return "255.128.0.0"; | ||||||
|  |       case 10:	return "255.192.0.0"; | ||||||
|  |       case 11:	return "255.224.0.0"; | ||||||
|  |       case 12:	return "255.240.0.0"; | ||||||
|  |       case 13:	return "255.248.0.0"; | ||||||
|  |       case 14:	return "255.252.0.0"; | ||||||
|  |       case 15:	return "255.254.0.0"; | ||||||
|  |       case 16:	return "255.255.0.0"; | ||||||
|  |       case 17:	return "255.255.128.0"; | ||||||
|  |       case 18:	return "255.255.192.0"; | ||||||
|  |       case 19:	return "255.255.224.0"; | ||||||
|  |       case 20:	return "255.255.240.0"; | ||||||
|  |       case 21:	return "255.255.248.0"; | ||||||
|  |       case 22:	return "255.255.252.0"; | ||||||
|  |       case 23:	return "255.255.254.0"; | ||||||
|  |       case 24:	return "255.255.255.0"; | ||||||
|  |       case 25:	return "255.255.255.128"; | ||||||
|  |       case 26:	return "255.255.255.192"; | ||||||
|  |       case 27:	return "255.255.255.224"; | ||||||
|  |       case 28:	return "255.255.255.240"; | ||||||
|  |       case 29:	return "255.255.255.248"; | ||||||
|  |       case 30:	return "255.255.255.252"; | ||||||
|  |       case 31:	return "255.255.255.254"; | ||||||
|  |  | ||||||
|  |       default: | ||||||
|  |       case 32:	return "255.255.255.255"; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   public: | ||||||
|  |   void SetInInterface(std::string interfaceName); | ||||||
|  |   void GetInInterface(std::string interfaceName); | ||||||
|  |  | ||||||
|  |   void addIPMask(std::string ip) { | ||||||
|  |     IpReference xTop; | ||||||
|  |     auto maskStart = ip.find("/"); | ||||||
|  |     auto isIPv6 = ip.find(":") != std::string::npos; | ||||||
|  |     if (isIPv6) xTop.Mask = 128; | ||||||
|  |     else xTop.Mask = 32; | ||||||
|  |     if (maskStart == std::string::npos) xTop.Address = ip; | ||||||
|  |     else { | ||||||
|  |       xTop.Address = ip.substr(0, maskStart); | ||||||
|  |       xTop.Mask = std::stoi(ip.substr(maskStart+1).c_str()); | ||||||
|  |       if (!isIPv6 && xTop.Mask > 32) throw std::string("Set valid mask to ipv4 address!"); | ||||||
|  |     } | ||||||
|  |     xTop.Proto = isIPv6 ? 6 : 4; | ||||||
|  |     if (!isIPv6) xTop.Subnet = this->getSubNet4(xTop.Mask); | ||||||
|  |     this->push_back(xTop.Address.append("/").append(std::to_string(xTop.Mask))); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   std::vector<IpReference> getIpParsed() { | ||||||
|  |     std::vector<IpReference> xTops; | ||||||
|  |     for (auto ipAddrr = this->begin(); ipAddrr != this->end(); ++ipAddrr) { | ||||||
|  |       IpReference nTop; | ||||||
|  |       auto maskStart = ipAddrr->find("/"); | ||||||
|  |       nTop.Address = ipAddrr->substr(0, maskStart); | ||||||
|  |       nTop.Mask = std::stoi(ipAddrr->substr(maskStart+1).c_str()); | ||||||
|  |       nTop.Proto = (nTop.Address.find(":") != std::string::npos) ? 6 : 4; | ||||||
|  |       if (nTop.Proto == 6) nTop.Subnet = this->getSubNet4(nTop.Mask); | ||||||
|  |       xTops.push_back(nTop); | ||||||
|  |     } | ||||||
|  |     return xTops; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * peer class | ||||||
|  |  */ | ||||||
|  | class Peer { | ||||||
|  |   public: | ||||||
|  |   Peer() { | ||||||
|  |     this->removeMe = false; | ||||||
|  |     this->keepInterval = 0; | ||||||
|  |     this->rxBytes = 0; | ||||||
|  |     this->txBytes = 0; | ||||||
|  |     this->lastHandshake = 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** Remove specifies if the peer with this public key should be removed from a device's peer list. */ | ||||||
|  |   bool removeMe; | ||||||
|  |  | ||||||
|  |   /** PresharedKey is an optional preshared key which may be used as an additional layer of security for peer communications. */ | ||||||
|  |   std::string presharedKey; | ||||||
|  |  | ||||||
|  |   /** Endpoint is the most recent source address used for communication by this Peer. */ | ||||||
|  |   std::string endpoint; | ||||||
|  |  | ||||||
|  |   /** PersistentKeepaliveInterval specifies how often an "empty" packet is sent to a peer to keep a connection alive. | ||||||
|  |    * | ||||||
|  |    * A value of 0 indicates that persistent keepalives are disabled. | ||||||
|  | 	 */ | ||||||
|  |   unsigned int keepInterval; | ||||||
|  |  | ||||||
|  |   /** Last peer handshake in milisseconds */ | ||||||
|  |   unsigned long long lastHandshake; | ||||||
|  |  | ||||||
|  |   /** Peer data received (RX) and transferred (TX)  */ | ||||||
|  |   unsigned long long rxBytes, txBytes; | ||||||
|  |  | ||||||
|  |   /** Peer ips allowed to recive data */ | ||||||
|  |   IpManeger allowedIPs; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  | * Set and Get Wireguard configs | ||||||
|  | */ | ||||||
|  | class WireguardConfig { | ||||||
|  |   public: | ||||||
|  |  | ||||||
|  |   WireguardConfig() { | ||||||
|  |     this->portListen = 0; | ||||||
|  |     this->fwmark = 0; | ||||||
|  |     this->replacePeers = false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** Wireguard interface name */ | ||||||
|  |   std::string name; | ||||||
|  |  | ||||||
|  |   /** Wireguard interface private key */ | ||||||
|  |   std::string privateKey; | ||||||
|  |  | ||||||
|  |   /** Wireguard interface public key */ | ||||||
|  |   std::string publicKey; | ||||||
|  |  | ||||||
|  |   /** Wireguard port listening or listened */ | ||||||
|  |   unsigned short portListen; | ||||||
|  |  | ||||||
|  |   /** FirewallMark specifies a device's firewall mark else set to 0, the firewall mark will be cleared */ | ||||||
|  |   unsigned int fwmark; | ||||||
|  |  | ||||||
|  |   /** Replace Wireguard peers if wireguard interface exists */ | ||||||
|  |   bool replacePeers; | ||||||
|  |  | ||||||
|  |   /** Wireguard interface IPs */ | ||||||
|  |   IpManeger interfaceAddress; | ||||||
|  |  | ||||||
|  |   /** Wireguard peers */ | ||||||
|  |   std::map<std::string, Peer> Peers; | ||||||
|  |  | ||||||
|  |   /** Set wireguard config in interface */ | ||||||
|  |   void setWireguardConfig(); | ||||||
|  |  | ||||||
|  |   /** Get configuration from wireguard */ | ||||||
|  |   void getWireguardConfig(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | namespace WireguardUserspace { | ||||||
|  |   // Get Wireguard-go version | ||||||
|  |   std::string getWireguardVersion(); | ||||||
|  |  | ||||||
|  |   // Close all wireguard tunels | ||||||
|  |   void closeAllWireguardTunnels(); | ||||||
|  |  | ||||||
|  |   // Create tunel and return path to tunel | ||||||
|  |   std::string createWireguardTunnel(std::string wgName); | ||||||
|  |  | ||||||
|  |   // Delete tunel by name and return true if success | ||||||
|  |   void deleteWireguardTunnel(std::string wgName); | ||||||
|  |  | ||||||
|  |   // List all tunels | ||||||
|  |   std::vector<std::string> listTunnels(); | ||||||
|  |  | ||||||
|  |   // Check if tunel exist | ||||||
|  |   bool checkIfExistTunnel(std::string wgName); | ||||||
|  | }; | ||||||
|  | #endif | ||||||
							
								
								
									
										
											BIN
										
									
								
								addon/win/arm/wireguard.dll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								addon/win/arm/wireguard.dll
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										530
									
								
								addon/win/wginterface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										530
									
								
								addon/win/wginterface.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,530 @@ | |||||||
|  | #include "wginterface.hh" | ||||||
|  | #include "genKey/wgkeys.hh" | ||||||
|  | #include <win/wireguard.h> | ||||||
|  | #include <string> | ||||||
|  | #include <locale> | ||||||
|  | #include <codecvt> | ||||||
|  | #include <vector> | ||||||
|  | #include <map> | ||||||
|  | #include <iostream> | ||||||
|  | #include <windows.h> | ||||||
|  | #include <tlhelp32.h> | ||||||
|  | #include <accctrl.h> | ||||||
|  | #include <aclapi.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <winsock2.h> | ||||||
|  | #include <ws2ipdef.h> | ||||||
|  | #include <ws2tcpip.h> | ||||||
|  | #include <iphlpapi.h> | ||||||
|  | #include <bcrypt.h> | ||||||
|  | #include <wincrypt.h> | ||||||
|  | #include <sysinfoapi.h> | ||||||
|  | #include <winternl.h> | ||||||
|  | #include <cstdlib> | ||||||
|  | #include <setupapi.h> | ||||||
|  | #include <cfgmgr32.h> | ||||||
|  | #include <devguid.h> | ||||||
|  | #include <ws2def.h> | ||||||
|  | #include <netioapi.h> | ||||||
|  | #include <chrono> | ||||||
|  | #include <thread> | ||||||
|  | #include <comdef.h> | ||||||
|  | #include <Wbemidl.h> | ||||||
|  | #include <stdexcept> | ||||||
|  |  | ||||||
|  | const DEVPROPKEY devpkey_name = { { 0x65726957, 0x7547, 0x7261, { 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79 } }, DEVPROPID_FIRST_USABLE + 1 }; | ||||||
|  | #define IFNAMSIZ MAX_ADAPTER_NAME - 1 | ||||||
|  |  | ||||||
|  | // Create Wireguard adapter | ||||||
|  | static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter; | ||||||
|  | // Open Wireguard adapter by name if exists | ||||||
|  | static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter; | ||||||
|  | // Close Wireguard adapter | ||||||
|  | static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter; | ||||||
|  | // Get Wireguard adapter LUID | ||||||
|  | static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID; | ||||||
|  | // Get running Wireguard driver version | ||||||
|  | static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC *WireGuardGetRunningDriverVersion; | ||||||
|  | // Delete Wireguard driver if non exists adapters | ||||||
|  | static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver; | ||||||
|  | // Set logger for Wireguard adapter | ||||||
|  | static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger; | ||||||
|  | // Set adapter logging for Wireguard adapter | ||||||
|  | static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging; | ||||||
|  | // Get adapter state for Wireguard adapter | ||||||
|  | static WIREGUARD_GET_ADAPTER_STATE_FUNC *WireGuardGetAdapterState; | ||||||
|  | // Set adapter state for Wireguard adapter | ||||||
|  | static WIREGUARD_SET_ADAPTER_STATE_FUNC *WireGuardSetAdapterState; | ||||||
|  | // Get Wireguard adapter configuration | ||||||
|  | static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration; | ||||||
|  | // Set Wireguard adapter configuration | ||||||
|  | static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration; | ||||||
|  |  | ||||||
|  | LPCWSTR WireguardAddonDescription = WireguardAddonDescription; | ||||||
|  |  | ||||||
|  | // Function to check if the current user has administrator privileges | ||||||
|  | bool IsRunAsAdmin() { | ||||||
|  |   BOOL fRet = FALSE; | ||||||
|  |   HANDLE hToken = NULL; | ||||||
|  |   if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { | ||||||
|  |     TOKEN_ELEVATION Elevation; | ||||||
|  |     DWORD cbSize = sizeof(TOKEN_ELEVATION); | ||||||
|  |     if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) { | ||||||
|  |       fRet = Elevation.TokenIsElevated; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (hToken) CloseHandle(hToken); | ||||||
|  |   return !!fRet; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string convertWcharString(const wchar_t *wideStr) { | ||||||
|  |   // Create a wstring from the wide character string | ||||||
|  |   std::wstring wideString(wideStr); | ||||||
|  |  | ||||||
|  |   // Use std::wstring_convert for conversion | ||||||
|  |   std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; | ||||||
|  |   std::string narrowString = converter.to_bytes(wideString); | ||||||
|  |  | ||||||
|  |   // Now narrowString is a std::string containing the converted string | ||||||
|  |   return narrowString; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | LPCWSTR toLpcwstr(std::string s) { | ||||||
|  |   wchar_t* wString = new wchar_t[s.length()+1]; | ||||||
|  |   MultiByteToWideChar(CP_ACP, 0, s.c_str(), -1, wString, s.length()+1); | ||||||
|  |   return wString; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string parseEndpoint(SOCKADDR_INET *input) { | ||||||
|  |   if (!(input->si_family == AF_INET || input->si_family == AF_INET6)) return ""; | ||||||
|  |   char saddr[INET6_ADDRSTRLEN]; | ||||||
|  |   input->si_family == AF_INET ? inet_ntop(AF_INET, &input->Ipv4.sin_addr, saddr, INET_ADDRSTRLEN) : inet_ntop(AF_INET6, &input->Ipv6.sin6_addr, saddr, INET6_ADDRSTRLEN); | ||||||
|  |  | ||||||
|  |   if (input->si_family == AF_INET6) return std::string("[").append(saddr).append("]:").append(std::to_string(htons(input->Ipv6.sin6_port))); | ||||||
|  |   return std::string(saddr).append(":").append(std::to_string(htons(input->Ipv4.sin_port))); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string getErrorString(DWORD errorMessageID) { | ||||||
|  |   if (errorMessageID == 0 || errorMessageID < 0) std::string("Error code: ").append(std::to_string(errorMessageID)); | ||||||
|  |   LPSTR messageBuffer = nullptr; | ||||||
|  |   //Ask Win32 to give us the string version of that message ID. | ||||||
|  |   //The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be). | ||||||
|  |   size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); | ||||||
|  |   //Copy the error message into a std::string. | ||||||
|  |   std::string message(messageBuffer, size); | ||||||
|  |   //Free the Win32's string's buffer. | ||||||
|  |   LocalFree(messageBuffer); | ||||||
|  |   return std::string("Error code: ").append(std::to_string(errorMessageID)).append(", Message: ").append(message); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string driveLoad(std::map<std::string, std::string> load)  { | ||||||
|  |   if (!IsRunAsAdmin()) return "Run nodejs with administrator privilegies"; | ||||||
|  |   auto DLLPATH = load["WIN32DLLPATH"]; | ||||||
|  |   if (!(DLLPATH.length())) return "Require Wireguard DLL file path!"; | ||||||
|  |   LPCWSTR dllPath = toLpcwstr(DLLPATH); | ||||||
|  |  | ||||||
|  |   HMODULE WireGuardDll = LoadLibraryExW(dllPath, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); | ||||||
|  |   if (!WireGuardDll) return std::string("Failed to initialize WireGuardNT, ").append(getErrorString(GetLastError()));; | ||||||
|  |   #define X(Name) ((*(FARPROC *)&Name = GetProcAddress(WireGuardDll, #Name)) == NULL) | ||||||
|  |   if (X(WireGuardCreateAdapter) || X(WireGuardOpenAdapter) || X(WireGuardCloseAdapter) || X(WireGuardGetAdapterLUID) || X(WireGuardGetRunningDriverVersion) || X(WireGuardDeleteDriver) || X(WireGuardSetLogger) || X(WireGuardSetAdapterLogging) || X(WireGuardGetAdapterState) || X(WireGuardSetAdapterState) || X(WireGuardGetConfiguration) || X(WireGuardSetConfiguration)) | ||||||
|  |   #undef X | ||||||
|  |   { | ||||||
|  |     DWORD LastError = GetLastError(); | ||||||
|  |     FreeLibrary(WireGuardDll); | ||||||
|  |     SetLastError(LastError); | ||||||
|  |     return std::string("Failed to set Functions from WireGuardNT DLL, ").append(getErrorString(GetLastError()));; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return ""; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string getWireguardVersion() { | ||||||
|  |   // Create interface to get version | ||||||
|  |   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"getWgVersion", WireguardAddonDescription, NULL); | ||||||
|  |   WireGuardCloseAdapter(Adapter); | ||||||
|  |   DWORD Version = WireGuardGetRunningDriverVersion(); | ||||||
|  |   if (Version == 0) { | ||||||
|  |     auto statusErr = GetLastError(); | ||||||
|  |     WireGuardCloseAdapter(Adapter); | ||||||
|  |     if (statusErr == ERROR_FILE_NOT_FOUND) return "Driver not loaded"; | ||||||
|  |     return std::string("Cannot get version drive, ").append(getErrorString(GetLastError())); | ||||||
|  |   } | ||||||
|  |   return std::string("WireGuardNT v").append(std::to_string((Version >> 16) & 0xff)).append(".").append(std::to_string((Version >> 0) & 0xff)).append(".").append(std::to_string((Version >> 8) & 0xff)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WireguardDevices::getInterfaces() { | ||||||
|  |   HDEVINFO dev_info = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"SWD\\WireGuard", NULL, DIGCF_PRESENT, NULL, NULL, NULL); | ||||||
|  |   if (dev_info == INVALID_HANDLE_VALUE) throw std::string("Cannot get devices"); | ||||||
|  |   for (DWORD devIndex = 0;; ++devIndex) { | ||||||
|  |     SP_DEVINFO_DATA dev_info_data; | ||||||
|  |     dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA); | ||||||
|  |     if (!SetupDiEnumDeviceInfo(dev_info, devIndex, &dev_info_data)) { | ||||||
|  |       if (GetLastError() == ERROR_NO_MORE_ITEMS) break; | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     DWORD buf_len; ULONG status, problem_code; | ||||||
|  |     WCHAR adapter_name[MAX_ADAPTER_NAME]; | ||||||
|  |     char *interface_name; | ||||||
|  |     DEVPROPTYPE prop_type; | ||||||
|  |  | ||||||
|  |     if (!SetupDiGetDevicePropertyW(dev_info, &dev_info_data, &devpkey_name, &prop_type, (PBYTE)adapter_name, sizeof(adapter_name), NULL, 0) || prop_type != DEVPROP_TYPE_STRING) continue; | ||||||
|  |     adapter_name[_countof(adapter_name) - 1] = L'0'; | ||||||
|  |     if (!adapter_name[0]) continue; | ||||||
|  |     buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, NULL, 0, NULL, NULL); | ||||||
|  |     if (!buf_len) continue; | ||||||
|  |     interface_name = (char *)malloc(buf_len); | ||||||
|  |     if (!interface_name) continue; | ||||||
|  |     buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, interface_name, buf_len, NULL, NULL); | ||||||
|  |     if (!buf_len) { | ||||||
|  |       free(interface_name); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (CM_Get_DevNode_Status(&status, &problem_code, dev_info_data.DevInst, 0) == CR_SUCCESS && (status & (DN_DRIVER_LOADED | DN_STARTED)) == (DN_DRIVER_LOADED | DN_STARTED)) this->push_back(std::string(interface_name)); | ||||||
|  |     free(interface_name); | ||||||
|  |   } | ||||||
|  |   SetupDiDestroyDeviceInfoList(dev_info); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |   Delete wireguard interface | ||||||
|  |  | ||||||
|  |   Current bug from Addon: Set interface down and not delete wireguard interface | ||||||
|  | */ | ||||||
|  | void WireguardDevices::deleteInterface(std::string wgName) { | ||||||
|  |   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); | ||||||
|  |   if (!Adapter) throw std::string("This interface not exists in Wireguard-Tools.js addon!"); | ||||||
|  |   if (!(WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_DOWN))) throw std::string("Failed to set down interface, ").append(getErrorString(GetLastError())); | ||||||
|  |   WireGuardCloseAdapter(Adapter); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Change point from calloc or malloc, T: from, C: to | ||||||
|  |  */ | ||||||
|  | template <typename T, typename C> C* changePoint(T *x) { | ||||||
|  |   return reinterpret_cast<C*>(((char*)x) + sizeof(T)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WireguardConfig::getWireguardConfig() { | ||||||
|  |   if (this->name.length() == 0) throw std::string("Require interface name!"); | ||||||
|  |   else if (!(WireguardDevices().exist(this->name))) throw std::string("This interface not exists in Wireguard-Tools.js addon!"); | ||||||
|  |  | ||||||
|  |   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(this->name)); | ||||||
|  |   if (!Adapter) throw std::string("This interface not exists in Wireguard-Tools.js addon!"); | ||||||
|  |   NET_LUID InterfaceLuid; | ||||||
|  |   WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); | ||||||
|  |   this->interfaceAddress.GetInInterface(this->name); | ||||||
|  |  | ||||||
|  |   DWORD buf_len = 0; | ||||||
|  |   WIREGUARD_INTERFACE *wg_iface = nullptr; | ||||||
|  |  | ||||||
|  |   while (!(WireGuardGetConfiguration(Adapter, wg_iface, &buf_len))) { | ||||||
|  |     free(wg_iface); | ||||||
|  |     if (GetLastError() != ERROR_MORE_DATA) throw std::string("Failed get interface config, code: ").append(std::to_string(GetLastError())); | ||||||
|  |     wg_iface = (WIREGUARD_INTERFACE *)malloc(buf_len); | ||||||
|  |     if (!wg_iface) throw std::string("Failed get interface config, ").append(std::to_string(-errno)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY) this->privateKey = wgKeys::toString(wg_iface->PrivateKey); | ||||||
|  |   if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PUBLIC_KEY) this->publicKey = wgKeys::toString(wg_iface->PublicKey); | ||||||
|  |   if (wg_iface->ListenPort > 0) this->portListen = wg_iface->ListenPort; | ||||||
|  |  | ||||||
|  |   WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface); | ||||||
|  |   for (DWORD i = 0; i < wg_iface->PeersCount; i++) { | ||||||
|  |     auto pubKey = wgKeys::toString(wg_peer->PublicKey); | ||||||
|  |     Peer peerConfig; | ||||||
|  |  | ||||||
|  |     peerConfig.txBytes = wg_peer->TxBytes; | ||||||
|  |     peerConfig.rxBytes = wg_peer->RxBytes; | ||||||
|  |     peerConfig.lastHandshake = (wg_peer->LastHandshake - 116444736000000000LL) / (100 / 1000); | ||||||
|  |  | ||||||
|  |     if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY) peerConfig.presharedKey = wgKeys::toString(wg_peer->PresharedKey); | ||||||
|  |     if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT) peerConfig.endpoint = parseEndpoint(&wg_peer->Endpoint); | ||||||
|  |     if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE) peerConfig.keepInterval = wg_peer->PersistentKeepalive; | ||||||
|  |  | ||||||
|  |     WIREGUARD_ALLOWED_IP* wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer); | ||||||
|  |     for (DWORD __aip = 0; __aip < wg_peer->AllowedIPsCount; __aip++) { | ||||||
|  | 			char saddr[INET6_ADDRSTRLEN]; | ||||||
|  |       if (wg_aip->AddressFamily == AF_INET) { | ||||||
|  |         inet_ntop(AF_INET, &wg_aip->Address.V6, saddr, INET_ADDRSTRLEN); | ||||||
|  |         peerConfig.allowedIPs.push_back(std::string(saddr).append("/").append(std::to_string(wg_aip->Cidr))); | ||||||
|  | 			} else if (wg_aip->AddressFamily == AF_INET6) { | ||||||
|  |         inet_ntop(AF_INET6, &wg_aip->Address.V6, saddr, INET6_ADDRSTRLEN); | ||||||
|  |         peerConfig.allowedIPs.push_back(std::string(saddr).append("/").append(std::to_string(wg_aip->Cidr))); | ||||||
|  | 			} | ||||||
|  |       ++wg_aip; | ||||||
|  |     } | ||||||
|  |     wg_peer = reinterpret_cast<WIREGUARD_PEER*>(wg_aip); | ||||||
|  |     this->Peers[pubKey] = peerConfig; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   free(wg_iface); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void WireguardConfig::setWireguardConfig() { | ||||||
|  |   if (this->name.length() == 0) throw std::string("Require interface name!"); | ||||||
|  |   else if (this->name.length() > IFNAMSIZ) throw std::string("Interface name too long"); | ||||||
|  |  | ||||||
|  |   DWORD buf_len = sizeof(WIREGUARD_INTERFACE); | ||||||
|  |   for (auto peer : this->Peers) { | ||||||
|  | 		if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER)) throw std::string("Buffer overflow"); | ||||||
|  | 		buf_len += sizeof(WIREGUARD_PEER); | ||||||
|  | 		for (auto aip : peer.second.allowedIPs) { | ||||||
|  | 			if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP)) throw std::string("Buffer overflow"); | ||||||
|  | 			buf_len += sizeof(WIREGUARD_ALLOWED_IP); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |   WIREGUARD_INTERFACE *wg_iface = reinterpret_cast<WIREGUARD_INTERFACE*>(calloc(1, buf_len)); | ||||||
|  |   if (!wg_iface) throw std::string("Cannot alloc buff"); | ||||||
|  |   wg_iface->PeersCount = 0; | ||||||
|  |  | ||||||
|  |   wgKeys::stringToKey(wg_iface->PrivateKey, this->privateKey); | ||||||
|  |   wg_iface->Flags = WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY; | ||||||
|  |  | ||||||
|  |   wg_iface->ListenPort = this->portListen; | ||||||
|  |   if (this->portListen >= 0) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT); | ||||||
|  |   if (this->replacePeers) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_REPLACE_PEERS); | ||||||
|  |  | ||||||
|  | 	WIREGUARD_ALLOWED_IP *wg_aip; | ||||||
|  | 	WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface); | ||||||
|  |   for (auto __peer : this->Peers) { | ||||||
|  |     auto peerPublicKey = __peer.first; auto peerConfig = __peer.second; | ||||||
|  |     wgKeys::stringToKey(wg_peer->PublicKey, peerPublicKey); | ||||||
|  |     wg_peer->Flags = WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PUBLIC_KEY; | ||||||
|  |     wg_peer->AllowedIPsCount = 0; | ||||||
|  |     wg_iface->PeersCount++; | ||||||
|  |  | ||||||
|  |     if (peerConfig.removeMe) { | ||||||
|  |       wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REMOVE); | ||||||
|  |       wg_peer = changePoint<WIREGUARD_PEER, WIREGUARD_PEER>(wg_peer); | ||||||
|  |     } else { | ||||||
|  |       if (peerConfig.presharedKey.size() == B64_WG_KEY_LENGTH) { | ||||||
|  |         wgKeys::stringToKey(wg_peer->PresharedKey, peerConfig.presharedKey); | ||||||
|  |         wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       wg_peer->PersistentKeepalive = peerConfig.keepInterval; | ||||||
|  |       if (peerConfig.keepInterval >= 0) wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE); | ||||||
|  |  | ||||||
|  |       if (peerConfig.endpoint.size() > 0) { | ||||||
|  |         int ret, retries = ([]() -> int { | ||||||
|  |           unsigned long ret; | ||||||
|  |           char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end; | ||||||
|  |  | ||||||
|  |           if (!retries) return 15; | ||||||
|  |           if (!strcmp(retries, "infinity")) return -1; | ||||||
|  |  | ||||||
|  |           ret = strtoul(retries, &end, 10); | ||||||
|  |           if (*end || ret > INT_MAX) { | ||||||
|  |             fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n", retries); | ||||||
|  |             exit(1); | ||||||
|  |           } | ||||||
|  |           return (int)ret; | ||||||
|  |         })(); | ||||||
|  |  | ||||||
|  |         char *begin, *end; | ||||||
|  |         auto mmutable = strdup(peerConfig.endpoint.c_str()); | ||||||
|  |         if (!mmutable) throw std::string("strdup"); | ||||||
|  |         if (!peerConfig.endpoint.size()) { | ||||||
|  |           free(mmutable); | ||||||
|  |           throw std::string("Unable to parse empty endpoint"); | ||||||
|  |         } | ||||||
|  |         if (mmutable[0] == '[') { | ||||||
|  |           begin = &mmutable[1]; | ||||||
|  |           end = strchr(mmutable, ']'); | ||||||
|  |           if (!end) { | ||||||
|  |             free(mmutable); | ||||||
|  |             throw std::string("Unable to find matching brace of endpoint: ").append(peerConfig.endpoint); | ||||||
|  |           } | ||||||
|  |           *end++ = '\0'; | ||||||
|  |           if (*end++ != ':' || !*end) { | ||||||
|  |             free(mmutable); | ||||||
|  |             throw std::string("Unable to find port of endpoint: ").append(peerConfig.endpoint); | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           begin = mmutable; | ||||||
|  |           end = strrchr(mmutable, ':'); | ||||||
|  |           if (!end || !*(end + 1)) { | ||||||
|  |             free(mmutable); | ||||||
|  |             throw std::string("Unable to find port of endpoint: ").append(peerConfig.endpoint); | ||||||
|  |           } | ||||||
|  |           *end++ = '\0'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         ADDRINFOA *resolved; | ||||||
|  |         for (unsigned int timeout = 1000000;; timeout = ((20000000) < (timeout * 6 / 5) ? (20000000) : (timeout * 6 / 5))) { | ||||||
|  |           // ret = getaddrinfo(begin, end, &hints, &resolved); | ||||||
|  |           ret = getaddrinfo(begin, end, NULL, &resolved); | ||||||
|  |           if (!ret) break; | ||||||
|  |           if (ret == EAI_NONAME || ret == EAI_FAIL || | ||||||
|  |             #ifdef EAI_NODATA | ||||||
|  |               ret == EAI_NODATA || | ||||||
|  |             #endif | ||||||
|  |               (retries >= 0 && !retries--)) { | ||||||
|  |             free(mmutable); | ||||||
|  |             throw std::string("Error code: ").append(std::to_string(ret)); | ||||||
|  |           } | ||||||
|  |           std::this_thread::sleep_for(std::chrono::microseconds(timeout)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(SOCKADDR_IN))) memcpy(&wg_peer->Endpoint.Ipv4, resolved->ai_addr, resolved->ai_addrlen); | ||||||
|  |         else if (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(SOCKADDR_IN6)) memcpy(&wg_peer->Endpoint.Ipv6, resolved->ai_addr, resolved->ai_addrlen); | ||||||
|  |         else { | ||||||
|  |           freeaddrinfo(resolved); | ||||||
|  |           throw std::string("Neither IPv4 nor IPv6 address found: ").append(peerConfig.endpoint); | ||||||
|  |         } | ||||||
|  |         freeaddrinfo(resolved); | ||||||
|  |         free(mmutable); | ||||||
|  |  | ||||||
|  |         wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  | 	    wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer); | ||||||
|  |       for (auto Ip : peerConfig.allowedIPs.getIpParsed()) { | ||||||
|  |         wg_aip->AddressFamily = Ip.Proto == 4 ? AF_INET : AF_INET6; | ||||||
|  |         wg_aip->Cidr = Ip.Mask; | ||||||
|  |  | ||||||
|  |         if (Ip.Proto == 6 && inet_pton(AF_INET6, Ip.Address.c_str(), &wg_aip->Address.V6) == 1) wg_aip->AddressFamily = AF_INET6; | ||||||
|  |         else if (Ip.Proto == 4 && inet_pton(AF_INET, Ip.Address.c_str(), &wg_aip->Address.V4) == 1) wg_aip->AddressFamily = AF_INET; | ||||||
|  |         else continue; | ||||||
|  |  | ||||||
|  |         wg_peer->AllowedIPsCount++; | ||||||
|  | 	      wg_aip = changePoint<WIREGUARD_ALLOWED_IP, WIREGUARD_ALLOWED_IP>(wg_aip); | ||||||
|  |         if (!(wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REPLACE_ALLOWED_IPS)) wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REPLACE_ALLOWED_IPS); | ||||||
|  |       } | ||||||
|  | 	    wg_peer = reinterpret_cast<WIREGUARD_PEER*>(((char*)wg_aip)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(this->name)); | ||||||
|  |   if (!Adapter) Adapter = WireGuardCreateAdapter(toLpcwstr(this->name), WireguardAddonDescription, NULL); | ||||||
|  |   if (!Adapter) throw std::string("Failed to create adapter, ").append(getErrorString(GetLastError())); | ||||||
|  |  | ||||||
|  |   auto status = WireGuardSetConfiguration(Adapter, reinterpret_cast<WIREGUARD_INTERFACE*>(wg_iface), buf_len) && WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP); | ||||||
|  |   free(wg_iface); | ||||||
|  |  | ||||||
|  |   if (!status) { | ||||||
|  |     auto status = GetLastError(); | ||||||
|  |     WireGuardCloseAdapter(Adapter); | ||||||
|  |     throw std::string("Failed to set interface config, ").append(getErrorString(status)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->interfaceAddress.SetInInterface(this->name); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void IpManeger::GetInInterface(std::string interfaceName) { | ||||||
|  |   // Define the InterfaceLuid of the network interface you want to query | ||||||
|  |   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(interfaceName)); | ||||||
|  |   if (!Adapter) throw std::string("Cannot open wireguard adapter"); | ||||||
|  |   NET_LUID InterfaceLuid; | ||||||
|  |   WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); | ||||||
|  |  | ||||||
|  |   ULONG bufferSize = 0; // Initial buffer size | ||||||
|  |   // Call GetAdaptersAddresses to get the required buffer size | ||||||
|  |   if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &bufferSize) == ERROR_BUFFER_OVERFLOW) { | ||||||
|  |     // Allocate memory for the buffer | ||||||
|  |     PIP_ADAPTER_ADDRESSES addresses = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(bufferSize)); | ||||||
|  |     // Call GetAdaptersAddresses again with the allocated buffer | ||||||
|  |     if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, addresses, &bufferSize) == NO_ERROR) { | ||||||
|  |       // Iterate through the list of adapters | ||||||
|  |       for (PIP_ADAPTER_ADDRESSES adapter = addresses; adapter != nullptr; adapter = adapter->Next) { | ||||||
|  |         // Check if the adapter matches the specified InterfaceLuid | ||||||
|  |         if (memcmp(&adapter->Luid, &InterfaceLuid, sizeof(NET_LUID)) == 0) { | ||||||
|  |           // Iterate through the list of IP addresses associated with the adapter | ||||||
|  |           for (PIP_ADAPTER_UNICAST_ADDRESS address = adapter->FirstUnicastAddress; address != nullptr; address = address->Next) { | ||||||
|  |             // Access the IP address in the address structure | ||||||
|  |             sockaddr* sa = address->Address.lpSockaddr; | ||||||
|  |             char ip[INET6_ADDRSTRLEN]; | ||||||
|  |             if (sa->sa_family == AF_INET) { | ||||||
|  |               inet_ntop(AF_INET, &reinterpret_cast<sockaddr_in*>(sa)->sin_addr, ip, sizeof(ip)); | ||||||
|  |             } else if (sa->sa_family == AF_INET6) { | ||||||
|  |               inet_ntop(AF_INET6, &reinterpret_cast<sockaddr_in6*>(sa)->sin6_addr, ip, sizeof(ip)); | ||||||
|  |             } else continue; | ||||||
|  |             // Print or use the IP address as needed | ||||||
|  |             this->addIPMask(std::string(ip).append("/").append(std::to_string(address->Address.iSockaddrLength))); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Free the allocated buffer | ||||||
|  |     free(addresses); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // https://docs.microsoft.com/en-us/windows/desktop/api/netioapi/nf-netioapi-createunicastipaddressentry | ||||||
|  | void IpManeger::SetInInterface(std::string interfaceName) { | ||||||
|  |   if (this->size() == 0) return; | ||||||
|  |   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(interfaceName)); | ||||||
|  |   if (!Adapter) throw std::string("Cannot open wireguard adapter"); | ||||||
|  |  | ||||||
|  |   NET_LUID InterfaceLuid; | ||||||
|  |   WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); | ||||||
|  |   ULONG bufferSize = 0; // Initial buffer size | ||||||
|  |   // Call GetAdaptersAddresses to get the required buffer size | ||||||
|  |   if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, nullptr, &bufferSize) == ERROR_BUFFER_OVERFLOW) { | ||||||
|  |     // Allocate memory for the buffer | ||||||
|  |     PIP_ADAPTER_ADDRESSES addresses = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(bufferSize)); | ||||||
|  |     // Call GetAdaptersAddresses again with the allocated buffer | ||||||
|  |     if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, addresses, &bufferSize) == NO_ERROR) { | ||||||
|  |       // Iterate through the list of adapters | ||||||
|  |       for (PIP_ADAPTER_ADDRESSES adapter = addresses; adapter != nullptr; adapter = adapter->Next) { | ||||||
|  |         // Check if the adapter matches the specified InterfaceLuid | ||||||
|  |         if (memcmp(&adapter->Luid, &InterfaceLuid, sizeof(NET_LUID)) == 0) { | ||||||
|  |           // Iterate through the list of IP addresses associated with the adapter | ||||||
|  |           for (PIP_ADAPTER_UNICAST_ADDRESS address = adapter->FirstUnicastAddress; address != nullptr; address = address->Next) { | ||||||
|  |             // Access the IP address in the address structure | ||||||
|  |             sockaddr* sa = address->Address.lpSockaddr; | ||||||
|  |             char ip[INET6_ADDRSTRLEN]; | ||||||
|  |             if (sa->sa_family == AF_INET) { | ||||||
|  |               inet_ntop(AF_INET, &reinterpret_cast<sockaddr_in*>(sa)->sin_addr, ip, sizeof(ip)); | ||||||
|  |             } else if (sa->sa_family == AF_INET6) { | ||||||
|  |               inet_ntop(AF_INET6, &reinterpret_cast<sockaddr_in6*>(sa)->sin6_addr, ip, sizeof(ip)); | ||||||
|  |             } else continue; | ||||||
|  |  | ||||||
|  |             // Delete the IP address | ||||||
|  |             MIB_UNICASTIPADDRESS_ROW row; | ||||||
|  |             memset(&row, 0, sizeof(row)); | ||||||
|  |             WireGuardGetAdapterLUID(Adapter, &row.InterfaceLuid); | ||||||
|  |             if (sa->sa_family == AF_INET) { | ||||||
|  |               row.Address.si_family = AF_INET; | ||||||
|  |               inet_pton(AF_INET, ip, &row.Address.Ipv4.sin_addr); | ||||||
|  |             } else if (sa->sa_family == AF_INET6) { | ||||||
|  |               row.Address.si_family = AF_INET6; | ||||||
|  |               inet_pton(AF_INET6, ip, &row.Address.Ipv6.sin6_addr); | ||||||
|  |             } else continue; | ||||||
|  |  | ||||||
|  |             if (DeleteUnicastIpAddressEntry(&row) != NO_ERROR) throw std::string("Cannot delete IP address from interface"); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Free the allocated buffer | ||||||
|  |     free(addresses); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (auto ip : this->getIpParsed()) { | ||||||
|  |     MIB_UNICASTIPADDRESS_ROW row; | ||||||
|  |     memset(&row, 0, sizeof(row)); | ||||||
|  |     memcpy(&row.InterfaceLuid, &InterfaceLuid, sizeof(NET_LUID)); | ||||||
|  |  | ||||||
|  |     row.DadState = NldsPreferred; | ||||||
|  |     row.ValidLifetime = 0xffffffff; | ||||||
|  |     row.PreferredLifetime = 0xffffffff; | ||||||
|  |  | ||||||
|  |     row.OnLinkPrefixLength = ip.Mask; | ||||||
|  |     if (ip.Proto == 4) { | ||||||
|  |       row.Address.si_family = AF_INET; | ||||||
|  |       inet_pton(AF_INET, ip.Address.c_str(), &row.Address.Ipv4.sin_addr); | ||||||
|  |     } else if (ip.Proto == 6) { | ||||||
|  |       row.Address.si_family = AF_INET6; | ||||||
|  |       inet_pton(AF_INET6, ip.Address.c_str(), &row.Address.Ipv6.sin6_addr); | ||||||
|  |     } else continue; | ||||||
|  |  | ||||||
|  |     if (CreateUnicastIpAddressEntry(&row) != NO_ERROR) throw std::string("Cannot add IP address to interface"); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								addon/win/x86/wireguard.dll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								addon/win/x86/wireguard.dll
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,163 +0,0 @@ | |||||||
| #include <napi.h> |  | ||||||
| #include "wgkeys.hh" |  | ||||||
|  |  | ||||||
| class privateKeyWorker : public Napi::AsyncWorker { |  | ||||||
|   private: |  | ||||||
|     std::string pskString; |  | ||||||
|     Napi::Promise::Deferred genPromise; |  | ||||||
|   public: |  | ||||||
|   ~privateKeyWorker() {} |  | ||||||
|   privateKeyWorker(const Napi::Env env) : AsyncWorker(env), genPromise{env} {} |  | ||||||
|   Napi::Promise getPromise() { return genPromise.Promise(); } |  | ||||||
|   void Execute() override { |  | ||||||
|     wg_key keyg; |  | ||||||
|     wgKeys::generatePrivate(keyg); |  | ||||||
|     pskString = wgKeys::toString(keyg); |  | ||||||
|   } |  | ||||||
|   void OnOK() override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     genPromise.Resolve(Napi::String::New(Env(), pskString)); |  | ||||||
|   } |  | ||||||
|   void OnError(const Napi::Error& e) override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     genPromise.Reject(e.Value()); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class publicKeyWorker : public Napi::AsyncWorker { |  | ||||||
|   private: |  | ||||||
|     std::string privKey, pubString; |  | ||||||
|     Napi::Promise::Deferred genPromise; |  | ||||||
|   public: |  | ||||||
|   ~publicKeyWorker() {} |  | ||||||
|   publicKeyWorker(const Napi::Env env, std::string privateKey) : AsyncWorker(env), privKey(privateKey), genPromise{env} {} |  | ||||||
|   Napi::Promise getPromise() { return genPromise.Promise(); } |  | ||||||
|   void Execute() override { |  | ||||||
|     wg_key interfacePrivateKey, interfacePublicKey; |  | ||||||
|     try { |  | ||||||
|       wgKeys::stringToKey(interfacePrivateKey, privKey); |  | ||||||
|       wgKeys::generatePublic(interfacePublicKey, interfacePrivateKey); |  | ||||||
|       pubString = wgKeys::toString(interfacePublicKey); |  | ||||||
|     } catch (std::string &err) { |  | ||||||
|       SetError(err); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   void OnOK() override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     genPromise.Resolve(Napi::String::New(Env(), pubString)); |  | ||||||
|   } |  | ||||||
|   void OnError(const Napi::Error& e) override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     genPromise.Reject(e.Value()); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class presharedKeyWorker : public Napi::AsyncWorker { |  | ||||||
|   private: |  | ||||||
|     std::string pskString; |  | ||||||
|     Napi::Promise::Deferred genPromise; |  | ||||||
|   public: |  | ||||||
|   ~presharedKeyWorker() {} |  | ||||||
|   presharedKeyWorker(const Napi::Env env) : AsyncWorker(env), genPromise{env} {} |  | ||||||
|   Napi::Promise getPromise() { return genPromise.Promise(); } |  | ||||||
|   void Execute() override { |  | ||||||
|     wg_key keyg; |  | ||||||
|     wgKeys::generatePreshared(keyg); |  | ||||||
|     pskString = wgKeys::toString(keyg); |  | ||||||
|   } |  | ||||||
|   void OnOK() override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     genPromise.Resolve(Napi::String::New(Env(), pskString)); |  | ||||||
|   } |  | ||||||
|   void OnError(const Napi::Error& e) override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     genPromise.Reject(e.Value()); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class genKeysWorker : public Napi::AsyncWorker { |  | ||||||
|   private: |  | ||||||
|     std::string privateKey, publicKey, presharedKey; |  | ||||||
|     bool withPreshared = false; |  | ||||||
|     Napi::Promise::Deferred genPromise; |  | ||||||
|   public: |  | ||||||
|   ~genKeysWorker() {} |  | ||||||
|   genKeysWorker(const Napi::Env env, bool withPresharedKey) : AsyncWorker(env), withPreshared(withPresharedKey), genPromise{env} {} |  | ||||||
|   Napi::Promise getPromise() { return genPromise.Promise(); } |  | ||||||
|   void Execute() override { |  | ||||||
|     wg_key keyPriv, preshe, pub; |  | ||||||
|  |  | ||||||
|     wgKeys::generatePrivate(keyPriv); |  | ||||||
|     privateKey = wgKeys::toString(keyPriv); |  | ||||||
|  |  | ||||||
|     wgKeys::generatePublic(pub, keyPriv); |  | ||||||
|     publicKey = wgKeys::toString(pub); |  | ||||||
|  |  | ||||||
|     if (!withPreshared) return; |  | ||||||
|     wgKeys::generatePreshared(preshe); |  | ||||||
|     presharedKey = wgKeys::toString(preshe); |  | ||||||
|   } |  | ||||||
|   void OnOK() override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     const Napi::Env env = Env(); |  | ||||||
|     auto keys = Napi::Object::New(env); |  | ||||||
|     keys.Set("privateKey", privateKey); |  | ||||||
|     keys.Set("publicKey", publicKey); |  | ||||||
|     if (withPreshared) keys.Set("presharedKey", presharedKey); |  | ||||||
|  |  | ||||||
|     genPromise.Resolve(keys); |  | ||||||
|   } |  | ||||||
|   void OnError(const Napi::Error& e) override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     genPromise.Reject(e.Value()); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| Napi::Object Init(Napi::Env exportsEnv, Napi::Object exports) { |  | ||||||
|   auto constants = Napi::Object::New(exportsEnv); |  | ||||||
|   constants.Set("WG_KEY_LENGTH", WG_KEY_LENGTH); |  | ||||||
|   constants.Set("B64_WG_KEY_LENGTH", B64_WG_KEY_LENGTH); |  | ||||||
|   exports.Set("constants", constants); |  | ||||||
|  |  | ||||||
|   exports.Set("presharedKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo& info) { |  | ||||||
|     const Napi::Env env = info.Env(); |  | ||||||
|  |  | ||||||
|     // Callback function is latest argument |  | ||||||
|     auto *Gen = new presharedKeyWorker(env); |  | ||||||
|     Gen->Queue(); |  | ||||||
|     return Gen->getPromise(); |  | ||||||
|   })); |  | ||||||
|  |  | ||||||
|   exports.Set("privateKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo& info) { |  | ||||||
|     const Napi::Env env = info.Env(); |  | ||||||
|  |  | ||||||
|     // Callback function is latest argument |  | ||||||
|     auto *Gen = new privateKeyWorker(env); |  | ||||||
|     Gen->Queue(); |  | ||||||
|     return Gen->getPromise(); |  | ||||||
|   })); |  | ||||||
|  |  | ||||||
|   exports.Set("publicKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo& info) -> Napi::Value { |  | ||||||
|     const Napi::Env env = info.Env(); |  | ||||||
|     if (!(info[0].IsString())) { |  | ||||||
|       Napi::Error::New(env, "Require private key").ThrowAsJavaScriptException(); |  | ||||||
|       return env.Undefined(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Callback function is latest argument |  | ||||||
|     auto *Gen = new publicKeyWorker(env, info[0].ToString().Utf8Value().c_str()); |  | ||||||
|     Gen->Queue(); |  | ||||||
|     return Gen->getPromise(); |  | ||||||
|   })); |  | ||||||
|  |  | ||||||
|   exports.Set("genKey", Napi::Function::New(exportsEnv, [&](const Napi::CallbackInfo &info) { |  | ||||||
|     const Napi::Env env = info.Env(); |  | ||||||
|     bool withPreshared = false; |  | ||||||
|     if (info[0].IsBoolean()) withPreshared = info[0].ToBoolean().Value(); |  | ||||||
|     auto Gen = new genKeysWorker(env, withPreshared); |  | ||||||
|     Gen->Queue(); |  | ||||||
|     return Gen->getPromise(); |  | ||||||
|   })); |  | ||||||
|   return exports; |  | ||||||
| } |  | ||||||
| NODE_API_MODULE(addon, Init); |  | ||||||
| @@ -1,29 +0,0 @@ | |||||||
| #ifndef _WGKEY_ |  | ||||||
| #define _WGKEY_ |  | ||||||
| #include <string> |  | ||||||
|  |  | ||||||
| const int WG_KEY_LENGTH = 32, B64_WG_KEY_LENGTH = ((WG_KEY_LENGTH + 2) / 3) * 4; |  | ||||||
| typedef unsigned char wg_key[WG_KEY_LENGTH]; |  | ||||||
| typedef char wg_key_b64_string[B64_WG_KEY_LENGTH + 1]; |  | ||||||
| typedef long long fe[16]; |  | ||||||
|  |  | ||||||
| namespace wgKeys { |  | ||||||
|   /* Convert wg_key to std::string */ |  | ||||||
|   std::string toString(const wg_key key); |  | ||||||
|  |  | ||||||
|   /* base64 to wg_key */ |  | ||||||
|   void stringToKey(wg_key key, std::string keyBase64); |  | ||||||
|  |  | ||||||
|   // bool key_is_zero(wg_key key); |  | ||||||
|  |  | ||||||
|   /* Generate preshared key */ |  | ||||||
|   void generatePreshared(wg_key key); |  | ||||||
|  |  | ||||||
|   /* Generate private key (based on generatePreshared) */ |  | ||||||
|   void generatePrivate(wg_key private_key); |  | ||||||
|  |  | ||||||
|   /* Get public key from private key */ |  | ||||||
|   void generatePublic(wg_key public_key, const wg_key private_key); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| #include <vector> |  | ||||||
| #include <string> |  | ||||||
|  |  | ||||||
| std::string setIps(std::string name, std::vector<std::string> ips) { |  | ||||||
|   return ""; |  | ||||||
| } |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| #include <napi.h> |  | ||||||
| #include <wginterface.hh> |  | ||||||
|  |  | ||||||
| unsigned long maxName() { |  | ||||||
|   return 16; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::string versionDrive() { |  | ||||||
|   return "Userspace"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void listDevices::Execute() {} |  | ||||||
| void deleteInterface::Execute() {} |  | ||||||
| void setConfig::Execute() {} |  | ||||||
| void getConfig::Execute() {} |  | ||||||
| @@ -1,353 +0,0 @@ | |||||||
| #include <napi.h> |  | ||||||
| #include <iostream> |  | ||||||
| #include <unistd.h> |  | ||||||
| #include <time.h> |  | ||||||
| #include <arpa/inet.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
| #include <sys/socket.h> |  | ||||||
| #include <netdb.h> |  | ||||||
| #include <unistd.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include <netinet/in.h> |  | ||||||
| #include <net/if.h> |  | ||||||
| #include <linux/netlink.h> |  | ||||||
| #include <linux/rtnetlink.h> |  | ||||||
| #include <linux/if_link.h> |  | ||||||
| #include <linux/if_addr.h> |  | ||||||
| #include <linux/if_ether.h> |  | ||||||
| #include <linux/if_arp.h> |  | ||||||
| #include <sys/ioctl.h> |  | ||||||
| #include <cerrno> |  | ||||||
| #include <ifaddrs.h> |  | ||||||
| #include <string> |  | ||||||
| #include <sysexits.h> |  | ||||||
| #include <sys/types.h> |  | ||||||
| #include "wginterface.hh" |  | ||||||
| #include "linux/set_ip.cpp" |  | ||||||
| extern "C" { |  | ||||||
|   #include "linux/wireguard.h" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::string getKernelMesage(int errStatus) { |  | ||||||
|   std::string message = std::string("Error code: ").append(std::to_string(errStatus)); |  | ||||||
|   return message; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| unsigned long maxName() { |  | ||||||
|   return IFNAMSIZ; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::string versionDrive() { |  | ||||||
|   return "Kernel"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| class List { |  | ||||||
|   public: |  | ||||||
|   std::vector<std::string> devs; |  | ||||||
|  |  | ||||||
|   List() {} |  | ||||||
|   ~List() { |  | ||||||
|     devs.clear(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void getAll() { |  | ||||||
|     char *device_name, *devicesList = wg_list_device_names(); |  | ||||||
|     if (!devicesList) throw std::string("Unable to get device names"); |  | ||||||
|     size_t len; |  | ||||||
|     for ((device_name) = (devicesList), (len) = 0; ((len) = strlen(device_name)); (device_name) += (len) + 1) devs.push_back(std::string(device_name)); |  | ||||||
|     free(devicesList); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   bool exist(std::string ifname) { |  | ||||||
|     this->getAll(); |  | ||||||
|     for (auto wg : devs) if (wg == ifname) return true; |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| void listDevices::Execute() { |  | ||||||
|   List l; |  | ||||||
|   try { |  | ||||||
|     l.getAll(); |  | ||||||
|     for (auto ifname : l.devs) { |  | ||||||
|       listInfo setInfo; |  | ||||||
|       setInfo.tunType = "kernel"; |  | ||||||
|       deviceNames[ifname] = setInfo; |  | ||||||
|     } |  | ||||||
|   } catch (std::string err) { |  | ||||||
|     SetError(err); |  | ||||||
|   } |  | ||||||
|   l.~List(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void deleteInterface::Execute() { |  | ||||||
|   int status = wg_del_device(wgName.c_str()); |  | ||||||
|   if (status < 0) SetError(std::string("Cannot delete interface, code status: ").append(std::to_string(status))); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int createInterface(std::string &wgName) { |  | ||||||
|   bool createInterface = true; |  | ||||||
|   size_t len = 0; |  | ||||||
|   char *device_name, *devicesList = wg_list_device_names(); |  | ||||||
|   if (!!devicesList) { |  | ||||||
|     for ((device_name) = (devicesList), (len) = 0; ((len) = strlen(device_name)); (device_name) += (len) + 1) { |  | ||||||
|       if (std::string(device_name) == wgName) { |  | ||||||
|         createInterface = false; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     free(devicesList); |  | ||||||
|   } |  | ||||||
|   if (createInterface) return wg_add_device(wgName.c_str()); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void setConfig::Execute() { |  | ||||||
|   int res = createInterface(wgName); |  | ||||||
|   if (res < 0) { |  | ||||||
|     SetError(std::string("Cannot create wireguard interface, Code: ").append(std::to_string(res))); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Set device struct |  | ||||||
|   auto deviceStruct = new wg_device({}); |  | ||||||
|   strncpy(deviceStruct->name, wgName.c_str(), wgName.length()); |  | ||||||
|  |  | ||||||
|   // Set private key |  | ||||||
|   wg_key_from_base64(deviceStruct->private_key, privateKey.c_str()); |  | ||||||
|   deviceStruct->flags = (wg_device_flags)WGDEVICE_HAS_PRIVATE_KEY; |  | ||||||
|  |  | ||||||
|   // Set public key |  | ||||||
|   if (publicKey.length() > 0) { |  | ||||||
|     wg_key_from_base64(deviceStruct->public_key, publicKey.c_str()); |  | ||||||
|     deviceStruct->flags = (wg_device_flags)WGDEVICE_HAS_PUBLIC_KEY; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Port listenings |  | ||||||
|   if (portListen > 0 && 25565 < portListen) { |  | ||||||
|     deviceStruct->listen_port = portListen; |  | ||||||
|     deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_HAS_LISTEN_PORT); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Linux firewall mark |  | ||||||
|   if (fwmark >= 0) { |  | ||||||
|     deviceStruct->fwmark = fwmark; |  | ||||||
|     deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_HAS_FWMARK); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Replace Peers |  | ||||||
|   if (replacePeers) deviceStruct->flags = (wg_device_flags)(deviceStruct->flags|WGDEVICE_REPLACE_PEERS); |  | ||||||
|  |  | ||||||
|   unsigned int peerIndex = 0; |  | ||||||
|   for (auto it = peersVector.begin(); it != peersVector.end(); ++it) { |  | ||||||
|     const std::string peerPubKey = it->first; |  | ||||||
|     auto peerConfig = it->second; |  | ||||||
|     peerIndex++; |  | ||||||
|  |  | ||||||
|     wg_peer *peerStruct = new wg_peer({}); |  | ||||||
|     // Set public key |  | ||||||
|     wg_key_from_base64(peerStruct->public_key, peerPubKey.c_str()); |  | ||||||
|     peerStruct->flags = (wg_peer_flags)WGPEER_HAS_PUBLIC_KEY; |  | ||||||
|  |  | ||||||
|     // Remove Peer |  | ||||||
|     if (peerConfig.removeMe) peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_REMOVE_ME); |  | ||||||
|     else { |  | ||||||
|       // Set preshared key if present |  | ||||||
|       if (peerConfig.presharedKey.length() > 0) { |  | ||||||
|         wg_key_from_base64(peerStruct->preshared_key, peerConfig.presharedKey.c_str()); |  | ||||||
|         peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_HAS_PRESHARED_KEY); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       // Set Keepalive |  | ||||||
|       if (peerConfig.keepInterval > 0) { |  | ||||||
|         peerStruct->persistent_keepalive_interval = peerConfig.keepInterval; |  | ||||||
|         peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       // Set endpoint |  | ||||||
|       if (peerConfig.endpoint.length() > 0) { |  | ||||||
|         sockaddr endpoint; |  | ||||||
|         int ret, retries; |  | ||||||
|         char *begin, *end; |  | ||||||
|         char *Endpoint = strdup(peerConfig.endpoint.c_str()); |  | ||||||
|         if (Endpoint[0] == '[') { |  | ||||||
|           begin = &Endpoint[1]; |  | ||||||
|           end = strchr(Endpoint, ']'); |  | ||||||
|           if (!end) { |  | ||||||
|             free(Endpoint); |  | ||||||
|             SetError("Unable to find matching brace of endpoint"); |  | ||||||
|             return; |  | ||||||
|           } |  | ||||||
|           *end++ = '\0'; |  | ||||||
|           if (*end++ != ':' || !*end) { |  | ||||||
|             free(Endpoint); |  | ||||||
|             SetError("Unable to find port of endpoint"); |  | ||||||
|             return; |  | ||||||
|           } |  | ||||||
|         } else { |  | ||||||
|           begin = Endpoint; |  | ||||||
|           end = strrchr(Endpoint, ':'); |  | ||||||
|           if (!end || !*(end + 1)) { |  | ||||||
|             free(Endpoint); |  | ||||||
|             SetError("Unable to find port of endpoint"); |  | ||||||
|             return; |  | ||||||
|           } |  | ||||||
|           *end++ = '\0'; |  | ||||||
|         } |  | ||||||
|         addrinfo *resolved; |  | ||||||
|         addrinfo hints = { |  | ||||||
|           ai_family: AF_UNSPEC, |  | ||||||
|           ai_socktype: SOCK_DGRAM, |  | ||||||
|           ai_protocol: IPPROTO_UDP |  | ||||||
|         }; |  | ||||||
|         #define min(a, b) ((a) < (b) ? (a) : (b)) |  | ||||||
|         for (unsigned int timeout = 1000000;; timeout = min(20000000, timeout * 6 / 5)) { |  | ||||||
|           ret = getaddrinfo(begin, end, &hints, &resolved); |  | ||||||
|           if (!ret) break; |  | ||||||
|           if (ret == EAI_NONAME || ret == EAI_FAIL || |  | ||||||
|             #ifdef EAI_NODATA |  | ||||||
|               ret == EAI_NODATA || |  | ||||||
|             #endif |  | ||||||
|               (retries >= 0 && !retries--)) { |  | ||||||
|             free(Endpoint); |  | ||||||
|             fprintf(stderr, "%s: `%s'\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), peerConfig.endpoint.c_str()); |  | ||||||
|             SetError("Unable to resolve endpoint"); |  | ||||||
|             return; |  | ||||||
|           } |  | ||||||
|           fprintf(stderr, "%s: `%s'. Trying again in %.2f seconds...\n", ret == EAI_SYSTEM ? strerror(errno) : gai_strerror(ret), peerConfig.endpoint.c_str(), timeout / 1000000.0); |  | ||||||
|           usleep(timeout); |  | ||||||
|         } |  | ||||||
|         if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(sockaddr_in)) || (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(sockaddr_in6))) { |  | ||||||
|           memcpy(&endpoint, resolved->ai_addr, resolved->ai_addrlen); |  | ||||||
|           memccpy(&peerStruct->endpoint.addr, &endpoint, 0, sizeof(peerStruct->endpoint.addr)); |  | ||||||
|           if (resolved->ai_family == AF_INET) { |  | ||||||
|             peerStruct->endpoint.addr4.sin_addr.s_addr = ((sockaddr_in *)&endpoint)->sin_addr.s_addr; |  | ||||||
|             peerStruct->endpoint.addr4.sin_port = ((sockaddr_in *)&endpoint)->sin_port; |  | ||||||
|             peerStruct->endpoint.addr4.sin_family = AF_INET; |  | ||||||
|           } else { |  | ||||||
|             peerStruct->endpoint.addr6.sin6_addr = ((struct sockaddr_in6 *)&endpoint)->sin6_addr; |  | ||||||
|             peerStruct->endpoint.addr6.sin6_port = ((struct sockaddr_in6 *)&endpoint)->sin6_port; |  | ||||||
|             peerStruct->endpoint.addr6.sin6_family = AF_INET6; |  | ||||||
|           } |  | ||||||
|         } else { |  | ||||||
|           freeaddrinfo(resolved); |  | ||||||
|           free(Endpoint); |  | ||||||
|           SetError("Neither IPv4 nor IPv6 address found"); |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
|         freeaddrinfo(resolved); |  | ||||||
|         free(Endpoint); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       // Set allowed IPs |  | ||||||
|       if (peerConfig.allowedIPs.size() > 0) { |  | ||||||
|         peerStruct->flags = (wg_peer_flags)(peerStruct->flags|WGPEER_REPLACE_ALLOWEDIPS); |  | ||||||
|         for (unsigned int allowIndex = 0; allowIndex < peerConfig.allowedIPs.size(); allowIndex++) { |  | ||||||
|           auto ip = peerConfig.allowedIPs[allowIndex]; |  | ||||||
|           unsigned long cidr = 0; |  | ||||||
|           if (ip.find("/") != std::string::npos) { |  | ||||||
|             cidr = std::stoi(ip.substr(ip.find("/")+1)); |  | ||||||
|             ip = ip.substr(0, ip.find("/")); |  | ||||||
|           } |  | ||||||
|           wg_allowedip *newAllowedIP = new wg_allowedip({family: AF_UNSPEC}); |  | ||||||
|           if (strchr(ip.c_str(), ':')) { |  | ||||||
|             if (inet_pton(AF_INET6, ip.c_str(), &newAllowedIP->ip6) == 1) { |  | ||||||
|               newAllowedIP->family = AF_INET6; |  | ||||||
|               if (cidr == 0) cidr = 128; |  | ||||||
|             } |  | ||||||
|           } else { |  | ||||||
|             if (inet_pton(AF_INET, ip.c_str(), &newAllowedIP->ip4) == 1) { |  | ||||||
|               newAllowedIP->family = AF_INET; |  | ||||||
|               if (cidr == 0) cidr = 32; |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|           if (newAllowedIP->family == AF_UNSPEC || cidr <= 0) continue; |  | ||||||
|           newAllowedIP->cidr = cidr; |  | ||||||
|           if (allowIndex > 0) newAllowedIP->next_allowedip = peerStruct->first_allowedip; |  | ||||||
|           peerStruct->first_allowedip = newAllowedIP; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Add to Peer struct |  | ||||||
|     if (peerIndex > 0) peerStruct->next_peer = deviceStruct->first_peer; |  | ||||||
|     deviceStruct->first_peer = peerStruct; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Set interface config |  | ||||||
|   if ((res = wg_set_device(deviceStruct)) < 0) SetError(getKernelMesage(res)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const char* getHostAddress(bool addPort, const sockaddr* addr) { |  | ||||||
|   char host[4096 + 1], service[512 + 1]; |  | ||||||
|   static char buf[sizeof(host) + sizeof(service) + 4]; |  | ||||||
|   memset(buf, 0, sizeof(buf)); |  | ||||||
|   int ret; |  | ||||||
|   socklen_t addr_len = 0; |  | ||||||
|   if (addr->sa_family == AF_INET) addr_len = sizeof(struct sockaddr_in); |  | ||||||
|   else if (addr->sa_family == AF_INET6) addr_len = sizeof(struct sockaddr_in6); |  | ||||||
|  |  | ||||||
|   ret = getnameinfo(addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST); |  | ||||||
|   if (ret) { |  | ||||||
|     strncpy(buf, gai_strerror(ret), sizeof(buf) - 1); |  | ||||||
|     buf[sizeof(buf) - 1] = '\0'; |  | ||||||
|   } else { |  | ||||||
|     if (addPort) snprintf(buf, sizeof(buf), (addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service); |  | ||||||
|     else snprintf(buf, sizeof(buf), "%s", host); |  | ||||||
|   } |  | ||||||
|   return buf; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::string keyTo64(const uint8_t *key) { |  | ||||||
|   wg_key_b64_string strKey; |  | ||||||
|   wg_key_to_base64(strKey, key); |  | ||||||
|   return strKey; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void getConfig::Execute() { |  | ||||||
|   int res; wg_device *device; |  | ||||||
|   if ((res = wg_get_device(&device, strdup(wgName.c_str()))) < 0) { |  | ||||||
|     SetError(std::string("Device not exists or cannot get config from this interface!, code error: ").append(std::to_string(res))); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (device->flags & WGDEVICE_HAS_PRIVATE_KEY) privateKey = keyTo64(device->private_key); |  | ||||||
|   if (device->flags & WGDEVICE_HAS_PUBLIC_KEY) publicKey = keyTo64(device->public_key); |  | ||||||
|   if (device->listen_port > 0) portListen = device->listen_port; |  | ||||||
|  |  | ||||||
|   // Set Address array and get interface ip addresses |  | ||||||
|   ifaddrs* ptr_ifaddrs = nullptr; |  | ||||||
|   if(getifaddrs(&ptr_ifaddrs) > 0) { |  | ||||||
|     for (ifaddrs* ptr_entry = ptr_ifaddrs; ptr_entry != nullptr; ptr_entry = ptr_entry->ifa_next) { |  | ||||||
|       if (ptr_entry->ifa_addr == nullptr) continue; |  | ||||||
|       else if (strcmp(ptr_entry->ifa_name, wgName.c_str()) != 0) continue; |  | ||||||
|       else if (ptr_entry->ifa_addr->sa_family == AF_INET) Address.push_back(getHostAddress(false, ptr_entry->ifa_addr)); |  | ||||||
|       else if (ptr_entry->ifa_addr->sa_family == AF_INET6) Address.push_back(getHostAddress(false, ptr_entry->ifa_addr)); |  | ||||||
|     } |  | ||||||
|     freeifaddrs(ptr_ifaddrs); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   wg_peer *peer; |  | ||||||
|   for ((peer) = (device)->first_peer; (peer); (peer) = (peer)->next_peer) { |  | ||||||
|     auto PeerConfig = Peer(); |  | ||||||
|     if (peer->flags & WGPEER_HAS_PRESHARED_KEY) PeerConfig.presharedKey = keyTo64(peer->preshared_key); |  | ||||||
|     if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL && peer->persistent_keepalive_interval > 0) PeerConfig.keepInterval = peer->persistent_keepalive_interval; |  | ||||||
|     if (peer->endpoint.addr.sa_family == AF_INET||peer->endpoint.addr.sa_family == AF_INET6) PeerConfig.endpoint = getHostAddress(true, &peer->endpoint.addr); |  | ||||||
|     if (peer->last_handshake_time.tv_sec > 0) PeerConfig.last_handshake = peer->last_handshake_time.tv_sec*1000; |  | ||||||
|     if (peer->rx_bytes > 0) PeerConfig.rxBytes = peer->rx_bytes; |  | ||||||
|     if (peer->tx_bytes > 0) PeerConfig.txBytes = peer->tx_bytes; |  | ||||||
|     if (peer->first_allowedip) { |  | ||||||
|       wg_allowedip *allowedip; |  | ||||||
|       for ((allowedip) = (peer)->first_allowedip; (allowedip); (allowedip) = (allowedip)->next_allowedip) { |  | ||||||
|         static char buf[INET6_ADDRSTRLEN + 1]; |  | ||||||
|         memset(buf, 0, INET6_ADDRSTRLEN + 1); |  | ||||||
|         if (allowedip->family == AF_INET) inet_ntop(AF_INET, &allowedip->ip4, buf, INET6_ADDRSTRLEN); |  | ||||||
|         else if (allowedip->family == AF_INET6) inet_ntop(AF_INET6, &allowedip->ip6, buf, INET6_ADDRSTRLEN); |  | ||||||
|         snprintf(buf + strlen(buf), INET6_ADDRSTRLEN - strlen(buf), "/%d", allowedip->cidr); |  | ||||||
|         PeerConfig.allowedIPs.push_back(buf); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     peersVector[keyTo64(peer->public_key)] = PeerConfig; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,363 +0,0 @@ | |||||||
| #include <napi.h> |  | ||||||
| #include <string> |  | ||||||
| #include <vector> |  | ||||||
| #include <map> |  | ||||||
| #include <iostream> |  | ||||||
| #include <wireguard-nt/include/wireguard.h> |  | ||||||
| #include <windows.h> |  | ||||||
| #include <tlhelp32.h> |  | ||||||
| #include <accctrl.h> |  | ||||||
| #include <aclapi.h> |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdbool.h> |  | ||||||
| #include <fcntl.h> |  | ||||||
| #include <winsock2.h> |  | ||||||
| #include <ws2ipdef.h> |  | ||||||
| #include <ws2tcpip.h> |  | ||||||
| #include <iphlpapi.h> |  | ||||||
| #include <bcrypt.h> |  | ||||||
| #include <wincrypt.h> |  | ||||||
| #include <sysinfoapi.h> |  | ||||||
| #include <winternl.h> |  | ||||||
| #include <cstdlib> |  | ||||||
| #include <setupapi.h> |  | ||||||
| #include <cfgmgr32.h> |  | ||||||
| #include <devguid.h> |  | ||||||
| #include "wginterface.hh" |  | ||||||
| #include "win/shared.cpp" |  | ||||||
| #include <wgkeys.hh> |  | ||||||
|  |  | ||||||
| const DEVPROPKEY devpkey_name = { { 0x65726957, 0x7547, 0x7261, { 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79 } }, DEVPROPID_FIRST_USABLE + 1 }; |  | ||||||
| #define IFNAMSIZ MAX_ADAPTER_NAME - 1 |  | ||||||
|  |  | ||||||
| static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter; |  | ||||||
| static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter; |  | ||||||
| static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter; |  | ||||||
| static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID; |  | ||||||
| static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC *WireGuardGetRunningDriverVersion; |  | ||||||
| static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver; |  | ||||||
| static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger; |  | ||||||
| static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging; |  | ||||||
| static WIREGUARD_GET_ADAPTER_STATE_FUNC *WireGuardGetAdapterState; |  | ||||||
| static WIREGUARD_SET_ADAPTER_STATE_FUNC *WireGuardSetAdapterState; |  | ||||||
| static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration; |  | ||||||
| static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration; |  | ||||||
|  |  | ||||||
| unsigned long maxName() { |  | ||||||
|   return IFNAMSIZ; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::string getErrorString(DWORD errorMessageID) { |  | ||||||
|   if (errorMessageID == 0 || errorMessageID < 0) std::string("Error code: ").append(std::to_string(errorMessageID)); |  | ||||||
|   LPSTR messageBuffer = nullptr; |  | ||||||
|   //Ask Win32 to give us the string version of that message ID. |  | ||||||
|   //The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be). |  | ||||||
|   size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); |  | ||||||
|   //Copy the error message into a std::string. |  | ||||||
|   std::string message(messageBuffer, size); |  | ||||||
|   //Free the Win32's string's buffer. |  | ||||||
|   LocalFree(messageBuffer); |  | ||||||
|   return std::string("Error code: ").append(std::to_string(errorMessageID)).append(", Message: ").append(message); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::string startAddon(const Napi::Env env, Napi::Object exports) { |  | ||||||
|   if (!IsRunAsAdmin()) return "Run nodejs with administrator privilegies"; |  | ||||||
|   auto DLLPATH = exports.Get("WIN32DLLPATH"); |  | ||||||
|   if (!(DLLPATH.IsString())) return "Require WIREGUARD_DLL_PATH in addon load!"; |  | ||||||
|   LPCWSTR dllPath = toLpcwstr(DLLPATH.ToString()); |  | ||||||
|  |  | ||||||
|   HMODULE WireGuardDll = LoadLibraryExW(dllPath, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); |  | ||||||
|   if (!WireGuardDll) return std::string("Failed to initialize WireGuardNT, ").append(getErrorString(GetLastError()));; |  | ||||||
|   #define X(Name) ((*(FARPROC *)&Name = GetProcAddress(WireGuardDll, #Name)) == NULL) |  | ||||||
|   if (X(WireGuardCreateAdapter) || X(WireGuardOpenAdapter) || X(WireGuardCloseAdapter) || X(WireGuardGetAdapterLUID) || X(WireGuardGetRunningDriverVersion) || X(WireGuardDeleteDriver) || X(WireGuardSetLogger) || X(WireGuardSetAdapterLogging) || X(WireGuardGetAdapterState) || X(WireGuardSetAdapterState) || X(WireGuardGetConfiguration) || X(WireGuardSetConfiguration)) |  | ||||||
|   #undef X |  | ||||||
|   { |  | ||||||
|     DWORD LastError = GetLastError(); |  | ||||||
|     FreeLibrary(WireGuardDll); |  | ||||||
|     SetLastError(LastError); |  | ||||||
|     return std::string("Failed to set Functions from WireGuardNT DLL, ").append(getErrorString(GetLastError()));; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return ""; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::string versionDrive() { |  | ||||||
|   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"getWgVersion", L"Wireguard-tools.js", NULL); |  | ||||||
|   DWORD Version = WireGuardGetRunningDriverVersion(); |  | ||||||
|   if (Version == 0) { |  | ||||||
|     auto statusErr = GetLastError(); |  | ||||||
|     WireGuardCloseAdapter(Adapter); |  | ||||||
|     if (statusErr == ERROR_FILE_NOT_FOUND) return "Driver not loaded"; |  | ||||||
|     return std::string("Cannot get version drive, ").append(getErrorString(GetLastError())); |  | ||||||
|   } |  | ||||||
|   WireGuardCloseAdapter(Adapter); |  | ||||||
|   return std::string("WireGuardNT v").append(std::to_string((Version >> 16) & 0xff)).append(".").append(std::to_string((Version >> 0) & 0xff)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void listDevices::Execute() { |  | ||||||
|   std::vector<std::string> arrayPrefix; |  | ||||||
|   arrayPrefix.push_back("ProtectedPrefix\\Administrators\\WireGuard\\"); |  | ||||||
|   arrayPrefix.push_back("WireGuard\\"); |  | ||||||
|  |  | ||||||
|   WIN32_FIND_DATA find_data; |  | ||||||
|   HANDLE find_handle; |  | ||||||
|   for (auto &preit : arrayPrefix) { |  | ||||||
|     int ret = 0; |  | ||||||
|     find_handle = FindFirstFile("\\\\.\\pipe\\*", &find_data); |  | ||||||
|     if (find_handle == INVALID_HANDLE_VALUE) continue; |  | ||||||
|  |  | ||||||
|     char *iface; |  | ||||||
|     do { |  | ||||||
|       if (strncmp(preit.c_str(), find_data.cFileName, strlen(preit.c_str()))) continue; |  | ||||||
|       iface = find_data.cFileName + strlen(preit.c_str()); |  | ||||||
|       listInfo setInfo; |  | ||||||
|       setInfo.tunType = "userspace"; |  | ||||||
|       setInfo.pathSock = std::string("\\\\.\\pipe\\").append(preit).append(iface); |  | ||||||
|       deviceNames[std::string(iface)] = setInfo; |  | ||||||
|     } while (FindNextFile(find_handle, &find_data)); |  | ||||||
|     FindClose(find_handle); |  | ||||||
|     if (ret < 0) return SetError(std::string("Erro code: ").append(std::to_string(ret))); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   HDEVINFO dev_info = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"SWD\\WireGuard", NULL, DIGCF_PRESENT, NULL, NULL, NULL); |  | ||||||
|   if (dev_info == INVALID_HANDLE_VALUE) return SetError("Cannot get devices"); |  | ||||||
|  |  | ||||||
|   for (DWORD i = 0;; ++i) { |  | ||||||
|     DWORD buf_len; |  | ||||||
|     WCHAR adapter_name[MAX_ADAPTER_NAME]; |  | ||||||
|     SP_DEVINFO_DATA dev_info_data; |  | ||||||
|     dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA); |  | ||||||
|     DEVPROPTYPE prop_type; |  | ||||||
|     ULONG status, problem_code; |  | ||||||
|     char *interface_name; |  | ||||||
|  |  | ||||||
|     if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) { |  | ||||||
|       if (GetLastError() == ERROR_NO_MORE_ITEMS) break; |  | ||||||
|       continue; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (!SetupDiGetDevicePropertyW(dev_info, &dev_info_data, &devpkey_name, &prop_type, (PBYTE)adapter_name, sizeof(adapter_name), NULL, 0) || prop_type != DEVPROP_TYPE_STRING) continue; |  | ||||||
|     adapter_name[_countof(adapter_name) - 1] = L'0'; |  | ||||||
|     if (!adapter_name[0]) continue; |  | ||||||
|     buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, NULL, 0, NULL, NULL); |  | ||||||
|     if (!buf_len) continue; |  | ||||||
|     interface_name = (char *)malloc(buf_len); |  | ||||||
|     if (!interface_name) continue; |  | ||||||
|     buf_len = WideCharToMultiByte(CP_UTF8, 0, adapter_name, -1, interface_name, buf_len, NULL, NULL); |  | ||||||
|     if (!buf_len) { |  | ||||||
|       free(interface_name); |  | ||||||
|       continue; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (CM_Get_DevNode_Status(&status, &problem_code, dev_info_data.DevInst, 0) == CR_SUCCESS && (status & (DN_DRIVER_LOADED | DN_STARTED)) == (DN_DRIVER_LOADED | DN_STARTED)) { |  | ||||||
|       listInfo setInfo; |  | ||||||
|       setInfo.tunType = "kernel"; |  | ||||||
|       deviceNames[std::string(interface_name)] = setInfo; |  | ||||||
|     } |  | ||||||
|     free(interface_name); |  | ||||||
|   } |  | ||||||
|   SetupDiDestroyDeviceInfoList(dev_info); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void deleteInterface::Execute() { |  | ||||||
|   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); |  | ||||||
|   if (!Adapter) return SetError("This interface not exists in Wireguard-Tools.js addon!"); |  | ||||||
|   if (!(WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_DOWN))) return SetError(std::string("Failed to set down interface, ").append(getErrorString(GetLastError()))); |  | ||||||
|   WireGuardCloseAdapter(Adapter); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Change point from calloc or malloc |  | ||||||
|  * |  | ||||||
|  * T: to |  | ||||||
|  * C: From |  | ||||||
|  */ |  | ||||||
| template <typename T, typename C> C* changePoint(T *x) { |  | ||||||
|   // reinterpret_cast<WIREGUARD_ALLOWED_IP*>(((char*)x) + sizeof(WIREGUARD_PEER)); |  | ||||||
|   // std::cout << "Sizeof: " << sizeof(C) << ", " << typeid(T).name() << " -> " << typeid(C).name() << std::endl; |  | ||||||
|   return reinterpret_cast<C*>(((char*)x) + sizeof(T)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void getConfig::Execute() { |  | ||||||
|   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); |  | ||||||
|   if (!Adapter) return SetError("This interface not exists in Wireguard-Tools.js addon!"); |  | ||||||
|   NET_LUID InterfaceLuid; |  | ||||||
|   WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); |  | ||||||
|   try { |  | ||||||
|     for (auto aip : getIpAddr(InterfaceLuid)) Address.push_back(aip); |  | ||||||
|   } catch (std::string err) { |  | ||||||
|     return SetError(err); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   DWORD buf_len = 0; |  | ||||||
|   WIREGUARD_INTERFACE *wg_iface = nullptr; |  | ||||||
|  |  | ||||||
|   while (!(WireGuardGetConfiguration(Adapter, wg_iface, &buf_len))) { |  | ||||||
|     free(wg_iface); |  | ||||||
|     if (GetLastError() != ERROR_MORE_DATA) return SetError((std::string("Failed get interface config, code: ")).append(std::to_string(GetLastError()))); |  | ||||||
|     wg_iface = (WIREGUARD_INTERFACE *)malloc(buf_len); |  | ||||||
|     if (!wg_iface) return SetError(std::string("Failed get interface config, ").append(std::to_string(-errno))); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY) privateKey = wgKeys::toString(wg_iface->PrivateKey); |  | ||||||
|   if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PUBLIC_KEY) publicKey = wgKeys::toString(wg_iface->PublicKey); |  | ||||||
|   portListen = 0; |  | ||||||
|   if (wg_iface->Flags & WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT) portListen = wg_iface->ListenPort; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface); |  | ||||||
|   for (DWORD i = 0; i < wg_iface->PeersCount; i++) { |  | ||||||
|     auto pubKey = wgKeys::toString(wg_peer->PublicKey); |  | ||||||
|     Peer peerConfig; |  | ||||||
|     peerConfig.last_handshake = 0; |  | ||||||
|     peerConfig.txBytes = wg_peer->TxBytes; |  | ||||||
|     peerConfig.rxBytes = wg_peer->RxBytes; |  | ||||||
|  |  | ||||||
|     if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY) peerConfig.presharedKey = wgKeys::toString(wg_peer->PresharedKey); |  | ||||||
|     if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT) peerConfig.endpoint = parseEndpoint(&wg_peer->Endpoint); |  | ||||||
|     if (wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE) peerConfig.keepInterval = wg_peer->PersistentKeepalive; |  | ||||||
|     if (wg_peer->LastHandshake > 0) peerConfig.last_handshake = (wg_peer->LastHandshake / 10000000 - 11644473600LL) * 1000; |  | ||||||
|  |  | ||||||
|     WIREGUARD_ALLOWED_IP* wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer); |  | ||||||
|     for (DWORD __aip = 0; __aip < wg_peer->AllowedIPsCount; __aip++) { |  | ||||||
| 			char saddr[INET6_ADDRSTRLEN]; |  | ||||||
|       if (wg_aip->AddressFamily == AF_INET) { |  | ||||||
|         inet_ntop(AF_INET, &wg_aip->Address.V6, saddr, INET_ADDRSTRLEN); |  | ||||||
|         peerConfig.allowedIPs.push_back(std::string(saddr).append("/").append(std::to_string(wg_aip->Cidr))); |  | ||||||
| 			} else if (wg_aip->AddressFamily == AF_INET6) { |  | ||||||
|         inet_ntop(AF_INET6, &wg_aip->Address.V6, saddr, INET6_ADDRSTRLEN); |  | ||||||
|         peerConfig.allowedIPs.push_back(std::string(saddr).append("/").append(std::to_string(wg_aip->Cidr))); |  | ||||||
| 			} |  | ||||||
|       ++wg_aip; |  | ||||||
|     } |  | ||||||
|     wg_peer = reinterpret_cast<WIREGUARD_PEER*>(wg_aip); |  | ||||||
|     peersVector[pubKey] = peerConfig; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   free(wg_iface); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void setConfig::Execute() { |  | ||||||
|   DWORD buf_len = sizeof(WIREGUARD_INTERFACE); |  | ||||||
|   for (auto peer : peersVector) { |  | ||||||
| 		if (DWORD_MAX - buf_len < sizeof(WIREGUARD_PEER)) return SetError("Buffer overflow"); |  | ||||||
| 		buf_len += sizeof(WIREGUARD_PEER); |  | ||||||
| 		for (auto aip : peer.second.allowedIPs) { |  | ||||||
| 			if (DWORD_MAX - buf_len < sizeof(WIREGUARD_ALLOWED_IP)) return SetError("Buffer overflow"); |  | ||||||
| 			buf_len += sizeof(WIREGUARD_ALLOWED_IP); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|   WIREGUARD_INTERFACE *wg_iface = reinterpret_cast<WIREGUARD_INTERFACE*>(calloc(1, buf_len)); |  | ||||||
|   if (!wg_iface) return SetError("Cannot alloc buff"); |  | ||||||
|   wg_iface->PeersCount = 0; |  | ||||||
|  |  | ||||||
|   wgKeys::stringToKey(wg_iface->PrivateKey, privateKey); |  | ||||||
|   wg_iface->Flags = WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_PRIVATE_KEY; |  | ||||||
|  |  | ||||||
|   wg_iface->ListenPort = portListen; |  | ||||||
|   if (portListen >= 0 && 65535 <= portListen) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_HAS_LISTEN_PORT); |  | ||||||
|  |  | ||||||
|   if (replacePeers) wg_iface->Flags = (WIREGUARD_INTERFACE_FLAG)(wg_iface->Flags|WIREGUARD_INTERFACE_FLAG::WIREGUARD_INTERFACE_REPLACE_PEERS); |  | ||||||
|  |  | ||||||
| 	WIREGUARD_ALLOWED_IP *wg_aip; |  | ||||||
| 	WIREGUARD_PEER *wg_peer = changePoint<WIREGUARD_INTERFACE, WIREGUARD_PEER>(wg_iface); |  | ||||||
|   for (auto __peer : peersVector) { |  | ||||||
|     auto peerPublicKey = __peer.first; auto peerConfig = __peer.second; |  | ||||||
|     try { |  | ||||||
|       wgKeys::stringToKey(wg_peer->PublicKey, peerPublicKey); |  | ||||||
|     } catch (std::string &err) { |  | ||||||
|       SetError(err); |  | ||||||
|       free(wg_iface); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     wg_peer->Flags = WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PUBLIC_KEY; |  | ||||||
|     wg_peer->AllowedIPsCount = 0; |  | ||||||
|     wg_iface->PeersCount++; |  | ||||||
|  |  | ||||||
|     if (peerConfig.removeMe) { |  | ||||||
|       wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REMOVE); |  | ||||||
|       wg_peer = changePoint<WIREGUARD_PEER, WIREGUARD_PEER>(wg_peer); |  | ||||||
|     } else { |  | ||||||
|       if (peerConfig.presharedKey.size() == B64_WG_KEY_LENGTH) { |  | ||||||
|         try { |  | ||||||
|           wgKeys::stringToKey(wg_peer->PresharedKey, peerConfig.presharedKey); |  | ||||||
|           wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PRESHARED_KEY); |  | ||||||
|         } catch (std::string &err) { |  | ||||||
|           SetError(err); |  | ||||||
|           free(wg_iface); |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       wg_peer->PersistentKeepalive = peerConfig.keepInterval; |  | ||||||
|       if (peerConfig.keepInterval >= 0) wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE); |  | ||||||
|  |  | ||||||
|       if (peerConfig.endpoint.size() > 0) { |  | ||||||
|         try { |  | ||||||
|           insertEndpoint(&wg_peer->Endpoint, peerConfig.endpoint.c_str()); |  | ||||||
|           wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_HAS_ENDPOINT); |  | ||||||
|         } catch (std::string &err) { |  | ||||||
|           SetError(std::string("Cannot parse endpoint, ").append(err)); |  | ||||||
|           free(wg_iface); |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
| 	    wg_aip = changePoint<WIREGUARD_PEER, WIREGUARD_ALLOWED_IP>(wg_peer); |  | ||||||
|       for (auto aip : peerConfig.allowedIPs) { |  | ||||||
|         unsigned long cidr = 0; |  | ||||||
|         if (aip.find("/") != std::string::npos) { |  | ||||||
|           cidr = std::stoi(aip.substr(aip.find("/")+1)); |  | ||||||
|           aip = aip.substr(0, aip.find("/")); |  | ||||||
|         } |  | ||||||
|         aip = aip.substr(0, aip.find("/")); |  | ||||||
|         wg_aip->AddressFamily = strchr(aip.c_str(), ':') ? AF_INET6 : AF_INET; |  | ||||||
|         auto status = wg_aip->AddressFamily == AF_INET6 ? inet_pton(wg_aip->AddressFamily, aip.c_str(), &wg_aip->Address.V6) : inet_pton(wg_aip->AddressFamily, aip.c_str(), &wg_aip->Address.V4); |  | ||||||
|         if (status == 1) { |  | ||||||
|           if (cidr == 0) cidr = wg_aip->AddressFamily == AF_INET6 ? 128 : 32; |  | ||||||
|         } else continue; |  | ||||||
|         wg_aip->Cidr = cidr; |  | ||||||
|         wg_peer->AllowedIPsCount++; |  | ||||||
| 	      wg_aip = changePoint<WIREGUARD_ALLOWED_IP, WIREGUARD_ALLOWED_IP>(wg_aip); |  | ||||||
|         if (!(wg_peer->Flags & WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REPLACE_ALLOWED_IPS)) wg_peer->Flags = (WIREGUARD_PEER_FLAG)(wg_peer->Flags|WIREGUARD_PEER_FLAG::WIREGUARD_PEER_REPLACE_ALLOWED_IPS); |  | ||||||
|       } |  | ||||||
| 	    wg_peer = reinterpret_cast<WIREGUARD_PEER*>(((char*)wg_aip)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(toLpcwstr(wgName)); |  | ||||||
|   if (!Adapter) Adapter = WireGuardCreateAdapter(toLpcwstr(wgName), L"Wireguard-tools.js", NULL); |  | ||||||
|   if (!Adapter) SetError(std::string("Failed to create adapter, ").append(getErrorString(GetLastError()))); |  | ||||||
|   else if (!WireGuardSetConfiguration(Adapter, reinterpret_cast<WIREGUARD_INTERFACE*>(wg_iface), buf_len)) { |  | ||||||
|     auto status = GetLastError(); |  | ||||||
|     SetError(std::string("Failed to set interface config, ").append(getErrorString(status))); |  | ||||||
|     WireGuardCloseAdapter(Adapter); |  | ||||||
|   } else if (!WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE::WIREGUARD_ADAPTER_STATE_UP)) { |  | ||||||
|     auto status = GetLastError(); |  | ||||||
|     SetError(std::string("Failed to set interface up, ").append(getErrorString(status))); |  | ||||||
|     WireGuardCloseAdapter(Adapter); |  | ||||||
|   } else { |  | ||||||
|     if (Address.size() > 0) { |  | ||||||
|       std::string IPv4, IPv6; |  | ||||||
|       for (auto aip : Address) { |  | ||||||
|         aip = aip.substr(0, aip.find("/")); |  | ||||||
|         auto family = strchr(aip.c_str(), ':') ? AF_INET6 : AF_INET; |  | ||||||
|         SOCKADDR_INET address; |  | ||||||
|         int status = family == AF_INET ? inet_pton(family, aip.c_str(), &address.Ipv4.sin_addr) : inet_pton(family, aip.c_str(), &address.Ipv6.sin6_addr); |  | ||||||
|         if (status != 1) continue; |  | ||||||
|         char saddr[INET6_ADDRSTRLEN]; |  | ||||||
|         family == AF_INET ? inet_ntop(AF_INET, &address.Ipv4.sin_addr, saddr, INET_ADDRSTRLEN) : inet_ntop(AF_INET6, &address.Ipv6.sin6_addr, saddr, INET6_ADDRSTRLEN); |  | ||||||
|         if (family == AF_INET) IPv4 = std::string(saddr); |  | ||||||
|         // else IPv6 = std::string(saddr); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if (IPv4.size() > 0 || IPv6.size() > 0) { |  | ||||||
|         NET_LUID InterfaceLuid; |  | ||||||
|         WireGuardGetAdapterLUID(Adapter, &InterfaceLuid); |  | ||||||
|         auto setStatus = insertIpAddr(InterfaceLuid, IPv4, IPv6); |  | ||||||
|         if (setStatus.size() > 0) SetError(setStatus); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   free(wg_iface); |  | ||||||
| } |  | ||||||
| @@ -1,116 +0,0 @@ | |||||||
| #include <napi.h> |  | ||||||
| #include <iostream> |  | ||||||
| #include "wginterface.hh" |  | ||||||
|  |  | ||||||
| Napi::Object Init(Napi::Env initEnv, Napi::Object exports) { |  | ||||||
|   /// Call Addon |  | ||||||
|   #ifdef ONSTARTADDON |  | ||||||
|   auto status = startAddon(initEnv, exports); |  | ||||||
|   if (status.length() >= 1) { |  | ||||||
|     Napi::Error::New(initEnv, status).ThrowAsJavaScriptException(); |  | ||||||
|     return exports; |  | ||||||
|   } |  | ||||||
|   #endif |  | ||||||
|  |  | ||||||
|   // Wireguard constants set |  | ||||||
|   const Napi::Object constants = Napi::Object::New(initEnv); |  | ||||||
|   // Set wireguard version if present |  | ||||||
|   constants.Set("driveVersion", versionDrive()); |  | ||||||
|  |  | ||||||
|   // Wireguard max name length |  | ||||||
|   constants.Set("nameLength", maxName()); |  | ||||||
|  |  | ||||||
|   constants.Set("base64Length", B64_WG_KEY_LENGTH); |  | ||||||
|   constants.Set("keyLength", WG_KEY_LENGTH); |  | ||||||
|  |  | ||||||
|   // Set addon constants |  | ||||||
|   exports.Set("constants", constants); |  | ||||||
|  |  | ||||||
|   // Function's |  | ||||||
|   #ifdef USERSPACE_GO |  | ||||||
|   exports.Set("createTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); })); |  | ||||||
|   exports.Set("deleteTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); })); |  | ||||||
|   exports.Set("checkTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); })); |  | ||||||
|   exports.Set("getTun", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { return info.Env().Undefined(); })); |  | ||||||
|   #endif |  | ||||||
|  |  | ||||||
|   #ifdef SETCONFIG |  | ||||||
|   exports.Set("setConfig", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { |  | ||||||
|     const Napi::Env env = info.Env(); |  | ||||||
|     const auto wgName = info[0]; |  | ||||||
|     const auto wgConfig = info[1]; |  | ||||||
|     Napi::Value ret = env.Undefined(); |  | ||||||
|     if (!(wgName.IsString())) { |  | ||||||
|       Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException(); |  | ||||||
|       return env.Undefined(); |  | ||||||
|     } else if (wgName.ToString().Utf8Value().length() >= maxName()) { |  | ||||||
|       Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException(); |  | ||||||
|       return env.Undefined(); |  | ||||||
|     } else if (!(wgConfig.IsObject())) { |  | ||||||
|       Napi::Error::New(env, "Require wireguard config object").ThrowAsJavaScriptException(); |  | ||||||
|       return env.Undefined(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     try { |  | ||||||
|       auto worker = new setConfig(env, wgName.ToString().Utf8Value(), wgConfig.ToObject()); |  | ||||||
|       worker->Queue(); |  | ||||||
|       return worker->setPromise.Promise(); |  | ||||||
|     } catch (const Napi::Error &err) { |  | ||||||
|       err.ThrowAsJavaScriptException(); |  | ||||||
|     } |  | ||||||
|     return ret; |  | ||||||
|   })); |  | ||||||
|   #endif |  | ||||||
|  |  | ||||||
|   #ifdef DELIFACE |  | ||||||
|   exports.Set("deleteInterface", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { |  | ||||||
|     const Napi::Env env = info.Env(); |  | ||||||
|     const auto wgName = info[0]; |  | ||||||
|     if (!(wgName.IsString())) { |  | ||||||
|       Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException(); |  | ||||||
|       return env.Undefined(); |  | ||||||
|     } else if (wgName.ToString().Utf8Value().length() >= maxName()) { |  | ||||||
|       Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException(); |  | ||||||
|       return env.Undefined(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     auto worker = new deleteInterface(env, wgName.ToString().Utf8Value()); |  | ||||||
|     worker->Queue(); |  | ||||||
|     return worker->deletePromise.Promise(); |  | ||||||
|   })); |  | ||||||
|   #endif |  | ||||||
|  |  | ||||||
|   #ifdef GETCONFIG |  | ||||||
|   exports.Set("getConfig", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { |  | ||||||
|     const Napi::Env env = info.Env(); |  | ||||||
|     const auto wgName = info[0]; |  | ||||||
|     if (!(wgName.IsString())) { |  | ||||||
|       Napi::Error::New(env, "Require wireguard interface name").ThrowAsJavaScriptException(); |  | ||||||
|       return env.Undefined(); |  | ||||||
|     } else if (wgName.ToString().Utf8Value().length() >= maxName()) { |  | ||||||
|       Napi::Error::New(env, "interface name is so long").ThrowAsJavaScriptException(); |  | ||||||
|       return env.Undefined(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     try { |  | ||||||
|       auto worker = new getConfig(env, wgName.ToString().Utf8Value()); |  | ||||||
|       worker->Queue(); |  | ||||||
|       return worker->getPromise.Promise(); |  | ||||||
|     } catch (const Napi::Error &err) { |  | ||||||
|       err.ThrowAsJavaScriptException(); |  | ||||||
|     } |  | ||||||
|     return env.Undefined(); |  | ||||||
|   })); |  | ||||||
|   #endif |  | ||||||
|  |  | ||||||
|   #ifdef LISTDEV |  | ||||||
|   exports.Set("listDevices", Napi::Function::New(initEnv, [&](const Napi::CallbackInfo &info) -> Napi::Value { |  | ||||||
|     const Napi::Env env = info.Env(); |  | ||||||
|     auto worker = new listDevices(env); |  | ||||||
|     worker->Queue(); |  | ||||||
|     return worker->listDevicesPromise.Promise(); |  | ||||||
|   })); |  | ||||||
|   #endif |  | ||||||
|   return exports; |  | ||||||
| } |  | ||||||
| NODE_API_MODULE(addon, Init); |  | ||||||
| @@ -1,338 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| #include <napi.h> |  | ||||||
| #include <string> |  | ||||||
| #include <vector> |  | ||||||
| #include <map> |  | ||||||
| #include <wgkeys.hh> |  | ||||||
|  |  | ||||||
| // Get wireguard max name length |  | ||||||
| unsigned long maxName(); |  | ||||||
|  |  | ||||||
| // Get wireguard version |  | ||||||
| std::string versionDrive(); |  | ||||||
|  |  | ||||||
| // On start module call this function |  | ||||||
| std::string startAddon(const Napi::Env env, Napi::Object exports); |  | ||||||
|  |  | ||||||
| class deleteInterface : public Napi::AsyncWorker { |  | ||||||
|   private: |  | ||||||
|     std::string wgName; |  | ||||||
|   public: |  | ||||||
|   deleteInterface(const Napi::Env env, std::string name): AsyncWorker(env), wgName{name}, deletePromise{env} {} |  | ||||||
|   ~deleteInterface() {} |  | ||||||
|   const Napi::Promise::Deferred deletePromise; |  | ||||||
|  |  | ||||||
|   void OnError(const Napi::Error &e) override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     deletePromise.Reject(e.Value()); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void OnOK() override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     deletePromise.Resolve(Env().Undefined()); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   // Set platform Execute script |  | ||||||
|   void Execute() override; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class listInfo { |  | ||||||
|   public: |  | ||||||
|   std::string tunType, pathSock; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class listDevices : public Napi::AsyncWorker { |  | ||||||
|   private: |  | ||||||
|     std::map<std::string, listInfo> deviceNames; |  | ||||||
|   public: |  | ||||||
|   ~listDevices() {} |  | ||||||
|   listDevices(const Napi::Env env) : AsyncWorker(env), listDevicesPromise{env} {} |  | ||||||
|   const Napi::Promise::Deferred listDevicesPromise; |  | ||||||
|  |  | ||||||
|   void OnError(const Napi::Error& e) override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     listDevicesPromise.Reject(e.Value()); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void OnOK() override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     const Napi::Env env = Env(); |  | ||||||
|     const auto deviceArray = Napi::Array::New(env); |  | ||||||
|     for (auto it : deviceNames) { |  | ||||||
|       auto name = it.first; auto infoSrc = it.second; |  | ||||||
|       auto info = Napi::Object::New(env); |  | ||||||
|       info.Set("name", name); |  | ||||||
|       info.Set("from", infoSrc.tunType); |  | ||||||
|       if (infoSrc.pathSock.size() > 0) info.Set("path", infoSrc.pathSock); |  | ||||||
|       deviceArray.Set(deviceArray.Length(), info); |  | ||||||
|     } |  | ||||||
|     listDevicesPromise.Resolve(deviceArray); |  | ||||||
|   }; |  | ||||||
|   void Execute() override; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class Peer { |  | ||||||
|   public: |  | ||||||
|   // Remove specifies if the peer with this public key should be removed |  | ||||||
| 	// from a device's peer list. |  | ||||||
|   bool removeMe; |  | ||||||
|  |  | ||||||
|   // PresharedKey is an optional preshared key which may be used as an |  | ||||||
| 	// additional layer of security for peer communications. |  | ||||||
|   std::string presharedKey; |  | ||||||
|  |  | ||||||
|   // Endpoint is the most recent source address used for communication by |  | ||||||
| 	// this Peer. |  | ||||||
|   std::string endpoint; |  | ||||||
|  |  | ||||||
|   // AllowedIPs specifies which IPv4 and IPv6 addresses this peer is allowed |  | ||||||
| 	// to communicate on. |  | ||||||
| 	// |  | ||||||
| 	// 0.0.0.0/0 indicates that all IPv4 addresses are allowed, and ::/0 |  | ||||||
| 	// indicates that all IPv6 addresses are allowed. |  | ||||||
|   std::vector<std::string> allowedIPs; |  | ||||||
|  |  | ||||||
|   // PersistentKeepaliveInterval specifies how often an "empty" packet is sent |  | ||||||
| 	// to a peer to keep a connection alive. |  | ||||||
| 	// |  | ||||||
| 	// A value of 0 indicates that persistent keepalives are disabled. |  | ||||||
|   unsigned int keepInterval = 0; |  | ||||||
|  |  | ||||||
|   // LastHandshakeTime indicates the most recent time a handshake was performed |  | ||||||
| 	// with this peer. |  | ||||||
| 	// |  | ||||||
| 	// A zero-value time.Time indicates that no handshake has taken place with |  | ||||||
| 	// this peer. |  | ||||||
|   long long last_handshake = 0; |  | ||||||
|  |  | ||||||
|   // rxBytes indicates the number of bytes received from this peer. |  | ||||||
|   unsigned long long rxBytes = 0; |  | ||||||
|  |  | ||||||
|   // txBytes indicates the number of bytes transmitted to this peer. |  | ||||||
|   unsigned long long txBytes = 0; |  | ||||||
|  |  | ||||||
|   // ProtocolVersion specifies which version of the WireGuard protocol is used |  | ||||||
| 	// for this Peer. |  | ||||||
| 	// |  | ||||||
| 	// A value of 0 indicates that the most recent protocol version will be used. |  | ||||||
| 	int ProtocolVersion = 0; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| Configure uma interface do Wireguard. |  | ||||||
| */ |  | ||||||
| class setConfig : public Napi::AsyncWorker { |  | ||||||
|   private: |  | ||||||
|     // Wireguard interface name (required) |  | ||||||
|     std::string wgName; |  | ||||||
|  |  | ||||||
|     // Wireguard private key (required) |  | ||||||
|     std::string privateKey; |  | ||||||
|  |  | ||||||
|     // Wireguard interface publicKey <optional> |  | ||||||
|     std::string publicKey; |  | ||||||
|  |  | ||||||
|     // Wireguard port listen |  | ||||||
|     unsigned short portListen = 0; |  | ||||||
|  |  | ||||||
|     // FirewallMark specifies a device's firewall mark |  | ||||||
|     // else set to 0, the firewall mark will be cleared. |  | ||||||
|     int fwmark = -1; |  | ||||||
|  |  | ||||||
|     // Interface address'es |  | ||||||
|     std::vector<std::string> Address; |  | ||||||
|  |  | ||||||
|     // Replace peers |  | ||||||
|     bool replacePeers = false; |  | ||||||
|  |  | ||||||
|     // Wireguard peers, Map: <publicKey(std::string), Peer> |  | ||||||
|     std::map<std::string, Peer> peersVector; |  | ||||||
|   public: |  | ||||||
|   const Napi::Promise::Deferred setPromise; |  | ||||||
|  |  | ||||||
|   void OnOK() override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     // Callback().Call({ Env().Undefined() }); |  | ||||||
|     setPromise.Resolve(Env().Undefined()); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   void OnError(const Napi::Error& e) override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     // Callback().Call({ e.Value() }); |  | ||||||
|     setPromise.Reject(e.Value()); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   ~setConfig() {} |  | ||||||
|   setConfig(const Napi::Env env, std::string name, const Napi::Object &config) : AsyncWorker(env), wgName{name}, setPromise{env} { |  | ||||||
|     // Wireguard public key |  | ||||||
|     const auto sppk = config.Get("publicKey"); |  | ||||||
|     if (sppk.IsString()) { |  | ||||||
|       publicKey = sppk.ToString().Utf8Value(); |  | ||||||
|       if (publicKey.length() != B64_WG_KEY_LENGTH) throw Napi::Error::New(env, "Set valid publicKey"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Private key |  | ||||||
|     const auto sprk = config.Get("privateKey"); |  | ||||||
|     if (!(sprk.IsString())) throw Napi::Error::New(env, "privateKey is empty"); |  | ||||||
|     privateKey = sprk.ToString().Utf8Value(); |  | ||||||
|     if (privateKey.length() != B64_WG_KEY_LENGTH) throw Napi::Error::New(env, (std::string("Set valid privateKey ")).append(std::to_string(privateKey.length()))); |  | ||||||
|  |  | ||||||
|     // Port to listen Wireguard interface |  | ||||||
|     const auto spor = config.Get("portListen"); |  | ||||||
|     if (spor.IsNumber() && (spor.ToNumber().Int32Value() >= 0 && spor.ToNumber().Int32Value() <= 65535)) portListen = spor.ToNumber().Int32Value(); |  | ||||||
|  |  | ||||||
|     // Firewall mark |  | ||||||
|     const auto sfw = config.Get("fwmark"); |  | ||||||
|     if (sfw.IsNumber() && (sfw.ToNumber().Uint32Value() >= 0)) fwmark = sfw.ToNumber().Uint32Value(); |  | ||||||
|     else fwmark = -1; |  | ||||||
|  |  | ||||||
|     const auto setAddress = config.Get("address"); |  | ||||||
|     if (setAddress.IsArray()) { |  | ||||||
|       const Napi::Array addrs = setAddress.As<Napi::Array>(); |  | ||||||
|       for (unsigned int i = 0; i < addrs.Length(); i++) { |  | ||||||
|         if (addrs.Get(i).IsString()) Address.push_back(addrs.Get(i).ToString().Utf8Value()); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Replace peers |  | ||||||
|     const auto setReplace = config.Get("replacePeers"); |  | ||||||
|     if (setReplace.IsBoolean()) replacePeers = setReplace.ToBoolean().Value(); |  | ||||||
|  |  | ||||||
|     // Peers |  | ||||||
|     const auto speers = config.Get("peers"); |  | ||||||
|     if (speers.IsObject()) { |  | ||||||
|       const Napi::Object Peers = speers.ToObject(); |  | ||||||
|       const Napi::Array Keys = Peers.GetPropertyNames(); |  | ||||||
|       for (unsigned int peerIndex = 0; peerIndex < Keys.Length(); peerIndex++) { |  | ||||||
|         const auto peerPubKey = Keys[peerIndex]; |  | ||||||
|         if (peerPubKey.IsString() && Peers.Get(Keys[peerIndex]).IsObject()) { |  | ||||||
|           std::string ppkey = peerPubKey.ToString().Utf8Value(); |  | ||||||
|           if (ppkey.length() != B64_WG_KEY_LENGTH) throw Napi::Error::New(env, std::string("Set valid peer publicKey, value: ").append(ppkey)); |  | ||||||
|           const Napi::Object peerConfigObject = Peers.Get(Keys[peerIndex]).ToObject(); |  | ||||||
|  |  | ||||||
|           Peer peerConfig = Peer(); |  | ||||||
|           const auto removeMe = peerConfigObject.Get("removeMe"); |  | ||||||
|           if (removeMe.IsBoolean() && removeMe.ToBoolean().Value()) peerConfig.removeMe = true; |  | ||||||
|           else { |  | ||||||
|             // Preshared key |  | ||||||
|             const auto pprekey = peerConfigObject.Get("presharedKey"); |  | ||||||
|             if (pprekey.IsString()) { |  | ||||||
|               peerConfig.presharedKey = pprekey.ToString().Utf8Value(); |  | ||||||
|               if (peerConfig.presharedKey.length() != B64_WG_KEY_LENGTH) throw Napi::Error::New(env, "Set valid peer presharedKey"); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // Keep interval |  | ||||||
|             const auto pKeepInterval = peerConfigObject.Get("keepInterval"); |  | ||||||
|             if (pKeepInterval.IsNumber() && (pKeepInterval.ToNumber().Int32Value() > 0 && pKeepInterval.ToNumber().Int32Value() <= 65535)) peerConfig.keepInterval = pKeepInterval.ToNumber().Int32Value(); |  | ||||||
|  |  | ||||||
|             // Peer endpoint |  | ||||||
|             const auto pEndpoint = peerConfigObject.Get("endpoint"); |  | ||||||
|             if (pEndpoint.IsString()) peerConfig.endpoint = pEndpoint.ToString().Utf8Value(); |  | ||||||
|  |  | ||||||
|             // Allowed ip's array |  | ||||||
|             const auto pAllowedIPs = peerConfigObject.Get("allowedIPs"); |  | ||||||
|             if (pAllowedIPs.IsArray()) { |  | ||||||
|               const auto AllowedIps = pAllowedIPs.As<Napi::Array>(); |  | ||||||
|               for (uint32_t allIndex = 0; allIndex < AllowedIps.Length(); allIndex++) { |  | ||||||
|                 if (AllowedIps.Get(allIndex).IsString()) peerConfig.allowedIPs.push_back(AllowedIps.Get(allIndex).ToString().Utf8Value()); |  | ||||||
|               } |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|           // Insert peer |  | ||||||
|           peersVector[ppkey] = peerConfig; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Set platform Execute script |  | ||||||
|   void Execute() override; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| class getConfig : public Napi::AsyncWorker { |  | ||||||
|   private: |  | ||||||
|     // Wireguard interface name (required) |  | ||||||
|     std::string wgName; |  | ||||||
|  |  | ||||||
|     // Wireguard private key (required) |  | ||||||
|     std::string privateKey; |  | ||||||
|  |  | ||||||
|     // Wireguard interface publicKey <optional> |  | ||||||
|     std::string publicKey; |  | ||||||
|  |  | ||||||
|     // Wireguard port listen |  | ||||||
|     unsigned int portListen; |  | ||||||
|  |  | ||||||
|     // FirewallMark specifies a device's firewall mark |  | ||||||
|     // else set to 0, the firewall mark will be cleared. |  | ||||||
|     int fwmark = -1; |  | ||||||
|  |  | ||||||
|     // Interface address'es |  | ||||||
|     std::vector<std::string> Address; |  | ||||||
|  |  | ||||||
|     /* |  | ||||||
|     Wireguard peers |  | ||||||
|     Map: <publicKey, Peer> |  | ||||||
|     */ |  | ||||||
|     std::map<std::string, Peer> peersVector; |  | ||||||
|   public: |  | ||||||
|   ~getConfig() {} |  | ||||||
|   getConfig(const Napi::Env env, std::string name): AsyncWorker(env), wgName{name}, getPromise{env} {} |  | ||||||
|   const Napi::Promise::Deferred getPromise; |  | ||||||
|  |  | ||||||
|   void OnError(const Napi::Error& e) override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     getPromise.Reject(e.Value()); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void OnOK() override { |  | ||||||
|     Napi::HandleScope scope(Env()); |  | ||||||
|     const Napi::Env env = Env(); |  | ||||||
|     const auto config = Napi::Object::New(env); |  | ||||||
|  |  | ||||||
|     if (privateKey.length() == B64_WG_KEY_LENGTH) config.Set("privateKey", privateKey); |  | ||||||
|     if (publicKey.length() == B64_WG_KEY_LENGTH) config.Set("publicKey", publicKey); |  | ||||||
|     if (portListen >= 0 && portListen <= 65535) config.Set("portListen", portListen); |  | ||||||
|     if (fwmark >= 0) config.Set("fwmark", fwmark); |  | ||||||
|     if (Address.size() > 0) { |  | ||||||
|       const auto Addrs = Napi::Array::New(env); |  | ||||||
|       for (auto &addr : Address) Addrs.Set(Addrs.Length(), addr); |  | ||||||
|       config.Set("address", Addrs); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Peer object |  | ||||||
|     const auto PeersObject = Napi::Object::New(env); |  | ||||||
|     for (auto &peer : peersVector) { |  | ||||||
|       const auto PeerObject = Napi::Object::New(env); |  | ||||||
|       auto peerConfig = peer.second; |  | ||||||
|  |  | ||||||
|       if (peerConfig.presharedKey.length() == B64_WG_KEY_LENGTH) PeerObject.Set("presharedKey", peerConfig.presharedKey); |  | ||||||
|       if (peerConfig.keepInterval > 0 && peerConfig.keepInterval <= 65535) PeerObject.Set("keepInterval", peerConfig.keepInterval); |  | ||||||
|       if (peerConfig.endpoint.length() > 0) PeerObject.Set("endpoint", peerConfig.endpoint); |  | ||||||
|       if (peerConfig.rxBytes >= 0) PeerObject.Set("rxBytes", Napi::BigInt::New(env, (uint64_t)peerConfig.rxBytes)); |  | ||||||
|       if (peerConfig.txBytes >= 0) PeerObject.Set("txBytes", Napi::BigInt::New(env, (uint64_t)peerConfig.txBytes)); |  | ||||||
|       if (peerConfig.last_handshake >= 0) { |  | ||||||
|         PeerObject.Set("lastHandshake", Napi::Date::New(env, peerConfig.last_handshake)); |  | ||||||
|         PeerObject.Set("lastHandshakeBigint", peerConfig.last_handshake); // Debug to windows |  | ||||||
|       } |  | ||||||
|       if (peerConfig.allowedIPs.size() > 0) { |  | ||||||
|         const auto allowedIPs = Napi::Array::New(env); |  | ||||||
|         for (auto &ip : peerConfig.allowedIPs) allowedIPs.Set(allowedIPs.Length(), ip); |  | ||||||
|         PeerObject.Set("allowedIPs", allowedIPs); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       // const std::string peerPubKey = peer.first; |  | ||||||
|       PeersObject.Set(peer.first, PeerObject); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Set peers to object |  | ||||||
|     config.Set("peers", PeersObject); |  | ||||||
|  |  | ||||||
|     // Resolve config json |  | ||||||
|     getPromise.Resolve(config); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   // Set platform Execute script |  | ||||||
|   void Execute() override; |  | ||||||
| }; |  | ||||||
| @@ -1,179 +0,0 @@ | |||||||
| #include <string> |  | ||||||
| #include <vector> |  | ||||||
| #include <wireguard-nt/include/wireguard.h> |  | ||||||
| #include <windows.h> |  | ||||||
| #include <ws2ipdef.h> |  | ||||||
| #include <ws2def.h> |  | ||||||
| #include <winsock2.h> |  | ||||||
| #include <ws2tcpip.h> |  | ||||||
| #include <netioapi.h> |  | ||||||
| #include <iphlpapi.h> |  | ||||||
| #include <chrono> |  | ||||||
| #include <thread> |  | ||||||
| #include <iostream> |  | ||||||
|  |  | ||||||
| // Function to check if the current user has administrator privileges |  | ||||||
| bool IsRunAsAdmin() |  | ||||||
| { |  | ||||||
|   BOOL fRet = FALSE; |  | ||||||
|   HANDLE hToken = NULL; |  | ||||||
|   if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { |  | ||||||
|     TOKEN_ELEVATION Elevation; |  | ||||||
|     DWORD cbSize = sizeof(TOKEN_ELEVATION); |  | ||||||
|     if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize)) { |  | ||||||
|       fRet = Elevation.TokenIsElevated; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   if (hToken) CloseHandle(hToken); |  | ||||||
|   return !!fRet; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| LPCWSTR toLpcwstr(std::string s) { |  | ||||||
|   wchar_t* wString = new wchar_t[s.length()+1]; |  | ||||||
|   MultiByteToWideChar(CP_ACP, 0, s.c_str(), -1, wString, s.length()+1); |  | ||||||
|   return wString; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int parse_dns_retries() { |  | ||||||
|   unsigned long ret; |  | ||||||
|   char *retries = getenv("WG_ENDPOINT_RESOLUTION_RETRIES"), *end; |  | ||||||
|  |  | ||||||
|   if (!retries) return 15; |  | ||||||
|   if (!strcmp(retries, "infinity")) return -1; |  | ||||||
|  |  | ||||||
|   ret = strtoul(retries, &end, 10); |  | ||||||
|   if (*end || ret > INT_MAX) { |  | ||||||
|     fprintf(stderr, "Unable to parse WG_ENDPOINT_RESOLUTION_RETRIES: `%s'\n", retries); |  | ||||||
|     exit(1); |  | ||||||
|   } |  | ||||||
|   return (int)ret; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void insertEndpoint(SOCKADDR_INET *endpoint, std::string value) { |  | ||||||
| 	int ret, retries = parse_dns_retries(); |  | ||||||
| 	char *begin, *end; |  | ||||||
|   auto mmutable = strdup(value.c_str()); |  | ||||||
| 	if (!mmutable) throw std::string("strdup"); |  | ||||||
| 	if (!value.size()) { |  | ||||||
|     free(mmutable); |  | ||||||
|     throw std::string("Unable to parse empty endpoint"); |  | ||||||
|   } |  | ||||||
| 	if (mmutable[0] == '[') { |  | ||||||
| 		begin = &mmutable[1]; |  | ||||||
| 		end = strchr(mmutable, ']'); |  | ||||||
| 		if (!end) { |  | ||||||
|       free(mmutable); |  | ||||||
|       throw std::string("Unable to find matching brace of endpoint: ").append(value); |  | ||||||
|     } |  | ||||||
| 		*end++ = '\0'; |  | ||||||
| 		if (*end++ != ':' || !*end) { |  | ||||||
|       free(mmutable); |  | ||||||
|       throw std::string("Unable to find port of endpoint: ").append(value); |  | ||||||
|     } |  | ||||||
| 	} else { |  | ||||||
| 		begin = mmutable; |  | ||||||
| 		end = strrchr(mmutable, ':'); |  | ||||||
| 		if (!end || !*(end + 1)) { |  | ||||||
|       free(mmutable); |  | ||||||
|       throw std::string("Unable to find port of endpoint: ").append(value); |  | ||||||
|     } |  | ||||||
| 		*end++ = '\0'; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	ADDRINFOA *resolved; |  | ||||||
| 	// #define min(a, b) ((a) < (b) ? (a) : (b)) |  | ||||||
| 	for (unsigned int timeout = 1000000;; timeout = ((20000000) < (timeout * 6 / 5) ? (20000000) : (timeout * 6 / 5))) { |  | ||||||
| 		// ret = getaddrinfo(begin, end, &hints, &resolved); |  | ||||||
| 		ret = getaddrinfo(begin, end, NULL, &resolved); |  | ||||||
| 		if (!ret) break; |  | ||||||
| 		/* The set of return codes that are "permanent failures". All other possibilities are potentially transient. |  | ||||||
| 		 * |  | ||||||
| 		 * This is according to https://sourceware.org/glibc/wiki/NameResolver which states: |  | ||||||
| 		 *	"From the perspective of the application that calls getaddrinfo() it perhaps |  | ||||||
| 		 *	 doesn't matter that much since EAI_FAIL, EAI_NONAME and EAI_NODATA are all |  | ||||||
| 		 *	 permanent failure codes and the causes are all permanent failures in the |  | ||||||
| 		 *	 sense that there is no point in retrying later." |  | ||||||
| 		 * |  | ||||||
| 		 * So this is what we do, except FreeBSD removed EAI_NODATA some time ago, so that's conditional. |  | ||||||
| 		 */ |  | ||||||
| 		if (ret == EAI_NONAME || ret == EAI_FAIL || |  | ||||||
| 			#ifdef EAI_NODATA |  | ||||||
| 				ret == EAI_NODATA || |  | ||||||
| 			#endif |  | ||||||
| 				(retries >= 0 && !retries--)) { |  | ||||||
| 			free(mmutable); |  | ||||||
| 			throw std::string("Error code: ").append(std::to_string(ret)); |  | ||||||
| 		} |  | ||||||
|     std::this_thread::sleep_for(std::chrono::microseconds(timeout)); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(SOCKADDR_IN))) memcpy(&endpoint->Ipv4, resolved->ai_addr, resolved->ai_addrlen); |  | ||||||
|   else if (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(SOCKADDR_IN6)) memcpy(&endpoint->Ipv6, resolved->ai_addr, resolved->ai_addrlen); |  | ||||||
| 	else { |  | ||||||
| 		freeaddrinfo(resolved); |  | ||||||
| 		throw std::string("Neither IPv4 nor IPv6 address found: ").append(value); |  | ||||||
| 	} |  | ||||||
| 	freeaddrinfo(resolved); |  | ||||||
|   free(mmutable); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::string parseEndpoint(SOCKADDR_INET *input) { |  | ||||||
|   if (!(input->si_family == AF_INET || input->si_family == AF_INET6)) return ""; |  | ||||||
|   char saddr[INET6_ADDRSTRLEN]; |  | ||||||
|   input->si_family == AF_INET ? inet_ntop(AF_INET, &input->Ipv4.sin_addr, saddr, INET_ADDRSTRLEN) : inet_ntop(AF_INET6, &input->Ipv6.sin6_addr, saddr, INET6_ADDRSTRLEN); |  | ||||||
|  |  | ||||||
|   if (input->si_family == AF_INET6) return std::string("[").append(saddr).append("]:").append(std::to_string(htons(input->Ipv6.sin6_port))); |  | ||||||
|   return std::string(saddr).append(":").append(std::to_string(htons(input->Ipv4.sin_port))); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::string insertIpAddr(NET_LUID InterfaceLuid, std::string IPv4, std::string IPv6) { |  | ||||||
|   NET_IFINDEX ind; |  | ||||||
|   if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &ind) != NO_ERROR) return "Cannot get interface index"; |  | ||||||
|  |  | ||||||
|   // IPv4 |  | ||||||
|   if (IPv4.size() > 0) { |  | ||||||
|     ULONG NTEContext = 0; |  | ||||||
|     ULONG NTEInstance = 0; |  | ||||||
|     UINT iaIPAddress; |  | ||||||
|     inet_pton(AF_INET, IPv4.c_str(), &iaIPAddress); |  | ||||||
|     auto status = AddIPAddress(iaIPAddress, NULL, ind, &NTEContext, &NTEInstance); |  | ||||||
|     if (status != NO_ERROR) { |  | ||||||
|       if (status == 5010) { |  | ||||||
|       } else return std::string("Cannot set IPv4 interface, error code: ").append(std::to_string(status)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // IPv6 |  | ||||||
|   if (IPv6.size() > 0) { |  | ||||||
|     UINT iaIPAddress; |  | ||||||
|     inet_pton(AF_INET6, IPv6.c_str(), &iaIPAddress); |  | ||||||
|     std::cerr << "Current not support IPv6 to set in interface!" << std::endl; |  | ||||||
|   } |  | ||||||
|   return ""; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::vector<std::string> getIpAddr(NET_LUID InterfaceLuid) { |  | ||||||
|   NET_IFINDEX ind; |  | ||||||
|   if (ConvertInterfaceLuidToIndex(&InterfaceLuid, &ind) != NO_ERROR) throw std::string("Cannot get interface index"); |  | ||||||
|   std::vector<std::string> ips; |  | ||||||
|  |  | ||||||
|   IP_ADAPTER_INFO  *pAdapterInfo; |  | ||||||
|   ULONG ulOutBufLen; |  | ||||||
|   DWORD dwRetVal; |  | ||||||
|   pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) ); |  | ||||||
|   ulOutBufLen = sizeof(IP_ADAPTER_INFO); |  | ||||||
|   if (GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) { |  | ||||||
|     free (pAdapterInfo); |  | ||||||
|     pAdapterInfo = (IP_ADAPTER_INFO *) malloc ( ulOutBufLen ); |  | ||||||
|   } |  | ||||||
|   if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) != ERROR_SUCCESS) throw std::string("GetAdaptersInfo call failed with ").append(std::to_string(dwRetVal)); |  | ||||||
|   PIP_ADAPTER_INFO pAdapter = pAdapterInfo; |  | ||||||
|   while (pAdapter) { |  | ||||||
|     if (pAdapter->Index == ind) ips.push_back(std::string(pAdapter->IpAddressList.IpAddress.String).append("/32")); |  | ||||||
|     pAdapter = pAdapter->Next; |  | ||||||
|   } |  | ||||||
|   if (pAdapterInfo) free(pAdapterInfo); |  | ||||||
|  |  | ||||||
|   return ips; |  | ||||||
| } |  | ||||||
							
								
								
									
										110
									
								
								binding.yaml
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								binding.yaml
									
									
									
									
									
								
							| @@ -1,80 +1,56 @@ | |||||||
| name: wginterface | name: wginterface | ||||||
| flags: |  | ||||||
|   - "!-fno-exceptions" |  | ||||||
|   - "-fpermissive" |  | ||||||
|   - "-fexceptions" |  | ||||||
|   - "-w" |  | ||||||
|   - "-fpermissive" |  | ||||||
| flagsCC: |  | ||||||
|   - "!-fno-exceptions" |  | ||||||
|   - "-fpermissive" |  | ||||||
|   - "-fexceptions" |  | ||||||
|   - "-w" |  | ||||||
|   - "-fpermissive" |  | ||||||
| defines: | defines: | ||||||
|   - "NAPI_DISABLE_CPP_EXCEPTIONS" |   - "NODE_VERSION=8" | ||||||
|   - "NODE_VERSION=4" |   - "NAPI_CPP_EXCEPTIONS" | ||||||
| includes: | includes: | ||||||
|   - addons/genKey |  | ||||||
|   - addons/tools |  | ||||||
|   - node_modules/node-addon-api |   - node_modules/node-addon-api | ||||||
|  |   - ./addon | ||||||
| sources: | sources: | ||||||
|   - "addons/genKey/wgkeys.cpp" |   - "addon/main.cpp" | ||||||
|   - "addons/tools/wginterface.cpp" |   - "addon/genKey/wgkeys.cpp" | ||||||
|   - "addons/tools/wginterface-dummy.cpp" |   - "addon/userspace/wginterface.cpp" | ||||||
|  | prebuild: | ||||||
|  |   - shell: bash | ||||||
|  |     cwd: ./addon/userspace/go | ||||||
|  |     env: | ||||||
|  |       CGO_ENABLED: "1" | ||||||
|  |       LDFLAGS: "-w" | ||||||
|  |     run: | | ||||||
|  |       go build -trimpath -v -o ../wg-go.o -buildmode c-archive . | ||||||
|  |       mv -fv ../wg-go.o "${BUILDDIR}" | ||||||
| target: | target: | ||||||
|   macos: |  | ||||||
|     defines: |  | ||||||
|       - USERSPACE_GO |  | ||||||
|   linux: |   linux: | ||||||
|     sources: |     sources: | ||||||
|       - "addons/tools/linux/wireguard.c" |       - "!addon/userspace/wginterface.cpp" | ||||||
|       - "addons/tools/wginterface-linux.cpp" |       - "addon/linux/wginterface.cpp" | ||||||
|       - "!addons/tools/wginterface-dummy.cpp" |       - "addon/linux/wireguard.c" | ||||||
|     defines: |  | ||||||
|       - "LISTDEV" |  | ||||||
|       - "GETCONFIG" |  | ||||||
|       - "SETCONFIG" |  | ||||||
|       - "DELIFACE" |  | ||||||
|     target: |  | ||||||
|       x86_64: |  | ||||||
|         release: true |  | ||||||
|     flags: |     flags: | ||||||
|           - "-fPIC" |       - "!-fno-exceptions" | ||||||
|         flagsCC: |       - "-fpermissive" | ||||||
|           - "-fPIC" |       - "-fexceptions" | ||||||
|       aarch64: |       - "-w" | ||||||
|         release: true |       - "-fpermissive" | ||||||
|         flags: |  | ||||||
|           - "-fPIC" |  | ||||||
|         flagsCC: |  | ||||||
|       - "-fPIC" |       - "-fPIC" | ||||||
|   windows: |   windows: | ||||||
|     flags: |  | ||||||
|       - "-undefined" |  | ||||||
|       - "dynamic_lookup" |  | ||||||
|     target: |  | ||||||
|       x86_64: |  | ||||||
|         release: true |  | ||||||
|       aarch64: |  | ||||||
|         release: true |  | ||||||
|     sources: |     sources: | ||||||
|       - "addons/tools/wginterface-win.cpp" |       - "!addon/userspace/wginterface.cpp" | ||||||
|       - "!addons/tools/wginterface-dummy.cpp" |       - "addon/win/wginterface.cpp" | ||||||
|     includes: |  | ||||||
|       - "addons/tools/win" |  | ||||||
|     defines: |  | ||||||
|       - "ONSTARTADDON" |  | ||||||
|       - "LISTDEV" |  | ||||||
|       - "GETCONFIG" |  | ||||||
|       - "SETCONFIG" |  | ||||||
|       - "DELIFACE" |  | ||||||
|       - "_HAS_EXCEPTIONS=1" |  | ||||||
|     libraries: |     libraries: | ||||||
|       - "bcrypt.lib" |       - wbemuuid.lib | ||||||
|       - "crypt32.lib" |       - bcrypt.lib | ||||||
|       - "iphlpapi.lib" |       - crypt32.lib | ||||||
|       - "kernel32.lib" |       - iphlpapi.lib | ||||||
|       - "ntdll.lib" |       - kernel32.lib | ||||||
|       - "ws2_32.lib" |       - ntdll.lib | ||||||
|       - "setupapi.lib" |       - ws2_32.lib | ||||||
|  |       - setupapi.lib | ||||||
|  |     defines: | ||||||
|  |       - "_HAS_EXCEPTIONS=1" | ||||||
|  |       - "ONSTARTADDON" | ||||||
|  |   macos: | ||||||
|  |     flags: | ||||||
|  |       - "!-fno-exceptions" | ||||||
|  |       - "-fpermissive" | ||||||
|  |       - "-fexceptions" | ||||||
|  |       - "-w" | ||||||
|  |       - "-fpermissive" | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								package.json
									
									
									
									
									
								
							| @@ -11,7 +11,7 @@ | |||||||
|   "license": "GPL-3.0-or-later", |   "license": "GPL-3.0-or-later", | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
|     "url": "git+https://sirherobrine23.org/Wireguard/Wireguard-tools.js.git" |     "url": "https://sirherobrine23.org/Wireguard/Wireguard-tools.js.git" | ||||||
|   }, |   }, | ||||||
|   "keywords": [ |   "keywords": [ | ||||||
|     "wireguard", |     "wireguard", | ||||||
| @@ -34,18 +34,18 @@ | |||||||
|   }, |   }, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "install": "rebory prebuild", |     "install": "rebory prebuild", | ||||||
|     "dev": "rebory build -DP", |     "dev": "rebory build", | ||||||
|     "test": "rebory build -D && node --no-warnings --loader ts-node/esm src/index_test.js", |     "test": "rebory build && node --no-warnings --loader ts-node/esm src/index_test.js", | ||||||
|     "prepack": "tsc --build --clean && tsc --build", |     "prepack": "tsc --build --clean && tsc --build && rebory build --release", | ||||||
|     "postpack": "tsc --build --clean" |     "postpack": "tsc --build --clean" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/node": "^20.11.19", |     "@types/node": "^20.11.26", | ||||||
|     "ts-node": "^10.9.2", |     "ts-node": "^10.9.2", | ||||||
|     "typescript": "^5.3.3" |     "typescript": "^5.4.2" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "node-addon-api": "^7.1.0", |     "node-addon-api": "^8.0.0", | ||||||
|     "rebory": "^0.1.12" |     "rebory": "^0.2.5" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,414 +0,0 @@ | |||||||
| # Do not edit. File was generated by node-gyp's "configure" step |  | ||||||
| { |  | ||||||
|   "target_defaults": { |  | ||||||
|     "cflags": [], |  | ||||||
|     "default_configuration": "Release", |  | ||||||
|     "defines": [], |  | ||||||
|     "include_dirs": [], |  | ||||||
|     "libraries": [], |  | ||||||
|     "msbuild_toolset": "v143", |  | ||||||
|     "msvs_windows_target_platform_version": "10.0.22621.0" |  | ||||||
|   }, |  | ||||||
|   "variables": { |  | ||||||
|     "asan": 0, |  | ||||||
|     "coverage": "false", |  | ||||||
|     "dcheck_always_on": 0, |  | ||||||
|     "debug_nghttp2": "false", |  | ||||||
|     "debug_node": "false", |  | ||||||
|     "enable_lto": "false", |  | ||||||
|     "enable_pgo_generate": "false", |  | ||||||
|     "enable_pgo_use": "false", |  | ||||||
|     "error_on_warn": "false", |  | ||||||
|     "force_dynamic_crt": 0, |  | ||||||
|     "host_arch": "x64", |  | ||||||
|     "icu_data_in": "..\\..\\deps\\icu-tmp\\icudt73l.dat", |  | ||||||
|     "icu_endianness": "l", |  | ||||||
|     "icu_gyp_path": "tools/icu/icu-generic.gyp", |  | ||||||
|     "icu_path": "deps/icu-small", |  | ||||||
|     "icu_small": "false", |  | ||||||
|     "icu_ver_major": "73", |  | ||||||
|     "is_debug": 0, |  | ||||||
|     "libdir": "lib", |  | ||||||
|     "llvm_version": "0.0", |  | ||||||
|     "napi_build_version": "9", |  | ||||||
|     "nasm_version": "2.16", |  | ||||||
|     "node_builtin_shareable_builtins": [ |  | ||||||
|       "deps/cjs-module-lexer/lexer.js", |  | ||||||
|       "deps/cjs-module-lexer/dist/lexer.js", |  | ||||||
|       "deps/undici/undici.js" |  | ||||||
|     ], |  | ||||||
|     "node_byteorder": "little", |  | ||||||
|     "node_debug_lib": "false", |  | ||||||
|     "node_enable_d8": "false", |  | ||||||
|     "node_enable_v8_vtunejit": "false", |  | ||||||
|     "node_fipsinstall": "false", |  | ||||||
|     "node_install_corepack": "true", |  | ||||||
|     "node_install_npm": "true", |  | ||||||
|     "node_library_files": [ |  | ||||||
|       "lib/_http_agent.js", |  | ||||||
|       "lib/_http_client.js", |  | ||||||
|       "lib/_http_common.js", |  | ||||||
|       "lib/_http_incoming.js", |  | ||||||
|       "lib/_http_outgoing.js", |  | ||||||
|       "lib/_http_server.js", |  | ||||||
|       "lib/_stream_duplex.js", |  | ||||||
|       "lib/_stream_passthrough.js", |  | ||||||
|       "lib/_stream_readable.js", |  | ||||||
|       "lib/_stream_transform.js", |  | ||||||
|       "lib/_stream_wrap.js", |  | ||||||
|       "lib/_stream_writable.js", |  | ||||||
|       "lib/_tls_common.js", |  | ||||||
|       "lib/_tls_wrap.js", |  | ||||||
|       "lib/assert.js", |  | ||||||
|       "lib/assert/strict.js", |  | ||||||
|       "lib/async_hooks.js", |  | ||||||
|       "lib/buffer.js", |  | ||||||
|       "lib/child_process.js", |  | ||||||
|       "lib/cluster.js", |  | ||||||
|       "lib/console.js", |  | ||||||
|       "lib/constants.js", |  | ||||||
|       "lib/crypto.js", |  | ||||||
|       "lib/dgram.js", |  | ||||||
|       "lib/diagnostics_channel.js", |  | ||||||
|       "lib/dns.js", |  | ||||||
|       "lib/dns/promises.js", |  | ||||||
|       "lib/domain.js", |  | ||||||
|       "lib/events.js", |  | ||||||
|       "lib/fs.js", |  | ||||||
|       "lib/fs/promises.js", |  | ||||||
|       "lib/http.js", |  | ||||||
|       "lib/http2.js", |  | ||||||
|       "lib/https.js", |  | ||||||
|       "lib/inspector.js", |  | ||||||
|       "lib/inspector/promises.js", |  | ||||||
|       "lib/internal/abort_controller.js", |  | ||||||
|       "lib/internal/assert.js", |  | ||||||
|       "lib/internal/assert/assertion_error.js", |  | ||||||
|       "lib/internal/assert/calltracker.js", |  | ||||||
|       "lib/internal/async_hooks.js", |  | ||||||
|       "lib/internal/blob.js", |  | ||||||
|       "lib/internal/blocklist.js", |  | ||||||
|       "lib/internal/bootstrap/node.js", |  | ||||||
|       "lib/internal/bootstrap/realm.js", |  | ||||||
|       "lib/internal/bootstrap/switches/does_not_own_process_state.js", |  | ||||||
|       "lib/internal/bootstrap/switches/does_own_process_state.js", |  | ||||||
|       "lib/internal/bootstrap/switches/is_main_thread.js", |  | ||||||
|       "lib/internal/bootstrap/switches/is_not_main_thread.js", |  | ||||||
|       "lib/internal/bootstrap/web/exposed-wildcard.js", |  | ||||||
|       "lib/internal/bootstrap/web/exposed-window-or-worker.js", |  | ||||||
|       "lib/internal/buffer.js", |  | ||||||
|       "lib/internal/child_process.js", |  | ||||||
|       "lib/internal/child_process/serialization.js", |  | ||||||
|       "lib/internal/cli_table.js", |  | ||||||
|       "lib/internal/cluster/child.js", |  | ||||||
|       "lib/internal/cluster/primary.js", |  | ||||||
|       "lib/internal/cluster/round_robin_handle.js", |  | ||||||
|       "lib/internal/cluster/shared_handle.js", |  | ||||||
|       "lib/internal/cluster/utils.js", |  | ||||||
|       "lib/internal/cluster/worker.js", |  | ||||||
|       "lib/internal/console/constructor.js", |  | ||||||
|       "lib/internal/console/global.js", |  | ||||||
|       "lib/internal/constants.js", |  | ||||||
|       "lib/internal/crypto/aes.js", |  | ||||||
|       "lib/internal/crypto/certificate.js", |  | ||||||
|       "lib/internal/crypto/cfrg.js", |  | ||||||
|       "lib/internal/crypto/cipher.js", |  | ||||||
|       "lib/internal/crypto/diffiehellman.js", |  | ||||||
|       "lib/internal/crypto/ec.js", |  | ||||||
|       "lib/internal/crypto/hash.js", |  | ||||||
|       "lib/internal/crypto/hashnames.js", |  | ||||||
|       "lib/internal/crypto/hkdf.js", |  | ||||||
|       "lib/internal/crypto/keygen.js", |  | ||||||
|       "lib/internal/crypto/keys.js", |  | ||||||
|       "lib/internal/crypto/mac.js", |  | ||||||
|       "lib/internal/crypto/pbkdf2.js", |  | ||||||
|       "lib/internal/crypto/random.js", |  | ||||||
|       "lib/internal/crypto/rsa.js", |  | ||||||
|       "lib/internal/crypto/scrypt.js", |  | ||||||
|       "lib/internal/crypto/sig.js", |  | ||||||
|       "lib/internal/crypto/util.js", |  | ||||||
|       "lib/internal/crypto/webcrypto.js", |  | ||||||
|       "lib/internal/crypto/webidl.js", |  | ||||||
|       "lib/internal/crypto/x509.js", |  | ||||||
|       "lib/internal/debugger/inspect.js", |  | ||||||
|       "lib/internal/debugger/inspect_client.js", |  | ||||||
|       "lib/internal/debugger/inspect_repl.js", |  | ||||||
|       "lib/internal/dgram.js", |  | ||||||
|       "lib/internal/dns/callback_resolver.js", |  | ||||||
|       "lib/internal/dns/promises.js", |  | ||||||
|       "lib/internal/dns/utils.js", |  | ||||||
|       "lib/internal/encoding.js", |  | ||||||
|       "lib/internal/error_serdes.js", |  | ||||||
|       "lib/internal/errors.js", |  | ||||||
|       "lib/internal/event_target.js", |  | ||||||
|       "lib/internal/events/symbols.js", |  | ||||||
|       "lib/internal/file.js", |  | ||||||
|       "lib/internal/fixed_queue.js", |  | ||||||
|       "lib/internal/freelist.js", |  | ||||||
|       "lib/internal/freeze_intrinsics.js", |  | ||||||
|       "lib/internal/fs/cp/cp-sync.js", |  | ||||||
|       "lib/internal/fs/cp/cp.js", |  | ||||||
|       "lib/internal/fs/dir.js", |  | ||||||
|       "lib/internal/fs/promises.js", |  | ||||||
|       "lib/internal/fs/read/context.js", |  | ||||||
|       "lib/internal/fs/read/utf8.js", |  | ||||||
|       "lib/internal/fs/recursive_watch.js", |  | ||||||
|       "lib/internal/fs/rimraf.js", |  | ||||||
|       "lib/internal/fs/streams.js", |  | ||||||
|       "lib/internal/fs/sync_write_stream.js", |  | ||||||
|       "lib/internal/fs/utils.js", |  | ||||||
|       "lib/internal/fs/watchers.js", |  | ||||||
|       "lib/internal/heap_utils.js", |  | ||||||
|       "lib/internal/histogram.js", |  | ||||||
|       "lib/internal/http.js", |  | ||||||
|       "lib/internal/http2/compat.js", |  | ||||||
|       "lib/internal/http2/core.js", |  | ||||||
|       "lib/internal/http2/util.js", |  | ||||||
|       "lib/internal/idna.js", |  | ||||||
|       "lib/internal/inspector_async_hook.js", |  | ||||||
|       "lib/internal/js_stream_socket.js", |  | ||||||
|       "lib/internal/legacy/processbinding.js", |  | ||||||
|       "lib/internal/linkedlist.js", |  | ||||||
|       "lib/internal/main/check_syntax.js", |  | ||||||
|       "lib/internal/main/embedding.js", |  | ||||||
|       "lib/internal/main/eval_stdin.js", |  | ||||||
|       "lib/internal/main/eval_string.js", |  | ||||||
|       "lib/internal/main/inspect.js", |  | ||||||
|       "lib/internal/main/mksnapshot.js", |  | ||||||
|       "lib/internal/main/print_help.js", |  | ||||||
|       "lib/internal/main/prof_process.js", |  | ||||||
|       "lib/internal/main/repl.js", |  | ||||||
|       "lib/internal/main/run_main_module.js", |  | ||||||
|       "lib/internal/main/test_runner.js", |  | ||||||
|       "lib/internal/main/watch_mode.js", |  | ||||||
|       "lib/internal/main/worker_thread.js", |  | ||||||
|       "lib/internal/mime.js", |  | ||||||
|       "lib/internal/modules/cjs/loader.js", |  | ||||||
|       "lib/internal/modules/esm/assert.js", |  | ||||||
|       "lib/internal/modules/esm/create_dynamic_module.js", |  | ||||||
|       "lib/internal/modules/esm/fetch_module.js", |  | ||||||
|       "lib/internal/modules/esm/formats.js", |  | ||||||
|       "lib/internal/modules/esm/get_format.js", |  | ||||||
|       "lib/internal/modules/esm/handle_process_exit.js", |  | ||||||
|       "lib/internal/modules/esm/hooks.js", |  | ||||||
|       "lib/internal/modules/esm/initialize_import_meta.js", |  | ||||||
|       "lib/internal/modules/esm/load.js", |  | ||||||
|       "lib/internal/modules/esm/loader.js", |  | ||||||
|       "lib/internal/modules/esm/module_job.js", |  | ||||||
|       "lib/internal/modules/esm/module_map.js", |  | ||||||
|       "lib/internal/modules/esm/package_config.js", |  | ||||||
|       "lib/internal/modules/esm/resolve.js", |  | ||||||
|       "lib/internal/modules/esm/shared_constants.js", |  | ||||||
|       "lib/internal/modules/esm/translators.js", |  | ||||||
|       "lib/internal/modules/esm/utils.js", |  | ||||||
|       "lib/internal/modules/esm/worker.js", |  | ||||||
|       "lib/internal/modules/helpers.js", |  | ||||||
|       "lib/internal/modules/package_json_reader.js", |  | ||||||
|       "lib/internal/modules/run_main.js", |  | ||||||
|       "lib/internal/net.js", |  | ||||||
|       "lib/internal/options.js", |  | ||||||
|       "lib/internal/per_context/domexception.js", |  | ||||||
|       "lib/internal/per_context/messageport.js", |  | ||||||
|       "lib/internal/per_context/primordials.js", |  | ||||||
|       "lib/internal/perf/event_loop_delay.js", |  | ||||||
|       "lib/internal/perf/event_loop_utilization.js", |  | ||||||
|       "lib/internal/perf/nodetiming.js", |  | ||||||
|       "lib/internal/perf/observe.js", |  | ||||||
|       "lib/internal/perf/performance.js", |  | ||||||
|       "lib/internal/perf/performance_entry.js", |  | ||||||
|       "lib/internal/perf/resource_timing.js", |  | ||||||
|       "lib/internal/perf/timerify.js", |  | ||||||
|       "lib/internal/perf/usertiming.js", |  | ||||||
|       "lib/internal/perf/utils.js", |  | ||||||
|       "lib/internal/policy/manifest.js", |  | ||||||
|       "lib/internal/policy/sri.js", |  | ||||||
|       "lib/internal/priority_queue.js", |  | ||||||
|       "lib/internal/process/esm_loader.js", |  | ||||||
|       "lib/internal/process/execution.js", |  | ||||||
|       "lib/internal/process/per_thread.js", |  | ||||||
|       "lib/internal/process/permission.js", |  | ||||||
|       "lib/internal/process/policy.js", |  | ||||||
|       "lib/internal/process/pre_execution.js", |  | ||||||
|       "lib/internal/process/promises.js", |  | ||||||
|       "lib/internal/process/report.js", |  | ||||||
|       "lib/internal/process/signal.js", |  | ||||||
|       "lib/internal/process/task_queues.js", |  | ||||||
|       "lib/internal/process/warning.js", |  | ||||||
|       "lib/internal/process/worker_thread_only.js", |  | ||||||
|       "lib/internal/promise_hooks.js", |  | ||||||
|       "lib/internal/querystring.js", |  | ||||||
|       "lib/internal/readline/callbacks.js", |  | ||||||
|       "lib/internal/readline/emitKeypressEvents.js", |  | ||||||
|       "lib/internal/readline/interface.js", |  | ||||||
|       "lib/internal/readline/promises.js", |  | ||||||
|       "lib/internal/readline/utils.js", |  | ||||||
|       "lib/internal/repl.js", |  | ||||||
|       "lib/internal/repl/await.js", |  | ||||||
|       "lib/internal/repl/history.js", |  | ||||||
|       "lib/internal/repl/utils.js", |  | ||||||
|       "lib/internal/socket_list.js", |  | ||||||
|       "lib/internal/socketaddress.js", |  | ||||||
|       "lib/internal/source_map/prepare_stack_trace.js", |  | ||||||
|       "lib/internal/source_map/source_map.js", |  | ||||||
|       "lib/internal/source_map/source_map_cache.js", |  | ||||||
|       "lib/internal/stream_base_commons.js", |  | ||||||
|       "lib/internal/streams/add-abort-signal.js", |  | ||||||
|       "lib/internal/streams/buffer_list.js", |  | ||||||
|       "lib/internal/streams/compose.js", |  | ||||||
|       "lib/internal/streams/destroy.js", |  | ||||||
|       "lib/internal/streams/duplex.js", |  | ||||||
|       "lib/internal/streams/duplexify.js", |  | ||||||
|       "lib/internal/streams/end-of-stream.js", |  | ||||||
|       "lib/internal/streams/from.js", |  | ||||||
|       "lib/internal/streams/lazy_transform.js", |  | ||||||
|       "lib/internal/streams/legacy.js", |  | ||||||
|       "lib/internal/streams/operators.js", |  | ||||||
|       "lib/internal/streams/passthrough.js", |  | ||||||
|       "lib/internal/streams/pipeline.js", |  | ||||||
|       "lib/internal/streams/readable.js", |  | ||||||
|       "lib/internal/streams/state.js", |  | ||||||
|       "lib/internal/streams/transform.js", |  | ||||||
|       "lib/internal/streams/utils.js", |  | ||||||
|       "lib/internal/streams/writable.js", |  | ||||||
|       "lib/internal/structured_clone.js", |  | ||||||
|       "lib/internal/test/binding.js", |  | ||||||
|       "lib/internal/test/transfer.js", |  | ||||||
|       "lib/internal/test_runner/coverage.js", |  | ||||||
|       "lib/internal/test_runner/harness.js", |  | ||||||
|       "lib/internal/test_runner/mock/mock.js", |  | ||||||
|       "lib/internal/test_runner/mock/mock_timers.js", |  | ||||||
|       "lib/internal/test_runner/reporter/dot.js", |  | ||||||
|       "lib/internal/test_runner/reporter/spec.js", |  | ||||||
|       "lib/internal/test_runner/reporter/tap.js", |  | ||||||
|       "lib/internal/test_runner/reporter/v8-serializer.js", |  | ||||||
|       "lib/internal/test_runner/runner.js", |  | ||||||
|       "lib/internal/test_runner/test.js", |  | ||||||
|       "lib/internal/test_runner/tests_stream.js", |  | ||||||
|       "lib/internal/test_runner/utils.js", |  | ||||||
|       "lib/internal/timers.js", |  | ||||||
|       "lib/internal/tls/secure-context.js", |  | ||||||
|       "lib/internal/tls/secure-pair.js", |  | ||||||
|       "lib/internal/trace_events_async_hooks.js", |  | ||||||
|       "lib/internal/tty.js", |  | ||||||
|       "lib/internal/url.js", |  | ||||||
|       "lib/internal/util.js", |  | ||||||
|       "lib/internal/util/colors.js", |  | ||||||
|       "lib/internal/util/comparisons.js", |  | ||||||
|       "lib/internal/util/debuglog.js", |  | ||||||
|       "lib/internal/util/embedding.js", |  | ||||||
|       "lib/internal/util/inspect.js", |  | ||||||
|       "lib/internal/util/inspector.js", |  | ||||||
|       "lib/internal/util/iterable_weak_map.js", |  | ||||||
|       "lib/internal/util/parse_args/parse_args.js", |  | ||||||
|       "lib/internal/util/parse_args/utils.js", |  | ||||||
|       "lib/internal/util/types.js", |  | ||||||
|       "lib/internal/v8/startup_snapshot.js", |  | ||||||
|       "lib/internal/v8_prof_polyfill.js", |  | ||||||
|       "lib/internal/v8_prof_processor.js", |  | ||||||
|       "lib/internal/validators.js", |  | ||||||
|       "lib/internal/vm.js", |  | ||||||
|       "lib/internal/vm/module.js", |  | ||||||
|       "lib/internal/wasm_web_api.js", |  | ||||||
|       "lib/internal/watch_mode/files_watcher.js", |  | ||||||
|       "lib/internal/watchdog.js", |  | ||||||
|       "lib/internal/webidl.js", |  | ||||||
|       "lib/internal/webstreams/adapters.js", |  | ||||||
|       "lib/internal/webstreams/compression.js", |  | ||||||
|       "lib/internal/webstreams/encoding.js", |  | ||||||
|       "lib/internal/webstreams/queuingstrategies.js", |  | ||||||
|       "lib/internal/webstreams/readablestream.js", |  | ||||||
|       "lib/internal/webstreams/transfer.js", |  | ||||||
|       "lib/internal/webstreams/transformstream.js", |  | ||||||
|       "lib/internal/webstreams/util.js", |  | ||||||
|       "lib/internal/webstreams/writablestream.js", |  | ||||||
|       "lib/internal/worker.js", |  | ||||||
|       "lib/internal/worker/io.js", |  | ||||||
|       "lib/internal/worker/js_transferable.js", |  | ||||||
|       "lib/module.js", |  | ||||||
|       "lib/net.js", |  | ||||||
|       "lib/os.js", |  | ||||||
|       "lib/path.js", |  | ||||||
|       "lib/path/posix.js", |  | ||||||
|       "lib/path/win32.js", |  | ||||||
|       "lib/perf_hooks.js", |  | ||||||
|       "lib/process.js", |  | ||||||
|       "lib/punycode.js", |  | ||||||
|       "lib/querystring.js", |  | ||||||
|       "lib/readline.js", |  | ||||||
|       "lib/readline/promises.js", |  | ||||||
|       "lib/repl.js", |  | ||||||
|       "lib/stream.js", |  | ||||||
|       "lib/stream/consumers.js", |  | ||||||
|       "lib/stream/promises.js", |  | ||||||
|       "lib/stream/web.js", |  | ||||||
|       "lib/string_decoder.js", |  | ||||||
|       "lib/sys.js", |  | ||||||
|       "lib/test.js", |  | ||||||
|       "lib/test/reporters.js", |  | ||||||
|       "lib/timers.js", |  | ||||||
|       "lib/timers/promises.js", |  | ||||||
|       "lib/tls.js", |  | ||||||
|       "lib/trace_events.js", |  | ||||||
|       "lib/tty.js", |  | ||||||
|       "lib/url.js", |  | ||||||
|       "lib/util.js", |  | ||||||
|       "lib/util/types.js", |  | ||||||
|       "lib/v8.js", |  | ||||||
|       "lib/vm.js", |  | ||||||
|       "lib/wasi.js", |  | ||||||
|       "lib/worker_threads.js", |  | ||||||
|       "lib/zlib.js" |  | ||||||
|     ], |  | ||||||
|     "node_module_version": 115, |  | ||||||
|     "node_no_browser_globals": "false", |  | ||||||
|     "node_prefix": "\\usr\\local", |  | ||||||
|     "node_release_urlbase": "https://nodejs.org/download/release/", |  | ||||||
|     "node_shared": "false", |  | ||||||
|     "node_shared_brotli": "false", |  | ||||||
|     "node_shared_cares": "false", |  | ||||||
|     "node_shared_http_parser": "false", |  | ||||||
|     "node_shared_libuv": "false", |  | ||||||
|     "node_shared_nghttp2": "false", |  | ||||||
|     "node_shared_nghttp3": "false", |  | ||||||
|     "node_shared_ngtcp2": "false", |  | ||||||
|     "node_shared_openssl": "false", |  | ||||||
|     "node_shared_zlib": "false", |  | ||||||
|     "node_tag": "", |  | ||||||
|     "node_target_type": "executable", |  | ||||||
|     "node_use_bundled_v8": "true", |  | ||||||
|     "node_use_node_code_cache": "true", |  | ||||||
|     "node_use_node_snapshot": "true", |  | ||||||
|     "node_use_openssl": "true", |  | ||||||
|     "node_use_v8_platform": "true", |  | ||||||
|     "node_with_ltcg": "true", |  | ||||||
|     "node_without_node_options": "false", |  | ||||||
|     "openssl_is_fips": "false", |  | ||||||
|     "openssl_quic": "true", |  | ||||||
|     "ossfuzz": "false", |  | ||||||
|     "shlib_suffix": "so.115", |  | ||||||
|     "single_executable_application": "true", |  | ||||||
|     "target_arch": "x64", |  | ||||||
|     "v8_enable_31bit_smis_on_64bit_arch": 0, |  | ||||||
|     "v8_enable_gdbjit": 0, |  | ||||||
|     "v8_enable_hugepage": 0, |  | ||||||
|     "v8_enable_i18n_support": 1, |  | ||||||
|     "v8_enable_inspector": 1, |  | ||||||
|     "v8_enable_javascript_promise_hooks": 1, |  | ||||||
|     "v8_enable_lite_mode": 0, |  | ||||||
|     "v8_enable_object_print": 1, |  | ||||||
|     "v8_enable_pointer_compression": 0, |  | ||||||
|     "v8_enable_shared_ro_heap": 1, |  | ||||||
|     "v8_enable_short_builtin_calls": 1, |  | ||||||
|     "v8_enable_webassembly": 1, |  | ||||||
|     "v8_no_strict_aliasing": 1, |  | ||||||
|     "v8_optimized_debug": 1, |  | ||||||
|     "v8_promise_internal_field_count": 1, |  | ||||||
|     "v8_random_seed": 0, |  | ||||||
|     "v8_trace_maps": 0, |  | ||||||
|     "v8_use_siphash": 1, |  | ||||||
|     "want_separate_host_toolset": 0, |  | ||||||
|     "nodedir": "C:\\Users\\mathe\\AppData\\Local\\node-gyp\\Cache\\20.6.1", |  | ||||||
|     "standalone_static_library": 1, |  | ||||||
|     "msbuild_path": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| export * as key from "./key.js"; | export * as key from "./key.js"; | ||||||
| export * as wgQuick from "./quick.js"; | export * as quickConfig from "./quick.js"; | ||||||
| export * from "./wginterface.js"; | export * from "./wginterface.js"; | ||||||
| export * as wginterface from "./wginterface.js"; | export * as wginterface from "./wginterface.js"; | ||||||
| export * as default from "./wginterface.js"; |  | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								src/key.ts
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								src/key.ts
									
									
									
									
									
								
							| @@ -1,5 +1,7 @@ | |||||||
| import crypto from "node:crypto"; | import crypto from "node:crypto"; | ||||||
|  |  | ||||||
|  | export const KeyLength = 32, Base64Length = 44; | ||||||
|  |  | ||||||
| type BinArray = Float64Array|Uint8Array|number[]; | type BinArray = Float64Array|Uint8Array|number[]; | ||||||
|  |  | ||||||
| function gf(init?: number[]) { | function gf(init?: number[]) { | ||||||
| @@ -94,39 +96,31 @@ function clamp(z: BinArray) { | |||||||
|   z[0] &= 248; |   z[0] &= 248; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | function Base64ToKey(keyInput: string): Uint8Array { | ||||||
|  * Generate preshared key blocking loop event |   if (keyInput.length !== Base64Length) throw new Error("Invalid key length", { cause: { Required: Base64Length, Input: keyInput.length } }); | ||||||
|  * |   return new Uint8Array(Buffer.from(keyInput, "base64")); | ||||||
|  * @deprecated - use presharedKey | } | ||||||
|  */ |  | ||||||
| export function presharedKeySync() { | function keyToBase64(key: Uint8Array): string { | ||||||
|   var privateKey = new Uint8Array(32); |   if (key.length !== KeyLength) throw new Error("Invalid key length", { cause: { Required: KeyLength, Input: key.length } }); | ||||||
|   crypto.randomFillSync(privateKey); |   return Buffer.from(key).toString("base64"); | ||||||
|   return keyToBase64(privateKey); | } | ||||||
|  |  | ||||||
|  | export function keyToHex(key: string): string { | ||||||
|  |   return Buffer.from(key, "base64").toString("hex"); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Generate preshared key |  * Generate preshared key | ||||||
|  */ |  */ | ||||||
| export async function presharedKey(): Promise<string> { | export async function presharedKey(): Promise<string> { | ||||||
|   var privateKey = new Uint8Array(32); |   var privateKey = new Uint8Array(KeyLength); | ||||||
|   return new Promise((done, reject) => crypto.randomFill(privateKey, (err) => { |   return new Promise((done, reject) => crypto.randomFill(privateKey, (err) => { | ||||||
|     if (err) return reject(err); |     if (err) return reject(err); | ||||||
|     done(keyToBase64(privateKey)); |     done(keyToBase64(privateKey)); | ||||||
|   })); |   })); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Create private key |  | ||||||
|  * |  | ||||||
|  * @deprecated - Use privateKey |  | ||||||
|  */ |  | ||||||
| export function privateKeySync() { |  | ||||||
|   var privateKey = Base64ToKey(presharedKeySync()); |  | ||||||
|   clamp(privateKey); |  | ||||||
|   return keyToBase64(privateKey); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Create private key |  * Create private key | ||||||
|  */ |  */ | ||||||
| @@ -136,14 +130,6 @@ export async function privateKey() { | |||||||
|   return keyToBase64(privateKey); |   return keyToBase64(privateKey); | ||||||
| } | } | ||||||
|  |  | ||||||
| export function keyToBase64(key: Uint8Array): string { |  | ||||||
|   return Buffer.from(key).toString("base64"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function Base64ToKey(keyInput: string): Uint8Array { |  | ||||||
|   return new Uint8Array(Buffer.from(keyInput, "base64")); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Get Public key from Private key |  * Get Public key from Private key | ||||||
|  * |  * | ||||||
| @@ -151,7 +137,7 @@ export function Base64ToKey(keyInput: string): Uint8Array { | |||||||
|  */ |  */ | ||||||
| export function publicKey(privKey: string) { | export function publicKey(privKey: string) { | ||||||
|   var privateKey: Uint8Array = Base64ToKey(privKey); |   var privateKey: Uint8Array = Base64ToKey(privKey); | ||||||
|   var r: number, z = new Uint8Array(32); |   var r: number, z = new Uint8Array(KeyLength); | ||||||
|   var a = gf([1]), |   var a = gf([1]), | ||||||
|     b = gf([9]), |     b = gf([9]), | ||||||
|     c = gf(), |     c = gf(), | ||||||
|   | |||||||
| @@ -1,46 +1,10 @@ | |||||||
| import { promises as fs } from "fs"; | import path from "node:path"; | ||||||
| import { isIPv4, createConnection as netConnection } from "net"; | import { loadAddon } from "rebory"; | ||||||
| import path from "path"; | import { key } from "./index.js"; | ||||||
| import readline from "readline"; | import { isIP } from "node:net"; | ||||||
| import { finished } from "stream/promises"; | const __dirname = import.meta.dirname || path.dirname((await import("node:url")).fileURLToPath(import.meta.url)); | ||||||
| import rebory from "rebory"; |  | ||||||
| import { fileURLToPath } from "url"; |  | ||||||
|  |  | ||||||
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | interface Peer { | ||||||
| const addon = rebory.loadAddon(path.join(__dirname, "../binding.yaml")).wginterface.loadRelease<{ |  | ||||||
|   listDevices?: () => Promise<{from: "userspace"|"kernel", name: string, path?: string}[]>; |  | ||||||
|   deleteInterface?: (wgName: string) => Promise<void>; |  | ||||||
|   setConfig?: (wgName: string, config: WgConfigSet) => Promise<void>; |  | ||||||
|   getConfig?: (wgName: string) => Promise<WgConfigGet>; |  | ||||||
|  |  | ||||||
|   createTun?: () => Promise<number|string>; |  | ||||||
|   deleteTun?: () => void; |  | ||||||
|   checkTun?: () => Promise<boolean>; |  | ||||||
|   getTun?: () => Promise<number|string>; |  | ||||||
|  |  | ||||||
|   /** Wireguard addon constants */ |  | ||||||
|   constants: { |  | ||||||
|     driveVersion: string; |  | ||||||
|     base64Length: number; |  | ||||||
|     keyLength: number; |  | ||||||
|     nameLength: number; |  | ||||||
|   }; |  | ||||||
| }>({ |  | ||||||
|   WIN32DLLPATH: path.resolve(__dirname, "../addons/tools/win/wireguard-nt/bin", ((process.arch === "x64" && "amd64") || (process.arch === "ia32" && "i386"))||process.arch, "wireguard.dll") |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| export const { |  | ||||||
|   constants |  | ||||||
| } = addon; |  | ||||||
|  |  | ||||||
| /** default location to run socket's */ |  | ||||||
| const defaultPath = (process.env.WIRWGUARD_GO_RUN||"").length > 0 ? path.resolve(process.cwd(), process.env.WIRWGUARD_GO_RUN) : process.platform === "win32" ? "\\\\.\\pipe\\WireGuard" : "/var/run/wireguard"; |  | ||||||
|  |  | ||||||
| async function exists(path: string) { |  | ||||||
|   return fs.open(path).then(o => o && (o.close().then(() => true, () => true))||true, () => false); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export interface Peer { |  | ||||||
|   /** Preshared key to peer */ |   /** Preshared key to peer */ | ||||||
|   presharedKey?: string; |   presharedKey?: string; | ||||||
|  |  | ||||||
| @@ -54,23 +18,26 @@ export interface Peer { | |||||||
|   allowedIPs?: string[]; |   allowedIPs?: string[]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export interface PeerSet extends Peer { | export interface SetPeer extends Peer { | ||||||
|   /** Mark this peer to be removed, any changes remove this option */ |   /** Remove this peer */ | ||||||
|   removeMe?: boolean; |   removeMe?: boolean; | ||||||
| } | } | ||||||
|  |  | ||||||
| export interface PeerGet extends Peer { | export interface GetPeer extends Peer { | ||||||
|   /** ReceiveBytes indicates the number of bytes received from this peer. */ |   /** ReceiveBytes indicates the number of bytes received from this peer. */ | ||||||
|   rxBytes?: number; |   rxBytes: bigint; | ||||||
|  |  | ||||||
|   /** TransmitBytes indicates the number of bytes transmitted to this peer. */ |   /** TransmitBytes indicates the number of bytes transmitted to this peer. */ | ||||||
|   txBytes?: number; |   txBytes: bigint; | ||||||
|  |  | ||||||
|   /** Last peer Handshake */ |   /** Last peer Handshake */ | ||||||
|   lastHandshake?: Date; |   lastHandshake: Date; | ||||||
| } | } | ||||||
|  |  | ||||||
| export interface WgConfigBase<T extends Peer> { | interface Config<T extends Peer> { | ||||||
|  |   /** Wireguard interface name */ | ||||||
|  |   name: string; | ||||||
|  |  | ||||||
|   /** privateKey specifies a private key configuration */ |   /** privateKey specifies a private key configuration */ | ||||||
|   privateKey: string; |   privateKey: string; | ||||||
|  |  | ||||||
| @@ -86,164 +53,341 @@ export interface WgConfigBase<T extends Peer> { | |||||||
|   /** Interface IP address'es */ |   /** Interface IP address'es */ | ||||||
|   address?: string[]; |   address?: string[]; | ||||||
|  |  | ||||||
|   /** Interface peers */ |   /** Interface Peers */ | ||||||
|   peers: Record<string, T>; |   peers: Record<string, T>; | ||||||
| } | }; | ||||||
|  |  | ||||||
| export interface WgConfigGet extends WgConfigBase<PeerGet> {} | export interface GetConfig extends Config<GetPeer> { }; | ||||||
| export interface WgConfigSet extends WgConfigBase<PeerSet> { | export interface SetConfig extends Config<SetPeer> { | ||||||
|   /** this option will remove all peers if `true` and add new peers */ |   /** this option will remove all peers if `true` and add new peers */ | ||||||
|   replacePeers?: boolean; |   replacePeers?: boolean; | ||||||
| } | }; | ||||||
|  |  | ||||||
| export type WgGlobalConfig = WgConfigSet & WgConfigGet; | export const addon = (await loadAddon(path.resolve(__dirname, "../binding.yaml"))).wginterface.load_addon<{ | ||||||
|  |   /** Current Wireguard drive version */ | ||||||
|  |   driveVersion?: string; | ||||||
|  |  | ||||||
| /** |   /** | ||||||
|  * Get Wireguard devices and locations |    * Delete interface if exists | ||||||
|  |    * @param name - Interface name | ||||||
|    */ |    */ | ||||||
| export async function listDevices() { |   deleteInterface(name: string): Promise<void>; | ||||||
|   let devices: {from: "userspace"|"kernel", name: string, path?: string}[] = []; |  | ||||||
|   if (typeof addon.listDevices === "function") devices = devices.concat(await addon.listDevices()); |  | ||||||
|   if (await exists(defaultPath)) (await fs.readdir(defaultPath)).forEach(file => devices.push({ from: "userspace", name: file.endsWith(".sock") ? file.slice(0, -5) : file, path: path.join("/var/run/wireguard", file) })); |  | ||||||
|   return devices; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |   /** | ||||||
|  * Delete wireguard interface if present |    * Get Wireguard interfaces list | ||||||
|  * @param wgName - Interface name |    * | ||||||
|  * @returns |    * if running in userspace return socket (UAPI) path's | ||||||
|    */ |    */ | ||||||
| export async function deleteInterface(wgName: string): Promise<void> { |   listDevices(): Promise<string[]>; | ||||||
|   if (typeof addon.deleteInterface === "function") return addon.deleteInterface(wgName); |  | ||||||
|   const dev = (await listDevices()).find(s => s.name === wgName); |  | ||||||
|   if (dev && dev.path) return fs.rm(dev.path, { force: true }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |   /** | ||||||
|  * Add the settings to the Wireguard interface, if it does not exist and the interface will be created automatically. |    * Get current config from Wireguard interface | ||||||
|  * |    * @param name - Interface name | ||||||
|  * To update the interface settings, first get the interface settings to update! |    */ | ||||||
|  * |   getConfig(name: string): Promise<GetConfig>; | ||||||
|  * @param wgName - Interface name |  | ||||||
|  |   /** | ||||||
|  |    * Set new config to Wireguard interface or create new interface if not exists | ||||||
|    * @param config - Interface config |    * @param config - Interface config | ||||||
|    */ |    */ | ||||||
| export async function setConfig(wgName: string, config: WgConfigGet): Promise<void>; |   setConfig(config: SetConfig): Promise<void>; | ||||||
| /** | }>({ | ||||||
|  * Add the settings to the Wireguard interface, if it does not exist and the interface will be created automatically. |   WIN32DLLPATH: path.resolve(__dirname, "../addon/win", (process.arch === "x64" && "amd64") || (process.arch === "ia32" && "x86") || process.arch, "wireguard.dll") | ||||||
|  * | }); | ||||||
|  * To update the interface settings, first get the interface settings to update! |  | ||||||
|  * | export const { | ||||||
|  * @param wgName - Interface name |   driveVersion, | ||||||
|  * @param config - Interface config |   listDevices, | ||||||
|  |   getConfig, | ||||||
|  |   setConfig, | ||||||
|  |   deleteInterface | ||||||
|  | } = addon; | ||||||
|  |  | ||||||
|  | export class WireGuardPeer { | ||||||
|  |   constructor(public publicKey: string, private __Wg: Wireguard) { } | ||||||
|  |  | ||||||
|  |   async getStats() { | ||||||
|  |     const { rxBytes, txBytes, lastHandshake } = await getConfig(this.__Wg.name).then((config) => config.peers[this.publicKey]); | ||||||
|  |     return { | ||||||
|  |       rxBytes, | ||||||
|  |       txBytes, | ||||||
|  |       lastHandshake | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   addNewAddress(address: string) { | ||||||
|  |     if (isIP(address.split("/")[0]) === 0) throw new Error("Invalid IP address"); | ||||||
|  |     if (!this.__Wg._peers) this.__Wg._peers = new Map(); | ||||||
|  |     const _addr = new Set(this.__Wg._peers.get(this.publicKey).allowedIPs); | ||||||
|  |     _addr.add(address.split("/")[0]); | ||||||
|  |     this.__Wg._peers.get(this.publicKey).allowedIPs = Array.from(_addr); | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   removeAddress(address: string) { | ||||||
|  |     if (isIP(address.split("/")[0]) === 0) throw new Error("Invalid IP address"); | ||||||
|  |     if (!this.__Wg._peers) this.__Wg._peers = new Map(); | ||||||
|  |     const _addr = new Set(this.__Wg._peers.get(this.publicKey).allowedIPs); | ||||||
|  |     _addr.delete(address.split("/")[0]); | ||||||
|  |     this.__Wg._peers.get(this.publicKey).allowedIPs = Array.from(_addr); | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   setKeepInterval(keepInterval: number) { | ||||||
|  |     if (typeof keepInterval !== "number" || keepInterval < 0) throw new Error("Invalid keepInterval"); | ||||||
|  |     if (!this.__Wg._peers) this.__Wg._peers = new Map(); | ||||||
|  |     if (keepInterval > 0) this.__Wg._peers.get(this.publicKey).keepInterval = keepInterval; | ||||||
|  |     else delete this.__Wg._peers.get(this.publicKey).keepInterval; | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   setEndpoint(endpoint: string) { | ||||||
|  |     if (typeof endpoint !== "string") throw new Error("Invalid endpoint"); | ||||||
|  |     if (!this.__Wg._peers) this.__Wg._peers = new Map(); | ||||||
|  |     if (endpoint.length > 0) this.__Wg._peers.get(this.publicKey).endpoint = endpoint; | ||||||
|  |     else delete this.__Wg._peers.get(this.publicKey).endpoint; | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Sets the preshared key for the peer. | ||||||
|  |    * @param presharedKey - The preshared key to set. If not provided, a new preshared key will be generated. | ||||||
|  |    * @returns The updated WireGuard interface object. | ||||||
|  |    * @throws {Error} If the provided preshared key is invalid. | ||||||
|    */ |    */ | ||||||
| export async function setConfig(wgName: string, config: WgConfigSet): Promise<void> { |   setPresharedKey(): Promise<this> & this; | ||||||
|   if (wgName.length > constants.nameLength) throw new Error("Interface name more then allowed", { cause: constants.nameLength }); |   /** | ||||||
|   if (typeof addon.setConfig === "function") return addon.setConfig(wgName, config); |    * Sets the preshared key for the peer. | ||||||
|   const client = netConnection(path.join(defaultPath, (wgName).concat(".sock"))); |    * @param presharedKey - The preshared key to set. If not provided, a new preshared key will be generated. | ||||||
|   const writel = (...data: any[]) => client.write(data.map(String).join("").concat("\n")); |    * @returns The updated WireGuard interface object. | ||||||
|   // Init set config in interface |    * @throws {Error} If the provided preshared key is invalid. | ||||||
|   writel("set=1"); |    */ | ||||||
|  |   setPresharedKey(presharedKey: string): this; | ||||||
|   // Port listening |   /** | ||||||
|   if (config.portListen !== undefined && Math.floor(config.portListen) >= 0) writel(("listen_port="), ((Math.floor(config.portListen)))); |    * Sets the preshared key for the peer. | ||||||
|  |    * @param presharedKey - The preshared key to set. If not provided, a new preshared key will be generated. | ||||||
|   // fwmark |    * @returns The updated WireGuard interface object. | ||||||
|   if (Math.floor(config.fwmark) >= 0) writel(("fwmark="), ((Math.floor(config.fwmark)))); |    * @throws {Error} If the provided preshared key is invalid. | ||||||
|  |    */ | ||||||
|   // Replace peer's |   setPresharedKey(presharedKey?: string) { | ||||||
|   if (config.replacePeers) writel("replace_peers=true"); |     if (!this.__Wg._peers) this.__Wg._peers = new Map(); | ||||||
|  |     if (!presharedKey) return Object.assign(key.presharedKey().then((presharedKey) => this.__Wg._peers.get(this.publicKey).presharedKey = presharedKey), this); | ||||||
|   // Keys |     if (typeof presharedKey !== "string" || presharedKey.length !== key.Base64Length) throw new Error("Invalid presharedKey"); | ||||||
|   if (typeof config.privateKey === "string" && config.privateKey.length > 0) writel(("private_key="), (Buffer.from(config.privateKey, "base64").toString("hex"))); |     if (!this.__Wg._peers) this.__Wg._peers = new Map(); | ||||||
|  |     this.__Wg._peers.get(this.publicKey).presharedKey = presharedKey; | ||||||
|   // Mount peer |     return this; | ||||||
|   for (const publicKey of Object.keys(config.peers||{})) { |  | ||||||
|     const { presharedKey, endpoint, keepInterval, removeMe, allowedIPs = [] } = config.peers[publicKey]; |  | ||||||
|  |  | ||||||
|     // Public key |  | ||||||
|     writel(("public_key="), (Buffer.from(publicKey, "base64").toString("hex"))); |  | ||||||
|     if (removeMe) { |  | ||||||
|       writel("remove=true"); // Remove peer |  | ||||||
|       continue; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|     if (typeof endpoint === "string" && endpoint.length > 0) writel(("endpoint="), (endpoint)); |   /** | ||||||
|     if (typeof presharedKey === "string" && presharedKey.length > 3) writel(("preshared_key="), (Buffer.from(presharedKey, "base64").toString("hex"))); |    * Removes the peer from the WireGuard interface. | ||||||
|     if (typeof keepInterval === "number" && Math.floor(keepInterval) > 0) writel(("persistent_keepalive_interval="), (String(Math.floor(keepInterval)))); |    * @returns The updated WireGuard interface. | ||||||
|     if (allowedIPs.length > 0) { |    */ | ||||||
|       writel("replace_allowed_ips=true"); |   remove() { | ||||||
|       const fixed = allowedIPs.map(i => i.indexOf("/") === -1 ? i.concat("/", (isIPv4(i) ? "32" : "128")) : i) |     if (!this.__Wg._peers) this.__Wg._peers = new Map(); | ||||||
|       for (const IIP of fixed) writel(("allowed_ip="), (IIP)); |     this.__Wg._peers.get(this.publicKey)["removeMe"] = true; | ||||||
|     } |     return this; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   let payload = ""; |   /** | ||||||
|   client.once("data", function processBuff(buff) { |    * Converts the `WireGuard Peer` object to a JSON representation. | ||||||
|     payload = payload.concat(buff.toString("utf8")); |    * @returns The JSON representation of the `WireGuard Peer` object. | ||||||
|     if (payload[payload.length - 1] === "\n" && payload[payload.length - 2] === "\n") { |    */ | ||||||
|       client.end(); // Close conenction |   toJSON(): [string, SetPeer] { | ||||||
|       return; |     if (!this.__Wg._peers) this.__Wg._peers = new Map(); | ||||||
|     } |     const { keepInterval, endpoint, presharedKey, allowedIPs } = this.__Wg._peers.get(this.publicKey); | ||||||
|     client.once("data", processBuff); |     const peer: SetPeer = Object.create({}); | ||||||
|   }); |     if (presharedKey) peer.presharedKey = presharedKey; | ||||||
|   client.write("\n"); |     if (keepInterval) peer.keepInterval = keepInterval; | ||||||
|   await finished(client, { error: true }); |     if (endpoint) peer.endpoint = endpoint; | ||||||
|   const payloadKeys = payload.split("\n").filter(i => i.length > 3).map(line => { const iit = line.indexOf("="); return [ line.slice(0, iit), line.slice(iit+1) ]; }) |     if (allowedIPs) peer.allowedIPs = allowedIPs; | ||||||
|   if (payloadKeys.at(-1)[1] !== "0") { |     return [this.publicKey, peer]; | ||||||
|     const err = new Error("Invalid send config, check log"); |  | ||||||
|     throw err; |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Get wireguard interface config |  * Maneger Wireguard interface and peers simple and fast | ||||||
|  * @param wgName - Interface name |  | ||||||
|  * @returns |  | ||||||
|  */ |  */ | ||||||
| export async function getConfig(wgName: string): Promise<WgConfigGet> { | export class Wireguard { | ||||||
|   if (typeof addon.getConfig === "function") return addon.getConfig(wgName); |   constructor(config?: SetConfig | GetConfig | Config<Peer>) { | ||||||
|   const info = (await listDevices()).find(int => int.name === wgName); |     // super({}); | ||||||
|   if (!info) throw new Error("Create interface, not exists"); |     if (!config) return; | ||||||
|   const client = netConnection(path.join(defaultPath, wgName.concat(".sock"))); |     if (typeof config === "object") { | ||||||
|   const config: WgConfigGet = Object(); |       if (config instanceof Wireguard) return config; | ||||||
|   let latestPeer: string, previewKey: string; |  | ||||||
|  |  | ||||||
|   const tetrisBreak = readline.createInterface(client); |  | ||||||
|   tetrisBreak.on("line", function lineProcess(line) { |  | ||||||
|     if (line === "") tetrisBreak.removeListener("line", lineProcess).close(); |  | ||||||
|     const findout = line.indexOf("="), keyName = line.slice(0, findout), value = line.slice(findout+1); |  | ||||||
|     if (findout <= 0) return; |  | ||||||
|     if (keyName === "errno" && value !== "0") throw new Error(("wireguard-go error, code: ").concat(value)); |  | ||||||
|  |  | ||||||
|     // Drop |  | ||||||
|     if ((["last_handshake_time_nsec", "protocol_version", "errno"]).includes(keyName)) return; |  | ||||||
|     else if (keyName === "private_key") config.privateKey = Buffer.from(value, "hex").toString("base64"); |  | ||||||
|     else if (keyName === "listen_port") config.portListen = Number(value); |  | ||||||
|     else if (keyName === "endpoint") ((config.peers||(config.peers = {}))[latestPeer]).endpoint = value; |  | ||||||
|     else if (keyName === "persistent_keepalive_interval") ((config.peers||(config.peers = {}))[latestPeer]).keepInterval = Number(value); |  | ||||||
|     else if (keyName === "rx_bytes") ((config.peers||(config.peers = {}))[latestPeer]).rxBytes = Number(value); |  | ||||||
|     else if (keyName === "tx_bytes") ((config.peers||(config.peers = {}))[latestPeer]).txBytes = Number(value); |  | ||||||
|     else if (keyName === "last_handshake_time_sec") ((config.peers||(config.peers = {}))[latestPeer]).lastHandshake = new Date(Number(value) * 1000); |  | ||||||
|     else if (keyName === "allowed_ip") { |  | ||||||
|       if (!value) return; |  | ||||||
|       ((config.peers||(config.peers = {}))[latestPeer]).allowedIPs = (((config.peers||(config.peers = {}))[latestPeer]).allowedIPs||[]).concat(value); |  | ||||||
|     } else if (keyName === "preshared_key") { |  | ||||||
|       if (value === "0000000000000000000000000000000000000000000000000000000000000000") return; |  | ||||||
|       ((config.peers||(config.peers = {}))[latestPeer]).presharedKey = Buffer.from(value, "hex").toString("base64"); |  | ||||||
|     } else if (keyName === "public_key") { |  | ||||||
|       const keyDecode = Buffer.from(value, "hex").toString("base64"); |  | ||||||
|       if (previewKey !== "public_key") (config.peers||(config.peers = {}))[latestPeer] = {}; |  | ||||||
|       else { |  | ||||||
|         config.publicKey = latestPeer; |  | ||||||
|         (config.peers||(config.peers = {}))[keyDecode] = (config.peers||(config.peers = {}))[latestPeer]; |  | ||||||
|         delete (config.peers||(config.peers = {}))[latestPeer]; |  | ||||||
|         latestPeer = keyDecode; |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|     previewKey = keyName; |  | ||||||
|   }); |   private _name: string; | ||||||
|   client.write("get=1\n\n"); |   get name() { | ||||||
|   await new Promise((done, reject) => tetrisBreak.on("error", reject).once("close", done)); |     return this._name; | ||||||
|   await finished(client.end()); |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Set Wireguard interface name | ||||||
|  |    * @param name - Interface name | ||||||
|  |    * @returns Wireguard | ||||||
|  |    */ | ||||||
|  |   set name(name: string) { | ||||||
|  |     if (typeof name !== "string" || name.length === 0) throw new Error("Invalid name"); | ||||||
|  |     this._name = name; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private _portListen: number; | ||||||
|  |   /** | ||||||
|  |    * Sets the port to listen on. | ||||||
|  |    * @param port - The port number to listen on. | ||||||
|  |    * @returns The current instance of the `Wireguard` class. | ||||||
|  |    * @throws {Error} If the provided port is not a number or is less than 0. | ||||||
|  |    */ | ||||||
|  |   setPortListen(port: number) { | ||||||
|  |     if (typeof port !== "number" || port < 0) throw new Error("Invalid port"); | ||||||
|  |     this._portListen = port; | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private _fwmark: number; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Sets the fwmark value for the WireGuard interface. | ||||||
|  |    * | ||||||
|  |    * @param fwmark - The fwmark value to set. | ||||||
|  |    * @returns The current instance of the `Wireguard` class. | ||||||
|  |    * @throws {Error} If the `fwmark` value is not a number or is less than 0. | ||||||
|  |    */ | ||||||
|  |   setFwmark(fwmark: number) { | ||||||
|  |     if (typeof fwmark !== "number" || fwmark < 0) throw new Error("Invalid fwmark"); | ||||||
|  |     this._fwmark = fwmark; | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private _privateKey: string; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Get interface public key | ||||||
|  |    */ | ||||||
|  |   public get publicKey() { | ||||||
|  |     return key.publicKey(this._privateKey); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Generate new private key and set to Wireguard interface | ||||||
|  |    */ | ||||||
|  |   setPrivateKey(): Promise<this> & this; | ||||||
|  |   /** | ||||||
|  |    * Set private key to Wireguard interface | ||||||
|  |    * @param privateKey - Private key | ||||||
|  |    * @returns Wireguard | ||||||
|  |    */ | ||||||
|  |   setPrivateKey(privateKey: string): this; | ||||||
|  |   setPrivateKey(privateKey?: string): this { | ||||||
|  |     if (!privateKey) return Object.assign(key.privateKey().then((privateKey) => this._privateKey = privateKey), this); | ||||||
|  |     else this._privateKey = privateKey; | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private _address: string[]; | ||||||
|  |  | ||||||
|  |   addNewAddress(address: string) { | ||||||
|  |     if (isIP(address.split("/")[0]) === 0) throw new Error("Invalid IP address"); | ||||||
|  |     const _addr = new Set(this._address); | ||||||
|  |     _addr.add(address.split("/")[0]); | ||||||
|  |     this._address = Array.from(_addr); | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   removeAddress(address: string) { | ||||||
|  |     if (isIP(address.split("/")[0]) === 0) throw new Error("Invalid IP address"); | ||||||
|  |     const _addr = new Set(this._address); | ||||||
|  |     _addr.delete(address.split("/")[0]); | ||||||
|  |     this._address = Array.from(_addr); | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   _peers: Map<string, Peer>; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Adds a new peer to the Wireguard interface. | ||||||
|  |    * | ||||||
|  |    * @param publicKey - The public key of the peer. | ||||||
|  |    * @param peer - other configuration options for the peer. | ||||||
|  |    * @throws Error if the peer is invalid. | ||||||
|  |    */ | ||||||
|  |   addNewPeer(publicKey: string, peer: Peer) { | ||||||
|  |     if (!this._peers) this._peers = new Map(); | ||||||
|  |     if (!((typeof publicKey === "string" && publicKey.length === key.Base64Length) && typeof peer === "object")) throw new Error("Invalid peer"); | ||||||
|  |     let { allowedIPs, endpoint, keepInterval, presharedKey } = peer; | ||||||
|  |     this._peers.set(publicKey, {}); | ||||||
|  |     if ((typeof presharedKey === "string" && presharedKey.length === key.Base64Length)) this._peers.get(publicKey).presharedKey = presharedKey; | ||||||
|  |     if (typeof keepInterval === "number") this._peers.get(publicKey).keepInterval = keepInterval; | ||||||
|  |     if (typeof endpoint === "string") this._peers.get(publicKey).endpoint = endpoint; | ||||||
|  |     if (Array.isArray(allowedIPs)) this._peers.get(publicKey).allowedIPs = allowedIPs.filter((ip) => isIP(ip.split("/")[0]) !== 0); | ||||||
|  |     return new WireGuardPeer(publicKey, this); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Removes a peer from the WireGuard interface. | ||||||
|  |    * @param publicKey - The public key of the peer to remove. | ||||||
|  |    * @returns The updated WireGuard interface. | ||||||
|  |    */ | ||||||
|  |   removePeer(publicKey: string) { | ||||||
|  |     if (this._peers) this._peers.delete(publicKey); | ||||||
|  |     return this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Converts the `Wireguard Interface` object to a JSON representation. | ||||||
|  |    * @returns The JSON representation of the `Wireguard Interface` object. | ||||||
|  |    */ | ||||||
|  |   toJSON(): SetConfig { | ||||||
|  |     const config: SetConfig = Object.create({}); | ||||||
|  |     config.name = this._name; | ||||||
|  |     config.privateKey = this._privateKey; | ||||||
|  |     if (this._portListen) config.portListen = this._portListen; | ||||||
|  |     if (this._fwmark) config.fwmark = this._fwmark; | ||||||
|  |     if (this._address) config.address = this._address; | ||||||
|  |     if (this._peers) config.peers = Array.from(this._peers||[]).map(([pubKey]) => new WireGuardPeer(pubKey, this).toJSON()).reduce((obj, [pubKey, peer]) => (obj[pubKey] = peer, obj), {}); | ||||||
|     return config; |     return config; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Set new config to Wireguard interface or create new interface if not exists | ||||||
|  |    * @returns Promise<void> | ||||||
|  |    */ | ||||||
|  |   async deploy() { | ||||||
|  |     return setConfig({ | ||||||
|  |       ...(this.toJSON()), | ||||||
|  |       replacePeers: true, | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Deletes the WireGuard interface. | ||||||
|  |    * @returns A promise that resolves when the interface is successfully deleted. | ||||||
|  |    */ | ||||||
|  |   async delete() { | ||||||
|  |     return deleteInterface(this._name); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Retrieves the configuration for the Wireguard interface. | ||||||
|  |    */ | ||||||
|  |   async getConfig() { | ||||||
|  |     const { peers, privateKey, address, fwmark, portListen } = await getConfig(this._name); | ||||||
|  |     this._privateKey = privateKey; | ||||||
|  |     this._portListen = portListen; | ||||||
|  |     this._address = address; | ||||||
|  |     this._fwmark = fwmark; | ||||||
|  |  | ||||||
|  |     this._peers = new Map(Object.entries(peers)); | ||||||
|  |     for (const [publicKey, { allowedIPs, endpoint, keepInterval, presharedKey }] of this._peers) { | ||||||
|  |       this._peers.set(publicKey, { allowedIPs, endpoint, keepInterval, presharedKey }); | ||||||
|  |       if (keepInterval === 0) delete this._peers.get(publicKey).keepInterval; | ||||||
|  |       if (!presharedKey) delete this._peers.get(publicKey).presharedKey; | ||||||
|  |       if (!endpoint) delete this._peers.get(publicKey).endpoint; | ||||||
|  |       if (!allowedIPs) delete this._peers.get(publicKey).allowedIPs; | ||||||
|  |       else if (allowedIPs.length === 0) delete this._peers.get(publicKey).allowedIPs; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | export default Wireguard; | ||||||
| @@ -1,54 +1,51 @@ | |||||||
| import test from "node:test"; | import test from "node:test"; | ||||||
| import { setConfig, deleteInterface, WgConfigSet, getConfig } from "./wginterface.js"; | import { Wireguard, getConfig, setConfig } from "./wginterface.js"; | ||||||
| import { publicKey } from "./key.js"; | import { presharedKey, privateKey, publicKey } from "./key.js"; | ||||||
| import { userInfo } from "os"; | import assert from "node:assert"; | ||||||
|  |  | ||||||
| if (process.platform === "win32" || process.platform === "linux" && (userInfo().uid === 0)) { | await test("Wireguard interface", async t => { | ||||||
|   test("Wireguard configuration", async t => { |   const config = new Wireguard; | ||||||
|     // Config base |   config.name = "wg23"; | ||||||
|     const peer1Key = 'EKgSatFzZtsv1qFJ6gE8HqfuA+tXzW+7vDeVc7Xaa2E=', peer2Key = '4BSvgiM9j5jjuR0Vg3gbqTFD5+CyuOU2K2kJE5+cakQ=', |   if (process.platform === "darwin") config.name = "utun23"; | ||||||
|     config: WgConfigSet = { |  | ||||||
|       privateKey: "4GTKsUfzodunTXaHtY/u+JhQN1D2CP1Sc+4D1VmpylY=", |  | ||||||
|       address: [ |  | ||||||
|         "10.66.124.1/32" |  | ||||||
|       ], |  | ||||||
|       peers: {} |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     config.peers[publicKey(peer1Key)] = { |   config.setPrivateKey(await privateKey()); | ||||||
|  |   config.addNewAddress("10.66.66.1/32"); | ||||||
|  |   config.addNewAddress("fd42:42:42::1/128"); | ||||||
|  |  | ||||||
|  |   const peer1 = await privateKey(); | ||||||
|  |   config.addNewPeer(publicKey(peer1), { | ||||||
|  |     keepInterval: 15, | ||||||
|  |     presharedKey: await presharedKey(), | ||||||
|     allowedIPs: [ |     allowedIPs: [ | ||||||
|         "10.66.124.2" |       "10.66.66.2/32" | ||||||
|     ] |     ] | ||||||
|     } |  | ||||||
|  |  | ||||||
|     await t.test("Set config in interface", async () => { |  | ||||||
|       await setConfig("wg23", config); |  | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|     await t.test("Get config in interface", async () => { |   const peer2 = await privateKey(); | ||||||
|       const __config = await getConfig("wg23"); |   config.addNewPeer(publicKey(peer2), { | ||||||
|       if (!__config.peers[publicKey(peer1Key)]) throw new Error("Not exist peer 1!"); |     keepInterval: 0, | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     config.peers[publicKey(peer1Key)].removeMe = true; |  | ||||||
|     config.peers[publicKey(peer2Key)] = { |  | ||||||
|     allowedIPs: [ |     allowedIPs: [ | ||||||
|         "10.66.124.3" |       "10.66.66.3/32" | ||||||
|     ] |     ] | ||||||
|     } |  | ||||||
|  |  | ||||||
|     await t.test("Set config in interface", async () => { |  | ||||||
|       await setConfig("wg23", config); |  | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|     await t.test("Get config in interface", async () => { |   const jsonConfig = config.toJSON(); | ||||||
|       const __config = await getConfig("wg23"); |  | ||||||
|       if (__config.peers[publicKey(peer1Key)]) throw new Error("Invalid config get!"); |   let skip: string; | ||||||
|       if (!__config.peers[publicKey(peer2Key)]) throw new Error("Not exist peer 2!"); |   await t.test("Create and Set config in interface", async () => setConfig(jsonConfig).catch(err => { skip = "Cannot set wireguard config"; return Promise.reject(err); })); | ||||||
|  |   await t.test("Get config from interface", { skip }, async () => { | ||||||
|  |     const config = await getConfig(jsonConfig.name); | ||||||
|  |     // console.dir(config, { depth: null }); | ||||||
|  |  | ||||||
|  |     if (!config.peers[publicKey(peer1)]) throw new Error("Peer not exists in interface"); | ||||||
|  |     if (!config.peers[publicKey(peer2)]) throw new Error("Peer not exists in interface"); | ||||||
|  |  | ||||||
|  |     assert.equal(config.peers[publicKey(peer1)].keepInterval, jsonConfig.peers[publicKey(peer1)].keepInterval); | ||||||
|  |     assert.equal(config.peers[publicKey(peer1)].presharedKey, jsonConfig.peers[publicKey(peer1)].presharedKey); | ||||||
|  |  | ||||||
|  |     assert.deepEqual(config.peers[publicKey(peer1)].allowedIPs, jsonConfig.peers[publicKey(peer1)].allowedIPs); | ||||||
|  |     assert.deepEqual(config.peers[publicKey(peer2)].allowedIPs, jsonConfig.peers[publicKey(peer2)].allowedIPs); | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|     await t.test("Delete interface", async () => { |   await t.test("Delete interface if exists", { skip }, async () => config.delete()); | ||||||
|       await deleteInterface("wg23"); | }); | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
		Reference in New Issue
	
	Block a user