From 0ea6f73332cf48374b8a98b16d68e25217ebf068 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 7 Feb 2018 19:19:20 +0100 Subject: GoBackend: integrate into app Signed-off-by: Jason A. Donenfeld --- app/tools/CMakeLists.txt | 13 +++++ app/tools/libwg-go/.gitignore | 4 ++ app/tools/libwg-go/Makefile | 21 ++++++++ app/tools/libwg-go/api-android.go | 111 ++++++++++++++++++++++++++++++++++++++ app/tools/libwg-go/jni.c | 40 ++++++++++++++ app/tools/wireguard-go | 1 + 6 files changed, 190 insertions(+) create mode 100644 app/tools/libwg-go/.gitignore create mode 100644 app/tools/libwg-go/Makefile create mode 100644 app/tools/libwg-go/api-android.go create mode 100644 app/tools/libwg-go/jni.c create mode 160000 app/tools/wireguard-go (limited to 'app/tools') diff --git a/app/tools/CMakeLists.txt b/app/tools/CMakeLists.txt index 22ddbcc1..4cf030bf 100644 --- a/app/tools/CMakeLists.txt +++ b/app/tools/CMakeLists.txt @@ -10,3 +10,16 @@ target_compile_options(libwg-quick.so PUBLIC -O3 -std=gnu11 -Wall -pedantic -Wno file(GLOB WG_SOURCES wireguard/src/tools/*.c libmnl/src/*.c) add_executable(libwg.so ${WG_SOURCES}) target_compile_options(libwg.so PUBLIC "-I${CMAKE_CURRENT_SOURCE_DIR}libmnl/src/" "-I${CMAKE_CURRENT_SOURCE_DIR}/libmnl/include/" "-I${CMAKE_CURRENT_SOURCE_DIR}/wireguard/src/tools/" -O3 -std=gnu11 -D_GNU_SOURCE -DHAVE_VISIBILITY_HIDDEN -DRUNSTATEDIR=\"\\\"/data/data/com.wireguard.android/cache\\\"\" -Wno-pointer-arith -Wno-unused-parameter) + +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} + CFLAGS=${CMAKE_C_FLAGS}\ -Wno-unused-command-line-argument + LDFLAGS=${CMAKE_SHARED_LINKER_FLAGS}\ -fuse-ld=gold + DESTDIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} +) +# Hack to make it actually build as part of the default target +add_dependencies(libwg.so libwg-go.so) diff --git a/app/tools/libwg-go/.gitignore b/app/tools/libwg-go/.gitignore new file mode 100644 index 00000000..c039ddfb --- /dev/null +++ b/app/tools/libwg-go/.gitignore @@ -0,0 +1,4 @@ +go/ +*.go +libwg-go.h +jni.o diff --git a/app/tools/libwg-go/Makefile b/app/tools/libwg-go/Makefile new file mode 100644 index 00000000..300b3841 --- /dev/null +++ b/app/tools/libwg-go/Makefile @@ -0,0 +1,21 @@ +containing = $(foreach v,$2,$(if $(findstring $1,$v),$v)) +FILES := $(wildcard ../wireguard-go/*/*.go) $(wildcard ../wireguard-go/*.go) +FILES := $(filter-out %/main.go $(filter-out %_linux.go,$(call containing,_,$(FILES))),$(FILES)) + +export GOPATH := $(CURDIR)/go +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) +GO_ARCH_FILTER := case "$(ANDROID_ARCH_NAME)" in x86) echo 386 ;; x86_64) echo amd64 ;; *) echo $(ANDROID_ARCH_NAME) ;; esac +export GOARCH := $(shell $(GO_ARCH_FILTER)) +export GOOS := android +export CGO_ENABLED := 1 + +$(DESTDIR)/libwg-go.so: $(FILES) api-android.go jni.c + find . -name '*.go' -type l -delete + find . -type d -empty -delete + mkdir -p $(subst ../wireguard-go/,./,$(dir $(FILES))) + $(foreach FILE,$(FILES),ln -sfrt $(subst ../wireguard-go/,./,$(dir $(FILE))) $(FILE);) + go get -v -d + go build -v -o $(DESTDIR)/libwg-go.so -buildmode c-shared diff --git a/app/tools/libwg-go/api-android.go b/app/tools/libwg-go/api-android.go new file mode 100644 index 00000000..b2e3da17 --- /dev/null +++ b/app/tools/libwg-go/api-android.go @@ -0,0 +1,111 @@ +package main + +// #cgo LDFLAGS: -llog +// #include +import "C" + +import ( + "bufio" + "io/ioutil" + "log" + "math" + "os" + "strings" +) + +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 +} + +var tunnelHandles map[int32]*Device + +func init() { + tunnelHandles = make(map[int32]*Device) +} + +//export wgTurnOn +func wgTurnOn(ifnameRef string, tun_fd int32, settings string) int32 { + interfaceName := string([]byte(ifnameRef)) + + logger := &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 := &NativeTun{ + fd: os.NewFile(uintptr(tun_fd), ""), + events: make(chan TUNEvent, 5), + errors: make(chan error, 5), + } + device := NewDevice(tun, logger) + device.tun.mtu = DefaultMTU //TODO: make dynamic + + bufferedSettings := bufio.NewReadWriter(bufio.NewReader(strings.NewReader(settings)), bufio.NewWriter(ioutil.Discard)) + setError := ipcSetOperation(device, bufferedSettings) + if setError != nil { + logger.Debug.Println(setError) + return -1 + } + + 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 { + return -1 + } + tunnelHandles[i] = device + return i +} + +//export wgTurnOff +func wgTurnOff(tunnelHandle int32) { + device, ok := tunnelHandles[tunnelHandle] + if !ok { + return + } + delete(tunnelHandles, tunnelHandle) + device.Close() +} + +//export wgGetSocketV4 +func wgGetSocketV4(tunnelHandle int32) int32 { + device, ok := tunnelHandles[tunnelHandle] + if !ok { + return -1 + } + native, ok := device.net.bind.(NativeBind) + if !ok { + return -1 + } + return int32(native.sock4) +} + +//export wgGetSocketV6 +func wgGetSocketV6(tunnelHandle int32) int32 { + device, ok := tunnelHandles[tunnelHandle] + if !ok { + return -1 + } + native, ok := device.net.bind.(NativeBind) + if !ok { + return -1 + } + return int32(native.sock6) +} + +func main() {} diff --git a/app/tools/libwg-go/jni.c b/app/tools/libwg-go/jni.c new file mode 100644 index 00000000..1476dab7 --- /dev/null +++ b/app/tools/libwg-go/jni.c @@ -0,0 +1,40 @@ +#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); + +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); +} diff --git a/app/tools/wireguard-go b/app/tools/wireguard-go new file mode 160000 index 00000000..8f1d1b8c --- /dev/null +++ b/app/tools/wireguard-go @@ -0,0 +1 @@ +Subproject commit 8f1d1b8c54d747309d9fdf06b157823af2a823bd -- cgit v1.2.3-59-g8ed1b