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

Reply via email to