diff options
author | Aurélien Chabot <aurelien@chabot.fr> | 2018-02-19 08:16:26 +1100 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2018-04-17 02:15:24 +0200 |
commit | 9dfab4d60f5dc06445df53d675a458dfae8cb5f6 (patch) | |
tree | e03f535972727ad83ff8daf1a33a7393ad749b57 /app/src/main | |
parent | 19aec7c5c68ae5f8763004d3673c57d0722db39a (diff) |
GoBackend: Use the android VpnService to encapsulate the go backend
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'app/src/main')
-rw-r--r-- | app/src/main/AndroidManifest.xml | 8 | ||||
-rw-r--r-- | app/src/main/java/com/wireguard/android/activity/BaseActivity.java | 10 | ||||
-rw-r--r-- | app/src/main/java/com/wireguard/android/backend/GoBackend.java | 86 |
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; } } } |