From 595451331b1e91907d987ca4b0b2ebb7e8f538bd Mon Sep 17 00:00:00 2001 From: Jan-Michael Brummer Date: Tue, 21 Mar 2023 02:50:57 -0400 Subject: Add common ignore handling (#99) Co-authored-by: Jan-Michael Brummer --- src/backend/plugins/config-env/config-env.c | 3 +- src/backend/plugins/config-gnome/config-gnome.c | 3 + src/backend/plugins/config-kde/config-kde.c | 14 ++- src/backend/plugins/config-osx/config-osx.c | 2 +- .../plugins/config-sysconfig/config-sysconfig.c | 8 +- .../plugins/config-windows/config-windows.c | 4 +- src/backend/px-manager.c | 109 +++++++++++++++++++++ src/backend/px-manager.h | 2 + tests/config-gnome-test.c | 1 + tests/px-manager-test.c | 90 +++++++++++++++++ 10 files changed, 225 insertions(+), 11 deletions(-) diff --git a/src/backend/plugins/config-env/config-env.c b/src/backend/plugins/config-env/config-env.c index 397fdd9..d7f5a73 100644 --- a/src/backend/plugins/config-env/config-env.c +++ b/src/backend/plugins/config-env/config-env.c @@ -143,9 +143,8 @@ px_config_env_get_config (PxConfig *config, const char *proxy = NULL; const char *scheme = g_uri_get_scheme (uri); - if (self->no_proxy && (g_strv_contains ((const char * const *)self->no_proxy, g_uri_get_host (uri)) || g_strv_contains ((const char * const *)self->no_proxy, "*"))) { + if (px_manager_is_ignore (uri, self->no_proxy)) return; - } if (g_strcmp0 (scheme, "ftp") == 0) proxy = self->ftp_proxy; diff --git a/src/backend/plugins/config-gnome/config-gnome.c b/src/backend/plugins/config-gnome/config-gnome.c index a41f54d..1d4f182 100644 --- a/src/backend/plugins/config-gnome/config-gnome.c +++ b/src/backend/plugins/config-gnome/config-gnome.c @@ -170,6 +170,9 @@ px_config_gnome_get_config (PxConfig *config, g_autofree char *proxy = NULL; GnomeProxyMode mode; + if (px_manager_is_ignore (uri, g_settings_get_strv (self->proxy_settings, "ignore-hosts"))) + return; + mode = g_settings_get_enum (self->proxy_settings, "mode"); if (mode == GNOME_PROXY_MODE_AUTO) { char *autoconfig_url = g_settings_get_string (self->proxy_settings, "autoconfig-url"); diff --git a/src/backend/plugins/config-kde/config-kde.c b/src/backend/plugins/config-kde/config-kde.c index f30a130..fba7ed3 100644 --- a/src/backend/plugins/config-kde/config-kde.c +++ b/src/backend/plugins/config-kde/config-kde.c @@ -44,7 +44,7 @@ struct _PxConfigKde { gboolean available; GFileMonitor *monitor; - char *no_proxy; + GStrv no_proxy; char *http_proxy; char *https_proxy; char *ftp_proxy; @@ -142,7 +142,8 @@ px_config_kde_set_config_file (PxConfigKde *self, } else if (strcmp (kv[0], "socksProxy") == 0) { self->socks_proxy = g_strdup (value->str); } else if (strcmp (kv[0], "NoProxyFor") == 0) { - self->no_proxy = g_strdup (value->str); + g_autofree char *no_proxy_for = g_strdup (value->str); + self->no_proxy = g_strsplit (no_proxy_for, ",", -1); } else if (strcmp (kv[0], "Proxy Config Script") == 0) { self->pac_script = g_strdup (value->str); } else if (strcmp (kv[0], "ProxyType") == 0) { @@ -166,7 +167,14 @@ px_config_kde_dispose (GObject *object) { PxConfigKde *self = PX_CONFIG_KDE (object); + g_clear_pointer (&self->config_file, g_free); g_clear_object (&self->monitor); + g_clear_pointer (&self->no_proxy, g_strfreev); + g_clear_pointer (&self->http_proxy, g_free); + g_clear_pointer (&self->https_proxy, g_free); + g_clear_pointer (&self->ftp_proxy, g_free); + g_clear_pointer (&self->socks_proxy, g_free); + g_clear_pointer (&self->pac_script, g_free); G_OBJECT_CLASS (px_config_kde_parent_class)->dispose (object); } @@ -241,7 +249,7 @@ px_config_kde_get_config (PxConfig *config, if (!self->proxy_type) return; - if (self->no_proxy && strstr (self->no_proxy, g_uri_get_host (uri))) + if (px_manager_is_ignore (uri, self->no_proxy)) return; switch (self->proxy_type) { diff --git a/src/backend/plugins/config-osx/config-osx.c b/src/backend/plugins/config-osx/config-osx.c index f733c93..68ce0f2 100644 --- a/src/backend/plugins/config-osx/config-osx.c +++ b/src/backend/plugins/config-osx/config-osx.c @@ -254,7 +254,7 @@ px_config_osx_get_config (PxConfig *self, ignore_list = get_ignore_list (proxies); - if (ignore_list && g_strv_contains ((const char * const *)ignore_list, g_uri_get_host (uri))) + if (px_manager_is_ignore (uri, ignore_list)) return; if (getbool (proxies, "ProxyAutoDiscoveryEnable")) { diff --git a/src/backend/plugins/config-sysconfig/config-sysconfig.c b/src/backend/plugins/config-sysconfig/config-sysconfig.c index 1f90a44..1adc1e8 100644 --- a/src/backend/plugins/config-sysconfig/config-sysconfig.c +++ b/src/backend/plugins/config-sysconfig/config-sysconfig.c @@ -37,7 +37,7 @@ struct _PxConfigSysConfig { char *https_proxy; char *http_proxy; char *ftp_proxy; - char *no_proxy; + GStrv no_proxy; }; static void px_config_iface_init (PxConfigInterface *iface); @@ -133,7 +133,8 @@ px_config_sysconfig_set_config_file (PxConfigSysConfig *self, } else if (strcmp (kv[0], "FTP_PROXY") == 0) { self->ftp_proxy = g_strdup (value->str); } else if (strcmp (kv[0], "NO_PROXY") == 0) { - self->no_proxy = g_strdup (value->str); + g_autofree char *tmp = g_strdup (value->str); + self->no_proxy = g_strsplit (tmp, ",", -1); } } } while (line); @@ -190,6 +191,7 @@ px_config_sysconfig_dispose (GObject *object) PxConfigSysConfig *self = PX_CONFIG_SYSCONFIG (object); g_clear_object (&self->monitor); + g_clear_pointer (&self->no_proxy, g_strfreev); G_OBJECT_CLASS (px_config_sysconfig_parent_class)->dispose (object); } @@ -226,7 +228,7 @@ px_config_sysconfig_get_config (PxConfig *config, if (!self->proxy_enabled) return; - if (self->no_proxy && strstr (self->no_proxy, g_uri_get_host (uri))) + if (px_manager_is_ignore (uri, self->no_proxy)) return; if (g_strcmp0 (scheme, "ftp") == 0) { diff --git a/src/backend/plugins/config-windows/config-windows.c b/src/backend/plugins/config-windows/config-windows.c index b623c2d..73a889a 100644 --- a/src/backend/plugins/config-windows/config-windows.c +++ b/src/backend/plugins/config-windows/config-windows.c @@ -159,9 +159,9 @@ px_config_windows_get_config (PxConfig *self, guint32 enabled = 0; if (get_registry (W32REG_BASEKEY, "ProxyOverride", &tmp, NULL, NULL)) { - const char *host = g_uri_get_host (uri); + g_auto (GStrv) no_proxy = g_strsplit (tmp, ",", -1); - if (g_strcmp0 (tmp, "") == 0 && g_strcmp0 (host, "127.0.0.1") == 0) + if (px_manager_is_ignore (uri, no_proxy)) return; } diff --git a/src/backend/px-manager.c b/src/backend/px-manager.c index 69d94fd..ef81eb1 100644 --- a/src/backend/px-manager.c +++ b/src/backend/px-manager.c @@ -594,3 +594,112 @@ px_strv_builder_add_proxy (GStrvBuilder *builder, g_strv_builder_add (builder, value); } + +static gboolean +ignore_domain (GUri *uri, + char *ignore) +{ + g_auto (GStrv) ignore_split = g_strsplit (ignore, ":", -1); + const char *host = g_uri_get_host (uri); + char *ig_host; + int ig_port = -1; + int port = g_uri_get_port (uri); + + /* Get our ignore pattern's hostname and port */ + ig_host = ignore_split[0]; + if (g_strv_length (ignore_split) == 2) + ig_port = atoi (ignore_split[1]); + + /* Hostname match (domain.com or domain.com:80) */ + if (g_strcmp0 (host, ig_host) == 0) + return (ig_port == -1 || port == ig_port); + + /* Endswith (.domain.com or .domain.com:80) */ + if (ig_host[0] == '.' && g_str_has_suffix (host, ig_host)) + return (ig_port == -1 || port == ig_port); + + /* Glob (*.domain.com or *.domain.com:80) */ + if (ig_host[0] == '*' && g_str_has_suffix (host, ig_host + 1)) + return (ig_port == -1 || port == ig_port); + + /* No match was found */ + return FALSE; +} + +static gboolean +ignore_hostname (GUri *uri, + char *ignore) +{ + const char *host = g_uri_get_host (uri); + + g_print ("%s %s\n", ignore, host); + + if (g_strcmp0 (ignore, "") == 0 && strchr (host, ':') == NULL && strchr (host, '.') == NULL) + return TRUE; + + return FALSE; +} + +static gboolean +ignore_ip (GUri *uri, + char *ignore) +{ + GInetAddress *inet_address1; + GInetAddress *inet_address2; + g_auto (GStrv) ignore_split = NULL; + gboolean is_ip1 = g_hostname_is_ip_address (g_uri_get_host (uri)); + gboolean is_ip2 = g_hostname_is_ip_address (ignore); + int port = g_uri_get_port (uri); + int ig_port = -1; + gboolean result; + + /* + * IPv4 + * IPv6 + */ + if (!is_ip1 || !is_ip2) + return FALSE; + + /* + * IPv4/CIDR + * IPv4/IPv4 + * IPv6/CIDR + * IPv6/IPv6 + */ + + /* MISSING */ + + /* + * IPv4:port + * [IPv6]:port + */ + ignore_split = g_strsplit (ignore, ":", -1); + if (g_strv_length (ignore_split) == 2) + ig_port = atoi (ignore_split[1]); + + inet_address1 = g_inet_address_new_from_string (g_uri_get_host (uri)); + inet_address2 = g_inet_address_new_from_string (ignore); + result = g_inet_address_equal (inet_address1, inet_address2); + + return port != -1 ? ((port == ig_port) && result) : result; +} +gboolean +px_manager_is_ignore (GUri *uri, + GStrv ignores) +{ + if (!ignores) + return FALSE; + + for (int idx = 0; idx < g_strv_length (ignores); idx++) { + if (ignore_hostname (uri, ignores[idx])) + return TRUE; + + if (ignore_domain (uri, ignores[idx])) + return TRUE; + + if (ignore_ip (uri, ignores[idx])) + return TRUE; + } + + return FALSE; +} diff --git a/src/backend/px-manager.h b/src/backend/px-manager.h index 2bb816b..558ddba 100644 --- a/src/backend/px-manager.h +++ b/src/backend/px-manager.h @@ -54,4 +54,6 @@ char **px_manager_get_configuration (PxManager *self, void px_strv_builder_add_proxy (GStrvBuilder *builder, const char *value); +gboolean px_manager_is_ignore (GUri *uri, GStrv ignores); + G_END_DECLS diff --git a/tests/config-gnome-test.c b/tests/config-gnome-test.c index fc688bd..71ddb28 100644 --- a/tests/config-gnome-test.c +++ b/tests/config-gnome-test.c @@ -86,6 +86,7 @@ test_config_gnome_manual (Fixture *self, g_auto (GStrv) config = NULL; ConfigGnomeTest test = config_gnome_test_set[idx]; + g_settings_set_strv (self->proxy_settings, "ignore-hosts", NULL); g_settings_set_enum (self->proxy_settings, "mode", test.mode); g_settings_set_string (self->http_proxy_settings, "host", test.proxy); g_settings_set_int (self->http_proxy_settings, "port", test.proxy_port); diff --git a/tests/px-manager-test.c b/tests/px-manager-test.c index 1b1eb06..bfd3112 100644 --- a/tests/px-manager-test.c +++ b/tests/px-manager-test.c @@ -196,6 +196,92 @@ test_get_wpad (Fixture *self, g_main_loop_run (self->loop); } +static void +test_ignore_domain (Fixture *self, + const void *user_data) +{ + g_autoptr (GUri) uri = g_uri_parse("http://10.10.1.12", G_URI_FLAGS_PARSE_RELAXED, NULL); + char **ignore_list = g_malloc0 (sizeof (char *) * 2); + gboolean ret; + + /* Invalid test */ + ignore_list[0] = g_strdup ("10.10.1.13"); + ignore_list[1] = NULL; + + ret = px_manager_is_ignore (uri, ignore_list); + g_assert_false (ret); + + /* Valid test */ + ignore_list[0] = g_strdup ("10.10.1.12"); + ignore_list[1] = NULL; + + ret = px_manager_is_ignore (uri, ignore_list); + g_assert_true (ret); + + g_free (ignore_list[0]); + g_free (ignore_list); +} + +static void +test_ignore_domain_port (Fixture *self, + const void *user_data) +{ + g_autoptr (GUri) uri = g_uri_parse("http://10.10.1.12:22", G_URI_FLAGS_PARSE_RELAXED, NULL); + char **ignore_list = g_malloc0 (sizeof (char *) * 2); + gboolean ret; + + /* Invalid test */ + ignore_list[0] = g_strdup ("10.10.1.13"); + ignore_list[1] = NULL; + + ret = px_manager_is_ignore (uri, ignore_list); + g_free (ignore_list[0]); + g_assert_false (ret); + + /* Invalid test */ + ignore_list[0] = g_strdup ("10.10.1.12:24"); + ignore_list[1] = NULL; + + ret = px_manager_is_ignore (uri, ignore_list); + g_free (ignore_list[0]); + g_assert_false (ret); + + /* Valid test */ + ignore_list[0] = g_strdup ("10.10.1.12:22"); + ignore_list[1] = NULL; + + ret = px_manager_is_ignore (uri, ignore_list); + g_assert_true (ret); + + g_free (ignore_list[0]); + g_free (ignore_list); +} + +static void +test_ignore_hostname (Fixture *self, + const void *user_data) +{ + g_autoptr (GUri) uri = g_uri_parse("http://18.10.1.12", G_URI_FLAGS_PARSE_RELAXED, NULL); + char **ignore_list = g_malloc0 (sizeof (char *) * 2); + gboolean ret; + + /* Invalid test */ + ignore_list[0] = g_strdup (""); + ignore_list[1] = NULL; + + ret = px_manager_is_ignore (uri, ignore_list); + g_assert_false (ret); + g_uri_unref (uri); + + /* Valid test */ + uri = g_uri_parse("http://127.0.0.1", G_URI_FLAGS_PARSE_RELAXED, NULL); + ret = px_manager_is_ignore (uri, ignore_list); + g_assert_false (ret); + + g_free (ignore_list[0]); + g_free (ignore_list); +} + int main (int argc, char **argv) @@ -219,6 +305,10 @@ main (int argc, g_test_add ("/pac/get_proxies_pac", Fixture, "px-manager-pac", fixture_setup, test_get_proxies_pac, fixture_teardown); g_test_add ("/pac/wpad", Fixture, "px-manager-wpad", fixture_setup, test_get_wpad, fixture_teardown); + g_test_add ("/ignore/domain", Fixture, "px-manager-ignore", fixture_setup, test_ignore_domain, fixture_teardown); + g_test_add ("/ignore/domain_port", Fixture, "px-manager-ignore", fixture_setup, test_ignore_domain_port, fixture_teardown); + g_test_add ("/ignore/hostname", Fixture, "px-manager-ignore", fixture_setup, test_ignore_hostname, fixture_teardown); + return g_test_run (); } -- cgit v1.2.1