[CI SKIP] Added kotlin 😢
Some checks failed
TVPN Actions Workflow / build (push) Has been cancelled

This commit is contained in:
Steven Tracey 2024-10-28 18:15:23 -04:00
parent d5e1142bce
commit dd8970758a
29 changed files with 557 additions and 236 deletions

View File

@ -16,5 +16,10 @@
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="Gitea" />
<option name="name" value="Gitea" />
<option name="url" value="https://git.nevets.tech/api/packages/Steven/maven" />
</remote-repository>
</component>
</project>

6
.idea/kotlinc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.21" />
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/TVPN.main.iml" filepath="$PROJECT_DIR$/.idea/modules/TVPN.main.iml" />
</modules>
</component>
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$/../../src/main" dumb="true">
<sourceFolder url="file://$MODULE_DIR$/../../src/main/kotlin" isTestSource="false" />
</content>
</component>
</module>

3
build-dll.bat Normal file
View File

@ -0,0 +1,3 @@
@echo off
cmake -DCMAKE_BUILD_TYPE=Release -G "CodeBlocks - MinGW Makefiles" -S .\src\main\cpp -B .\src\main\cpp\build
cmake --build .\src\main\cpp\build --target wireguard_wrapper -- -j 14

55
build.gradle.kts Normal file
View File

@ -0,0 +1,55 @@
plugins {
java
kotlin("jvm") version "1.9.21"
id("com.github.johnrengelman.shadow") version "8.1.1"
id("edu.sc.seis.launch4j") version "3.0.6"
}
group = "tech.nevets"
version = "0.3.1"
repositories {
mavenCentral()
maven {
url = uri("https://git.nevets.tech/api/packages/Steven/maven")
}
}
dependencies {
implementation("com.miglayout:miglayout-swing:11.4.2")
implementation("com.miglayout:miglayout-core:11.4.2")
implementation("com.formdev:flatlaf:3.5.1")
implementation("com.google.code.gson:gson:2.11.0")
implementation("tech.nevets:JConf:0.1.0:no-deps")
}
kotlin {
jvmToolchain(21)
}
//tasks.withType(JavaCompile).configureEach {
// options.encoding = "UTF-8"
//}
tasks.jar {
manifest {
attributes["Main-Class"] = "tech.nevets.tvpn.Main"
}
configurations["compileClasspath"].forEach { file: File ->
from(zipTree(file.absoluteFile))
}
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}
launch4j {
mainClassName.set("tech.nevets.tvpn.Main")
outfile.set("TVPN.exe")
setJarTask(project.tasks["shadowJar"])
fileDescription.set("TVPN Client")
icon.set("$projectDir/src/main/resources/icon.ico")
productName.set("TVPN")
version.set("$this.version")
textVersion.set("$this.version")
bundledJrePath.set("./jre")
manifest.set("$projectDir/TVPN.exe.manifest")
}

View File

@ -1,2 +1,2 @@
org.gradle.jvmargs=-Xmx8192M
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx8192M -Dfile.encoding=UTF-8
org.gradle.parallel=true

View File

@ -1,2 +0,0 @@
rootProject.name = 'TVPN'

1
settings.gradle.kts Normal file
View File

@ -0,0 +1 @@
rootProject.name = "TVPN"

View File

