From: Jaehyun Kim Date: Wed, 8 Sep 2021 06:45:19 +0000 (+0000) Subject: Merge "wireguard: Add routes for allowedIPs" into tizen X-Git-Tag: accepted/tizen/unified/20210915.025055~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fca568ced12e61747d4f28cd0e88f44c30cabcfa;hp=53b8b52126ac91550b12ac3bd9a212dd97232a77;p=platform%2Fupstream%2Fconnman.git Merge "wireguard: Add routes for allowedIPs" into tizen --- diff --git a/vpn/plugins/wireguard.c b/vpn/plugins/wireguard.c index d8f32b3..25ec32d 100644 --- a/vpn/plugins/wireguard.c +++ b/vpn/plugins/wireguard.c @@ -50,6 +50,9 @@ #include "wireguard.h" #define DNS_RERESOLVE_TIMEOUT 20 +#if defined TIZEN_EXT +#define ADD_ALLOWED_IP_ROUTE_TIMEOUT 2 +#endif /* TIZEN_EXT */ struct wireguard_info { struct wg_device device; @@ -57,6 +60,9 @@ struct wireguard_info { char *endpoint_fqdn; char *port; int reresolve_id; +#if defined TIZEN_EXT + int allowed_ip_route_id; +#endif /* TIZEN_EXT */ }; struct sockaddr_u { @@ -94,14 +100,49 @@ static int parse_allowed_ips(const char *allowed_ips, wg_peer *peer) int i; curaip = NULL; +#if defined TIZEN_EXT + /** + * Note: At API level we donot check Wireguard specific configurations, + * User can provide any space separated string for IP. + * Ideally it should be using "10.0.0.2/32, 10.0.0.3/32" + * However there can be cases like "10.0.0.2/32,10.0.0.3/32" + * + * So we need to parse the allowed_ips configuration properly. + */ + tokens = g_strsplit(allowed_ips, ",", -1); +#else tokens = g_strsplit(allowed_ips, ", ", -1); +#endif for (i = 0; tokens[i]; i++) { +#if defined TIZEN_EXT + int len = strlen(tokens[i]); + char *ptr = tokens[i]; + int j = -1; + + //skip forward spaces + while (++j < len && ptr[j] == ' ') + ;// Do Nothing + + if (!ptr[j]) + continue; + + toks = g_strsplit(ptr + j, "/", -1); + if (g_strv_length(toks) != 2) { + DBG("Ignore AllowedIPs value [%s]", ptr + j); + g_strfreev(toks); + continue; + } + + DBG("Parsed AllowedIPs [%s]", ptr + j); +#else + toks = g_strsplit(tokens[i], "/", -1); if (g_strv_length(toks) != 2) { DBG("Ignore AllowedIPs value %s", tokens[i]); g_strfreev(toks); continue; } +#endif allowedip = g_malloc0(sizeof(*allowedip)); @@ -112,7 +153,11 @@ static int parse_allowed_ips(const char *allowed_ips, wg_peer *peer) allowedip->family = AF_INET6; memcpy(&allowedip->ip6, buf, sizeof(allowedip->ip6)); } else { +#if defined TIZEN_EXT + DBG("Ignore AllowedIPs value [%s]", ptr + j); +#else DBG("Ignore AllowedIPs value %s", tokens[i]); +#endif g_free(allowedip); g_strfreev(toks); continue; @@ -269,6 +314,143 @@ static bool sockaddr_cmp_addr(struct sockaddr_u *a, struct sockaddr_u *b) return false; } +#if defined TIZEN_EXT +#include +#include +#include +#include + +#define MAX_SIZE_ERROR_BUFFER 256 +#define MAX_CMD_SIZE 80 + +typedef struct { + struct vpn_provider *provider; + struct wireguard_info *info; +} wg_allowed_ip_route_cb_data_s; + +static int wg_execute_cmd(const char *format, ...) +{ + int status = 0; + int rv = 0; + char cmd[MAX_CMD_SIZE] = { 0, }; + char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, }; + pid_t pid = 0; + va_list va_ptr; + gchar **args = NULL; + + va_start(va_ptr, format); + vsnprintf(cmd, (unsigned int) MAX_CMD_SIZE, format, va_ptr); + va_end(va_ptr); + + if (strlen(cmd) == 0) + return -EIO; + + DBG("command: %s", cmd); + + args = g_strsplit_set(cmd, " ", -1); + + errno = 0; + if (!(pid = fork())) { + DBG("pid(%d), ppid (%d)", getpid(), getppid()); + + errno = 0; + if (execv(args[0], args) == -1) { + DBG("Fail to execute command (%s)", + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER)); + g_strfreev(args); + exit(1); + } + } else if (pid > 0) { + if (waitpid(pid, &status, 0) == -1) + DBG("wait pid (%u) status (%d)", pid, status); + + if (WIFEXITED(status)) { + rv = WEXITSTATUS(status); + DBG("exited, status=%d", rv); + + } else if (WIFSIGNALED(status)) { + DBG("killed by signal %d", WTERMSIG(status)); + + } else if (WIFSTOPPED(status)) { + DBG("stopped by signal %d", WSTOPSIG(status)); + + } else if (WIFCONTINUED(status)) { + DBG("continued"); + } + + g_strfreev(args); + return rv; + } + + DBG("failed to fork(%s)", strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER)); + g_strfreev(args); + + return -EIO; +} + +static gboolean wg_add_allowed_ip_route_cb(gpointer user_data) +{ + wg_allowed_ip_route_cb_data_s *cb_data = user_data; + const char *allowed_ips; + char **tokens = NULL; + char **toks = NULL; + int i; + + DBG(""); + + allowed_ips = vpn_provider_get_string(cb_data->provider, "WireGuard.AllowedIPs"); + if (!allowed_ips) { + DBG("WireGuard.AllowedIPs is missing"); + goto done; + } + + tokens = g_strsplit(allowed_ips, ",", -1); + if (g_strv_length(tokens) == 0) + goto done; + + for (i = 0; tokens[i]; i++) { + int len = strlen(tokens[i]); + char *ptr = tokens[i]; + int j = -1; + + //skip forward spaces + while (++j < len && ptr[j] == ' ') + ;// Do Nothing + + if (!ptr[j]) + continue; + + toks = g_strsplit(ptr + j, "/", -1); + if (g_strv_length(toks) != 2) { + DBG("Ignore AllowedIPs value [%s]", ptr + j); + g_strfreev(toks); + continue; + } + g_strfreev(toks); + + DBG("Allowed IP: [%s], Device Name: [%s]", ptr + j, cb_data->info->device.name); + + // TODO: Remove system call to add route entry present in wg_execute_cmd() + if (!g_strcmp0("0.0.0.0/0", ptr + j)) { + // TODO: Update default route because user wants all data to be routed from wg0, + // when 0.0.0.0/0 is passed in allowed ips list. + // Should we replace the default route? + // If yes, then how to recover default route when wg0 tunnel is removed. + } else { + wg_execute_cmd("/usr/sbin/ip route add %s dev %s", ptr + j, cb_data->info->device.name); + } + } + +done: + if (tokens) + g_strfreev(tokens); + + free(cb_data); + + return FALSE; +} +#endif /* TIZEN_EXT */ + static gboolean wg_dns_reresolve_cb(gpointer user_data) { struct wireguard_info *info = user_data; @@ -432,6 +614,24 @@ done: connman_ipaddress_free(ipaddress); +#if defined TIZEN_EXT + if (!err) { + const char *allowed_ips = vpn_provider_get_string(provider, "WireGuard.AllowedIPs"); + if (allowed_ips) { + wg_allowed_ip_route_cb_data_s *cb_data = + (wg_allowed_ip_route_cb_data_s *) calloc(1, sizeof(wg_allowed_ip_route_cb_data_s)); + if (cb_data) { + cb_data->provider = provider; + cb_data->info = info; + + info->allowed_ip_route_id = + g_timeout_add_seconds(ADD_ALLOWED_IP_ROUTE_TIMEOUT, + wg_add_allowed_ip_route_cb, cb_data); + } + } + } +#endif /* TIZEN_EXT */ + if (!err) info->reresolve_id = g_timeout_add_seconds(DNS_RERESOLVE_TIMEOUT, @@ -448,6 +648,11 @@ static void wg_disconnect(struct vpn_provider *provider) if (!info) return; +#if defined TIZEN_EXT + if (info->allowed_ip_route_id > 0) + g_source_remove(info->allowed_ip_route_id); +#endif /* TIZEN_EXT */ + if (info->reresolve_id > 0) g_source_remove(info->reresolve_id);