[tor-commits] [torsocks/master] Multiple changes accross the code base

dgoulet at torproject.org dgoulet at torproject.org
Fri Apr 4 22:40:25 UTC 2014


commit 501ee46377144fc1fc769c82fe77b67efd4c9e6c
Author: David Goulet <dgoulet at ev0ke.net>
Date:   Wed Jun 12 18:48:42 2013 -0400

    Multiple changes accross the code base
    
    This is a pretty big commit because a lot of inter connected things had
    to be changed across the code base.
    
    The config file part is completely reengineered because it turns out the
    torsocks.conf was not really "Tor centric" and was adding features that
    are IMHO out of the scope of torsocks. For now only two options are
    supported which are "TorAddress" and "TorPort" having a format like Tor
    config file has.
    
    The global configuration object is added also which is initialized
    within the constructor of the library using the new config file API.
    Some utils functions were added to support that as well.
    
    Also, the connection.c/.h is improved.
    
    At this commit, torsocks can parse a config file or use default values
    if none found, do logging and connect to Tor using only SOCKS5.
    
    Signed-off-by: David Goulet <dgoulet at ev0ke.net>
---
 doc/torsocks.conf        |   47 +--
 src/common/Makefile.am   |    3 +-
 src/common/config-file.c |  876 +++++++++-------------------------------------
 src/common/config-file.h |   71 ++--
 src/common/connection.c  |   93 ++++-
 src/common/connection.h  |   17 +-
 src/common/defaults.h    |   12 +-
 src/common/log.h         |    2 +-
 src/common/socks5.c      |   11 +-
 src/common/utils.c       |   99 ++++--
 src/common/utils.h       |    5 +-
 src/lib/Makefile.am      |    2 +-
 src/lib/torsocks.c       |   83 +++++
 src/lib/torsocks.h       |    4 +
 14 files changed, 483 insertions(+), 842 deletions(-)

diff --git a/doc/torsocks.conf b/doc/torsocks.conf
index 8cc1b2c..60eb697 100644
--- a/doc/torsocks.conf
+++ b/doc/torsocks.conf
@@ -2,16 +2,9 @@
 # with tor, which is providing a socks server on port 9050 by default.
 #
 # Lines beginning with # and blank lines are ignored
-#
-# The basic idea is to specify:
-#       - Local subnets - Networks that can be accessed directly without
-#                         assistance from a socks server
-#       - Paths - Paths are basically lists of networks and a socks server
-#                 which can be used to reach these networks
-#       - Default server - A socks server which should be used to access
-#                          networks for which no path is available
 # Much more documentation than provided in these comments can be found in
-# torsocks.conf(5) and usewithtor(1) manpages.
+#
+# torsocks.conf(5) and torsocks(1) manpages.
 
 # We specify local as 127.0.0.0 - 127.191.255.255 because the
 # Tor MAPADDRESS virtual IP range is the rest of net 127.
@@ -21,36 +14,8 @@ local = 127.128.0.0/255.192.0.0
 local = 169.254.0.0/255.255.0.0
 local = 172.16.0.0/255.240.0.0
 local = 192.168.0.0/255.255.0.0
-  
-# Default server
-# For connections that aren't to the local subnets 
-# the server at 127.0.0.1 should be used (again, hostnames could be used
-# too, see note above)
-server = 127.0.0.1
-
-# SOCKS server type defaults to 4
-#server_type = 5
-
-# The port defaults to 1080 but I've stated it here for clarity
-server_port = 9050
 
-# Username and password (if required on a SOCKSv5 server)
-#default_user =
-#default_pass =
-
-# Paths
-# For this example this machine needs to access 150.0.0.0/255.255.0.0 as
-# well as port 80 on the network 150.1.0.0/255.255.0.0 through
-# the socks 5 server at 10.1.7.25 (if this machines hostname was
-# "socks.hello.com" we could also specify that, unless --disable-hostnames
-# was specified to ./configure).
-
-#path {
-#        reaches = 150.0.0.0/255.255.0.0
-#        reaches = 150.1.0.0:80/255.255.0.0
-#        server = 10.1.7.25
-#        server_type = 5
-#        default_user = delius
-#        default_pass = hello
-#}
-#
+# Default Tor address and port. By default, Tor will listen on localhost for
+# any SOCKS connection and relay the traffic on the Tor network.
+TorAddress 127.0.0.1
+TorPort 9050
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index ab4d166..13d4d41 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -4,4 +4,5 @@ AM_CFLAGS = -fno-strict-aliasing
 
 noinst_LTLIBRARIES = libcommon.la
 libcommon_la_SOURCES = log.c log.h config-file.c config-file.h utils.c utils.h \
-                       compat.c compat.h socks5.c socks5.h
+                       compat.c compat.h socks5.c socks5.h \
+                       connection.c connection.h
diff --git a/src/common/config-file.c b/src/common/config-file.c
index 47f6a09..0a05325 100644
--- a/src/common/config-file.c
+++ b/src/common/config-file.c
@@ -17,690 +17,163 @@
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <arpa/inet.h>
-#include <errno.h>
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <config.h>
 
 #include "config-file.h"
 #include "log.h"
 #include "utils.h"
 
-/* Global configuration variables. */
-static struct config_server_entry *currentcontext = NULL;
+/*
+ * These are the torsocks.conf string values.
+ */
+static const char *conf_toraddr_str = "TorAddress";
+static const char *conf_torport_str = "TorPort";
 
