[PATCH] wg-quick: Android: Add up/down hook support

Adam Irr adam.irr at outlook.com
Sat Mar 27 20:58:25 UTC 2021


Hello,

I have been using my Nvidia Shield with a self-built kernel module as a 
Wireguard server with the support of this patch to have access to my 
home network. There is a corresponding change needed in the Android 
app[1] to make this work. I am not super familiar with C so please take 
time to scrutinize this code - particularly the memory management. If 
its easier to provide feedback on a Github pull request, let me know and 
I can open one.

[1] https://github.com/WireGuard/wireguard-android/pull/23

Thank you,

Adam

-----

>From 77e9153510fbcacafe20b2813ca11464768f1fd0 Mon Sep 17 00:00:00 2001
From: Adam Irr <adam.irr at outlook.com>
Date: Sat, 27 Mar 2021 13:47:09 -0700
Subject: [PATCH] wg-quick: Android: Add up/down hook support

This change allows Pre/Post Up/Down commands to be run
for Android devices. This provides a mechanism for Android
devices to behave like a server and automatically set up
routing rules.

Signed-off-by: Adam Irr <adam.irr at outlook.com>
---
  src/wg-quick/android.c | 91 ++++++++++++++++++++++++++++++++++++++----
  1 file changed, 84 insertions(+), 7 deletions(-)

diff --git a/src/wg-quick/android.c b/src/wg-quick/android.c
index 941c7b8..7d3cd03 100644
--- a/src/wg-quick/android.c
+++ b/src/wg-quick/android.c
@@ -1097,6 +1097,9 @@ static void cmd_usage(const char *program)
          "  - DNS: an optional DNS server to use while the device is up.\n"
          "  - ExcludedApplications: optional blacklist of applications 
to exclude from the tunnel.\n\n"
          "  - IncludedApplications: optional whitelist of applications 
to include in the tunnel.\n\n"
+        "  - PreUp, PostUp, PreDown, PostDown: script snippets which 
will be executed\n"
+        "    by a root shell at the corresponding phases of the link.\n"
+        "    The string \\`%i' is expanded to INTERFACE."
          "  See wg-quick(8) for more info and examples.\n");
  }

@@ -1110,7 +1113,39 @@ static void cmd_up_cleanup(void)
      free(cleanup_iface);
  }

