diff options
author | Mikael Magnusson <mikma@users.sourceforge.net> | 2021-11-20 20:03:32 +0100 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2022-03-18 22:04:47 +0100 |
commit | 2e5c0ca5c079a783992fc3f2bb6bd5f64bceadc1 (patch) | |
tree | ce5cd426b7bf61873cfc3f5999148dc08c9e6048 | |
parent | e99531653dedd3d4180016f5cffc7c29f0af378c (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.java | 128 | ||||
-rw-r--r-- | tunnel/src/main/proto/libwg.proto | 47 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/Makefile | 2 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/api-android.go | 3 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/go.mod | 3 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/go.sum | 5 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/http-proxy.go | 165 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/service.go | 123 |
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 +} |