diff --git a/client/android/wireguard/CMakeLists.txt b/client/android/wireguard/CMakeLists.txt new file mode 100644 index 00000000..00389300 --- /dev/null +++ b/client/android/wireguard/CMakeLists.txt @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright © 2018-2019 WireGuard LLC. All Rights Reserved. + +cmake_minimum_required(VERSION 3.4.1) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") + +message("PROJECT_SOURCE_DIR ${PROJECT_SOURCE_DIR}") +set( CMAKE_WG_TOOLS_DIR ../../../desktop-client/client/3rd/wireguard-tools ) + + +find_program(CCACHE_FOUND ccache) +if(CCACHE_FOUND) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) +endif(CCACHE_FOUND) + +# Work around https://github.com/android-ndk/ndk/issues/602 +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold") + +add_executable(libwg-quick.so ${CMAKE_WG_TOOLS_DIR}/src/wg-quick/android.c ndk-compat/compat.c) +target_compile_options(libwg-quick.so PUBLIC -O3 -std=gnu11 -Wall -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DWG_PACKAGE_NAME=\"${ANDROID_PACKAGE_NAME}\") +target_link_libraries(libwg-quick.so -ldl) + +file(GLOB WG_SOURCES ${CMAKE_WG_TOOLS_DIR}/src/*.c ndk-compat/compat.c) +add_executable(libwg.so ${WG_SOURCES}) +target_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_WG_TOOLS_DIR}/src/uapi/linux/" "${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_WG_TOOLS_DIR}/src/") +target_compile_options(libwg.so PUBLIC -O3 -std=gnu11 -D_GNU_SOURCE -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DHAVE_VISIBILITY_HIDDEN -DRUNSTATEDIR=\"/data/data/${ANDROID_PACKAGE_NAME}/cache\") + +add_custom_target(libwg-go.so WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libwg-go" COMMENT "Building wireguard-go" + ANDROID_ARCH_NAME=${ANDROID_ARCH_NAME} + ANDROID_C_COMPILER=${ANDROID_C_COMPILER} + ANDROID_TOOLCHAIN_ROOT=${ANDROID_TOOLCHAIN_ROOT} + ANDROID_LLVM_TRIPLE=${ANDROID_LLVM_TRIPLE} + ANDROID_SYSROOT=${ANDROID_SYSROOT} + ANDROID_PACKAGE_NAME=${ANDROID_PACKAGE_NAME} + GRADLE_USER_HOME=${GRADLE_USER_HOME} + CFLAGS=${CMAKE_C_FLAGS}\ -Wno-unused-command-line-argument + LDFLAGS=${CMAKE_SHARED_LINKER_FLAGS}\ -fuse-ld=gold + DESTDIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + BUILDDIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/../generated-src +) +# Hack to make it actually build as part of the default target +add_dependencies(libwg.so libwg-go.so) diff --git a/client/android/wireguard/libwg-go/api-android.go b/client/android/wireguard/libwg-go/api-android.go new file mode 100644 index 00000000..6d0802ff --- /dev/null +++ b/client/android/wireguard/libwg-go/api-android.go @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: Apache-2.0 + * + * Copyright (C) 2017-2019 Jason A. Donenfeld . All Rights Reserved. + */ + +package main + +// #cgo LDFLAGS: -llog +// #include +import "C" + +import ( + "fmt" + "math" + "net" + "os" + "os/signal" + "runtime" + "runtime/debug" + "strings" + "unsafe" + + "golang.org/x/sys/unix" + "golang.zx2c4.com/wireguard/conn" + "golang.zx2c4.com/wireguard/device" + "golang.zx2c4.com/wireguard/ipc" + "golang.zx2c4.com/wireguard/tun" +) + +type AndroidLogger struct { + level C.int + tag *C.char +} + +func cstring(s string) *C.char { + b, err := unix.BytePtrFromString(s) + if err != nil { + b := [1]C.char{} + return &b[0] + } + return (*C.char)(unsafe.Pointer(b)) +} + +func (l AndroidLogger) Printf(format string, args ...interface{}) { + C.__android_log_write(l.level, l.tag, cstring(fmt.Sprintf(format, args...))) +} + +type TunnelHandle struct { + device *device.Device + uapi net.Listener +} + +var tunnelHandles map[int32]TunnelHandle + +func init() { + tunnelHandles = make(map[int32]TunnelHandle) + signals := make(chan os.Signal) + signal.Notify(signals, unix.SIGUSR2) + go func() { + buf := make([]byte, os.Getpagesize()) + for { + select { + case <-signals: + n := runtime.Stack(buf, true) + if n == len(buf) { + n-- + } + buf[n] = 0 + C.__android_log_write(C.ANDROID_LOG_ERROR, cstring("WireGuard/GoBackend/Stacktrace"), (*C.char)(unsafe.Pointer(&buf[0]))) + } + } + }() +} + +//export wgTurnOn +func wgTurnOn(interfaceName string, tunFd int32, settings string) int32 { + tag := cstring("WireGuard/GoBackend/" + interfaceName) + logger := &device.Logger{ + Verbosef: AndroidLogger{level: C.ANDROID_LOG_DEBUG, tag: tag}.Printf, + Errorf: AndroidLogger{level: C.ANDROID_LOG_ERROR, tag: tag}.Printf, + } + + tun, name, err := tun.CreateUnmonitoredTUNFromFD(int(tunFd)) + if err != nil { + unix.Close(int(tunFd)) + logger.Errorf("CreateUnmonitoredTUNFromFD: %v", err) + return -1 + } + + logger.Verbosef("Attaching to interface %v", name) + device := device.NewDevice(tun, conn.NewStdNetBind(), logger) + + err = device.IpcSet(settings) + if err != nil { + unix.Close(int(tunFd)) + logger.Errorf("IpcSet: %v", err) + return -1 + } + device.DisableSomeRoamingForBrokenMobileSemantics() + + var uapi net.Listener + + uapiFile, err := ipc.UAPIOpen(name) + if err != nil { + logger.Errorf("UAPIOpen: %v", err) + } else { + uapi, err = ipc.UAPIListen(name, uapiFile) + if err != nil { + uapiFile.Close() + logger.Errorf("UAPIListen: %v", err) + } else { + go func() { + for { + conn, err := uapi.Accept() + if err != nil { + return + } + go device.IpcHandle(conn) + } + }() + } + } + + err = device.Up() + if err != nil { + logger.Errorf("Unable to bring up device: %v", err) + uapiFile.Close() + device.Close() + return -1 + } + logger.Verbosef("Device started") + + var i int32 + for i = 0; i < math.MaxInt32; i++ { + if _, exists := tunnelHandles[i]; !exists { + break + } + } + if i == math.MaxInt32 { + logger.Errorf("Unable to find empty handle") + uapiFile.Close() + device.Close() + return -1 + } + tunnelHandles[i] = TunnelHandle{device: device, uapi: uapi} + return i +} + +//export wgTurnOff +func wgTurnOff(tunnelHandle int32) { + handle, ok := tunnelHandles[tunnelHandle] + if !ok { + return + } + delete(tunnelHandles, tunnelHandle) + if handle.uapi != nil { + handle.uapi.Close() + } + handle.device.Close() +} + +//export wgGetSocketV4 +func wgGetSocketV4(tunnelHandle int32) int32 { + handle, ok := tunnelHandles[tunnelHandle] + if !ok { + return -1 + } + bind, _ := handle.device.Bind().(conn.PeekLookAtSocketFd) + if bind == nil { + return -1 + } + fd, err := bind.PeekLookAtSocketFd4() + if err != nil { + return -1 + } + return int32(fd) +} + +//export wgGetSocketV6 +func wgGetSocketV6(tunnelHandle int32) int32 { + handle, ok := tunnelHandles[tunnelHandle] + if !ok { + return -1 + } + bind, _ := handle.device.Bind().(conn.PeekLookAtSocketFd) + if bind == nil { + return -1 + } + fd, err := bind.PeekLookAtSocketFd6() + if err != nil { + return -1 + } + return int32(fd) +} + +//export wgGetConfig +func wgGetConfig(tunnelHandle int32) *C.char { + handle, ok := tunnelHandles[tunnelHandle] + if !ok { + return nil + } + settings, err := handle.device.IpcGet() + if err != nil { + return nil + } + return C.CString(settings) +} + +//export wgVersion +func wgVersion() *C.char { + info, ok := debug.ReadBuildInfo() + if !ok { + return C.CString("unknown") + } + for _, dep := range info.Deps { + if dep.Path == "golang.zx2c4.com/wireguard" { + parts := strings.Split(dep.Version, "-") + if len(parts) == 3 && len(parts[2]) == 12 { + return C.CString(parts[2][:7]) + } + return C.CString(dep.Version) + } + } + return C.CString("unknown") +} + +func main() {} diff --git a/client/android/wireguard/libwg-go/go.mod b/client/android/wireguard/libwg-go/go.mod new file mode 100644 index 00000000..280e464e --- /dev/null +++ b/client/android/wireguard/libwg-go/go.mod @@ -0,0 +1,10 @@ +module golang.zx2c4.com/wireguard/android + +go 1.16 + +require ( + golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect + golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d // indirect + golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 + golang.zx2c4.com/wireguard v0.0.0-20210222142647-219296a1e787 +) diff --git a/client/android/wireguard/libwg-go/go.sum b/client/android/wireguard/libwg-go/go.sum new file mode 100644 index 00000000..b3df2480 --- /dev/null +++ b/client/android/wireguard/libwg-go/go.sum @@ -0,0 +1,21 @@ +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d h1:1aflnvSoWWLI2k/dMUAl5lvU1YO4Mb4hz0gh+1rjcxU= +golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 h1:SgQ6LNaYJU0JIuEHv9+s6EbhSCwYeAf5Yvj6lpYlqAE= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.zx2c4.com/wireguard v0.0.0-20210222142647-219296a1e787 h1:zrctiUlt4hD1sgxBYrG5CAjobVhpdxnUXy+qyWWLR1w= +golang.zx2c4.com/wireguard v0.0.0-20210222142647-219296a1e787/go.mod h1:LofpIKqPJNvHiwKXuzsBshJCTe7IgRAz3iizquljFDk= diff --git a/client/android/wireguard/libwg-go/goruntime-boottime-over-monotonic.diff b/client/android/wireguard/libwg-go/goruntime-boottime-over-monotonic.diff new file mode 100644 index 00000000..5cbc2256 --- /dev/null +++ b/client/android/wireguard/libwg-go/goruntime-boottime-over-monotonic.diff @@ -0,0 +1,161 @@ +From b83553d9f260ba20c6faaa52e6fe6f74309eb41a Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 22 Feb 2021 02:36:03 +0100 +Subject: [PATCH] runtime: use CLOCK_BOOTTIME in nanotime on Linux + +This makes timers account for having expired while a computer was +asleep, which is quite common on mobile devices. Note that BOOTTIME is +identical to MONOTONIC, except that it takes into account time spent +in suspend. In Linux 4.17, the kernel will actually make MONOTONIC act +like BOOTTIME anyway, so this switch will additionally unify the +timer behavior across kernels. + +BOOTTIME was introduced into Linux 2.6.39-rc1 with 70a08cca1227d in +2011. + +Fixes #24595 + +Change-Id: I7b2a6ca0c5bc5fce57ec0eeafe7b68270b429321 +--- + src/runtime/sys_linux_386.s | 4 ++-- + src/runtime/sys_linux_amd64.s | 2 +- + src/runtime/sys_linux_arm.s | 4 ++-- + src/runtime/sys_linux_arm64.s | 4 ++-- + src/runtime/sys_linux_mips64x.s | 2 +- + src/runtime/sys_linux_mipsx.s | 2 +- + src/runtime/sys_linux_ppc64x.s | 2 +- + src/runtime/sys_linux_s390x.s | 2 +- + 8 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s +index 1e3a834812..78b6021fc7 100644 +--- a/src/runtime/sys_linux_386.s ++++ b/src/runtime/sys_linux_386.s +@@ -337,13 +337,13 @@ noswitch: + + LEAL 8(SP), BX // &ts (struct timespec) + MOVL BX, 4(SP) +- MOVL $1, 0(SP) // CLOCK_MONOTONIC ++ MOVL $7, 0(SP) // CLOCK_BOOTTIME + CALL AX + JMP finish + + fallback: + MOVL $SYS_clock_gettime, AX +- MOVL $1, BX // CLOCK_MONOTONIC ++ MOVL $7, BX // CLOCK_BOOTTIME + LEAL 8(SP), CX + INVOKE_SYSCALL + +diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s +index 37cb8dad03..e8b730bcaa 100644 +--- a/src/runtime/sys_linux_amd64.s ++++ b/src/runtime/sys_linux_amd64.s +@@ -302,7 +302,7 @@ noswitch: + SUBQ $16, SP // Space for results + ANDQ $~15, SP // Align for C code + +- MOVL $1, DI // CLOCK_MONOTONIC ++ MOVL $7, DI // CLOCK_BOOTTIME + LEAQ 0(SP), SI + MOVQ runtime·vdsoClockgettimeSym(SB), AX + CMPQ AX, $0 +diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s +index 475f52344c..bb567abcf4 100644 +--- a/src/runtime/sys_linux_arm.s ++++ b/src/runtime/sys_linux_arm.s +@@ -11,7 +11,7 @@ + #include "textflag.h" + + #define CLOCK_REALTIME 0 +-#define CLOCK_MONOTONIC 1 ++#define CLOCK_BOOTTIME 7 + + // for EABI, as we don't support OABI + #define SYS_BASE 0x0 +@@ -366,7 +366,7 @@ noswitch: + SUB $24, R13 // Space for results + BIC $0x7, R13 // Align for C code + +- MOVW $CLOCK_MONOTONIC, R0 ++ MOVW $CLOCK_BOOTTIME, R0 + MOVW $8(R13), R1 // timespec + MOVW runtime·vdsoClockgettimeSym(SB), R2 + CMP $0, R2 +diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s +index 198a5bacef..9715387f36 100644 +--- a/src/runtime/sys_linux_arm64.s ++++ b/src/runtime/sys_linux_arm64.s +@@ -13,7 +13,7 @@ + #define AT_FDCWD -100 + + #define CLOCK_REALTIME 0 +-#define CLOCK_MONOTONIC 1 ++#define CLOCK_BOOTTIME 7 + + #define SYS_exit 93 + #define SYS_read 63 +@@ -319,7 +319,7 @@ noswitch: + BIC $15, R1 + MOVD R1, RSP + +- MOVW $CLOCK_MONOTONIC, R0 ++ MOVW $CLOCK_BOOTTIME, R0 + MOVD runtime·vdsoClockgettimeSym(SB), R2 + CBZ R2, fallback + +diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s +index c3e9f37694..e3879acd38 100644 +--- a/src/runtime/sys_linux_mips64x.s ++++ b/src/runtime/sys_linux_mips64x.s +@@ -312,7 +312,7 @@ noswitch: + AND $~15, R1 // Align for C code + MOVV R1, R29 + +- MOVW $1, R4 // CLOCK_MONOTONIC ++ MOVW $7, R4 // CLOCK_BOOTTIME + MOVV $0(R29), R5 + + MOVV runtime·vdsoClockgettimeSym(SB), R25 +diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s +index fab2ab3892..f9af103594 100644 +--- a/src/runtime/sys_linux_mipsx.s ++++ b/src/runtime/sys_linux_mipsx.s +@@ -238,7 +238,7 @@ TEXT runtime·walltime1(SB),NOSPLIT,$8-12 + RET + + TEXT runtime·nanotime1(SB),NOSPLIT,$8-8 +- MOVW $1, R4 // CLOCK_MONOTONIC ++ MOVW $7, R4 // CLOCK_BOOTTIME + MOVW $4(R29), R5 + MOVW $SYS_clock_gettime, R2 + SYSCALL +diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s +index fd69ee70a5..ff6bc8355b 100644 +--- a/src/runtime/sys_linux_ppc64x.s ++++ b/src/runtime/sys_linux_ppc64x.s +@@ -249,7 +249,7 @@ fallback: + JMP finish + + TEXT runtime·nanotime1(SB),NOSPLIT,$16-8 +- MOVD $1, R3 // CLOCK_MONOTONIC ++ MOVD $7, R3 // CLOCK_BOOTTIME + + MOVD R1, R15 // R15 is unchanged by C code + MOVD g_m(g), R21 // R21 = m +diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s +index c15a1d5364..f52c4d5098 100644 +--- a/src/runtime/sys_linux_s390x.s ++++ b/src/runtime/sys_linux_s390x.s +@@ -207,7 +207,7 @@ TEXT runtime·walltime1(SB),NOSPLIT,$16 + RET + + TEXT runtime·nanotime1(SB),NOSPLIT,$16 +- MOVW $1, R2 // CLOCK_MONOTONIC ++ MOVW $7, R2 // CLOCK_BOOTTIME + MOVD $tp-16(SP), R3 + MOVW $SYS_clock_gettime, R1 + SYSCALL +-- +2.30.1 + diff --git a/client/android/wireguard/libwg-go/jni.c b/client/android/wireguard/libwg-go/jni.c new file mode 100644 index 00000000..372c788b --- /dev/null +++ b/client/android/wireguard/libwg-go/jni.c @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: Apache-2.0 + * + * Copyright © 2017-2019 Jason A. Donenfeld . All Rights + * Reserved. + */ + +#include +#include +#include + +struct go_string { + const char* str; + long n; +}; +extern int wgTurnOn(struct go_string ifname, int tun_fd, + struct go_string settings); +extern void wgTurnOff(int handle); +extern int wgGetSocketV4(int handle); +extern int wgGetSocketV6(int handle); +extern char* wgGetConfig(int handle); +extern char* wgVersion(); + +JNIEXPORT jint JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgTurnOn( + JNIEnv* env, jclass c, jstring ifname, jint tun_fd, jstring settings) { + const char* ifname_str = (*env)->GetStringUTFChars(env, ifname, 0); + size_t ifname_len = (*env)->GetStringUTFLength(env, ifname); + const char* settings_str = (*env)->GetStringUTFChars(env, settings, 0); + size_t settings_len = (*env)->GetStringUTFLength(env, settings); + int ret = + wgTurnOn((struct go_string){.str = ifname_str, .n = ifname_len}, tun_fd, + (struct go_string){.str = settings_str, .n = settings_len}); + (*env)->ReleaseStringUTFChars(env, ifname, ifname_str); + (*env)->ReleaseStringUTFChars(env, settings, settings_str); + return ret; +} + +JNIEXPORT void JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgTurnOff( + JNIEnv* env, jclass c, jint handle) { + wgTurnOff(handle); +} + +JNIEXPORT jint JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgGetSocketV4( + JNIEnv* env, jclass c, jint handle) { + return wgGetSocketV4(handle); +} + +JNIEXPORT jint JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgGetSocketV6( + JNIEnv* env, jclass c, jint handle) { + return wgGetSocketV6(handle); +} + +JNIEXPORT jstring JNICALL Java_org_mozilla_firefox_vpn_VPNService_wgGetConfig( + JNIEnv* env, jclass c, jint handle) { + jstring ret; + char* config = wgGetConfig(handle); + if (!config) return NULL; + ret = (*env)->NewStringUTF(env, config); + free(config); + return ret; +} + +JNIEXPORT jstring JNICALL +Java_org_mozilla_firefox_vpn_VPNService_wgVersion(JNIEnv* env, jclass c) { + jstring ret; + char* version = wgVersion(); + if (!version) return NULL; + ret = (*env)->NewStringUTF(env, version); + free(version); + return ret; +} diff --git a/client/android/wireguard/ndk-compat/compat.c b/client/android/wireguard/ndk-compat/compat.c new file mode 100644 index 00000000..09b3febc --- /dev/null +++ b/client/android/wireguard/ndk-compat/compat.c @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: BSD + * + * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. + * + */ + +#define FILE_IS_EMPTY + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 18 +# undef FILE_IS_EMPTY +# include +# include + +ssize_t getdelim(char** buf, size_t* bufsiz, int delimiter, FILE* fp) { + char *ptr, *eptr; + + if (*buf == NULL || *bufsiz == 0) { + *bufsiz = BUFSIZ; + if ((*buf = malloc(*bufsiz)) == NULL) return -1; + } + + for (ptr = *buf, eptr = *buf + *bufsiz;;) { + int c = fgetc(fp); + if (c == -1) { + if (feof(fp)) { + ssize_t diff = (ssize_t)(ptr - *buf); + if (diff != 0) { + *ptr = '\0'; + return diff; + } + } + return -1; + } + *ptr++ = c; + if (c == delimiter) { + *ptr = '\0'; + return ptr - *buf; + } + if (ptr + 2 >= eptr) { + char* nbuf; + size_t nbufsiz = *bufsiz * 2; + ssize_t d = ptr - *buf; + if ((nbuf = realloc(*buf, nbufsiz)) == NULL) return -1; + *buf = nbuf; + *bufsiz = nbufsiz; + eptr = nbuf + nbufsiz; + ptr = nbuf + d; + } + } +} + +ssize_t getline(char** buf, size_t* bufsiz, FILE* fp) { + return getdelim(buf, bufsiz, '\n', fp); +} +#endif + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 24 +# undef FILE_IS_EMPTY +# include + +char* strchrnul(const char* s, int c) { + char* x = strchr(s, c); + if (!x) return (char*)s + strlen(s); + return x; +} +#endif + +#ifdef FILE_IS_EMPTY +# undef FILE_IS_EMPTY +static char ____x __attribute__((unused)); +#endif diff --git a/client/android/wireguard/ndk-compat/compat.h b/client/android/wireguard/ndk-compat/compat.h new file mode 100644 index 00000000..4109ad72 --- /dev/null +++ b/client/android/wireguard/ndk-compat/compat.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: BSD + * + * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. + * + */ + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 18 +# include +ssize_t getdelim(char** buf, size_t* bufsiz, int delimiter, FILE* fp); +ssize_t getline(char** buf, size_t* bufsiz, FILE* fp); +#endif + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 24 +char* strchrnul(const char* s, int c); +#endif