Droping rebory and migrate to cmake-js #14
@ -10,10 +10,11 @@ src/**/*_test.*
|
||||
src/**/*.ts
|
||||
!src/**/*.d.ts
|
||||
|
||||
# vscode
|
||||
# IDEs
|
||||
.devcontainer/
|
||||
.vscode/
|
||||
.vscode-ctags
|
||||
.vscode/
|
||||
.zed/
|
||||
|
||||
# Github and Git
|
||||
.github/
|
||||
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -116,6 +116,8 @@
|
||||
"xtr1common": "cpp",
|
||||
"xtree": "cpp",
|
||||
"xutility": "cpp",
|
||||
"fstream": "cpp"
|
||||
"fstream": "cpp",
|
||||
"deque": "cpp",
|
||||
"stack": "cpp"
|
||||
}
|
||||
}
|
38
.zed/settings.json
Normal file
38
.zed/settings.json
Normal file
@ -0,0 +1,38 @@
|
||||
// Folder-specific settings
|
||||
//
|
||||
// For a full list of overridable settings, and general information on folder-specific settings,
|
||||
// see the documentation: https://zed.dev/docs/configuring-zed#folder-specific-settings
|
||||
{
|
||||
"remove_trailing_whitespace_on_save": true,
|
||||
"ensure_final_newline_on_save": true,
|
||||
"formatter": "auto",
|
||||
"format_on_save": "off",
|
||||
"tab_size": 2,
|
||||
"languages": {
|
||||
"TypeScript": {
|
||||
"hard_tabs": false
|
||||
"format_on_save": true,
|
||||
"code_actions_on_format": {
|
||||
"source.organizeImports": true,
|
||||
"source.removeUnusedImports": true
|
||||
}
|
||||
},
|
||||
"JavaScript": {
|
||||
"hard_tabs": false
|
||||
"format_on_save": true,
|
||||
"code_actions_on_format": {
|
||||
"source.organizeImports": true,
|
||||
"source.removeUnusedImports": true
|
||||
}
|
||||
},
|
||||
"Go": {
|
||||
"format_on_save": true
|
||||
},
|
||||
"C++": {
|
||||
"hard_tabs": false
|
||||
},
|
||||
"C": {
|
||||
"hard_tabs": false
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
#include "wgkeys.hh"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __linux__
|
||||
@ -263,7 +265,7 @@ void wgKeys::generatePublic(wg_key public_key, const wg_key private_key) {
|
||||
memzero_explicit(f, sizeof(f));
|
||||
}
|
||||
|
||||
std::string wgKeys::generatePublic(const std::string private_key) {
|
||||
std::string wgKeys::generatePublic(const std::string &private_key) {
|
||||
wg_key public_key;
|
||||
wg_key private_key_;
|
||||
stringToKey(private_key_, private_key);
|
||||
@ -282,7 +284,7 @@ bool key_is_zero(const uint8_t key[32]) {
|
||||
}
|
||||
|
||||
void wgKeys::stringToKey(wg_key key, std::string keyBase64) {
|
||||
auto base64 = keyBase64.c_str();
|
||||
const char* base64 = keyBase64.c_str();
|
||||
if (keyBase64.length() != B64_WG_KEY_LENGTH ||
|
||||
base64[B64_WG_KEY_LENGTH - 1] != '=')
|
||||
throw std::string("invalid key, length: ")
|
||||
@ -315,8 +317,7 @@ std::string wgKeys::toString(const wg_key key) {
|
||||
wg_key_b64_string base64;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 32 / 3; ++i)
|
||||
encode_base64(&base64[i * 4], &key[i * 3]);
|
||||
for (i = 0; i < 32 / 3; ++i) encode_base64(&base64[i * 4], &key[i * 3]);
|
||||
const uint8_t tempKey[3] = {key[i * 3 + 0], key[i * 3 + 1], 0};
|
||||
encode_base64(&base64[i * 4], tempKey);
|
||||
base64[sizeof(wg_key_b64_string) - 2] = '=';
|
||||
@ -325,7 +326,7 @@ std::string wgKeys::toString(const wg_key key) {
|
||||
return std::string(base64);
|
||||
}
|
||||
|
||||
std::string wgKeys::toHex(const std::string keyBase64) {
|
||||
std::string wgKeys::toHex(const std::string &keyBase64) {
|
||||
wg_key key;
|
||||
wgKeys::stringToKey(key, keyBase64);
|
||||
char hex[65];
|
||||
@ -334,8 +335,11 @@ std::string wgKeys::toHex(const std::string keyBase64) {
|
||||
return std::string(hex);
|
||||
}
|
||||
|
||||
std::string wgKeys::HextoBase64(const std::string keyHex) {
|
||||
std::string wgKeys::HextoBase64(const std::string &s_hex) {
|
||||
wg_key key;
|
||||
for (int i = 0; i < 32; ++i) sscanf(keyHex.c_str() + i * 2, "%02x", &key[i]);
|
||||
for(unsigned i = 0, uchr ; i < s_hex.length() ; i += 2) {
|
||||
sscanf( s_hex.c_str()+ i, "%2x", &uchr); // conversion
|
||||
key[i/2] = uchr; // save as char
|
||||
}
|
||||
return wgKeys::toString(key);
|
||||
}
|
@ -14,10 +14,10 @@ namespace wgKeys {
|
||||
std::string toString(const wg_key key);
|
||||
|
||||
// Convert base64 to hex key
|
||||
std::string toHex(const std::string keyBase64);
|
||||
std::string toHex(const std::string &keyBase64);
|
||||
|
||||
// Convert hex to base64
|
||||
std::string HextoBase64(const std::string keyHex);
|
||||
std::string HextoBase64(const std::string &keyHex);
|
||||
|
||||
// Convert base64 to wg_key
|
||||
void stringToKey(wg_key key, std::string keyBase64);
|
||||
@ -31,7 +31,7 @@ namespace wgKeys {
|
||||
// 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);
|
||||
std::string generatePublic(const std::string &private_key);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,15 +1,9 @@
|
||||
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/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||
|
@ -4,49 +4,24 @@ import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"syscall"
|
||||
_ "unsafe"
|
||||
|
||||
"golang.zx2c4.com/wireguard/conn"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/ipc"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
|
||||
const levelLog = device.LogLevelError
|
||||
|
||||
//go:linkname socketDirectory golang.xz2c4.com/wireguard/ipc.socketDirectory
|
||||
var socketDirectory = "/var/run/wireguard"
|
||||
|
||||
func init() {
|
||||
if runtime.GOOS == "windows" {
|
||||
socketDirectory = `\\.\pipe\ProtectedPrefix\Administrators\WireGuard`
|
||||
}
|
||||
}
|
||||
|
||||
// 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()
|
||||
}()
|
||||
|
||||
// Default log level to print in terminal
|
||||
const levelLog = device.LogLevelSilent
|
||||
|
||||
func getCharErr(err error) *C.char {
|
||||
if err == nil {
|
||||
return C.CString("")
|
||||
}
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
|
||||
// Get wireguard-go version
|
||||
@ -65,158 +40,68 @@ func wgVersion() *C.char {
|
||||
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("")
|
||||
}
|
||||
// End process function callbacks
|
||||
var Tuns = make(map[string]tun.Device)
|
||||
var Devices = make(map[string]*device.Device)
|
||||
|
||||
// List wireguard-go UAPI's sockets
|
||||
// first\0second\0third\0forth\0last\0\0
|
||||
//
|
||||
//export listUapis
|
||||
func listUapis() *C.char {
|
||||
Files, err := os.ReadDir(socketDirectory)
|
||||
if err != nil {
|
||||
return C.CString("")
|
||||
}
|
||||
//export listInternalTuns
|
||||
func listInternalTuns() *C.char {
|
||||
var uapis []string
|
||||
for _, file := range Files {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
uapis = append(uapis, strings.Join(([]string{socketDirectory, file.Name()}), "/"))
|
||||
for tun := range Tuns {
|
||||
uapis = append(uapis, tun)
|
||||
}
|
||||
return C.CString(strings.Join(uapis, "\x00") + "\x00")
|
||||
}
|
||||
|
||||
// Delete interface
|
||||
//
|
||||
//export stopWg
|
||||
func stopWg(wgName *C.char) (bool, *C.char) {
|
||||
tunName := C.GoString(wgName)
|
||||
if dev, ok := Devices[tunName]; ok {
|
||||
dev.Close()
|
||||
if tun, ok := Tuns[tunName]; ok {
|
||||
if err := tun.Close(); err != nil {
|
||||
return false, getCharErr(err)
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Set config in tun, if not exist create and add to Tuns
|
||||
//
|
||||
//export setWg
|
||||
func setWg(wgName, wgConfig *C.char) *C.char {
|
||||
tunName, configString := C.GoString(wgName), C.GoString(wgConfig)
|
||||
_, okTuns := Tuns[tunName]
|
||||
_, okDev := Devices[tunName]
|
||||
if !(okTuns || okDev) {
|
||||
logger := device.NewLogger(levelLog, fmt.Sprintf("(%s) ", tunName))
|
||||
// open TUN device (or use supplied fd)
|
||||
tdev, err := tun.CreateTUN(tunName, device.DefaultMTU)
|
||||
Tuns[tunName] = tdev
|
||||
if err != nil {
|
||||
return getCharErr(err)
|
||||
}
|
||||
Devices[tunName] = device.NewDevice(tdev, conn.NewDefaultBind(), logger)
|
||||
}
|
||||
dev := Devices[tunName]
|
||||
return getCharErr(dev.IpcSet(configString))
|
||||
}
|
||||
|
||||
// Get config from Tuns device
|
||||
//
|
||||
//export getWg
|
||||
func getWg(wgName *C.char) (*C.char, *C.char) {
|
||||
tunName := C.GoString(wgName)
|
||||
if dev, ok := Devices[tunName]; ok {
|
||||
config, err := dev.IpcGet()
|
||||
return C.CString(config), getCharErr(err)
|
||||
}
|
||||
return nil, getCharErr(fmt.Errorf("device not exists"))
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
#include "wginterface.hh"
|
||||
#include "userspace/wg-go.h"
|
||||
#include "userspace/ipc.cpp"
|
||||
#include "genKey/wgkeys.hh"
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <vector>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
@ -16,161 +19,134 @@
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
void IpManeger::SetInInterface(std::string interfaceName) {}
|
||||
void IpManeger::GetInInterface(std::string interfaceName) {}
|
||||
|
||||
// Ignore if required to windows
|
||||
std::string driveLoad(std::map<std::string, std::string> load) {}
|
||||
std::string driveLoad(std::map<std::string, std::string> load) { return ""; }
|
||||
|
||||
std::string getWireguardVersion() {
|
||||
return std::string(wgVersion());
|
||||
}
|
||||
|
||||
void WireguardDevices::getInterfaces() {
|
||||
size_t len; char *device_name, *devicesList = listUapis();
|
||||
size_t len; char *device_name, *devicesList = listInternalTuns();
|
||||
for (device_name = devicesList, len = 0; (len = strlen(device_name)); device_name += len + 1) this->push_back(std::string(device_name));
|
||||
}
|
||||
|
||||
void WireguardDevices::deleteInterface(std::string wgName) {
|
||||
std::string deleteStatus = deleteTun((char*)wgName.c_str());
|
||||
if (!deleteStatus.empty()) throw deleteStatus;
|
||||
auto status = stopWg((char*)wgName.c_str());
|
||||
if (!!status.r1) throw std::string(status.r1);
|
||||
}
|
||||
|
||||
bool char_is_digit(int c) {
|
||||
return (unsigned int)(('0' - 1 - c) & (c - ('9' + 1))) >> (sizeof(c) * 8 - 1);
|
||||
}
|
||||
|
||||
void WireguardConfig::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;
|
||||
}
|
||||
std::string userspaceConfig;
|
||||
|
||||
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");
|
||||
if (this->privateKey.length() == Base64WgKeyLength) userspaceConfig = userspaceConfig.append("private_key=").append(wgKeys::toHex(this->privateKey)).append("\n");
|
||||
if (this->portListen >= 0) userspaceConfig = userspaceConfig.append("listen_port=").append(std::to_string(this->portListen)).append("\n");
|
||||
if (this->fwmark >= 0) userspaceConfig = userspaceConfig.append("fwmark=").append(std::to_string(this->fwmark)).append("\n");
|
||||
if (this->replacePeers) userspaceConfig = userspaceConfig.append("replace_peers=true\n");
|
||||
|
||||
for (auto peer : this->Peers) {
|
||||
fprintf(f, "public_key=%s\n", wgKeys::toHex(peer.first).c_str());
|
||||
if (peer.second.removeMe) {
|
||||
fprintf(f, "remove=true\n");
|
||||
continue;
|
||||
userspaceConfig = userspaceConfig.append("public_key=").append(wgKeys::toHex(peer.first)).append("\n");
|
||||
auto config = peer.second;
|
||||
if (config.removeMe) {
|
||||
userspaceConfig = userspaceConfig.append("remove=true\n");
|
||||
continue;
|
||||
}
|
||||
if (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);
|
||||
if (config.presharedKey.length() == Base64WgKeyLength) userspaceConfig = userspaceConfig.append("preshared_key=").append(wgKeys::toHex(config.presharedKey)).append("\n");
|
||||
if (config.keepInterval > 0) userspaceConfig = userspaceConfig.append("persistent_keepalive_interval=").append(std::to_string(config.keepInterval)).append("\n");
|
||||
if (config.endpoint.length() > 0) userspaceConfig = userspaceConfig.append("endpoint=").append(config.endpoint).append("\n");
|
||||
if (config.allowedIPs.size() > 0) {
|
||||
userspaceConfig = userspaceConfig.append("replace_allowed_ips=true\n");
|
||||
for (auto s : config.allowedIPs.getIpParsed()) userspaceConfig = userspaceConfig.append("allowed_ip=").append(s.Address).append("/").append(std::to_string(s.Mask)).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
std::string err = setWg((char*)this->name.c_str(), (char*)userspaceConfig.append("\n").c_str());
|
||||
if (!err.empty()) throw err;
|
||||
}
|
||||
|
||||
void IpManeger::SetInInterface(std::string interfaceName) {}
|
||||
void IpManeger::GetInInterface(std::string interfaceName) {}
|
||||
std::vector<std::string> splitLines(const std::string& str) {
|
||||
std::vector<std::string> result;
|
||||
std::stringstream ss(str);
|
||||
std::string line;
|
||||
// Loop until the end of the string
|
||||
while (std::getline(ss, line)) {
|
||||
if (!line.empty()) {
|
||||
result.push_back(line);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void WireguardConfig::getWireguardConfig() {
|
||||
auto status = getWg((char*)this->name.c_str());
|
||||
if (strlen(status.r1) > 0) throw std::string(status.r1, strlen(status.r1));
|
||||
std::string wgConfig(status.r0, strlen(status.r0));
|
||||
std::string pubKey;
|
||||
int ret = 0;
|
||||
for (auto line : splitLines(wgConfig)) {
|
||||
std::string key(line.substr(0, line.find("="))), value(line.substr(line.find("=")+1));
|
||||
if (key == "private_key") {
|
||||
this->privateKey = wgKeys::HextoBase64(value);
|
||||
} else if (key == "listen_port") {
|
||||
this->portListen = (unsigned short)std::strtoul(value.c_str(), NULL, 0);
|
||||
} else if (key == "public_key") {
|
||||
// Insert to peer key
|
||||
pubKey = wgKeys::HextoBase64(value);
|
||||
this->Peers[pubKey] = Peer{};
|
||||
} else if (key == "preshared_key" && pubKey.length() > 0) {
|
||||
this->Peers[pubKey].presharedKey = wgKeys::HextoBase64(value);
|
||||
} else if (key == "allowed_ip" && pubKey.length() > 0) {
|
||||
this->Peers[pubKey].allowedIPs.push_back(value);
|
||||
} else if (key == "persistent_keepalive_interval" && pubKey.length() > 0) {
|
||||
this->Peers[pubKey].keepInterval = std::stoi(value);
|
||||
} else if (key == "last_handshake_time_sec" && pubKey.length() > 0) {
|
||||
} else if (key == "last_handshake_time_nsec" && pubKey.length() > 0) {
|
||||
this->Peers[pubKey].lastHandshake = ({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = std::strtoull(value.c_str(), &end, 10); if (*end || num > 0x7fffffffffffffffULL) break; num; });
|
||||
} else if (key == "rx_bytes" && pubKey.length() > 0) {
|
||||
this->Peers[pubKey].rxBytes = std::stoull(value);
|
||||
} else if (key == "tx_bytes" && pubKey.length() > 0) {
|
||||
this->Peers[pubKey].txBytes = std::stoull(value);
|
||||
} else if (key == "endpoint" && pubKey.length() > 0) {
|
||||
char *cvalue = strdup(value.c_str());
|
||||
char *begin, *end;
|
||||
struct addrinfo *resolved;
|
||||
struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_DGRAM, .ai_protocol = IPPROTO_UDP };
|
||||
if (!value.length()) break;
|
||||
if (value[0] == '[') {
|
||||
begin = &value[1];
|
||||
end = strchr(cvalue, ']');
|
||||
if (!end) break;
|
||||
*end++ = '\0';
|
||||
if (*end++ != ':' || !*end) break;
|
||||
} else {
|
||||
begin = cvalue;
|
||||
end = strrchr(cvalue, ':');
|
||||
if (!end || !*(end + 1)) break;
|
||||
*end++ = '\0';
|
||||
}
|
||||
if (getaddrinfo(begin, end, &hints, &resolved) != 0) {
|
||||
ret = ENETUNREACH;
|
||||
throw std::string("Failed to resolve endpoint");
|
||||
}
|
||||
if ((resolved->ai_family == AF_INET && resolved->ai_addrlen == sizeof(struct sockaddr_in)) || (resolved->ai_family == AF_INET6 && resolved->ai_addrlen == sizeof(struct sockaddr_in6))) this->Peers[pubKey].endpoint = value;
|
||||
else {
|
||||
freeaddrinfo(resolved);
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(resolved);
|
||||
} else if (key == "errno") {
|
||||
ret = -({ unsigned long long num; char *end; if (!char_is_digit(value[0])) break; num = std::strtoull(value.c_str(), &end, 10); if (*end || num > 0x7fffffffU) break; num; });
|
||||
break;
|
||||
} else if (key == "protocol_version") {
|
||||
}
|
||||
}
|
||||
if (ret < 0) throw std::string("Failed to get wireguard config");
|
||||
}
|
||||
|
3
compile_flags.txt
Normal file
3
compile_flags.txt
Normal file
@ -0,0 +1,3 @@
|
||||
-Iaddon/
|
||||
-Iaddon/genKey
|
||||
-std=c++17
|
@ -1,8 +1,8 @@
|
||||
import test from "node:test"
|
||||
import { Config, setConfig, getConfig, deleteInterface } from "./wginterface.js"
|
||||
import { privateKey, publicKey, presharedKey } from "./key.js"
|
||||
import { format } from "node:util";
|
||||
import assert from "node:assert";
|
||||
import test from "node:test";
|
||||
import { format } from "node:util";
|
||||
import { presharedKey, privateKey, publicKey } from "./key.js";
|
||||
import { Config, deleteInterface, getConfig, setConfig } from "./wginterface.js";
|
||||
|
||||
await test("Wireguard interface", async t => {
|
||||
const newConfig: Config = {
|
||||
@ -19,21 +19,27 @@ await test("Wireguard interface", async t => {
|
||||
presharedKey: await presharedKey(),
|
||||
keepInterval: 25,
|
||||
allowedIPs: [
|
||||
format("10.66.66.%d/24", i+2)
|
||||
format("10.66.66.%d/32", i+2)
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
function checkExists<T extends any[]>(arg0: T, arg1: T) {
|
||||
for (const a1 of arg0) {
|
||||
if (!Array.from(arg1).includes(a1)) throw new Error(format("%O not includes in %O", a1, arg1))
|
||||
}
|
||||
}
|
||||
|
||||
await t.test("Set config", async () => setConfig(newConfig));
|
||||
await t.test("Get config and check", async () => {
|
||||
const currentConfig = await getConfig(newConfig.name)
|
||||
assert.equal(currentConfig.privateKey, newConfig.privateKey)
|
||||
for (const pubKey in newConfig.peers) {
|
||||
console.log("Current: %O\nIn set: %O", currentConfig.peers[pubKey], newConfig.peers[pubKey])
|
||||
if (!currentConfig.peers[pubKey]) throw new Error("one peer not exists in currentConfig")
|
||||
else if (currentConfig.peers[pubKey].presharedKey != newConfig.peers[pubKey].presharedKey) throw new Error("presharedKey is mismatch")
|
||||
else if (currentConfig.peers[pubKey].keepInterval != newConfig.peers[pubKey].keepInterval) throw new Error("keepInterval is mismatch")
|
||||
else if (currentConfig.peers[pubKey].presharedKey != newConfig.peers[pubKey].presharedKey) throw new Error("presharedKey is mismatch");
|
||||
else if (currentConfig.peers[pubKey].keepInterval != newConfig.peers[pubKey].keepInterval) throw new Error("keepInterval is mismatch");
|
||||
checkExists(newConfig.peers[pubKey].allowedIPs, currentConfig.peers[pubKey].allowedIPs);
|
||||
}
|
||||
});
|
||||
await t.test("Deleting interface", async () => deleteInterface(newConfig.name));
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user