diff --git a/properties/import-export.c b/properties/import-export.c index e31aa58..c67c259 100644 --- a/properties/import-export.c +++ b/properties/import-export.c @@ -37,15 +37,6 @@ #include "utils.h" #include "nm-utils/nm-shared-utils.h" - -#define INLINE_BLOB_CA "ca" -#define INLINE_BLOB_CERT "cert" -#define INLINE_BLOB_KEY "key" -#define INLINE_BLOB_PKCS12 "pkcs12" -#define INLINE_BLOB_SECRET "secret" -#define INLINE_BLOB_TLS_AUTH "tls-auth" -#define INLINE_BLOB_TLS_CRYPT "tls-crypt" - const char *_nmovpn_test_temp_path = NULL; /*****************************************************************************/ @@ -128,249 +119,6 @@ setting_vpn_add_data_item (NMSettingVpn *setting, nm_setting_vpn_add_data_item (setting, key, value); } -static void -setting_vpn_add_data_item_utf8safe (NMSettingVpn *setting, - const char *key, - const char *value) -{ - gs_free char *s = NULL; - - g_return_if_fail (NM_IS_SETTING_VPN (setting)); - g_return_if_fail (key && key[0]); - g_return_if_fail (value && value[0]); - - nm_setting_vpn_add_data_item (setting, key, - nm_utils_str_utf8safe_escape (value, 0, &s)); -} - -static void -setting_vpn_add_data_item_path (NMSettingVpn *setting, - const char *key, - const char *value) -{ - setting_vpn_add_data_item_utf8safe (setting, key, value); -} - -static gboolean -setting_vpn_eq_data_item_utf8safe (NMSettingVpn *setting, - const char *key, - const char *expected_value) -{ - gs_free char *s_free = NULL; - const char *s; - - s = nm_setting_vpn_get_data_item (setting, key); - if (!s) - return expected_value == NULL; - - if (!expected_value) - return FALSE; - return nm_streq (expected_value, nm_utils_str_utf8safe_unescape (s, &s_free)); -} - -/*****************************************************************************/ - -static gboolean -args_params_check_nargs_minmax (const char **params, guint nargs_min, guint nargs_max, char **out_error) -{ - guint nargs; - - g_return_val_if_fail (params, FALSE); - g_return_val_if_fail (params[0], FALSE); - g_return_val_if_fail (out_error && !*out_error, FALSE); - - nargs = g_strv_length ((char **) params) - 1; - - if (nargs < nargs_min || nargs > nargs_max) { - if (nargs_min != nargs_max) { - *out_error = g_strdup_printf (ngettext ("option %s expects between %u and %u argument", - "option %s expects between %u and %u arguments", - nargs_max), - params[0], nargs_min, nargs_max); - } else if (nargs_min == 0) - *out_error = g_strdup_printf (_("option %s expects no arguments"), params[0]); - else { - *out_error = g_strdup_printf (ngettext ("option %s expects exactly one argument", - "option %s expects exactly %u arguments", - nargs_min), - params[0], nargs_min); - } - return FALSE; - } - return TRUE; -} - -static gboolean -args_params_check_nargs_n (const char **params, guint nargs, char **out_error) -{ - return args_params_check_nargs_minmax (params, nargs, nargs, out_error); -} - -static gboolean -args_params_check_arg_nonempty (const char **params, - guint n_param, - const char *argument_name, - char **out_error) -{ - g_return_val_if_fail (params, FALSE); - g_return_val_if_fail (params[0], FALSE); - g_return_val_if_fail (n_param > 0 && n_param < g_strv_length ((char **) params), FALSE); - g_return_val_if_fail (out_error && !*out_error, FALSE); - - if (params[n_param][0] == '\0') { - if (argument_name) - *out_error = g_strdup_printf (_("argument %s of “%s” can not be empty"), argument_name, params[0]); - else - *out_error = g_strdup_printf (_("argument of “%s” can not be empty"), params[0]); - return FALSE; - } - return TRUE; -} - -static gboolean -args_params_check_arg_utf8 (const char **params, - guint n_param, - const char *argument_name, - char **out_error) -{ - if (!args_params_check_arg_nonempty (params, n_param, argument_name, out_error)) - return FALSE; - if (!_is_utf8 (params[n_param])) { - if (argument_name) - *out_error = g_strdup_printf (_("argument %s of “%s” must be UTF-8 encoded"), argument_name, params[0]); - else - *out_error = g_strdup_printf (_("argument of “%s” must be UTF-8 encoded"), params[0]); - return FALSE; - } - return TRUE; -} - -static gboolean -args_params_parse_int64 (const char **params, - guint n_param, - gint64 min, - gint64 max, - gint64 *out, - char **out_error) -{ - gint64 v; - - g_return_val_if_fail (params, FALSE); - g_return_val_if_fail (params[0], FALSE); - g_return_val_if_fail (n_param > 0, FALSE); - g_return_val_if_fail (n_param < g_strv_length ((char **) params), FALSE); - g_return_val_if_fail (out_error && !*out_error, FALSE); - - v = _nm_utils_ascii_str_to_int64 (params[n_param], 10, min, max, -1); - if (errno) { - *out_error = g_strdup_printf (_("invalid %uth argument to “%s” where number expected"), - n_param, - params[0]); - return FALSE; - } - *out = v; - return TRUE; -} - -static gboolean -args_params_parse_port (const char **params, guint n_param, gint64 *out, char **out_error) -{ - return args_params_parse_int64 (params, n_param, 1, 65535, out, out_error); -} - -static gboolean -args_params_parse_ip4 (const char **params, - guint n_param, - gboolean ovpn_extended_format, - in_addr_t *out, - char **out_error) -{ - in_addr_t a; - const char *p; - - g_return_val_if_fail (params, FALSE); - g_return_val_if_fail (params[0], FALSE); - g_return_val_if_fail (n_param > 0, FALSE); - g_return_val_if_fail (n_param < g_strv_length ((char **) params), FALSE); - g_return_val_if_fail (out, FALSE); - g_return_val_if_fail (out_error && !*out_error, FALSE); - - if (inet_pton (AF_INET, params[n_param], &a) == 1) { - *out = a; - return TRUE; - } - - if ( ovpn_extended_format - && NM_IN_STRSET (params[n_param], "vpn_gateway", "net_gateway", "remote_host")) { - /* we don't support these special destinations, as they currently cannot be expressed - * in a connection. */ - *out_error = g_strdup_printf (_("unsupported %uth argument %s to “%s”"), - n_param, - params[n_param], - params[0]); - return FALSE; - } - - if ( ovpn_extended_format - && params[n_param] - && strlen (params[n_param]) <= 255) { - for (p = params[n_param]; *p; p++) { - if (NM_IN_SET (*p, '-', '.')) - continue; - if (g_ascii_isalnum (*p)) - continue; - goto not_dns; - } - /* we also don't support specifing a FQDN. */ - *out_error = g_strdup_printf (_("unsupported %uth argument to “%s” which looks like a FQDN but only IPv4 address supported"), - n_param, - params[0]); - return FALSE; - } - -not_dns: - *out_error = g_strdup_printf (_("invalid %uth argument to “%s” where IPv4 address expected"), - n_param, - params[0]); - return FALSE; -} - -static gboolean -args_params_parse_key_direction (const char **params, - guint n_param, - const char **out_key_direction, - char **out_error) -{ - g_return_val_if_fail (params, FALSE); - g_return_val_if_fail (params[0], FALSE); - g_return_val_if_fail (n_param > 0, FALSE); - g_return_val_if_fail (n_param < g_strv_length ((char **) params), FALSE); - g_return_val_if_fail (out_key_direction, FALSE); - g_return_val_if_fail (out_error && !*out_error, FALSE); - - /* params will be freed in the next loop iteration. "internalize" the values. */ - if (nm_streq (params[n_param], "0")) - *out_key_direction = "0"; - else if (nm_streq (params[n_param], "1")) - *out_key_direction = "1"; - else { - *out_error = g_strdup_printf (_("invalid %uth key-direction argument to “%s”"), n_param, params[0]); - return FALSE; - } - return TRUE; -} - -static char * -args_params_error_message_invalid_arg (const char **params, guint n_param) -{ - g_return_val_if_fail (params, NULL); - g_return_val_if_fail (params[0], NULL); - g_return_val_if_fail (n_param > 0, FALSE); - g_return_val_if_fail (n_param < g_strv_length ((char **) params), FALSE); - - return g_strdup_printf (_("invalid %uth argument to “%s”"), n_param, params[0]); -} - /*****************************************************************************/ static char @@ -604,68 +352,6 @@ args_next_line (const char **content, /*****************************************************************************/ -static gboolean -parse_http_proxy_auth (const char *default_path, - const char *file, - char **out_user, - char **out_pass, - char **out_error) -{ - gs_free char *file_free = NULL; - gs_free char *contents = NULL; - char **lines, **iter; - - g_return_val_if_fail (out_user && !*out_user, FALSE); - g_return_val_if_fail (out_pass && !*out_pass, FALSE); - g_return_val_if_fail (out_error && !*out_error, FALSE); - - if (!file || - NM_IN_STRSET (file, "stdin", "auto")) - return TRUE; - - if (!g_path_is_absolute (file)) { - file_free = g_build_path ("/", default_path, file, NULL); - file = file_free; - } - - /* Grab user/pass from authfile */ - if (!g_file_get_contents (file, &contents, NULL, NULL)) { - *out_error = g_strdup_printf (_("unable to read HTTP proxy auth file")); - return FALSE; - } - - lines = g_strsplit_set (contents, "\n\r", 0); - for (iter = lines; iter && *iter; iter++) { - if ((*iter)[0] == '\0') - continue; - if (!*out_user) - *out_user = g_strdup (g_strstrip (*iter)); - else if (!*out_pass) { - *out_pass = g_strdup (g_strstrip (*iter)); - break; - } - } - g_strfreev (lines); - - if (!*out_user || !*out_pass) { - *out_error = g_strdup_printf (_("cannot read user/password from HTTP proxy auth file")); - g_clear_pointer (out_user, g_free); - g_clear_pointer (out_pass, g_free); - return FALSE; - } - - if ( !_is_utf8 (*out_user) - || !_is_utf8 (*out_pass)) { - *out_error = g_strdup_printf (_("user/password from HTTP proxy auth file must be UTF-8 encoded")); - g_clear_pointer (out_user, g_free); - g_clear_pointer (out_pass, g_free); - return FALSE; - } - return TRUE; -} - -/*****************************************************************************/ - typedef struct { char *token; char *path; @@ -674,107 +360,6 @@ typedef struct { const char *key; } InlineBlobData; -static void -inline_blob_data_free (InlineBlobData *data) -{ - g_return_if_fail (data); - - g_free (data->token); - g_free (data->path); - g_string_free (data->blob_data, TRUE); - g_slice_free (InlineBlobData, data); -} - -static char * -inline_blob_construct_path (const char *basename, const char *token) -{ - gs_free char *f_filename = NULL; - - g_return_val_if_fail (basename, NULL); - g_return_val_if_fail (token && token[0], NULL); - - /* Construct file name to write the data in */ - f_filename = g_strdup_printf ("%s-%s.pem", basename, token); - - if (_nmovpn_test_temp_path) - return g_build_filename (_nmovpn_test_temp_path, f_filename, NULL); - - return g_build_filename (g_get_home_dir (), ".cert/nm-openvpn", f_filename, NULL); -} - -static gboolean -inline_blob_mkdir_parents (const InlineBlobData *data, const char *filepath, char **out_error) -{ - gs_free char *dirname = NULL; - - g_return_val_if_fail (filepath && filepath[0], FALSE); - g_return_val_if_fail (out_error && !*out_error, FALSE); - - dirname = g_path_get_dirname (filepath); - if (NM_IN_STRSET (dirname, "/", ".")) - return TRUE; - - if (g_file_test (dirname, G_FILE_TEST_IS_DIR)) - return TRUE; - - if (g_file_test (dirname, G_FILE_TEST_EXISTS)) { - *out_error = g_strdup_printf (_("“%s” is not a directory"), dirname); - return FALSE; - } - - if (!inline_blob_mkdir_parents (data, dirname, out_error)) - return FALSE; - - if (mkdir (dirname, 0755) < 0) { - *out_error = g_strdup_printf (_("cannot create “%s” directory"), dirname); - return FALSE; - } - - return TRUE; -} - -static gboolean -inline_blob_write_out (const InlineBlobData *data, GError **error) -{ - mode_t saved_umask; - - if (!_nmovpn_test_temp_path) { - gs_free char *err_msg = NULL; - - /* in test mode we don't create the certificate directory. */ - if (!inline_blob_mkdir_parents (data, data->path, &err_msg)) { - g_set_error (error, - NMV_EDITOR_PLUGIN_ERROR, - NMV_EDITOR_PLUGIN_ERROR_FAILED, - _("cannot write <%s> blob from line %ld to file (%s)"), - data->token, - (long) data->token_start_line, - err_msg); - return FALSE; - } - } - - saved_umask = umask (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - - /* The file is written with the default umask. Whether that is safe enough - * to protect (potentally) private data or allows the openvpn service to - * access the file later on is left as exercise for the user. */ - if (!g_file_set_contents (data->path, data->blob_data->str, data->blob_data->len, NULL)) { - g_set_error (error, - NMV_EDITOR_PLUGIN_ERROR, - NMV_EDITOR_PLUGIN_ERROR_FAILED, - _("cannot write <%s> blob from line %ld to file “%s”"), - data->token, - (long) data->token_start_line, - data->path); - umask (saved_umask); - return FALSE; - } - - umask (saved_umask); - return TRUE; -} - /*****************************************************************************/ static gboolean @@ -884,179 +469,6 @@ parse_preshared_key(const char **line, char **key, char **out_error) return TRUE; } -static gboolean -_is_ip4(char *addr) -{ - int idx = 0; - int dots = 0; - gchar **parts; - gchar **tmp; - gchar **tmp2; - gchar *lastpart; - gboolean success = TRUE; - - if(!addr){ - return FALSE; - } - - while(addr && addr[idx]){ - if(addr[idx] == '.'){ - dots++; - } - idx++; - } - - if(dots != 3){ - return FALSE; - } - - parts = g_strsplit(addr, ".", 0); - - // iterate over the first three parts, which cannot be anything else than numbers - for(idx = 0; idx < 3; idx++){ - if(!g_ascii_string_to_unsigned(parts[idx], 10, 0, 255, NULL, NULL)){ - success = FALSE; - goto ip4end; - } - } - - // if the last part is a number, we're fine - lastpart = parts[3]; - if(g_ascii_string_to_unsigned(lastpart, 10, 0, 255, NULL, NULL)){ - success = TRUE; - goto ip4end; - } - - // might have a subnet suffix after a slash (e.g. 192.168.1.254/24) - // might have a port suffix after a colon (e.g. 192.168.1.254:8080) - if(g_strrstr(lastpart, ":") && g_strrstr(lastpart, "/")){ - tmp = g_strsplit(lastpart, ":", 2); - tmp2 = g_strsplit(tmp[1], "/", 2); - - if(!g_ascii_string_to_unsigned(tmp[0], 10, 0, 255, NULL, NULL)){ - // the last part of the IP - success = FALSE; - } - - if(!g_ascii_string_to_unsigned(tmp2[0], 10, 0, 65535, NULL, NULL)){ - // the port - success = FALSE; - } - - if(!g_ascii_string_to_unsigned(tmp2[1], 10, 0, 32, NULL, NULL)){ - // the subnet portion - success = FALSE; - } - - g_strfreev(tmp); - g_strfreev(tmp2); - } - else if(g_strrstr(lastpart, "/")){ - tmp = g_strsplit(lastpart, "/", 2); - - if(!g_ascii_string_to_unsigned(tmp[0], 10, 0, 255, NULL, NULL)){ - // the last part of the IP - success = FALSE; - } - - if(!g_ascii_string_to_unsigned(tmp[1], 10, 0, 32, NULL, NULL)){ - // the subnet portion - success = FALSE; - } - - g_strfreev(tmp); - } - else if(g_strrstr(lastpart, ":")){ - tmp = g_strsplit(lastpart, ":", 2); - - if(!g_ascii_string_to_unsigned(tmp[0], 10, 0, 255, NULL, NULL)){ - // the last part of the IP - success = FALSE; - } - - if(!g_ascii_string_to_unsigned(tmp[1], 10, 0, 65535, NULL, NULL)){ - // the port - success = FALSE; - } - - g_strfreev(tmp); - } - else{ - // we have neither a port nor a subnet suffix, but it's not a number either - success = FALSE; - } - -ip4end: - g_strfreev(parts); - return success; -} - -static gboolean -_is_ip6(char *addr) -{ - gchar **parts; - gchar **tmp; - gchar *lastpart; - int len = 0; - int i = 0; - int num_empty = 0; - gboolean success = TRUE; - - if(!addr){ - return FALSE; - } - else if(!g_strrstr(addr, ":")){ - return FALSE; - } - - parts = g_strsplit(addr, ":", 0); - while(parts && parts[len]){ - len++; - } - - num_empty = 0; - for(i = 0; i < (len-1); i++){ - if((i == 0) && (!g_strcmp0("", parts[i]))){ - // the beginning may be empty (e.g. in "::1") - continue; - } - - if(!g_strcmp0("", parts[i]) && (num_empty < 1)){ - // there may be one "skipped" part in the IP6 - num_empty++; - } - else if(!g_ascii_string_to_unsigned(parts[i], 16, 0, 65536, NULL, NULL)){ - // the rest of the parts have to be numerals between 0 and 16^4 in hex - success = FALSE; - goto ip6end; - } - } - - lastpart = parts[len-1]; - if(g_strrstr(lastpart, "/")){ - // we have a subnet portion - tmp = g_strsplit(lastpart, "/", 2); - - if(g_strcmp0("", tmp[0]) && !g_ascii_string_to_unsigned(tmp[0], 16, 0, 65536, NULL, NULL)){ - success = FALSE; - } - else if(!g_ascii_string_to_unsigned(tmp[1], 10, 0, 128, NULL, NULL)){ - success = FALSE; - } - - g_strfreev(tmp); - } - else{ - // there is only a number, or an empty string (e.g. in the case of "::") - if(g_strcmp0("", lastpart) && !g_ascii_string_to_unsigned(lastpart, 16, 0, 65536, NULL, NULL)){ - success = FALSE; - } - } - -ip6end: - g_strfreev(parts); - return success; -} static char * _parse_ip4_address(const char *address) @@ -1070,7 +482,7 @@ _parse_ip4_address(const char *address) ip4[len - 1] = '\0'; } - if(!_is_ip4(ip4)){ + if(!is_ip4(ip4)){ g_free(ip4); ip4 = NULL; } @@ -1089,7 +501,7 @@ _parse_ip6_address(const char *address) ip6[len - 1] = '\0'; } - if(!_is_ip6(ip6)){ + if(!is_ip6(ip6)){ g_free(ip6); ip6 = NULL; } @@ -1097,6 +509,58 @@ _parse_ip6_address(const char *address) return ip6; } +static gboolean +parse_dns(const char **line, char **dns, char **out_error) +{ + int idx = 0; + char *tmp = NULL; + + if(!_parse_common(line, &idx, out_error)){ + *dns = NULL; + return FALSE; + } + + tmp = _parse_ip4_address(line[idx]); + if(!tmp){ + + // if the DNS isn't an IPv4 address, let's try IPv6... + tmp = _parse_ip6_address(line[idx]); + if(tmp){ + *dns = tmp; + return TRUE; + } + + *out_error = g_strdup_printf("'%s' is not a valid DNS address!", line[idx]); + *dns = NULL; + return FALSE; + } + + *dns = tmp; + return TRUE; +} + +static gboolean +parse_mtu(const char **line, guint64 *mtu, char **out_error) +{ + int idx = 0; + char *tmp = NULL; + gboolean success = TRUE; + + if(!_parse_common(line, &idx, out_error)){ + return FALSE; + } + + tmp = g_strdup(line[idx]); + if(!g_ascii_string_to_unsigned(tmp, 10, 0, 1500, mtu, NULL)){ + *out_error = g_strdup_printf("'%s' is not a valid MTU assignment!", tmp); + *mtu = -1; + success = FALSE; + } + + g_free(tmp); + return success; +} + static gboolean parse_address(const char **line, char **ip4_address, char **ip6_address, char **out_error) { @@ -1129,6 +593,11 @@ parse_address(const char **line, char **ip4_address, char **ip6_address, char ** idx++; } + if(!success) + { + *out_error = g_strdup_printf("Assignment of Addresses was invalid (requires at least one valid IPv4 or IPv6 address)!"); + } + return success; } @@ -1165,6 +634,7 @@ ip4next: } if(!success){ + *out_error = g_strdup_printf("Assignment of Allowed IPs was invalid (requires at least one valid IPv4 or IPv6 address)!"); g_array_free(*addresses, TRUE); } return success; @@ -1258,16 +728,13 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** const char *cur_line, *cur_line_delimiter; gsize cur_line_len; gsize contents_cur_line; - gboolean have_client = FALSE, have_remote = FALSE; - gboolean have_pass = FALSE, have_sk = FALSE; - const char *ctype = NULL; + gboolean have_endpoint = FALSE, have_allowed_ips = FALSE; + gboolean have_pub_key = FALSE, have_priv_key = FALSE; + gboolean have_ip4_addr = FALSE, have_ip6_addr = FALSE; + gboolean have_listen_port = FALSE; gs_free char *basename = NULL; gs_free char *default_path = NULL; char *tmp, *tmp2; - const char *ta_direction = NULL, *secret_direction = NULL; - gboolean allow_ta_direction = FALSE, allow_secret_direction = FALSE; - gboolean have_certs, have_ca; - GSList *inline_blobs = NULL, *sl_iter; g_return_val_if_fail (!error || !*error, NULL); @@ -1314,7 +781,6 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** &cur_line_delimiter)) { gs_free const char **params = NULL; char *line_error = NULL; - gint64 v_int64; contents_cur_line++; @@ -1342,6 +808,7 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** } setting_vpn_add_data_item_int64(s_vpn, NM_WG_KEY_LISTEN_PORT, port); + have_listen_port = TRUE; printf("%s = %ld\n", NMV_WG_TAG_LISTEN_PORT, port); continue; } @@ -1356,20 +823,46 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** if(addr4 && addr6){ setting_vpn_add_data_item(s_vpn, NM_WG_KEY_ADDR_IP4, addr4); setting_vpn_add_data_item(s_vpn, NM_WG_KEY_ADDR_IP6, addr6); + have_ip4_addr = TRUE; + have_ip6_addr = TRUE; printf("%s = %s, %s\n", NMV_WG_TAG_ADDRESS, addr4, addr6); } else if(addr4){ setting_vpn_add_data_item(s_vpn, NM_WG_KEY_ADDR_IP4, addr4); + have_ip4_addr = TRUE; printf("%s = %s\n", NMV_WG_TAG_ADDRESS, addr4); } else if(addr6){ setting_vpn_add_data_item(s_vpn, NM_WG_KEY_ADDR_IP6, addr6); + have_ip6_addr = TRUE; printf("%s = %s\n", NMV_WG_TAG_ADDRESS, addr6); } continue; } + if (NM_IN_STRSET (params[0], NMV_WG_TAG_DNS)){ + char *dns = NULL; + if(!parse_dns(params, &dns, &line_error)){ + goto handle_line_error; + } + + setting_vpn_add_data_item(s_vpn, NM_WG_KEY_DNS, dns); + printf("%s = %s\n", NM_WG_KEY_DNS, dns); + continue; + } + + if (NM_IN_STRSET (params[0], NMV_WG_TAG_MTU)){ + char *mtu = NULL; + if(!parse_mtu(params, &mtu, &line_error)){ + goto handle_line_error; + } + + setting_vpn_add_data_item_int64(s_vpn, NM_WG_KEY_MTU, mtu); + printf("%s = %s\n", NM_WG_KEY_DNS, mtu); + continue; + } + if (NM_IN_STRSET (params[0], NMV_WG_TAG_PRIVATE_KEY)){ char *key = NULL; if(!parse_private_key(params, &key, &line_error)){ @@ -1377,6 +870,7 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** } setting_vpn_add_data_item(s_vpn, NM_WG_KEY_PRIVATE_KEY, key); + have_priv_key = TRUE; printf("%s = %s\n", NMV_WG_TAG_PRIVATE_KEY, key); continue; } @@ -1392,6 +886,17 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** continue; } + if (NM_IN_STRSET (params[0], NMV_WG_TAG_PRE_UP)){ + char *script = NULL; + if(!parse_script(params, &script, &line_error)){ + goto handle_line_error; + } + + setting_vpn_add_data_item(s_vpn, NM_WG_KEY_PRE_UP, script); + printf("%s = %s\n", NMV_WG_TAG_PRE_UP, script); + continue; + } + if (NM_IN_STRSET (params[0], NMV_WG_TAG_POST_UP)){ char *script = NULL; if(!parse_script(params, &script, &line_error)){ @@ -1403,6 +908,17 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** continue; } + if (NM_IN_STRSET (params[0], NMV_WG_TAG_PRE_DOWN)){ + char *script = NULL; + if(!parse_script(params, &script, &line_error)){ + goto handle_line_error; + } + + setting_vpn_add_data_item(s_vpn, NM_WG_KEY_PRE_DOWN, script); + printf("%s = %s\n", NMV_WG_TAG_PRE_DOWN, script); + continue; + } + if (NM_IN_STRSET (params[0], NMV_WG_TAG_POST_DOWN)){ char *script = NULL; if(!parse_script(params, &script, &line_error)){ @@ -1439,7 +955,12 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** ip_string = concatenate_strings(addrs, ", "); allowed_ips = concatenate_strings(addrs, ","); - setting_vpn_add_data_item(s_vpn, NM_WG_KEY_ALLOWED_IPS, allowed_ips); + if(addrs->len >= 1){ + setting_vpn_add_data_item(s_vpn, NM_WG_KEY_ALLOWED_IPS, allowed_ips); + have_allowed_ips = TRUE; + } + + g_array_free(addrs, TRUE); printf("%s = %s\n", NMV_WG_TAG_ALLOWED_IPS, ip_string); continue; } @@ -1451,6 +972,7 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** } setting_vpn_add_data_item(s_vpn, NM_WG_KEY_PUBLIC_KEY, key); + have_pub_key = TRUE; printf("%s = %s\n", NMV_WG_TAG_PUBLIC_KEY, key); continue; } @@ -1462,675 +984,12 @@ do_import (const char *path, const char *contents, gsize contents_len, GError ** } setting_vpn_add_data_item(s_vpn, NM_WG_KEY_ENDPOINT, endpoint); + have_endpoint = TRUE; printf("%s = %s\n", NMV_WG_TAG_ENDPOINT, endpoint); continue; } - /*************************************************************************************/ - - /* allow for a leading double-dash and skip over it (bypass_doubledash). */ - if (g_str_has_prefix (params[0], "--")) - params[0] = ¶ms[0][2]; - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_CLIENT, NMV_OVPN_TAG_TLS_CLIENT)) { - if (!args_params_check_nargs_n (params, 0, &line_error)) - goto handle_line_error; - have_client = TRUE; - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_KEY_DIRECTION)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_parse_key_direction (params, 1, &ta_direction, &line_error)) - goto handle_line_error; - secret_direction = ta_direction; - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_DEV)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_check_arg_nonempty (params, 1, NULL, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item_utf8safe (s_vpn, NM_OPENVPN_KEY_DEV, params[1]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_DEV_TYPE)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!NM_IN_STRSET (params[1], "tun", "tap")) { - line_error = args_params_error_message_invalid_arg (params, 1); - goto handle_line_error; - } - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_DEV_TYPE, params[1]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_PROTO)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - /* Valid parameters are "udp", "tcp-client" and "tcp-server". - * 'tcp' isn't technically valid, but it used to be accepted so - * we'll handle it here anyway. - */ - if (nm_streq (params[1], "udp")) { - /* ignore; udp is default */ - } else if (NM_IN_STRSET (params[1], "tcp-client", "tcp-server", "tcp")) - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_PROTO_TCP, "yes"); - else { - line_error = args_params_error_message_invalid_arg (params, 1); - goto handle_line_error; - } - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_MSSFIX)) { - if (!args_params_check_nargs_minmax (params, 0, 1, &line_error)) - goto handle_line_error; - if (params[1]) { - if (!args_params_parse_int64 (params, 1, 1, G_MAXINT32, &v_int64, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_MSSFIX, v_int64); - } else - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_MSSFIX, "yes"); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_MTU_DISC)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!NM_IN_STRSET (params[1], "no", "maybe", "yes")) { - line_error = g_strdup_printf (_("unsupported mtu-disc argument")); - goto handle_line_error; - } - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_MTU_DISC, params[1]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_NS_CERT_TYPE)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!NM_IN_STRSET (params[1], NM_OPENVPN_NS_CERT_TYPE_CLIENT, NM_OPENVPN_NS_CERT_TYPE_SERVER)) { - line_error = g_strdup_printf (_("invalid option")); - goto handle_line_error; - } - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_NS_CERT_TYPE, params[1]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_TUN_MTU)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_parse_int64 (params, 1, 0, 0xffff, &v_int64, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_TUNNEL_MTU, v_int64); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_FRAGMENT)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_parse_int64 (params, 1, 0, 0xffff, &v_int64, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_FRAGMENT_SIZE, v_int64); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_COMP_LZO)) { - const char *v; - - if (!args_params_check_nargs_minmax (params, 0, 1, &line_error)) - goto handle_line_error; - - v = params[1] ?: "adaptive"; - - if (nm_streq (v, "no")) { - /* old plasma-nm used to set "comp-lzo=no" to mean unset, thus it spoiled - * to "no" option to be used in the connection. Workaround that, by instead - * using "no-by-default" (bgo#769177). */ - v = "no-by-default"; - } else if (!NM_IN_STRSET (v, "yes", "adaptive")) { - line_error = g_strdup_printf (_("unsupported comp-lzo argument")); - goto handle_line_error; - } - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_COMP_LZO, v); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_FLOAT)) { - if (!args_params_check_nargs_n (params, 0, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_FLOAT, "yes"); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_RENEG_SEC)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_parse_int64 (params, 1, 0, G_MAXINT, &v_int64, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_RENEG_SECONDS, v_int64); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_MAX_ROUTES)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_parse_int64 (params, 1, 0, 100000000, &v_int64, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_MAX_ROUTES, v_int64); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_HTTP_PROXY_RETRY, NMV_OVPN_TAG_SOCKS_PROXY_RETRY)) { - if (!args_params_check_nargs_n (params, 0, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_PROXY_RETRY, "yes"); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_HTTP_PROXY, NMV_OVPN_TAG_SOCKS_PROXY)) { - const char *proxy_type = NULL; - gint64 port = 0; - gs_free char *user = NULL; - gs_free char *pass = NULL; - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_HTTP_PROXY)) { - proxy_type = "http"; - if (!args_params_check_nargs_minmax (params, 2, 4, &line_error)) - goto handle_line_error; - } else { - proxy_type = "socks"; - if (!args_params_check_nargs_minmax (params, 1, 3, &line_error)) - goto handle_line_error; - } - - if (!args_params_check_arg_utf8 (params, 1, "service", &line_error)) - goto handle_line_error; - - if (params[2]) { - if (!args_params_parse_port (params, 2, &port, &line_error)) - goto handle_line_error; - - if (params[3]) { - if (!parse_http_proxy_auth (default_path, params[3], &user, &pass, &line_error)) - goto handle_line_error; - } - } - - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_PROXY_TYPE, proxy_type); - - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_PROXY_SERVER, params[1]); - if (port > 0) - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_PROXY_PORT, port); - if (user) - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_USERNAME, user); - if (pass) { - nm_setting_vpn_add_secret (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD, pass); - nm_setting_set_secret_flags (NM_SETTING (s_vpn), - NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD, - NM_SETTING_SECRET_FLAG_AGENT_OWNED, - NULL); - } - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_REMOTE)) { - const char *prev; - GString *new_remote; - int port = -1; - gboolean host_has_colon; - struct in6_addr a; - - if (!args_params_check_nargs_minmax (params, 1, 3, &line_error)) - goto handle_line_error; - - if (!args_params_check_arg_utf8 (params, 1, NULL, &line_error)) - goto handle_line_error; - if (strchr (params[1], ' ')) { - line_error = g_strdup_printf (_("remote cannot contain space")); - goto handle_line_error; - } - if (strchr (params[1], ',')) { - line_error = g_strdup_printf (_("remote cannot contain comma")); - goto handle_line_error; - } - - if (params[2]) { - if (!args_params_parse_port (params, 2, &v_int64, &line_error)) - goto handle_line_error; - port = v_int64; - - if (params[3]) { - if (!NM_IN_STRSET (params[3], NMOVPN_PROTCOL_TYPES)) { - line_error = g_strdup_printf (_("remote expects protocol type like “udp” or “tcp”")); - goto handle_line_error; - } - } - } - - new_remote = g_string_sized_new (64); - - prev = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE); - if (prev) { - g_string_assign (new_remote, prev); - g_string_append (new_remote, ", "); - } - - host_has_colon = (strchr (params[1], ':') != NULL); - if ( host_has_colon - && inet_pton (AF_INET6, params[1], &a) == 1) { - /* need to escape the host. */ - g_string_append_printf (new_remote, "[%s]", params[1]); - } else - g_string_append (new_remote, params[1]); - - if (params[2]) { - g_string_append_printf (new_remote, ":%d", port); - if (params[3]) { - g_string_append_c (new_remote, ':'); - g_string_append (new_remote, params[3]); - } else if (host_has_colon) - g_string_append_c (new_remote, ':'); - } else if (host_has_colon) - g_string_append (new_remote, "::"); - - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE, new_remote->str); - g_string_free (new_remote, TRUE); - - have_remote = TRUE; - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_REMOTE_RANDOM)) { - if (!args_params_check_nargs_n (params, 0, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE_RANDOM, "yes"); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_TUN_IPV6)) { - if (!args_params_check_nargs_n (params, 0, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_TUN_IPV6, "yes"); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_PORT, NMV_OVPN_TAG_RPORT)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_parse_port (params, 1, &v_int64, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_PORT, v_int64); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_PING, NMV_OVPN_TAG_PING_EXIT, NMV_OVPN_TAG_PING_RESTART)) { - const char *key = NULL; - - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_parse_int64 (params, 1, 0, G_MAXINT, &v_int64, &line_error)) - goto handle_line_error; - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_PING)) - key = NM_OPENVPN_KEY_PING; - else if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_PING_EXIT)) - key = NM_OPENVPN_KEY_PING_EXIT; - else if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_PING_RESTART)) - key = NM_OPENVPN_KEY_PING_RESTART; - - setting_vpn_add_data_item_int64 (s_vpn, key, v_int64); - continue; - } - - if (NM_IN_STRSET (params[0], - NMV_OVPN_TAG_PKCS12, - NMV_OVPN_TAG_CA, - NMV_OVPN_TAG_CERT, - NMV_OVPN_TAG_KEY, - NMV_OVPN_TAG_SECRET, - NMV_OVPN_TAG_TLS_AUTH, - NMV_OVPN_TAG_TLS_CRYPT)) { - const char *file; - gs_free char *file_free = NULL; - gboolean can_have_direction; - const char *s_direction = NULL; - - can_have_direction = NM_IN_STRSET (params[0], - NMV_OVPN_TAG_SECRET, - NMV_OVPN_TAG_TLS_AUTH); - - if (!args_params_check_nargs_minmax (params, 1, can_have_direction ? 2 : 1, &line_error)) - goto handle_line_error; - - if (!args_params_check_arg_nonempty (params, 1, NULL, &line_error)) - goto handle_line_error; - file = params[1]; - - if (params[2]) { - if (!args_params_parse_key_direction (params, 2, &s_direction, &line_error)) - goto handle_line_error; - } - - if (!g_path_is_absolute (file)) - file = file_free = g_build_filename (default_path, file, NULL); - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_PKCS12)) { - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_CA, file); - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_CERT, file); - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_KEY, file); - } else if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_CA)) - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_CA, file); - else if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_CERT)) - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_CERT, file); - else if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_KEY)) - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_KEY, file); - else if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_SECRET)) { - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_STATIC_KEY, file); - if (s_direction) - secret_direction = s_direction; - allow_secret_direction = TRUE; - have_sk = TRUE; - } else if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_TLS_AUTH)) { - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_TA, file); - if (s_direction) - ta_direction = s_direction; - allow_ta_direction = TRUE; - } else if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_TLS_CRYPT)) - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_TLS_CRYPT, file); - else - g_assert_not_reached (); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_CIPHER)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_check_arg_utf8 (params, 1, NULL, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_CIPHER, params[1]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_TLS_CIPHER)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_check_arg_utf8 (params, 1, NULL, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_TLS_CIPHER, params[1]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_KEEPALIVE)) { - gint64 v2; - - if (!args_params_check_nargs_n (params, 2, &line_error)) - goto handle_line_error; - if (!args_params_parse_int64 (params, 1, 0, G_MAXINT, &v_int64, &line_error)) - goto handle_line_error; - if (!args_params_parse_int64 (params, 2, 0, G_MAXINT, &v2, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_PING, v_int64); - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_PING_RESTART, v2); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_KEYSIZE)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_parse_int64 (params, 1, 1, 65535, &v_int64, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item_int64 (s_vpn, NM_OPENVPN_KEY_KEYSIZE, v_int64); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_TLS_REMOTE)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_check_arg_utf8 (params, 1, NULL, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_TLS_REMOTE, params[1]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_VERIFY_X509_NAME)) { - const char *type = NM_OPENVPN_VERIFY_X509_NAME_TYPE_SUBJECT; - gs_free char *item = NULL; - - if (!args_params_check_nargs_minmax (params, 1, 2, &line_error)) - goto handle_line_error; - if (!args_params_check_arg_utf8 (params, 1, NULL, &line_error)) - goto handle_line_error; - - if (params[2]) { - if (!NM_IN_STRSET (params[2], - NM_OPENVPN_VERIFY_X509_NAME_TYPE_SUBJECT, - NM_OPENVPN_VERIFY_X509_NAME_TYPE_NAME, - NM_OPENVPN_VERIFY_X509_NAME_TYPE_NAME_PREFIX)) { - line_error = g_strdup_printf (_("invalid verify-x509-name type")); - goto handle_line_error; - } - - type = params[2]; - } - - item = g_strdup_printf ("%s:%s", type, params[1]); - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_VERIFY_X509_NAME, item); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_REMOTE_CERT_TLS)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!NM_IN_STRSET (params[1], NM_OPENVPN_REM_CERT_TLS_CLIENT, NM_OPENVPN_REM_CERT_TLS_SERVER)) { - line_error = g_strdup_printf (_("invalid option")); - goto handle_line_error; - } - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE_CERT_TLS, params[1]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_IFCONFIG)) { - if (!args_params_check_nargs_n (params, 2, &line_error)) - goto handle_line_error; - if (!args_params_check_arg_utf8 (params, 1, "local", &line_error)) - goto handle_line_error; - if (!args_params_check_arg_utf8 (params, 2, "remote", &line_error)) - goto handle_line_error; - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_LOCAL_IP, params[1]); - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE_IP, params[2]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_AUTH_USER_PASS)) { - if (!args_params_check_nargs_minmax (params, 0, 1, &line_error)) - goto handle_line_error; - have_pass = TRUE; - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_AUTH)) { - if (!args_params_check_nargs_n (params, 1, &line_error)) - goto handle_line_error; - if (!args_params_check_arg_utf8 (params, 1, NULL, &line_error)) - goto handle_line_error; - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_AUTH, params[1]); - continue; - } - - if (NM_IN_STRSET (params[0], NMV_OVPN_TAG_ROUTE)) { - in_addr_t network; - in_addr_t gateway = 0; - guint32 prefix = 32; - gint64 metric = -1; - - if (!args_params_check_nargs_minmax (params, 1, 4, &line_error)) - goto handle_line_error; - - if (!args_params_parse_ip4 (params, 1, TRUE, &network, &line_error)) - goto handle_line_error; - - if (params[2]) { - in_addr_t netmask; - - if (!args_params_parse_ip4 (params, 2, FALSE, &netmask, &line_error)) - goto handle_line_error; - prefix = nm_utils_ip4_netmask_to_prefix (netmask); - - if (params[3]) { - if (!args_params_parse_ip4 (params, 3, TRUE, &gateway, &line_error)) - goto handle_line_error; - if (params[4]) { - if (!args_params_parse_int64 (params, 4, 0, G_MAXUINT32, &v_int64, &line_error)) - goto handle_line_error; - metric = (guint32) v_int64; - } - } - } - - if (prefix == 0 && network == 0) { - /* the default-route cannot be specified as normal route in NMSettingIPConfig. - * Just set never-default=FALSE (which is already the default). */ - g_object_set (s_ip4, - NM_SETTING_IP_CONFIG_NEVER_DEFAULT, - FALSE, - NULL); - continue; - } - - { -#ifdef NM_VPN_OLD - NMIP4Route *route; - - route = nm_ip4_route_new (); - nm_ip4_route_set_dest (route, network); - nm_ip4_route_set_prefix (route, prefix); - nm_ip4_route_set_next_hop (route, gateway); - if (metric >= 0) - nm_ip4_route_set_metric (route, metric); - nm_setting_ip4_config_add_route (s_ip4, route); - nm_ip4_route_unref (route); -#else - NMIPRoute *route; - - route = nm_ip_route_new_binary (AF_INET, &network, prefix, params[3] ? &gateway : NULL, metric, NULL); - nm_setting_ip_config_add_route (s_ip4, route); - nm_ip_route_unref (route); -#endif - } - } - - if (params[0][0] == '<' && params[0][strlen (params[0]) - 1] == '>') { - gs_free char *token = g_strndup (¶ms[0][1], strlen (params[0]) - 2); - gs_free char *end_token = NULL; - gsize end_token_len; - gsize my_contents_cur_line = contents_cur_line; - gboolean is_base64 = FALSE; - char *f_path; - const char *key; - GString *blob_data; - InlineBlobData *inline_blob_data; - - if (nm_streq (token, INLINE_BLOB_CA)) - key = NM_OPENVPN_KEY_CA; - else if (nm_streq (token, INLINE_BLOB_CERT)) - key = NM_OPENVPN_KEY_CERT; - else if (nm_streq (token, INLINE_BLOB_KEY)) - key = NM_OPENVPN_KEY_KEY; - else if (nm_streq (token, INLINE_BLOB_PKCS12)) { - is_base64 = TRUE; - key = NULL; - } else if (nm_streq (token, INLINE_BLOB_TLS_CRYPT)) - key = NM_OPENVPN_KEY_TLS_CRYPT; - else if (nm_streq (token, INLINE_BLOB_TLS_AUTH)) { - key = NM_OPENVPN_KEY_TA; - allow_ta_direction = TRUE; - } else if (nm_streq (token, INLINE_BLOB_SECRET)) { - key = NM_OPENVPN_KEY_STATIC_KEY; - allow_secret_direction = TRUE; - } else { - line_error = g_strdup_printf (_("unsupported blob/xml element")); - goto handle_line_error; - } - - end_token = g_strdup_printf ("", token); - end_token_len = strlen (end_token); - - blob_data = g_string_new (NULL); - - while (args_next_line (&contents, - &contents_len, - &cur_line, - &cur_line_len, - &cur_line_delimiter)) { - my_contents_cur_line++; - - /* skip over trailing space like openvpn does. */ - _ch_skip_over_leading_whitespace (&cur_line, &cur_line_len); - - if (!strncmp (cur_line, end_token, end_token_len)) { - end_token_len = 0; - break; - } - - g_string_append_len (blob_data, cur_line, cur_line_len); - if (cur_line_delimiter) - g_string_append_c (blob_data, cur_line_delimiter[0]); - } - if (end_token_len) { - line_error = g_strdup_printf (_("unterminated blob element <%s>"), token); - g_string_free (blob_data, TRUE); - goto handle_line_error; - } - - if (is_base64) { - gs_free guint8 *d = NULL; - gsize l; - - d = g_base64_decode (blob_data->str, &l); - g_string_truncate (blob_data, 0); - g_string_append_len (blob_data, (const char *) d, l); - } - - /* the latest cert wins... */ - for (sl_iter = inline_blobs; sl_iter; sl_iter = sl_iter->next) { - InlineBlobData *d = sl_iter->data; - - if (nm_streq (d->token, token)) { - inline_blobs = g_slist_delete_link (inline_blobs, sl_iter); - inline_blob_data_free (d); - break; - } - } - - f_path = inline_blob_construct_path (basename, token); - - inline_blob_data = g_slice_new (InlineBlobData); - inline_blob_data->blob_data = blob_data; - inline_blob_data->token_start_line = contents_cur_line; - inline_blob_data->path = f_path; - inline_blob_data->token = token; - inline_blob_data->key = key; - token = NULL; - - inline_blobs = g_slist_prepend (inline_blobs, inline_blob_data); - contents_cur_line = my_contents_cur_line; - - if (key) - setting_vpn_add_data_item_path (s_vpn, key, f_path); - else { - nm_assert (nm_streq (token, INLINE_BLOB_PKCS12)); - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_CA, f_path); - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_CERT, f_path); - setting_vpn_add_data_item_path (s_vpn, NM_OPENVPN_KEY_KEY, f_path); - } - continue; - } - - /* TODO: currently we ignore any unknown options and skip over them. */ + /* currently we ignore any unknown options and skip over them. */ continue; handle_line_error: @@ -2144,102 +1003,55 @@ handle_line_error: goto out_error; } - if (allow_secret_direction && secret_direction) - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_STATIC_KEY_DIRECTION, secret_direction); - if (allow_ta_direction && ta_direction) - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_TA_DIR, ta_direction); + // check requirements for interface + + if(!have_priv_key){ + g_set_error_literal(error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FAILED, + "The file to import wasn't a valid Wireguard configuration (no local private key)"); - if (!have_client && !have_sk) { - g_set_error_literal (error, - NMV_EDITOR_PLUGIN_ERROR, - NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN, - _("The file to import wasn’t a valid OpenVPN client configuration")); goto out_error; } - if (!have_remote) { - g_set_error_literal (error, - NMV_EDITOR_PLUGIN_ERROR, - NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN, - _("The file to import wasn’t a valid OpenVPN configure (no remote)")); + if(!have_listen_port){ + g_set_error_literal(error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FAILED, + "The file to import wasn't a valid Wireguard configuration (no local listen port)"); + goto out_error; } - have_certs = FALSE; - have_ca = FALSE; + if(!have_ip4_addr && !have_ip6_addr){ + g_set_error_literal(error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FAILED, + "The file to import wasn't a valid Wireguard configuration (no local IPv4 or IPv6 addresses)"); - if (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CA)) - have_ca = TRUE; - - if ( have_ca - && nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CERT) - && nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_KEY)) - have_certs = TRUE; - - /* Determine connection type */ - if (have_pass) { - if (have_certs) - ctype = NM_OPENVPN_CONTYPE_PASSWORD_TLS; - else if (have_ca) - ctype = NM_OPENVPN_CONTYPE_PASSWORD; - } else if (have_certs) { - ctype = NM_OPENVPN_CONTYPE_TLS; - } else if (have_sk) - ctype = NM_OPENVPN_CONTYPE_STATIC_KEY; - - if (!ctype) - ctype = NM_OPENVPN_CONTYPE_TLS; - - setting_vpn_add_data_item (s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE, ctype); - - /* Default secret flags to be agent-owned */ - if (have_pass) { - nm_setting_set_secret_flags (NM_SETTING (s_vpn), - NM_OPENVPN_KEY_PASSWORD, - NM_SETTING_SECRET_FLAG_AGENT_OWNED, - NULL); - } - if (have_certs) { - gs_free char *key_path_free = NULL; - const char *key_path; - - key_path = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_KEY); - if (is_encrypted (nm_utils_str_utf8safe_unescape (key_path, &key_path_free))) { - /* If there should be a private key password, default it to - * being agent-owned. - */ - nm_setting_set_secret_flags (NM_SETTING (s_vpn), - NM_OPENVPN_KEY_CERTPASS, - NM_SETTING_SECRET_FLAG_AGENT_OWNED, - NULL); - } + goto out_error; } - inline_blobs = g_slist_reverse (inline_blobs); - for (sl_iter = inline_blobs; sl_iter; sl_iter = sl_iter->next) { - const InlineBlobData *data = sl_iter->data; + // check requirements for peer - /* Check whether the setting was not overwritten by a later entry in the config-file. */ - if (nm_streq (data->token, INLINE_BLOB_PKCS12)) { - if ( !setting_vpn_eq_data_item_utf8safe (s_vpn, NM_OPENVPN_KEY_CA, data->path) - && !setting_vpn_eq_data_item_utf8safe (s_vpn, NM_OPENVPN_KEY_CERT, data->path) - && !setting_vpn_eq_data_item_utf8safe (s_vpn, NM_OPENVPN_KEY_KEY, data->path)) - continue; - } else { - if (!setting_vpn_eq_data_item_utf8safe (s_vpn, data->key, data->path)) - continue; - } - if (!inline_blob_write_out (sl_iter->data, error)) - goto out_error; + if(!have_pub_key){ + g_set_error_literal(error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FAILED, + "The file to import wasn't a valid Wireguard configuration (no peer public key)"); + + goto out_error; + } + + if(!have_allowed_ips){ + // if we don't have allowed IPs set: don't fret! + setting_vpn_add_data_item(s_vpn, NM_WG_KEY_ALLOWED_IPS, "0.0.0.0/0,::/0"); + } + + if(!have_endpoint){ + g_set_error_literal(error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FAILED, + "The file to import wasn't a valid Wireguard configuration (no peer endpoint)"); + + goto out_error; } - g_slist_free_full (inline_blobs, (GDestroyNotify) inline_blob_data_free); connection_free = NULL; g_return_val_if_fail (!error || !*error, connection); return connection; out_error: - g_slist_free_full (inline_blobs, (GDestroyNotify) inline_blob_data_free); g_return_val_if_fail (!error || *error, NULL); return NULL; } @@ -2311,8 +1123,6 @@ args_write_line_v (GString *f, gsize nargs, const char **args) nm_assert (args[0]); for (i = 0; i < nargs; i++) { - gs_free char *tmp = NULL; - /* NULL is skipped. This is for convenience to specify * optional arguments. */ if (!args[i]) @@ -2321,7 +1131,7 @@ args_write_line_v (GString *f, gsize nargs, const char **args) if (printed) g_string_append_c (f, ' '); printed = TRUE; - g_string_append (f, escape_arg (args[i], &tmp)); + g_string_append (f, args[i]); } g_string_append_c (f, '\n'); } @@ -2377,16 +1187,20 @@ static GString * do_export_create (NMConnection *connection, const char *path, GError **error) { NMSettingConnection *s_con; - NMSettingIPConfig *s_ip4; NMSettingVpn *s_vpn; - const char *value; - const char *gateways; - char **gw_list, **gw_iter; - const char *connection_type; - const char *local_ip = NULL; - const char *remote_ip = NULL; - const char *proxy_type = NULL; - guint i, num; + const char *ip4; + const char *ip6; + const char *listen_port; + const char *private_key; + const char *post_up; + const char *post_down; + const char *public_key; + const char *allowed_ips; + const char *endpoint; + const char *psk; + char *value = NULL; + char **ip_list, **ip_iter; + GArray *ips; nm_auto(_auto_free_gstring_p) GString *f = NULL; if (!path || !path[0]) { @@ -2403,329 +1217,109 @@ do_export_create (NMConnection *connection, const char *path, GError **error) g_set_error_literal (error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN, - _("connection is not a valid OpenVPN connection")); + _("connection is not a valid Wireguard connection")); return NULL; } - gateways = _arg_is_set (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE)); - if (!gateways) { - g_set_error_literal (error, - NMV_EDITOR_PLUGIN_ERROR, - NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN, - _("connection was incomplete (missing gateway)")); + ip4 = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_ADDR_IP4)); + ip6 = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_ADDR_IP6)); + listen_port = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_LISTEN_PORT)); + private_key = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_PRIVATE_KEY)); + post_up = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_POST_UP)); + post_down = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_POST_DOWN)); + public_key = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_PUBLIC_KEY)); + allowed_ips = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_ALLOWED_IPS)); + endpoint = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_ENDPOINT)); + psk = _arg_is_set(nm_setting_vpn_get_data_item(s_vpn, NM_WG_KEY_PRESHARED_KEY)); + + if(!ip4 && !ip6){ + g_set_error_literal(error, + NMV_EDITOR_PLUGIN_ERROR, + NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN, + "Connection was incomplete (missing local address)"); return NULL; } - connection_type = _arg_is_set (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE)); + if(!listen_port){ + g_set_error_literal(error, + NMV_EDITOR_PLUGIN_ERROR, + NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN, + "Connection was incomplete (missing local listen port)"); + return NULL; + } + + if(!private_key){ + g_set_error_literal(error, + NMV_EDITOR_PLUGIN_ERROR, + NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN, + "Connection was incomplete (missing local private key)"); + return NULL; + } + + if(!public_key){ + g_set_error_literal(error, + NMV_EDITOR_PLUGIN_ERROR, + NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN, + "Connection was incomplete (missing peer public key)"); + return NULL; + } + + if(!endpoint){ + g_set_error_literal(error, + NMV_EDITOR_PLUGIN_ERROR, + NMV_EDITOR_PLUGIN_ERROR_FILE_NOT_VPN, + "Connection was incomplete (missing endpoint)"); + return NULL; + } + + // if we don't have a limitation on the peer's allowed IPs, we assume that everything is allowed + if(!allowed_ips){ + allowed_ips = "0.0.0.0/0,::/0"; + } f = g_string_sized_new (512); - args_write_line (f, NMV_OVPN_TAG_CLIENT); + args_write_line (f, NMV_WG_TAG_INTERFACE); + args_write_line(f, NMV_WG_TAG_PRIVATE_KEY, "=", private_key); - /* 'remote' */ - gw_list = g_strsplit_set (gateways, " \t,", 0); - for (gw_iter = gw_list; gw_iter && *gw_iter; gw_iter++) { - gs_free char *str_free = NULL; - const char *host, *port, *proto; - gssize eidx; - - eidx = nmovpn_remote_parse (*gw_iter, - &str_free, - &host, - &port, - &proto, - NULL); - if (eidx >= 0) - continue; - args_write_line (f, - NMV_OVPN_TAG_REMOTE, - host, - port ?: (proto ? "1194" : NULL), - proto); + if(ip4 && ip6){ + value = g_strdup_printf("%s = %s, %s", NMV_WG_TAG_ADDRESS, ip4, ip6); } - g_strfreev (gw_list); + else if(ip4){ + value = g_strdup_printf("%s = %s", NMV_WG_TAG_ADDRESS, ip4); + } + else if(ip6){ + value = g_strdup_printf("%s = %s", NMV_WG_TAG_ADDRESS, ip6); + } + args_write_line(f, value); + g_free(value); - if (nm_streq0 (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE_RANDOM), "yes")) - args_write_line (f, NMV_OVPN_TAG_REMOTE_RANDOM); + args_write_line(f, NMV_WG_TAG_LISTEN_PORT, "=", listen_port); - if (nm_streq0 (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_TUN_IPV6), "yes")) - args_write_line (f, NMV_OVPN_TAG_TUN_IPV6); - - { - gs_free char *cacert_free = NULL, *user_cert_free = NULL, *private_key_free = NULL; - const char *cacert = NULL, *user_cert = NULL, *private_key = NULL; - - if (NM_IN_STRSET (connection_type, NM_OPENVPN_CONTYPE_TLS, - NM_OPENVPN_CONTYPE_PASSWORD, - NM_OPENVPN_CONTYPE_PASSWORD_TLS)) { - value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CA); - if (_arg_is_set (value)) - cacert = nm_utils_str_utf8safe_unescape (value, &cacert_free); - } - - if (NM_IN_STRSET (connection_type, NM_OPENVPN_CONTYPE_TLS, - NM_OPENVPN_CONTYPE_PASSWORD_TLS)) { - value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CERT); - if (_arg_is_set (value)) - user_cert = nm_utils_str_utf8safe_unescape (value, &user_cert_free); - - value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_KEY); - if (_arg_is_set (value)) - private_key = nm_utils_str_utf8safe_unescape (value, &private_key_free); - } - - if ( cacert && user_cert && private_key - && nm_streq (cacert, user_cert) && nm_streq (cacert, private_key)) { - /* Handle PKCS#12 (all certs are the same file) */ - args_write_line (f, NMV_OVPN_TAG_PKCS12, cacert); - } else { - if (cacert) - args_write_line (f, NMV_OVPN_TAG_CA, cacert); - if (user_cert) - args_write_line (f, NMV_OVPN_TAG_CERT, user_cert); - if (private_key) - args_write_line (f, NMV_OVPN_TAG_KEY, private_key); - } + if(psk){ + args_write_line(f, NMV_WG_TAG_PRESHARED_KEY, "=", psk); + } + if(post_up){ + args_write_line(f, NMV_WG_TAG_POST_UP, "=", post_up); + } + if(post_down){ + args_write_line(f, NMV_WG_TAG_POST_DOWN, "=", post_down); } - if (NM_IN_STRSET (connection_type, NM_OPENVPN_CONTYPE_PASSWORD, - NM_OPENVPN_CONTYPE_PASSWORD_TLS)) - args_write_line (f, NMV_OVPN_TAG_AUTH_USER_PASS); + args_write_line(f, NMV_WG_TAG_PEER); + args_write_line(f, NMV_WG_TAG_PUBLIC_KEY, "=", public_key); + args_write_line(f, NMV_WG_TAG_ENDPOINT, "=", endpoint); - if (NM_IN_STRSET (connection_type, NM_OPENVPN_CONTYPE_STATIC_KEY)) { - value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_STATIC_KEY); - if (_arg_is_set (value)) { - gs_free char *s_free = NULL; - - args_write_line (f, - NMV_OVPN_TAG_SECRET, - nm_utils_str_utf8safe_unescape (value, &s_free), - _arg_is_set (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_STATIC_KEY_DIRECTION))); - } + ip_list = g_strsplit_set (allowed_ips, " \t,", 0); + ips = g_array_new(TRUE, TRUE, sizeof(char *)); + for (ip_iter = ip_list; ip_iter && *ip_iter; ip_iter++) { + g_array_append_val(ips, *ip_iter); } - args_write_line_setting_value_int (f, NMV_OVPN_TAG_RENEG_SEC, s_vpn, NM_OPENVPN_KEY_RENEG_SECONDS); - - args_write_line_setting_value_int (f, NMV_OVPN_TAG_MAX_ROUTES, s_vpn, NM_OPENVPN_KEY_MAX_ROUTES); - - args_write_line_setting_value (f, NMV_OVPN_TAG_CIPHER, s_vpn, NM_OPENVPN_KEY_CIPHER); - - args_write_line_setting_value (f, NMV_OVPN_TAG_TLS_CIPHER, s_vpn, NM_OPENVPN_KEY_TLS_CIPHER); - - args_write_line_setting_value_int (f, NMV_OVPN_TAG_KEYSIZE, s_vpn, NM_OPENVPN_KEY_KEYSIZE); - - value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_COMP_LZO); - if (value) { - if (nm_streq (value, "no-by-default")) - value = "no"; - args_write_line (f, NMV_OVPN_TAG_COMP_LZO, value); - } - - if (nm_streq0 (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_FLOAT), "yes")) - args_write_line (f, NMV_OVPN_TAG_FLOAT); - - value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_MSSFIX); - if (nm_streq0 (value, "yes")) - args_write_line (f, NMV_OVPN_TAG_MSSFIX); - else if (value) - args_write_line_setting_value_int (f, NMV_OVPN_TAG_MSSFIX, s_vpn, NM_OPENVPN_KEY_MSSFIX); - - args_write_line_setting_value (f, NMV_OVPN_TAG_MTU_DISC, s_vpn, NM_OPENVPN_KEY_MTU_DISC); - - args_write_line_setting_value_int (f, NMV_OVPN_TAG_TUN_MTU, s_vpn, NM_OPENVPN_KEY_TUNNEL_MTU); - - args_write_line_setting_value_int (f, NMV_OVPN_TAG_FRAGMENT, s_vpn, NM_OPENVPN_KEY_FRAGMENT_SIZE); - - { - gs_free char *device_free = NULL; - const char *device_type, *device; - - device_type = _arg_is_set (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_DEV_TYPE)); - device = _arg_is_set (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_DEV)); - device = nm_utils_str_utf8safe_unescape (device, &device_free); - args_write_line (f, - NMV_OVPN_TAG_DEV, - device ?: - (device_type ?: - (nm_streq0 (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_TAP_DEV), "yes") - ? "tap" : "tun"))); - if (device_type) - args_write_line (f, NMV_OVPN_TAG_DEV_TYPE, device_type); - } - - args_write_line (f, - NMV_OVPN_TAG_PROTO, - nm_streq0 (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_PROTO_TCP), "yes") - ? "tcp" : "udp"); - - args_write_line_setting_value_int (f, NMV_OVPN_TAG_PORT, s_vpn, NM_OPENVPN_KEY_PORT); - - args_write_line_setting_value_int (f, NMV_OVPN_TAG_PING, s_vpn, NM_OPENVPN_KEY_PING); - - args_write_line_setting_value_int (f, NMV_OVPN_TAG_PING_EXIT, s_vpn, NM_OPENVPN_KEY_PING_EXIT); - - args_write_line_setting_value_int (f, NMV_OVPN_TAG_PING_RESTART, s_vpn, NM_OPENVPN_KEY_PING_RESTART); - - local_ip = _arg_is_set (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_LOCAL_IP)); - remote_ip = _arg_is_set (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_REMOTE_IP)); - if (local_ip && remote_ip) - args_write_line (f, NMV_OVPN_TAG_IFCONFIG, local_ip, remote_ip); - - if (NM_IN_STRSET (connection_type, - NM_OPENVPN_CONTYPE_TLS, - NM_OPENVPN_CONTYPE_PASSWORD_TLS)) { - const char *x509_name, *key; - - args_write_line_setting_value (f, NMV_OVPN_TAG_REMOTE_CERT_TLS, s_vpn, NM_OPENVPN_KEY_REMOTE_CERT_TLS); - args_write_line_setting_value (f, NMV_OVPN_TAG_NS_CERT_TYPE, s_vpn, NM_OPENVPN_KEY_NS_CERT_TYPE); - args_write_line_setting_value (f, NMV_OVPN_TAG_TLS_REMOTE, s_vpn, NM_OPENVPN_KEY_TLS_REMOTE); - - x509_name = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_VERIFY_X509_NAME); - if (_arg_is_set (x509_name)) { - const char *name; - gs_free char *type = NULL; - - name = strchr (x509_name, ':'); - if (name) { - type = g_strndup (x509_name, name - x509_name); - name++; - } else - name = x509_name; - - args_write_line (f, NMV_OVPN_TAG_VERIFY_X509_NAME, name, type); - } - - key = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_TA); - if (_arg_is_set (key)) { - gs_free char *s_free = NULL; - args_write_line (f, - NMV_OVPN_TAG_TLS_AUTH, - nm_utils_str_utf8safe_unescape (key, &s_free), - _arg_is_set (nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_TA_DIR))); - } - - key = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_TLS_CRYPT); - if (_arg_is_set (key)) { - gs_free char *s_free = NULL; - args_write_line (f, - NMV_OVPN_TAG_TLS_CRYPT, - nm_utils_str_utf8safe_unescape (key, &s_free)); - } - - } - - proxy_type = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_PROXY_TYPE); - if (_arg_is_set (proxy_type)) { - const char *proxy_server; - const char *proxy_port; - const char *proxy_retry; - const char *proxy_username; - const char *proxy_password; - - proxy_server = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_PROXY_SERVER); - proxy_port = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_PROXY_PORT); - proxy_retry = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_PROXY_RETRY); - proxy_username = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_USERNAME); - proxy_password = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD); - - if (nm_streq (proxy_type, "http") && proxy_server) { - char *authfile, *authcontents, *base, *dirname; - - if (!proxy_port) - proxy_port = "8080"; - - /* If there's a username, need to write an authfile */ - base = g_path_get_basename (path); - dirname = g_path_get_dirname (path); - authfile = g_strdup_printf ("%s/%s-httpauthfile", dirname, base); - g_free (base); - g_free (dirname); - - args_write_line (f, - NMV_OVPN_TAG_HTTP_PROXY, - proxy_server, - proxy_port, - proxy_username ? authfile : NULL); - if (proxy_retry && !strcmp (proxy_retry, "yes")) - args_write_line (f, NMV_OVPN_TAG_HTTP_PROXY_RETRY); - - /* Write out the authfile */ - if (proxy_username) { - authcontents = g_strdup_printf ("%s\n%s\n", - proxy_username, - proxy_password ? proxy_password : ""); - g_file_set_contents (authfile, authcontents, -1, NULL); - g_free (authcontents); - } - g_free (authfile); - } else if (nm_streq (proxy_type, "socks") && proxy_server) { - if (!proxy_port) - proxy_port = "1080"; - args_write_line (f, NMV_OVPN_TAG_SOCKS_PROXY, proxy_server, proxy_port); - if (proxy_retry && !strcmp (proxy_retry, "yes")) - args_write_line (f, NMV_OVPN_TAG_SOCKS_PROXY_RETRY); - } - } - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4) { -#ifdef NM_VPN_OLD - num = nm_setting_ip4_config_get_num_routes (s_ip4); -#else - num = nm_setting_ip_config_get_num_routes (s_ip4); -#endif - for (i = 0; i < num; i++) { - char netmask_str[INET_ADDRSTRLEN] = { 0 }; - const char *next_hop_str, *dest_str; - in_addr_t netmask; - guint prefix; - guint64 metric; - char metric_buf[50]; - -#ifdef NM_VPN_OLD - char next_hop_str_buf[INET_ADDRSTRLEN] = { 0 }; - char dest_str_buf[INET_ADDRSTRLEN] = { 0 }; - in_addr_t dest, next_hop; - NMIP4Route *route = nm_setting_ip4_config_get_route (s_ip4, i); - - dest = nm_ip4_route_get_dest (route); - inet_ntop (AF_INET, (const void *) &dest, dest_str_buf, sizeof (dest_str_buf)); - dest_str = dest_str_buf; - - next_hop = nm_ip4_route_get_next_hop (route); - inet_ntop (AF_INET, (const void *) &next_hop, next_hop_str_buf, sizeof (next_hop_str_buf)); - next_hop_str = next_hop_str_buf; - - prefix = nm_ip4_route_get_prefix (route); - metric = nm_ip4_route_get_metric (route); -#else - NMIPRoute *route = nm_setting_ip_config_get_route (s_ip4, i); - - dest_str = nm_ip_route_get_dest (route); - next_hop_str = nm_ip_route_get_next_hop (route) ? : "0.0.0.0", - prefix = nm_ip_route_get_prefix (route); - metric = nm_ip_route_get_metric (route); -#endif - netmask = nm_utils_ip4_prefix_to_netmask (prefix); - inet_ntop (AF_INET, (const void *) &netmask, netmask_str, sizeof (netmask_str)); - - args_write_line (f, - NMV_OVPN_TAG_ROUTE, - dest_str, - netmask_str, - next_hop_str, - metric == -1 ? NULL : nm_sprintf_buf (metric_buf, "%u", (unsigned) metric)); - } - } - - /* Add hard-coded stuff */ - args_write_line (f, NMV_OVPN_TAG_NOBIND); - args_write_line (f, NMV_OVPN_TAG_AUTH_NOCACHE); - args_write_line (f, NMV_OVPN_TAG_SCRIPT_SECURITY, "2"); - args_write_line (f, NMV_OVPN_TAG_PERSIST_KEY); - args_write_line (f, NMV_OVPN_TAG_PERSIST_TUN); - args_write_line (f, NMV_OVPN_TAG_USER, NM_OPENVPN_USER); - args_write_line (f, NMV_OVPN_TAG_GROUP, NM_OPENVPN_GROUP); + allowed_ips = concatenate_strings(ips, ", "); + args_write_line(f, NMV_WG_TAG_ALLOWED_IPS, "=", allowed_ips); + g_strfreev (ip_list); + g_array_free(ips, TRUE); return g_steal_pointer (&f); } diff --git a/properties/nm-openvpn-editor.c b/properties/nm-openvpn-editor.c index f35dec7..763c718 100644 --- a/properties/nm-openvpn-editor.c +++ b/properties/nm-openvpn-editor.c @@ -65,30 +65,56 @@ typedef struct { #define COL_AUTH_PAGE 1 #define COL_AUTH_TYPE 2 +static gboolean +is_empty(const char *str) +{ + gboolean empty = FALSE; + gchar *tmp = g_strdup(str); + tmp = g_strstrip(tmp); + + if(!tmp || !tmp[0]){ + empty = TRUE; + } + + g_free(tmp); + return empty; +} + static gboolean check_interface_ip4_entry(const char *str) { - gs_free char *str_clone = NULL; - char *str_iter; - const char *tok; - int count = 0; + return is_ip4((char *)str); +} - if(!str || !str[0]) { - return FALSE; +static gboolean +check_interface_ip6_entry(const char *str) +{ + return is_ip6((char *)str); +} + +static gboolean +check_interface_dns_entry(const char *str) +{ + if(is_empty(str)){ + return TRUE; + } + else if(is_ip4(str)){ + return TRUE; + } + else if(is_ip6(str)){ + return TRUE; } - str_clone = g_strdup(str); - str_iter = str_clone; - while((tok = strsep(&str_iter, "."))){ - count ++; - // each number in an IP4 must be: 0 <= X <= 255 - if(!g_ascii_string_to_unsigned(tok, 10, 0, 255, NULL, NULL)){ - return FALSE; - } - } + return FALSE; +} - // an IP4 consists of 4 segments - if(count != 4){ +static gboolean +check_interface_mtu_entry(const char *str) +{ + if(is_empty(str)){ + return TRUE; + } + else if(!g_ascii_string_to_unsigned(str, 10, 0, 1500, NULL, NULL)){ return FALSE; } @@ -98,11 +124,7 @@ check_interface_ip4_entry(const char *str) static gboolean check_interface_private_key(const char *str) { - gs_free char *str_clone = NULL; - str_clone = g_strdup(str); - str_clone = g_strstrip(str_clone); - - if(!g_strcmp0("", str_clone)){ + if(is_empty(str)){ return FALSE; } @@ -113,10 +135,7 @@ check_interface_private_key(const char *str) static gboolean check_interface_listen_port(const char *str) { - gs_free char *str_clone = NULL; - str_clone = g_strdup(str); - - if(!g_ascii_string_to_unsigned(str_clone, 10, 0, 65535, NULL, NULL)){ + if(!g_ascii_string_to_unsigned(str, 10, 0, 65535, NULL, NULL)){ return FALSE; } @@ -124,58 +143,54 @@ check_interface_listen_port(const char *str) } static gboolean -check_peer_public_key(const char *str) -{ - // TODO +check_peer_public_key(const char *str){ return check_interface_private_key(str); } static gboolean check_peer_allowed_ips(const char *str) { - // TODO - return check_interface_ip4_entry(str); + gchar **ips; + int idx = 0; + gboolean success = TRUE; + + ips = g_strsplit_set(str, ", \t", 0); + + while(ips && ips[idx]){ + + if(is_empty(ips[idx])){ + idx++; + continue; + } + + // there should not be any trailing commas, etc. anymore + // -> if any of the items is not a valid IPv4 or IPv6 address: error! + if(!is_ip4(ips[idx]) && !is_ip6(ips[idx])){ + success = FALSE; + break; + } + idx++; + } + + g_strfreev(ips); + return success; } static gboolean check_peer_endpoint(const char *str) { - // TODO - return check_interface_ip4_entry(str); -} - -static gboolean -check_gateway_entry (const char *str) -{ - gs_free char *str_clone = NULL; - char *str_iter; - const char *tok; - gboolean success = FALSE; - - if (!str || !str[0]) - return FALSE; - - str_clone = g_strdup (str); - str_iter = str_clone; - while ((tok = strsep (&str_iter, " \t,"))) { - if ( tok[0] - && (nmovpn_remote_parse (tok, - NULL, - NULL, - NULL, - NULL, - NULL) != -1)) - return FALSE; - success = TRUE; - } - return success; + return is_ip4((char *)str) || is_ip6((char *)str); } typedef gboolean (*CheckFunc)(const char *str); // helper function to reduce boilerplate code in 'check_validity()' static gboolean -check (OpenvpnEditorPrivate *priv, char *widget_name, CheckFunc chk, GError **error) +check (OpenvpnEditorPrivate *priv, + char *widget_name, + CheckFunc chk, const char *key, + gboolean set_error, + GError **error) { const char *str; GtkWidget *widget; @@ -186,11 +201,11 @@ check (OpenvpnEditorPrivate *priv, char *widget_name, CheckFunc chk, GError **er else { gtk_style_context_add_class (gtk_widget_get_style_context (widget), "error"); // only set the error if it's NULL - if(error == NULL){ + if(error == NULL && set_error){ g_set_error (error, NMV_EDITOR_PLUGIN_ERROR, NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY, - NM_WG_KEY_ADDR_IP4); + key); } return FALSE; } @@ -198,6 +213,28 @@ check (OpenvpnEditorPrivate *priv, char *widget_name, CheckFunc chk, GError **er return TRUE; } +static void +set_error_class(OpenvpnEditorPrivate *priv, char *widget_name, gboolean error) +{ + GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, widget_name)); + if(error){ + gtk_style_context_add_class (gtk_widget_get_style_context (widget), "error"); + } + else{ + gtk_style_context_remove_class (gtk_widget_get_style_context (widget), "error"); + } +} + +static gboolean +is_filled_out(OpenvpnEditorPrivate *priv, char *widget_name) +{ + const char *str; + GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, widget_name)); + str = gtk_entry_get_text(GTK_ENTRY (widget)); + + return !is_empty(str); +} + static gboolean check_validity (OpenvpnEditor *self, GError **error) { @@ -206,27 +243,73 @@ check_validity (OpenvpnEditor *self, GError **error) GtkTreeModel *model; GtkTreeIter iter; const char *contype = NULL; - gboolean success; + gboolean success = TRUE; + gboolean ip4_ok = TRUE; + gboolean ip6_ok = TRUE; // check the various input fields for errors - if(!check(priv, "interface_ip4_entry", check_interface_ip4_entry, error)){ + if(!check(priv, "interface_ip4_entry", check_interface_ip4_entry, NM_WG_KEY_ADDR_IP4, FALSE, error)){ + ip4_ok = FALSE; + } + if(!check(priv, "interface_ip6_entry", check_interface_ip6_entry, NM_WG_KEY_ADDR_IP6, FALSE, error)){ + ip6_ok = FALSE; + } + if(!check(priv, "interface_private_key_entry", check_interface_private_key, NM_WG_KEY_PRIVATE_KEY, TRUE, error)){ success = FALSE; } - if(!check(priv, "interface_private_key_entry", check_interface_private_key, error)){ + if(!check(priv, "interface_port_entry", check_interface_listen_port, NM_WG_KEY_LISTEN_PORT, TRUE, error)){ success = FALSE; } - if(!check(priv, "interface_port_entry", check_interface_listen_port, error)){ + if(!check(priv, "interface_dns_entry", check_interface_dns_entry, NM_WG_KEY_DNS, TRUE, error)){ success = FALSE; } - if(!check(priv, "peer_public_key_entry", check_peer_public_key, error)){ + if(!check(priv, "interface_mtu_entry", check_interface_mtu_entry, NM_WG_KEY_MTU, TRUE, error)){ success = FALSE; } - if(!check(priv, "peer_allowed_ips_entry", check_peer_allowed_ips, error)){ + if(!check(priv, "peer_public_key_entry", check_peer_public_key, NM_WG_KEY_PUBLIC_KEY, TRUE, error)){ success = FALSE; } - if(!check(priv, "peer_endpoint_entry", check_peer_endpoint, error)){ + if(!check(priv, "peer_allowed_ips_entry", check_peer_allowed_ips, NM_WG_KEY_ALLOWED_IPS, TRUE, error)){ success = FALSE; } + if(!check(priv, "peer_endpoint_entry", check_peer_endpoint, NM_WG_KEY_ENDPOINT, TRUE, error)){ + success = FALSE; + } + // pre-up, post-up, pre-down, post-down are scripts and don't get validated + + if(ip4_ok && ip6_ok){ + set_error_class(priv, "interface_ip4_entry", FALSE); + set_error_class(priv, "interface_ip6_entry", FALSE); + // this should be fine, actually + } + else if(ip4_ok){ + // IP6 is filled out but not ok + if(is_filled_out(priv, "interface_ip6_entry")){ + success = FALSE; + g_set_error (error, + NMV_EDITOR_PLUGIN_ERROR, + NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY, + NM_WG_KEY_ADDR_IP6); + } + else{ + set_error_class(priv, "interface_ip4_entry", FALSE); + set_error_class(priv, "interface_ip6_entry", FALSE); + } + } + else if(ip6_ok){ + // IP4 is filled out but not ok + if(is_filled_out(priv, "interface_ip4_entry")){ + success = FALSE; + g_set_error (error, + NMV_EDITOR_PLUGIN_ERROR, + NMV_EDITOR_PLUGIN_ERROR_INVALID_PROPERTY, + NM_WG_KEY_ADDR_IP4); + } + else{ + set_error_class(priv, "interface_ip4_entry", FALSE); + set_error_class(priv, "interface_ip6_entry", FALSE); + } + } /* widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "auth_combo")); @@ -367,11 +450,41 @@ init_editor_plugin (OpenvpnEditor *self, NMConnection *connection, GError **erro } g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + // Local IPv6 address + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_ip6_entry")); + g_return_val_if_fail (widget != NULL, FALSE); + if (s_vpn) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_ADDR_IP6); + if (value) + gtk_entry_set_text (GTK_ENTRY (widget), value); + } + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + + // DNS + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_dns_entry")); + g_return_val_if_fail (widget != NULL, FALSE); + if (s_vpn) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_DNS); + if (value) + gtk_entry_set_text (GTK_ENTRY (widget), value); + } + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + + // Interface Private Key + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_mtu_entry")); + g_return_val_if_fail (widget != NULL, FALSE); + if (s_vpn) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_MTU); + if (value) + gtk_entry_set_text (GTK_ENTRY (widget), value); + } + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + // Interface Private Key widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_private_key_entry")); g_return_val_if_fail (widget != NULL, FALSE); if (s_vpn) { - value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_ADDR_IP4); + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_PRIVATE_KEY); if (value) gtk_entry_set_text (GTK_ENTRY (widget), value); } @@ -381,7 +494,57 @@ init_editor_plugin (OpenvpnEditor *self, NMConnection *connection, GError **erro widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_port_entry")); g_return_val_if_fail (widget != NULL, FALSE); if (s_vpn) { - value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_ADDR_IP4); + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_LISTEN_PORT); + if (value) + gtk_entry_set_text (GTK_ENTRY (widget), value); + } + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + + // Interface Pre Up + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_pre_up_entry")); + g_return_val_if_fail (widget != NULL, FALSE); + if (s_vpn) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_PRE_UP); + if (value) + gtk_entry_set_text (GTK_ENTRY (widget), value); + } + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + + // Interface Post Up + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_post_up_entry")); + g_return_val_if_fail (widget != NULL, FALSE); + if (s_vpn) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_POST_UP); + if (value) + gtk_entry_set_text (GTK_ENTRY (widget), value); + } + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + + // Interface Pre Down + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_pre_down_entry")); + g_return_val_if_fail (widget != NULL, FALSE); + if (s_vpn) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_PRE_DOWN); + if (value) + gtk_entry_set_text (GTK_ENTRY (widget), value); + } + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + + // Interface Post Down + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_post_down_entry")); + g_return_val_if_fail (widget != NULL, FALSE); + if (s_vpn) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_POST_DOWN); + if (value) + gtk_entry_set_text (GTK_ENTRY (widget), value); + } + g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self); + + // Interface Preshared Key + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_psk_entry")); + g_return_val_if_fail (widget != NULL, FALSE); + if (s_vpn) { + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_PRESHARED_KEY); if (value) gtk_entry_set_text (GTK_ENTRY (widget), value); } @@ -392,7 +555,7 @@ init_editor_plugin (OpenvpnEditor *self, NMConnection *connection, GError **erro widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "peer_public_key_entry")); g_return_val_if_fail (widget != NULL, FALSE); if (s_vpn) { - value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_ADDR_IP4); + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_PUBLIC_KEY); if (value) gtk_entry_set_text (GTK_ENTRY (widget), value); } @@ -402,7 +565,7 @@ init_editor_plugin (OpenvpnEditor *self, NMConnection *connection, GError **erro widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "peer_allowed_ips_entry")); g_return_val_if_fail (widget != NULL, FALSE); if (s_vpn) { - value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_ADDR_IP4); + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_ALLOWED_IPS); if (value) gtk_entry_set_text (GTK_ENTRY (widget), value); } @@ -412,7 +575,7 @@ init_editor_plugin (OpenvpnEditor *self, NMConnection *connection, GError **erro widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "peer_endpoint_entry")); g_return_val_if_fail (widget != NULL, FALSE); if (s_vpn) { - value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_ADDR_IP4); + value = nm_setting_vpn_get_data_item (s_vpn, NM_WG_KEY_ENDPOINT); if (value) gtk_entry_set_text (GTK_ENTRY (widget), value); } @@ -576,18 +739,66 @@ update_connection (NMVpnEditor *iface, if (str && str[0]) nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_ADDR_IP4, str); + // local ip6 + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_ip6_entry")); + str = gtk_entry_get_text (GTK_ENTRY (widget)); + if (str && str[0]) + nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_ADDR_IP6, str); + // private key widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_private_key_entry")); str = gtk_entry_get_text (GTK_ENTRY (widget)); if (str && str[0]) nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_PRIVATE_KEY, str); + // dns + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_dns_entry")); + str = gtk_entry_get_text (GTK_ENTRY (widget)); + if (str && str[0]) + nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_DNS, str); + + // mtu + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_mtu_entry")); + str = gtk_entry_get_text (GTK_ENTRY (widget)); + if (str && str[0]) + nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_MTU, str); + // listen port widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_port_entry")); str = gtk_entry_get_text (GTK_ENTRY (widget)); if (str && str[0]) nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_LISTEN_PORT, str); + // pre up script + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_pre_up_entry")); + str = gtk_entry_get_text (GTK_ENTRY (widget)); + if (str && str[0]) + nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_PRE_UP, str); + + // post up script + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_post_up_entry")); + str = gtk_entry_get_text (GTK_ENTRY (widget)); + if (str && str[0]) + nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_POST_UP, str); + + // pre up script + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_pre_down_entry")); + str = gtk_entry_get_text (GTK_ENTRY (widget)); + if (str && str[0]) + nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_PRE_DOWN, str); + + // post down script + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_post_down_entry")); + str = gtk_entry_get_text (GTK_ENTRY (widget)); + if (str && str[0]) + nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_POST_DOWN, str); + + // preshared key + widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "interface_psk_entry")); + str = gtk_entry_get_text (GTK_ENTRY (widget)); + if (str && str[0]) + nm_setting_vpn_add_data_item (s_vpn, NM_WG_KEY_PRESHARED_KEY, str); + // peer public key widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "peer_public_key_entry")); str = gtk_entry_get_text (GTK_ENTRY (widget)); diff --git a/shared/utils.c b/shared/utils.c index aa2565e..34af0c5 100644 --- a/shared/utils.c +++ b/shared/utils.c @@ -248,3 +248,199 @@ out_fail: } /*****************************************************************************/ + +// check if the given string looks like an IPv4 address +// that is, four segments of numbers (0-255), separated by dots +// additionally, there may be a port suffix (separated from the address by a colon; 0 - 65535) +// and/or a subnet (separated by the rest by a slash; 0 - 32) +gboolean +is_ip4(char *addr) +{ + int idx = 0; + int dots = 0; + gchar **parts; + gchar **tmp; + gchar **tmp2; + gchar *lastpart; + gboolean success = TRUE; + + if(!addr){ + return FALSE; + } + + while(addr && addr[idx]){ + if(addr[idx] == '.'){ + dots++; + } + idx++; + } + + if(dots != 3){ + return FALSE; + } + + parts = g_strsplit(addr, ".", 0); + + // iterate over the first three parts, which cannot be anything else than numbers + for(idx = 0; idx < 3; idx++){ + if(!g_ascii_string_to_unsigned(parts[idx], 10, 0, 255, NULL, NULL)){ + success = FALSE; + goto ip4end; + } + } + + // if the last part is a number, we're fine + lastpart = parts[3]; + if(g_ascii_string_to_unsigned(lastpart, 10, 0, 255, NULL, NULL)){ + success = TRUE; + goto ip4end; + } + + // might have a subnet suffix after a slash (e.g. 192.168.1.254/24) + // might have a port suffix after a colon (e.g. 192.168.1.254:8080) + if(g_strrstr(lastpart, ":") && g_strrstr(lastpart, "/")){ + tmp = g_strsplit(lastpart, ":", 2); + tmp2 = g_strsplit(tmp[1], "/", 2); + + if(!g_ascii_string_to_unsigned(tmp[0], 10, 0, 255, NULL, NULL)){ + // the last part of the IP + success = FALSE; + } + + if(!g_ascii_string_to_unsigned(tmp2[0], 10, 0, 65535, NULL, NULL)){ + // the port + success = FALSE; + } + + if(!g_ascii_string_to_unsigned(tmp2[1], 10, 0, 32, NULL, NULL)){ + // the subnet portion + success = FALSE; + } + + g_strfreev(tmp); + g_strfreev(tmp2); + } + else if(g_strrstr(lastpart, "/")){ + tmp = g_strsplit(lastpart, "/", 2); + + if(!g_ascii_string_to_unsigned(tmp[0], 10, 0, 255, NULL, NULL)){ + // the last part of the IP + success = FALSE; + } + + if(!g_ascii_string_to_unsigned(tmp[1], 10, 0, 32, NULL, NULL)){ + // the subnet portion + success = FALSE; + } + + g_strfreev(tmp); + } + else if(g_strrstr(lastpart, ":")){ + tmp = g_strsplit(lastpart, ":", 2); + + if(!g_ascii_string_to_unsigned(tmp[0], 10, 0, 255, NULL, NULL)){ + // the last part of the IP + success = FALSE; + } + + if(!g_ascii_string_to_unsigned(tmp[1], 10, 0, 65535, NULL, NULL)){ + // the port + success = FALSE; + } + + g_strfreev(tmp); + } + else{ + // we have neither a port nor a subnet suffix, but it's not a number either + success = FALSE; + } + +ip4end: + g_strfreev(parts); + return success; +} + +// check if the given string looks like an IPv6 address +// that is, several segments of up to 4 hexadecimal digits +// separated by colons, possibly followed by a slash and a subnet (0 - 128) +// +// if there are several zeroes in adjacent segments, +// those segments may be omitted +gboolean +is_ip6(char *addr) +{ + gchar **parts; + gchar **tmp; + gchar *lastpart; + int len = 0; + int i = 0; + int num_empty = 0; + int num_colons = 0; + gboolean success = TRUE; + + if(!addr){ + return FALSE; + } + else if(!g_strrstr(addr, ":")){ + return FALSE; + } + + while(addr && addr[i]){ + if(addr[i] == ':'){ + num_colons++; + } + i++; + } + if(num_colons < 2){ + // an IPv6 has to contain at least two colons + return FALSE; + } + + parts = g_strsplit(addr, ":", 0); + while(parts && parts[len]){ + len++; + } + + num_empty = 0; + for(i = 0; i < (len-1); i++){ + if((i == 0) && (!g_strcmp0("", parts[i]))){ + // the beginning may be empty (e.g. in "::1") + continue; + } + + if(!g_strcmp0("", parts[i]) && (num_empty < 1)){ + // there may be one "skipped" part in the IP6 + num_empty++; + } + else if(!g_ascii_string_to_unsigned(parts[i], 16, 0, 65536, NULL, NULL)){ + // the rest of the parts have to be numerals between 0 and 16^4 in hex + success = FALSE; + goto ip6end; + } + } + + lastpart = parts[len-1]; + if(g_strrstr(lastpart, "/")){ + // we have a subnet portion + tmp = g_strsplit(lastpart, "/", 2); + + if(g_strcmp0("", tmp[0]) && !g_ascii_string_to_unsigned(tmp[0], 16, 0, 65536, NULL, NULL)){ + success = FALSE; + } + else if(!g_ascii_string_to_unsigned(tmp[1], 10, 0, 128, NULL, NULL)){ + success = FALSE; + } + + g_strfreev(tmp); + } + else{ + // there is only a number, or an empty string (e.g. in the case of "::") + if(g_strcmp0("", lastpart) && !g_ascii_string_to_unsigned(lastpart, 16, 0, 65536, NULL, NULL)){ + success = FALSE; + } + } + +ip6end: + g_strfreev(parts); + return success; +} \ No newline at end of file diff --git a/shared/utils.h b/shared/utils.h index 894e9fe..5370087 100644 --- a/shared/utils.h +++ b/shared/utils.h @@ -26,7 +26,11 @@ #define NMV_WG_TAG_PRIVATE_KEY "PrivateKey" #define NMV_WG_TAG_LISTEN_PORT "ListenPort" #define NMV_WG_TAG_ADDRESS "Address" +#define NMV_WG_TAG_DNS "DNS" +#define NMV_WG_TAG_MTU "MTU" +#define NMV_WG_TAG_PRE_UP "PreUp" #define NMV_WG_TAG_POST_UP "PostUp" +#define NMV_WG_TAG_PRE_DOWN "PreDown" #define NMV_WG_TAG_POST_DOWN "PostDown" #define NMV_WG_TAG_PRESHARED_KEY "PresharedKey" #define NMV_WG_TAG_PEER "[Peer]" @@ -92,6 +96,10 @@ gboolean is_pkcs12 (const char *filepath); gboolean is_encrypted (const char *filename); +gboolean is_ip4 (char *addr); + +gboolean is_ip6 (char *addr); + #define NMOVPN_PROTCOL_TYPES \ "udp", \ "udp4", \