@ -15,9 +15,11 @@ set(JNI_INCLUDE_DIR2 "${JAVA_HOME}/include/win32")
include_directories(${JNI_INCLUDE_DIR} ${JNI_INCLUDE_DIR2})
# Add the source file that includes your JNI C wrapper code
add_library(wireguard_wrapper SHARED wireguard_wrapper.c)
add_library(wireguard_wrapper SHARED wireguard_wrapper.c
example.c)
target_link_libraries(wireguard_wrapper PRIVATE Rpcrt4)
#target_link_libraries(wireguard_wrapper PRIVATE Rpcrt4)
target_link_libraries(wireguard_wrapper ws2_32 rpcrt4)
# Optionally, you can specify output directory for the compiled library
set_target_properties(wireguard_wrapper PROPERTIES

4
src/main/cpp/build.ps1 Normal file
View File

@ -0,0 +1,4 @@
Get-ChildItem -Path build -Recurse | Remove-Item -force -recurse
if (Test-Path -Path .\build) { Remove-Item -Path .\build -Recurse -Force }
cmake -DCMAKE_BUILD_TYPE=Release -G "CodeBlocks - MinGW Makefiles" -S . -B .\build
cmake --build .\build --target wireguard_wrapper -- -j 14

View File

@ -276,10 +276,19 @@ int __cdecl main(void)
WIREGUARD_INTERFACE Interface;
WIREGUARD_PEER DemoServer;
WIREGUARD_ALLOWED_IP AllV4;
} Config = { .Interface = { .Flags = WIREGUARD_INTERFACE_HAS_PRIVATE_KEY, .PeersCount = 1 },
.DemoServer = { .Flags = WIREGUARD_PEER_HAS_PUBLIC_KEY | WIREGUARD_PEER_HAS_ENDPOINT,
.AllowedIPsCount = 1 },
.AllV4 = { .AddressFamily = AF_INET } };
} Config = {
.Interface = {
.Flags = WIREGUARD_INTERFACE_HAS_PRIVATE_KEY,
.PeersCount = 1
},
.DemoServer = {
.Flags = WIREGUARD_PEER_HAS_PUBLIC_KEY | WIREGUARD_PEER_HAS_ENDPOINT,
.AllowedIPsCount = 1
},
.AllV4 = {
.AddressFamily = AF_INET
}
};
Log(WIREGUARD_LOG_INFO, L"Generating keypair");
BYTE PublicKey[WIREGUARD_KEY_LENGTH];

View File

