From 831640312c7cd0305e47c6292f9494a9e779b769 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sat, 9 Jun 2018 03:14:34 +0200 Subject: [PATCH] First stab at Go bridge Signed-off-by: Jason A. Donenfeld --- .gitmodules | 3 + wireguard-go | 1 + wireguard-go-bridge/Makefile | 32 +++++ wireguard-go-bridge/example.c | 46 +++++++ .../src/git.zx2c4.com/wireguard-go/api-ios.go | 128 ++++++++++++++++++ .../git.zx2c4.com/wireguard-go/tun/tun_ios.go | 85 ++++++++++++ wireguard-go-bridge/wireguard.h | 19 +++ 7 files changed, 314 insertions(+) create mode 100644 .gitmodules create mode 160000 wireguard-go create mode 100644 wireguard-go-bridge/Makefile create mode 100644 wireguard-go-bridge/example.c create mode 100644 wireguard-go-bridge/src/git.zx2c4.com/wireguard-go/api-ios.go create mode 100644 wireguard-go-bridge/src/git.zx2c4.com/wireguard-go/tun/tun_ios.go create mode 100644 wireguard-go-bridge/wireguard.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b8270fa --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "wireguard-go"] + path = wireguard-go + url = https://git.zx2c4.com/wireguard-go diff --git a/wireguard-go b/wireguard-go new file mode 160000 index 0000000..0ba5518 --- /dev/null +++ b/wireguard-go @@ -0,0 +1 @@ +Subproject commit 0ba551807fcd0d33c6ad80842b71c8de42c2da55 diff --git a/wireguard-go-bridge/Makefile b/wireguard-go-bridge/Makefile new file mode 100644 index 0000000..90dc7ac --- /dev/null +++ b/wireguard-go-bridge/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2018 Jason A. Donenfeld . All Rights Reserved. + +FILES := $(filter-out %/main.go,$(wildcard ../wireguard-go/*/*.go) $(wildcard ../wireguard-go/*.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) +# export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME)) +export GOOS := darwin +export CGO_ENABLED := 1 + +default: example + +libwg-go.so: $(FILES) src/git.zx2c4.com/wireguard-go/api-ios.go src/git.zx2c4.com/wireguard-go/tun/tun_ios.go + find . -name '*.go' -type l -delete + find . -type d -empty -delete + mkdir -p $(subst ../wireguard-go/,./src/git.zx2c4.com/wireguard-go/,$(dir $(FILES))) + $(foreach FILE,$(FILES),ln -sf $(abspath $(FILE)) $(subst ../wireguard-go/,./src/git.zx2c4.com/wireguard-go/,$(dir $(FILE)))$(file $(FILE));) + GOPATH=$(PWD) go get -v -d git.zx2c4.com/wireguard-go + GOPATH=$(PWD) go build -tags ios -v -o libwg-go.so -buildmode c-shared git.zx2c4.com/wireguard-go + @rm -f libwg-go.h + +example: example.c libwg-go.so + $(CC) -L. -lwg-go -o example example.c + +clean: + rm -f libwg-go.so test + +.PHONY: clean default diff --git a/wireguard-go-bridge/example.c b/wireguard-go-bridge/example.c new file mode 100644 index 0000000..912d181 --- /dev/null +++ b/wireguard-go-bridge/example.c @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018 Jason A. Donenfeld . All Rights Reserved. + */ + +#include "wireguard.h" +#include +#include +#include + +static struct { + int something; +} ctx; + +static bool is_closed = false; + +ssize_t do_read(const void *ctx, const unsigned char *buf, size_t len) +{ + printf("Reading from instance with ctx %p into buffer %p of length %zu\n", ctx, buf, len); + sleep(1); + return is_closed ? -1 : 0; +} + +ssize_t do_write(const void *ctx, const unsigned char *buf, size_t len) +{ + printf("Writing from instance with ctx %p into buffer %p of length %zu\n", ctx, buf, len); + return len; +} + +void do_log(int level, const char *tag, const char *msg) +{ + printf("Log level %d for %s: %s", level, tag, msg); +} + +int main(int argc, char *argv[]) +{ + int handle; + + printf("WireGuard Go Version %s\n", wgVersion()); + wgSetLogger(do_log); + handle = wgTurnOn((gostring_t){ .p = "test", .n = 4 }, (gostring_t){ .p = "", .n = 0 }, do_read, do_write, &ctx); + sleep(5); + is_closed = true; + wgTurnOff(handle); + return 0; +} diff --git a/wireguard-go-bridge/src/git.zx2c4.com/wireguard-go/api-ios.go b/wireguard-go-bridge/src/git.zx2c4.com/wireguard-go/api-ios.go new file mode 100644 index 0000000..0caab3e --- /dev/null +++ b/wireguard-go-bridge/src/git.zx2c4.com/wireguard-go/api-ios.go @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018 Jason A. Donenfeld . All Rights Reserved. + */ + +package main + +// #include +// static void callLogger(void *func, int level, const char *tag, const char *msg) +// { +// ((void(*)(int, const char *, const char *))func)(level, tag, msg); +// } +import "C" + +import ( + "bufio" + "git.zx2c4.com/wireguard-go/tun" + "golang.org/x/sys/unix" + "io/ioutil" + "log" + "math" + "os" + "os/signal" + "runtime" + "strings" + "unsafe" + "errors" +) + +var loggerFunc unsafe.Pointer + +type CLogger struct { + level C.int + interfaceName string +} + +func (l *CLogger) Write(p []byte) (int, error) { + if uintptr(loggerFunc) == 0 { + return 0, errors.New("No logger initialized") + } + C.callLogger(loggerFunc, l.level, C.CString("WireGuard/GoBackend/"+l.interfaceName), C.CString(string(p))) + return len(p), nil +} + +var tunnelHandles map[int32]*Device + +func init() { + roamingDisabled = true + tunnelHandles = make(map[int32]*Device) + 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 + if uintptr(loggerFunc) != 0 { + C.callLogger(loggerFunc, 0, C.CString("WireGuard/GoBackend/Stacktrace"), (*_Ctype_char)(unsafe.Pointer(&buf[0]))) + } + } + } + }() +} + +//export wgSetLogger +func wgSetLogger(loggerFn uintptr) { + loggerFunc = unsafe.Pointer(loggerFn) +} + +//export wgTurnOn +func wgTurnOn(ifnameRef string, settings string, readFn uintptr, writeFn uintptr, ctx uintptr) int32 { + interfaceName := string([]byte(ifnameRef)) + + logger := &Logger{ + Debug: log.New(&CLogger{level: 0, interfaceName: interfaceName}, "", 0), + Info: log.New(&CLogger{level: 1, interfaceName: interfaceName}, "", 0), + Error: log.New(&CLogger{level: 2, interfaceName: interfaceName}, "", 0), + } + + logger.Debug.Println("Debug log enabled") + + tun := tun.CreateTUN(1280, unsafe.Pointer(readFn), unsafe.Pointer(writeFn), unsafe.Pointer(ctx)) + logger.Info.Println("Attaching to interface") + device := NewDevice(tun, logger) + + logger.Debug.Println("Interface has MTU", device.tun.mtu) + + bufferedSettings := bufio.NewReadWriter(bufio.NewReader(strings.NewReader(settings)), bufio.NewWriter(ioutil.Discard)) + setError := ipcSetOperation(device, bufferedSettings) + if setError != nil { + logger.Error.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 wgVersion +func wgVersion() *C.char { + return C.CString(WireGuardGoVersion) +} + +func main() {} diff --git a/wireguard-go-bridge/src/git.zx2c4.com/wireguard-go/tun/tun_ios.go b/wireguard-go-bridge/src/git.zx2c4.com/wireguard-go/tun/tun_ios.go new file mode 100644 index 0000000..fd8a1a1 --- /dev/null +++ b/wireguard-go-bridge/src/git.zx2c4.com/wireguard-go/tun/tun_ios.go @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018 Jason A. Donenfeld . All Rights Reserved. + */ + +package tun + +// #include +// static ssize_t callFnWithCtx(const void *func, const void *ctx, const void *buffer, size_t len) +// { +// return ((ssize_t(*)(const void *, const unsigned char *, size_t))func)(ctx, buffer, len); +// } +import "C" + +import ( + "os" + "syscall" + "unsafe" +) + +type nativeTun struct { + events chan TUNEvent + mtu int + readFn unsafe.Pointer + writeFn unsafe.Pointer + ctx unsafe.Pointer +} + +func CreateTUN(mtu int, readFn unsafe.Pointer, writeFn unsafe.Pointer, ctx unsafe.Pointer) TUNDevice { + tun := &nativeTun{ + events: make(chan TUNEvent, 10), + mtu: mtu, + readFn: readFn, + writeFn: writeFn, + ctx: ctx, + } + tun.events <- TUNEventUp + return tun +} + +func (tun *nativeTun) Name() (string, error) { + return "tun", nil +} + +func (tun *nativeTun) File() *os.File { + return nil +} + +func (tun *nativeTun) Events() chan TUNEvent { + return tun.events +} + +func (tun *nativeTun) Read(buff []byte, offset int) (int, error) { + buff = buff[offset:] + ret := C.callFnWithCtx(tun.readFn, tun.ctx, unsafe.Pointer(&buff[0]), C.size_t(len(buff))) + if ret < 0 { + return 0, syscall.Errno(-ret) + } + return int(ret), nil +} + +func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { + buff = buff[offset:] + ret := C.callFnWithCtx(tun.writeFn, tun.ctx, unsafe.Pointer(&buff[0]), C.size_t(len(buff))) + if ret < 0 { + return 0, syscall.Errno(-ret) + } + return int(ret), nil +} + +func (tun *nativeTun) Close() error { + if tun.events != nil { + close(tun.events) + } + return nil +} + +func (tun *nativeTun) setMTU(n int) error { + tun.mtu = n + return nil +} + +func (tun *nativeTun) MTU() (int, error) { + return tun.mtu, nil +} diff --git a/wireguard-go-bridge/wireguard.h b/wireguard-go-bridge/wireguard.h new file mode 100644 index 0000000..483d564 --- /dev/null +++ b/wireguard-go-bridge/wireguard.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018 Jason A. Donenfeld . All Rights Reserved. + */ + +#ifndef WIREGUARD_H +#define WIREGUARD_H + +#include + +typedef struct { const char *p; size_t n; } gostring_t; +typedef ssize_t(*read_write_fn_t)(const void *ctx, const unsigned char *buf, size_t len); +typedef void(*logger_fn_t)(int level, const char *tag, const char *msg); +extern void wgSetLogger(logger_fn_t logger_fn); +extern int wgTurnOn(gostring_t ifname, gostring_t settings, read_write_fn_t read_fn, read_write_fn_t write_fn, void *ctx); +extern void wgTurnOff(int handle); +extern char *wgVersion(); + +#endif