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>
|
</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"
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user