Development discussion of WireGuard
 help / color / mirror / Atom feed
* [PATCH] wg-quick: Android: Add up/down hook support
@ 2021-03-27 20:58 Adam Irr
  0 siblings, 0 replies; only message in thread
From: Adam Irr @ 2021-03-27 20:58 UTC (permalink / raw)
  To: wireguard

[-- Attachment #1: Type: text/plain, Size: 9211 bytes --]

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@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@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



[-- Attachment #2: 0001-wg-quick-Android-Add-up-down-hook-support.patch --]
[-- Type: text/x-patch, Size: 7190 bytes --]

From 77e9153510fbcacafe20b2813ca11464768f1fd0 Mon Sep 17 00:00:00 2001
From: Adam Irr <adam.irr@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@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


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-03-30  8:38 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-27 20:58 [PATCH] wg-quick: Android: Add up/down hook support Adam Irr

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).