GoBackend: Use the android VpnService to encapsulate the go backend
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
19aec7c5c6
commit
9dfab4d60f
@ -50,6 +50,14 @@
|
||||
</intent-filter>
|
||||
</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"
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
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());
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user