summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gradle/libs.versions.toml10
-rw-r--r--tunnel/build.gradle.kts58
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java29
-rw-r--r--tunnel/src/main/proto/libwg.proto27
-rw-r--r--tunnel/tools/libwg-go/.gitignore3
-rw-r--r--tunnel/tools/libwg-go/Makefile27
-rw-r--r--tunnel/tools/libwg-go/api-android.go29
-rw-r--r--tunnel/tools/libwg-go/jni.c13
-rw-r--r--tunnel/tools/libwg-go/service.go76
9 files changed, 265 insertions, 7 deletions
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 25b59ff1..ce2a5af1 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,6 +1,10 @@
[versions]
agp = "8.1.0-beta02"
+grpc = "1.55.1"
kotlin = "1.8.21"
+protobuf = "0.9.3"
+protoc = "3.22.2"
+protocgengrpc = '1.55.1'
[libraries]
androidx-activity-ktx = "androidx.activity:activity-ktx:1.7.1"
@@ -17,6 +21,11 @@ androidx-lifecycle-runtime-ktx = "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1
androidx-preference-ktx = "androidx.preference:preference-ktx:1.2.0"
desugarJdkLibs = "com.android.tools:desugar_jdk_libs:2.0.3"
google-material = "com.google.android.material:material:1.9.0"
+grpc-android = "io.grpc:grpc-android:1.55.1"
+grpc-okhttp = "io.grpc:grpc-okhttp:1.55.1"
+grpc-protobuf-lite = "io.grpc:grpc-protobuf-lite:1.55.1"
+grpc-stub = "io.grpc:grpc-stub:1.55.1"
+javax-annotation-api = "javax.annotation:javax.annotation-api:1.2"
jsr305 = "com.google.code.findbugs:jsr305:3.0.2"
junit = "junit:junit:4.13.2"
kotlinx-coroutines-android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.0"
@@ -25,5 +34,6 @@ zxing-android-embedded = "com.journeyapps:zxing-android-embedded:4.3.0"
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
+google-protobuf = { id = "com.google.protobuf", version.ref = "protobuf" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
diff --git a/tunnel/build.gradle.kts b/tunnel/build.gradle.kts
index fff3857d..7f6bd0e6 100644
--- a/tunnel/build.gradle.kts
+++ b/tunnel/build.gradle.kts
@@ -1,5 +1,6 @@
@file:Suppress("UnstableApiUsage")
+import com.google.protobuf.gradle.*
import org.gradle.api.tasks.testing.logging.TestLogEvent
val pkg: String = providers.gradleProperty("wireguardPackageName").get()
@@ -7,6 +8,7 @@ val pkg: String = providers.gradleProperty("wireguardPackageName").get()
plugins {
alias(libs.plugins.android.library)
`maven-publish`
+ alias(libs.plugins.google.protobuf)
signing
}
@@ -67,10 +69,66 @@ android {
dependencies {
implementation(libs.androidx.annotation)
implementation(libs.androidx.collection)
+ implementation(libs.grpc.android)
+ implementation(libs.grpc.okhttp)
+ implementation(libs.grpc.protobuf.lite)
+ implementation(libs.grpc.stub)
+ compileOnly(libs.javax.annotation.api)
compileOnly(libs.jsr305)
testImplementation(libs.junit)
}
+protobuf {
+ protoc {
+ // The artifact spec for the Protobuf Compiler
+ artifact = "com.google.protobuf:protoc:${libs.versions.protoc.get()}"
+ }
+ plugins {
+ // Optional: an artifact spec for a protoc plugin, with "grpc" as
+ // the identifier, which can be referred to in the "plugins"
+ // container of the "generateProtoTasks" closure.
+ id("grpc") {
+ artifact = "io.grpc:protoc-gen-grpc-java:${libs.versions.protocgengrpc.get()}"
+ }
+ id("java") {
+ }
+ }
+ generateProtoTasks {
+ all().forEach { task ->
+ task.plugins{
+ id("grpc") {
+ option("lite")
+ }
+ id("java") {
+ option("lite")
+ }
+ }
+ }
+ }
+}
+
+afterEvaluate({ ->
+ // All custom configurations created by the protobuf plugin,
+ // are only available at this point.
+ var protoc = configurations.named("protobufToolsLocator_protoc")
+ var protocCache = "${gradle.gradleUserHomeDir}/caches/protoc-bin-${libs.versions.protoc.get()}"
+
+ tasks.register("copyProtoc", Copy::class) {
+ // Used by tunnel/tools/libwg-go/Makefile run in tools/CMakeLists.txt
+ from(protoc)
+ into(protocCache)
+ rename("protoc-.*", "protoc")
+ setFileMode(7 * 64 + 7 * 8 + 5) // 0775
+ }
+
+ tasks.named("preBuild").get().dependsOn("copyProtoc")
+
+ // Extract duration.proto used by external library in libwg.proto
+ tasks.named("preDebugBuild").get().dependsOn(tasks.named("extractIncludeDebugProto").get())
+ tasks.named("preReleaseBuild").get().dependsOn(tasks.named("extractIncludeReleaseProto").get())
+ println("done afterEvaluate")
+})
+
publishing {
publications {
register<MavenPublication>("release") {
diff --git a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
index 242f81d8..98ce8d7d 100644
--- a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
+++ b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
@@ -7,14 +7,22 @@ package com.wireguard.android.backend;
import android.content.Context;
import android.content.Intent;
+import android.net.LocalSocketAddress;
import android.net.ProxyInfo;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.system.OsConstants;
import android.util.Log;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.Empty;
+
import com.wireguard.android.backend.BackendException.Reason;
import com.wireguard.android.backend.Tunnel.State;
+import com.wireguard.android.backend.gen.LibwgGrpc;
+import com.wireguard.android.backend.gen.VersionRequest;
+import com.wireguard.android.backend.gen.VersionResponse;
import com.wireguard.android.util.SharedLibraryLoader;
import com.wireguard.config.Config;
import com.wireguard.config.InetEndpoint;
@@ -24,6 +32,12 @@ import com.wireguard.crypto.Key;
import com.wireguard.crypto.KeyFormatException;
import com.wireguard.util.NonNullForAll;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.android.UdsChannelBuilder;
+import io.grpc.okhttp.OkHttpChannelBuilder;
+
+import java.io.File;
import java.net.InetAddress;
import java.net.URL;
import java.time.Instant;
@@ -35,6 +49,8 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import javax.net.SocketFactory;
+
import androidx.annotation.Nullable;
import androidx.collection.ArraySet;
@@ -52,6 +68,7 @@ public final class GoBackend implements Backend {
@Nullable private Config currentConfig;
@Nullable private Tunnel currentTunnel;
private int currentTunnelHandle = -1;
+ private ManagedChannel channel;
/**
* Public constructor for GoBackend.
@@ -61,6 +78,11 @@ public final class GoBackend implements Backend {
public GoBackend(final Context context) {
SharedLibraryLoader.loadSharedLibrary(context, "wg-go");
this.context = context;
+
+ File socketFile = new File(context.getCacheDir(), "libwg.sock");
+ String socketName = socketFile.getAbsolutePath();
+ Log.i(TAG, "wgStartGrpc: " + wgStartGrpc(socketName));
+ channel = UdsChannelBuilder.forPath(socketName, LocalSocketAddress.Namespace.FILESYSTEM).build();
}
/**
@@ -85,6 +107,8 @@ public final class GoBackend implements Backend {
private static native String wgVersion();
+ private static native int wgStartGrpc(String sockName);
+
/**
* Method to get the names of running tunnels.
*
@@ -187,7 +211,10 @@ public final class GoBackend implements Backend {
*/
@Override
public String getVersion() {
- return wgVersion();
+ LibwgGrpc.LibwgBlockingStub stub = LibwgGrpc.newBlockingStub(channel);
+ VersionRequest request = VersionRequest.newBuilder().build();
+ VersionResponse resp = stub.version(request);
+ return resp.getVersion();
}
/**
diff --git a/tunnel/src/main/proto/libwg.proto b/tunnel/src/main/proto/libwg.proto
new file mode 100644
index 00000000..2d964897
--- /dev/null
+++ b/tunnel/src/main/proto/libwg.proto
@@ -0,0 +1,27 @@
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = 'com.wireguard.android.backend.gen';
+option java_outer_classname = "LibwgProto";
+option java_generic_services = true;
+option go_package = 'golang.zx2c4.com/wireguard/android/gen';
+
+package api;
+
+service Libwg {
+ rpc StopGrpc(StopGrpcRequest) returns (StopGrpcResponse);
+ rpc Version(VersionRequest) returns (VersionResponse);
+}
+
+message StopGrpcRequest {
+}
+
+message StopGrpcResponse {
+}
+
+message VersionRequest {
+}
+
+message VersionResponse {
+ string version = 1;
+}
diff --git a/tunnel/tools/libwg-go/.gitignore b/tunnel/tools/libwg-go/.gitignore
index d1638636..d69ee823 100644
--- a/tunnel/tools/libwg-go/.gitignore
+++ b/tunnel/tools/libwg-go/.gitignore
@@ -1 +1,2 @@
-build/ \ No newline at end of file
+build/
+/gen/
diff --git a/tunnel/tools/libwg-go/Makefile b/tunnel/tools/libwg-go/Makefile
index f1936e1d..9f6bad39 100644
--- a/tunnel/tools/libwg-go/Makefile
+++ b/tunnel/tools/libwg-go/Makefile
@@ -19,6 +19,7 @@ export CGO_LDFLAGS := $(CLANG_FLAGS) $(patsubst -Wl$(comma)--build-id=%,-Wl$(com
export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME))
export GOOS := android
export CGO_ENABLED := 1
+export GOPATH ?= $(HOME)/go
GO_VERSION := 1.20.3
GO_PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]')-$(NDK_GO_ARCH_MAP_$(shell uname -m))
@@ -27,6 +28,13 @@ GO_HASH_darwin-amd64 := c1e1161d6d859deb576e6cfabeb40e3d042ceb1c6f444f617c3c9d76
GO_HASH_darwin-arm64 := 86b0ed0f2b2df50fa8036eea875d1cf2d76cefdacf247c44639a1464b7e36b95
GO_HASH_linux-amd64 := 979694c2c25c735755bf26f4f45e19e64e4811d661dd07b8c010f7a8e18adfca
+PROTOC_VERSION := 3.22.2
+PROTOC_GEN_GO := $(GOPATH)/bin/protoc-gen-go
+PROTOC := $(GRADLE_USER_HOME)/caches/protoc-bin-$(PROTOC_VERSION)/protoc
+PROTODIR = $(CURDIR)/../../src/main/proto
+PROTO_INCLUDEDIR = $(CURDIR)/../../build/extracted-include-protos/debug
+PBDIR = $(GOPATH)/pkg/mod
+
default: $(DESTDIR)/libwg-go.so
$(GRADLE_USER_HOME)/caches/golang/$(GO_TARBALL):
@@ -45,8 +53,25 @@ $(BUILDDIR)/go-$(GO_VERSION)/.prepared: $(GRADLE_USER_HOME)/caches/golang/$(GO_T
patch -p1 -f -N -r- -d "$(dir $@)" < goruntime-boottime-over-monotonic.diff && \
touch "$@"'
+$(PROTOC_GEN_GO): export GOARCH :=
+$(PROTOC_GEN_GO): export GOOS :=
+$(PROTOC_GEN_GO): export PATH := $(BUILDDIR)/go-$(GO_VERSION)/bin/:$(PATH)
+$(PROTOC_GEN_GO): $(BUILDDIR)/go-$(GO_VERSION)/.prepared Makefile
+ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
+ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
+
+gen/%.pb.go: export PATH := $(GOPATH)/bin:$(PATH)
+gen/%.pb.go: $(PROTODIR)/%.proto $(BUILDDIR)/go-$(GO_VERSION)/.prepared $(PROTOC_GEN_GO)
+ test -d gen || mkdir gen
+ $(PROTOC) -I $(PROTODIR) -I $(PROTO_INCLUDEDIR) --go_out=paths=source_relative:./gen $<
+
+gen/%_grpc.pb.go: export PATH := $(GOPATH)/bin:$(PATH)
+gen/%_grpc.pb.go: $(PROTODIR)/%.proto $(BUILDDIR)/go-$(GO_VERSION)/.prepared $(PROTOC_GEN_GO)
+ test -d gen || mkdir gen
+ $(PROTOC) -I $(PROTODIR) -I $(PROTO_INCLUDEDIR) --go-grpc_out=./gen --go-grpc_opt=paths=source_relative $<
+
$(DESTDIR)/libwg-go.so: export PATH := $(BUILDDIR)/go-$(GO_VERSION)/bin/:$(PATH)
-$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod
+$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod api-android.go service.go gen/libwg.pb.go gen/libwg_grpc.pb.go jni.c
go build -tags linux -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/wireguard -buildid=" -v -trimpath -buildvcs=false -o "$@" -buildmode c-shared
.DELETE_ON_ERROR:
diff --git a/tunnel/tools/libwg-go/api-android.go b/tunnel/tools/libwg-go/api-android.go
index d47c5d76..fd0142e1 100644
--- a/tunnel/tools/libwg-go/api-android.go
+++ b/tunnel/tools/libwg-go/api-android.go
@@ -48,6 +48,7 @@ func (l AndroidLogger) Printf(format string, args ...interface{}) {
type TunnelHandle struct {
device *device.Device
uapi net.Listener
+ logger *device.Logger
}
var tunnelHandles map[int32]TunnelHandle
@@ -208,20 +209,40 @@ func wgGetConfig(tunnelHandle int32) *C.char {
//export wgVersion
func wgVersion() *C.char {
+ return C.CString(Version())
+}
+
+func Version() string {
info, ok := debug.ReadBuildInfo()
if !ok {
- return C.CString("unknown")
+ return "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 parts[2][:7]
}
- return C.CString(dep.Version)
+ return dep.Version
}
}
- return C.CString("unknown")
+ return "unknown"
+}
+
+//export wgStartGrpc
+func wgStartGrpc(sock_path string) C.int{
+ tag := cstring("WireGuard/GoBackend/gRPC")
+ logger := &device.Logger{
+ Verbosef: AndroidLogger{level: C.ANDROID_LOG_DEBUG, tag: tag}.Printf,
+ Errorf: AndroidLogger{level: C.ANDROID_LOG_ERROR, tag: tag}.Printf,
+ }
+
+ res, errmsg := StartGrpc(sock_path, logger)
+ if res < 0 {
+ logger.Verbosef("wgStartGrpc: %v (%v)", errmsg, res)
+ }
+
+ return C.int(res)
}
func main() {}
diff --git a/tunnel/tools/libwg-go/jni.c b/tunnel/tools/libwg-go/jni.c
index 7ad94d35..121729a7 100644
--- a/tunnel/tools/libwg-go/jni.c
+++ b/tunnel/tools/libwg-go/jni.c
@@ -14,6 +14,7 @@ extern int wgGetSocketV4(int handle);
extern int wgGetSocketV6(int handle);
extern char *wgGetConfig(int handle);
extern char *wgVersion();
+extern int wgStartGrpc();
JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOn(JNIEnv *env, jclass c, jstring ifname, jint tun_fd, jstring settings)
{
@@ -69,3 +70,15 @@ JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgVersion
free(version);
return ret;
}
+
+JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgStartGrpc(JNIEnv *env, jclass c, jstring sockname)
+{
+ const char *sockname_str = (*env)->GetStringUTFChars(env, sockname, 0);
+ size_t sockname_len = (*env)->GetStringUTFLength(env, sockname);
+ jint res = wgStartGrpc((struct go_string){
+ .str = sockname_str,
+ .n = sockname_len
+ });
+ (*env)->ReleaseStringUTFChars(env, sockname, sockname_str);
+ return res;
+}
diff --git a/tunnel/tools/libwg-go/service.go b/tunnel/tools/libwg-go/service.go
new file mode 100644
index 00000000..2a0dfb2d
--- /dev/null
+++ b/tunnel/tools/libwg-go/service.go
@@ -0,0 +1,76 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "os"
+
+ "google.golang.org/grpc"
+
+ gen "golang.zx2c4.com/wireguard/android/gen"
+ "golang.zx2c4.com/wireguard/device"
+)
+
+type LibwgServiceImpl struct {
+ gen.UnimplementedLibwgServer
+ logger *device.Logger
+}
+
+var _ gen.LibwgServer = (*LibwgServiceImpl)(nil)
+var server *grpc.Server
+
+func NewLibwgService(logger *device.Logger) gen.LibwgServer {
+ return &LibwgServiceImpl{logger: logger}
+}
+
+func StartGrpc(sock_path string, logger *device.Logger) (int, string) {
+ if server != nil {
+ return -1, "Already started"
+ }
+
+ if _, err := os.Stat(sock_path); err == nil {
+ if err := os.RemoveAll(sock_path); err != nil {
+ return -1, fmt.Sprintf("Cleanup failed: %v %v", sock_path, err)
+ }
+ }
+
+ listener, err := net.Listen("unix", sock_path)
+ if err != nil {
+ return -1, fmt.Sprintf("Listen failed: %v %v", sock_path, err)
+ }
+
+ server = grpc.NewServer()
+ service := NewLibwgService(logger)
+
+ gen.RegisterLibwgServer(server, service)
+
+ go func() {
+ server.Serve(listener)
+ }()
+
+ logger.Verbosef("gRPC started")
+
+ return 0, ""
+}
+
+func (e *LibwgServiceImpl) Version(ctx context.Context, req *gen.VersionRequest) (*gen.VersionResponse, error) {
+
+ r := &gen.VersionResponse{
+ Version: Version(),
+ }
+
+ return r, nil
+}
+
+func (e *LibwgServiceImpl) StopGrpc(ctx context.Context, req *gen.StopGrpcRequest) (*gen.StopGrpcResponse, error) {
+ if server != nil {
+ server.Stop()
+ server = nil
+ }
+
+ r := &gen.StopGrpcResponse{
+ }
+
+ return r, nil
+}