This tool is a proposal for manual proxy configuration implementation.
---
Makefile.am | 5 +-
tools/manual.c | 732 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 736 insertions(+), 1 deletions(-)
create mode 100644 tools/manual.c
diff --git a/Makefile.am b/Makefile.am
index 4b2efa4..bdc7983 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -79,11 +79,14 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libproxy/libproxy-1.0.pc
endif
-bin_PROGRAMS = tools/proxy
+bin_PROGRAMS = tools/proxy tools/manual
tools_proxy_SOURCES = tools/proxy.c
tools_proxy_LDADD = libproxy/libproxy.la
+
+tools_manual_SOURCES = tools/manual.c
+
endif
if MOZJS
diff --git a/tools/manual.c b/tools/manual.c
new file mode 100644
index 0000000..ef1bc1e
--- /dev/null
+++ b/tools/manual.c
@@ -0,0 +1,732 @@
+/*
+ *
+ * PACrunner - Proxy configuration daemon
+ *
+ * Copyright (C) 2011 Intel 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 <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#define DBG(fmt, arg...) do { \
+ printf("%s() " fmt "\n", __FUNCTION__ , ## arg); \
+} while (0)
+
+enum pacrunner_manual_protocol {
+ PACRUNNER_PROTOCOL_ALL = 0,
+ PACRUNNER_PROTOCOL_HTTP = 1,
+ PACRUNNER_PROTOCOL_HTTPS = 2,
+ PACRUNNER_PROTOCOL_FTP = 3,
+ PACRUNNER_PROTOCOL_SOCKS4 = 4,
+ PACRUNNER_PROTOCOL_SOCKS5 = 5,
+ PACRUNNER_PROTOCOL_MAXIMUM_NUMBER = 6,
+ PACRUNNER_PROTOCOL_UNKNOWN = 7,
+};
+
+enum pacrunner_manual_exclude_appliance {
+ PACRUNNER_MANUAL_EXCLUDE_POST = 0,
+ PACRUNNER_MANUAL_EXCLUDE_PRE = 1,
+ PACRUNNER_MANUAL_EXCLUDE_ANY = 2,
+};
+
+struct pacrunner_manual_exclude {
+ enum pacrunner_manual_exclude_appliance appliance;
+ int host_length;
+ char *host;
+};
+
+static enum pacrunner_manual_protocol get_protocol_from_string(const char
*protocol)
+{
+ if (protocol == NULL)
+ return PACRUNNER_PROTOCOL_ALL;
+
+ if (g_strcmp0(protocol, "http") == 0)
+ return PACRUNNER_PROTOCOL_HTTP;
+ if (g_strcmp0(protocol, "https") == 0)
+ return PACRUNNER_PROTOCOL_HTTPS;
+ if (g_strcmp0(protocol, "ftp") == 0)
+ return PACRUNNER_PROTOCOL_FTP;
+ if (g_strcmp0(protocol, "socks4") == 0)
+ return PACRUNNER_PROTOCOL_SOCKS4;
+ if (g_strcmp0(protocol, "socks5") == 0)
+ return PACRUNNER_PROTOCOL_SOCKS5;
+
+ return PACRUNNER_PROTOCOL_UNKNOWN;
+}
+
+static const char *get_protocol_to_string(enum pacrunner_manual_protocol
protocol)
+{
+ switch (protocol) {
+ case PACRUNNER_PROTOCOL_ALL:
+ return "ALL";
+ case PACRUNNER_PROTOCOL_HTTP:
+ return "HTTP";
+ case PACRUNNER_PROTOCOL_HTTPS:
+ return "HTTPS";
+ case PACRUNNER_PROTOCOL_FTP:
+ return "FTP";
+ case PACRUNNER_PROTOCOL_SOCKS4:
+ return "SOCKS4";
+ case PACRUNNER_PROTOCOL_SOCKS5:
+ return "SOCKS5";
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+}
+
+static const char *get_appliance_to_string(enum
pacrunner_manual_exclude_appliance appliance)
+{
+ switch(appliance) {
+ case PACRUNNER_MANUAL_EXCLUDE_POST:
+ return "POST";
+ case PACRUNNER_MANUAL_EXCLUDE_PRE:
+ return "PRE";
+ case PACRUNNER_MANUAL_EXCLUDE_ANY:
+ return "ANY";
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+}
+
+static int parse_uri(char *uri,
+ char **host,
+ char **protocol,
+ gboolean no_path,
+ gboolean exclusion)
+{
+ gboolean proto, post_confirmed, ipv6;
+ char *scheme, *sep, *cur;
+ int length, ret = 0;
+ long int port = -1;
+
+ proto = post_confirmed = ipv6 = FALSE;
+
+ 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 = TRUE;
+ }
+
+ sep = strchr(cur, '/');
+ if (sep != NULL) {
+ if (exclusion == TRUE || (*(sep + 1) != '\0' &&
+ no_path == TRUE))
+ goto error;
+
+ *sep = '\0';
+ }
+
+ /* We skip <login:password> if present */
+ sep = strchr(cur, '@');
+ if (sep != NULL) {
+ if (exclusion == TRUE)
+ 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;
+ cur = sep;
+ sep = strchr(bracket, ':');
+ //*bracket = '\0';
+ ipv6 = TRUE;
+ }
+ else
+ sep = strchr(cur, ':');
+
+ /* Checking port validity if present */
+ if (sep != NULL) {
+ char *err = NULL;
+
+ /* We do not filter out per port in exclusion URI */
+ if (exclusion == TRUE)
+ 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 == FALSE)
+ goto error;
+
+ cur = sep;
+ post_confirmed = TRUE;
+ }
+
+ length = strlen(cur);
+ if (length > 0) {
+ const char *forbidden_chars;
+ char **forbidden = NULL;
+
+ for (sep = cur + length - 1;
+ *sep != '\0' && (*sep == '*' || *sep == '.');
+ *sep = '\0', sep--);
+
+ if (sep - cur + 1 != length) {
+ if (exclusion == FALSE)
+ goto error;
+
+ length = sep - cur + 1;
+
+ ret = PACRUNNER_MANUAL_EXCLUDE_PRE;
+ if (post_confirmed == TRUE)
+ ret = PACRUNNER_MANUAL_EXCLUDE_ANY;
+ }
+
+ if ((length > 255) || (*cur == '-' || *sep == '-') ||
+ ((*cur == '\0') && (exclusion == FALSE ||
+ (exclusion == TRUE && proto == FALSE))))
+ goto error;
+
+ /* We do not allow some characters
+ * However we do not run a strict check
+ * if it's an IP address which is given */
+ if (ipv6 == TRUE)
+ forbidden_chars = "%?!,;@\\'*|<>{}()+=$&~# \"";
+ else
+ forbidden_chars = "%?!,;@\\'*|<>{}[]()+=$&~# \"";
+
+ forbidden = g_strsplit_set(cur, forbidden_chars, -1);
+ if (forbidden != NULL) {
+ length = g_strv_length(forbidden);
+ g_strfreev(forbidden);
+
+ if (length > 1)
+ goto error;
+ }
+
+ if (host != NULL && *cur != '\0') {
+ if (port > 0) {
+ /* Instead of transcoding the port back
+ * to string we just get the host:port line
+ * from the original uri */
+ cur = uri + (cur - scheme);
+
+ sep = strchr(cur, '/');
+ if (sep != NULL)
+ length = sep - cur;
+ else
+ length = strlen(cur);
+
+ *host = g_strndup(cur, length);
+ } else
+ *host = g_strdup(cur);
+
+ if (*host == NULL)
+ goto error;
+ }
+ } else {
+ if (exclusion == FALSE ||
+ (exclusion == TRUE && proto == FALSE))
+ goto error;
+ else
+ ret = PACRUNNER_MANUAL_EXCLUDE_ANY;
+ }
+
+ g_free(scheme);
+
+ return ret;
+
+error:
+ if (protocol != NULL)
+ g_free(*protocol);
+
+ g_free(scheme);
+
+ return -EINVAL;
+}
+
+static void free_exclude(gpointer data)
+{
+ struct pacrunner_manual_exclude *exclude;
+
+ exclude = (struct pacrunner_manual_exclude *) data;
+ if (exclude == NULL)
+ return;
+
+ g_free(exclude->host);
+ g_free(exclude);
+}
+
+static void __pacrunner_manual_destroy_excludes(GList **excludes)
+{
+ int i;
+
+ if (excludes == NULL)
+ return;
+
+ for (i = 0; i < PACRUNNER_PROTOCOL_MAXIMUM_NUMBER; i++)
+ g_list_free_full(excludes[i], free_exclude);
+
+ g_free(excludes);
+}
+
+static GList **__pacrunner_manual_create_excludes(const char **excludes)
+{
+ struct pacrunner_manual_exclude *exclude;
+ char *host, *protocol;
+ GList **result = NULL;
+ int ret, proto;
+ char **uri;
+
+ if (excludes == NULL)
+ return NULL;
+
+ result = g_try_malloc0(PACRUNNER_PROTOCOL_MAXIMUM_NUMBER *
+ sizeof(GList *));
+ if (result == NULL)
+ return NULL;
+
+ for (uri = (char **)excludes; *uri != NULL; uri++) {
+ ret = parse_uri(*uri, &host, &protocol, TRUE, TRUE);
+
+ if (ret < 0)
+ continue;
+
+ exclude = g_try_malloc0(sizeof(
+ struct pacrunner_manual_exclude));
+ if (exclude == NULL)
+ goto error;
+
+ proto = get_protocol_from_string(protocol);
+
+ exclude->appliance = ret;
+
+ if (proto == PACRUNNER_PROTOCOL_UNKNOWN)
+ goto error;
+
+ exclude->host = host;
+ if (host != NULL)
+ exclude->host_length = strlen(host);
+
+ if (proto == PACRUNNER_PROTOCOL_ALL)
+ result[proto] = g_list_prepend(result[proto], exclude);
+ else
+ result[proto] = g_list_append(result[proto], exclude);
+
+ g_free(protocol);
+ protocol = NULL;
+ host = NULL;
+ }
+
+ return result;
+
+error:
+ g_free(host);
+ g_free(protocol);
+
+ __pacrunner_manual_destroy_excludes(result);
+
+ return NULL;
+}
+
+static void __pacrunner_manual_destroy_servers(GList **servers)
+{
+ int i;
+
+ if (servers == NULL)
+ return;
+
+ for (i = 0; i < PACRUNNER_PROTOCOL_MAXIMUM_NUMBER; i++)
+ g_list_free_full(servers[i], g_free);
+
+ g_free(servers);
+}
+
+static GList **__pacrunner_manual_create_servers(const char **servers)
+{
+ char *host, *protocol;
+ GList **result;
+ char **uri;
+ int proto;
+ int ret;
+
+ if (servers == NULL)
+ return NULL;
+
+ result = g_try_malloc0(PACRUNNER_PROTOCOL_MAXIMUM_NUMBER *
+ sizeof(GList *));
+ if (result == NULL)
+ return NULL;
+
+ for (uri = (char **)servers; *uri != NULL; uri++) {
+ ret = parse_uri(*uri, &host, &protocol, TRUE, FALSE);
+
+ if (ret < 0)
+ continue;
+
+ proto = get_protocol_from_string(protocol);
+ if (proto == PACRUNNER_PROTOCOL_UNKNOWN)
+ goto error;
+
+ result[proto] = g_list_append(result[proto], host);
+
+ g_free(protocol);
+ }
+
+ return result;
+
+error:
+ g_free(host);
+ g_free(protocol);
+
+ __pacrunner_manual_destroy_servers(result);
+
+ return NULL;
+}
+
+static gboolean is_exclusion_matching(GList *excludes_list,
+ const char *host)
+{
+ struct pacrunner_manual_exclude *exclusion;
+ GList *excludes = NULL;
+ char *cursor;
+
+ for (excludes = excludes_list; excludes != NULL;
+ excludes = excludes->next) {
+ exclusion = (struct pacrunner_manual_exclude *) excludes->data;
+ if (exclusion == NULL)
+ continue;
+
+ cursor = NULL;
+
+ if (exclusion->host != NULL)
+ cursor = strstr(host, exclusion->host);
+
+ switch(exclusion->appliance) {
+ case PACRUNNER_MANUAL_EXCLUDE_POST:
+ if (cursor == NULL)
+ break;
+
+ if (*(cursor + exclusion->host_length) == '\0')
+ return TRUE;
+
+ break;
+ case PACRUNNER_MANUAL_EXCLUDE_PRE:
+ if (cursor == host)
+ return TRUE;
+
+ break;
+ case PACRUNNER_MANUAL_EXCLUDE_ANY:
+ if (exclusion->host != NULL) {
+ if (cursor != NULL)
+ return TRUE;
+ else
+ break;
+ }
+
+ return TRUE;
+ default:
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean is_url_excluded(GList **excludes,
+ const char *host,
+ enum pacrunner_manual_protocol proto)
+{
+ if (excludes == NULL)
+ return FALSE;
+
+ if (excludes[PACRUNNER_PROTOCOL_ALL] != NULL)
+ if (is_exclusion_matching(excludes[PACRUNNER_PROTOCOL_ALL],
+ host) == TRUE)
+ return TRUE;
+
+ if (proto == PACRUNNER_PROTOCOL_UNKNOWN)
+ return FALSE;
+
+ if (excludes[proto] != NULL)
+ if (is_exclusion_matching(excludes[proto], host) == TRUE)
+ return TRUE;
+
+ return FALSE;
+}
+
+static char *__pacrunner_manual_execute(const char *url,
+ GList **servers,
+ GList **excludes)
+{
+ char *protocol = NULL;
+ char *host = NULL;
+ int proto;
+
+ if (servers == NULL)
+ return NULL;
+
+ if (parse_uri((char *)url, &host, &protocol, FALSE, FALSE) < 0)
+ goto direct;
+
+ proto = get_protocol_from_string(protocol);
+
+ if (is_url_excluded(excludes, host, proto) == TRUE)
+ goto direct;
+
+ g_free(protocol);
+
+ if (servers[PACRUNNER_PROTOCOL_ALL] != NULL)
+ return (char *)servers[PACRUNNER_PROTOCOL_ALL]->data;
+
+ if (proto == PACRUNNER_PROTOCOL_UNKNOWN ||
+ proto == PACRUNNER_PROTOCOL_ALL)
+ return NULL;
+
+ return (char *)servers[proto]->data;
+
+direct:
+ g_free(protocol);
+
+ return NULL;
+}
+
+static void dump_proxy_exclusion(gpointer data, gpointer user_data)
+{
+ struct pacrunner_manual_exclude *exclusion;
+
+ exclusion = (struct pacrunner_manual_exclude *) data;
+ if (exclusion == NULL)
+ return;
+
+ printf("\tappliance: %s\n",
+ get_appliance_to_string(exclusion->appliance));
+ printf("\thost: %s (%d)\n", exclusion->host, exclusion->host_length);
+}
+
+static void dump_excludes(GList **excludes)
+{
+ int i;
+
+ printf("EXCLUDES:\n");
+
+ if (excludes == NULL) {
+ printf("\tNO EXCLUDES\n");
+ return;
+ }
+
+ for (i = 0; i < PACRUNNER_PROTOCOL_MAXIMUM_NUMBER; i++) {
+ printf("Protocol: %s\n", get_protocol_to_string(i));
+
+ if (excludes[i] == NULL) {
+ printf("\tNONE\n");
+ continue;
+ }
+
+ g_list_foreach(excludes[i], dump_proxy_exclusion, NULL);
+ printf("\n");
+ }
+}
+
+static void dump_proxy_server(gpointer data, gpointer user_data)
+{
+ printf("\t%s \n", (char *)data);
+}
+
+static void dump_servers(GList **servers)
+{
+ int i;
+
+ printf("SERVERS:\n");
+
+ if (servers == NULL) {
+ printf("\tNO SERVERS\n");
+ return;
+ }
+
+ for (i = 0; i < PACRUNNER_PROTOCOL_MAXIMUM_NUMBER; i++) {
+ printf("Protocol: %s\n", get_protocol_to_string(i));
+
+ if (servers[i] == NULL) {
+ printf("\tNONE\n");
+ continue;
+ }
+
+ g_list_foreach(servers[i], dump_proxy_server, NULL);
+ printf("\n");
+ }
+}
+
+static void print_help(void)
+{
+ printf("Manual Proxy configuration test tool\n"
+ "Usage:\n"
+ "-e,--excludes <list>: provides an exclusion list (optional)\n"
+ "-h,--help : prints this help message\n"
+ "-s,--servers <list>: provides the proxy server(s)
(mandatory)\n"
+ "-t,--test <list>: provides the URLs to test (mandatory)\n"
+ "list should be made like \"elt1,elt2\" and so on\n");
+}
+
+static struct option long_options[] =
+{
+ {"excludes", 1, 0, 'e'},
+ {"help", 0, 0, 'h'},
+ {"servers", 1, 0, 's'},
+ {"test", 1, 0, 't'},
+ {NULL, 0, 0, 0 }
+};
+
+static const char *short_options = "e:hs:t:";
+
+int main(int argc, char *argv[])
+{
+ int opt, option_index = 0;
+ char **excludes_list, **servers_list, **tests_list;
+ GList **excludes = NULL;
+ GList **servers = NULL;
+ char **url;
+
+ excludes_list = NULL;
+ servers_list = NULL;
+ tests_list = NULL;
+
+ while ((opt = getopt_long(argc, argv, short_options,
+ long_options, &option_index)) != -1) {
+ switch (opt) {
+ case 'e':
+ excludes_list = g_strsplit(optarg, ",", 0);
+ if (excludes_list == NULL)
+ exit(EXIT_FAILURE);
+
+ break;
+ case 'h':
+ print_help();
+ exit(EXIT_SUCCESS);
+
+ break;
+ case 's':
+ servers_list = g_strsplit(optarg, ",", 0);
+ if (servers_list == NULL)
+ exit(EXIT_FAILURE);
+
+ break;
+ case 't':
+ tests_list = g_strsplit(optarg, ",", 0);
+ if (tests_list == NULL)
+ exit(EXIT_FAILURE);
+
+ break;
+ case '?':
+ break;
+ default:
+ printf("Unknown option\n"
+ "please see --help for more informations\n");
+ exit(EXIT_FAILURE);
+
+ break;
+ }
+ }
+
+ if (servers_list == NULL || tests_list == NULL) {
+ printf("You must provide server(s) and test(s) options\n");
+ exit(EXIT_FAILURE);
+ }
+
+ excludes = __pacrunner_manual_create_excludes((const char **)
+ excludes_list);
+
+ servers = __pacrunner_manual_create_servers((const char **)
+ servers_list);
+ if (servers == NULL)
+ exit(EXIT_FAILURE);
+
+ dump_excludes(excludes);
+ dump_servers(servers);
+
+ g_strfreev(excludes_list);
+ g_strfreev(servers_list);
+
+ for (url = tests_list; *url != NULL; url++) {
+ char *proxy;
+
+ printf("Url: %s -> ", *url);
+
+ proxy = __pacrunner_manual_execute(*url, servers, excludes);
+ if (proxy == NULL)
+ printf("DIRECT\n");
+ else
+ printf("%s\n", proxy);
+ }
+
+ g_strfreev(tests_list);
+
+ __pacrunner_manual_destroy_excludes(excludes);
+ __pacrunner_manual_destroy_servers(servers);
+
+ return 0;
+}
--
1.7.3.4
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman