diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml
new file mode 100644
index 0000000..4ef8594
--- /dev/null
+++ b/.gitea/workflows/build.yml
@@ -0,0 +1,54 @@
+name: TVPN Actions Workflow
+run-name: Deploy to ${{ inputs.deploy_target }} by ${{ gitea.actor }}
+on: [push]
+
+jobs:
+ build:
+ runs-on: windows-10
+ steps:
+ - uses: actions/checkout@v4
+ #- name: Setup JDK 21
+ # uses: actions-setup-java@v4.4.0
+ # with:
+ # java-version: 21
+ # distribution: 'temurin'
+ - name: Test Java
+ run: java --version
+ - name: Configure Git
+ run: |
+ git config --global user.email "git@nevets.tech"
+ git config --global user.name "Gitea Actions"
+ - name: Build TVPN Jar
+ run: .\gradlew.bat clean shadowJar createExe
+ - name: Copy Header to C Dir
+ run: |
+ cp build/generated/sources/headers/java/main/tech_nevets_tvpn_wg_WireGuardJNI.h src/main/cpp/
+ - name: Build DLL
+ run: |
+ 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
+ # uses: actions/cmake-action@v2.0.0
+ # with:
+ # source-dir: src/main/cpp
+ # output-dir: src/main/cpp/build
+ - name: Prepare artifacts
+ run: |
+ Get-ChildItem -Path artifacts -Recurse | Remove-Item -force -recurse
+ if (Test-Path -Path .\artifacts) { Remove-Item -Path .\artifacts -Recurse -Force }
+ $version = (Select-String -Path "build.gradle" -Pattern "^\s*version\s*=\s*'([^']+)'" | ForEach-Object { $_.Matches[0].Groups[1].Value })
+ echo Version: $version
+ New-Item -Path "artifacts" -ItemType Directory
+ Copy-Item -Path "./build/libs/TVPN-$version-all.jar" -Destination "./artifacts/TVPN-$version.jar" -Verbose
+ Copy-Item -Path "./build/launch4j/TVPN.exe" -Destination "./artifacts/TVPN.exe" -Verbose
+ Copy-Item -Path "./src/main/cpp/build/libwireguard_wrapper.dll" -Destination "./artifacts/libwireguard_wrapper.dll" -Verbose
+ Copy-Item -Path "./libs/tunnel.dll" -Destination "./artifacts/tunnel.dll" -Verbose
+ Copy-Item -Path "./libs/wireguard.dll" -Destination "./artifacts/wireguard.dll" -Verbose
+ - name: Create Installer
+ run: |
+ git clone https://git.nevets.tech/Steven/TVPN-jre.git jre
+ ISCC /DMyAppVersion=$version "./installer-script.iss"
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: artifacts
+ path: artifacts\*
diff --git a/.gitignore b/.gitignore
index 2d797e8..3a46706 100644
--- a/.gitignore
+++ b/.gitignore
@@ -152,3 +152,8 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
+src/main/cpp/tech_nevets_tvpn_wg_WireGuardJNI.h
+
+jre/
+src/main/cpp/build
+inno/
\ No newline at end of file
diff --git a/TVPN.exe.manifest b/TVPN.exe.manifest
new file mode 100644
index 0000000..3119ef3
--- /dev/null
+++ b/TVPN.exe.manifest
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 262d827..a889fc5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,13 +1,18 @@
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '8.1.1'
+ id 'edu.sc.seis.launch4j' version '3.0.6'
}
group = 'tech.nevets'
-version = '0.2.0'
+version = '0.3.0'
repositories {
mavenCentral()
+ maven {
+ name = "Gitea"
+ url = uri("https://git.nevets.tech/api/packages/Steven/maven")
+ }
}
dependencies {
@@ -18,6 +23,8 @@ dependencies {
//implementation "com.formdev:flatlaf:3.5.1"
implementation files("libs/gson-2.11.0.jar")
//implementation "com.google.code.gson:gson:2.11.0"
+
+ implementation "tech.nevets:JConf:0.1.0:no-deps"
}
tasks.withType(JavaCompile).configureEach {
@@ -33,4 +40,17 @@ jar {
'Main-Class': 'tech.nevets.tvpn.Main'
)
}
+}
+
+launch4j {
+ mainClassName = 'tech.nevets.tvpn.Main'
+ outfile = 'TVPN.exe'
+ jarTask = project.tasks.shadowJar
+ fileDescription = 'TVPN Client'
+ icon = "${projectDir}/src/main/resources/icon.ico"
+ productName = 'TVPN'
+ version = "$this.version"
+ textVersion = "$this.version"
+ bundledJrePath = './jre'
+ manifest = "${projectDir}/TVPN.exe.manifest"
}
\ No newline at end of file
diff --git a/installer-script.iss b/installer-script.iss
new file mode 100644
index 0000000..f09c050
--- /dev/null
+++ b/installer-script.iss
@@ -0,0 +1,51 @@
+; Script generated by the Inno Setup Script Wizard.
+; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
+
+#define MyAppName "TVPN"
+#define MyAppPublisher "nevetS Tech"
+#define MyAppURL "https://git.nevets.tech/Steven/TVPN"
+#define MyAppExeName "TVPN.exe"
+
+[Setup]
+; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
+; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
+AppId={{79AFBC44-4C4B-4509-9723-5CB4F30E875F}
+AppName={#MyAppName}
+AppVersion={#MyAppVersion}
+;AppVerName={#MyAppName} {#MyAppVersion}
+AppPublisher={#MyAppPublisher}
+AppPublisherURL={#MyAppURL}
+AppSupportURL={#MyAppURL}
+AppUpdatesURL={#MyAppURL}
+DefaultDirName={autopf}\{#MyAppName}
+DisableProgramGroupPage=yes
+; Uncomment the following line to run in non administrative install mode (install for current user only.)
+;PrivilegesRequired=lowest
+OutputDir=.\artifacts
+OutputBaseFilename=tvpn-installer
+SetupIconFile=.\src\main\resources\icon.ico
+Compression=lzma
+SolidCompression=yes
+WizardStyle=modern
+
+[Languages]
+Name: "english"; MessagesFile: "compiler:Default.isl"
+
+[Tasks]
+Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
+
+[Files]
+Source: ".\artifacts\TVPN.exe"; DestDir: "{app}"; Flags: ignoreversion
+Source: ".\jre\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: ".\artifacts\wireguard.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: ".\artifacts\tunnel.dll"; DestDir: "{app}"; Flags: ignoreversion
+Source: ".\artifacts\libwireguard_wrapper.dll"; DestDir: "{app}"; Flags: ignoreversion
+; NOTE: Don't use "Flags: ignoreversion" on any shared system files
+
+[Icons]
+Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
+Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
+
+[Run]
+Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
+
diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt
index 26936ff..10e1a71 100644
--- a/src/main/cpp/CMakeLists.txt
+++ b/src/main/cpp/CMakeLists.txt
@@ -17,8 +17,10 @@ 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)
+target_link_libraries(wireguard_wrapper PRIVATE Rpcrt4)
+
# Optionally, you can specify output directory for the compiled library
set_target_properties(wireguard_wrapper PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY build/lib
+ LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
OUTPUT_NAME "wireguard_wrapper"
)
diff --git a/src/main/cpp/example.c b/src/main/cpp/example.c
new file mode 100644
index 0000000..7d8e5bf
--- /dev/null
+++ b/src/main/cpp/example.c
@@ -0,0 +1,444 @@
+//
+// Created by steven on 10/27/2024.
+//
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "wireguard.h"
+
+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;
+
+static HMODULE
+InitializeWireGuardNT(void)
+{
+ HMODULE WireGuardDll =
+ LoadLibraryExW(L"wireguard.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (!WireGuardDll)
+ return NULL;
+#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 NULL;
+ }
+ return WireGuardDll;
+}
+
+static void CALLBACK
+ConsoleLogger(_In_ WIREGUARD_LOGGER_LEVEL Level, _In_ DWORD64 Timestamp, _In_z_ const WCHAR *LogLine)
+{
+ SYSTEMTIME SystemTime;
+ FileTimeToSystemTime((FILETIME *)&Timestamp, &SystemTime);
+ WCHAR LevelMarker;
+ switch (Level)
+ {
+ case WIREGUARD_LOG_INFO:
+ LevelMarker = L'+';
+ break;
+ case WIREGUARD_LOG_WARN:
+ LevelMarker = L'-';
+ break;
+ case WIREGUARD_LOG_ERR:
+ LevelMarker = L'!';
+ break;
+ default:
+ return;
+ }
+ fwprintf(
+ stderr,
+ L"%04u-%02u-%02u %02u:%02u:%02u.%04u [%c] %s\n",
+ SystemTime.wYear,
+ SystemTime.wMonth,
+ SystemTime.wDay,
+ SystemTime.wHour,
+ SystemTime.wMinute,
+ SystemTime.wSecond,
+ SystemTime.wMilliseconds,
+ LevelMarker,
+ LogLine);
+}
+
+static DWORD64 Now(VOID)
+{
+ LARGE_INTEGER Timestamp;
+ NtQuerySystemTime(&Timestamp);
+ return Timestamp.QuadPart;
+}
+
+static DWORD
+LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error)
+{
+ WCHAR *SystemMessage = NULL, *FormattedMessage = NULL;
+ FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL,
+ HRESULT_FROM_SETUPAPI(Error),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (void *)&SystemMessage,
+ 0,
+ NULL);
+ FormatMessageW(
+ FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ SystemMessage ? L"%1: %3(Code 0x%2!08X!)" : L"%1: Code 0x%2!08X!",
+ 0,
+ 0,
+ (void *)&FormattedMessage,
+ 0,
+ (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage });
+ if (FormattedMessage)
+ ConsoleLogger(WIREGUARD_LOG_ERR, Now(), FormattedMessage);
+ LocalFree(FormattedMessage);
+ LocalFree(SystemMessage);
+ return Error;
+}
+
+static DWORD
+LogLastError(_In_z_ const WCHAR *Prefix)
+{
+ DWORD LastError = GetLastError();
+ LogError(Prefix, LastError);
+ SetLastError(LastError);
+ return LastError;
+}
+
+static void
+Log(_In_ WIREGUARD_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...)
+{
+ WCHAR LogLine[0x200];
+ va_list args;
+ va_start(args, Format);
+ _vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, args);
+ va_end(args);
+ ConsoleLogger(Level, Now(), LogLine);
+}
+
+_Must_inspect_result_
+_Return_type_success_(return != FALSE)
+static BOOL
+GenerateKeyPair(
+ _Out_writes_bytes_all_(WIREGUARD_KEY_LENGTH) BYTE PublicKey[WIREGUARD_KEY_LENGTH],
+ _Out_writes_bytes_all_(WIREGUARD_KEY_LENGTH) BYTE PrivateKey[WIREGUARD_KEY_LENGTH])
+{
+ BCRYPT_ALG_HANDLE Algorithm;
+ BCRYPT_KEY_HANDLE Key;
+ NTSTATUS Status;
+ struct
+ {
+ BCRYPT_ECCKEY_BLOB Header;
+ BYTE Public[32];
+ BYTE Unused[32];
+ BYTE Private[32];
+ } ExportedKey;
+ ULONG Bytes;
+
+ Status = BCryptOpenAlgorithmProvider(&Algorithm, BCRYPT_ECDH_ALGORITHM, NULL, 0);
+ if (!NT_SUCCESS(Status))
+ goto out;
+
+ Status = BCryptSetProperty(
+ Algorithm, BCRYPT_ECC_CURVE_NAME, (PUCHAR)BCRYPT_ECC_CURVE_25519, sizeof(BCRYPT_ECC_CURVE_25519), 0);
+ if (!NT_SUCCESS(Status))
+ goto cleanupProvider;
+
+ Status = BCryptGenerateKeyPair(Algorithm, &Key, 255, 0);
+ if (!NT_SUCCESS(Status))
+ goto cleanupProvider;
+
+ Status = BCryptFinalizeKeyPair(Key, 0);
+ if (!NT_SUCCESS(Status))
+ goto cleanupKey;
+
+ Status = BCryptExportKey(Key, NULL, BCRYPT_ECCPRIVATE_BLOB, (PUCHAR)&ExportedKey, sizeof(ExportedKey), &Bytes, 0);
+ if (!NT_SUCCESS(Status))
+ goto cleanupKey;
+
+ memcpy(PublicKey, ExportedKey.Public, WIREGUARD_KEY_LENGTH);
+ memcpy(PrivateKey, ExportedKey.Private, WIREGUARD_KEY_LENGTH);
+ SecureZeroMemory(&ExportedKey, sizeof(ExportedKey));
+
+ cleanupKey:
+ BCryptDestroyKey(Key);
+ cleanupProvider:
+ BCryptCloseAlgorithmProvider(Algorithm, 0);
+ out:
+ SetLastError(RtlNtStatusToDosError(Status));
+ return NT_SUCCESS(Status);
+}
+
+static HANDLE QuitEvent;
+
+static BOOL WINAPI
+CtrlHandler(_In_ DWORD CtrlType)
+{
+ switch (CtrlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ case CTRL_CLOSE_EVENT:
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ Log(WIREGUARD_LOG_INFO, L"Cleaning up and shutting down");
+ SetEvent(QuitEvent);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+_Return_type_success_(return != FALSE)
+static BOOL
+TalkToDemoServer(
+ _In_reads_bytes_(InputLength) const CHAR *Input,
+ _In_ DWORD InputLength,
+ _Out_writes_bytes_(*OutputLength) CHAR *Output,
+ _Inout_ DWORD *OutputLength,
+ _Out_ SOCKADDR_INET *ResolvedDemoServer)
+{
+ SOCKET Socket = INVALID_SOCKET;
+ ADDRINFOW Hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_protocol = IPPROTO_TCP }, *Resolution;
+ BOOL Ret = FALSE;
+
+ if (GetAddrInfoW(L"demo.wireguard.com", L"42912", &Hints, &Resolution))
+ return FALSE;
+ for (ADDRINFOW *Candidate = Resolution; Candidate; Candidate = Candidate->ai_next)
+ {
+ if (Candidate->ai_family != AF_INET && Candidate->ai_family != AF_INET6)
+ continue;
+ Socket = socket(Candidate->ai_family, Candidate->ai_socktype, Candidate->ai_protocol);
+ if (Socket == INVALID_SOCKET)
+ goto cleanupResolution;
+ if (connect(Socket, Candidate->ai_addr, (int)Candidate->ai_addrlen) == SOCKET_ERROR)
+ {
+ closesocket(Socket);
+ Socket = INVALID_SOCKET;
+ }
+ memcpy(ResolvedDemoServer, Candidate->ai_addr, Candidate->ai_addrlen);
+ break;
+ }
+ if (Socket == INVALID_SOCKET)
+ goto cleanupResolution;
+ if (send(Socket, Input, InputLength, 0) == SOCKET_ERROR)
+ goto cleanupSocket;
+ if ((*OutputLength = recv(Socket, Output, *OutputLength, 0)) == SOCKET_ERROR)
+ goto cleanupSocket;
+ Ret = TRUE;
+ cleanupSocket:
+ closesocket(Socket);
+ cleanupResolution:
+ FreeAddrInfoW(Resolution);
+ return Ret;
+}
+
+int __cdecl main(void)
+{
+ DWORD LastError;
+ WSADATA WsaData;
+ if (WSAStartup(MAKEWORD(2, 2), &WsaData))
+ return LogError(L"Failed to initialize Winsock", GetLastError());
+ HMODULE WireGuard = InitializeWireGuardNT();
+ if (!WireGuard)
+ {
+ LastError = LogError(L"Failed to initialize WireGuardNT", GetLastError());
+ goto cleanupWinsock;
+ }
+ WireGuardSetLogger(ConsoleLogger);
+ Log(WIREGUARD_LOG_INFO, L"WireGuardNT library loaded");
+
+ struct
+ {
+ 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 } };
+
+ Log(WIREGUARD_LOG_INFO, L"Generating keypair");
+ BYTE PublicKey[WIREGUARD_KEY_LENGTH];
+ if (!GenerateKeyPair(PublicKey, Config.Interface.PrivateKey))
+ {
+ LastError = LogError(L"Failed to generate keypair", GetLastError());
+ goto cleanupWireGuard;
+ }
+ CHAR PublicKeyString[46] = { 0 };
+ DWORD Bytes = sizeof(PublicKeyString);
+ CryptBinaryToStringA(
+ PublicKey, sizeof(PublicKey), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, PublicKeyString, &Bytes);
+ CHAR ServerResponse[256] = { 0 };
+ Log(WIREGUARD_LOG_INFO, L"Talking to demo server");
+ Bytes = sizeof(ServerResponse) - 1;
+ if (!TalkToDemoServer(
+ PublicKeyString, (DWORD)strlen(PublicKeyString), ServerResponse, &Bytes, &Config.DemoServer.Endpoint))
+ {
+ LastError = LogError(L"Failed to talk to demo server", GetLastError());
+ goto cleanupWireGuard;
+ }
+
+ CHAR *Colon1 = strchr(ServerResponse, ':');
+ CHAR *Colon2 = Colon1 ? strchr(Colon1 + 1, ':') : NULL;
+ CHAR *Colon3 = Colon2 ? strchr(Colon2 + 1, ':') : NULL;
+ if (!Colon1 || !Colon2 || !Colon3)
+ {
+ LastError = LogError(L"Failed to parse demo server response", ERROR_UNDEFINED_CHARACTER);
+ goto cleanupWireGuard;
+ }
+ if (Bytes && ServerResponse[--Bytes] == '\n')
+ ServerResponse[Bytes] = '\0';
+ *Colon1 = *Colon2 = *Colon3 = '\0';
+
+ MIB_UNICASTIPADDRESS_ROW AddressRow;
+ InitializeUnicastIpAddressEntry(&AddressRow);
+ AddressRow.Address.Ipv4.sin_family = AF_INET;
+ AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
+ AddressRow.DadState = IpDadStatePreferred;
+ Bytes = sizeof(Config.DemoServer.PublicKey);
+ if (strcmp(ServerResponse, "OK") || InetPtonA(AF_INET, Colon3 + 1, &AddressRow.Address.Ipv4.sin_addr) != 1 ||
+ !CryptStringToBinaryA(Colon1 + 1, 0, CRYPT_STRING_BASE64, Config.DemoServer.PublicKey, &Bytes, NULL, NULL))
+ {
+ LastError = LogError(L"Failed to parse demo server response", ERROR_UNDEFINED_CHARACTER);
+ goto cleanupWireGuard;
+ }
+ if (Config.DemoServer.Endpoint.si_family == AF_INET)
+ Config.DemoServer.Endpoint.Ipv4.sin_port = htons((u_short)atoi(Colon2 + 1));
+ else if (Config.DemoServer.Endpoint.si_family == AF_INET6)
+ Config.DemoServer.Endpoint.Ipv6.sin6_port = htons((u_short)atoi(Colon2 + 1));
+
+ QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+ if (!QuitEvent)
+ {
+ LastError = LogError(L"Failed to create event", GetLastError());
+ goto cleanupWireGuard;
+ }
+ if (!SetConsoleCtrlHandler(CtrlHandler, TRUE))
+ {
+ LastError = LogError(L"Failed to set console handler", GetLastError());
+ goto cleanupQuit;
+ }
+
+ GUID ExampleGuid = { 0xdeadc001, 0xbeef, 0xbabe, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
+ WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"Demo", L"Example", &ExampleGuid);
+ if (!Adapter)
+ {
+ LastError = GetLastError();
+ LogError(L"Failed to create adapter", LastError);
+ goto cleanupQuit;
+ }
+
+ if (!WireGuardSetAdapterLogging(Adapter, WIREGUARD_ADAPTER_LOG_ON))
+ LogError(L"Failed to enable adapter logging", GetLastError());
+
+ DWORD Version = WireGuardGetRunningDriverVersion();
+ Log(WIREGUARD_LOG_INFO, L"WireGuardNT v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff);
+
+ WireGuardGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid);
+ MIB_IPFORWARD_ROW2 DefaultRoute = { 0 };
+ InitializeIpForwardEntry(&DefaultRoute);
+ DefaultRoute.InterfaceLuid = AddressRow.InterfaceLuid;
+ DefaultRoute.DestinationPrefix.Prefix.si_family = AF_INET;
+ DefaultRoute.NextHop.si_family = AF_INET;
+ DefaultRoute.Metric = 0;
+ LastError = CreateIpForwardEntry2(&DefaultRoute);
+ if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS)
+ {
+ LogError(L"Failed to set default route", LastError);
+ goto cleanupAdapter;
+ }
+ LastError = CreateUnicastIpAddressEntry(&AddressRow);
+ if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS)
+ {
+ LogError(L"Failed to set IP address", LastError);
+ goto cleanupAdapter;
+ }
+ MIB_IPINTERFACE_ROW IpInterface = { 0 };
+ InitializeIpInterfaceEntry(&IpInterface);
+ IpInterface.InterfaceLuid = AddressRow.InterfaceLuid;
+ IpInterface.Family = AF_INET;
+ LastError = GetIpInterfaceEntry(&IpInterface);
+ if (LastError != ERROR_SUCCESS)
+ {
+ LogError(L"Failed to get IP interface", LastError);
+ goto cleanupAdapter;
+ }
+ IpInterface.UseAutomaticMetric = FALSE;
+ IpInterface.Metric = 0;
+ IpInterface.NlMtu = 1420;
+ IpInterface.SitePrefixLength = 0;
+ LastError = SetIpInterfaceEntry(&IpInterface);
+ if (LastError != ERROR_SUCCESS)
+ {
+ LogError(L"Failed to set metric and MTU", LastError);
+ goto cleanupAdapter;
+ }
+
+ Log(WIREGUARD_LOG_INFO, L"Setting configuration and adapter up");
+ if (!WireGuardSetConfiguration(Adapter, &Config.Interface, sizeof(Config)) ||
+ !WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE_UP))
+ {
+ LastError = LogError(L"Failed to set configuration and adapter up", GetLastError());
+ goto cleanupAdapter;
+ }
+
+ do
+ {
+ Bytes = sizeof(Config);
+ if (!WireGuardGetConfiguration(Adapter, &Config.Interface, &Bytes) || !Config.Interface.PeersCount)
+ {
+ LastError = LogError(L"Failed to get configuration", GetLastError());
+ goto cleanupAdapter;
+ }
+ DWORD64 Timestamp = Now();
+ SYSTEMTIME SystemTime;
+ FileTimeToSystemTime((FILETIME *)&Timestamp, &SystemTime);
+ fwprintf(
+ stderr,
+ L"%04u-%02u-%02u %02u:%02u:%02u.%04u [#] RX: %llu, TX: %llu\r",
+ SystemTime.wYear,
+ SystemTime.wMonth,
+ SystemTime.wDay,
+ SystemTime.wHour,
+ SystemTime.wMinute,
+ SystemTime.wSecond,
+ SystemTime.wMilliseconds,
+ Config.DemoServer.RxBytes,
+ Config.DemoServer.TxBytes);
+ } while (WaitForSingleObject(QuitEvent, 1000) == WAIT_TIMEOUT);
+
+ cleanupAdapter:
+ WireGuardCloseAdapter(Adapter);
+ cleanupQuit:
+ SetConsoleCtrlHandler(CtrlHandler, FALSE);
+ CloseHandle(QuitEvent);
+ cleanupWireGuard:
+ FreeLibrary(WireGuard);
+ cleanupWinsock:
+ WSACleanup();
+ return LastError;
+}
\ No newline at end of file
diff --git a/src/main/cpp/tech_nevets_tvpn_wg_WireGuardJNI.h b/src/main/cpp/tech_nevets_tvpn_wg_WireGuardJNI.h
deleted file mode 100644
index b3141ff..0000000
--- a/src/main/cpp/tech_nevets_tvpn_wg_WireGuardJNI.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include
-/* Header for class tech_nevets_tvpn_wg_WireGuardJNI */
-
-#ifndef _Included_tech_nevets_tvpn_wg_WireGuardJNI
-#define _Included_tech_nevets_tvpn_wg_WireGuardJNI
-#ifdef __cplusplus
-extern "C" {
-#endif
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: installAdapter
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_installAdapter
- (JNIEnv *, jobject);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: removeAdapter
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_removeAdapter
- (JNIEnv *, jobject);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: startTunnel
- * Signature: (Ljava/lang/String;)I
- */
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_startTunnel
- (JNIEnv *, jobject, jstring);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: stopTunnel
- * Signature: (Ljava/lang/String;)I
- */
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_stopTunnel
- (JNIEnv *, jobject, jstring);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: createTunnel
- * Signature: (Ljava/lang/String;)I
- */
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_createTunnel
- (JNIEnv *, jobject, jstring);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: deleteTunnel
- * Signature: (Ljava/lang/String;)I
- */
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_deleteTunnel
- (JNIEnv *, jobject, jstring);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: getConfig
- * Signature: (Ljava/lang/String;)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_getConfig
- (JNIEnv *, jobject, jstring);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: updateConfig
- * Signature: (Ljava/lang/String;Ljava/lang/String;)I
- */
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_updateConfig
- (JNIEnv *, jobject, jstring, jstring);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: addConfig
- * Signature: (Ljava/lang/String;Ljava/lang/String;)I
- */
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_addConfig
- (JNIEnv *, jobject, jstring, jstring);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: getActiveTunnel
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_getActiveTunnel
- (JNIEnv *, jobject);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: isActive
- * Signature: ()Z
- */
-JNIEXPORT jboolean JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_isActive
- (JNIEnv *, jobject);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: initializeWireGuard
- * Signature: (Ljava/lang/String;)I
- */
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_initializeWireGuard
- (JNIEnv *, jobject, jstring);
-
-/*
- * Class: tech_nevets_tvpn_wg_WireGuardJNI
- * Method: cleanup
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_cleanup
- (JNIEnv *, jobject);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/src/main/cpp/wireguard_wrapper.c b/src/main/cpp/wireguard_wrapper.c
index 22e0bb4..8af66fb 100644
--- a/src/main/cpp/wireguard_wrapper.c
+++ b/src/main/cpp/wireguard_wrapper.c
@@ -1,28 +1,133 @@
#include
+#include
#include
+#include
+#include
#include
#include
#include "wireguard.h"
-#include
#include "tech_nevets_tvpn_wg_WireGuardJNI.h"
-const char *APP_DIR = "C:\\Program Files\\TVPN\\";
+#pragma comment(lib, "Rpcrt4.lib")
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_createTunnel(JNIEnv *env, jobject obj, jstring tunnelName) {
- const char *tunnelCharArr = (*env)->GetStringUTFChars(env, tunnelName, NULL);
- if (tunnelCharArr == NULL) {
- return 1;
+const wchar_t *APP_DIR = L"C:\\Program Files\\TVPN\\";
+
+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;
+
+static HMODULE InitializeWireGuardNT(void) {
+ HMODULE WireGuardDll = LoadLibraryExW(
+ L"wireguard.dll",
+ NULL,
+ LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32
+ );
+ if (!WireGuardDll) return NULL;
+#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 NULL;
+ }
+ return WireGuardDll;
+}
+
+GUID generateGUID() {
+ UUID uuid;
+ RPC_STATUS status = UuidCreate(&uuid);
+
+ // Handle GUID generation error
+ if (status != RPC_S_OK) {
+ fprintf(stderr, "[C] Failed to create GUID\n");
+ exit(1); // Exiting here to indicate a critical error; you may handle differently
}
- char *initialServiceName = "WireGuardTunnel$";
- char *tnlName = malloc(strlen(initialServiceName) + strlen(tunnelCharArr) + 1);
- strcpy(tnlName, initialServiceName);
- strcat(tnlName, tunnelCharArr);
+ // Copy the generated UUID into a GUID struct
+ GUID guid = { uuid.Data1, uuid.Data2, uuid.Data3 };
+ for (int i = 0; i < 8; i++) {
+ guid.Data4[i] = uuid.Data4[i];
+ }
- char *initialDisplayName = "WireGuard Tunnel: ";
- char *displayName = malloc(strlen(initialDisplayName) + strlen(tunnelCharArr) + 1);
- strcpy(displayName, initialDisplayName);
- strcat(displayName, tunnelCharArr);
+ return guid;
+}
+
+JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_installAdapter(JNIEnv *env, jobject obj) {
+ HMODULE WireGuardDLL = InitializeWireGuardNT();
+
+ GUID guid = generateGUID();
+ WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardCreateAdapter(L"TVPNet", L"WireGuard", &guid);
+
+ struct {
+ 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
+ }
+ };
+
+ WireGuardSetConfiguration(Adapter, &Config.Interface, sizeof(Config));
+ WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE_UP);
+
+ FreeLibrary(WireGuardDLL);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_removeAdapter(JNIEnv *env, jobject obj) {
+ HMODULE WireGuardDLL = InitializeWireGuardNT();
+
+ WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(L"TVPNet");
+
+ printf("[C] Closing Adapter...\n");
+ WireGuardCloseAdapter(Adapter);
+
+ FreeLibrary(WireGuardDLL);
+ return 0;
+}
+
+JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_installTunnel(JNIEnv *env, jobject obj, jstring tunnelName, jstring pathToConfig) {
+ printf("[C] Started installTunnel\n");
+
+ const jchar *rawStr = (*env)->GetStringChars(env, tunnelName, 0); //TODO mem cleanup
+ LPWSTR tnlName = (LPWSTR) rawStr;
+
+ wprintf(L"[C] Tunnel Name: %ls", tnlName);
+
+ wchar_t *servicePrefix = L"WireGuardTunnel$";
+ wchar_t *serviceName = malloc(sizeof(wchar_t) * (wcslen(servicePrefix) + wcslen(tnlName) + 1)); //TODO mem cleanup
+ wcscpy(serviceName, servicePrefix);
+ wcscat(serviceName, tnlName);
+
+ wchar_t *displayNamePrefix = L"WireGuard Tunnel: ";
+ wchar_t *displayName = malloc(sizeof(wchar_t) * (wcslen(displayNamePrefix) + wcslen(tnlName) + 1)); //TODO mem cleanup
+ wcscpy(displayName, displayNamePrefix);
+ wcscat(displayName, tnlName);
+
+ printf("[C] Opening Service Manager\n");
SC_HANDLE hSCManager = OpenSCManager(
NULL,
@@ -30,21 +135,23 @@ JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_createTunnel(JNIEnv
SC_MANAGER_ALL_ACCESS
);
if (hSCManager == NULL) {
- printf("OpenSCManager failed (%lu)\n", GetLastError());
- return 2;
+ printf("[C] OpenSCManager failed (%lu)\n", GetLastError());
+ return 3;
}
- char *params = "TVPN.exe /installtunnelservice ";
- char *conf = ".conf";
- char *exePath = malloc(strlen(APP_DIR) + strlen(params) + strlen(tunnelCharArr) + strlen(conf) + 1);
- strcpy(exePath, APP_DIR);
- strcat(exePath, params);
- strcat(exePath, tunnelCharArr);
- strcat(exePath, conf);
+ wchar_t *params = L"TVPN.exe /installtunnelservice ";
+ wchar_t *conf = L".conf";
+ wchar_t *exePath = malloc(sizeof(wchar_t) * (wcslen(APP_DIR) + wcslen(params) + wcslen(tnlName) + wcslen(conf) + 1)); //TODO mem cleanup
+ wcscpy(exePath, APP_DIR);
+ wcscat(exePath, params);
+ wcscat(exePath, tnlName);
+ wcscat(exePath, conf);
- SC_HANDLE hService = CreateServiceA(
+ wprintf(L"[C] Creating Service: %ls\n", exePath);
+
+ SC_HANDLE hService = CreateServiceW(
hSCManager,
- tnlName,
+ serviceName,
displayName,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
@@ -53,42 +160,62 @@ JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_createTunnel(JNIEnv
exePath,
NULL,
NULL,
- "Nsi\0TcpIp\0\0",
+ L"Nsi\0TcpIp\0\0",
NULL,
NULL
- );
+ );
DWORD sid_info = SERVICE_SID_TYPE_UNRESTRICTED;
- if (!ChangeServiceConfig2A(hService, SERVICE_CONFIG_SERVICE_SID_INFO, &sid_info)) {
- printf("ChangeServiceConfig2W failed (%lu)\n", GetLastError());
- (*env)->ReleaseStringUTFChars(env, tunnelName, tunnelCharArr);
- free(tnlName);
+ printf("[C] Changing Service Config\n");
+
+ if (!ChangeServiceConfig2W(hService, SERVICE_CONFIG_SERVICE_SID_INFO, &sid_info)) {
+ printf("[C] ChangeServiceConfig2W failed (%lu)\n", GetLastError());
+ (*env)->ReleaseStringChars(env, tunnelName, rawStr);
+ free(serviceName);
free(displayName);
free(exePath);
CloseServiceHandle(hSCManager);
CloseServiceHandle(hService);
- return 3;
+ return 4;
}
+ printf("[C] Cleaning up creation\n");
- (*env)->ReleaseStringUTFChars(env, tunnelName, tunnelCharArr);
- free(tnlName);
- free(displayName);
- free(exePath);
CloseServiceHandle(hSCManager);
CloseServiceHandle(hService);
+ free(serviceName);
+ free(displayName);
+ free(exePath);
+ (*env)->ReleaseStringChars(env, tunnelName, rawStr);
- return 0;
+ printf("[C] Loading tunnel.dll\n");
+
+ HMODULE tunnel_lib = LoadLibrary("tunnel.dll");
+ if (!tunnel_lib) abort();
+
+ BOOL (_cdecl *tunnel_proc) (_In_ LPCWSTR conf_file);
+ *(FARPROC*) &tunnel_proc = GetProcAddress(tunnel_lib, "WireGuardTunnelService");
+ if (!tunnel_proc) abort();
+
+ const jchar *rawString = (*env)->GetStringChars(env, pathToConfig, NULL);
+ LPCWSTR configPath = (LPCWSTR) rawString;
+
+ //TODO figure out how to handle this
+ //(*env)->ReleaseStringChars(env, tunnelName, rawStr);
+
+ wprintf(L"[C] Calling function with arg: %ls\n", configPath);
+
+ return tunnel_proc(configPath);
}
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_deleteTunnel(JNIEnv *env, jobject obj, jstring tunnelName) {
- const char *nativeString = (*env)->GetStringUTFChars(env, tunnelName, NULL);
+JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_removeTunnel(JNIEnv *env, jobject obj, jstring tunnelName) {
+ const jchar *nativeString = (*env)->GetStringChars(env, tunnelName, NULL);
- char *initialServiceName = "WireGuardTunnel$";
- char *tnlName = malloc(strlen(initialServiceName) + strlen(nativeString) + 1);
- strcpy(tnlName, initialServiceName);
- strcat(tnlName, nativeString);
+ wchar_t *initialServiceName = L"WireGuardTunnel$";
+ wchar_t *tnlName = malloc(sizeof(wchar_t) * (wcslen(initialServiceName) + wcslen(nativeString) + 1));
+ wcscpy(tnlName, initialServiceName);
+ wcscat(tnlName, nativeString);
SC_HANDLE hSCManager = OpenSCManager(
NULL,
@@ -100,7 +227,7 @@ JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_deleteTunnel(JNIEnv
return 1;
}
- SC_HANDLE hService = OpenServiceA(hSCManager, tnlName, DELETE);
+ SC_HANDLE hService = OpenServiceW(hSCManager, tnlName, DELETE);
if (hService != NULL) {
if (!DeleteService(hService)) {
// Handle error
@@ -113,49 +240,8 @@ JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_deleteTunnel(JNIEnv
}
CloseServiceHandle(hSCManager);
- (*env)->ReleaseStringUTFChars(env, tunnelName, nativeString);
+ (*env)->ReleaseStringChars(env, tunnelName, nativeString);
free(tnlName);
return 0;
-}
-
-JNIEXPORT jint JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_initializeWireGuard(JNIEnv *env, jobject obj, jstring configFilePath) {
- const char *nativeString = (*env)->GetStringUTFChars(env, configFilePath, 0);
-
- int confLength = strlen(nativeString);
-
- (*env)->ReleaseStringUTFChars(env, configFilePath, nativeString);
-
- return confLength;
-
-// const char *nativeConfigFilePath = (*env)->GetStringUTFChars(env, configFilePath, 0);
-
- // Load the WireGuard DLL dynamically
-// hInstLibrary = LoadLibrary("tunnel.dll"); // Adjust with the actual DLL name
-
-// if (hInstLibrary) {
- // Example: Load the WireGuard function from DLL
-// wg_func_t wg_init_func = (wg_func_t) GetProcAddress(hInstLibrary, "WireGuardInitFunction"); // Adjust based on the WireGuard API
-
-
-// if (wg_init_func) {
-// wg_init_func(nativeConfigFilePath);
-// (*env)->ReleaseStringUTFChars(env, configFilePath, nativeConfigFilePath);
-// return 0; // Success
-// } else {
-// printf("Failed to get function from WireGuard DLL\n");
-// return -2; // Failed to get function
-// }
-// } else {
-// printf("Failed to load WireGuard DLL\n");
-// return -1; // Failed to load DLL
-// }
-}
-
-JNIEXPORT void JNICALL Java_tech_nevets_tvpn_wg_WireGuardJNI_cleanup(JNIEnv *env, jobject obj) {
- printf("Silly goose, this isn't implemented yet!\n");
-
-// if (hInstLibrary) {
-// FreeLibrary(hInstLibrary);
-// }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/tech/nevets/tvpn/Main.java b/src/main/java/tech/nevets/tvpn/Main.java
index 185ec85..b01e2cb 100644
--- a/src/main/java/tech/nevets/tvpn/Main.java
+++ b/src/main/java/tech/nevets/tvpn/Main.java
@@ -1,6 +1,8 @@
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;
@@ -9,11 +11,16 @@ import java.io.File;
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("");
+
+ if (args.length > 0) {
+ new CommandBrigadier().execute(args);
+ }
+
try {
javax.swing.UIManager.setLookAndFeel(new FlatDarkLaf());
} catch (UnsupportedLookAndFeelException e) {
@@ -26,9 +33,8 @@ public class Main {
UIManager uim = new UIManager(logOut);
uim.startLoginFrame();
- WireGuardJNI wgjni = new WireGuardJNI();
+ //WireGuardJNI wgjni = new WireGuardJNI();
//System.out.println(wgjni.createTunnel("test"));
- System.out.println(wgjni.deleteTunnel("test"));
+ //System.out.println(wgjni.removeTunnel("test"));
}
-
}
diff --git a/src/main/java/tech/nevets/tvpn/Utils.java b/src/main/java/tech/nevets/tvpn/Utils.java
index 5e10dd8..b388a8f 100644
--- a/src/main/java/tech/nevets/tvpn/Utils.java
+++ b/src/main/java/tech/nevets/tvpn/Utils.java
@@ -1,5 +1,7 @@
package tech.nevets.tvpn;
+import tech.nevets.jconf.JsonConfig;
+
import java.io.File;
import java.io.IOException;
import java.net.URI;
@@ -10,14 +12,24 @@ import java.util.Map;
public class Utils {
private static final Logger LOGGER = new Logger(Utils.class);
- public static final File APP_DIR = new File("./tvpn/");
+
public static final String WG_CONF_DIR = "C:\\Program Files\\WireGuard\\Data\\Configurations\\";
- public static final String API_ENDPOINT_BASE = "http://tvpn.lan/testing/";
+ public static final File APP_DIR = new File("C:\\Program Files\\TVPN\\");
+ public static final JsonConfig CONFIG = new JsonConfig(APP_DIR + "/config.json", getConfStr());
+ public static final String API_ENDPOINT_BASE = CONFIG.getString("apiEndpoint");
static {
if (!APP_DIR.exists()) APP_DIR.mkdirs();
}
+ private static String getConfStr() {
+ return """
+ {
+ "apiEndpoint":"http://tvpn.lan"
+ }
+ """;
+ }
+
public static String get(URI url, Map headers) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest.Builder reqBuilder = HttpRequest.newBuilder()
diff --git a/src/main/java/tech/nevets/tvpn/cli/Command.java b/src/main/java/tech/nevets/tvpn/cli/Command.java
new file mode 100644
index 0000000..64f0e28
--- /dev/null
+++ b/src/main/java/tech/nevets/tvpn/cli/Command.java
@@ -0,0 +1,12 @@
+package tech.nevets.tvpn.cli;
+
+public interface Command {
+
+ void execute(String[] args);
+
+ String getName();
+
+ String getUsage();
+
+ String getDescription();
+}
diff --git a/src/main/java/tech/nevets/tvpn/cli/CommandBrigadier.java b/src/main/java/tech/nevets/tvpn/cli/CommandBrigadier.java
new file mode 100644
index 0000000..b09f4f5
--- /dev/null
+++ b/src/main/java/tech/nevets/tvpn/cli/CommandBrigadier.java
@@ -0,0 +1,49 @@
+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 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 getCommands() {
+ return registeredCommands;
+ }
+}
diff --git a/src/main/java/tech/nevets/tvpn/cli/commands/HelpCmd.java b/src/main/java/tech/nevets/tvpn/cli/commands/HelpCmd.java
new file mode 100644
index 0000000..366a69e
--- /dev/null
+++ b/src/main/java/tech/nevets/tvpn/cli/commands/HelpCmd.java
@@ -0,0 +1,52 @@
+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";
+ }
+}
diff --git a/src/main/java/tech/nevets/tvpn/cli/commands/InstallTunnelServiceCmd.java b/src/main/java/tech/nevets/tvpn/cli/commands/InstallTunnelServiceCmd.java
new file mode 100644
index 0000000..6602669
--- /dev/null
+++ b/src/main/java/tech/nevets/tvpn/cli/commands/InstallTunnelServiceCmd.java
@@ -0,0 +1,71 @@
+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();
+ }
+}
diff --git a/src/main/java/tech/nevets/tvpn/cli/commands/UninstallTunnelServiceCmd.java b/src/main/java/tech/nevets/tvpn/cli/commands/UninstallTunnelServiceCmd.java
new file mode 100644
index 0000000..9f812e0
--- /dev/null
+++ b/src/main/java/tech/nevets/tvpn/cli/commands/UninstallTunnelServiceCmd.java
@@ -0,0 +1,28 @@
+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";
+ }
+}
diff --git a/src/main/java/tech/nevets/tvpn/ui/UIManager.java b/src/main/java/tech/nevets/tvpn/ui/UIManager.java
index fa01607..c38efd3 100644
--- a/src/main/java/tech/nevets/tvpn/ui/UIManager.java
+++ b/src/main/java/tech/nevets/tvpn/ui/UIManager.java
@@ -13,7 +13,7 @@ public class UIManager {
public UIManager(LogOutputStream logOut) {
frame = new JFrame();
- tabPane = new JTabbedPane();
+ tabPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
homePanel = new HomePanel();
tabPane.addTab("Home", homePanel);
diff --git a/src/main/java/tech/nevets/tvpn/wg/WireGuardJNI.java b/src/main/java/tech/nevets/tvpn/wg/WireGuardJNI.java
index 328649b..5251a65 100644
--- a/src/main/java/tech/nevets/tvpn/wg/WireGuardJNI.java
+++ b/src/main/java/tech/nevets/tvpn/wg/WireGuardJNI.java
@@ -10,10 +10,14 @@ public class WireGuardJNI {
public native int installAdapter();
public native int removeAdapter();
- public native int startTunnel(String tunnelName);
- public native int stopTunnel(String tunnelName);
- public native int createTunnel(String tunnelName);
- public native int deleteTunnel(String tunnelName);
+ /**
+ * Creates and starts the WireGuard service
+ * @param tunnelName Name of the tunnel
+ * @param pathToConfig Full path to the tunnel's configuration file
+ * @return 0 if successful, 1 if failed
+ */
+ public native int installTunnel(String tunnelName, String pathToConfig);
+ public native int removeTunnel(String tunnelName);
public native String getConfig(String tunnelName);
public native int updateConfig(String tunnelName, String newConfig);
diff --git a/src/main/resources/icon.ico b/src/main/resources/icon.ico
new file mode 100644
index 0000000..9df27e0
Binary files /dev/null and b/src/main/resources/icon.ico differ
diff --git a/src/main/resources/icon.png b/src/main/resources/icon.png
new file mode 100644
index 0000000..827f8ef
Binary files /dev/null and b/src/main/resources/icon.png differ