summaryrefslogtreecommitdiffhomepage
path: root/tunnel/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tunnel/tools')
-rw-r--r--tunnel/tools/CMakeLists.txt33
-rw-r--r--tunnel/tools/libwg-go/.gitignore1
-rw-r--r--tunnel/tools/libwg-go/Makefile35
-rw-r--r--tunnel/tools/libwg-go/api-android.go193
-rw-r--r--tunnel/tools/libwg-go/go.mod10
-rw-r--r--tunnel/tools/libwg-go/go.sum19
-rw-r--r--tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff161
-rw-r--r--tunnel/tools/libwg-go/jni.c71
-rw-r--r--tunnel/tools/ndk-compat/compat.c77
-rw-r--r--tunnel/tools/ndk-compat/compat.h16
m---------tunnel/tools/wireguard-tools0
11 files changed, 616 insertions, 0 deletions
diff --git a/tunnel/tools/CMakeLists.txt b/tunnel/tools/CMakeLists.txt
new file mode 100644
index 00000000..90e61a06
--- /dev/null
+++ b/tunnel/tools/CMakeLists.txt
@@ -0,0 +1,33 @@
+# 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}")
+
+# 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 wireguard-tools/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 wireguard-tools/src/*.c ndk-compat/compat.c)
+add_executable(libwg.so ${WG_SOURCES})
+target_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/uapi/" "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/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" VERBATIM COMMAND make
+ 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}
+ 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/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;
+}
diff --git a/tunnel/tools/ndk-compat/compat.c b/tunnel/tools/ndk-compat/compat.c
new file mode 100644
index 00000000..7cc99fc4
--- /dev/null
+++ b/tunnel/tools/ndk-compat/compat.c
@@ -0,0 +1,77 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+
+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 <string.h>
+
+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/tunnel/tools/ndk-compat/compat.h b/tunnel/tools/ndk-compat/compat.h
new file mode 100644
index 00000000..52f6c127
--- /dev/null
+++ b/tunnel/tools/ndk-compat/compat.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: BSD
+ *
+ * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
+ *
+ */
+
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
+#include <stdio.h>
+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
+
diff --git a/tunnel/tools/wireguard-tools b/tunnel/tools/wireguard-tools
new file mode 160000
+Subproject e5b08c2849256367fc6bf37be9e737bdb21ee66