Allow a unix: address to contain a C-style quoted string.

Feature 18753 -- all this to allow spaces.
This commit is contained in:
Nick Mathewson 2016-10-03 16:32:00 -04:00
parent 684500519d
commit 05aed5b635
9 changed files with 352 additions and 82 deletions

6
changes/feature18753 Normal file
View File

@ -0,0 +1,6 @@
o Minor features (unix domain sockets):
- When configuring a unix domain socket for a SocksPort,
ControlPort, or Hidden service, you can now wrap the address
in quotes, using C-style escapes inside the quotes. This
allows unix domain socket paths to contain spaces.

View File

@ -323,6 +323,8 @@ GENERAL OPTIONS
any process on the local host to control it. (Setting both authentication any process on the local host to control it. (Setting both authentication
methods means either method is sufficient to authenticate to Tor.) This methods means either method is sufficient to authenticate to Tor.) This
option is required for many Tor controllers; most use the value of 9051. option is required for many Tor controllers; most use the value of 9051.
If a unix domain socket is used, you may quote the path using standard
C escape sequences.
Set it to "auto" to have Tor pick a port for you. (Default: 0) + Set it to "auto" to have Tor pick a port for you. (Default: 0) +
+ +
Recognized flags are... Recognized flags are...
@ -1032,7 +1034,9 @@ The following options are useful only for clients (that is, if
applications. Set this to 0 if you don't want to allow application applications. Set this to 0 if you don't want to allow application
connections via SOCKS. Set it to "auto" to have Tor pick a port for connections via SOCKS. Set it to "auto" to have Tor pick a port for
you. This directive can be specified multiple times to bind you. This directive can be specified multiple times to bind
to multiple addresses/ports. (Default: 9050) + to multiple addresses/ports. If a unix domain socket is used, you may
quote the path using standard C escape sequences.
(Default: 9050) +
+ +
NOTE: Although this option allows you to specify an IP address NOTE: Although this option allows you to specify an IP address
other than localhost, you should do so only with extreme caution. other than localhost, you should do so only with extreme caution.
@ -2342,7 +2346,8 @@ The following options are used to configure a hidden service.
recent HiddenServiceDir. By default, this option maps the virtual port to recent HiddenServiceDir. By default, this option maps the virtual port to
the same port on 127.0.0.1 over TCP. You may override the target port, the same port on 127.0.0.1 over TCP. You may override the target port,
address, or both by specifying a target of addr, port, addr:port, or address, or both by specifying a target of addr, port, addr:port, or
**unix:**__path__. (You can specify an IPv6 target as [addr]:port.) **unix:**__path__. (You can specify an IPv6 target as [addr]:port. Unix
paths may be quoted, and may use standard C escapes.)
You may also have multiple lines with the same VIRTPORT: when a user You may also have multiple lines with the same VIRTPORT: when a user
connects to that VIRTPORT, one of the TARGETs from those lines will be connects to that VIRTPORT, one of the TARGETs from those lines will be
chosen at random. chosen at random.

View File

@ -2906,7 +2906,7 @@ read_file_to_str, (const char *filename, int flags, struct stat *stat_out))
* provided), and return a pointer to the position in <b>s</b> immediately * provided), and return a pointer to the position in <b>s</b> immediately
* after the string. On failure, return NULL. * after the string. On failure, return NULL.
*/ */
static const char * const char *
unescape_string(const char *s, char **result, size_t *size_out) unescape_string(const char *s, char **result, size_t *size_out)
{ {
const char *cp; const char *cp;

View File

@ -385,6 +385,7 @@ MOCK_DECL_ATTR(char *, read_file_to_str,
char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read,
size_t *sz_out) size_t *sz_out)
ATTR_MALLOC; ATTR_MALLOC;
const char *unescape_string(const char *s, char **result, size_t *size_out);
const char *parse_config_line_from_str_verbose(const char *line, const char *parse_config_line_from_str_verbose(const char *line,
char **key_out, char **value_out, char **key_out, char **value_out,
const char **err_out); const char **err_out);

View File

@ -68,6 +68,9 @@
/* Prefix used to indicate a Unix socket in a FooPort configuration. */ /* Prefix used to indicate a Unix socket in a FooPort configuration. */
static const char unix_socket_prefix[] = "unix:"; static const char unix_socket_prefix[] = "unix:";
/* Prefix used to indicate a Unix socket with spaces in it, in a FooPort
* configuration. */
static const char unix_q_socket_prefix[] = "unix:\"";
/** A list of abbreviations and aliases to map command-line options, obsolete /** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */ * option names, or alternative option names, to their current values. */
@ -6288,55 +6291,62 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid_nonlocal)
} SMARTLIST_FOREACH_END(port); } SMARTLIST_FOREACH_END(port);
} }
#ifdef HAVE_SYS_UN_H /**
* Take a string (<b>line</b>) that begins with either an address:port, a
/** Parse the given <b>addrport</b> and set <b>path_out</b> if a Unix socket * port, or an AF_UNIX address, optionally quoted, prefixed with
* path is found. Return 0 on success. On error, a negative value is * "unix:". Parse that line, and on success, set <b>addrport_out</b> to a new
* returned, -ENOENT if no Unix statement found, -EINVAL if the socket path * string containing the beginning portion (without prefix). Iff there was a
* is empty and -ENOSYS if AF_UNIX is not supported (see function in the * unix: prefix, set <b>is_unix_out</b> to true. On success, also set
* #else statement below). */ * <b>rest_out</b> to point to the part of the line after the address portion.
*
* Return 0 on success, -1 on failure.
*/
int int
config_parse_unix_port(const char *addrport, char **path_out) port_cfg_line_extract_addrport(const char *line,
char **addrport_out,
int *is_unix_out,
const char **rest_out)
{ {
tor_assert(path_out); tor_assert(line);
tor_assert(addrport); tor_assert(addrport_out);
tor_assert(is_unix_out);
tor_assert(rest_out);
if (strcmpstart(addrport, unix_socket_prefix)) { line = eat_whitespace(line);
/* Not a Unix socket path. */
return -ENOENT; if (!strcmpstart(line, unix_q_socket_prefix)) {
// It starts with unix:"
size_t sz;
*is_unix_out = 1;
*addrport_out = NULL;
line += strlen(unix_socket_prefix); /*No q: Keep the quote */
*rest_out = unescape_string(line, addrport_out, &sz);
if (!*rest_out || (*addrport_out && sz != strlen(*addrport_out))) {
tor_free(*addrport_out);
return -1;
}
*rest_out = eat_whitespace(*rest_out);
return 0;
} else {
// Is there a unix: prefix?
if (!strcmpstart(line, unix_socket_prefix)) {
line += strlen(unix_socket_prefix);
*is_unix_out = 1;
} else {
*is_unix_out = 0;
}
const char *end = find_whitespace(line);
if (BUG(!end)) {
end = strchr(line, '\0'); // LCOV_EXCL_LINE -- this can't be NULL
}
tor_assert(end && end >= line);
*addrport_out = tor_strndup(line, end - line);
*rest_out = eat_whitespace(end);
return 0;
} }
if (strlen(addrport + strlen(unix_socket_prefix)) == 0) {
/* Empty socket path, not very usable. */
return -EINVAL;
}
*path_out = tor_strdup(addrport + strlen(unix_socket_prefix));
return 0;
} }
#else /* defined(HAVE_SYS_UN_H) */
int
config_parse_unix_port(const char *addrport, char **path_out)
{
tor_assert(path_out);
tor_assert(addrport);
if (strcmpstart(addrport, unix_socket_prefix)) {
/* Not a Unix socket path. */
return -ENOENT;
}
log_warn(LD_CONFIG,
"Port configuration %s is for an AF_UNIX socket, but we have no"
"support available on this platform",
escaped(addrport));
return -ENOSYS;
}
#endif /* defined(HAVE_SYS_UN_H) */
static void static void
warn_client_dns_cache(const char *option, int disabling) warn_client_dns_cache(const char *option, int disabling)
{ {
@ -6515,16 +6525,16 @@ parse_port_config(smartlist_t *out,
/* At last we can actually parse the FooPort lines. The syntax is: /* At last we can actually parse the FooPort lines. The syntax is:
* [Addr:](Port|auto) [Options].*/ * [Addr:](Port|auto) [Options].*/
elts = smartlist_new(); elts = smartlist_new();
char *addrport = NULL;
for (; ports; ports = ports->next) { for (; ports; ports = ports->next) {
tor_addr_t addr; tor_addr_t addr;
int port, ret; int port;
int sessiongroup = SESSION_GROUP_UNSET; int sessiongroup = SESSION_GROUP_UNSET;
unsigned isolation = ISO_DEFAULT; unsigned isolation = ISO_DEFAULT;
int prefer_no_auth = 0; int prefer_no_auth = 0;
int socks_iso_keep_alive = 0; int socks_iso_keep_alive = 0;
char *addrport;
uint16_t ptmp=0; uint16_t ptmp=0;
int ok; int ok;
/* This must be kept in sync with port_cfg_new's defaults */ /* This must be kept in sync with port_cfg_new's defaults */
@ -6538,23 +6548,31 @@ parse_port_config(smartlist_t *out,
relax_dirmode_check = 0, relax_dirmode_check = 0,
has_used_unix_socket_only_option = 0; has_used_unix_socket_only_option = 0;
smartlist_split_string(elts, ports->value, NULL, int is_unix_tagged_addr = 0;
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); const char *rest_of_line = NULL;
if (smartlist_len(elts) == 0) { if (port_cfg_line_extract_addrport(ports->value,
log_warn(LD_CONFIG, "Invalid %sPort line with no value", portname); &addrport, &is_unix_tagged_addr, &rest_of_line)<0) {
log_warn(LD_CONFIG, "Invalid %sPort line with unparsable address",
portname);
goto err;
}
if (strlen(addrport) == 0) {
log_warn(LD_CONFIG, "Invalid %sPort line with no address", portname);
goto err; goto err;
} }
/* Now parse the addr/port value */ /* Split the remainder... */
addrport = smartlist_get(elts, 0); smartlist_split_string(elts, rest_of_line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
/* Let's start to check if it's a Unix socket path. */ /* Let's start to check if it's a Unix socket path. */
ret = config_parse_unix_port(addrport, &unix_socket_path); if (is_unix_tagged_addr) {
if (ret < 0 && ret != -ENOENT) { #ifndef HAVE_SYS_UN_H
if (ret == -EINVAL) { log_warn(LD_CONFIG, "Unix sockets not supported on this system.");
log_warn(LD_CONFIG, "Empty Unix socket path.");
}
goto err; goto err;
#endif
unix_socket_path = addrport;
addrport = NULL;
} }
if (unix_socket_path && if (unix_socket_path &&
@ -6612,9 +6630,6 @@ parse_port_config(smartlist_t *out,
if (use_server_options) { if (use_server_options) {
/* This is a server port; parse advertising options */ /* This is a server port; parse advertising options */
SMARTLIST_FOREACH_BEGIN(elts, char *, elt) { SMARTLIST_FOREACH_BEGIN(elts, char *, elt) {
if (elt_sl_idx == 0)
continue; /* Skip addr:port */
if (!strcasecmp(elt, "NoAdvertise")) { if (!strcasecmp(elt, "NoAdvertise")) {
no_advertise = 1; no_advertise = 1;
} else if (!strcasecmp(elt, "NoListen")) { } else if (!strcasecmp(elt, "NoListen")) {
@ -6662,8 +6677,6 @@ parse_port_config(smartlist_t *out,
SMARTLIST_FOREACH_BEGIN(elts, char *, elt) { SMARTLIST_FOREACH_BEGIN(elts, char *, elt) {
int no = 0, isoflag = 0; int no = 0, isoflag = 0;
const char *elt_orig = elt; const char *elt_orig = elt;
if (elt_sl_idx == 0)
continue; /* Skip addr:port */
if (!strcasecmpstart(elt, "SessionGroup=")) { if (!strcasecmpstart(elt, "SessionGroup=")) {
int group = (int)tor_parse_long(elt+strlen("SessionGroup="), int group = (int)tor_parse_long(elt+strlen("SessionGroup="),
@ -6880,6 +6893,7 @@ parse_port_config(smartlist_t *out,
} }
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_clear(elts); smartlist_clear(elts);
tor_free(addrport);
} }
if (warn_nonlocal && out) { if (warn_nonlocal && out) {
@ -6903,6 +6917,7 @@ parse_port_config(smartlist_t *out,
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts); smartlist_free(elts);
tor_free(unix_socket_path); tor_free(unix_socket_path);
tor_free(addrport);
return retval; return retval;
} }

View File

@ -128,7 +128,11 @@ int addressmap_register_auto(const char *from, const char *to,
time_t expires, time_t expires,
addressmap_entry_source_t addrmap_source, addressmap_entry_source_t addrmap_source,
const char **msg); const char **msg);
int config_parse_unix_port(const char *addrport, char **path_out);
int port_cfg_line_extract_addrport(const char *line,
char **addrport_out,
int *is_unix_out,
const char **rest_out);
/** Represents the information stored in a torrc Bridge line. */ /** Represents the information stored in a torrc Bridge line. */
typedef struct bridge_line_t { typedef struct bridge_line_t {

View File

@ -347,22 +347,20 @@ rend_service_parse_port_config(const char *string, const char *sep,
int realport = 0; int realport = 0;
uint16_t p; uint16_t p;
tor_addr_t addr; tor_addr_t addr;
const char *addrport;
rend_service_port_config_t *result = NULL; rend_service_port_config_t *result = NULL;
unsigned int is_unix_addr = 0; unsigned int is_unix_addr = 0;
char *socket_path = NULL; const char *socket_path = NULL;
char *err_msg = NULL; char *err_msg = NULL;
char *addrport = NULL;
sl = smartlist_new(); sl = smartlist_new();
smartlist_split_string(sl, string, sep, smartlist_split_string(sl, string, sep,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
if (smartlist_len(sl) < 1 || smartlist_len(sl) > 2) { if (smartlist_len(sl) < 1 || BUG(smartlist_len(sl) > 2)) {
if (err_msg_out) if (err_msg_out)
err_msg = tor_strdup("Bad syntax in hidden service port configuration."); err_msg = tor_strdup("Bad syntax in hidden service port configuration.");
goto err; goto err;
} }
virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL); virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL);
if (!virtport) { if (!virtport) {
if (err_msg_out) if (err_msg_out)
@ -371,7 +369,6 @@ rend_service_parse_port_config(const char *string, const char *sep,
goto err; goto err;
} }
if (smartlist_len(sl) == 1) { if (smartlist_len(sl) == 1) {
/* No addr:port part; use default. */ /* No addr:port part; use default. */
realport = virtport; realport = virtport;
@ -379,17 +376,18 @@ rend_service_parse_port_config(const char *string, const char *sep,
} else { } else {
int ret; int ret;
addrport = smartlist_get(sl,1); const char *addrport_element = smartlist_get(sl,1);
ret = config_parse_unix_port(addrport, &socket_path); const char *rest = NULL;
if (ret < 0 && ret != -ENOENT) { int is_unix;
if (ret == -EINVAL) ret = port_cfg_line_extract_addrport(addrport_element, &addrport,
if (err_msg_out) &is_unix, &rest);
err_msg = tor_strdup("Empty socket path in hidden service port " if (ret < 0) {
"configuration."); tor_asprintf(&err_msg, "Couldn't process address <%s> from hidden service "
"configuration", addrport_element);
goto err; goto err;
} }
if (socket_path) { if (is_unix) {
socket_path = addrport;
is_unix_addr = 1; is_unix_addr = 1;
} else if (strchr(addrport, ':') || strchr(addrport, '.')) { } else if (strchr(addrport, ':') || strchr(addrport, '.')) {
/* else try it as an IP:port pair if it has a : or . in it */ /* else try it as an IP:port pair if it has a : or . in it */
@ -427,10 +425,10 @@ rend_service_parse_port_config(const char *string, const char *sep,
} }
err: err:
tor_free(addrport);
if (err_msg_out) *err_msg_out = err_msg; if (err_msg_out) *err_msg_out = err_msg;
SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl); smartlist_free(sl);
if (socket_path) tor_free(socket_path);
return result; return result;
} }

View File

@ -3710,6 +3710,145 @@ test_config_default_fallback_dirs(void *arg)
clear_dir_servers(); clear_dir_servers();
} }
static void
test_config_port_cfg_line_extract_addrport(void *arg)
{
(void)arg;
int unixy = 0;
const char *rest = NULL;
char *a = NULL;
tt_int_op(port_cfg_line_extract_addrport("", &a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
tt_str_op(a, OP_EQ, "");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("hello", &a, &unixy, &rest),
OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
tt_str_op(a, OP_EQ, "hello");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport(" flipperwalt gersplut",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
tt_str_op(a, OP_EQ, "flipperwalt");;
tt_str_op(rest, OP_EQ, "gersplut");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport(" flipperwalt \t gersplut",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
tt_str_op(a, OP_EQ, "flipperwalt");;
tt_str_op(rest, OP_EQ, "gersplut");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("flipperwalt \t gersplut",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
tt_str_op(a, OP_EQ, "flipperwalt");;
tt_str_op(rest, OP_EQ, "gersplut");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:flipperwalt \t gersplut",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
tt_str_op(a, OP_EQ, "flipperwalt");;
tt_str_op(rest, OP_EQ, "gersplut");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
tt_str_op(a, OP_EQ, "lolol");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
tt_str_op(a, OP_EQ, "lolol");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:lolol ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
tt_str_op(a, OP_EQ, "lolol");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport(" unix:lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
tt_str_op(a, OP_EQ, "lolol");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("foobar:lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
tt_str_op(a, OP_EQ, "foobar:lolol");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport(":lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
tt_str_op(a, OP_EQ, ":lolol");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lolol\"",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
tt_str_op(a, OP_EQ, "lolol");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lolol\" ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
tt_str_op(a, OP_EQ, "lolol");;
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lolol\" foo ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
tt_str_op(a, OP_EQ, "lolol");;
tt_str_op(rest, OP_EQ, "foo ");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lol ol\" foo ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
tt_str_op(a, OP_EQ, "lol ol");;
tt_str_op(rest, OP_EQ, "foo ");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lol\\\" ol\" foo ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
tt_str_op(a, OP_EQ, "lol\" ol");;
tt_str_op(rest, OP_EQ, "foo ");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lol\\\" ol foo ",
&a, &unixy, &rest), OP_EQ, -1);
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lol\\0\" ol foo ",
&a, &unixy, &rest), OP_EQ, -1);
tor_free(a);
done:
tor_free(a);
}
static config_line_t * static config_line_t *
mock_config_line(const char *key, const char *val) mock_config_line(const char *key, const char *val)
{ {
@ -4050,6 +4189,49 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1); tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1);
#endif #endif
// Test success with quoted unix: address.
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:\"/tmp/foo/ bar\" "
"NoDNSRequest NoIPv4Traffic");
ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
tt_int_op(ret, OP_EQ, -1);
#else
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->entry_cfg.dns_request, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1);
#endif
// Test failure with broken quoted unix: address.
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:\"/tmp/foo/ bar "
"NoDNSRequest NoIPv4Traffic");
ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
// Test failure with empty quoted unix: address.
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:\"\" "
"NoDNSRequest NoIPv4Traffic");
ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
// Test success with OnionTrafficOnly (no DNS, no ipv4, no ipv6) // Test success with OnionTrafficOnly (no DNS, no ipv4, no ipv6)
config_free_lines(config_port_valid); config_port_valid = NULL; config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
@ -4690,6 +4872,15 @@ test_config_parse_port_config__ports__server_options(void *data)
0, CL_PORT_SERVER_OPTIONS); 0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1); tt_int_op(ret, OP_EQ, -1);
// Check for failure with empty unix: address.
config_free_lines(config_port_invalid); config_port_invalid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("ORPort", "unix:\"\"");
ret = parse_port_config(slout, config_port_invalid, NULL, "ORPort", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
done: done:
if (slout) if (slout)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf)); SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
@ -4719,6 +4910,7 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(write_to_data_subdir, TT_FORK), CONFIG_TEST(write_to_data_subdir, TT_FORK),
CONFIG_TEST(fix_my_family, 0), CONFIG_TEST(fix_my_family, 0),
CONFIG_TEST(directory_fetch, 0), CONFIG_TEST(directory_fetch, 0),
CONFIG_TEST(port_cfg_line_extract_addrport, 0),
CONFIG_TEST(parse_port_config__listenaddress, 0), CONFIG_TEST(parse_port_config__listenaddress, 0),
CONFIG_TEST(parse_port_config__ports__no_ports_given, 0), CONFIG_TEST(parse_port_config__ports__no_ports_given, 0),
CONFIG_TEST(parse_port_config__ports__server_options, 0), CONFIG_TEST(parse_port_config__ports__server_options, 0),

View File

@ -137,6 +137,8 @@ test_rend_service_parse_port_config(void *arg)
cfg = rend_service_parse_port_config("80,[2001:db8::1]:8080", sep, &err_msg); cfg = rend_service_parse_port_config("80,[2001:db8::1]:8080", sep, &err_msg);
tt_assert(cfg); tt_assert(cfg);
tt_assert(!err_msg); tt_assert(!err_msg);
rend_service_port_config_free(cfg);
cfg = NULL;
/* XXX: Someone should add tests for AF_UNIX targets if supported. */ /* XXX: Someone should add tests for AF_UNIX targets if supported. */
@ -151,6 +153,53 @@ test_rend_service_parse_port_config(void *arg)
cfg = rend_service_parse_port_config("90001", sep, &err_msg); cfg = rend_service_parse_port_config("90001", sep, &err_msg);
tt_assert(!cfg); tt_assert(!cfg);
tt_assert(err_msg); tt_assert(err_msg);
tor_free(err_msg);
/* unix port */
cfg = NULL;
/* quoted unix port */
tor_free(err_msg);
cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar\"",
" ", &err_msg);
tt_assert(cfg);
tt_assert(!err_msg);
rend_service_port_config_free(cfg);
cfg = NULL;
/* quoted unix port */
tor_free(err_msg);
cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar\"",
" ", &err_msg);
tt_assert(cfg);
tt_assert(!err_msg);
rend_service_port_config_free(cfg);
cfg = NULL;
/* quoted unix port, missing end quote */
cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar",
" ", &err_msg);
tt_assert(!cfg);
tt_str_op(err_msg, OP_EQ, "Couldn't process address <unix:\"/tmp/foo bar> "
"from hidden service configuration");
tor_free(err_msg);
/* bogus IP address */
cfg = rend_service_parse_port_config("100 1.2.3.4.5:9000",
" ", &err_msg);
tt_assert(!cfg);
tt_str_op(err_msg, OP_EQ, "Unparseable address in hidden service port "
"configuration.");
tor_free(err_msg);
/* bogus port port */
cfg = rend_service_parse_port_config("100 99999",
" ", &err_msg);
tt_assert(!cfg);
tt_str_op(err_msg, OP_EQ, "Unparseable or out-of-range port \"99999\" "
"in hidden service port configuration.");
tor_free(err_msg);
done: done:
rend_service_port_config_free(cfg); rend_service_port_config_free(cfg);