summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAurélien Chabot <aurelien@chabot.fr>2018-02-19 08:16:26 +1100
committerJason A. Donenfeld <Jason@zx2c4.com>2018-04-17 02:15:24 +0200
commit9dfab4d60f5dc06445df53d675a458dfae8cb5f6 (patch)
treee03f535972727ad83ff8daf1a33a7393ad749b57
parent19aec7c5c68ae5f8763004d3673c57d0722db39a (diff)
GoBackend: Use the android VpnService to encapsulate the go backend
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--app/src/main/AndroidManifest.xml8
-rw-r--r--app/src/main/java/com/wireguard/android/activity/BaseActivity.java10
-rw-r--r--app/src/main/java/com/wireguard/android/backend/GoBackend.java86
3 files changed, 98 insertions, 6 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8104350f..d42eabdc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -51,6 +51,14 @@
</receiver>
<service
+ android:name=".backend.GoBackend$VpnService"
+ android:permission="android.permission.BIND_VPN_SERVICE" >
+ <intent-filter>
+ <action android:name="android.net.VpnService" />
+ </intent-filter>
+ </service>
+
+ <service
android:name=".QuickTileService"
android:icon="@drawable/ic_tile"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
diff --git a/app/src/main/java/com/wireguard/android/activity/BaseActivity.java b/app/src/main/java/com/wireguard/android/activity/BaseActivity.java
index 10c7bca9..f6f56601 100644
--- a/app/src/main/java/com/wireguard/android/activity/BaseActivity.java
+++ b/app/src/main/java/com/wireguard/android/activity/BaseActivity.java
@@ -1,11 +1,13 @@
package com.wireguard.android.activity;
import android.app.Activity;
+import android.content.Intent;
import android.databinding.CallbackRegistry;
import android.databinding.CallbackRegistry.NotifierCallback;
import android.os.Bundle;
import com.wireguard.android.Application;
+import com.wireguard.android.backend.GoBackend;
import com.wireguard.android.model.Tunnel;
import com.wireguard.android.model.TunnelManager;
@@ -42,8 +44,16 @@ public abstract class BaseActivity extends Activity {
final TunnelManager tunnelManager = Application.getComponent().getTunnelManager();
selectedTunnel = tunnelManager.getTunnels().get(savedTunnelName);
}
+
// The selected tunnel must be set before the superclass method recreates fragments.
super.onCreate(savedInstanceState);
+
+ if (Application.getComponent().getBackendType() == GoBackend.class) {
+ Intent intent = GoBackend.VpnService.prepare(this);
+ if (intent != null) {
+ startActivityForResult(intent, 0);
+ }
+ }
}
@Override
diff --git a/app/src/main/java/com/wireguard/android/backend/GoBackend.java b/app/src/main/java/com/wireguard/android/backend/GoBackend.java
index db059e22..eda4123c 100644
--- a/app/src/main/java/com/wireguard/android/backend/GoBackend.java
+++ b/app/src/main/java/com/wireguard/android/backend/GoBackend.java
@@ -1,6 +1,8 @@
package com.wireguard.android.backend;
import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
import android.support.v4.util.ArraySet;
import android.util.Log;
@@ -23,13 +25,36 @@ public final class GoBackend implements Backend {
System.loadLibrary("wg-go");
}
- private final Context context;
private Tunnel currentTunnel;
+ private int currentTunnelHandle = -1;
- public GoBackend(final Context context) {
+ private Context context;
+
+ public GoBackend(Context context) {
this.context = context;
+ context.startService(new Intent(context, VpnService.class));
+ }
+
+ public static class VpnService extends android.net.VpnService {
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ vpnService = this;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ vpnService = null;
+ }
+
+ public Builder getBuilder() {
+ return new Builder();
+ }
}
+ private static VpnService vpnService = null;
+
private static native int wgGetSocketV4(int handle);
private static native int wgGetSocketV6(int handle);
@@ -90,10 +115,22 @@ public final class GoBackend implements Backend {
private void setStateInternal(final Tunnel tunnel, final Config config, final State state)
throws Exception {
+
if (state == State.UP) {
- // Do something (context.startService()...).
- currentTunnel = tunnel;
+ Log.i(TAG, "Bringing tunnel up");
+
+ if (VpnService.prepare(context) != null)
+ throw new Exception("VPN service not authorized by user");
+ if (vpnService == null)
+ throw new Exception("Android VPN service is not running");
+
+ if (currentTunnelHandle != -1) {
+ Log.w(TAG, "Tunnel already up");
+ return;
+ }
+
+ // Build config
Formatter fmt = new Formatter(new StringBuilder());
final Interface iface = config.getInterface();
fmt.format("replace_peers=true\n");
@@ -116,10 +153,47 @@ public final class GoBackend implements Backend {
}
}
}
- wgTurnOn(tunnel.getName(), -1, fmt.toString());
+
+ // Create the vpn tunnel with android API
+ VpnService.Builder builder = vpnService.getBuilder();
+ builder.setSession(tunnel.getName());
+ builder.addAddress(config.getInterface().getAddress(), 32);
+ if (config.getInterface().getDns() != null)
+ builder.addDnsServer(config.getInterface().getDns());
+
+ for (final Peer peer : config.getPeers()) {
+ if (peer.getAllowedIPs() != null) {
+ for (final String allowedIp : peer.getAllowedIPs().split(" *, *")) {
+ String[] part = allowedIp.split("/", 2);
+ builder.addRoute(part[0], Integer.parseInt(part[1]));
+ }
+ }
+ }
+
+ builder.setBlocking(true);
+ ParcelFileDescriptor tun = builder.establish();
+ if (tun == null)
+ throw new Exception("Unable to create tun device");
+
+ currentTunnelHandle = wgTurnOn(tunnel.getName(), tun.detachFd(), fmt.toString());
+ if (currentTunnelHandle < 0)
+ throw new Exception("Unable to turn tunnel on (wgTurnOn return " + currentTunnelHandle + ")");
+
+ currentTunnel = tunnel;
+
+ vpnService.protect(wgGetSocketV4(currentTunnelHandle));
+ vpnService.protect(wgGetSocketV6(currentTunnelHandle));
} else {
- // Do something else.
+ Log.i(TAG, "Bringing tunnel down");
+
+ if (currentTunnelHandle == -1) {
+ Log.w(TAG, "Tunnel already down");
+ return;
+ }
+
+ wgTurnOff(currentTunnelHandle);
currentTunnel = null;
+ currentTunnelHandle = -1;
}
}
}