Send connman mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
https://lists.01.org/mailman/listinfo/connman
or, via email, send a message with subject or body 'help' to
[email protected]
You can reach the person managing the list at
[email protected]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of connman digest..."
Today's Topics:
1. Re: [PATCH] [Pacrunner]: Domains are looked up to match host
of URL. (Patrik Flykt)
----------------------------------------------------------------------
Message: 1
Date: Tue, 14 Jun 2016 16:28:44 +0300
From: Patrik Flykt <[email protected]>
To: Atul Anand <[email protected]>, [email protected]
Subject: Re: [PATCH] [Pacrunner]: Domains are looked up to match host
of URL.
Message-ID: <[email protected]>
Content-Type: text/plain; charset="UTF-8"
Hi,
Please split this patch into three, documentation, implementation and
testing.
On Mon, 2016-06-13 at 16:48 +0530, Atul Anand wrote:
> Pacrunner now scan stored domains to match the host of URL.
> In this way the most appropriate proxy config is selected
> to answer the proxy query.
> ---
> ?doc/manager-api.txt????????????|???3 +-
> ?src/manager.c??????????????????|???7 +-
> ?src/pacrunner.h????????????????|???2 +
> ?src/proxy.c????????????????????| 207
> +++++++++++++++++++++++++++++++++++++++--
> ?unit/suite/manual_basic.test???|???2 +
> ?unit/suite/manual_exclude.test |???2 +
> ?unit/suite/pac_basic.test??????|???2 +
> ?unit/suite/pac_direct.test?????|???2 +
> ?unit/suite/proxy_domain.test???|??37 ++++++++
> ?unit/suite/stub.test???????????|???3 +
> ?unit/test-pacrunner.c??????????|??86 ++++++++++++++++-
> ?11 files changed, 336 insertions(+), 17 deletions(-)
> ?create mode 100644 unit/suite/proxy_domain.test
>
> diff --git a/doc/manager-api.txt b/doc/manager-api.txt
> index ab2f6b9..622fffa 100644
> --- a/doc/manager-api.txt
> +++ b/doc/manager-api.txt
> @@ -62,7 +62,8 @@ Methods object CreateProxyConfiguration(dict
> settings)
> ?
> ? array{string} Domains [optional]
> ?
> - Domain names for which the URL is valid.
> + Domain names and IP ranges for which this proxy
> + configuration shall be valid.
> ?
> ? array{string} Nameservers [optional]
The above should be the first patch updating documentation. IP range
formats should also be documented so that one does not have to guess
what the string should look like.
?
> diff --git a/src/manager.c b/src/manager.c
> index 1676466..5a8b4fd 100644
> --- a/src/manager.c
> +++ b/src/manager.c
> @@ -35,7 +35,6 @@ struct proxy_config {
> ? DBusConnection *conn;
> ? guint watch;
> ?
> - char **domains;
> ? char **nameservers;
> ?
> ? struct pacrunner_proxy *proxy;
> @@ -58,7 +57,6 @@ static void destroy_config(gpointer data)
> ? if (config->watch > 0)
> ? g_dbus_remove_watch(config->conn, config->watch);
> ?
> - g_strfreev(config->domains);
> ? g_strfreev(config->nameservers);
> ?
> ? g_free(config->sender);
> @@ -224,12 +222,13 @@ static DBusMessage *create_proxy_config(DBusConnection
> *conn,
> ? goto done;
> ? }
> ?
> - config->domains = domains;
> ? config->nameservers = nameservers;
> ?
> - domains = NULL;
> ? nameservers = NULL;
> ?
> + if (pacrunner_proxy_set_domains(config->proxy, domains) < 0)
> + pacrunner_error("Failed to set proxy domains");
> +
> ? if (g_str_equal(method, "direct")) {
> ? if (pacrunner_proxy_set_direct(config->proxy) < 0)
> ? pacrunner_error("Failed to set direct proxy");
> diff --git a/src/pacrunner.h b/src/pacrunner.h
> index 6731d7c..db534cf 100644
> --- a/src/pacrunner.h
> +++ b/src/pacrunner.h
> @@ -63,6 +63,8 @@ void pacrunner_proxy_unref(struct pacrunner_proxy *proxy);
> ?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);
> ?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 8bb03af..2aeae0b 100644
> --- a/src/proxy.c
> +++ b/src/proxy.c
> @@ -23,6 +23,9 @@
> ?#include
> ?#endif
> ?
> +#include
> +#include
> +#include
> ?#include
> ?#include
> ?
> @@ -37,6 +40,17 @@ struct pacrunner_proxy {
> ? char *script;
> ? GList **servers;
> ? GList **excludes;
> + GList *domains;
> +};
> +
> +struct proxy_domain {
> + char *domain;
> + int proto;
> + union {
> + struct in_addr ip4;
> + struct in6_addr ip6;
> + } addr;
> + int mask;
> ?};
> ?
> ?static GList *proxy_list = NULL;
> @@ -77,6 +91,14 @@ struct pacrunner_proxy *pacrunner_proxy_ref(struct
> pacrunner_proxy *proxy)
> ? return proxy;
> ?}
> ?
> +static void proxy_domain_destroy(struct proxy_domain *domain)
> +{
> + g_return_if_fail(domain != NULL);
> +
> + g_free(domain->domain);
> + g_free(domain);
> +}
> +
> ?static void reset_proxy(struct pacrunner_proxy *proxy)
> ?{
> ? DBG("proxy %p", proxy);
> @@ -92,6 +114,12 @@ static void reset_proxy(struct pacrunner_proxy *proxy)
> ?
> ? __pacrunner_manual_destroy_excludes(proxy->excludes);
> ? proxy->excludes = NULL;
> +
> + if (proxy->domains) {
> + g_list_free_full(proxy->domains,
> + (GDestroyNotify) proxy_domain_destroy);
Please don't cast here, if needed do necessary casts in
proxy_domain_destroy() instead.
> + }
> + proxy->domains = NULL;
> ?}
> ?
> ?void pacrunner_proxy_unref(struct pacrunner_proxy *proxy)
> @@ -130,6 +158,69 @@ const char *pacrunner_proxy_get_script(struct
> pacrunner_proxy *proxy)
> ? return proxy->script;
> ?}
> ?
> +int pacrunner_proxy_set_domains(struct pacrunner_proxy *proxy, char
> **domains)
> +{
> + int len;
> + char *slash, **domain;
> + char ip[INET6_ADDRSTRLEN + 1];
> +
> + DBG("proxy %p domains %p", proxy, domains);
> +
> + if (!proxy)
> + return -EINVAL;
> +
> + if (!domains)
> + return -EINVAL;
> +
> + for (domain = (char **)domains; *domain; domain++) {
The cast to (char **) does not seem necessary here?
> + struct proxy_domain *data;
> +
> + data = g_malloc0(sizeof(struct proxy_domain));
> + g_return_val_if_fail(data != NULL, -EINVAL);
> +
> + slash = strchr(*domain, '/');
> + if (!slash) {
> + data->domain = g_strdup(*domain);
> + data->proto = 0;
> +
> + proxy->domains = g_list_append(proxy->domains, data);
> + continue;
> + }
> +
> + len = slash - *domain;
> + if (len > INET6_ADDRSTRLEN)
> + return -EINVAL;
> +
> + strncpy(ip, *domain, len);
> + ip[len] = '\0';
> +
> + if (inet_pton(AF_INET, ip, &(data->addr.ip4)) == 1) {
> + data->domain = NULL;
> + data->proto = 4;
> +
> + errno = 0;
> + data->mask = strtol(slash + 1, NULL, 10);
Hmm, it would look a bit cleaner if the return value for strtol() were
examined for INT_MIN and 32 with errno returned in that case.
> + if (errno || data->mask > 32)
> + return -EINVAL;
If this return is taken, 'data' leaks memory? It's probably easier with
a goto error; to the very end of this function?
> +
> + proxy->domains = g_list_append(proxy->domains, data);
> + } else if (inet_pton(AF_INET6, ip, &(data->addr.ip6)) == 1) {
> + data->domain = NULL;
> + data->proto = 6;
> +
> + errno = 0;
Same as above.
> + data->mask = strtol(slash + 1, NULL, 10);
> + if (errno || data->mask > 128)
> + return -EINVAL;
> +
> + proxy->domains = g_list_append(proxy->domains, data);
> + } else
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> ?static int set_method(struct pacrunner_proxy *proxy,
> ? enum pacrunner_proxy_method method)
> ?{
> @@ -324,10 +415,60 @@ int pacrunner_proxy_disable(struct pacrunner_proxy
> *proxy)
> ? return 0;
> ?}
> ?
> +static int compare_legacy_ip_in_net(struct in_addr *host,
> + struct proxy_domain *match)
> +{
> + if (ntohl(host->s_addr ^ match->addr.ip4.s_addr) >> (32 - match->mask))
> + return -1;
> +
> + return 0;
> +}
> +
> +static int compare_ipv6_in_net(struct in6_addr *host,
> + struct proxy_domain *match)
> +{
> + int i, shift;
> +
> + for (i = 0; i < (match->mask)/8; i++) {
> + if (host->s6_addr[i] != match->addr.ip6.s6_addr[i])
> + return -1;
> + }
> +
> + if ((match->mask) % 8) {
> + /**
> + ?* If mask bits are not multiple of 8 , 1-7 bits are left
> + ?* to be compared.
> + ?*/
> + shift = 8 - (match->mask - (i*8));
> +
> + if ((host->s6_addr[i] >> shift) !=
> + (match->addr.ip6.s6_addr[i] >> shift))
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int compare_host_in_domain(const char *host, struct proxy_domain
> *match)
> +{
> + if (g_str_has_suffix(host, match->domain)) {
g_str_has_suffix() appears starting from glib 2.2. Currently only 2.16
is required, so either do a string comparison for the last bytes or
update glib requirement to >= 2.2. It is possible some embedded
developers might still be upset with the latter, though.
> + size_t hlen = strlen(host);
> + size_t dlen = strlen(match->domain);
> +
> + if (hlen == dlen || host[hlen - dlen - 1] == '.')
Can the following happen: hlen("foo"), dlen("myverylongdomain") ->
host[3 - 16 - 1] == host[-14] which is indexed outside the array?
> + return 0;
> + }
> +
> + return -1;
> +}
> +
> ?char *pacrunner_proxy_lookup(const char *url, const char *host)
> ?{
> - GList *list;
> - struct pacrunner_proxy *selected_proxy = NULL;
> + GList *l, *list;
> + struct in_addr ip4_addr;
> + struct in6_addr ip6_addr;
> + struct pacrunner_proxy *selected_proxy = NULL, *default_proxy = NULL;
> + int protocol = 0;
> ?
> ? DBG("url %s host %s", url, host);
> ?
> @@ -340,17 +481,67 @@ char *pacrunner_proxy_lookup(const char *url, const
> char *host)
> ? return NULL;
> ? }
> ?
> + if (inet_pton(AF_INET, host, &ip4_addr) == 1) {
> + protocol = 4;
> + } else if (inet_pton(AF_INET6, host, &ip6_addr) == 1) {
> + protocol = 6;
> + } else if (host[0] == '[') {
proxy_set_domains() above seems not to be able to handle an IPv6
address written as [2002:dead:beef::1]. Should the host and the domains
allow for the same formatting? AF_INET and AF_INET6 may look nicer to
some eyes (but that may introduce unnecessary glitches in the code, so
it can stay as is).
> + char ip[INET6_ADDRSTRLEN + 1];
> + int len = strlen(host);
> +
> + if (len < INET6_ADDRSTRLEN + 2 && host[len - 1] == ']') {
> + strncpy(ip, host + 1, len - 2);
> + ip[len - 2] = '\0';
> +
> + if (inet_pton(AF_INET6, ip, &ip6_addr) == 1)
> + protocol = 6;
> + }
> + }
> +
> ? for (list = g_list_first(proxy_list); list; list = g_list_next(list)) {
> ? struct pacrunner_proxy *proxy = list->data;
> ?
> - if (proxy->method == PACRUNNER_PROXY_METHOD_MANUAL ||
> - proxy->method == PACRUNNER_PROXY_METHOD_AUTO) {
> - selected_proxy = proxy;
> - break;
> - } else if (proxy->method == PACRUNNER_PROXY_METHOD_DIRECT)
> - selected_proxy = proxy;
> + if (!proxy->domains) {
> + if (!default_proxy)
> + default_proxy = proxy;
> + continue;
> + }
> +
> + for (l = g_list_first(proxy->domains); l; l = g_list_next(l)) {
> + struct proxy_domain *data = l->data;
> +
> + if (data->proto != protocol)
> + continue;
> +
> + switch (protocol) {
> + case 4:
> + if (compare_legacy_ip_in_net(&ip4_addr,
> + data) == 0) {
> + selected_proxy = proxy;
> + goto found;
> + }
> + break;
> + case 6:
> + if (compare_ipv6_in_net(&ip6_addr,
> + data) == 0) {
> + selected_proxy = proxy;
> + goto found;
> + }
> + break;
> + default:
> + if (compare_host_in_domain(host, data) == 0) {
> + selected_proxy = proxy;
> + goto found;
> + }
> + break;
> + }
> + }
> ? }
> ?
> + if (!selected_proxy)
> + selected_proxy = default_proxy;
> +
> +found:
> ? pthread_mutex_unlock(&proxy_mutex);
> ?
> ? if (!selected_proxy)
The above part should be patch #2, with the below patch #3. Good to see
there are test cases added for this!
> diff --git a/unit/suite/manual_basic.test b/unit/suite/manual_basic.test
> index a5ec3a1..4406d9c 100644
> --- a/unit/suite/manual_basic.test
> +++ b/unit/suite/manual_basic.test
> @@ -10,6 +10,8 @@ socks4://sockproxy.internal.com
> ?
> ?[excludes]
> ?
> +[domains]
> +
> ?[config]
> ?VALID
> ?
> diff --git a/unit/suite/manual_exclude.test b/unit/suite/manual_exclude.test
> index c155743..211ae16 100644
> --- a/unit/suite/manual_exclude.test
> +++ b/unit/suite/manual_exclude.test
> @@ -15,6 +15,8 @@ ftp://
> ?*net
> ?tri*
> ?
> +[domains]
> +
> ?[config]
> ?VALID
> ?
> diff --git a/unit/suite/pac_basic.test b/unit/suite/pac_basic.test
> index 58af200..c63757e 100644
> --- a/unit/suite/pac_basic.test
> +++ b/unit/suite/pac_basic.test
> @@ -17,6 +17,8 @@ function FindProxyForURL(url, host)
> ?
> ?[excludes]
> ?
> +[domains]
> +
> ?[config]
> ?VALID
> ?
> diff --git a/unit/suite/pac_direct.test b/unit/suite/pac_direct.test
> index 3164872..b820abc 100644
> --- a/unit/suite/pac_direct.test
> +++ b/unit/suite/pac_direct.test
> @@ -11,6 +11,8 @@ function FindProxyForURL(url, host)
> ?
> ?[excludes]
> ?
> +[domains]
> +
> ?[config]
> ?VALID
> ?
> diff --git a/unit/suite/proxy_domain.test b/unit/suite/proxy_domain.test
> new file mode 100644
> index 0000000..8c2c5e4
> --- /dev/null
> +++ b/unit/suite/proxy_domain.test
> @@ -0,0 +1,37 @@
> +[title]
> +Proxy Domain lookup
> +
> +[pac]
> +
> +[servers]
> +http://proxy.suite.com
> +
> +[excludes]
> +
> +[domains]
> +suite.com
> +test.suite.com
> +172.132.231.6/24
> +
> +[config]
> +VALID
> +
> +[tests]
> +http://foo.suite.com foo.suite.com
> +PROXY proxy.suite.com
> +http://172.132.231.101/search=?true 172.132.231.101
> +PROXY proxy.suite.com
> +http://111.121.131.141/page1 111.121.131.141
> +DIRECT
> +http://notintel.com notintel.com
> +DIRECT
> +http://intel.com intel.com
> +PROXY proxy2.com; PROXY secproxy2.com
> +https://bar.domain2.com bar.domain2.com
> +PROXY secproxy2.com; PROXY proxy2.com
> +http://192.168.4.4/index.html 192.168.4.4
> +PROXY proxy2.com; PROXY secproxy2.com
> +socks4://baz.domain3.com/xyz baz.domain3.com
> +SOCKS4 sockproxy3.com; PROXY proxy3.com
> +http://[fe80:96db:12ce::43ef]/ip6.mp4 [fe80:96db:12ce::43ef]
> +PROXY proxy3.com; SOCKS4 sockproxy3.com
> diff --git a/unit/suite/stub.test b/unit/suite/stub.test
> index 12a0426..cde0aeb 100644
> --- a/unit/suite/stub.test
> +++ b/unit/suite/stub.test
> @@ -11,6 +11,9 @@ Stub suite file
> ?[excludes]
> ?#?If so, optional exlusion rules can be written here
> ?
> +[domains]
> +# List of domains are here
> +
> ?[config]
> ?#?Result of the configuration: VALID or INVALID
> ?
> diff --git a/unit/test-pacrunner.c b/unit/test-pacrunner.c
> index f234a35..0c4ac69 100644
> --- a/unit/test-pacrunner.c
> +++ b/unit/test-pacrunner.c
> @@ -42,9 +42,10 @@ enum test_suite_part {
> ? SUITE_PAC??????= 1,
> ? SUITE_SERVERS??= 2,
> ? SUITE_EXCLUDES = 3,
> - SUITE_CONFIG???= 4,
> - SUITE_TESTS????= 5,
> - SUITE_NOTHING??= 6,
> + SUITE_DOMAINS??= 4,
> + SUITE_CONFIG???= 5,
> + SUITE_TESTS????= 6,
> + SUITE_NOTHING??= 7,
> ?};
> ?
> ?enum cu_test_mode {
> @@ -58,6 +59,7 @@ struct pacrunner_test_suite {
> ? gchar *pac;
> ? gchar **servers;
> ? gchar **excludes;
> + gchar **domains;
> ?
> ? bool config_result;
> ?
> @@ -67,7 +69,7 @@ struct pacrunner_test_suite {
> ?static struct pacrunner_test_suite *test_suite;
> ?static bool verbose = false;
> ?
> -static struct pacrunner_proxy *proxy;
> +static struct pacrunner_proxy *proxy, *proxy2 = NULL, *proxy3 = NULL;
> ?static bool test_config;
> ?
> ?static void free_pacrunner_test_suite(struct pacrunner_test_suite *suite)
> @@ -79,6 +81,7 @@ static void free_pacrunner_test_suite(struct
> pacrunner_test_suite *suite)
> ? g_free(suite->pac);
> ? g_strfreev(suite->servers);
> ? g_strfreev(suite->excludes);
> + g_strfreev(suite->domains);
> ? g_strfreev(suite->tests);
> ?
> ? g_free(suite);
> @@ -142,6 +145,13 @@ static void print_test_suite(struct pacrunner_test_suite
> *suite)
> ? } else
> ? printf("(none)\n");
> ?
> + printf("\nDomains:\n");
> + if (suite->domains) {
> + for (line = suite->domains; *line; line++)
> + printf("%s\n", *line);
> + } else
> + printf("(none)\n");
> +
> ? printf("\nConfig result: %s\n",
> ? suite->config_result ? "Valid" : "Invalid");
> ?
> @@ -240,6 +250,15 @@ static struct pacrunner_test_suite
> *read_test_suite(const char *path)
> ? suite->excludes = array;
> ?
> ? break;
> + case SUITE_DOMAINS:
> + array = _g_strappendv(suite->domains, *line);
> + if (!array)
> + goto error;
> +
> + g_free(suite->domains);
> + suite->domains = array;
> +
> + break;
> ? case SUITE_CONFIG:
> ? if (strncmp(*line, "VALID", 5) == 0)
> ? suite->config_result = true;
> @@ -272,6 +291,8 @@ static struct pacrunner_test_suite *read_test_suite(const
> char *path)
> ? part = SUITE_SERVERS;
> ? else if (strncmp(*line, "[excludes]", 10) == 0)
> ? part = SUITE_EXCLUDES;
> + else if (strncmp(*line, "[domains]", 9) == 0)
> + part = SUITE_DOMAINS;
> ? else if (strncmp(*line, "[config]", 8) == 0)
> ? part = SUITE_CONFIG;
> ? else if (strncmp(*line, "[tests]", 7) == 0)
> @@ -338,6 +359,54 @@ static void test_manual_config(void)
> ? CU_ASSERT_TRUE(test_suite->config_result == test_config);
> ?}
> ?
> +static void test_proxy_domain(void)
> +{
> + int val = 0;
> +
> + if (pacrunner_proxy_set_domains(proxy, test_suite->domains) != 0)
> + val = -1;
> +
> + proxy2 = pacrunner_proxy_create("eth1");
> + if (proxy2) {
> + char *servers[] = {
> + "http://proxy2.com",
> + "https://secproxy2.com",
> + NULL};
> + char *domains[] = {
> + "intel.com",
> + "domain2.com",
> + "192.168.4.0/16",
> + NULL};
> +
> + if (pacrunner_proxy_set_manual(proxy2, servers, NULL) != 0)
> + val = -1;
> +
> + if (pacrunner_proxy_set_domains(proxy2, domains) != 0)
> + val = -1;
> + }
> +
> + proxy3 = pacrunner_proxy_create("wl0");
> + if (proxy3) {
> + char *servers[] = {
> + "http://proxy3.com",
> + "socks4://sockproxy3.com",
> + NULL};
> + char *domains[] = {
> + "redhat.com",
> + "domain3.com",
> + "fe80:96db::/32",
> + NULL};
> +
> + if (pacrunner_proxy_set_manual(proxy3, servers, NULL) != 0)
> + val = -1;
> +
> + if (pacrunner_proxy_set_domains(proxy3, domains) != 0)
> + val = -1;
> + }
> +
> + CU_ASSERT_TRUE(val == 0);
> +}
> +
> ?static void test_proxy_requests(void)
> ?{
> ? gchar **test_strings;
> @@ -430,12 +499,21 @@ static void run_test_suite(const char *test_file_path,
> enum cu_test_mode mode)
> ? CU_add_test(cu_suite, "Manual config test",
> ? test_manual_config);
> ?
> + if (test_suite->domains)
> + CU_add_test(cu_suite, "Proxy domain test",
> + test_proxy_domain);
> +
> ? if (test_suite->config_result && test_suite->tests)
> ? CU_add_test(cu_suite, "Proxy requests test",
> ? test_proxy_requests);
> ?
> ? test_config = false;
> ?
> + if (test_suite->domains) {
> + pacrunner_proxy_unref(proxy2);
> + pacrunner_proxy_unref(proxy3);
> + }
> +
> ? switch (mode) {
> ? case CU_MODE_BASIC:
> ? CU_basic_set_mode(CU_BRM_VERBOSE);
Cheers,
Patrik
------------------------------
Subject: Digest Footer
_______________________________________________
connman mailing list
[email protected]
https://lists.01.org/mailman/listinfo/connman
------------------------------
End of connman Digest, Vol 8, Issue 17
**************************************