[PATCH wireguard-tools] wg-quick: android: add support for {Pre, Post}{Up, Down} hooks

Claire Elaina git at claire.sharkgirl.ing
Sun May 25 08:04:57 UTC 2025


---
 src/wg-quick/android.c | 96 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 89 insertions(+), 7 deletions(-)

diff --git a/src/wg-quick/android.c b/src/wg-quick/android.c
index 1263ee4..8a8df47 100644
--- a/src/wg-quick/android.c
+++ b/src/wg-quick/android.c
@@ -60,6 +60,15 @@ static void *xcalloc(size_t nmemb, size_t size)
 	exit(errno);
 }
 
+static void *xrealloc(void *ptr, size_t size)
+{
+	void *ret = realloc(ptr, size);
+	if (ret)
+		return ret;
+	perror("Error: realloc");
+	exit(errno);
+}
+
 static void *xstrdup(const char *str)
 {
 	char *ret = strdup(str);
@@ -126,6 +135,27 @@ static void free_command_buffer(struct command_buffer *c)
 	free(c->line);
 }
 
+struct str_list {
+	char **items;
+	size_t len;
+};
+
+static void append_str_list(struct str_list *l, char *item)
+{
+	l->len++;
+	l->items = xrealloc(l->items, sizeof(char*) * l->len);
+	l->items[l->len - 1] = item;
+}
+
+static void free_str_list(struct str_list *l)
+{
+	if (!l)
+		return;
+	for (size_t i = 0; i < l->len; ++i)
+		free(l->items[i]);
+	free(l->items);
+}
+
 static void freep(void *p)
 {
 	free(*(void **)p);
@@ -140,6 +170,7 @@ static void fclosep(FILE **f)
 #define _cleanup_regfree_ _cleanup_(regfree)
 
 #define DEFINE_CMD(name) _cleanup_(free_command_buffer) struct command_buffer name = { 0 };
+#define DEFINE_STR_LIST(name) _cleanup_(free_str_list) struct str_list name = { 0 };
 
 static char *vcmd_ret(struct command_buffer *c, const char *cmd_fmt, va_list args)
 {
@@ -239,6 +270,12 @@ _printf_(1, 2) static void cndc(const char *cmd_fmt, ...)
 	}
 }
 
+static void execute_hooks(const struct str_list *hooks)
+{
+	for (size_t i = 0; i < hooks->len; ++i)
+		cmd("%s", hooks->items[i]);
+}
+
 /* Values are from AOSP repository platform/frameworks/native in libs/binder/ndk/include_ndk/android/binder_status.h. */
 enum {
 	STATUS_OK = 0,
@@ -1112,7 +1149,7 @@ 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 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 struct str_list *pre_up, const struct str_list *post_up)
 {
 	DEFINE_CMD(c);
 	unsigned int netid = 0;
@@ -1127,6 +1164,7 @@ static void cmd_up(const char *iface, const char *config, unsigned int mtu, cons
 	atexit(cmd_up_cleanup);
 
 	add_if(iface);
+	execute_hooks(pre_up);
 	set_config(iface, config);
 	listen_port = determine_listen_port(iface);
 	up_if(&netid, iface, listen_port);
@@ -1135,6 +1173,7 @@ static void cmd_up(const char *iface, const char *config, unsigned int mtu, cons
 	set_routes(iface, netid);
 	set_mtu(iface, mtu);
 	set_users(netid, excluded_applications, included_applications);
+	execute_hooks(post_up);
 	broadcast_change();
 
 	free(cleanup_iface);
@@ -1142,7 +1181,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, const struct str_list *pre_down, const struct str_list *post_down)
 {
 	DEFINE_CMD(c);
 	bool found = false;
@@ -1161,12 +1200,14 @@ static void cmd_down(const char *iface)
 		exit(EMEDIUMTYPE);
 	}
 
+	execute_hooks(pre_down);
 	del_if(iface);
+	execute_hooks(post_down);
 	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 parse_options(char **iface, char **config, unsigned int *mtu, char **addrs, char **dnses, char **excluded_applications, char **included_applications, struct str_list *pre_up, struct str_list *post_up, struct str_list *pre_down, struct str_list *post_down, const char *arg)
 {
 	_cleanup_fclose_ FILE *file = NULL;
 	_cleanup_free_ char *line = NULL;
@@ -1236,6 +1277,27 @@ static void parse_options(char **iface, char **config, unsigned int *mtu, char *
 		}
 		clean[j] = '\0';
 
+		char *line_value = strchr(line, '=');
+		_cleanup_free_ char *unstripped_value = NULL;
+		if (line_value) {
+			/* Skip equal sign. */
+			line_value++;
+
+			/* Skip leading whitespace. */
+			while (isspace(line_value[0]))
+				line_value++;
+
+			/* Calculate length of the value without trailing whitespace. */
+			size_t line_value_len = strlen(line_value);
+			while (line_value_len && isspace(line_value[line_value_len - 1]))
+				line_value_len--;
+
+			/* Create the string. */
+			unstripped_value = xmalloc(line_value_len + 1);
+			memcpy(unstripped_value, line_value, line_value_len);
+			unstripped_value[line_value_len] = '\0';
+		}
+
 		if (clean[0] == '[')
 			in_interface_section = false;
 		if (!strcasecmp(clean, "[Interface]"))
@@ -1256,6 +1318,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 > 6) {
+				append_str_list(pre_up, unstripped_value);
+				unstripped_value = NULL;
+				continue;
+			} else if (!strncasecmp(clean, "PostUp=", 7) && j > 7) {
+				append_str_list(post_up, unstripped_value);
+				unstripped_value = NULL;
+				continue;
+			} else if (!strncasecmp(clean, "PreDown=", 8) && j > 8) {
+				append_str_list(pre_down, unstripped_value);
+				unstripped_value = NULL;
+				continue;
+			} else if (!strncasecmp(clean, "PostDown=", 9) && j > 9) {
+				append_str_list(post_down, unstripped_value);
+				unstripped_value = NULL;
+				continue;
 			}
 		}
 		*config = concat_and_free(*config, "", line);
@@ -1279,6 +1357,10 @@ int main(int argc, char *argv[])
 	_cleanup_free_ char *dnses = NULL;
 	_cleanup_free_ char *excluded_applications = NULL;
 	_cleanup_free_ char *included_applications = NULL;
+	DEFINE_STR_LIST(pre_up);
+	DEFINE_STR_LIST(post_up);
+	DEFINE_STR_LIST(pre_down);
+	DEFINE_STR_LIST(post_down);
 	unsigned int mtu;
 	char prop[PROP_VALUE_MAX + 1];
 
@@ -1289,12 +1371,12 @@ int main(int argc, char *argv[])
 		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, &post_up, &pre_down, &post_down, argv[2]);
+		cmd_up(iface, config, mtu, addrs, dnses, excluded_applications, included_applications, &pre_up, &post_up);
 	} 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, &post_up, &pre_down, &post_down, argv[2]);
+		cmd_down(iface, &pre_down, &post_down);
 	} else {
 		cmd_usage(argv[0]);
 		return 1;
-- 
2.49.0



More information about the WireGuard mailing list