GoBackend: Use the android VpnService to encapsulate the go backend

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Aurélien Chabot 2018-02-19 08:16:26 +11:00 committed by Jason A. Donenfeld
parent 19aec7c5c6
commit 9dfab4d60f
3 changed files with 99 additions and 7 deletions

View File

@ -50,6 +50,14 @@
</intent-filter> </intent-filter>
</receiver> </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 <service
android:name=".QuickTileService" android:name=".QuickTileService"
android:icon="@drawable/ic_tile" android:icon="@drawable/ic_tile"

View File

@ -1,11 +1,13 @@
package com.wireguard.android.activity; package com.wireguard.android.activity;
import android.app.Activity; import android.app.Activity;
import android.content.Intent;
import android.databinding.CallbackRegistry; import android.databinding.CallbackRegistry;
import android.databinding.CallbackRegistry.NotifierCallback; import android.databinding.CallbackRegistry.NotifierCallback;
import android.os.Bundle; import android.os.Bundle;
import com.wireguard.android.Application; import com.wireguard.android.Application;
import com.wireguard.android.backend.GoBackend;
import com.wireguard.android.model.Tunnel; import com.wireguard.android.model.Tunnel;
import com.wireguard.android.model.TunnelManager; import com.wireguard.android.model.TunnelManager;
@ -42,8 +44,16 @@ public abstract class BaseActivity extends Activity {
final TunnelManager tunnelManager = Application.getComponent().getTunnelManager(); final TunnelManager tunnelManager = Application.getComponent().getTunnelManager();
selectedTunnel = tunnelManager.getTunnels().get(savedTunnelName); selectedTunnel = tunnelManager.getTunnels().get(savedTunnelName);
} }
// The selected tunnel must be set before the superclass method recreates fragments. // The selected tunnel must be set before the superclass method recreates fragments.
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (Application.getComponent().getBackendType() == GoBackend.class) {
Intent intent = GoBackend.VpnService.prepare(this);
if (intent != null) {
startActivityForResult(intent, 0);
}
}
} }
@Override @Override

View File

@ -1,6 +1,8 @@
package com.wireguard.android.backend; package com.wireguard.android.backend;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.os.ParcelFileDescriptor;
import android.support.v4.util.ArraySet; import android.support.v4.util.ArraySet;
import android.util.Log; import android.util.Log;
@ -23,13 +25,36 @@ public final class GoBackend implements Backend {
System.loadLibrary("wg-go"); System.loadLibrary("wg-go");
} }
private final Context context;
private Tunnel currentTunnel; private Tunnel currentTunnel;
private int currentTunnelHandle = -1;
public GoBackend(final Context context) { private Context context;
public GoBackend(Context context) {
this.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 wgGetSocketV4(int handle);
private static native int wgGetSocketV6(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) private void setStateInternal(final Tunnel tunnel, final Config config, final State state)
throws Exception { throws Exception {
if (state == State.UP) {
// Do something (context.startService()...).
currentTunnel = tunnel;
if (state == State.UP) {
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()); Formatter fmt = new Formatter(new StringBuilder());
final Interface iface = config.getInterface(); final Interface iface = config.getInterface();
fmt.format("replace_peers=true\n"); 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 { } else {
// Do something else. Log.i(TAG, "Bringing tunnel down");
if (currentTunnelHandle == -1) {
Log.w(TAG, "Tunnel already down");
return;
}
wgTurnOff(currentTunnelHandle);
currentTunnel = null; currentTunnel = null;
currentTunnelHandle = -1;
} }
} }
} }