summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMikael Magnusson <mikma@users.sourceforge.net>2021-11-20 20:03:32 +0100
committerMikael Magnusson <mikma@users.sourceforge.net>2022-03-18 22:04:47 +0100
commit2e5c0ca5c079a783992fc3f2bb6bd5f64bceadc1 (patch)
treece5cd426b7bf61873cfc3f5999148dc08c9e6048
parente99531653dedd3d4180016f5cffc7c29f0af378c (diff)
tunnel: WIP implement http proxy for Android 10+
TODO: fix hard-coded proxy URLs.
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java128
-rw-r--r--tunnel/src/main/proto/libwg.proto47
-rw-r--r--tunnel/tools/libwg-go/Makefile2
-rw-r--r--tunnel/tools/libwg-go/api-android.go3
-rw-r--r--tunnel/tools/libwg-go/go.mod3
-rw-r--r--tunnel/tools/libwg-go/go.sum5
-rw-r--r--tunnel/tools/libwg-go/http-proxy.go165
-rw-r--r--tunnel/tools/libwg-go/service.go123
8 files changed, 471 insertions, 5 deletions
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 b78fa9ce..a68d205b 100644
--- a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
+++ b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
@@ -7,7 +7,9 @@ package com.wireguard.android.backend;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
import android.net.LocalSocketAddress;
+import android.net.ProxyInfo;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.system.OsConstants;
@@ -30,16 +32,21 @@ import com.wireguard.util.NonNullForAll;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.okhttp.OkHttpChannelBuilder;
+import io.grpc.stub.StreamObserver;
import java.io.File;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
import javax.net.SocketFactory;
@@ -52,6 +59,13 @@ import com.wireguard.android.backend.gen.TunnelHandle;
import com.wireguard.android.backend.gen.TurnOnRequest;
import com.wireguard.android.backend.gen.TurnOnResponse;
import com.wireguard.android.backend.gen.VersionResponse;
+import com.wireguard.android.backend.gen.ReverseRequest;
+import com.wireguard.android.backend.gen.ReverseResponse;
+import com.wireguard.android.backend.gen.StartHttpProxyRequest;
+import com.wireguard.android.backend.gen.StartHttpProxyResponse;
+import com.wireguard.android.backend.gen.StopHttpProxyRequest;
+import com.wireguard.android.backend.gen.StopHttpProxyResponse;
+import com.wireguard.android.backend.gen.GetConnectionOwnerUidResponse;
/**
@@ -69,6 +83,7 @@ public final class GoBackend implements Backend {
@Nullable private Tunnel currentTunnel;
private int currentTunnelHandle = -1;
private ManagedChannel channel;
+ private ConnectivityManager connectivityManager;
/**
* Public constructor for GoBackend.
@@ -79,9 +94,11 @@ public final class GoBackend implements Backend {
SharedLibraryLoader.loadSharedLibrary(context, "wg-go");
this.context = context;
+ connectivityManager = context.getSystemService(ConnectivityManager.class);
+
File socketFile = new File(context.getCacheDir(), "libwg.sock");
String socketName = socketFile.getAbsolutePath();
- Log.i(TAG, "wgStartGrpc: " + wgStartGrpc(socketName));
+ Log.i(TAG, "java wgStartGrpc: " + wgStartGrpc(socketName));
ManagedChannelBuilder<?> channelBuilder = ManagedChannelBuilder.forAddress("localhost", 10000).usePlaintext();
LocalSocketAddress address = new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.FILESYSTEM);
SocketFactory socketFactory = new UnixDomainSocketFactory(address);
@@ -264,6 +281,107 @@ public final class GoBackend implements Backend {
}
+ private int startHttpProxy() {
+ LibwgGrpc.LibwgStub asyncStub = LibwgGrpc.newStub(channel);
+ LibwgGrpc.LibwgBlockingStub stub = LibwgGrpc.newBlockingStub(channel);
+
+ Thread streamer = new Thread(new Runnable() {
+ public void run() {
+ try {
+ while (true) {
+ Log.i(TAG, "Before streamReverse");
+ streamReverse(asyncStub);
+ Log.i(TAG, "After streamReverse");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ streamer.start();
+
+ StartHttpProxyRequest req = StartHttpProxyRequest.newBuilder().build();
+ StartHttpProxyResponse resp = stub.startHttpProxy(req);
+ Log.i(TAG, "Start http proxy listen_port:" + resp.getListenPort() + ", error:" + resp.getError().getMessage());
+ return resp.getListenPort();
+ }
+
+ private void stopHttpProxy() {
+ LibwgGrpc.LibwgBlockingStub stub = LibwgGrpc.newBlockingStub(channel);
+ StopHttpProxyRequest req = StopHttpProxyRequest.newBuilder().build();
+ StopHttpProxyResponse resp = stub.stopHttpProxy(req);
+ Log.i(TAG, "Stop http proxy: " + resp.getError().getMessage());
+ }
+
+ private static InetSocketAddress toInetSocketAddress(com.wireguard.android.backend.gen.InetSocketAddress sockAddr) {
+ try {
+ return new InetSocketAddress(InetAddress.getByAddress(sockAddr.getAddress().getAddress().toByteArray()), sockAddr.getPort());
+ } catch (UnknownHostException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void streamReverse(LibwgGrpc.LibwgStub asyncStub) throws InterruptedException,
+ RuntimeException {
+ Log.i(TAG, "In streamReverse");
+ final CountDownLatch finishLatch = new CountDownLatch(1);
+ final AtomicReference<StreamObserver<ReverseRequest>> atomicRequestObserver = new AtomicReference<StreamObserver<ReverseRequest>>();
+ // Throwable failed = null;
+
+ StreamObserver<ReverseResponse> responseObserver = new StreamObserver<ReverseResponse>() {
+ @Override
+ public void onNext(ReverseResponse resp) {
+ int uid = connectivityManager.getConnectionOwnerUid(resp.getUid().getProtocol(), toInetSocketAddress(resp.getUid().getLocal()), toInetSocketAddress(resp.getUid().getRemote()));
+ String pkg = context.getPackageManager().getNameForUid(uid);
+ Log.i(TAG, "reverse onNext uid:" + uid + " package:" + pkg);
+
+ ReverseRequest req = ReverseRequest.newBuilder()
+ .setUid(GetConnectionOwnerUidResponse.newBuilder()
+ .setUid(uid)
+ .setPackage(pkg)
+ .build())
+ .build();
+
+ io.grpc.Context.current().fork().run(new Runnable() {
+ public void run() {
+ atomicRequestObserver.get().onNext(req);
+ }
+ });
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ // failed = t;
+ Log.i(TAG, "streamReverse error: " + t);
+ finishLatch.countDown();
+ }
+
+ @Override
+ public void onCompleted() {
+ Log.i(TAG, "streamReverse completed");
+ finishLatch.countDown();
+ }
+ };
+ StreamObserver<ReverseRequest> requestObserver = asyncStub.reverse(responseObserver);
+ atomicRequestObserver.set(requestObserver);
+
+ // Mark the end of requests
+ //requestObserver.onCompleted();
+
+ //requestObserver.onNext(ReverseRequest.getDefaultInstance());
+
+ Log.i(TAG, "Waiting streamReverse");
+ // Receiving happens asynchronously
+ if (!finishLatch.await(1, TimeUnit.HOURS)) {
+ throw new RuntimeException("Could not finish rpc within 1 minute, the server is likely down");
+ }
+
+ // if (failed != null) {
+ // throw new RuntimeException(failed);
+ // }
+ Log.i(TAG, "Exit streamReverse");
+ }
+
private void setStateInternal(final Tunnel tunnel, @Nullable final Config config, final State state)
throws Exception {
Log.i(TAG, "Bringing tunnel " + tunnel.getName() + ' ' + state);
@@ -359,6 +477,12 @@ public final class GoBackend implements Backend {
service.setUnderlyingNetworks(null);
builder.setBlocking(true);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ int listenPort = startHttpProxy();
+ ProxyInfo proxy = ProxyInfo.buildDirectProxy("localhost", listenPort);
+ builder.setHttpProxy(proxy);
+ }
try (final ParcelFileDescriptor tun = builder.establish()) {
if (tun == null)
throw new BackendException(Reason.TUN_CREATION_ERROR);
@@ -383,6 +507,7 @@ public final class GoBackend implements Backend {
currentTunnel = null;
currentTunnelHandle = -1;
currentConfig = null;
+ stopHttpProxy();
wgTurnOff(handleToClose);
}
@@ -445,6 +570,7 @@ public final class GoBackend implements Backend {
@Override
public void onDestroy() {
if (owner != null) {
+ owner.stopHttpProxy();
final Tunnel tunnel = owner.currentTunnel;
if (tunnel != null) {
if (owner.currentTunnelHandle != -1)
diff --git a/tunnel/src/main/proto/libwg.proto b/tunnel/src/main/proto/libwg.proto
index 065c663c..ce908d02 100644
--- a/tunnel/src/main/proto/libwg.proto
+++ b/tunnel/src/main/proto/libwg.proto
@@ -16,6 +16,9 @@ service Libwg {
rpc TurnOff(TurnOffRequest) returns (Empty);
rpc GetConfig(GetConfigRequest) returns (GetConfigResponse);
rpc Version(Empty) returns (VersionResponse);
+ rpc StartHttpProxy(StartHttpProxyRequest) returns (StartHttpProxyResponse);
+ rpc StopHttpProxy(StopHttpProxyRequest) returns (StopHttpProxyResponse);
+ rpc Reverse(stream ReverseRequest) returns (stream ReverseResponse);
}
// FIXME use google.protobuf.Empty
@@ -37,6 +40,11 @@ message InetAddress {
bytes address = 1;
}
+message InetSocketAddress {
+ InetAddress address = 1;
+ uint32 port = 2;
+}
+
message TurnOnRequest {
string interface_name = 1;
int32 tun_fd = 2;
@@ -63,3 +71,42 @@ message GetConfigResponse {
message VersionResponse {
string version = 1;
}
+
+message StartHttpProxyRequest {
+}
+
+message StartHttpProxyResponse {
+ uint32 listen_port = 1;
+ Error error = 2;
+}
+
+message StopHttpProxyRequest {
+}
+
+message StopHttpProxyResponse {
+ Error error = 1;
+}
+
+message ReverseRequest {
+ oneof response {
+ GetConnectionOwnerUidResponse uid = 1;
+ }
+}
+
+message ReverseResponse {
+ oneof request {
+ GetConnectionOwnerUidRequest uid = 1;
+ }
+}
+
+message GetConnectionOwnerUidRequest {
+ // ConnectivityManager.getConnectionOwnerUid(int protocol, InetSocketAddress local, InetSocketAddress remote)
+ int32 protocol = 1;
+ InetSocketAddress local = 2;
+ InetSocketAddress remote = 3;
+}
+
+message GetConnectionOwnerUidResponse {
+ int32 uid = 1;
+ string package = 2; // context.getPackageManager().getNameForUid()
+}
diff --git a/tunnel/tools/libwg-go/Makefile b/tunnel/tools/libwg-go/Makefile
index 32c5ae22..10a8f409 100644
--- a/tunnel/tools/libwg-go/Makefile
+++ b/tunnel/tools/libwg-go/Makefile
@@ -70,7 +70,7 @@ gen/%_grpc.pb.go: $(PROTODIR)/%.proto $(BUILDDIR)/go-$(GO_VERSION)/.prepared $(P
$(PROTOC) -I $(PROTODIR) --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 api-android.go service.go gen/libwg.pb.go gen/libwg_grpc.pb.go jni.c
+$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod api-android.go http-proxy.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" -v -trimpath -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 d0086a75..01608923 100644
--- a/tunnel/tools/libwg-go/api-android.go
+++ b/tunnel/tools/libwg-go/api-android.go
@@ -231,7 +231,7 @@ func Version() string {
//export wgStartGrpc
func wgStartGrpc(sock_path string) C.int{
- tag := cstring("helloworld")
+ 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,
@@ -240,6 +240,7 @@ func wgStartGrpc(sock_path string) C.int{
res, errmsg := StartGrpc(sock_path, logger)
logger.Verbosef("wgStartGrpc: %v %v", res, errmsg)
+
return C.int(res)
}
diff --git a/tunnel/tools/libwg-go/go.mod b/tunnel/tools/libwg-go/go.mod
index 33aa796d..3d24d309 100644
--- a/tunnel/tools/libwg-go/go.mod
+++ b/tunnel/tools/libwg-go/go.mod
@@ -3,7 +3,9 @@ module golang.zx2c4.com/wireguard/android
go 1.17
require (
+ github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08
+ golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d
golang.zx2c4.com/wireguard v0.0.0-20211111141719-cad0ff2cfbd9
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84
google.golang.org/protobuf v1.27.1
@@ -14,7 +16,6 @@ require (
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect
golang.org/x/net v0.0.0-20211111083644-e5c967477495 // indirect
golang.org/x/text v0.3.6 // indirect
- golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
)
diff --git a/tunnel/tools/libwg-go/go.sum b/tunnel/tools/libwg-go/go.sum
index f5bc4340..c68fb496 100644
--- a/tunnel/tools/libwg-go/go.sum
+++ b/tunnel/tools/libwg-go/go.sum
@@ -13,6 +13,10 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b h1:1XqENn2YoYZd6w3Awx+7oa+aR87DFIZJFLF2n1IojA0=
+github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
+github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
+github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -49,6 +53,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
diff --git a/tunnel/tools/libwg-go/http-proxy.go b/tunnel/tools/libwg-go/http-proxy.go
new file mode 100644
index 00000000..4af97314
--- /dev/null
+++ b/tunnel/tools/libwg-go/http-proxy.go
@@ -0,0 +1,165 @@
+package main
+
+import (
+ "net"
+ "net/http"
+ "net/url"
+
+ "github.com/elazarl/goproxy"
+
+ "golang.zx2c4.com/go118/netip"
+ "golang.zx2c4.com/wireguard/device"
+)
+
+type HttpProxy struct {
+ listener net.Listener
+ logger *device.Logger
+ addrPort netip.AddrPort
+ uidRequest chan netip.AddrPort
+ uidResponse chan string
+}
+
+func NewHttpProxy(uidRequest chan netip.AddrPort, uidResponse chan string, logger *device.Logger) *HttpProxy {
+ logger.Verbosef("NewHttpProxy")
+ return &HttpProxy{
+ listener: nil,
+ logger: logger,
+ uidRequest: uidRequest,
+ uidResponse: uidResponse,
+ }
+}
+
+func (p *HttpProxy) GetAddrPort() netip.AddrPort {
+ return p.addrPort
+}
+
+func newGoProxy(proxyUrl string) *goproxy.ProxyHttpServer {
+ proxy := goproxy.NewProxyHttpServer()
+ proxy.Verbose = true
+ proxy.Tr.Proxy = func(req *http.Request) (*url.URL, error) {
+ return url.Parse(proxyUrl)
+ }
+ proxy.ConnectDial = proxy.NewConnectDialToProxy(proxyUrl)
+
+ return proxy
+}
+
+func (p *HttpProxy) Start() (listen_port uint16, err error) {
+ p.logger.Verbosef("HttpProxy.Start()")
+ listen_port = 0
+
+ proxyMap := make(map[string]*goproxy.ProxyHttpServer)
+ proxyMap["bbc.iplayer.android"] = newGoProxy("http://10.49.124.111:8888")
+ proxyMap["no.nrk.tv"] = newGoProxy("http://10.49.124.115:8888")
+
+ defaultProxy := goproxy.NewProxyHttpServer()
+ defaultProxy.Verbose = true
+
+ listener, err := net.Listen("tcp", "localhost:")
+ if err != nil {
+ return
+ }
+
+ p.addrPort, err = netip.ParseAddrPort(listener.Addr().String())
+ if err != nil {
+ return
+ }
+
+ listen_port = p.addrPort.Port()
+
+ handler := NewHttpHandler(proxyMap, defaultProxy, p.logger)
+
+ go http.Serve(NewUidListener(listener, handler, p.uidRequest, p.uidResponse, p.logger), handler)
+
+ return
+}
+
+func (p *HttpProxy) Stop() {
+ if p.listener != nil {
+ p.logger.Verbosef("Close: %v", p.listener)
+ p.listener.Close()
+ p.listener = nil
+ }
+}
+
+type HttpHandler struct {
+ proxyMap map[string]*goproxy.ProxyHttpServer
+ defaultProxy *goproxy.ProxyHttpServer
+ logger *device.Logger
+ remoteAddrPkgMap map[string]string
+}
+
+func NewHttpHandler(proxyMap map[string]*goproxy.ProxyHttpServer, defaultProxy *goproxy.ProxyHttpServer, logger *device.Logger) *HttpHandler{
+ return &HttpHandler{
+ proxyMap: proxyMap,
+ defaultProxy: defaultProxy,
+ logger: logger,
+ remoteAddrPkgMap: make(map[string]string),
+ }
+}
+
+func (h *HttpHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
+ pkg, ok := h.remoteAddrPkgMap[req.RemoteAddr]
+ if ok {
+ h.logger.Verbosef("ServeHTTP remote:%s package:%s", req.RemoteAddr, pkg)
+ delete(h.remoteAddrPkgMap, req.RemoteAddr)
+
+ proxy, ok := h.proxyMap[pkg]
+ if ok {
+ proxy.ServeHTTP(rw, req)
+ } else {
+ h.defaultProxy.ServeHTTP(rw, req)
+ }
+ } else {
+ h.defaultProxy.ServeHTTP(rw, req)
+ }
+}
+
+// UidListener
+type UidListener struct {
+ l net.Listener
+ handler *HttpHandler
+ logger *device.Logger
+ uidRequest chan netip.AddrPort
+ uidResponse chan string
+}
+
+func NewUidListener(listener net.Listener, handler *HttpHandler, uidRequest chan netip.AddrPort, uidResponse chan string, logger *device.Logger) *UidListener{
+ return &UidListener{
+ l: listener,
+ handler: handler,
+ logger: logger,
+ uidRequest: uidRequest,
+ uidResponse: uidResponse,
+ }
+}
+
+func (l *UidListener) Accept() (net.Conn, error) {
+ c, err := l.l.Accept()
+ if err != nil {
+ return c, err
+ }
+
+ l.logger.Verbosef("Accept: %v", c.RemoteAddr().String())
+ addr_port, err := netip.ParseAddrPort(c.RemoteAddr().String())
+ if err == nil {
+ l.logger.Verbosef("uidRequest")
+ l.uidRequest <- addr_port
+
+ // TODO add timeout?
+ select {
+ case pkg := <-l.uidResponse:
+ l.logger.Verbosef("uidResponse: %v", pkg)
+ l.handler.remoteAddrPkgMap[c.RemoteAddr().String()] = pkg
+ }
+ }
+ return c, nil
+}
+
+func (l *UidListener) Close() error {
+ return l.l.Close()
+}
+
+func (l *UidListener) Addr() net.Addr {
+ return l.l.Addr()
+}
diff --git a/tunnel/tools/libwg-go/service.go b/tunnel/tools/libwg-go/service.go
index 904dbdcd..e370f824 100644
--- a/tunnel/tools/libwg-go/service.go
+++ b/tunnel/tools/libwg-go/service.go
@@ -3,25 +3,40 @@ package main
import (
"context"
"fmt"
+ "io"
"net"
"os"
"google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+ "golang.zx2c4.com/go118/netip"
gen "golang.zx2c4.com/wireguard/android/gen"
"golang.zx2c4.com/wireguard/device"
)
+const (
+ IPPROTO_TCP = 6
+)
+
type LibwgServiceImpl struct {
gen.UnimplementedLibwgServer
logger *device.Logger
+ http_proxy *HttpProxy
+ uidRequest chan netip.AddrPort
+ uidResponse chan string
}
var _ gen.LibwgServer = (*LibwgServiceImpl)(nil)
var server *grpc.Server
func NewLibwgService(logger *device.Logger) gen.LibwgServer {
- return &LibwgServiceImpl{logger: logger}
+ return &LibwgServiceImpl{
+ logger: logger,
+ uidRequest: make(chan netip.AddrPort),
+ uidResponse: make(chan string),
+ }
}
func StartGrpc(sock_path string, logger *device.Logger) (int, string) {
@@ -76,3 +91,109 @@ func (e *LibwgServiceImpl) StopGrpc(ctx context.Context, req *gen.Empty) (*gen.E
return r, nil
}
+
+func (e *LibwgServiceImpl) StartHttpProxy(ctx context.Context, req *gen.StartHttpProxyRequest) (*gen.StartHttpProxyResponse, error) {
+ if e.http_proxy != nil {
+ listen_port := e.http_proxy.GetAddrPort().Port()
+ r := &gen.StartHttpProxyResponse{
+ ListenPort: uint32(listen_port),
+ Error: &gen.Error{
+ Message: fmt.Sprintf("Http proxy already running"),
+ },
+ }
+ return r, nil
+ }
+
+ e.http_proxy = NewHttpProxy(e.uidRequest, e.uidResponse, e.logger)
+ listen_port, err := e.http_proxy.Start()
+
+ if err != nil {
+ r := &gen.StartHttpProxyResponse{
+ Error: &gen.Error{
+ Message: fmt.Sprintf("Http proxy start: %v", err),
+ },
+ }
+ return r, nil
+ }
+
+ r := &gen.StartHttpProxyResponse{
+ ListenPort: uint32(listen_port),
+ }
+
+ e.logger.Verbosef("Started http proxy")
+ return r, nil
+}
+
+func (e *LibwgServiceImpl) StopHttpProxy(ctx context.Context, req *gen.StopHttpProxyRequest) (*gen.StopHttpProxyResponse, error) {
+ if e.http_proxy == nil {
+ r := &gen.StopHttpProxyResponse{
+ Error: &gen.Error{
+ Message: fmt.Sprintf("Http proxy not running"),
+ },
+ }
+ return r, nil
+ }
+
+ e.http_proxy.Stop()
+ e.http_proxy = nil
+ r := &gen.StopHttpProxyResponse{}
+ e.logger.Verbosef("Stopped http proxy")
+ return r, nil
+}
+
+func (e *LibwgServiceImpl) Reverse(stream gen.Libwg_ReverseServer) error {
+ e.logger.Verbosef("Reverse enter loop")
+ for {
+ var err error
+
+ // err := contextError(stream.Context())
+ err = stream.Context().Err()
+ if err != nil {
+ e.logger.Verbosef("Reverse: context: %v", err)
+ return err
+ }
+
+ select {
+ case addr_port := <-e.uidRequest:
+ r := &gen.ReverseResponse{
+ Request: &gen.ReverseResponse_Uid{
+ Uid: &gen.GetConnectionOwnerUidRequest{
+ Protocol: IPPROTO_TCP,
+ Local: &gen.InetSocketAddress{
+ Address: &gen.InetAddress{
+ Address: addr_port.Addr().AsSlice(),
+ },
+ Port: uint32(addr_port.Port()),
+ },
+ Remote: &gen.InetSocketAddress{
+ Address: &gen.InetAddress{
+ Address: e.http_proxy.GetAddrPort().Addr().AsSlice(),
+ },
+ Port: uint32(e.http_proxy.GetAddrPort().Port()),
+ },
+ },
+ },
+ }
+
+ stream.Send(r)
+ }
+
+ req, err := stream.Recv()
+ if err == io.EOF {
+ e.logger.Verbosef("no more data")
+ break
+ }
+ if err != nil {
+ err = status.Errorf(codes.Unknown, "cannot receive stream request: %v", err)
+ e.logger.Verbosef("Reverse: %v", err)
+ return err
+ }
+
+ e.logger.Verbosef("Reverse: received, wait: %v", req)
+ e.uidResponse <- req.GetUid().GetPackage()
+ }
+
+
+ e.logger.Verbosef("Reverse returns")
+ return nil
+}