diff options
Diffstat (limited to 'app/src/main/java/com/wireguard/android/backend')
3 files changed, 0 insertions, 453 deletions
diff --git a/app/src/main/java/com/wireguard/android/backend/Backend.java b/app/src/main/java/com/wireguard/android/backend/Backend.java deleted file mode 100644 index a25bfd04..00000000 --- a/app/src/main/java/com/wireguard/android/backend/Backend.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.backend; - -import com.wireguard.android.model.Tunnel; -import com.wireguard.android.model.Tunnel.State; -import com.wireguard.android.model.Tunnel.Statistics; -import com.wireguard.config.Config; - -import java.util.Set; - -/** - * Interface for implementations of the WireGuard secure network tunnel. - */ - -public interface Backend { - /** - * Update the volatile configuration of a running tunnel and return the resulting configuration. - * If the tunnel is not up, return the configuration that would result (if known), or else - * simply return the given configuration. - * - * @param tunnel The tunnel to apply the configuration to. - * @param config The new configuration for this tunnel. - * @return The updated configuration of the tunnel. - */ - Config applyConfig(Tunnel tunnel, Config config) throws Exception; - - /** - * Enumerate the names of currently-running tunnels. - * - * @return The set of running tunnel names. - */ - Set<String> enumerate(); - - /** - * Get the actual state of a tunnel. - * - * @param tunnel The tunnel to examine the state of. - * @return The state of the tunnel. - */ - State getState(Tunnel tunnel) throws Exception; - - /** - * Get statistics about traffic and errors on this tunnel. If the tunnel is not running, the - * statistics object will be filled with zero values. - * - * @param tunnel The tunnel to retrieve statistics for. - * @return The statistics for the tunnel. - */ - Statistics getStatistics(Tunnel tunnel) throws Exception; - - /** - * Determine type name of underlying backend. - * - * @return Type name - */ - String getTypePrettyName(); - - /** - * Determine version of underlying backend. - * - * @return The version of the backend. - * @throws Exception - */ - String getVersion() throws Exception; - - /** - * Set the state of a tunnel. - * - * @param tunnel The tunnel to control the state of. - * @param state The new state for this tunnel. Must be {@code UP}, {@code DOWN}, or - * {@code TOGGLE}. - * @return The updated state of the tunnel. - */ - State setState(Tunnel tunnel, State state) throws Exception; -} diff --git a/app/src/main/java/com/wireguard/android/backend/GoBackend.java b/app/src/main/java/com/wireguard/android/backend/GoBackend.java deleted file mode 100644 index e85f2b0d..00000000 --- a/app/src/main/java/com/wireguard/android/backend/GoBackend.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.backend; - -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.os.ParcelFileDescriptor; -import androidx.annotation.Nullable; -import androidx.collection.ArraySet; -import android.util.Log; - -import com.wireguard.android.Application; -import com.wireguard.android.R; -import com.wireguard.android.activity.MainActivity; -import com.wireguard.android.model.Tunnel; -import com.wireguard.android.model.Tunnel.State; -import com.wireguard.android.model.Tunnel.Statistics; -import com.wireguard.android.util.ExceptionLoggers; -import com.wireguard.android.util.SharedLibraryLoader; -import com.wireguard.config.Config; -import com.wireguard.config.InetNetwork; -import com.wireguard.config.Peer; - -import java.net.InetAddress; -import java.util.Collections; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import java9.util.concurrent.CompletableFuture; - -public final class GoBackend implements Backend { - private static final String TAG = "WireGuard/" + GoBackend.class.getSimpleName(); - private static CompletableFuture<VpnService> vpnService = new CompletableFuture<>(); - - private final Context context; - @Nullable private Tunnel currentTunnel; - private int currentTunnelHandle = -1; - - public GoBackend(final Context context) { - SharedLibraryLoader.loadSharedLibrary(context, "wg-go"); - this.context = context; - } - - private static native int wgGetSocketV4(int handle); - - private static native int wgGetSocketV6(int handle); - - private static native void wgTurnOff(int handle); - - private static native int wgTurnOn(String ifName, int tunFd, String settings); - - private static native String wgVersion(); - - @Override - public Config applyConfig(final Tunnel tunnel, final Config config) throws Exception { - if (tunnel.getState() == State.UP) { - // Restart the tunnel to apply the new config. - setStateInternal(tunnel, tunnel.getConfig(), State.DOWN); - try { - setStateInternal(tunnel, config, State.UP); - } catch (final Exception e) { - // The new configuration didn't work, so try to go back to the old one. - setStateInternal(tunnel, tunnel.getConfig(), State.UP); - throw e; - } - } - return config; - } - - @Override - public Set<String> enumerate() { - if (currentTunnel != null) { - final Set<String> runningTunnels = new ArraySet<>(); - runningTunnels.add(currentTunnel.getName()); - return runningTunnels; - } - return Collections.emptySet(); - } - - @Override - public State getState(final Tunnel tunnel) { - return currentTunnel == tunnel ? State.UP : State.DOWN; - } - - @Override - public Statistics getStatistics(final Tunnel tunnel) { - return new Statistics(); - } - - @Override - public String getTypePrettyName() { - return context.getString(R.string.type_name_go_userspace); - } - - @Override - public String getVersion() { - return wgVersion(); - } - - @Override - public State setState(final Tunnel tunnel, State state) throws Exception { - final State originalState = getState(tunnel); - if (state == State.TOGGLE) - state = originalState == State.UP ? State.DOWN : State.UP; - if (state == originalState) - return originalState; - if (state == State.UP && currentTunnel != null) - throw new IllegalStateException(context.getString(R.string.multiple_tunnels_error)); - Log.d(TAG, "Changing tunnel " + tunnel.getName() + " to state " + state); - setStateInternal(tunnel, tunnel.getConfig(), state); - return getState(tunnel); - } - - private void setStateInternal(final Tunnel tunnel, @Nullable final Config config, final State state) - throws Exception { - - if (state == State.UP) { - Log.i(TAG, "Bringing tunnel up"); - - Objects.requireNonNull(config, context.getString(R.string.no_config_error)); - - if (VpnService.prepare(context) != null) - throw new Exception(context.getString(R.string.vpn_not_authorized_error)); - - final VpnService service; - if (!vpnService.isDone()) - startVpnService(); - - try { - service = vpnService.get(2, TimeUnit.SECONDS); - } catch (final TimeoutException e) { - throw new Exception(context.getString(R.string.vpn_start_error), e); - } - - if (currentTunnelHandle != -1) { - Log.w(TAG, "Tunnel already up"); - return; - } - - // Build config - final String goConfig = config.toWgUserspaceString(); - - // Create the vpn tunnel with android API - final VpnService.Builder builder = service.getBuilder(); - builder.setSession(tunnel.getName()); - - final Intent configureIntent = new Intent(context, MainActivity.class); - configureIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - builder.setConfigureIntent(PendingIntent.getActivity(context, 0, configureIntent, 0)); - - for (final String excludedApplication : config.getInterface().getExcludedApplications()) - builder.addDisallowedApplication(excludedApplication); - - 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 Peer peer : config.getPeers()) { - for (final InetNetwork addr : peer.getAllowedIps()) - builder.addRoute(addr.getAddress(), addr.getMask()); - } - - builder.setMtu(config.getInterface().getMtu().orElse(1280)); - - builder.setBlocking(true); - try (final ParcelFileDescriptor tun = builder.establish()) { - if (tun == null) - throw new Exception(context.getString(R.string.tun_create_error)); - Log.d(TAG, "Go backend v" + wgVersion()); - currentTunnelHandle = wgTurnOn(tunnel.getName(), tun.detachFd(), goConfig); - } - if (currentTunnelHandle < 0) - throw new Exception(context.getString(R.string.tunnel_on_error, currentTunnelHandle)); - - currentTunnel = tunnel; - - service.protect(wgGetSocketV4(currentTunnelHandle)); - service.protect(wgGetSocketV6(currentTunnelHandle)); - } else { - Log.i(TAG, "Bringing tunnel down"); - - if (currentTunnelHandle == -1) { - Log.w(TAG, "Tunnel already down"); - return; - } - - wgTurnOff(currentTunnelHandle); - currentTunnel = null; - currentTunnelHandle = -1; - } - } - - private void startVpnService() { - Log.d(TAG, "Requesting to start VpnService"); - context.startService(new Intent(context, VpnService.class)); - } - - public static class VpnService extends android.net.VpnService { - public Builder getBuilder() { - return new Builder(); - } - - @Override - public void onCreate() { - vpnService.complete(this); - super.onCreate(); - } - - @Override - public void onDestroy() { - Application.getTunnelManager().getTunnels().thenAccept(tunnels -> { - for (final Tunnel tunnel : tunnels) { - if (tunnel != null && tunnel.getState() != State.DOWN) - tunnel.setState(State.DOWN); - } - }); - - vpnService = vpnService.newIncompleteFuture(); - super.onDestroy(); - } - - @Override - public int onStartCommand(@Nullable final Intent intent, final int flags, final int startId) { - vpnService.complete(this); - if (intent == null || intent.getComponent() == null || !intent.getComponent().getPackageName().equals(getPackageName())) { - Log.d(TAG, "Service started by Always-on VPN feature"); - Application.getTunnelManager().restoreState(true).whenComplete(ExceptionLoggers.D); - } - return super.onStartCommand(intent, flags, startId); - } - - } -} diff --git a/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java b/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java deleted file mode 100644 index 71427d8a..00000000 --- a/app/src/main/java/com/wireguard/android/backend/WgQuickBackend.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.backend; - -import android.content.Context; -import androidx.annotation.Nullable; -import android.util.Log; - -import com.wireguard.android.Application; -import com.wireguard.android.R; -import com.wireguard.android.model.Tunnel; -import com.wireguard.android.model.Tunnel.State; -import com.wireguard.android.model.Tunnel.Statistics; -import com.wireguard.config.Config; - -import java.io.File; -import java.io.FileOutputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Objects; -import java.util.Set; - -import java9.util.stream.Collectors; -import java9.util.stream.Stream; - -/** - * WireGuard backend that uses {@code wg-quick} to implement tunnel configuration. - */ - -public final class WgQuickBackend implements Backend { - private static final String TAG = "WireGuard/" + WgQuickBackend.class.getSimpleName(); - - private final File localTemporaryDir; - private final Context context; - - public WgQuickBackend(final Context context) { - localTemporaryDir = new File(context.getCacheDir(), "tmp"); - this.context = context; - } - - @Override - public Config applyConfig(final Tunnel tunnel, final Config config) throws Exception { - if (tunnel.getState() == State.UP) { - // Restart the tunnel to apply the new config. - setStateInternal(tunnel, tunnel.getConfig(), State.DOWN); - try { - setStateInternal(tunnel, config, State.UP); - } catch (final Exception e) { - // The new configuration didn't work, so try to go back to the old one. - setStateInternal(tunnel, tunnel.getConfig(), State.UP); - throw e; - } - } - return config; - } - - @Override - public Set<String> enumerate() { - final List<String> output = new ArrayList<>(); - // Don't throw an exception here or nothing will show up in the UI. - try { - Application.getToolsInstaller().ensureToolsAvailable(); - if (Application.getRootShell().run(output, "wg show interfaces") != 0 || output.isEmpty()) - return Collections.emptySet(); - } catch (final Exception e) { - Log.w(TAG, "Unable to enumerate running tunnels", e); - return Collections.emptySet(); - } - // wg puts all interface names on the same line. Split them into separate elements. - return Stream.of(output.get(0).split(" ")).collect(Collectors.toUnmodifiableSet()); - } - - @Override - public State getState(final Tunnel tunnel) { - return enumerate().contains(tunnel.getName()) ? State.UP : State.DOWN; - } - - @Override - public Statistics getStatistics(final Tunnel tunnel) { - return new Statistics(); - } - - @Override - public String getTypePrettyName() { - return context.getString(R.string.type_name_kernel_module); - } - - @Override - public String getVersion() throws Exception { - final List<String> output = new ArrayList<>(); - if (Application.getRootShell() - .run(output, "cat /sys/module/wireguard/version") != 0 || output.isEmpty()) - throw new Exception(context.getString(R.string.module_version_error)); - return output.get(0); - } - - @Override - public State setState(final Tunnel tunnel, State state) throws Exception { - final State originalState = getState(tunnel); - if (state == State.TOGGLE) - state = originalState == State.UP ? State.DOWN : State.UP; - if (state == originalState) - return originalState; - Log.d(TAG, "Changing tunnel " + tunnel.getName() + " to state " + state); - Application.getToolsInstaller().ensureToolsAvailable(); - setStateInternal(tunnel, tunnel.getConfig(), state); - return getState(tunnel); - } - - private void setStateInternal(final Tunnel tunnel, @Nullable final Config config, final State state) throws Exception { - Objects.requireNonNull(config, "Trying to set state with a null config"); - - final File tempFile = new File(localTemporaryDir, tunnel.getName() + ".conf"); - try (final FileOutputStream stream = new FileOutputStream(tempFile, false)) { - stream.write(config.toWgQuickString().getBytes(StandardCharsets.UTF_8)); - } - String command = String.format("wg-quick %s '%s'", - state.toString().toLowerCase(Locale.ENGLISH), tempFile.getAbsolutePath()); - if (state == State.UP) - command = "cat /sys/module/wireguard/version && " + command; - final int result = Application.getRootShell().run(null, command); - // noinspection ResultOfMethodCallIgnored - tempFile.delete(); - if (result != 0) - throw new Exception(context.getString(R.string.tunnel_config_error, result)); - } -} |