-/* Check server entries (and establish defaults) */
-static int check_server(struct config_server_entry *server)
+/*
+ * Set the given string port in a configuration object.
+ *
+ * Return 0 on success or else a negative EINVAL if the port is equal to 0 or
+ * over 65535.
+ */
+static int set_tor_port(const char *port, struct configuration *config)
 {
-    /* Default to the default Tor Socks port */
-    if (server->port == 0) {
-        server->port = 9050;
-    }
-
-    /* Default to a presumably local installation of Tor */
-    if (server->address == NULL) {
-        server->address = strdup("127.0.0.1");
-    }
-
-    /* Default to SOCKS V4 */
-    if (server->type == 0) {
-        server->type = 4;
-    }
-
-    return(0);
-}
-
-static int handle_endpath(struct config_parsed *config, int lineno, int nowords) {
-
-	if (nowords != 1) {
-		ERR("Badly formed path close statement on line  %d in configuration"
-				"file (should look like \"}\")\n", lineno);
-	} else {
-		currentcontext = &(config->default_server);
-	}
-
-	/* We could perform some checking on the validty of data in */
-	/* the completed path here, but thats what verifyconf is    */
-	/* designed to do, no point in weighing down libtorsocks      */
-
-	return(0);
-}
-
-/* Construct a config_network_entry given a string like                             */
-/* "198.126.0.1[:portno[-portno]]/255.255.255.0"                      */
-int make_config_network_entry(char *value, struct config_network_entry **ent) {
-	char *ip;
-	char *subnet;
-	char *start_port = NULL;
-	char *end_port = NULL;
-	char *badchar;
-	char separator;
-	static char buf[200];
-	char *split;
-
-	/* Get a copy of the string so we can modify it */
-	strncpy(buf, value, sizeof(buf) - 1);
-	buf[sizeof(buf) - 1] = (char) 0;
-	split = buf;
-
-	/* Now rip it up */
-	ip = utils_strsplit(&separator, &split, "/:");
-	if (separator == ':') {
-		/* We have a start port */
-		start_port = utils_strsplit(&separator, &split, "-/");
-		if (separator == '-') 
-			/* We have an end port */
-			end_port = utils_strsplit(&separator, &split, "/");
-	}
-	subnet = utils_strsplit(NULL, &split, " \n");
-
-	if ((ip == NULL) || (subnet == NULL)) {
-		/* Network specification not validly constructed */
-		return(1);
-	}
-
-	/* Allocate the new entry */
-	if ((*ent = (struct config_network_entry *) malloc(sizeof(struct config_network_entry)))
-			== NULL) {
-		/* If we couldn't malloc some storage, leave */
-		exit(1);
-	}
-
-	DBG("New network entry for %s going to 0x%08x\n", ip, *ent);
-
-	if (!start_port)
-		(*ent)->start_port = 0;
-	if (!end_port)
-		(*ent)->end_port = 0;
-
-#ifdef HAVE_INET_ADDR
-	if (((*ent)->local_ip.s_addr = inet_addr(ip)) == -1) {
-#elif defined(HAVE_INET_ATON)
-		if (!(inet_aton(ip, &((*ent)->local_ip)))) {
-#endif
-			/* Badly constructed IP */
-			free(*ent);
-			return(2);
-		}
-#ifdef HAVE_INET_ADDR
-		else if (((*ent)->local_net.s_addr = inet_addr(subnet)) == -1) {
-#elif defined(HAVE_INET_ATON)
-			else if (!(inet_aton(subnet, &((*ent)->local_net)))) {
-#endif
-				/* Badly constructed subnet */
-				free(*ent);
-				return(3);
-			} else if (((*ent)->local_ip.s_addr &
-						(*ent)->local_net.s_addr) != 
-					(*ent)->local_ip.s_addr) {
-				/* Subnet and Ip != Ip */
-				free(*ent);
-				return(4);
-			} else if (start_port && 
-					(!((*ent)->start_port = strtol(start_port, &badchar, 10)) || 
-					 (*badchar != 0) || ((*ent)->start_port > 65535))) {
-				/* Bad start port */
-				free(*ent);
-				return(5);
-			} else if (end_port && 
-					(!((*ent)->end_port = strtol(end_port, &badchar, 10)) || 
-					 (*badchar != 0) || ((*ent)->end_port > 65535))) {
-				/* Bad end port */
-				free(*ent);
-				return(6);
-			} else if (((*ent)->start_port > (*ent)->end_port) && !(start_port && !end_port)) {
-				/* End port is less than start port */
-				free(*ent);
-				return(7);
-			}
-
-			if (start_port && !end_port)
-				(*ent)->end_port = (*ent)->start_port;
-
-			return(0);
-		}
-
-
-static int handle_reaches(int lineno, char *value) {
-	int rc;
-	struct config_network_entry *ent;
-
-	rc = make_config_network_entry(value, &ent);
-	switch(rc) {
-		case 1:
-			ERR("Local network specification (%s) is not validly "
-					"constructed in reach statement on line "
-					"%d in configuration "
-					"file\n", value, lineno);
-			return(0);
-			break;
-		case 2:
-			ERR("IP in reach statement "
-					"network specification (%s) is not valid on line "
-					"%d in configuration file\n", value, lineno);
-			return(0);
-			break;
-		case 3:
-			ERR("SUBNET in reach statement "
-					"network specification (%s) is not valid on "
-					"line %d in configuration file\n", value,
-					lineno);
-			return(0);
-			break;
-		case 4:
-			ERR("IP (%s) & ", inet_ntoa(ent->local_ip));
-			ERR("SUBNET (%s) != IP on line %d in "
-					"configuration file, ignored\n",
-					inet_ntoa(ent->local_net), lineno);
-			return(0);
-			break;
-		case 5:
-			ERR("Start port in reach statement "
-					"network specification (%s) is not valid on line "
-					"%d in configuration file\n", value, lineno);
-			return(0);
-			break;
-		case 6:
-			ERR("End port in reach statement "
-					"network specification (%s) is not valid on line "
-					"%d in configuration file\n", value, lineno);
-			return(0);
-			break;
-		case 7:
-			ERR("End port in reach statement "
-					"network specification (%s) is less than the start "
-					"port on line %d in configuration file\n", value, 
-					lineno);
-			return(0);
-			break;
-	}
-
-	/* The entry is valid so add it to linked list */
-	ent -> next = currentcontext -> reachnets;
-	currentcontext -> reachnets = ent;
+	int ret = 0;
+	char *endptr;
+	unsigned long _port;
 
-	return(0);
-}
+	assert(port);
+	assert(config);
 
-static int handle_server(struct config_parsed *config, int lineno, char *value) {
-	char *ip;
-
-	ip = utils_strsplit(NULL, &value, " ");
-
-	/* We don't verify this ip/hostname at this stage, */
-	/* its resolved immediately before use in torsocks.c */
-	if (currentcontext->address == NULL)
-		currentcontext->address = strdup(ip);
-	else {
-		if (currentcontext == &(config->default_server))
-			ERR("Only one default SOCKS server "
-					"may be specified at line %d in "
-					"configuration file\n", lineno);
-		else
-			ERR("Only one SOCKS server may be specified "
-					"per path on line %d in configuration "
-					"file. (Path begins on line %d)\n",
-					lineno, currentcontext->lineno);
+	/* Let's avoid a integer overflow here ;). */
+	_port = strtoul(port, &endptr, 10);
+	if (_port == 0 || _port > 65535) {
+		ret = -EINVAL;
+		ERR("Config file invalid port: %s", port);
+		goto error;
 	}
 
-	return(0);
-}
+	config->conf_file.tor_port = (in_port_t) _port;
 
-static int handle_port(struct config_parsed *config, int lineno, char *value) {
-
-	if (currentcontext->port != 0) {
-		if (currentcontext == &(config->default_server))
-			ERR("Server port may only be specified "
-					"once for default server, at line %d "
-					"in configuration file\n", lineno);
-		else
-			ERR("Server port may only be specified "
-					"once per path on line %d in configuration "
-					"file. (Path begins on line %d)\n",
-					lineno, currentcontext->lineno);
-	} else {
-		errno = 0;
-		currentcontext->port = (unsigned short int)
-			(strtol(value, (char **)NULL, 10));
-		if ((errno != 0) || (currentcontext->port == 0)) {
-			ERR("Invalid server port number "
-					"specified in configuration file "
-					"(%s) on line %d\n", value, lineno);
-			currentcontext->port = 0;
-		}
-	}
+	DBG("Config file setting tor port to %lu", _port);
 
-	return(0);
+error:
+	return ret;
 }
 
-static int handle_username(struct config_parsed *config, int lineno, char *value) {
-
-	if (currentcontext->username != NULL) {
-		if (currentcontext == &(config->default_server))
-			ERR("Default username may only be specified "
-					"once for default server, at line %d "
-					"in configuration file\n", lineno);
-		else
-			ERR("Default username may only be specified "
-					"once per path on line %d in configuration "
-					"file. (Path begins on line %d)\n",
-					lineno, currentcontext->lineno);
-	} else {
-		currentcontext->username = strdup(value);
-	}
-
-	return(0);
-}
-
-static int handle_password(struct config_parsed *config, int lineno, char *value) {
-
-	if (currentcontext->password != NULL) {
-		if (currentcontext == &(config->default_server))
-			ERR("Default password may only be specified "
-					"once for default server, at line %d "
-					"in configuration file\n", lineno);
-		else
-			ERR("Default password may only be specified "
-					"once per path on line %d in configuration "
-					"file. (Path begins on line %d)\n",
-					lineno, currentcontext->lineno);
-	} else {
-		currentcontext->password = strdup(value);
-	}
+/*
+ * Set the given string address in a configuration object.
+ *
+ * Return 0 on success or else a negative value. On error, the address was not
+ * recognized.
+ */
+static int set_tor_address(const char *addr, struct configuration *config)
+{
+	int ret;
 
-	return(0);
-}
+	assert(addr);
+	assert(config);
 
-static int handle_type(struct config_parsed *config, int lineno, char *value) {
-
-	if (currentcontext->type != 0) {
-		if (currentcontext == &(config->default_server))
-			ERR("Server type may only be specified "
-					"once for default server, at line %d "
-					"in configuration file\n", lineno);
-		else
-			ERR("Server type may only be specified "
-					"once per path on line %d in configuration "
-					"file. (Path begins on line %d)\n",
-					lineno, currentcontext->lineno);
+	ret = utils_is_address_ipv4(addr);
+	if (ret == 1 ) {
+		config->conf_file.tor_domain = CONNECTION_DOMAIN_INET;
 	} else {
-		errno = 0;
-		currentcontext->type = (int) strtol(value, (char **)NULL, 10);
-		if ((errno != 0) || (currentcontext->type == 0) ||
-				((currentcontext->type != 4) && (currentcontext->type != 5))) {
-			ERR("Invalid server type (%s) "
-					"specified in configuration file "
-					"on line %d, only 4 or 5 may be "
-					"specified\n", value, lineno);
-			currentcontext->type = 0;
+		ret = utils_is_address_ipv6(addr);
+		if (ret != 1) {
+			/* At this point, the addr is either v4 nor v6 so error. */
+			ERR("Config file unknown tor address: %s", addr);
+			goto error;
 		}
+		config->conf_file.tor_domain = CONNECTION_DOMAIN_INET6;
 	}
+	config->conf_file.tor_address = strdup(addr);
 
-	return(0);
-}
-
-static int handle_flag(char *value) 
-{
-	if(!strcasecmp(value, "true") || !strcasecmp(value, "yes")  
-			|| !strcmp(value, "1")) {
-		return 1;
-	} else if (!strcasecmp(value, "false") || !strcasecmp(value, "no") 
-			|| !strcmp(value, "0")) {
-		return 0;
-	} else {
-		return -1;
-	}
-}
-
-static int handle_tordns_enabled(struct config_parsed *config, int lineno,
-		char *value)
-{
-	int val = handle_flag(value);
-	if(val == -1) {
-		ERR("Invalid value %s supplied for tordns_enabled at "
-				"line %d in config file, IGNORED\n", value, lineno);
-	} else {
-		config->tordns_enabled = val;
-	}
-	return 0;
-}
+	DBG("Config file setting tor address to %s", addr);
+	ret = 0;
 
-static int handle_tordns_cache_size(struct config_parsed *config,
-		char *value)
-{
-	char *endptr;
-	long size = strtol(value, &endptr, 10);
-	if(*endptr != '\0') {
-		ERR("Error parsing integer value for "
-				"tordns_cache_size (%s), using default %d\n", 
-				value, config->tordns_cache_size);
-	} else if(size < 128) {
-		ERR("The value supplied for tordns_cache_size (%d) "
-				"is too small (<128), using default %d\n", size, 
-				config->tordns_cache_size);
-	} else if(size > 4096) {
-		ERR("The value supplied for tordns_cache_range (%d) "
-				"is too large (>4096), using default %d\n", size, 
-				config->tordns_cache_size);
-	} else {
-		config->tordns_cache_size = size;
-	}
-	return 0;
+error:
+	return ret;
 }
 
-static int handle_path(struct config_parsed *config, int lineno, int nowords, char *words[])
+/*
+ * Parse a single line of from a configuration file and set the value found in
+ * the configuration object.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int parse_config_line(const char *line, struct configuration *config)
 {
-	struct config_server_entry *newserver;
-
-	if ((nowords != 2) || (strcmp(words[1], "{"))) {
-		ERR("Badly formed path open statement on line %d "
-				"in configuration file (should look like "
-				"\"path {\")\n", lineno);
-	} else if (currentcontext != &(config->default_server)) {
-		/* You cannot nest path statements so check that */
-		/* the current context is default_server          */
-		ERR("Path statements cannot be nested on line %d "
-				"in configuration file\n", lineno);
+	int ret, nb_token;
+	char *tokens[DEFAULT_MAX_CONF_TOKEN];
+
+	assert(line);
+	assert(config);
+
+	/*
+	 * The line is tokenized and each token is NULL terminated.
+	 */
+	nb_token = utils_tokenize_ignore_comments(line, sizeof(tokens), tokens);
+	if (nb_token <= 0) {
+		/* Nothing on this line that is useful to parse. */
+		ret = 0;
+		goto end;
+	}
+
+	if (!strcmp(tokens[0], conf_toraddr_str)) {
+		ret = set_tor_address(tokens[1], config);
+		if (ret < 0) {
+			goto error;
+		}
+	} else if (!strcmp(tokens[0], conf_torport_str)) {
+		ret = set_tor_port(tokens[1], config);
+		if (ret < 0) {
+			goto error;
+		}
 	} else {
-		/* Open up a new config_server_entry, put it on the list   */
-		/* then set the current context                  */
-		if ((newserver = malloc(sizeof(*newserver))) == NULL)
-			exit(-1);
-
-		/* Initialize the structure */
-		DBG("New server structure from line %d in configuration file going "
-				"to 0x%08x\n", lineno, newserver);
-		memset(newserver, 0x0, sizeof(*newserver));
-		newserver->next = config->paths;
-		newserver->lineno = lineno;
-		config->paths = newserver;
-		currentcontext = newserver;
+		WARN("Config file contains unknown value: %s", line);
 	}
 
-	return(0);
-}
+	/* Everything went well. */
+	ret = 0;
 
-static int handle_local(struct config_parsed *config, int lineno, const char *value) {
-	int rc;
-	struct config_network_entry *ent;
-
-	if (currentcontext != &(config->default_server)) {
-		ERR("Local networks cannot be specified in path "
-				"block at line %d in configuration file. "
-				"(Path block started at line %d)\n",
-				lineno, currentcontext->lineno);
-		return(0);
-	}
-
-	rc = make_config_network_entry((char *)value, &ent);
-	switch(rc) {
-		case 1:
-			ERR("Local network specification (%s) is not validly "
-					"constructed on line %d in configuration "
-					"file\n", value, lineno);
-			return(0);
-			break;
-		case 2:
-			ERR("IP for local "
-					"network specification (%s) is not valid on line "
-					"%d in configuration file\n", value, lineno);
-			return(0);
-			break;
-		case 3:
-			ERR("SUBNET for "
-					"local network specification (%s) is not valid on "
-					"line %d in configuration file\n", value,
-					lineno);
-			return(0);
-			break;
-		case 4:
-			ERR("IP (%s) & ", inet_ntoa(ent->local_ip));
-			ERR("SUBNET (%s) != IP on line %d in "
-					"configuration file, ignored\n",
-					inet_ntoa(ent->local_net), lineno);
-			return(0);
-		case 5:
-		case 6:
-		case 7:
-			ERR("Port specification is invalid and "
-					"not allowed in local network specification "
-					"(%s) on line %d in configuration file\n",
-					value, lineno);
-			return(0);
-			break;
-	}
-
-	if (ent->start_port || ent->end_port) {
-		ERR("Port specification is "
-				"not allowed in local network specification "
-				"(%s) on line %d in configuration file\n",
-				value, lineno);
-		return(0);
-	}
-
-	/* The entry is valid so add it to linked list */
-	ent -> next = config->local_nets;
-	(config->local_nets) = ent;
-
-	return(0);
+end:
+error:
+	return ret;
 }
 
-static int handle_tordns_deadpool_range(struct config_parsed *config, int lineno, 
-		const char *value)
+/*
+ * Parse the configuration file with the given file pointer into the
+ * configuration object.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int parse_config_file(FILE *fp, struct configuration *config)
 {
-	int rc;
-	struct config_network_entry *ent;
-
-	if (config->tordns_deadpool_range != NULL) {
-		ERR("Only one 'deadpool' entry permitted, found a "
-				"second at line %d in configuration file.\n");
-		return(0);
-	}
-
-	if (currentcontext != &(config->default_server)) {
-		ERR("Deadpool cannot be specified in path "
-				"block at line %d in configuration file. "
-				"(Path block started at line %d)\n",
-				lineno, currentcontext->lineno);
-		return(0);
-	}
+	int ret = -1;
+	/* Usually, this value is 8192 on most Unix systems. */
+	char line[BUFSIZ];
+
+	assert(fp);
+	assert(config);
+
+	while (fgets(line, sizeof(line), fp) != NULL) {
+		/*
+		 * Remove the \n at the end of the buffer and replace it by a NULL
+		 * bytes so we handle the line without this useless char.
+		 */
+		if (strlen(line) > 0) {
+			line[strlen(line) - 1] = '\0';
+		}
 
-	rc = make_config_network_entry((char *)value, &ent);
-	/* This is copied from handle_local and should probably be folded into
-	   a generic whinge() function or something */
-	switch(rc) {
-		case 1:
-			ERR("The deadpool specification (%s) is not validly "
-					"constructed on line %d in configuration "
-					"file\n", value, lineno);
-			return(0);
-			break;
-		case 2:
-			ERR("IP for deadpool "
-					"network specification (%s) is not valid on line "
-					"%d in configuration file\n", value, lineno);
-			return(0);
-			break;
-		case 3:
-			ERR("SUBNET for " 
-					"deadpool network specification (%s) is not valid on "
-					"line %d in configuration file\n", value, 
-					lineno);
-			return(0);
-			break;
-		case 4:
-			ERR("IP (%s) & ", inet_ntoa(ent->local_ip));
-			ERR("SUBNET (%s) != IP on line %d in "
-					"configuration file, ignored\n",
-					inet_ntoa(ent->local_net), lineno);
-			return(0);
-		case 5:
-		case 6:
-		case 7:
-			ERR("Port specification is invalid and "
-					"not allowed in deadpool specification "
-					"(%s) on line %d in configuration file\n",
-					value, lineno);
-			return(0);
-			break;
-	}
-	if (ent->start_port || ent->end_port) {
-		ERR("Port specification is "
-				"not allowed in deadpool specification "
-				"(%s) on line %d in configuration file\n",
-				value, lineno);
-		return(0);
+		ret = parse_config_line(line, config);
+		if (ret < 0) {
+			goto error;
+		}
 	}
 
-	config->tordns_deadpool_range = ent;
-	return 0;
-}
-
-static int handle_line(struct config_parsed *config, char *line, int lineno)
-{
-    char *words[10];
-    static char savedline[CONFIG_MAXLINE];
-    int   nowords = 0, i;
-
-    /* Save the input string */
-    strncpy(savedline, line, CONFIG_MAXLINE - 1);
-    savedline[CONFIG_MAXLINE - 1] = (char) 0;
-    /* Tokenize the input string */
-    nowords = utils_tokenize_ignore_comments(line, 10, words);
-
-    /* Set the spare slots to an empty string to simplify */
-    /* processing                                         */
-    for (i = nowords; i < 10; i++)
-        words[i] = NULL;
-
-    if (nowords > 0) {
-        /* Now this can either be a "path" block starter or */
-        /* ender, otherwise it has to be a pair (<name> =   */
-        /* <value>)                                         */
-        if (!strcmp(words[0], "path")) {
-            handle_path(config, lineno, nowords, words);
-        } else if (!strcmp(words[0], "}")) {
-            handle_endpath(config, lineno, nowords);
-        } else {
-            /* Has to be a pair */
-            if ((nowords != 3) || (strcmp(words[1], "="))) {
-                ERR("Malformed configuration pair "
-                       "on line %d in configuration "
-                       "file, \"%s\"\n", lineno, savedline);
-            } else if (!strcmp(words[0], "reaches")) {
-                handle_reaches(lineno, words[2]);
-            } else if (!strcmp(words[0], "server")) {
-                handle_server(config, lineno, words[2]);
-            } else if (!strcmp(words[0], "server_port")) {
-                handle_port(config, lineno, words[2]);
-            } else if (!strcmp(words[0], "server_type")) {
-                handle_type(config, lineno, words[2]);
-            } else if (!strcmp(words[0], "default_user")) {
-                handle_username(config, lineno, words[2]);
-            } else if (!strcmp(words[0], "default_pass")) {
-                handle_password(config, lineno, words[2]);
-            } else if (!strcmp(words[0], "local")) {
-                handle_local(config, lineno, words[2]);
-            } else if (!strcmp(words[0], "tordns_enable")) {
-                handle_tordns_enabled(config, lineno, words[2]);
-            } else if (!strcmp(words[0], "tordns_deadpool_range")) {
-                handle_tordns_deadpool_range(config, lineno, words[2]);
-            } else if (!strcmp(words[0], "tordns_cache_size")) {
-                handle_tordns_cache_size(config, words[2]);
-            } else {
-                ERR("Invalid pair type (%s) specified "
-                       "on line %d in configuration file, "
-                       "\"%s\"\n", words[0], lineno,
-                       savedline);
-            }
-        }
-    }
-
-    return(0);
-}
-
-int is_local(struct config_parsed *config, struct in_addr *testip) {
-    struct config_network_entry *ent;
-    char buf[16];
-    inet_ntop(AF_INET, testip, buf, sizeof(buf));
-    DBG("checking if address: %s is local"
-                        "\n",
-                        buf);
-
-    for (ent = (config->local_nets); ent != NULL; ent = ent -> next) {
-        inet_ntop(AF_INET, &ent->local_net, buf, sizeof(buf));
-        DBG("local_net addr: %s"
-                            "\n",
-                            buf);
-        inet_ntop(AF_INET, &ent->local_ip, buf, sizeof(buf));
-        DBG("local_ip addr: %s"
-                            "\n",
-                            buf);
-        DBG("result testip->s_addr & ent->local_net.s_addr : %i"
-                            "\n",
-                            testip->s_addr & ent->local_net.s_addr);
-        DBG("result ent->local_ip.s_addr & ent->local_net.s_addr : %i"
-                            "\n",
-                            ent->local_ip.s_addr & ent->local_net.s_addr);
-        DBG("result ent->local_ip.s_addr : %i"
-                            "\n",
-                            ent->local_ip.s_addr);
-        if ((testip->s_addr & ent->local_net.s_addr) ==
-            (ent->local_ip.s_addr & ent->local_net.s_addr))  {
-            DBG("address: %s is local"
-                                "\n",
-                                buf);
-            return(0);
-        }
-    }
-
-    inet_ntop(AF_INET, testip, buf, sizeof(buf));
-    DBG("address: %s is not local"
-                        "\n",
-                        buf);
-    return(1);
-}
-
-/* Find the appropriate server to reach an ip */
-int pick_server(struct config_parsed *config, struct config_server_entry **ent, 
-                struct in_addr *ip, unsigned int port) {
-    struct config_network_entry *net;
-   char ipbuf[64];
-
-   DBG("Picking appropriate server for %s\n", inet_ntoa(*ip));
-    *ent = (config->paths);
-    while (*ent != NULL) {
-        /* Go through all the servers looking for one */
-        /* with a path to this network                */
-        DBG("Checking SOCKS server %s\n", 
-                ((*ent)->address ? (*ent)->address : "(No Address)"));
-        net = (*ent)->reachnets;
-        while (net != NULL) {
-         strcpy(ipbuf, inet_ntoa(net->local_ip));
-         DBG("Server can reach %s/%s\n", 
-                  ipbuf, inet_ntoa(net->local_net));
-            if (((ip->s_addr & net->local_net.s_addr) ==
-                (net->local_ip.s_addr & net->local_net.s_addr)) &&
-                (!net->start_port || 
-                ((net->start_port <= port) && (net->end_port >= port))))  
-            {
-                DBG("This server can reach target\n");
-                    /* Found the net, return */
-                    return(0);
-            }
-            net = net->next;
-        }
-        (*ent) = (*ent)->next;
-    }
-
-    *ent = &(config->default_server);
-
-    return(0);
+error:
+	return ret;
 }
 
 /*
@@ -708,83 +181,58 @@ int pick_server(struct config_parsed *config, struct config_server_entry **ent,
  *
  * Return 0 on success or else a negative value.
  */
-int config_file_read(const char *filename, struct config_parsed *config)
+int config_file_read(const char *filename, struct configuration *config)
 {
-	FILE *conf;
-	char line[CONFIG_MAXLINE];
-	int rc = 0;
-	int lineno = 1;
-	struct config_server_entry *server;
+	int ret;
+	FILE *fp;
+
+	assert(config);
 
 	/* Clear out the structure */
 	memset(config, 0x0, sizeof(*config));
 
-	/* Initialization */
-	currentcontext = &(config->default_server);
-
-	/* Tordns defaults */
-	config->tordns_cache_size = 256;
-	config->tordns_enabled = 1;
-
+	/* If a filename wasn't provided, use the default. */
+	if (!filename) {
+		filename = DEFAULT_CONF_FILE;
+		DBG("Config file not provided by TORSOCKS_CONF_FILE. Using default %s",
+				filename);
+	}
 
-	/* If a filename wasn't provided, use the default */
-	if (filename == NULL) {
-		strncpy(line, CONF_FILE, sizeof(line) - 1);
-		/* Insure null termination */
-		line[sizeof(line) - 1] = (char) 0;
-		filename = line;
-		DBG("Configuration file not provided by TORSOCKS_CONF_FILE "
-				"environment variable, attempting to use defaults in %s.\n", filename);
+	fp = fopen(filename, "r");
+	if (!fp) {
+		WARN("Config file not found: %s. Using default for Tor", filename);
+		(void) set_tor_address(DEFAULT_TOR_ADDRESS, config);
+		/*
+		 * We stringify the default value here so we can print the debug
+		 * statement in the function call to set port.
+		 */
+		(void) set_tor_port(XSTR(DEFAULT_TOR_PORT), config);
+		ret = 0;
+		goto end;
 	}
 
-	/* If there is no configuration file use reasonable defaults for Tor */
-	if ((conf = fopen(filename, "r")) == NULL) {
-		ERR("Could not open socks configuration file "
-				"(%s) errno (%d), assuming sensible defaults for Tor.\n", filename, errno);
-		memset(&(config->default_server), 0x0, sizeof(config->default_server));
-		check_server(&(config->default_server));
-		handle_local(config, 0, "127.0.0.0/255.0.0.0");
-		handle_local(config, 0, "10.0.0.0/255.0.0.0");
-		handle_local(config, 0, "192.168.0.0/255.255.0.0");
-		handle_local(config, 0, "172.16.0.0/255.240.0.0");
-		handle_local(config, 0, "169.254.0.0/255.255.0.0");
-		rc = 1; /* Severe errors reading configuration */
-	} else {
-		memset(&(config->default_server), 0x0, sizeof(config->default_server));
-
-		while (NULL != fgets(line, CONFIG_MAXLINE, conf)) {
-			/* This line _SHOULD_ end in \n so we  */
-			/* just chop off the \n and hand it on */
-			if (strlen(line) > 0)
-				line[strlen(line) - 1] = '\0';
-			handle_line(config, line, lineno);
-			lineno++;
-		}
-		fclose(conf);
-
-		/* Always add the 127.0.0.1/255.0.0.0 subnet to local */
-		handle_local(config, 0, "127.0.0.0/255.0.0.0");
-		/* We always consider this local, because many users' dsl
-		   routers act as their DNS. */
-		handle_local(config, 0, "10.0.0.0/255.0.0.0");
-		handle_local(config, 0, "192.168.0.0/255.255.0.0");
-		handle_local(config, 0, "172.16.0.0/255.240.0.0");
-		handle_local(config, 0, "169.254.0.0/255.255.0.0");
-		handle_local(config, 0, "192.168.0.0/255.255.0.0");
-
-		/* Check default server */
-		check_server(&(config->default_server));
-		server = (config->paths);
-		while (server != NULL) {
-			check_server(server);
-			server = server->next;
-		}
+	ret = parse_config_file(fp, config);
+	if (ret < 0) {
+		goto error;
 	}
 
-	/* Initialize tordns deadpool_range if not supplied */
-	if(config->tordns_deadpool_range == NULL) {
-		handle_tordns_deadpool_range(config, 0, "127.0.69.0/255.255.255.0");
+	DBG("Config file %s opened and parsed.", filename);
+
+end:
+error:
+	if (fp) {
+		fclose(fp);
 	}
+	return ret;
+}
+
+/*
+ * Free everything inside a configuration file object. It is the caller
+ * responsability to free the object if needed.
+ */
+void config_file_destroy(struct config_file *conf)
+{
+	assert(conf);
 
-	return(rc);
+	free(conf->tor_address);
 }
diff --git a/src/common/config-file.h b/src/common/config-file.h
index dcd3a58..b0c2e84 100644
--- a/src/common/config-file.h
+++ b/src/common/config-file.h
@@ -22,64 +22,37 @@
 
 #include <netinet/in.h>
 
-/* Max length of a configuration line. */
-#define CONFIG_MAXLINE BUFSIZ
+#include "connection.h"
 
 /*
- * Structure representing one server entry specified in the config.
+ * Represent the values in a configuration file (torsocks.conf). Basically,
+ * this is the data structure of a parsed config file.
  */
-struct config_server_entry {
-	/* Line number in conf file this path started on. */
-    int lineno;
-	/* Address/hostname of server. */
-    const char *address;
-	/* Port number of server. */
-    in_port_t port;
-	/* Type of server (4/5). */
-    int type;
-	/* Username for this socks server. */
-    const char *username;
-	/* Password for this socks server. */
-    const char *password;
-	/* Linked list of nets from this serveri. */
-    struct config_network_entry *reachnets;
-	/* Pointer to next server entry. */
-    struct config_server_entry *next;
-};
-
-/*
- * Structure representing a network.
- */
-struct config_network_entry {
-	/* Base IP of the network */
-   struct in_addr local_ip;
-   /* Mask for the network */
-   struct in_addr local_net;
-   /* Range of ports for the network */
-   in_port_t start_port;
-   in_port_t end_port;
-   /* Pointer to next network entry */
-   struct config_network_entry *next;
+struct config_file {
+	/* The tor address is inet or inet 6. */
+	enum connection_domain tor_domain;
+	/* The IP of the Tor SOCKS. */
+	char *tor_address;
+	/* The port of the Tor SOCKS. */
+	in_port_t tor_port;
 };
 
 /*
  * Structure representing a complete parsed file.
  */
-struct config_parsed {
-   struct config_network_entry *local_nets;
-   struct config_server_entry default_server;
-   struct config_server_entry *paths;
-   int tordns_enabled;
-   int tordns_failopen;
-   unsigned int tordns_cache_size;
-   struct config_network_entry *tordns_deadpool_range;
+struct configuration {
+	/*
+	 * Parsed config file (torsocks.conf).
+	 */
+	struct config_file conf_file;
+
+	/*
+	 * Socks5 address so basically where to connect to Tor.
+	 */
+	struct connection_addr socks5_addr;
 };
 
-/* Functions provided by parser module */
-int config_file_read(const char *filename, struct config_parsed *config);
-
-int is_local(struct config_parsed *, struct in_addr *);
-int pick_server(struct config_parsed *, struct config_server_entry **, struct in_addr *, unsigned int port);
-char *strsplit(char *separator, char **text, const char *search);
+int config_file_read(const char *filename, struct configuration *config);
+void config_file_destroy(struct config_file *conf);
 
 #endif /* CONFIG_FILE_H */
diff --git a/src/common/connection.c b/src/common/connection.c
index 0831340..f19d289 100644
--- a/src/common/connection.c
+++ b/src/common/connection.c
@@ -15,16 +15,82 @@
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include <arpa/inet.h>
+#include <assert.h>
+#include <stdlib.h>
+
 #include "connection.h"
+#include "macros.h"
+
+/*
+ * Set an already allocated connection address using the given IPv4/6 address,
+ * domain and port.
+ *
+ * Return 0 on success or else a negative value.
+ */
+int connection_addr_set(enum connection_domain domain, const char *ip,
+		in_port_t port, struct connection_addr *addr)
+{
+	int ret;
+
+	assert(ip);
+	assert(addr);
+
+	if (port == 0 || port >= 65535) {
+		ret = -EINVAL;
+		ERR("Connection addr set port out of range: %d", port);
+		goto error;
+	}
+
+	memset(addr, 0, sizeof(*addr));
+
+	switch (domain) {
+	case CONNECTION_DOMAIN_INET:
+		addr->domain = domain;
+		addr->u.sin.sin_family = AF_INET;
+		addr->u.sin.sin_port = htons(port);
+		ret = inet_pton(addr->u.sin.sin_family, ip,
+				&addr->u.sin.sin_addr);
+		if (ret != 1) {
+			PERROR("Connection addr set inet_pton");
+			ret = -EINVAL;
+			goto error;
+		}
+		break;
+	case CONNECTION_DOMAIN_INET6:
+		addr->domain = domain;
+		addr->u.sin6.sin6_family = AF_INET6;
+		addr->u.sin6.sin6_port = htons(port);
+		ret = inet_pton(addr->u.sin6.sin6_family, ip,
+				&addr->u.sin6.sin6_addr);
+		if (ret != 1) {
+			PERROR("Connection addr6 set inet_pton");
+			ret = -EINVAL;
+			goto error;
+		}
+		break;
+	default:
+		ERR("Connection addr set unknown domain %d", domain);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	/* Everything is set and good. */
+	ret = 0;
+
+error:
+	return ret;
+}
 
 /*
  * Create a new connection with the given fd and destination address.
  *
  * Return a newly allocated connection object or else NULL.
  */
-struct connection *connection_create(int fd, struct sockaddr_in *dest)
+struct connection *connection_create(int fd, enum connection_domain domain,
+		struct sockaddr *dest)
 {
-	struct connection *conn;
+	struct connection *conn = NULL;
 
 	assert(dest);
 
@@ -34,12 +100,24 @@ struct connection *connection_create(int fd, struct sockaddr_in *dest)
 		goto error;
 	}
 
+	switch (domain) {
+	case CONNECTION_DOMAIN_INET:
+		memcpy(&conn->dest_addr.u.sin, dest, sizeof(conn->dest_addr.u.sin));
+		break;
+	case CONNECTION_DOMAIN_INET6:
+		memcpy(&conn->dest_addr.u.sin6, dest, sizeof(conn->dest_addr.u.sin6));
+		break;
+	default:
+		ERR("Connection domain unknown %d", domain);
+		goto error;
+	}
+
 	conn->fd = fd;
-	memcpy(conn->dest_addr, dest, sizeof(conn->dest_addr));
 
 	return conn;
 
 error:
+	free(conn);
 	return NULL;
 }
 
@@ -53,8 +131,13 @@ void connection_destroy(struct connection *conn)
 	}
 
 	/* Remove from the double linked list. */
-	conn->prev->next = conn->next;
-	conn->next->prev = conn->prev;
+	if (conn->prev) {
+		conn->prev->next = conn->next;
+	}
+
+	if (conn->next) {
+		conn->next->prev = conn->prev;
+	}
 
 	free(conn);
 }
diff --git a/src/common/connection.h b/src/common/connection.h
index 75c3945..18b55ce 100644
--- a/src/common/connection.h
+++ b/src/common/connection.h
@@ -29,6 +29,9 @@ enum connection_domain {
 	CONNECTION_DOMAIN_INET6	= 2,
 };
 
+/*
+ * Connection address which both supports IPv4 and IPv6.
+ */
 struct connection_addr {
 	enum connection_domain domain;
 	union {
@@ -37,13 +40,14 @@ struct connection_addr {
 	} u;
 };
 
+/*
+ * Connection object representing a connect we did to the Tor network from a
+ * connect(2) hijacked call.
+ */
 struct connection {
 	/* Socket fd and also unique ID. */
 	int fd;
 
-	/* Location of the SOCKS5 server. */
-	struct connection_addr socks5_addr;
-
 	/* Remote destination that passes through Tor. */
 	struct connection_addr dest_addr;
 
@@ -51,4 +55,11 @@ struct connection {
 	struct connection *next, *prev;
 };
 
+int connection_addr_set(enum connection_domain domain, const char *ip,
+		in_port_t port, struct connection_addr *addr);
+
+struct connection *connection_create(int fd, enum connection_domain domain,
+		struct sockaddr *dest);
+void connection_destroy(struct connection *conn);
+
 #endif /* TORSOCKS_CONNECTION_H */
diff --git a/src/common/defaults.h b/src/common/defaults.h
index 3f4c8d6..c127eec 100644
--- a/src/common/defaults.h
+++ b/src/common/defaults.h
@@ -18,11 +18,12 @@
 #ifndef TORSOCKS_DEFAULTS_H
 #define TORSOCKS_DEFAULTS_H
 
+#include "connection.h"
 #include "log.h"
 
 #define DEFAULT_TOR_PORT	9050
 #define DEFAULT_TOR_ADDRESS	"127.0.0.1"
-#define DEFAULT_TOR_SOCKS	5
+#define DEFAULT_TOR_DOMAIN  CONNECTION_DOMAIN_INET
 
 /* Logging defaults. */
 #define DEFAULT_LOG_LEVEL_ENV		"TORSOCKS_LOG_LEVEL"
@@ -37,4 +38,13 @@
  */
 #define DEFAULT_DOMAIN_NAME_SIZE	255
 
+#define DEFAULT_CONF_FILE			"/etc/torsocks.conf"
+#define DEFAULT_CONF_FILE_ENV		"TORSOCKS_CONF_FILE"
+
+/*
+ * Maximum number of token in a single line of the torsocks configuration file.
+ * For instance, "TorAddress 127.0.0.1" is two tokens.
+ */
+#define DEFAULT_MAX_CONF_TOKEN		5
+
 #endif /* TORSOCKS_DEFAULTS_H */
diff --git a/src/common/log.h b/src/common/log.h
index 29460df..0423aee 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -65,7 +65,7 @@ void log_destroy(void);
 
 #define MSG(fmt, args...) __tsocks_print(MSGNOTICE, fmt "\n", ## args)
 #define ERR(fmt, args...) _ERRMSG("ERROR", MSGERR, fmt, ## args)
-#define WARN(fmt, args...) _ERRMSG("Warning", MSGWARN, fmt, ## args)
+#define WARN(fmt, args...) _ERRMSG("WARNING", MSGWARN, fmt, ## args)
 #define DBG(fmt, args...) _ERRMSG("DEBUG", MSGDEBUG, fmt, ## args)
 
 /*
diff --git a/src/common/socks5.c b/src/common/socks5.c
index 817f120..eb3baef 100644
--- a/src/common/socks5.c
+++ b/src/common/socks5.c
@@ -112,7 +112,7 @@ error:
 }
 
 /*
- * Connect to socks5 server address in the connection object.
+ * Connect to socks5 server address from the global configuration.
  *
  * Return 0 on success or else a negative value.
  */
@@ -124,15 +124,16 @@ int socks5_connect(struct connection *conn)
 	assert(conn);
 	assert(conn->fd >= 0);
 
-	switch (conn->socks5_addr.domain) {
+	switch (tsocks_config.socks5_addr.domain) {
 	case CONNECTION_DOMAIN_INET:
-		socks5_addr = (struct sockaddr *) &conn->socks5_addr.u.sin;
+		socks5_addr = (struct sockaddr *) &tsocks_config.socks5_addr.u.sin;
 		break;
 	case CONNECTION_DOMAIN_INET6:
-		socks5_addr = (struct sockaddr *) &conn->socks5_addr.u.sin6;
+		socks5_addr = (struct sockaddr *) &tsocks_config.socks5_addr.u.sin6;
 		break;
 	default:
-		ERR("Socks5 connect domain unknown %d", conn->socks5_addr.domain);
+		ERR("Socks5 connect domain unknown %d",
+				tsocks_config.socks5_addr.domain);
 		assert(0);
 		ret = -EBADF;
 		goto error;
diff --git a/src/common/utils.c b/src/common/utils.c
index 3c537fc..f041cd1 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -17,42 +17,101 @@
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "macros.h"
 #include "utils.h"
 
 /*
+ * Return 1 if the given IP belongs in the af domain else return a negative
+ * value.
+ */
+static int check_addr(const char *ip, int af)
+{
+	int ret = 0;
+	char buf[128];
+
+	assert(ip);
+
+	ret = inet_pton(af, ip, buf);
+	if (ret != 1) {
+		ret = -1;
+	}
+
+	return ret;
+}
+
+/*
+ * Return 1 if the given IP is an IPv4.
+ */
+ATTR_HIDDEN
+int utils_is_address_ipv4(const char *ip)
+{
+	return check_addr(ip, AF_INET);
+}
+
+/*
+ * Return 1 if the given IP is an IPv6.
+ */
+ATTR_HIDDEN
+int utils_is_address_ipv6(const char *ip)
+{
+	return check_addr(ip, AF_INET6);
+}
+
+/*
  * This routines breaks up input lines into tokens and places these tokens into
  * the array specified by tokens
  *
  * Return the number of token plus one set in the given array.
  */
 ATTR_HIDDEN
-int utils_tokenize_ignore_comments(char *line, int arrsize, char **tokens)
+int utils_tokenize_ignore_comments(const char *_line, size_t size, char **tokens)
 {
-	int tokenno = -1;
-	int finished = 0;
-
-	/* Whitespace is ignored before and after tokens     */
-	while ((tokenno < (arrsize - 1)) &&
-			(line = line + strspn(line, " \t")) &&
-			(*line != (char) 0) &&
-			(!finished)) {
-		tokenno++;
-		tokens[tokenno] = line;
-		line = line + strcspn(line, " \t");
-		*line = '\0';
-		line++;
-
-		/* We ignore everything after a # */
-		if (*tokens[tokenno] == '#') {
-			finished = 1;
-			tokenno--;
+	int ret, i = 0, argc = 0;
+	char *c, *line = NULL;
+
+	assert(_line);
+	assert(tokens);
+
+	line = strdup(_line);
+
+	/* Ignore line if it starts with a # meaning a comment. */
+	if (*line == '#') {
+		goto end;
+	}
+
+	/* Count number of token. If larger than size, we return an error. */
+	c = line;
+	while ((c = strchr(c + 1, ' '))) {
+		/* Skip consecutive spaces. */
+		if (*(c + 1) == ' ') {
+			continue;
 		}
+		argc++;
+	}
+
+	if (argc > size) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	c = strtok(line, " \t");
+	while (c != NULL) {
+		tokens[i] = strdup(c);
+		c = strtok(NULL, " \t");
+		i++;
 	}
 
-	return tokenno + 1;
+end:
+	ret = i;
+error:
+	free(line);
+	return ret;
 }
 
 /*
diff --git a/src/common/utils.h b/src/common/utils.h
index 26a5092..f6a25e9 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -23,6 +23,9 @@
 #include <netinet/in.h>
 
 char *utils_strsplit(char *separator, char **text, const char *search);
-int utils_tokenize_ignore_comments(char *line, int arrsize, char **tokens);
+int utils_tokenize_ignore_comments(const char *_line, size_t size, char **tokens);
+
+int utils_is_address_ipv4(const char *ip);
+int utils_is_address_ipv6(const char *ip);
 
 #endif /* TORSOCKS_UTILS_H */
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 7a1586d..3c7b3df 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,5 +1,5 @@
 AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src -I$(builddir)
-AM_CFLAGS = -fno-strict-aliasing
+#AM_CFLAGS = -fno-strict-aliasing
 
 libdir = @libdir@/torsocks
 
diff --git a/src/lib/torsocks.c b/src/lib/torsocks.c
index b927201..9d7408f 100644
--- a/src/lib/torsocks.c
+++ b/src/lib/torsocks.c
@@ -21,12 +21,23 @@
 #include <dlfcn.h>
 #include <stdlib.h>
 
+#include <common/config-file.h>
+#include <common/connection.h>
 #include <common/defaults.h>
 #include <common/log.h>
+#include <common/socks5.h>
 
 #include "torsocks.h"
 
 /*
+ * Global configuration of torsocks taken from the configuration file or set
+ * with the defaults. This is initialized in the constructor once and only
+ * once. Once done, this object is *immutable* thus no locking is needed to
+ * read this object as long as there is not write action.
+ */
+struct configuration tsocks_config;
+
+/*
  * Set to 1 if the binary is set with suid or 0 if not. This is set once during
  * initialization so after that it can be read without any protection.
  */
@@ -66,6 +77,63 @@ static void *find_libc_symbol(const char *symbol,
 }
 
 /*
+ * Initialize torsocks configuration from a given conf file or the default one.
+ */
+static void init_config(void)
+{
+	int ret;
+	const char *filename = NULL;
+
+	if (!is_suid) {
+		filename = getenv("TORSOCKS_CONF_FILE");
+	}
+
+	ret  = config_file_read(filename, &tsocks_config);
+	if (ret < 0) {
+		/*
+		 * Failing to get the configuration means torsocks can not function
+		 * properly so stops everything.
+		 */
+		clean_exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * Setup configuration from config file. Use defaults if some attributes
+	 * are missing.
+	 */
+	if (!tsocks_config.conf_file.tor_address) {
+		tsocks_config.conf_file.tor_address = strdup(DEFAULT_TOR_ADDRESS);
+	}
+	if (tsocks_config.conf_file.tor_port == 0) {
+		tsocks_config.conf_file.tor_port = DEFAULT_TOR_PORT;
+	}
+	if (tsocks_config.conf_file.tor_domain == 0) {
+		tsocks_config.conf_file.tor_domain = DEFAULT_TOR_DOMAIN;
+	}
+
+	/* Create the Tor SOCKS5 connection address. */
+	ret = connection_addr_set(tsocks_config.conf_file.tor_domain,
+			tsocks_config.conf_file.tor_address,
+			tsocks_config.conf_file.tor_port, &tsocks_config.socks5_addr);
+	if (ret < 0) {
+		/*
+		 * Without a valid connection address object to Tor well torsocks can't
+		 * work properly at all so abort everything.
+		 */
+		clean_exit(EXIT_FAILURE);
+	}
+}
+
+/*
+ * Save all the original libc function calls that torsocks needs.
+ */
+static void init_libc_symbols(void)
+{
+	tsocks_libc_connect = find_libc_symbol(LIBC_CONNECT_NAME_STR,
+			TSOCKS_SYM_EXIT_NOT_FOUND);
+}
+
+/*
  * Initialize logging subsytem using either the default values or the one given
  * by the environment variables.
  */
@@ -119,6 +187,17 @@ static void __attribute__((constructor)) tsocks_init(void)
 	is_suid = (getuid() != geteuid());
 
 	init_logging();
+
+	/*
+	 * We need to save libc symbols *before* we override them so torsocks can
+	 * use the original libc calls.
+	 */
+	init_libc_symbols();
+
+	/*
+	 * Read configuration file and set the global config.
+	 */
+	init_config();
 }
 
 /*
@@ -126,10 +205,14 @@ static void __attribute__((constructor)) tsocks_init(void)
  */
 static void __attribute__((destructor)) tsocks_exit(void)
 {
+	/* Cleanup allocated memory in the config file. */
+	config_file_destroy(&tsocks_config.conf_file);
 	/* Clean up logging. */
 	log_destroy();
 }
 
+#include <arpa/inet.h>
+
 /*
  * Torsocks call for connect(2).
  */
diff --git a/src/lib/torsocks.h b/src/lib/torsocks.h
index 3d0b1b6..14d0694 100644
--- a/src/lib/torsocks.h
+++ b/src/lib/torsocks.h
@@ -21,6 +21,7 @@
 #define TORSOCKS_H
 
 #include <common/compat.h>
+#include <common/config-file.h>
 
 #define TSOCKS_LIBC_DECL(name, type, sig) \
 	type (*tsocks_libc_##name)(sig);
@@ -56,4 +57,7 @@ enum tsocks_sym_action {
 	TSOCKS_SYM_EXIT_NOT_FOUND	= 1,
 };
 
+/* Global configuration of torsocks. */
+extern struct configuration tsocks_config;
+
 #endif /* TORSOCKS_H */





More information about the tor-commits mailing list