diff options
Diffstat (limited to 'tunnel/tools/libwg-go')
-rw-r--r-- | tunnel/tools/libwg-go/.gitignore | 1 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/Makefile | 35 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/api-android.go | 193 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/go.mod | 10 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/go.sum | 19 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff | 161 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/jni.c | 71 |
7 files changed, 490 insertions, 0 deletions
diff --git a/tunnel/tools/libwg-go/.gitignore b/tunnel/tools/libwg-go/.gitignore new file mode 100644 index 00000000..d1638636 --- /dev/null +++ b/tunnel/tools/libwg-go/.gitignore @@ -0,0 +1 @@ +build/
\ No newline at end of file diff --git a/tunnel/tools/libwg-go/Makefile b/tunnel/tools/libwg-go/Makefile new file mode 100644 index 00000000..5c46df52 --- /dev/null +++ b/tunnel/tools/libwg-go/Makefile @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. + +BUILDDIR ?= $(CURDIR)/build +DESTDIR ?= $(CURDIR)/out + +NDK_GO_ARCH_MAP_x86 := 386 +NDK_GO_ARCH_MAP_x86_64 := amd64 +NDK_GO_ARCH_MAP_arm := arm +NDK_GO_ARCH_MAP_arm64 := arm64 +NDK_GO_ARCH_MAP_mips := mipsx +NDK_GO_ARCH_MAP_mips64 := mips64x + +CLANG_FLAGS := --target=$(ANDROID_LLVM_TRIPLE) --gcc-toolchain=$(ANDROID_TOOLCHAIN_ROOT) --sysroot=$(ANDROID_SYSROOT) +export CGO_CFLAGS := $(CLANG_FLAGS) $(CFLAGS) +export CGO_LDFLAGS := $(CLANG_FLAGS) $(LDFLAGS) +export CC := $(ANDROID_C_COMPILER) +export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME)) +export GOOS := android +export CGO_ENABLED := 1 + +DESIRED_GO_VERSION := 1.13.7 + +default: $(DESTDIR)/libwg-go.so + +$(BUILDDIR)/go-$(DESIRED_GO_VERSION)/.prepared: + mkdir -p "$(dir $@)" + curl "https://dl.google.com/go/go$(DESIRED_GO_VERSION).$(shell uname -s | tr '[:upper:]' '[:lower:]')-$(NDK_GO_ARCH_MAP_$(shell uname -m)).tar.gz" | tar -C "$(dir $@)" --strip-components=1 -xzf - + patch -p1 -f -N -r- -d "$(dir $@)" < goruntime-boottime-over-monotonic.diff + touch "$@" + +$(DESTDIR)/libwg-go.so: export PATH := $(BUILDDIR)/go-$(DESIRED_GO_VERSION)/bin/:$(PATH) +$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(DESIRED_GO_VERSION)/.prepared go.mod + go build -tags linux -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/wireguard" -v -trimpath -o "$@" -buildmode c-shared diff --git a/tunnel/tools/libwg-go/api-android.go b/tunnel/tools/libwg-go/api-android.go new file mode 100644 index 00000000..7a393cae --- /dev/null +++ b/tunnel/tools/libwg-go/api-android.go @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: Apache-2.0 + * + * Copyright (C) 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + +package main + +// #cgo LDFLAGS: -llog +// #include <android/log.h> +import "C" + +import ( + "bufio" + "golang.org/x/sys/unix" + "golang.zx2c4.com/wireguard/device" + "golang.zx2c4.com/wireguard/ipc" + "golang.zx2c4.com/wireguard/tun" + "bytes" + "log" + "math" + "net" + "os" + "os/signal" + "runtime" + "strings" + "unsafe" +) + +type AndroidLogger struct { + level C.int + interfaceName string +} + +func (l AndroidLogger) Write(p []byte) (int, error) { + C.__android_log_write(l.level, C.CString("WireGuard/GoBackend/"+l.interfaceName), C.CString(string(p))) + return len(p), nil +} + +type TunnelHandle struct { + device *device.Device + uapi net.Listener +} + +var tunnelHandles map[int32]TunnelHandle + +func init() { + device.RoamingDisabled = true + 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) + buf[n] = 0 + C.__android_log_write(C.ANDROID_LOG_ERROR, C.CString("WireGuard/GoBackend/Stacktrace"), (*C.char)(unsafe.Pointer(&buf[0]))) + } + } + }() +} + +//export wgTurnOn +func wgTurnOn(ifnameRef string, tunFd int32, settings string) int32 { + interfaceName := string([]byte(ifnameRef)) + + logger := &device.Logger{ + Debug: log.New(&AndroidLogger{level: C.ANDROID_LOG_DEBUG, interfaceName: interfaceName}, "", 0), + Info: log.New(&AndroidLogger{level: C.ANDROID_LOG_INFO, interfaceName: interfaceName}, "", 0), + Error: log.New(&AndroidLogger{level: C.ANDROID_LOG_ERROR, interfaceName: interfaceName}, "", 0), + } + + logger.Debug.Println("Debug log enabled") + + tun, name, err := tun.CreateUnmonitoredTUNFromFD(int(tunFd)) + if err != nil { + unix.Close(int(tunFd)) + logger.Error.Println(err) + return -1 + } + + logger.Info.Println("Attaching to interface", name) + device := device.NewDevice(tun, logger) + + setError := device.IpcSetOperation(bufio.NewReader(strings.NewReader(settings))) + if setError != nil { + unix.Close(int(tunFd)) + logger.Error.Println(setError) + return -1 + } + + var uapi net.Listener + + uapiFile, err := ipc.UAPIOpen(name) + if err != nil { + logger.Error.Println(err) + } else { + uapi, err = ipc.UAPIListen(name, uapiFile) + if err != nil { + uapiFile.Close() + logger.Error.Println(err) + } else { + go func() { + for { + conn, err := uapi.Accept() + if err != nil { + return + } + go device.IpcHandle(conn) + } + }() + } + } + + device.Up() + logger.Info.Println("Device started") + + var i int32 + for i = 0; i < math.MaxInt32; i++ { + if _, exists := tunnelHandles[i]; !exists { + break + } + } + if i == math.MaxInt32 { + unix.Close(int(tunFd)) + 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 + } + fd, err := handle.device.PeekLookAtSocketFd4() + if err != nil { + return -1 + } + return int32(fd) +} + +//export wgGetSocketV6 +func wgGetSocketV6(tunnelHandle int32) int32 { + handle, ok := tunnelHandles[tunnelHandle] + if !ok { + return -1 + } + fd, err := handle.device.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 := new(bytes.Buffer) + writer := bufio.NewWriter(settings) + err := handle.device.IpcGetOperation(writer) + if err != nil { + return nil + } + writer.Flush() + return C.CString(settings.String()) +} + +//export wgVersion +func wgVersion() *C.char { + return C.CString(device.WireGuardGoVersion) +} + +func main() {} diff --git a/tunnel/tools/libwg-go/go.mod b/tunnel/tools/libwg-go/go.mod new file mode 100644 index 00000000..a5bd709b --- /dev/null +++ b/tunnel/tools/libwg-go/go.mod @@ -0,0 +1,10 @@ +module golang.zx2c4.com/wireguard/android + +go 1.13 + +require ( + golang.org/x/crypto v0.0.0-20200117160349-530e935923ad // indirect + golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect + golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 + golang.zx2c4.com/wireguard v0.0.20200121 +) diff --git a/tunnel/tools/libwg-go/go.sum b/tunnel/tools/libwg-go/go.sum new file mode 100644 index 00000000..25d8f90c --- /dev/null +++ b/tunnel/tools/libwg-go/go.sum @@ -0,0 +1,19 @@ +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.zx2c4.com/wireguard v0.0.20200121 h1:vcswa5Q6f+sylDfjqyrVNNrjsFUUbPsgAQTBCAg/Qf8= +golang.zx2c4.com/wireguard v0.0.20200121/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4= diff --git a/tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff b/tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff new file mode 100644 index 00000000..5fd02397 --- /dev/null +++ b/tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff @@ -0,0 +1,161 @@ +From b19623e7673a4d6743745382d5d38751b64e011d Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" <Jason@zx2c4.com> +Date: Wed, 27 Feb 2019 05:05:44 +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 72c43bd9da..daadfe32a9 100644 +--- a/src/runtime/sys_linux_386.s ++++ b/src/runtime/sys_linux_386.s +@@ -288,13 +288,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 5c300f553d..e4a6f12ec6 100644 +--- a/src/runtime/sys_linux_amd64.s ++++ b/src/runtime/sys_linux_amd64.s +@@ -261,7 +261,7 @@ noswitch: + MOVQ runtime·vdsoClockgettimeSym(SB), AX + CMPQ AX, $0 + JEQ fallback +- MOVL $1, DI // CLOCK_MONOTONIC ++ MOVL $7, DI // CLOCK_BOOTTIME + LEAQ 0(SP), SI + CALL AX + MOVQ 0(SP), AX // sec +diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s +index 9c7398451c..61b6cd91f6 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 +@@ -291,7 +291,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), R11 + CMP $0, R11 +diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s +index 2835b6ca1c..346ca9cfce 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 +@@ -247,7 +247,7 @@ noswitch: + BIC $15, R1 + MOVD R1, RSP + +- MOVW $CLOCK_MONOTONIC, R0 ++ MOVW $CLOCK_BOOTTIME, R0 + MOVD runtime·vdsoClockgettimeSym(SB), R2 + CBZ R2, fallback + BL (R2) +diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s +index 33ed1050c2..59a5be179c 100644 +--- a/src/runtime/sys_linux_mips64x.s ++++ b/src/runtime/sys_linux_mips64x.s +@@ -189,7 +189,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$16 + RET + + TEXT runtime·nanotime(SB),NOSPLIT,$16 +- MOVW $1, R4 // CLOCK_MONOTONIC ++ MOVW $7, R4 // CLOCK_BOOTTIME + MOVV $0(R29), R5 + MOVV $SYS_clock_gettime, R2 + SYSCALL +diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s +index 6e539fbc6f..55b2bf7156 100644 +--- a/src/runtime/sys_linux_mipsx.s ++++ b/src/runtime/sys_linux_mipsx.s +@@ -194,7 +194,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$8-12 + RET + + TEXT runtime·nanotime(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 13d23156bd..f67e5062aa 100644 +--- a/src/runtime/sys_linux_ppc64x.s ++++ b/src/runtime/sys_linux_ppc64x.s +@@ -204,7 +204,7 @@ fallback: + JMP finish + + TEXT runtime·nanotime(SB),NOSPLIT,$16 +- 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 58b36dff0a..cb92e9a402 100644 +--- a/src/runtime/sys_linux_s390x.s ++++ b/src/runtime/sys_linux_s390x.s +@@ -180,7 +180,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$16 + RET + + TEXT runtime·nanotime(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.23.0 + diff --git a/tunnel/tools/libwg-go/jni.c b/tunnel/tools/libwg-go/jni.c new file mode 100644 index 00000000..3f877d47 --- /dev/null +++ b/tunnel/tools/libwg-go/jni.c @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: Apache-2.0 + * + * Copyright © 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. + */ + +#include <jni.h> +#include <stdlib.h> +#include <string.h> + +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_com_wireguard_android_backend_GoBackend_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_com_wireguard_android_backend_GoBackend_wgTurnOff(JNIEnv *env, jclass c, jint handle) +{ + wgTurnOff(handle); +} + +JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetSocketV4(JNIEnv *env, jclass c, jint handle) +{ + return wgGetSocketV4(handle); +} + +JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetSocketV6(JNIEnv *env, jclass c, jint handle) +{ + return wgGetSocketV6(handle); +} + +JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_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_com_wireguard_android_backend_GoBackend_wgVersion(JNIEnv *env, jclass c) +{ + jstring ret; + char *version = wgVersion(); + if (!version) + return NULL; + ret = (*env)->NewStringUTF(env, version); + free(version); + return ret; +} |