diff --git a/changes/feature18753 b/changes/feature18753 new file mode 100644 index 0000000000000000000000000000000000000000..2eb0e359da5ae3ad947fbe519f31e22c315e0959 --- /dev/null +++ b/changes/feature18753 @@ -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. + diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 9f4eb314451739abe4d62f464e2ee67d9737bd5a..1a584e89dc50a6ea187a70006e5e076d71c4aee4 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -323,6 +323,8 @@ GENERAL OPTIONS any process on the local host to control it. (Setting both authentication methods means either method is sufficient to authenticate to Tor.) This 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) + + 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 connections via SOCKS. Set it to "auto" to have Tor pick a port for 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 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 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 - **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 connects to that VIRTPORT, one of the TARGETs from those lines will be chosen at random. diff --git a/src/common/util.c b/src/common/util.c index 259ff8756f02de6d11b992671c8a2b93456b4335..c632ee498eabcef42514776d4b2f01da30fd2d7c 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -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 * after the string. On failure, return NULL. */ -static const char * +const char * unescape_string(const char *s, char **result, size_t *size_out) { const char *cp; diff --git a/src/common/util.h b/src/common/util.h index 57605ccfd1c01158f7f2ba2e398302aa51ee022c..479fc8d610e5e1b7a9a24fae2b46f2ecd8011589 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -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, size_t *sz_out) 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, char **key_out, char **value_out, const char **err_out); diff --git a/src/or/config.c b/src/or/config.c index 18cbe34be30aca73c6ebc2edb780e34b629f25e6..ff434860847828c66b75cf5b4c4f89853b761f8f 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -68,6 +68,9 @@ /* Prefix used to indicate a Unix socket in a FooPort configuration. */ 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 * option names, or alternative option names, to their current values. */ @@ -6288,54 +6291,61 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid_nonlocal) } SMARTLIST_FOREACH_END(port); } -#ifdef HAVE_SYS_UN_H - -/** Parse the given <b>addrport</b> and set <b>path_out</b> if a Unix socket - * path is found. Return 0 on success. On error, a negative value is - * returned, -ENOENT if no Unix statement found, -EINVAL if the socket path - * is empty and -ENOSYS if AF_UNIX is not supported (see function in the - * #else statement below). */ - -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; - } - - 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) */ - +/** + * Take a string (<b>line</b>) that begins with either an address:port, a + * port, or an AF_UNIX address, optionally quoted, prefixed with + * "unix:". Parse that line, and on success, set <b>addrport_out</b> to a new + * string containing the beginning portion (without prefix). Iff there was a + * unix: prefix, set <b>is_unix_out</b> to true. On success, also set + * <b>rest_out</b> to point to the part of the line after the address portion. + * + * Return 0 on success, -1 on failure. + */ 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(addrport); + tor_assert(line); + tor_assert(addrport_out); + tor_assert(is_unix_out); + tor_assert(rest_out); + + line = eat_whitespace(line); + + 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; + } - if (strcmpstart(addrport, unix_socket_prefix)) { - /* Not a Unix socket path. */ - return -ENOENT; + 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; } - - 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 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: * [Addr:](Port|auto) [Options].*/ elts = smartlist_new(); + char *addrport = NULL; for (; ports; ports = ports->next) { tor_addr_t addr; - int port, ret; + int port; int sessiongroup = SESSION_GROUP_UNSET; unsigned isolation = ISO_DEFAULT; int prefer_no_auth = 0; int socks_iso_keep_alive = 0; - char *addrport; uint16_t ptmp=0; int ok; /* 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, has_used_unix_socket_only_option = 0; - smartlist_split_string(elts, ports->value, NULL, - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - if (smartlist_len(elts) == 0) { - log_warn(LD_CONFIG, "Invalid %sPort line with no value", portname); + int is_unix_tagged_addr = 0; + const char *rest_of_line = NULL; + if (port_cfg_line_extract_addrport(ports->value, + &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; } - /* Now parse the addr/port value */ - addrport = smartlist_get(elts, 0); + /* Split the remainder... */ + 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. */ - ret = config_parse_unix_port(addrport, &unix_socket_path); - if (ret < 0 && ret != -ENOENT) { - if (ret == -EINVAL) { - log_warn(LD_CONFIG, "Empty Unix socket path."); - } + if (is_unix_tagged_addr) { +#ifndef HAVE_SYS_UN_H + log_warn(LD_CONFIG, "Unix sockets not supported on this system."); goto err; +#endif + unix_socket_path = addrport; + addrport = NULL; } if (unix_socket_path && @@ -6612,9 +6630,6 @@ parse_port_config(smartlist_t *out, if (use_server_options) { /* This is a server port; parse advertising options */ SMARTLIST_FOREACH_BEGIN(elts, char *, elt) { - if (elt_sl_idx == 0) - continue; /* Skip addr:port */ - if (!strcasecmp(elt, "NoAdvertise")) { no_advertise = 1; } else if (!strcasecmp(elt, "NoListen")) { @@ -6662,8 +6677,6 @@ parse_port_config(smartlist_t *out, SMARTLIST_FOREACH_BEGIN(elts, char *, elt) { int no = 0, isoflag = 0; const char *elt_orig = elt; - if (elt_sl_idx == 0) - continue; /* Skip addr:port */ if (!strcasecmpstart(elt, "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_clear(elts); + tor_free(addrport); } if (warn_nonlocal && out) { @@ -6903,6 +6917,7 @@ parse_port_config(smartlist_t *out, SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); smartlist_free(elts); tor_free(unix_socket_path); + tor_free(addrport); return retval; } diff --git a/src/or/config.h b/src/or/config.h index 208659acb71ace01dc3ab908c026e016245b6d88..f5a19602f25b90c33e0586c34c2d6e5a5239eeac 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -128,7 +128,11 @@ int addressmap_register_auto(const char *from, const char *to, time_t expires, addressmap_entry_source_t addrmap_source, 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. */ typedef struct bridge_line_t { diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 114a56b74efaa045d5fc8cbc861936f84033978e..a2d7a373781ba8792d0e22813d8c294e29459ef5 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -347,22 +347,20 @@ rend_service_parse_port_config(const char *string, const char *sep, int realport = 0; uint16_t p; tor_addr_t addr; - const char *addrport; rend_service_port_config_t *result = NULL; unsigned int is_unix_addr = 0; - char *socket_path = NULL; + const char *socket_path = NULL; char *err_msg = NULL; + char *addrport = NULL; sl = smartlist_new(); smartlist_split_string(sl, string, sep, - SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); - if (smartlist_len(sl) < 1 || smartlist_len(sl) > 2) { + SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); + if (smartlist_len(sl) < 1 || BUG(smartlist_len(sl) > 2)) { if (err_msg_out) err_msg = tor_strdup("Bad syntax in hidden service port configuration."); - goto err; } - virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL); if (!virtport) { if (err_msg_out) @@ -371,7 +369,6 @@ rend_service_parse_port_config(const char *string, const char *sep, goto err; } - if (smartlist_len(sl) == 1) { /* No addr:port part; use default. */ realport = virtport; @@ -379,17 +376,18 @@ rend_service_parse_port_config(const char *string, const char *sep, } else { int ret; - addrport = smartlist_get(sl,1); - ret = config_parse_unix_port(addrport, &socket_path); - if (ret < 0 && ret != -ENOENT) { - if (ret == -EINVAL) - if (err_msg_out) - err_msg = tor_strdup("Empty socket path in hidden service port " - "configuration."); - + const char *addrport_element = smartlist_get(sl,1); + const char *rest = NULL; + int is_unix; + ret = port_cfg_line_extract_addrport(addrport_element, &addrport, + &is_unix, &rest); + if (ret < 0) { + tor_asprintf(&err_msg, "Couldn't process address <%s> from hidden service " + "configuration", addrport_element); goto err; } - if (socket_path) { + if (is_unix) { + socket_path = addrport; is_unix_addr = 1; } else if (strchr(addrport, ':') || strchr(addrport, '.')) { /* 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: + tor_free(addrport); if (err_msg_out) *err_msg_out = err_msg; SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); smartlist_free(sl); - if (socket_path) tor_free(socket_path); return result; } diff --git a/src/test/test_config.c b/src/test/test_config.c index ee1686c65a0340c7e0ccce9a4a47358d9a748290..4efefa8050fe984421404c467f4e6e3cf1990396 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -3710,6 +3710,145 @@ test_config_default_fallback_dirs(void *arg) 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 * 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); #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) config_free_lines(config_port_valid); config_port_valid = NULL; 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); 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: if (slout) 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(fix_my_family, 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__ports__no_ports_given, 0), CONFIG_TEST(parse_port_config__ports__server_options, 0), diff --git a/src/test/test_controller.c b/src/test/test_controller.c index 0dea8473b9ea3d491dcefa477f1ca07f373528c0..4ae35c8fe081a52b11dce0bde93ef7d947acf5fa 100644 --- a/src/test/test_controller.c +++ b/src/test/test_controller.c @@ -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); tt_assert(cfg); tt_assert(!err_msg); + rend_service_port_config_free(cfg); + cfg = NULL; /* 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); tt_assert(!cfg); 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: rend_service_port_config_free(cfg);