summaryrefslogtreecommitdiffhomepage
path: root/tunnel/src/main/java
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 /tunnel/src/main/java
parente99531653dedd3d4180016f5cffc7c29f0af378c (diff)
tunnel: WIP implement http proxy for Android 10+
TODO: fix hard-coded proxy URLs.
Diffstat (limited to 'tunnel/src/main/java')
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java128
1 files changed, 127 insertions, 1 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)