aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAtul Anand <atulhjp@gmail.com>2016-06-16 16:45:53 +0530
committerPatrik Flykt <patrik.flykt@linux.intel.com>2016-06-16 15:35:34 +0300
commitee610da7096d5b3dfa7e073141de8c82b71250d0 (patch)
tree46d79dd62c71c82f942867b7c1b632b9cf8e0d3b
parent741959fcce8193ff441c5df0c21089b51b4c8c77 (diff)
downloadpacrunner-ee610da7096d5b3dfa7e073141de8c82b71250d0.tar.gz
src: Domains are looked up to match the host.
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.
-rw-r--r--src/manager.c7
-rw-r--r--src/pacrunner.h2
-rw-r--r--src/proxy.c214
3 files changed, 211 insertions, 12 deletions
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..2ebc75d 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -23,6 +23,9 @@
#include <config.h>
#endif
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
#include <errno.h>
#include <pthread.h>
@@ -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,15 @@ struct pacrunner_proxy *pacrunner_proxy_ref(struct pacrunner_proxy *proxy)
return proxy;
}
+static void proxy_domain_destroy(gpointer data)
+{
+ struct proxy_domain *domain = data;
+ 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 +115,10 @@ 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, proxy_domain_destroy);
+ proxy->domains = NULL;
}
void pacrunner_proxy_unref(struct pacrunner_proxy *proxy)
@@ -130,6 +157,76 @@ 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 = domains; *domain; domain++) {
+ struct proxy_domain *data;
+
+ data = g_malloc0(sizeof(struct proxy_domain));
+
+ 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) {
+ g_free(data);
+ continue;
+ }
+
+ 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);
+ if (errno || data->mask < 0 || data->mask > 32) {
+ g_free(data);
+ continue;
+ }
+
+ 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;
+ data->mask = strtol(slash + 1, NULL, 10);
+ if (errno || data->mask < 0 || data->mask > 128) {
+ g_free(data);
+ continue;
+ }
+
+ proxy->domains = g_list_append(proxy->domains, data);
+ } else {
+ g_free(data);
+ continue;
+ }
+ }
+
+ return 0;
+}
+
static int set_method(struct pacrunner_proxy *proxy,
enum pacrunner_proxy_method method)
{
@@ -324,10 +421,61 @@ 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)
+{
+ size_t hlen = strlen(host);
+ size_t dlen = strlen(match->domain);
+
+ if ((hlen >= dlen) && (strcmp(host + (hlen - dlen),
+ match->domain) == 0)) {
+ if (hlen == dlen || host[hlen - dlen - 1] == '.')
+ 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 +488,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] == '[') {
+ 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)