--- Makefile.am | 7 +- src/manager.c | 70 ++++++++++---- src/manual.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/manual.h | 26 +++++ src/pacrunner.h | 16 +++- src/proxy.c | 76 ++++++++++++--- 6 files changed, 435 insertions(+), 37 deletions(-) create mode 100644 src/manual.c create mode 100644 src/manual.h
diff --git a/Makefile.am b/Makefile.am index 5a9aa7e..62fb474 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,3 @@ - AM_MAKEFLAGS = --no-print-directory if DATAFILES @@ -32,6 +31,7 @@ src_pacrunner_SOURCES = $(gdbus_sources) $(builtin_sources) \ src/main.c src/pacrunner.h \ src/log.h src/log.c src/plugin.h src/plugin.c \ src/download.h src/download.c \ + src/manual.h src/manual.c \ src/client.c src/manager.c \ src/proxy.c src/mozjs.c src/javascript.h @@ -75,8 +75,9 @@ endif noinst_PROGRAMS = unit/test-mozjs -unit_test_mozjs_SOURCES = unit/test-mozjs.c src/pacrunner.h \ - src/proxy.c src/download.c src/mozjs.c +unit_test_mozjs_SOURCES = unit/test-mozjs.c src/pacrunner.h src/manual.h \ + src/manual.c src/proxy.c src/download.c \ + src/mozjs.c unit_test_mozjs_LDADD = @MOZJS_LIBS@ @GLIB_LIBS@ diff --git a/src/manager.c b/src/manager.c index 170ee1d..8303b57 100644 --- a/src/manager.c +++ b/src/manager.c @@ -82,7 +82,8 @@ static struct proxy_config *create_config(DBusConnection *conn, const char *method, const char *url, const char *script, - const char *server, + const char *servers, + const char *excludes, const char *interface, const char *domainname, const char *nameserver) @@ -113,8 +114,9 @@ static struct proxy_config *create_config(DBusConnection *conn, disconnect_callback, config, NULL); if (g_strcmp0(method, "manual") == 0) { - if (pacrunner_proxy_set_server(config->proxy, server) < 0) - pacrunner_error("Failed to set proxy server"); + if (pacrunner_proxy_set_manual(config->proxy, servers, + excludes) < 0) + pacrunner_error("Failed to set manual proxy"); return config; } else if (g_strcmp0(method, "auto") != 0) { @@ -135,6 +137,34 @@ static struct proxy_config *create_config(DBusConnection *conn, return config; } +static char *get_list_as_string(DBusMessageIter *array) +{ + char *str = NULL, *str_tmp; + + DBG(" "); + + while (dbus_message_iter_get_arg_type(array) == DBUS_TYPE_STRING) { + char *value = NULL; + + dbus_message_iter_get_basic(array, &value); + + if (str == NULL) + str = g_strdup(value); + else { + str_tmp = g_strjoin(" ", str, value, NULL); + g_free(str); + str = str_tmp; + } + + if (str == NULL) + return NULL; + + dbus_message_iter_next(array); + } + + return str; +} + static DBusMessage *create_proxy_config(DBusConnection *conn, DBusMessage *msg, void *user_data) { @@ -142,7 +172,7 @@ static DBusMessage *create_proxy_config(DBusConnection *conn, struct proxy_config *config; const char *sender, *method = NULL; const char *url = NULL, *script = NULL; - const char *server = NULL, *exclude = NULL; + char *servers = NULL, *excludes = NULL; const char *interface = NULL, *domainname = NULL, *nameserver = NULL; sender = dbus_message_get_sender(msg); @@ -187,15 +217,11 @@ static DBusMessage *create_proxy_config(DBusConnection *conn, DBUS_TYPE_INVALID) break; - if (g_str_equal(key, "Servers") == TRUE) { - dbus_message_iter_get_basic(&list, &server); - if (strlen(server) == 0) - server = NULL; - } else if (g_str_equal(key, "Excludes") == TRUE) { - dbus_message_iter_get_basic(&list, &exclude); - if (strlen(exclude) == 0) - exclude = NULL; - } else if (g_str_equal(key, "Domains") == TRUE) { + if (g_str_equal(key, "Servers") == TRUE) + servers = get_list_as_string(&list); + else if (g_str_equal(key, "Excludes") == TRUE) + excludes = get_list_as_string(&list); + else if (g_str_equal(key, "Domains") == TRUE) { dbus_message_iter_get_basic(&list, &domainname); if (strlen(domainname) == 0) domainname = NULL; @@ -211,18 +237,26 @@ static DBusMessage *create_proxy_config(DBusConnection *conn, } DBG("sender %s method %s", sender, method); - DBG("url %s script %p server %s exclude %s", - url, script, server, exclude); + DBG("url %s script %p servers %p excludes %p", + url, script, servers, excludes); DBG("interface %s domainname %s nameserver %s", interface, domainname, nameserver); - if (method == NULL) + if (method == NULL) { + g_free(servers); + g_free(excludes); + return g_dbus_create_error(msg, PACRUNNER_ERROR_INTERFACE ".Failed", "No proxy method specified"); + } + + config = create_config(conn, sender, method, url, script, servers, + excludes, interface, domainname, nameserver); + + g_free(servers); + g_free(excludes); - config = create_config(conn, sender, method, url, script, server, - interface, domainname, nameserver); if (config == NULL) return g_dbus_create_error(msg, PACRUNNER_ERROR_INTERFACE ".Failed", diff --git a/src/manual.c b/src/manual.c new file mode 100644 index 0000000..345e5ca --- /dev/null +++ b/src/manual.c @@ -0,0 +1,277 @@ +/* +* +* PACrunner - Proxy configuration daemon +* +* Copyright (C) 2010 Nokia Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "pacrunner.h" + +#include "manual.h" + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <limits.h> + + +struct pacrunner_manual_excludes { + char *proto; + char *host; + int host_length; + enum pacrunner_manual_exclude_appliance appliance; + + struct pacrunner_manual_excludes *next; +}; + +int __pacrunner_manual_parse_uri(const char *uri, char **host, + char **protocol, int no_path, int exclusion) +{ + int length; + int proto = 0, ret = 0; + int post_confirmed = 0; + char *scheme, *sep, *cur; + char **forbiden_chars = NULL; + + if (host != NULL) + *host = NULL; + + if (protocol != NULL) + *protocol = NULL; + + scheme = g_strdup(uri); + if (scheme == NULL) + goto error; + + cur = scheme; + + sep = strstr(cur, "://"); + if (sep != NULL) { + if (sep == cur) + goto error; + + if (protocol != NULL) { + *sep = '\0'; + + *protocol = g_strdup(cur); + if (*protocol == NULL) + goto error; + } + + cur = sep + 3; + proto = 1; + + if (!exclusion) + ret = PACRUNNER_PROXY_MANUAL_PROTOCOL_BASED; + } + + sep = strchr(cur, '/'); + if (sep != NULL) { + if (exclusion || (*(sep + 1) != '\0' && no_path)) + goto error; + + *sep = '\0'; + } + + /* We skip <login:password> if present */ + sep = strchr(cur, '@'); + if (sep != NULL) { + if (exclusion) + goto error; + + *sep = '\0'; + cur = sep + 1; + } + + /* Are we in front of a possible IPv6 address? */ + sep = strchr(cur, '['); + if (sep != NULL) { + char *bracket; + + bracket = strchr(cur, ']'); + if (bracket == NULL) + goto error; + + cur = sep+1; + sep = strchr(bracket, ':'); + *bracket = '\0'; + } + else + sep = strchr(cur, ':'); + + /* Checking port validity if present */ + if (sep != NULL) { + long int port = -1; + char *err = NULL; + + /* We do not filter out per port in exclusion URI */ + if (exclusion) + goto error; + + errno = 0; + port = strtol(sep+1, &err, 10); + if (*err != '\0' || port <= 0 || port > USHRT_MAX || + errno == ERANGE || errno == EINVAL) + goto error; + + *sep = '\0'; + } + + /* We detect/trim '.'/'*' on both ends. + * This is not an error only for exclusion URI since + * it defines its rule's appliance */ + for (sep = cur; + *sep != '\0' && (*sep == '*' || *sep == '.'); + *sep = '\0', sep++); + + if (sep != cur) { + if (!exclusion) + goto error; + + cur = sep; + post_confirmed = 1; + } + + length = strlen(cur); + if (length > 0) { + for (sep = cur + length - 1; + *sep != '\0' && (*sep == '*' || *sep == '.'); + *sep = '\0', sep--); + + if (sep - cur + 1 != length) { + if (!exclusion) + goto error; + + length = sep - cur + 1; + + ret = PACRUNNER_MANUAL_EXCLUDE_PRE; + if (post_confirmed) + ret = PACRUNNER_MANUAL_EXCLUDE_ANY; + } + + if ((length > 255) + || (*cur == '-' || *sep == '-') + || ((*cur == '\0') && (!exclusion || + (exclusion && !proto)))) + goto error; + + /* We do not allow some characters */ + forbiden_chars = g_strsplit_set(cur, + "%?!,;@\\'*|<>{}[]()+=$&~# ", -1); + + if (forbiden_chars != NULL) { + length = g_strv_length(forbiden_chars); + g_strfreev(forbiden_chars); + + if (length > 1) + goto error; + } + + if (host != NULL && *cur != '\0') { + *host = g_strdup(cur); + if (*host == NULL) + goto error; + } + } else + if (!exclusion || (exclusion && !proto)) + goto error; + + g_free(scheme); + return ret; + +error: + if (protocol != NULL) + g_free(*protocol); + + g_free(scheme); + return -EINVAL; +} + +void __pacrunner_manual_free_excludes(struct pacrunner_manual_excludes *excludes) +{ + struct pacrunner_manual_excludes *free_rule, *next_rule; + + if (excludes == NULL) + return; + + for (next_rule = excludes; next_rule != NULL;) { + free_rule = next_rule; + + g_free(next_rule->proto); + g_free(next_rule->host); + + next_rule = free_rule->next; + g_free(free_rule); + } +} + +struct pacrunner_manual_excludes *__pacrunner_manual_create_excludes(const char *excludes) +{ + char *host, *proto; + char **uri_list, **uri; + struct pacrunner_manual_excludes *rule_list, *new_rule, *cur_rule; + + DBG(" "); + + if (excludes == NULL) + return NULL; + + rule_list = NULL; + cur_rule = NULL; + + uri_list = g_strsplit_set(excludes, " ", -1); + + for (uri = uri_list; *uri != NULL; uri++) { + int ret = __pacrunner_manual_parse_uri(*uri, &host, &proto, + 1, 1); + if (ret >= 0) { + new_rule = g_try_malloc0(sizeof( + struct pacrunner_manual_excludes)); + if (new_rule == NULL) + break; + + new_rule->proto = proto; + new_rule->host = host; + new_rule->appliance = ret; + if (host != NULL) + new_rule->host_length = strlen(host); + + if (rule_list == NULL) + rule_list = new_rule; + + if (cur_rule != NULL) + cur_rule->next = new_rule; + + cur_rule = new_rule; + + proto = NULL; + host = NULL; + } + } + + g_strfreev(uri_list); + + /* In case previous loop ended at 'break;'*/ + g_free(proto); + g_free(host); + + return rule_list; +} diff --git a/src/manual.h b/src/manual.h new file mode 100644 index 0000000..1028acd --- /dev/null +++ b/src/manual.h @@ -0,0 +1,26 @@ +/* +* +* PACrunner - Proxy configuration daemon +* +* Copyright (C) 2010 Nokia Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +enum pacrunner_manual_exclude_appliance { + PACRUNNER_MANUAL_EXCLUDE_POST = 0, + PACRUNNER_MANUAL_EXCLUDE_PRE = 1, + PACRUNNER_MANUAL_EXCLUDE_ANY = 2, +}; diff --git a/src/pacrunner.h b/src/pacrunner.h index cb5b496..6439908 100644 --- a/src/pacrunner.h +++ b/src/pacrunner.h @@ -52,6 +52,13 @@ enum pacrunner_proxy_method { PACRUNNER_PROXY_METHOD_AUTO = 3, }; +enum pacrunner_proxy_manual_context { + PACRUNNER_PROXY_MANUAL_GENERIC = 0, + PACRUNNER_PROXY_MANUAL_PROTOCOL_BASED = 1, +}; + +struct pacrunner_manual_excludes; + struct pacrunner_proxy; struct pacrunner_proxy *pacrunner_proxy_create(const char *interface); @@ -67,8 +74,8 @@ int pacrunner_proxy_set_direct(struct pacrunner_proxy *proxy); int pacrunner_proxy_set_auto(struct pacrunner_proxy *proxy, const char *url); int pacrunner_proxy_set_script(struct pacrunner_proxy *proxy, const char *script); -int pacrunner_proxy_set_server(struct pacrunner_proxy *proxy, - const char *server); +int pacrunner_proxy_set_manual(struct pacrunner_proxy *proxy, + const char *servers, const char *excludes); int pacrunner_proxy_enable(struct pacrunner_proxy *proxy); int pacrunner_proxy_disable(struct pacrunner_proxy *proxy); @@ -96,3 +103,8 @@ int __pacrunner_mozjs_init(void); void __pacrunner_mozjs_cleanup(void); int __pacrunner_mozjs_set_proxy(struct pacrunner_proxy *proxy); const char *__pacrunner_mozjs_execute(const char *url, const char *host); + +int __pacrunner_manual_parse_uri(const char *uri, char **host, + char **protocol, int no_path, int exclusion); +void __pacrunner_manual_free_excludes(struct pacrunner_manual_excludes *excludes); +struct pacrunner_manual_excludes *__pacrunner_manual_create_excludes(const char *excludes); diff --git a/src/proxy.c b/src/proxy.c index c50f366..391fa9f 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -34,7 +34,9 @@ struct pacrunner_proxy { enum pacrunner_proxy_method method; char *url; char *script; - char *server; + enum pacrunner_proxy_manual_context context; + char **servers; + struct pacrunner_manual_excludes *excludes; char *result; }; @@ -80,8 +82,11 @@ static void reset_proxy(struct pacrunner_proxy *proxy) g_free(proxy->script); proxy->script = NULL; - g_free(proxy->server); - proxy->server = NULL; + g_strfreev(proxy->servers); + proxy->servers = NULL; + + __pacrunner_manual_free_excludes(proxy->excludes); + proxy->excludes = NULL; g_free(proxy->result); proxy->result = NULL; @@ -230,31 +235,74 @@ int pacrunner_proxy_set_script(struct pacrunner_proxy *proxy, return 0; } -int pacrunner_proxy_set_server(struct pacrunner_proxy *proxy, - const char *server) +int pacrunner_proxy_set_manual(struct pacrunner_proxy *proxy, + const char *servers, const char *excludes) { - int err; + int code; + char **uri_list, **valids, **uri; - DBG("proxy %p server %s", proxy, server); + DBG("proxy %p servers %s excludes %s", proxy, servers, excludes); if (proxy == NULL) return -EINVAL; - if (server == NULL) + if (servers == NULL) return -EINVAL; - err = pacrunner_proxy_set_method(proxy, PACRUNNER_PROXY_METHOD_MANUAL); - if (err < 0) - return err; + code = pacrunner_proxy_set_method(proxy, + PACRUNNER_PROXY_METHOD_MANUAL); + if (code < 0) + return code; + + proxy->context = PACRUNNER_PROXY_MANUAL_GENERIC; + + g_strfreev(proxy->servers); + proxy->servers = NULL; + + __pacrunner_manual_free_excludes(proxy->excludes); + proxy->excludes = NULL; + + valids = NULL; + uri_list = g_strsplit_set(servers, " ", -1); + + for (uri = uri_list; *uri != NULL; uri++) { + code = __pacrunner_manual_parse_uri(*uri, NULL, NULL, 1, 0); - g_free(proxy->server); - proxy->server = g_strdup(server); + if (code < 0) { + if (valids != NULL) { + char *str_xchg = *valids; + + *valids = *uri; + *uri = str_xchg; + valids++; + } + } else { + if (valids == NULL) + valids = uri; + + if (proxy->context == PACRUNNER_PROXY_MANUAL_GENERIC) + proxy->context = code; + } + } + + proxy->servers = g_strdupv(valids); + g_strfreev(uri_list); + + if (proxy->servers == NULL) + /* No valid server URI, this is fatal */ + return -EINVAL; + + proxy->excludes = __pacrunner_manual_create_excludes(excludes); g_free(proxy->result); - proxy->result = g_strdup_printf("PROXY %s", server); + proxy->result = g_strdup(proxy->servers[0]); pacrunner_proxy_enable(proxy); + DBG("servers = %d - context %d, excludes %p", + g_strv_length(proxy->servers), + proxy->context, proxy->excludes); + return 0; } -- 1.7.1 _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman