summaryrefslogtreecommitdiffhomepage
path: root/tunnel/src/main/java/com/wireguard/android
diff options
context:
space:
mode:
Diffstat (limited to 'tunnel/src/main/java/com/wireguard/android')
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java214
1 files changed, 158 insertions, 56 deletions
diff --git a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
index e8148c04..375de1f2 100644
--- a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
+++ b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
@@ -28,9 +28,12 @@ import com.google.protobuf.Empty;
import com.wireguard.android.backend.BackendException.Reason;
import com.wireguard.android.backend.Tunnel.State;
+import com.wireguard.android.backend.gen.DhcpRequest;
+import com.wireguard.android.backend.gen.DhcpResponse;
import com.wireguard.android.backend.gen.GetConnectionOwnerUidResponse;
import com.wireguard.android.backend.gen.IpcSetRequest;
import com.wireguard.android.backend.gen.IpcSetResponse;
+import com.wireguard.android.backend.gen.Lease;
import com.wireguard.android.backend.gen.LibwgGrpc;
import com.wireguard.android.backend.gen.ReverseRequest;
import com.wireguard.android.backend.gen.ReverseResponse;
@@ -71,6 +74,7 @@ import java.net.UnknownHostException;
import java.net.URL;
import java.nio.ByteOrder;
import java.util.Collections;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -103,7 +107,9 @@ public final class GoBackend implements Backend {
private ManagedChannel channel;
private ConnectivityManager connectivityManager;
private ConnectivityManager.NetworkCallback myNetworkCallback = new MyNetworkCallback();
+ private ConnectivityManager.NetworkCallback vpnNetworkCallback;
@Nullable private Network activeNetwork;
+ private boolean obtainDhcpLease = false;
/**
* Public constructor for GoBackend.
@@ -140,6 +146,8 @@ public final class GoBackend implements Backend {
private static native int wgGetSocketV6(int handle);
+ private static native void wgSetFd(int handle, int tunFd);
+
private static native void wgTurnOff(int handle);
private static native int wgTurnOn(String ifName, int tunFd, String settings);
@@ -344,6 +352,34 @@ public final class GoBackend implements Backend {
}
}
+ private void Dhcp(VpnService service) throws Exception{
+ obtainDhcpLease = false;
+
+ LibwgGrpc.LibwgBlockingStub stub = LibwgGrpc.newBlockingStub(channel);
+ DhcpRequest request = DhcpRequest.newBuilder().build();
+ DhcpResponse resp = stub.dhcp(request);
+ Log.i(TAG, "Dhcp: " + resp.getError().getMessage());
+
+ // Replace the vpn tunnel
+ final VpnService.Builder builder = getBuilder(currentTunnel.getName(), currentConfig, service, resp.getLeasesList());
+
+ Log.i(TAG, "Builder: " + builder);
+
+ try (final ParcelFileDescriptor tun = builder.establish()) {
+ if (tun == null)
+ throw new BackendException(Reason.TUN_CREATION_ERROR);
+ Log.d(TAG, "Go backend " + wgVersion());
+ // SetFd
+ wgSetFd(currentTunnelHandle, tun.detachFd());
+ }
+ if (currentTunnelHandle < 0)
+ throw new BackendException(Reason.GO_ACTIVATION_ERROR_CODE, currentTunnelHandle);
+
+ service.protect(wgGetSocketV4(currentTunnelHandle));
+ service.protect(wgGetSocketV6(currentTunnelHandle));
+ Log.i(TAG, "Dhcp done");
+ }
+
private int getConnectionOwnerUid(int protocol, InetSocketAddress local, InetSocketAddress remote) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
return connectivityManager.getConnectionOwnerUid(protocol, local, remote);
@@ -426,6 +462,94 @@ public final class GoBackend implements Backend {
Log.i(TAG, "Exit streamReverse");
}
+ private VpnService.Builder getBuilder(final String name, @Nullable final Config config, final VpnService service, @Nullable final List<Lease> leases) throws PackageManager.NameNotFoundException {
+ Log.i(TAG, "Builder 1");
+ final VpnService.Builder builder = service.getBuilder();
+ Log.i(TAG, "Builder 2");
+ builder.setSession(name);
+
+ Log.i(TAG, "Builder 3");
+ for (final String excludedApplication : config.getInterface().getExcludedApplications())
+ builder.addDisallowedApplication(excludedApplication);
+
+ Log.i(TAG, "Builder 4");
+ for (final String includedApplication : config.getInterface().getIncludedApplications())
+ builder.addAllowedApplication(includedApplication);
+
+ Log.i(TAG, "Builder 5");
+ if (leases != null) {
+ for (final Lease lease: leases) {
+ try {
+ InetAddress addr = InetAddress.getByAddress(lease.getAddress().getAddress().toByteArray());
+ Log.i(TAG, "Lease: " + addr);
+ builder.addAddress(addr, 128);
+ } catch (UnknownHostException ex) {
+ // Ignore
+ }
+ }
+ }
+
+ Log.i(TAG, "Builder 6");
+ for (final InetNetwork addr : config.getInterface().getAddresses())
+ builder.addAddress(addr.getAddress(), addr.getMask());
+
+ Log.i(TAG, "Builder 7");
+ for (final InetAddress addr : config.getInterface().getDnsServers())
+ builder.addDnsServer(addr.getHostAddress());
+
+ Log.i(TAG, "Builder 8");
+ for (final String dnsSearchDomain : config.getInterface().getDnsSearchDomains())
+ builder.addSearchDomain(dnsSearchDomain);
+
+ Log.i(TAG, "Builder 9");
+ boolean sawDefaultRoute = false;
+ for (final Peer peer : config.getPeers()) {
+ for (final InetNetwork addr : peer.getAllowedIps()) {
+ if (addr.getMask() == 0)
+ sawDefaultRoute = true;
+ builder.addRoute(addr.getAddress(), addr.getMask());
+ }
+ }
+
+ Log.i(TAG, "Builder 10");
+ // "Kill-switch" semantics
+ if (!(sawDefaultRoute && config.getPeers().size() == 1)) {
+ builder.allowFamily(OsConstants.AF_INET);
+ builder.allowFamily(OsConstants.AF_INET6);
+ }
+
+ Log.i(TAG, "Builder 11");
+ builder.setMtu(config.getInterface().getMtu().orElse(1280));
+
+ Log.i(TAG, "Builder 12");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
+ builder.setMetered(false);
+ Log.i(TAG, "Builder 13");
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
+ service.setUnderlyingNetworks(null);
+
+ Log.i(TAG, "Builder 14");
+ // Optional<HttpProxy> proxy = config.getInterface().getHttpProxy();
+ // if (proxy.isPresent()) {
+ // ProxyInfo pi = proxy.get().getProxyInfo();
+ // Uri pacFileUrl = pi.getPacFileUrl();
+
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ // if (pacFileUrl != null && pacFileUrl != Uri.EMPTY) {
+ // int listenPort = startHttpProxy(pacFileUrl);
+ // ProxyInfo localPi = ProxyInfo.buildDirectProxy("localhost", listenPort);
+ // builder.setHttpProxy(localPi);
+ // } else {
+ // builder.setHttpProxy(pi);
+ // }
+ // }
+ // }
+
+ Log.i(TAG, "Builder 15");
+ builder.setBlocking(true);
+ return builder;
+ }
+
private void setStateInternal(final Tunnel tunnel, @Nullable final Config config, final State state)
throws Exception {
Log.i(TAG, "Bringing tunnel " + tunnel.getName() + ' ' + state);
@@ -486,63 +610,8 @@ public final class GoBackend implements Backend {
final String goConfig = config.toWgUserspaceString(resolver);
// Create the vpn tunnel with android API
- final VpnService.Builder builder = service.getBuilder();
- builder.setSession(tunnel.getName());
-
- for (final String excludedApplication : config.getInterface().getExcludedApplications())
- builder.addDisallowedApplication(excludedApplication);
-
- for (final String includedApplication : config.getInterface().getIncludedApplications())
- builder.addAllowedApplication(includedApplication);
-
- for (final InetNetwork addr : config.getInterface().getAddresses())
- builder.addAddress(addr.getAddress(), addr.getMask());
-
- for (final InetAddress addr : config.getInterface().getDnsServers())
- builder.addDnsServer(addr.getHostAddress());
-
- for (final String dnsSearchDomain : config.getInterface().getDnsSearchDomains())
- builder.addSearchDomain(dnsSearchDomain);
-
- boolean sawDefaultRoute = false;
- for (final Peer peer : config.getPeers()) {
- for (final InetNetwork addr : peer.getAllowedIps()) {
- if (addr.getMask() == 0)
- sawDefaultRoute = true;
- builder.addRoute(addr.getAddress(), addr.getMask());
- }
- }
-
- // "Kill-switch" semantics
- if (!(sawDefaultRoute && config.getPeers().size() == 1)) {
- builder.allowFamily(OsConstants.AF_INET);
- builder.allowFamily(OsConstants.AF_INET6);
- }
-
- builder.setMtu(config.getInterface().getMtu().orElse(1280));
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
- builder.setMetered(false);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
- service.setUnderlyingNetworks(null);
-
- Optional<HttpProxy> proxy = config.getInterface().getHttpProxy();
- if (proxy.isPresent()) {
- ProxyInfo pi = proxy.get().getProxyInfo();
- Uri pacFileUrl = pi.getPacFileUrl();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- if (pacFileUrl != null && pacFileUrl != Uri.EMPTY) {
- int listenPort = startHttpProxy(pacFileUrl);
- ProxyInfo localPi = ProxyInfo.buildDirectProxy("localhost", listenPort);
- builder.setHttpProxy(localPi);
- } else {
- builder.setHttpProxy(pi);
- }
- }
- }
+ final VpnService.Builder builder = getBuilder(tunnel.getName(), config, service, null);
- builder.setBlocking(true);
try (final ParcelFileDescriptor tun = builder.establish()) {
if (tun == null)
throw new BackendException(Reason.TUN_CREATION_ERROR);
@@ -558,8 +627,14 @@ public final class GoBackend implements Backend {
service.protect(wgGetSocketV4(currentTunnelHandle));
service.protect(wgGetSocketV6(currentTunnelHandle));
+ obtainDhcpLease = true;
+
NetworkRequest req = new NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN).build();
connectivityManager.requestNetwork(req, myNetworkCallback);
+
+ NetworkRequest vpnReq = new NetworkRequest.Builder().addTransportType(NetworkCapabilities.TRANSPORT_VPN).removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN).build();
+ vpnNetworkCallback = new VpnNetworkCallback(service);
+ connectivityManager.requestNetwork(vpnReq, vpnNetworkCallback);
} else {
if (currentTunnelHandle == -1) {
Log.w(TAG, "Tunnel already down");
@@ -570,6 +645,9 @@ public final class GoBackend implements Backend {
currentTunnelHandle = -1;
currentConfig = null;
stopHttpProxy();
+ if (vpnNetworkCallback != null)
+ connectivityManager.unregisterNetworkCallback(vpnNetworkCallback);
+ vpnNetworkCallback = null;
connectivityManager.unregisterNetworkCallback(myNetworkCallback);
activeNetwork = null;
wgTurnOff(handleToClose);
@@ -638,6 +716,9 @@ public final class GoBackend implements Backend {
final Tunnel tunnel = owner.currentTunnel;
if (tunnel != null) {
if (owner.currentTunnelHandle != -1) {
+ if (owner.vpnNetworkCallback != null)
+ owner.connectivityManager.unregisterNetworkCallback(owner.vpnNetworkCallback);
+ owner.vpnNetworkCallback = null;
owner.connectivityManager.unregisterNetworkCallback(owner.myNetworkCallback);
owner.activeNetwork = null;
wgTurnOff(owner.currentTunnelHandle);
@@ -668,6 +749,27 @@ public final class GoBackend implements Backend {
}
}
+ private class VpnNetworkCallback extends ConnectivityManager.NetworkCallback {
+ private VpnService service;
+ public VpnNetworkCallback(VpnService service) {
+ this.service = service;
+ }
+ @Override
+ public void onAvailable(Network network) {
+ Log.w(TAG, "VPN onAvailable: " + network);
+ if (obtainDhcpLease) {
+ Log.w(TAG, "Obtaindhcplease");
+ try {
+ Log.w(TAG, "Before Dhcp");
+ Dhcp(service);
+ Log.w(TAG, "After Dhcp");
+ } catch (Exception ex) {
+ Log.e(TAG, "DHCP failed: " + ex);
+ }
+ }
+ }
+ }
+
private class MyNetworkCallback extends ConnectivityManager.NetworkCallback {
@Override
public void onAvailable(Network network) {