-static void cmd_up(const char *iface, const char *config, unsigned int 
mtu, const char *addrs, const char *dnses, const char 
*excluded_applications, const char *included_applications)
+static void run_hooks(const char *cmds, const char *iface)
+{
+    if (cmds == NULL)
+        return;
+    size_t len = strlen(cmds), iface_len = strlen(iface), j = 0, 
iface_count = 0;
+    if (len > (1<<16))
+        return;
+    for (size_t i = 0; i < len - 1; ++i) {
+        if (cmds[i] == '%' && cmds[++i] == 'i') {
+            iface_count++;
+        }
+    }
+
+    // Allocate enough space for the full command after replacing %i 
with the interface name
+    _cleanup_free_ char *current_cmd = xmalloc(len + ((iface_len - 2) * 
iface_count) + 1);
+
+    for (size_t i = 0; i < len; ++i) {
+        if (cmds[i] != '\n') {
+            if (cmds[i] == '%' && cmds[++i] == 'i') {
+                strcpy(current_cmd + j, iface);
+                j += iface_len;
+            } else {
+                current_cmd[j++] = cmds[i];
+            }
+        } else if (j != 0) {
+            current_cmd[j] = '\0';
+            j = 0;
+            cmd("%s", current_cmd);
+        }
+    }
+}
+
+static void cmd_up(const char *iface, const char *config, unsigned int 
mtu, const char *addrs, const char *dnses, const char 
*excluded_applications, const char *included_applications, const char 
*pre_up_cmds, const char *post_up_cmds)
  {
      DEFINE_CMD(c);
      unsigned int netid = 0;
@@ -1127,7 +1162,9 @@ static void cmd_up(const char *iface, const char 
*config, unsigned int mtu, cons
      add_if(iface);
      set_config(iface, config);
      listen_port = determine_listen_port(iface);
+    run_hooks(pre_up_cmds, iface);
      up_if(&netid, iface, listen_port);
+    run_hooks(post_up_cmds, iface);
      set_addr(iface, addrs);
      set_dnses(netid, dnses);
      set_routes(iface, netid);
@@ -1140,7 +1177,7 @@ static void cmd_up(const char *iface, const char 
*config, unsigned int mtu, cons
      exit(EXIT_SUCCESS);
  }

-static void cmd_down(const char *iface)
+static void cmd_down(const char *iface, char *pre_down_cmds, char 
*post_down_cmds)
  {
      DEFINE_CMD(c);
      bool found = false;
@@ -1159,12 +1196,32 @@ static void cmd_down(const char *iface)
          exit(EMEDIUMTYPE);
      }

+    run_hooks(pre_down_cmds, iface);
      del_if(iface);
+    run_hooks(post_down_cmds, iface);
      broadcast_change();
      exit(EXIT_SUCCESS);
  }

-static void parse_options(char **iface, char **config, unsigned int 
*mtu, char **addrs, char **dnses, char **excluded_applications, char 
**included_applications, const char *arg)
+static void clean_hook_cmd(const char *line, const size_t len, char 
*output)
+{
+    size_t j = 0;
+    bool found_prefix = false;
+    bool found_cmd_start = false;
+    for (size_t i = 0; i < len; ++i) {
+        if (!found_cmd_start && isspace(line[i]))
+            continue;
+        if (found_prefix && !isspace(line[i]))
+            found_cmd_start = true;
+        if (line[i] == '=')
+            found_prefix = true;
+
+        output[j++] = line[i];
+    }
+    output[j] = '\0';
+}
+
+static void parse_options(char **iface, char **config, unsigned int 
*mtu, char **addrs, char **dnses, char **excluded_applications, char 
**included_applications, char **pre_up_cmds, char **post_up_cmds, char 
**pre_down_cmds, char **post_down_cmds, const char *arg)
  {
      _cleanup_fclose_ FILE *file = NULL;
      _cleanup_free_ char *line = NULL;
@@ -1254,6 +1311,22 @@ static void parse_options(char **iface, char 
**config, unsigned int *mtu, char *
              } else if (!strncasecmp(clean, "MTU=", 4) && j > 4) {
                  *mtu = atoi(clean + 4);
                  continue;
+            } else if (!strncasecmp(clean, "PreUp=", 6) && j > 4) {
+                clean_hook_cmd(line, len, clean);
+                *pre_up_cmds = concat_and_free(*pre_up_cmds, "\n", 
clean + 6);
+                continue;
+            } else if (!strncasecmp(clean, "PostUp=", 7) && j > 4) {
+                clean_hook_cmd(line, len, clean);
+                *post_up_cmds = concat_and_free(*post_up_cmds, "\n", 
clean + 7);
+                continue;
+            } else if (!strncasecmp(clean, "PreDown=", 8) && j > 4) {
+                clean_hook_cmd(line, len, clean);
+                *pre_down_cmds = concat_and_free(*pre_down_cmds, "\n", 
clean + 8);
+                continue;
+            } else if (!strncasecmp(clean, "PostDown=", 9) && j > 4) {
+                clean_hook_cmd(line, len, clean);
+                *post_down_cmds = concat_and_free(*post_down_cmds, 
"\n", clean + 9);
+                continue;
              }
          }
          *config = concat_and_free(*config, "", line);
@@ -1278,17 +1351,21 @@ int main(int argc, char *argv[])
      _cleanup_free_ char *excluded_applications = NULL;
      _cleanup_free_ char *included_applications = NULL;
      unsigned int mtu;
+    _cleanup_free_ char *pre_up_cmds = NULL;
+    _cleanup_free_ char *post_up_cmds = NULL;
+    _cleanup_free_ char *pre_down_cmds = NULL;
+    _cleanup_free_ char *post_down_cmds = NULL;

      if (argc == 2 && (!strcmp(argv[1], "help") || !strcmp(argv[1], 
"--help") || !strcmp(argv[1], "-h")))
          cmd_usage(argv[0]);
      else if (argc == 3 && !strcmp(argv[1], "up")) {
          auto_su(argc, argv);
-        parse_options(&iface, &config, &mtu, &addrs, &dnses, 
&excluded_applications, &included_applications, argv[2]);
-        cmd_up(iface, config, mtu, addrs, dnses, excluded_applications, 
included_applications);
+        parse_options(&iface, &config, &mtu, &addrs, &dnses, 
&excluded_applications, &included_applications, &pre_up_cmds, 
&post_up_cmds, &pre_down_cmds, &post_down_cmds, argv[2]);
+        cmd_up(iface, config, mtu, addrs, dnses, excluded_applications, 
included_applications, pre_up_cmds, post_up_cmds);
      } else if (argc == 3 && !strcmp(argv[1], "down")) {
          auto_su(argc, argv);
-        parse_options(&iface, &config, &mtu, &addrs, &dnses, 
&excluded_applications, &included_applications, argv[2]);
-        cmd_down(iface);
+        parse_options(&iface, &config, &mtu, &addrs, &dnses, 
&excluded_applications, &included_applications, &pre_up_cmds, 
&post_up_cmds, &pre_down_cmds, &post_down_cmds, argv[2]);
+        cmd_down(iface, pre_down_cmds, post_down_cmds);
      } else {
          cmd_usage(argv[0]);
          return 1;
-- 
2.25.1


-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-wg-quick-Android-Add-up-down-hook-support.patch
Type: text/x-patch
Size: 7191 bytes
Desc: not available
URL: <http://lists.zx2c4.com/pipermail/wireguard/attachments/20210327/1fe2514e/attachment.bin>


More information about the WireGuard mailing list