diff options
author | Mikael Magnusson <mikma@users.sourceforge.net> | 2022-12-29 00:23:17 +0100 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2023-05-10 21:08:27 +0200 |
commit | 8033d4fb8ea06c5182fa79a6f6c9f9464a3543b8 (patch) | |
tree | 3bf11f940cef017603b409930a9e9f91148a912f /tunnel/src/main/java/com/wireguard/android | |
parent | dfe485619b5d7c7a2a3a5fb3eff54bcec6776a79 (diff) |
ui,tunnel: auto-detect IPv6/IPv4 preference
Detect IP address change.
Request non-VPN network.
Update endpoint when needed.
Unregister network on wgTurnOff and use IPv4 if network is not known.
Diffstat (limited to 'tunnel/src/main/java/com/wireguard/android')
-rw-r--r-- | tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java | 53 |
1 files changed, 50 insertions, 3 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 68acd2e8..ac1d03c4 100644 --- a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java +++ b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java @@ -9,7 +9,11 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.ConnectivityManager; +import android.net.LinkProperties; import android.net.LocalSocketAddress; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.net.ProxyInfo; import android.net.Uri; import android.os.Build; @@ -25,6 +29,8 @@ 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.GetConnectionOwnerUidResponse; +import com.wireguard.android.backend.gen.IpcSetRequest; +import com.wireguard.android.backend.gen.IpcSetResponse; import com.wireguard.android.backend.gen.LibwgGrpc; import com.wireguard.android.backend.gen.ReverseRequest; import com.wireguard.android.backend.gen.ReverseResponse; @@ -32,6 +38,7 @@ import com.wireguard.android.backend.gen.StartHttpProxyRequest; import com.wireguard.android.backend.gen.StartHttpProxyResponse; import com.wireguard.android.backend.gen.StopHttpProxyRequest; import com.wireguard.android.backend.gen.StopHttpProxyResponse; +import com.wireguard.android.backend.gen.TunnelHandle; import com.wireguard.android.backend.gen.VersionRequest; import com.wireguard.android.backend.gen.VersionResponse; import com.wireguard.android.util.SharedLibraryLoader; @@ -43,6 +50,7 @@ import com.wireguard.config.Peer; import com.wireguard.crypto.Key; import com.wireguard.crypto.KeyFormatException; import com.wireguard.util.NonNullForAll; +import com.wireguard.util.Resolver; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; @@ -94,6 +102,8 @@ public final class GoBackend implements Backend { private int currentTunnelHandle = -1; private ManagedChannel channel; private ConnectivityManager connectivityManager; + private ConnectivityManager.NetworkCallback myNetworkCallback = new MyNetworkCallback(); + @Nullable private Network activeNetwork; /** * Public constructor for GoBackend. @@ -434,13 +444,19 @@ public final class GoBackend implements Backend { } + activeNetwork = connectivityManager.getActiveNetwork(); + if (!connectivityManager.getNetworkCapabilities(activeNetwork).hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)) { + Log.w(TAG, "VPN network is active, null activeNetwork"); + activeNetwork = null; + } + final Resolver resolver = new Resolver(activeNetwork, connectivityManager.getLinkProperties(activeNetwork)); dnsRetry: for (int i = 0; i < DNS_RESOLUTION_RETRIES; ++i) { // Pre-resolve IPs so they're cached when building the userspace string for (final Peer peer : config.getPeers()) { final InetEndpoint ep = peer.getEndpoint().orElse(null); if (ep == null) continue; - if (ep.getResolved().orElse(null) == null) { + if (ep.getResolved(resolver, true).orElse(null) == null) { if (i < DNS_RESOLUTION_RETRIES - 1) { Log.w(TAG, "DNS host \"" + ep.getHost() + "\" failed to resolve; trying again"); Thread.sleep(1000); @@ -453,7 +469,7 @@ public final class GoBackend implements Backend { } // Build config - final String goConfig = config.toWgUserspaceString(); + final String goConfig = config.toWgUserspaceString(resolver); // Create the vpn tunnel with android API final VpnService.Builder builder = service.getBuilder(); @@ -527,6 +543,9 @@ public final class GoBackend implements Backend { service.protect(wgGetSocketV4(currentTunnelHandle)); service.protect(wgGetSocketV6(currentTunnelHandle)); + + NetworkRequest req = new NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN).build(); + connectivityManager.requestNetwork(req, myNetworkCallback); } else { if (currentTunnelHandle == -1) { Log.w(TAG, "Tunnel already down"); @@ -537,6 +556,8 @@ public final class GoBackend implements Backend { currentTunnelHandle = -1; currentConfig = null; stopHttpProxy(); + connectivityManager.unregisterNetworkCallback(myNetworkCallback); + activeNetwork = null; wgTurnOff(handleToClose); try { vpnService.get(0, TimeUnit.NANOSECONDS).stopSelf(); @@ -605,8 +626,11 @@ public final class GoBackend implements Backend { owner.stopHttpProxy(); final Tunnel tunnel = owner.currentTunnel; if (tunnel != null) { - if (owner.currentTunnelHandle != -1) + if (owner.currentTunnelHandle != -1) { + owner.connectivityManager.unregisterNetworkCallback(owner.myNetworkCallback); + owner.activeNetwork = null; wgTurnOff(owner.currentTunnelHandle); + } owner.currentTunnel = null; owner.currentTunnelHandle = -1; owner.currentConfig = null; @@ -632,4 +656,27 @@ public final class GoBackend implements Backend { this.owner = owner; } } + + private class MyNetworkCallback extends ConnectivityManager.NetworkCallback { + @Override + public void onAvailable(Network network) { + activeNetwork = network; + Log.w(TAG, "onAvailable: " + activeNetwork); + } + + @Override + public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { + Log.w(TAG, "onLinkPropertiesChanged: " + network + " is default:" + (network.equals(activeNetwork))); + if (network.equals(activeNetwork) && currentConfig != null && currentTunnelHandle > -1) { + final Resolver resolver = new Resolver(network, linkProperties); + final String goConfig = currentConfig.toWgUserspaceStringWithChangedEndpoints(resolver); + Log.w(TAG, "is default network, config:" + goConfig); + + LibwgGrpc.LibwgBlockingStub stub = LibwgGrpc.newBlockingStub(channel); + TunnelHandle tunnel = TunnelHandle.newBuilder().setHandle(currentTunnelHandle).build(); + IpcSetRequest request = IpcSetRequest.newBuilder().setTunnel(tunnel).setConfig(goConfig).build(); + IpcSetResponse resp = stub.ipcSet(request); + } + } + } } |