@ -1,17 +1,23 @@
#include <jni.h>
#include <rpc.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <winsock2.h>
#include <windows.h>
#include "wireguard.h"
#include <string.h>
#include <ws2tcpip.h>
#include "tech_nevets_tvpn_wg_WireGuardJNI.h"
#pragma comment(lib, "Rpcrt4.lib")
const wchar_t *APP_DIR = L"C:\\Program Files\\TVPN\\";
typedef struct {
WIREGUARD_INTERFACE Interface;
WIREGUARD_PEER Peer;
WIREGUARD_ALLOWED_IP AllowedIP;
} Config;
static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter;
static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter;
static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter;
@ -26,12 +32,12 @@ static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration;
static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration;
static HMODULE InitializeWireGuardNT(void) {
HMODULE WireGuardDll = LoadLibraryExW(
L"wireguard.dll",
NULL,
LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32
);
if (!WireGuardDll) return NULL;
printf("[C] Starting InitializeWireGuardNT!\n");
HMODULE WireGuardDll = LoadLibraryW(L"wireguard.dll");
if (!WireGuardDll) {
printf("[C] Error loading wireguard.dll\n");
return NULL;
}
#define X(Name) ((*(FARPROC *)&Name = GetProcAddress(WireGuardDll, #Name)) == NULL)
if (X(WireGuardCreateAdapter) || X(WireGuardOpenAdapter) || X(WireGuardCloseAdapter) ||
X(WireGuardGetAdapterLUID) || X(WireGuardGetRunningDriverVersion) || X(WireGuardDeleteDriver) ||
@ -40,14 +46,16 @@ static HMODULE InitializeWireGuardNT(void) {
#undef X
{
DWORD LastError = GetLastError();
fprintf(stderr, "[C] Failed to load wireguard.dll, error code: %lu\n", LastError);
FreeLibrary(WireGuardDll);
SetLastError(LastError);
return NULL;
}
printf("[C] Finished Init WG.dll\n");
return WireGuardDll;
}
GUID generateGUID() {
static GUID generateGUID(void) {
UUID uuid;
RPC_STATUS status = UuidCreate(&uuid);
@ -115,7 +123,7 @@ JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_installTunnel(JNIEn
const jchar *rawStr = (*env)->GetStringChars(env, tunnelName, 0); //TODO mem cleanup
LPWSTR tnlName = (LPWSTR) rawStr;
wprintf(L"[C] Tunnel Name: %ls", tnlName);
wprintf(L"[C] Tunnel Name: %ls\n", tnlName);
wchar_t *servicePrefix = L"WireGuardTunnel$";
wchar_t *serviceName = malloc(sizeof(wchar_t) * (wcslen(servicePrefix) + wcslen(tnlName) + 1)); //TODO mem cleanup
@ -244,4 +252,115 @@ JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_removeTunnel(JNIEnv
free(tnlName);
return 0;
}
JNIEXPORT jlong JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_getWGVersion(JNIEnv *env, jobject obj) {
WSADATA WsaData;
if (WSAStartup(MAKEWORD(2, 2), &WsaData)) {
fprintf(stderr, "[C] Failed to initialize Winsock\n");
return 0;
}
HMODULE WireGuardDLL = InitializeWireGuardNT();
printf("[C] Post Init WGNT\n");
if (WireGuardDLL == NULL) {
fprintf(stderr, "[C] Failed to initialize WireGuardNT library\n");
return 1;
}
DWORD Version = WireGuardGetRunningDriverVersion();
printf("[C] Before Printed version\n");
//printf("[C] WG Ver: %lu\n", Version);
wprintf(L"WireGuardNT v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff);
FreeLibrary(WireGuardDLL);
return Version;
}
JNIEXPORT jlong JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_parseConfig(JNIEnv *env, jobject obj, jobject conf) {
// Allocate memory for Config struct
Config *config = (Config *)malloc(sizeof(Config));
if (config == NULL) {
return 0; // Memory allocation failed
}
// Get WGConf class and fields
jclass wgConfClass = (*env)->GetObjectClass(env, conf);
// Step 1: Fill Interface fields
jfieldID ifaceFieldID = (*env)->GetFieldID(env, wgConfClass, "iface", "Ltech/nevets/tvpn/wg/WGConf$Interface;");
jobject ifaceObj = (*env)->GetObjectField(env, conf, ifaceFieldID);
jclass ifaceClass = (*env)->GetObjectClass(env, ifaceObj);
config->Interface.Flags = (WIREGUARD_INTERFACE_FLAG)(*env)->GetIntField(env, ifaceObj, (*env)->GetFieldID(env, ifaceClass, "flags", "I"));
config->Interface.ListenPort = (WORD)(*env)->GetIntField(env, ifaceObj, (*env)->GetFieldID(env, ifaceClass, "port", "I"));
// Get and copy privateKey
jbyteArray privateKeyArray = (jbyteArray)(*env)->GetObjectField(env, ifaceObj, (*env)->GetFieldID(env, ifaceClass, "privateKey", "[B"));
(*env)->GetByteArrayRegion(env, privateKeyArray, 0, WIREGUARD_KEY_LENGTH, (jbyte *)config->Interface.PrivateKey);
// Get and copy publicKey
jbyteArray publicKeyArray = (jbyteArray)(*env)->GetObjectField(env, ifaceObj, (*env)->GetFieldID(env, ifaceClass, "publicKey", "[B"));
(*env)->GetByteArrayRegion(env, publicKeyArray, 0, WIREGUARD_KEY_LENGTH, (jbyte *)config->Interface.PublicKey);
config->Interface.PeersCount = (DWORD)(*env)->GetIntField(env, ifaceObj, (*env)->GetFieldID(env, ifaceClass, "peersCount", "I"));
// Step 2: Fill Peer fields
jfieldID peerFieldID = (*env)->GetFieldID(env, wgConfClass, "peer", "Ltech/nevets/tvpn/wg/WGConf$Peer;");
jobject peerObj = (*env)->GetObjectField(env, conf, peerFieldID);
jclass peerClass = (*env)->GetObjectClass(env, peerObj);
config->Peer.Flags = (WIREGUARD_PEER_FLAG)(*env)->GetIntField(env, peerObj, (*env)->GetFieldID(env, peerClass, "flags", "I"));
config->Peer.Reserved = (DWORD)(*env)->GetIntField(env, peerObj, (*env)->GetFieldID(env, peerClass, "reserved", "I"));
// Get and copy publicKey
jbyteArray peerPublicKeyArray = (jbyteArray)(*env)->GetObjectField(env, peerObj, (*env)->GetFieldID(env, peerClass, "publicKey", "[B"));
(*env)->GetByteArrayRegion(env, peerPublicKeyArray, 0, WIREGUARD_KEY_LENGTH, (jbyte *)config->Peer.PublicKey);
// Get and copy presharedKey
jbyteArray presharedKeyArray = (jbyteArray)(*env)->GetObjectField(env, peerObj, (*env)->GetFieldID(env, peerClass, "presharedKey", "[B"));
(*env)->GetByteArrayRegion(env, presharedKeyArray, 0, WIREGUARD_KEY_LENGTH, (jbyte *)config->Peer.PresharedKey);
config->Peer.PersistentKeepalive = (WORD)(*env)->GetIntField(env, peerObj, (*env)->GetFieldID(env, peerClass, "persistentKeepalive", "I"));
config->Peer.AllowedIPsCount = (DWORD)(*env)->GetIntField(env, peerObj, (*env)->GetFieldID(env, peerClass, "allowedIPsCount", "I"));
// Endpoint is more complex: requires parsing from byte array and setting `SOCKADDR_INET`
jbyteArray endpointArray = (jbyteArray)(*env)->GetObjectField(env, peerObj, (*env)->GetFieldID(env, peerClass, "endpoint", "[B"));
jsize endpointLen = (*env)->GetArrayLength(env, endpointArray);
jbyte *endpointBytes = (*env)->GetByteArrayElements(env, endpointArray, NULL);
if (endpointLen == sizeof(SOCKADDR_INET)) {
memcpy(&config->Peer.Endpoint, endpointBytes, sizeof(SOCKADDR_INET));
}
(*env)->ReleaseByteArrayElements(env, endpointArray, endpointBytes, 0);
// Step 3: Fill AllowedIP fields
jfieldID allowedIPFieldID = (*env)->GetFieldID(env, wgConfClass, "allowedIP", "Ltech/nevets/tvpn/wg/WGConf$AllowedIP;");
jobject allowedIPObj = (*env)->GetObjectField(env, conf, allowedIPFieldID);
jclass allowedIPClass = (*env)->GetObjectClass(env, allowedIPObj);
jstring addressStr = (jstring)(*env)->GetObjectField(env, allowedIPObj, (*env)->GetFieldID(env, allowedIPClass, "address", "Ljava/lang/String;"));
const char *addressChars = (*env)->GetStringUTFChars(env, addressStr, NULL);
// Assuming address parsing logic here, converting to either IN_ADDR or IN6_ADDR based on `addressFamily`
jstring familyStr = (jstring)(*env)->GetObjectField(env, allowedIPObj, (*env)->GetFieldID(env, allowedIPClass, "addressFamily", "Ljava/lang/String;"));
const char *familyChars = (*env)->GetStringUTFChars(env, familyStr, NULL);
if (strcmp(familyChars, "AF_INET") == 0) {
config->AllowedIP.AddressFamily = AF_INET;
inet_pton(AF_INET, addressChars, &config->AllowedIP.Address.V4);
} else if (strcmp(familyChars, "AF_INET6") == 0) {
config->AllowedIP.AddressFamily = AF_INET6;
inet_pton(AF_INET6, addressChars, &config->AllowedIP.Address.V6);
}
(*env)->ReleaseStringUTFChars(env, familyStr, familyChars);
(*env)->ReleaseStringUTFChars(env, addressStr, addressChars);
config->AllowedIP.Cidr = (BYTE)(*env)->GetByteField(env, allowedIPObj, (*env)->GetFieldID(env, allowedIPClass, "cidr", "B"));
// Return the pointer to Config struct as jlong
return (jlong)(uintptr_t)config;
}

View File

@ -43,6 +43,8 @@ public class LogOutputStream extends OutputStream {
for (int i = 0; i < pointer; i++) {
sb.append(buf[i]);
}
textArea.append(sb.toString());
if (textArea != null) {
textArea.append(sb.toString());
}
}
}

View File

@ -2,20 +2,20 @@ package tech.nevets.tvpn;
import com.formdev.flatlaf.FlatDarkLaf;
import tech.nevets.jconf.JsonConfig;
import tech.nevets.tvpn.cli.CommandBrigadier;
import tech.nevets.tvpn.ui.UIManager;
import tech.nevets.tvpn.wg.WireGuardJNI;
import javax.swing.*;
import java.io.File;
import tech.nevets.tvpn.cli.CommandBrigadier;
public class Main {
private static final Logger LOGGER = new Logger(Main.class);
public static void main(String[] args) {
LogOutputStream logOut = new LogOutputStream();
Logger.loadLogOutStream(logOut);
JsonConfig conf = new JsonConfig("");
JsonConfig conf = new JsonConfig("config.json");
if (args.length > 0) {
new CommandBrigadier().execute(args);

View File

@ -1,12 +0,0 @@
package tech.nevets.tvpn.cli;
public interface Command {
void execute(String[] args);
String getName();
String getUsage();
String getDescription();
}

View File

@ -1,49 +0,0 @@
package tech.nevets.tvpn.cli;
import tech.nevets.tvpn.Logger;
import tech.nevets.tvpn.cli.commands.HelpCmd;
import tech.nevets.tvpn.cli.commands.InstallTunnelServiceCmd;
import tech.nevets.tvpn.cli.commands.UninstallTunnelServiceCmd;
import java.util.ArrayList;
import java.util.List;
public class CommandBrigadier {
private static final Logger LOGGER = new Logger(CommandBrigadier.class);
private final List<Command> registeredCommands;
private final HelpCmd helpCmd;
public CommandBrigadier() {
this.registeredCommands = new ArrayList<>();
helpCmd = new HelpCmd(this);
registerCommand(helpCmd);
registerCommand(new InstallTunnelServiceCmd());
registerCommand(new UninstallTunnelServiceCmd());
}
public void registerCommand(Command cmd) {
for (Command c : registeredCommands) {
if (c.getName().equals(cmd.getName())) {
LOGGER.warn("Command with name " + cmd.getName() + " already registered, skipping.");
return;
}
}
registeredCommands.add(cmd);
}
public void execute(String[] args) {
for (Command c : registeredCommands) {
if (c.getName().equals(args[0])) {
c.execute(args);
return;
}
}
helpCmd.execute(new String[0]);
}
public List<Command> getCommands() {
return registeredCommands;
}
}

View File

@ -1,52 +0,0 @@
package tech.nevets.tvpn.cli.commands;
import tech.nevets.tvpn.cli.Command;
import tech.nevets.tvpn.cli.CommandBrigadier;
public class HelpCmd implements Command {
private final CommandBrigadier cb;
public HelpCmd(CommandBrigadier cb) {
this.cb = cb;
}
@Override
public void execute(String[] args) {
if (args.length > 0) {
for (Command c : cb.getCommands()) {
if (!(args.length == 1) && args[1].equals(c.getName())) {
System.out.println("TVPN - Usage Menu [" + c.getName() + "]");
System.out.println(c.getName() + " " + c.getUsage() + ": " + c.getDescription());
System.exit(0);
}
}
}
StringBuilder sb = new StringBuilder();
sb.append("TVPN - Help Menu\n");
for (Command c : cb.getCommands()) {
sb.append(" - ").append(c.getName())
.append(" ").append(c.getUsage())
.append(": ").append(c.getDescription())
.append("\n");
}
System.out.println(sb);
System.exit(0);
}
@Override
public String getName() {
return "help";
}
@Override
public String getUsage() {
return "";
}
@Override
public String getDescription() {
return "Displays the help menu";
}
}

View File

@ -1,71 +0,0 @@
package tech.nevets.tvpn.cli.commands;
import tech.nevets.tvpn.Utils;
import tech.nevets.tvpn.cli.Command;
import tech.nevets.tvpn.wg.WireGuardJNI;
import java.util.regex.Pattern;
public class InstallTunnelServiceCmd implements Command {
@Override
public void execute(String[] args) {
System.out.println("Executing InstallTunnelServiceCmd");
String path = Utils.APP_DIR + "/configurations/" + args[1] + ".conf";
System.out.println(new WireGuardJNI().installTunnel(args[1], path));
System.exit(0);
}
@Override
public String getName() {
return "/installtunnelservice";
}
@Override
public String getUsage() {
return "(/path/to/tunnel/config)";
}
@Override
public String getDescription() {
return "Creates and starts a WireGuard Tunnel Service";
}
String[] reservedNames = new String[]{
"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
};
private boolean isReserved(String name) {
if (name.isEmpty()) {
return false;
}
for (String s : reservedNames) {
if (name.contains(s)) {
return true;
}
}
return false;
}
private static final String[] SPECIAL_CHARS = new String[]{"$", "\\", "/", ":", "*", "?", "\"", "'", "<", ">", "|", "\t", "\00"};
private boolean hasSpecialChars(String name) {
for (String s : SPECIAL_CHARS) {
if (name.contains(s)) {
return true;
}
}
return false;
}
private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9_=+.-]{1,32}$");
private boolean tunnelNameIsValid(String name) {
if (isReserved(name) || hasSpecialChars(name)) {
return false;
}
return PATTERN.matcher(name).hasMatch();
}
}

View File

@ -1,28 +0,0 @@
package tech.nevets.tvpn.cli.commands;
import tech.nevets.tvpn.cli.Command;
import tech.nevets.tvpn.wg.WireGuardJNI;
public class UninstallTunnelServiceCmd implements Command {
@Override
public void execute(String[] args) {
System.out.println("Executing UnInstallTunnelServiceCmd");
System.out.println(new WireGuardJNI().removeTunnel(args[1]));
System.exit(0);
}
@Override
public String getName() {
return "/uninstalltunnelservice";
}
@Override
public String getUsage() {
return "(tunnel name)";
}
@Override
public String getDescription() {
return "Stops and removes WireGuard Tunnel Service";
}
}

View File

@ -0,0 +1,92 @@
package tech.nevets.tvpn.wg;
public class WGConf {
public Interface iface;
public Peer peer;
public AllowedIP allowedIP;
public WGConf(Interface iface, Peer peer, AllowedIP allowedIP) {
this.iface = iface;
this.peer = peer;
this.allowedIP = allowedIP;
}
/*
struct WIREGUARD_INTERFACE {
WIREGUARD_INTERFACE_FLAG Flags; < Bitwise combination of flags
WORD ListenPort; < Port for UDP listen socket, or 0 to choose randomly
BYTE PrivateKey[WIREGUARD_KEY_LENGTH]; < Private key of interface
BYTE PublicKey[WIREGUARD_KEY_LENGTH]; < Corresponding public key of private key
DWORD PeersCount; < Number of peer structs following this struct
};
typedef enum {
WIREGUARD_INTERFACE_HAS_PUBLIC_KEY = (1 << 0), < The PublicKey field is set
WIREGUARD_INTERFACE_HAS_PRIVATE_KEY = (1 << 1), < The PrivateKey field is set
WIREGUARD_INTERFACE_HAS_LISTEN_PORT = (1 << 2), < The ListenPort field is set
WIREGUARD_INTERFACE_REPLACE_PEERS = (1 << 3) < Remove all peers before adding new ones
} WIREGUARD_INTERFACE_FLAG;
*/
public class Interface {
public int flags;
public int port; // Should be 0 for random
public byte[] privateKey;
public byte[] publicKey; // Should be unused, will be calculated by privateKey
public int peersCount; // Should be 1
}
/*
struct WIREGUARD_PEER {
WIREGUARD_PEER_FLAG Flags; < Bitwise combination of flags
DWORD Reserved; < Reserved; must be zero
BYTE PublicKey[32]; < Public key, the peer's primary identifier
BYTE PresharedKey[32]; < Preshared key for additional layer of post-quantum resistance
WORD PersistentKeepalive; < Seconds interval, or 0 to disable
SOCKADDR_INET Endpoint; < Endpoint, with IP address and UDP port number
DWORD64 TxBytes; < Number of bytes transmitted
DWORD64 RxBytes; < Number of bytes received
DWORD64 LastHandshake; < Time of the last handshake, in 100ns intervals since 1601-01-01 UTC
DWORD AllowedIPsCount; < Number of allowed IP structs following this struct
};
typedef enum {
WIREGUARD_PEER_HAS_PUBLIC_KEY = 1 << 0, < The PublicKey field is set
WIREGUARD_PEER_HAS_PRESHARED_KEY = 1 << 1, < The PresharedKey field is set
WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE = 1 << 2, < The PersistentKeepAlive field is set
WIREGUARD_PEER_HAS_ENDPOINT = 1 << 3, < The Endpoint field is set
WIREGUARD_PEER_REPLACE_ALLOWED_IPS = 1 << 5, < Remove all allowed IPs before adding new ones
WIREGUARD_PEER_REMOVE = 1 << 6, < Remove specified peer
WIREGUARD_PEER_UPDATE = 1 << 7 < Do not add a new peer
} WIREGUARD_PEER_FLAG;
*/
public class Peer {
public int flags;
public int reserved = 0; // "Must be 0"
public byte[] publicKey;
public byte[] presharedKey;
public int persistentKeepalive; // In seconds, or 0 to disable
public byte[] endpoint; // Going to have to figure out how to parse this. IP + UDP Port
public int txBytes; // Unused, changed later
public int rxBytes; // Unused, changed later
public long lastHandshake; // Time of last handshake, in 100ns intervals since 1601-01-01 UTC. Unused, changed later
public int allowedIPsCount; // Number of allowed IP structures
}
/*
struct WIREGUARD_ALLOWED_IP {
union
{
IN_ADDR V4;
IN6_ADDR V6;
} Address; < IP address
ADDRESS_FAMILY AddressFamily; < Address family, either AF_INET or AF_INET6
BYTE Cidr; < CIDR of allowed IPs
};
*/
public class AllowedIP {
public String address; // IP address; the V4 member is an IN_ADDR and the V6 member is an IN6_ADDR
public String addressFamily; // Address family, either AF_INET or AF_INET6
public byte cidr; // The CIDR of the address range
}
}

View File

@ -1,9 +1,14 @@
package tech.nevets.tvpn.wg;
import tech.nevets.tvpn.Logger;
public class WireGuardJNI {
private static final Logger LOGGER = new Logger(WireGuardJNI.class);
// Load the native library
static {
System.loadLibrary("libwireguard_wrapper"); // This will load wireguard_wrapper.dll (or .so on Linux)
LOGGER.log("Loaded libwireguard_wrapper");
}
// Native method declaration
@ -29,5 +34,8 @@ public class WireGuardJNI {
public native int initializeWireGuard(String configFilePath);
public native void cleanup();
public native String getWGVersion();
public native long parseConfig(WGConf conf);
// Other methods for WireGuard interaction can be added here if needed
}

View File

@ -0,0 +1,11 @@
package tech.nevets.tvpn.cli
interface Command {
fun execute(args: Array<String>)
fun getName(): String
fun getUsage(): String
fun getDescription(): String
}

View File

@ -0,0 +1,41 @@
package tech.nevets.tvpn.cli
import tech.nevets.tvpn.cli.commands.*
import tech.nevets.tvpn.Logger
class CommandBrigadier {
private val logger: Logger = Logger(CommandBrigadier::class.java)
private val registeredCmds: List<Command> = ArrayList()
private val helpCmd: HelpCmd = HelpCmd(this)
init {
registerCmd(helpCmd)
registerCmd(InstallTunnelServiceCmd())
registerCmd(UninstallTunnelServiceCmd())
registerCmd(VersionCmd())
}
private fun registerCmd(cmd: Command) {
for (c in registeredCmds) {
if (c.getName() == cmd.getName()) {
logger.warn("Command with name " + cmd.getName() + " already registered, skipping.")
return
}
}
registeredCmds.addLast(cmd)
}
fun execute(args: Array<String>) {
for (c in registeredCmds) {
if (c.getName() == args[0]) {
c.execute(args)
return
}
}
helpCmd.execute(arrayOf(""))
}
fun getCommands(): List<Command> {
return registeredCmds
}
}

View File

@ -0,0 +1,45 @@
package tech.nevets.tvpn.cli.commands
import tech.nevets.tvpn.cli.Command
import tech.nevets.tvpn.cli.CommandBrigadier
import kotlin.system.exitProcess
class HelpCmd(private val cb: CommandBrigadier) : Command {
override fun execute(args: Array<String>) {
if (args.isNotEmpty()) {
for (c in cb.getCommands()) {
if (args.size != 1 && args[1] == c.getName()) {
println(("TVPN - Usage Menu [" + c.getName()) + "]")
println((c.getName() + " " + c.getUsage()) + ": " + c.getDescription())
exitProcess(0)
}
}
}
val sb = StringBuilder()
sb.append("TVPN - Help Menu\n")
for (c in cb.getCommands()) {
sb.append(" - ").append(c.getName())
.append(" ").append(c.getUsage())
.append(": ").append(c.getDescription())
.append("\n")
}
println(sb)
exitProcess(0)
}
override fun getName(): String {
return "help"
}
override fun getUsage(): String {
return ""
}
override fun getDescription(): String {
return "Displays the help menu"
}
}

View File

@ -0,0 +1,65 @@
package tech.nevets.tvpn.cli.commands
import tech.nevets.tvpn.Utils
import tech.nevets.tvpn.cli.Command
import tech.nevets.tvpn.wg.WireGuardJNI
import java.util.regex.Pattern
import kotlin.system.exitProcess
class InstallTunnelServiceCmd : Command {
override fun execute(args: Array<String>) {
println("Executing InstallTunnelServiceCmd")
val path = Utils.APP_DIR.toString() + "/configurations/" + args[1] + ".conf"
println(WireGuardJNI().installTunnel(args[1], path))
exitProcess(0)
}
override fun getName(): String {
return "/installtunnelservice"
}
override fun getUsage(): String {
return "(/path/to/tunnel/config)"
}
override fun getDescription(): String {
return "Creates and starts a WireGuard Tunnel Service"
}
private var reservedNames: Array<String> = arrayOf(
"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
)
private fun isReserved(name: String): Boolean {
if (name.isEmpty()) {
return false
}
for (s in reservedNames) {
if (name.contains(s)) {
return true
}
}
return false
}
private val specialChars = arrayOf("$", "\\", "/", ":", "*", "?", "\"", "'", "<", ">", "|", "\t", "\u0000")
private fun hasSpecialChars(name: String): Boolean {
for (s in specialChars) {
if (name.contains(s)) {
return true
}
}
return false
}
private val pattern: Pattern = Pattern.compile("^[a-zA-Z0-9_=+.-]{1,32}$")
private fun tunnelNameIsValid(name: String): Boolean {
if (isReserved(name) || hasSpecialChars(name)) {
return false
}
return pattern.matcher(name).hasMatch()
}
}

View File

@ -0,0 +1,25 @@
package tech.nevets.tvpn.cli.commands
import tech.nevets.tvpn.cli.Command
import tech.nevets.tvpn.wg.WireGuardJNI
import kotlin.system.exitProcess
class UninstallTunnelServiceCmd : Command {
override fun execute(args: Array<String>) {
println("Executing UnInstallTunnelServiceCmd")
println(WireGuardJNI().removeTunnel(args[1]))
exitProcess(0)
}
override fun getName(): String {
return "/uninstalltunnelservice"
}
override fun getUsage(): String {
return "(tunnel name)"
}
override fun getDescription(): String {
return "Stops and removes WireGuard Tunnel Service"
}
}

View File

@ -0,0 +1,26 @@
package tech.nevets.tvpn.cli.commands
import tech.nevets.tvpn.cli.Command
import tech.nevets.tvpn.wg.WireGuardJNI
import kotlin.system.exitProcess
class VersionCmd : Command {
override fun execute(args: Array<String>) {
println("Version: 0.3.1")
print("WireGuard Version: ")
WireGuardJNI().getWGVersion()
exitProcess(0)
}
override fun getName(): String {
return "version"
}
override fun getUsage(): String {
return ""
}
override fun getDescription(): String {
return "Shows the current running version."
}
}