From 70fa645211b8de10eae1afdba5a5b42309dfc40e Mon Sep 17 00:00:00 2001 From: Atul Anand Date: Mon, 29 Aug 2016 13:55:41 +0530 Subject: src/proxy.c: modify the proxy_lookup () supporting non-browser schemes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As discussed, the proxy lookup for browser and non browser schemes should be handled in an order as follows: A request for a "browser" protocol would match the following configs order of preference (if they exist): • Matching "Domains", BrowserOnly==TRUE • Matching "Domains", BrowserOnly==FALSE • Domains==NULL, BrowserOnly==TRUE • Domains==NULL, BrowserOnly==FALSE A request for a non-browser protocol would match the following: • Matching "Domains", BrowserOnly==FALSE • Domains==NULL, BrowserOnly==FALSE (except if a config exists with Matching "Domains", BrowserOnly==TRUE, in which case we need to return NULL). Update test cases to use pacrunner_proxy_set_domains() with three arguments. --- src/manager.c | 11 ++++- src/pacrunner.h | 2 +- src/proxy.c | 121 ++++++++++++++++++++++++++++++++++++++++---------- unit/test-pacrunner.c | 6 +-- 4 files changed, 111 insertions(+), 29 deletions(-) diff --git a/src/manager.c b/src/manager.c index 5a8b4fd..fa8a7b4 100644 --- a/src/manager.c +++ b/src/manager.c @@ -142,6 +142,7 @@ static DBusMessage *create_proxy_config(DBusConnection *conn, const char *url = NULL, *script = NULL; char **servers = NULL, **excludes = NULL; char **domains = NULL, **nameservers = NULL; + gboolean browser_only = FALSE; sender = dbus_message_get_sender(msg); @@ -199,13 +200,18 @@ static DBusMessage *create_proxy_config(DBusConnection *conn, nameservers = extract_string_array(&list); } break; + case DBUS_TYPE_BOOLEAN: + if (g_str_equal(key, "BrowserOnly")) + dbus_message_iter_get_basic(&value, + &browser_only); + break; } dbus_message_iter_next(&array); } DBG("sender %s method %s interface %s", sender, method, interface); - DBG("url %s script %p", url, script); + DBG("browser-only %u url %s script %p", browser_only, url, script); if (!method) { reply = g_dbus_create_error(msg, @@ -226,7 +232,8 @@ static DBusMessage *create_proxy_config(DBusConnection *conn, nameservers = NULL; - if (pacrunner_proxy_set_domains(config->proxy, domains) < 0) + if (pacrunner_proxy_set_domains(config->proxy, domains, + browser_only) < 0) pacrunner_error("Failed to set proxy domains"); if (g_str_equal(method, "direct")) { diff --git a/src/pacrunner.h b/src/pacrunner.h index 87c51da..e31d7ef 100644 --- a/src/pacrunner.h +++ b/src/pacrunner.h @@ -64,7 +64,7 @@ const char *pacrunner_proxy_get_interface(struct pacrunner_proxy *proxy); const char *pacrunner_proxy_get_script(struct pacrunner_proxy *proxy); int pacrunner_proxy_set_domains(struct pacrunner_proxy *proxy, - char **domains); + char **domains, gboolean browser_only); int pacrunner_proxy_set_direct(struct pacrunner_proxy *proxy); int pacrunner_proxy_set_manual(struct pacrunner_proxy *proxy, char **servers, char **excludes); diff --git a/src/proxy.c b/src/proxy.c index db49c58..7579887 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -40,6 +40,7 @@ struct pacrunner_proxy { char *script; GList **servers; GList **excludes; + gboolean browser_only; GList *domains; void *jsctx; }; @@ -159,13 +160,37 @@ const char *pacrunner_proxy_get_script(struct pacrunner_proxy *proxy) return proxy->script; } -int pacrunner_proxy_set_domains(struct pacrunner_proxy *proxy, char **domains) +static gboolean check_browser_protocol(const char *url) +{ + static const char *browser_schemes[] = { + "http://", + "https://", + "ftp://", + "nntp://", + "nntps://", + }; + guint i; + + for (i = 0; i < G_N_ELEMENTS(browser_schemes); i++) { + if (strncmp(browser_schemes[i], url, + strlen(browser_schemes[i])) == 0) + return TRUE; + } + + return FALSE; +} + +int pacrunner_proxy_set_domains(struct pacrunner_proxy *proxy, char **domains, + gboolean browser_only) { int len; char *slash, **domain; char ip[INET6_ADDRSTRLEN + 1]; - DBG("proxy %p domains %p", proxy, domains); + DBG("proxy %p domains %p browser-only %u", proxy, + domains, browser_only); + + proxy->browser_only = browser_only; if (!proxy) return -EINVAL; @@ -476,13 +501,34 @@ static int compare_host_in_domain(const char *host, struct proxy_domain *match) return -1; } +/** + * A request for a "browser" protocol would match the following configs + * order of preference (if they exist): + * • Matching "Domains", BrowserOnly==TRUE + * • Matching "Domains", BrowserOnly==FALSE + * • Domains==NULL, BrowserOnly==TRUE + * • Domains==NULL, BrowserOnly==FALSE + * + * A request for a non-browser protocol would match the following : + * • Matching "Domains", BrowserOnly==FALSE + * • Domains==NULL, BrowserOnly==FALSE (except if a config exists with + * Matching "Domains", BrowserOnly==TRUE, in which case we need to + * return NULL). + **/ char *pacrunner_proxy_lookup(const char *url, const char *host) { GList *l, *list; + int protocol = 0; struct in_addr ip4_addr; struct in6_addr ip6_addr; - struct pacrunner_proxy *selected_proxy = NULL, *default_proxy = NULL; - int protocol = 0; + gboolean request_is_browser; + struct pacrunner_proxy *proxy = NULL; + + /* Four classes of 'match' */ + struct pacrunner_proxy *alldomains_browseronly = NULL; + struct pacrunner_proxy *alldomains_allprotos = NULL; + struct pacrunner_proxy *domainmatch_browseronly = NULL; + struct pacrunner_proxy *domainmatch_allprotos = NULL; DBG("url %s host %s", url, host); @@ -512,12 +558,16 @@ char *pacrunner_proxy_lookup(const char *url, const char *host) } } + request_is_browser = check_browser_protocol(url); + for (list = g_list_first(proxy_list); list; list = g_list_next(list)) { - struct pacrunner_proxy *proxy = list->data; + proxy = list->data; if (!proxy->domains) { - if (!default_proxy) - default_proxy = proxy; + if (proxy->browser_only && !alldomains_browseronly) + alldomains_browseronly = proxy; + else if (!proxy->browser_only && !alldomains_allprotos) + alldomains_allprotos = proxy; continue; } @@ -531,54 +581,79 @@ char *pacrunner_proxy_lookup(const char *url, const char *host) case 4: if (compare_legacy_ip_in_net(&ip4_addr, data) == 0) { - selected_proxy = proxy; DBG("match proxy %p Legacy IP range %s", proxy, data->domain); - goto found; + goto matches; } break; case 6: if (compare_ipv6_in_net(&ip6_addr, data) == 0) { - selected_proxy = proxy; DBG("match proxy %p IPv6 range %s", proxy, data->domain); - goto found; + goto matches; } break; default: if (compare_host_in_domain(host, data) == 0) { - selected_proxy = proxy; DBG("match proxy %p DNS domain %s", proxy, data->domain); - goto found; + goto matches; } break; } } + /* No match */ + continue; + + matches: + if (proxy->browser_only == request_is_browser) { + goto found; + } else if (proxy->browser_only) { + /* A non-browser request will return DIRECT instead of + * falling back to alldomains_* if this exists. + */ + if (!domainmatch_browseronly) + domainmatch_browseronly = proxy; + } else { + /* We might fall back to this, for a browser request */ + if (!domainmatch_allprotos) + domainmatch_allprotos = proxy; + } } - if (!selected_proxy) { - DBG("default proxy %p", default_proxy); - selected_proxy = default_proxy; + if (request_is_browser) { + /* We'll have bailed out immediately if we found a domain match + * with proxy->browser_only==TRUE. Fallbacks in order of prefe- + * rence. + */ + proxy = domainmatch_allprotos; + if (!proxy) + proxy = alldomains_browseronly; + if (!proxy) + proxy = alldomains_allprotos; + } else { + if (!domainmatch_browseronly) + proxy = alldomains_allprotos; + else + proxy = NULL; } -found: + found: pthread_mutex_unlock(&proxy_mutex); - if (!selected_proxy) + if (!proxy) return NULL; - switch (selected_proxy->method) { + switch (proxy->method) { case PACRUNNER_PROXY_METHOD_UNKNOWN: case PACRUNNER_PROXY_METHOD_DIRECT: break; case PACRUNNER_PROXY_METHOD_MANUAL: - return __pacrunner_manual_execute(url, host, - selected_proxy->servers, - selected_proxy->excludes); + return __pacrunner_manual_execute(url, host, proxy->servers, + proxy->excludes); case PACRUNNER_PROXY_METHOD_AUTO: - return __pacrunner_js_execute(selected_proxy, url, host); + return __pacrunner_js_execute(proxy, url, host); } return NULL; diff --git a/unit/test-pacrunner.c b/unit/test-pacrunner.c index 0c4ac69..e485c61 100644 --- a/unit/test-pacrunner.c +++ b/unit/test-pacrunner.c @@ -363,7 +363,7 @@ static void test_proxy_domain(void) { int val = 0; - if (pacrunner_proxy_set_domains(proxy, test_suite->domains) != 0) + if (pacrunner_proxy_set_domains(proxy, test_suite->domains, FALSE) != 0) val = -1; proxy2 = pacrunner_proxy_create("eth1"); @@ -381,7 +381,7 @@ static void test_proxy_domain(void) if (pacrunner_proxy_set_manual(proxy2, servers, NULL) != 0) val = -1; - if (pacrunner_proxy_set_domains(proxy2, domains) != 0) + if (pacrunner_proxy_set_domains(proxy2, domains, FALSE) != 0) val = -1; } @@ -400,7 +400,7 @@ static void test_proxy_domain(void) if (pacrunner_proxy_set_manual(proxy3, servers, NULL) != 0) val = -1; - if (pacrunner_proxy_set_domains(proxy3, domains) != 0) + if (pacrunner_proxy_set_domains(proxy3, domains, FALSE) != 0) val = -1; } -- cgit 1.2.3-korg