summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/Backend.java11
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java18
-rw-r--r--tunnel/src/main/java/com/wireguard/android/backend/WgQuickBackend.java5
-rw-r--r--tunnel/tools/libwg-go/api-android.go35
-rw-r--r--tunnel/tools/libwg-go/jni.c25
-rw-r--r--ui/src/main/AndroidManifest.xml3
-rw-r--r--ui/src/main/java/com/wireguard/android/model/TunnelManager.java86
7 files changed, 163 insertions, 20 deletions
diff --git a/tunnel/src/main/java/com/wireguard/android/backend/Backend.java b/tunnel/src/main/java/com/wireguard/android/backend/Backend.java
index 4c18d98b..9afda719 100644
--- a/tunnel/src/main/java/com/wireguard/android/backend/Backend.java
+++ b/tunnel/src/main/java/com/wireguard/android/backend/Backend.java
@@ -19,6 +19,17 @@ import androidx.annotation.Nullable;
@NonNullForAll
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 applyUserspaceConfig(ObservableTunnel tunnel, Config config) throws Exception;
+
+ /**
* Enumerate names of currently-running tunnels.
*
* @return The set of running tunnel names.
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 978b39aa..952a30f0 100644
--- a/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
+++ b/tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java
@@ -61,9 +61,26 @@ public final class GoBackend implements Backend {
private static native int wgTurnOn(String ifName, int tunFd, String settings);
+ private static native String wgGetOperation(int handle);
+
+ private static native int wgSetOperation(int handle, String settings);
+
private static native String wgVersion();
@Override
+ public Config applyUserspaceConfig(final ObservableTunnel tunnel, final Config config) throws Exception {
+ if (currentTunnelHandle != -1) {
+ // Build config
+ final String goConfig = config.toWgUserspaceString();
+
+ Log.d(TAG, "Go backend v" + wgVersion());
+ wgSetOperation(currentTunnelHandle, goConfig);
+ Log.d(TAG, "Settings " + wgGetOperation(currentTunnelHandle));
+ }
+ return config;
+ }
+
+ @Override
public Set<String> getRunningTunnelNames() {
if (currentTunnel != null) {
final Set<String> runningTunnels = new ArraySet<>();
@@ -216,6 +233,7 @@ public final class GoBackend implements Backend {
throw new BackendException(Reason.TUN_CREATION_ERROR);
Log.d(TAG, "Go backend v" + wgVersion());
currentTunnelHandle = wgTurnOn(tunnel.getName(), tun.detachFd(), goConfig);
+ Log.d(TAG, "Settings " + wgGetOperation(currentTunnelHandle));
}
if (currentTunnelHandle < 0)
throw new BackendException(Reason.GO_ACTIVATION_ERROR_CODE, currentTunnelHandle);
diff --git a/tunnel/src/main/java/com/wireguard/android/backend/WgQuickBackend.java b/tunnel/src/main/java/com/wireguard/android/backend/WgQuickBackend.java
index 78d7d5b6..c6a63691 100644
--- a/tunnel/src/main/java/com/wireguard/android/backend/WgQuickBackend.java
+++ b/tunnel/src/main/java/com/wireguard/android/backend/WgQuickBackend.java
@@ -55,6 +55,11 @@ public final class WgQuickBackend implements Backend {
}
@Override
+ public Config applyUserspaceConfig(final ObservableTunnel tunnel, final Config config) throws Exception {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
public Set<String> getRunningTunnelNames() {
final List<String> output = new ArrayList<>();
// Don't throw an exception here or nothing will show up in the UI.
diff --git a/tunnel/tools/libwg-go/api-android.go b/tunnel/tools/libwg-go/api-android.go
index 7a393cae..9ccd913f 100644
--- a/tunnel/tools/libwg-go/api-android.go
+++ b/tunnel/tools/libwg-go/api-android.go
@@ -11,6 +11,7 @@ import "C"
import (
"bufio"
+ "bytes"
"golang.org/x/sys/unix"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/ipc"
@@ -143,6 +144,40 @@ func wgTurnOff(tunnelHandle int32) {
handle.device.Close()
}
+//export wgGetOperation
+func wgGetOperation(tunnelHandle int32) *C.char {
+ handle, ok := tunnelHandles[tunnelHandle]
+ if !ok {
+ return C.CString("(bad handle)")
+ }
+
+ var buf bytes.Buffer
+ writer := bufio.NewWriter(&buf)
+
+ getError := handle.device.IpcGetOperation(writer)
+ if getError != nil {
+ return C.CString(getError.Error())
+ }
+
+ writer.Flush()
+ return C.CString(buf.String())
+}
+
+//export wgSetOperation
+func wgSetOperation(tunnelHandle int32, settings string) int32 {
+ handle, ok := tunnelHandles[tunnelHandle]
+ if !ok {
+ return -1
+ }
+
+ setError := handle.device.IpcSetOperation(bufio.NewReader(strings.NewReader(settings)))
+ if setError != nil {
+ return -1
+ }
+
+ return 0
+}
+
//export wgGetSocketV4
func wgGetSocketV4(tunnelHandle int32) int32 {
handle, ok := tunnelHandles[tunnelHandle]
diff --git a/tunnel/tools/libwg-go/jni.c b/tunnel/tools/libwg-go/jni.c
index 3f877d47..1cc69343 100644
--- a/tunnel/tools/libwg-go/jni.c
+++ b/tunnel/tools/libwg-go/jni.c
@@ -10,6 +10,8 @@
struct go_string { const char *str; long n; };
extern int wgTurnOn(struct go_string ifname, int tun_fd, struct go_string settings);
extern void wgTurnOff(int handle);
+extern char *wgGetOperation(int handle);
+extern int wgSetOperation(int handle, struct go_string settings);
extern int wgGetSocketV4(int handle);
extern int wgGetSocketV6(int handle);
extern char *wgGetConfig(int handle);
@@ -38,6 +40,29 @@ JNIEXPORT void JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOff(JN
wgTurnOff(handle);
}
+JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetOperation(JNIEnv *env, jclass c, jint handle)
+{
+ jstring ret;
+ char *settings = wgGetOperation(handle);
+ if (!settings)
+ return NULL;
+ ret = (*env)->NewStringUTF(env, settings);
+ free(settings);
+ return ret;
+}
+
+JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgSetOperation(JNIEnv *env, jclass c, jint handle, jstring settings)
+{
+ const char *settings_str = (*env)->GetStringUTFChars(env, settings, 0);
+ size_t settings_len = (*env)->GetStringUTFLength(env, settings);
+ int ret = wgSetOperation(handle, (struct go_string){
+ .str = settings_str,
+ .n = settings_len
+ });
+ (*env)->ReleaseStringUTFChars(env, settings, settings_str);
+ return ret;
+}
+
JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetSocketV4(JNIEnv *env, jclass c, jint handle)
{
return wgGetSocketV4(handle);
diff --git a/ui/src/main/AndroidManifest.xml b/ui/src/main/AndroidManifest.xml
index 5e993ae2..99a8f623 100644
--- a/ui/src/main/AndroidManifest.xml
+++ b/ui/src/main/AndroidManifest.xml
@@ -70,6 +70,9 @@
<action android:name="com.wireguard.android.action.REFRESH_TUNNEL_STATES" />
<action android:name="com.wireguard.android.action.SET_TUNNEL_UP" />
<action android:name="com.wireguard.android.action.SET_TUNNEL_DOWN" />
+ <action android:name="com.wireguard.android.action.GET_TUNNEL_CONFIG" />
+ <action android:name="com.wireguard.android.action.SET_TUNNEL_CONFIG" />
+ <action android:name="com.wireguard.android.action.SET_TUNNEL_USERSPACE_CONFIG" />
</intent-filter>
</receiver>
diff --git a/ui/src/main/java/com/wireguard/android/model/TunnelManager.java b/ui/src/main/java/com/wireguard/android/model/TunnelManager.java
index e370f8de..e1806c2f 100644
--- a/ui/src/main/java/com/wireguard/android/model/TunnelManager.java
+++ b/ui/src/main/java/com/wireguard/android/model/TunnelManager.java
@@ -8,6 +8,10 @@ package com.wireguard.android.model;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.util.Log;
+import androidx.annotation.Nullable;
+import androidx.databinding.BaseObservable;
+import androidx.databinding.Bindable;
import com.wireguard.android.Application;
import com.wireguard.android.BR;
@@ -19,9 +23,13 @@ import com.wireguard.android.configStore.ConfigStore;
import com.wireguard.android.util.ExceptionLoggers;
import com.wireguard.android.util.ObservableSortedKeyedArrayList;
import com.wireguard.android.util.ObservableSortedKeyedList;
+import com.wireguard.config.BadConfigException;
import com.wireguard.config.Config;
import com.wireguard.util.NonNullForAll;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
@@ -42,6 +50,7 @@ import java9.util.stream.StreamSupport;
@NonNullForAll
public final class TunnelManager extends BaseObservable {
+ private static final String TAG = "WireGuard/" + TunnelManager.class.getSimpleName();
private static final Comparator<String> COMPARATOR = Comparators.<String>thenComparing(
String.CASE_INSENSITIVE_ORDER, Comparators.naturalOrder());
private static final String KEY_LAST_USED_TUNNEL = "last_used_tunnel";
@@ -215,6 +224,15 @@ public final class TunnelManager extends BaseObservable {
}).thenApply(tunnel::onConfigChanged);
}
+ CompletionStage<Config> setTunnelUserspaceConfig(final Tunnel tunnel, final Config config) {
+ Log.println(Log.INFO, TAG, "Called setTunnelUserspaceConfig " + config);
+ return Application.getAsyncWorker().supplyAsync(() -> {
+ Log.println(Log.INFO, TAG, "Async setTunnelUserspaceConfig " + config);
+ final Config appliedConfig = Application.getBackend().applyUserspaceConfig(tunnel, config);
+ return appliedConfig;
+ });
+ }
+
CompletionStage<String> setTunnelName(final ObservableTunnel tunnel, final String name) {
if (Tunnel.isNameInvalid(name))
return CompletableFuture.failedFuture(new IllegalArgumentException(context.getString(R.string.tunnel_error_invalid_name)));
@@ -263,6 +281,7 @@ public final class TunnelManager extends BaseObservable {
public static final class IntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, @Nullable final Intent intent) {
+ Log.println(Log.INFO, TAG, "Broadcast received " + intent);
final TunnelManager manager = Application.getTunnelManager();
if (intent == null)
return;
@@ -275,29 +294,56 @@ public final class TunnelManager extends BaseObservable {
return;
}
- /* We disable the below, for now, as the security model of allowing this
- * might take a bit more consideration.
- */
- if (true)
- return;
-
- final State state;
- if ("com.wireguard.android.action.SET_TUNNEL_UP".equals(action))
- state = State.UP;
- else if ("com.wireguard.android.action.SET_TUNNEL_DOWN".equals(action))
- state = State.DOWN;
- else
- return;
-
final String tunnelName = intent.getStringExtra("tunnel");
if (tunnelName == null)
return;
- manager.getTunnels().thenAccept(tunnels -> {
- final ObservableTunnel tunnel = tunnels.get(tunnelName);
- if (tunnel == null)
- return;
- manager.setTunnelState(tunnel, state);
- });
+
+ if ("com.wireguard.android.action.SET_TUNNEL_UP".equals(action) ||
+ "com.wireguard.android.action.SET_TUNNEL_DOWN".equals(action)) {
+ final State state;
+ if ("com.wireguard.android.action.SET_TUNNEL_UP".equals(action))
+ state = State.UP;
+ else /* "com.wireguard.android.action.SET_TUNNEL_DOWN".equals(action) */
+ state = State.DOWN;
+
+ manager.getTunnels().thenAccept(tunnels -> {
+ final ObservableTunnel tunnel = tunnels.get(tunnelName);
+ if (tunnel == null)
+ return;
+ manager.setTunnelState(tunnel, state);
+ });
+ } else if ("com.wireguard.android.action.GET_TUNNEL_CONFIG".equals(action) ||
+ "com.wireguard.android.action.SET_TUNNEL_CONFIG".equals(action) ||
+ "com.wireguard.android.action.SET_TUNNEL_USERSPACE_CONFIG".equals(action)) {
+ final ActionCode code;
+ if ("com.wireguard.android.action.SET_TUNNEL_CONFIG".equals(action))
+ code = ActionCode.SET_CONFIG;
+ else if ("com.wireguard.android.action.SET_TUNNEL_USERSPACE_CONFIG".equals(action))
+ code = ActionCode.SET_USERSPACE_CONFIG;
+ else /* "com.wireguard.android.action.GET_TUNNEL_CONFIG".equals(action) */
+ code = ActionCode.GET_CONFIG;
+ manager.getTunnels().thenAccept(tunnels -> {
+ final ObservableTunnel tunnel = tunnels.get(tunnelName);
+ if (tunnel == null)
+ return;
+
+ final String config = intent.getStringExtra("config");
+ try {
+ if (code == ActionCode.SET_USERSPACE_CONFIG) {
+ Log.println(Log.INFO, TAG, "Call setTunnelUserspaceConfig " + config);
+ manager.setTunnelUserspaceConfig(tunnel, Config.parse(new BufferedReader(new StringReader(config))));
+ } else {
+ Log.println(Log.INFO, TAG, "Call setTunnelConfig " + config);
+ manager.setTunnelConfig(tunnel, Config.parse(new BufferedReader(new StringReader(config))));
+ }
+ } catch (IOException | BadConfigException e) {
+ Log.println(Log.ERROR, TAG, Log.getStackTraceString(e));
+ }
+ });
+ } else
+ return;
}
}
+
+ private enum ActionCode { GET_CONFIG, SET_CONFIG, SET_USERSPACE_CONFIG };
}