mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 04:13:28 +01:00
Merge branch 'bugs25036_25055_clean_033' into maint-0.3.3
This commit is contained in:
commit
d416e208e4
7
changes/bugs_25036_25055
Normal file
7
changes/bugs_25036_25055
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
o Minor bugfixes (networking):
|
||||||
|
- Tor will not reject IPv6 address strings from TorBrowser when they
|
||||||
|
are passed as hostnames in SOCKS5 requests. Fixes bug 25036,
|
||||||
|
bugfix on Tor 0.3.1.2.
|
||||||
|
- string_is_valid_hostname() will not consider IP strings to be valid
|
||||||
|
hostnames. Fixes bug 25055; bugfix on Tor 0.2.5.5.
|
||||||
|
|
@ -1071,6 +1071,36 @@ string_is_valid_ipv6_address(const char *string)
|
|||||||
return (tor_inet_pton(AF_INET6,string,&addr) == 1);
|
return (tor_inet_pton(AF_INET6,string,&addr) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return true iff <b>string</b> is a valid destination address,
|
||||||
|
* i.e. either a DNS hostname or IPv4/IPv6 address string.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
string_is_valid_dest(const char *string)
|
||||||
|
{
|
||||||
|
char *tmp = NULL;
|
||||||
|
int retval;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (string == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = strlen(string);
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (string[0] == '[' && string[len - 1] == ']')
|
||||||
|
string = tmp = tor_strndup(string + 1, len - 2);
|
||||||
|
|
||||||
|
retval = string_is_valid_ipv4_address(string) ||
|
||||||
|
string_is_valid_ipv6_address(string) ||
|
||||||
|
string_is_valid_nonrfc_hostname(string);
|
||||||
|
|
||||||
|
tor_free(tmp);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/** Return true iff <b>string</b> matches a pattern of DNS names
|
/** Return true iff <b>string</b> matches a pattern of DNS names
|
||||||
* that we allow Tor clients to connect to.
|
* that we allow Tor clients to connect to.
|
||||||
*
|
*
|
||||||
@ -1078,37 +1108,51 @@ string_is_valid_ipv6_address(const char *string)
|
|||||||
* with misconfigured zones that have been encountered in the wild.
|
* with misconfigured zones that have been encountered in the wild.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
string_is_valid_hostname(const char *string)
|
string_is_valid_nonrfc_hostname(const char *string)
|
||||||
{
|
{
|
||||||
int result = 1;
|
int result = 1;
|
||||||
|
int has_trailing_dot;
|
||||||
|
char *last_label;
|
||||||
smartlist_t *components;
|
smartlist_t *components;
|
||||||
|
|
||||||
|
if (!string || strlen(string) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (string_is_valid_ipv4_address(string))
|
||||||
|
return 0;
|
||||||
|
|
||||||
components = smartlist_new();
|
components = smartlist_new();
|
||||||
|
|
||||||
smartlist_split_string(components,string,".",0,0);
|
smartlist_split_string(components,string,".",0,0);
|
||||||
|
|
||||||
|
if (BUG(smartlist_len(components) == 0))
|
||||||
|
return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks.
|
||||||
|
|
||||||
|
/* Allow a single terminating '.' used rarely to indicate domains
|
||||||
|
* are FQDNs rather than relative. */
|
||||||
|
last_label = (char *)smartlist_get(components,
|
||||||
|
smartlist_len(components) - 1);
|
||||||
|
has_trailing_dot = (last_label[0] == '\0');
|
||||||
|
if (has_trailing_dot) {
|
||||||
|
smartlist_pop_last(components);
|
||||||
|
tor_free(last_label);
|
||||||
|
last_label = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
SMARTLIST_FOREACH_BEGIN(components, char *, c) {
|
SMARTLIST_FOREACH_BEGIN(components, char *, c) {
|
||||||
if ((c[0] == '-') || (*c == '_')) {
|
if ((c[0] == '-') || (*c == '_')) {
|
||||||
result = 0;
|
result = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow a single terminating '.' used rarely to indicate domains
|
|
||||||
* are FQDNs rather than relative. */
|
|
||||||
if ((c_sl_idx > 0) && (c_sl_idx + 1 == c_sl_len) && !*c) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ((*c >= 'a' && *c <= 'z') ||
|
result = (TOR_ISALNUM(*c) || (*c == '-') || (*c == '_'));
|
||||||
(*c >= 'A' && *c <= 'Z') ||
|
|
||||||
(*c >= '0' && *c <= '9') ||
|
|
||||||
(*c == '-') || (*c == '_'))
|
|
||||||
c++;
|
c++;
|
||||||
else
|
|
||||||
result = 0;
|
|
||||||
} while (result && *c);
|
} while (result && *c);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
} SMARTLIST_FOREACH_END(c);
|
} SMARTLIST_FOREACH_END(c);
|
||||||
|
|
||||||
SMARTLIST_FOREACH_BEGIN(components, char *, c) {
|
SMARTLIST_FOREACH_BEGIN(components, char *, c) {
|
||||||
|
@ -233,7 +233,8 @@ const char *find_str_at_start_of_line(const char *haystack,
|
|||||||
const char *needle);
|
const char *needle);
|
||||||
int string_is_C_identifier(const char *string);
|
int string_is_C_identifier(const char *string);
|
||||||
int string_is_key_value(int severity, const char *string);
|
int string_is_key_value(int severity, const char *string);
|
||||||
int string_is_valid_hostname(const char *string);
|
int string_is_valid_dest(const char *string);
|
||||||
|
int string_is_valid_nonrfc_hostname(const char *string);
|
||||||
int string_is_valid_ipv4_address(const char *string);
|
int string_is_valid_ipv4_address(const char *string);
|
||||||
int string_is_valid_ipv6_address(const char *string);
|
int string_is_valid_ipv6_address(const char *string);
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
|
|||||||
req->port = ntohs(get_uint16(data+5+len));
|
req->port = ntohs(get_uint16(data+5+len));
|
||||||
*drain_out = 5+len+2;
|
*drain_out = 5+len+2;
|
||||||
|
|
||||||
if (!string_is_valid_hostname(req->address)) {
|
if (!string_is_valid_dest(req->address)) {
|
||||||
socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
|
socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
|
||||||
|
|
||||||
log_warn(LD_PROTOCOL,
|
log_warn(LD_PROTOCOL,
|
||||||
@ -518,7 +518,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
|
|||||||
log_debug(LD_APP,"socks4: Everything is here. Success.");
|
log_debug(LD_APP,"socks4: Everything is here. Success.");
|
||||||
strlcpy(req->address, startaddr ? startaddr : tmpbuf,
|
strlcpy(req->address, startaddr ? startaddr : tmpbuf,
|
||||||
sizeof(req->address));
|
sizeof(req->address));
|
||||||
if (!string_is_valid_hostname(req->address)) {
|
if (!string_is_valid_dest(req->address)) {
|
||||||
log_warn(LD_PROTOCOL,
|
log_warn(LD_PROTOCOL,
|
||||||
"Your application (using socks4 to port %d) gave Tor "
|
"Your application (using socks4 to port %d) gave Tor "
|
||||||
"a malformed hostname: %s. Rejecting the connection.",
|
"a malformed hostname: %s. Rejecting the connection.",
|
||||||
|
@ -347,17 +347,35 @@ test_socks_5_supported_commands(void *ptr)
|
|||||||
|
|
||||||
socks_request_clear(socks);
|
socks_request_clear(socks);
|
||||||
|
|
||||||
/* SOCKS 5 should NOT reject RESOLVE [F0] reject for IPv6 address
|
/* SOCKS 5 should NOT reject RESOLVE [F0] request for IPv6 address
|
||||||
* string if SafeSocks is enabled. */
|
* string if SafeSocks is enabled. */
|
||||||
|
|
||||||
|
ADD_DATA(buf, "\x05\x01\x00");
|
||||||
|
ADD_DATA(buf, "\x05\xF0\x00\x03\x29");
|
||||||
|
ADD_DATA(buf, "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]");
|
||||||
|
ADD_DATA(buf, "\x01\x02");
|
||||||
|
tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, 1),
|
||||||
|
OP_EQ, 1);
|
||||||
|
|
||||||
|
tt_str_op("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", OP_EQ,
|
||||||
|
socks->address);
|
||||||
|
tt_int_op(258, OP_EQ, socks->port);
|
||||||
|
|
||||||
|
tt_int_op(0, OP_EQ, buf_datalen(buf));
|
||||||
|
|
||||||
|
socks_request_clear(socks);
|
||||||
|
|
||||||
|
/* Also allow bracket-less form. */
|
||||||
|
|
||||||
ADD_DATA(buf, "\x05\x01\x00");
|
ADD_DATA(buf, "\x05\x01\x00");
|
||||||
ADD_DATA(buf, "\x05\xF0\x00\x03\x27");
|
ADD_DATA(buf, "\x05\xF0\x00\x03\x27");
|
||||||
ADD_DATA(buf, "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
|
ADD_DATA(buf, "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
|
||||||
ADD_DATA(buf, "\x01\x02");
|
ADD_DATA(buf, "\x01\x02");
|
||||||
tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, 1),
|
tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, 1),
|
||||||
OP_EQ, -1);
|
OP_EQ, 1);
|
||||||
|
|
||||||
tt_str_op("2001:0db8:85a3:0000:0000:8a2e:0370:7334", OP_EQ, socks->address);
|
tt_str_op("2001:0db8:85a3:0000:0000:8a2e:0370:7334", OP_EQ,
|
||||||
|
socks->address);
|
||||||
tt_int_op(258, OP_EQ, socks->port);
|
tt_int_op(258, OP_EQ, socks->port);
|
||||||
|
|
||||||
tt_int_op(0, OP_EQ, buf_datalen(buf));
|
tt_int_op(0, OP_EQ, buf_datalen(buf));
|
||||||
|
@ -5541,48 +5541,75 @@ test_util_max_mem(void *arg)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_util_dest_validation_edgecase(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
tt_assert(!string_is_valid_dest(NULL));
|
||||||
|
tt_assert(!string_is_valid_dest(""));
|
||||||
|
|
||||||
|
done:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_util_hostname_validation(void *arg)
|
test_util_hostname_validation(void *arg)
|
||||||
{
|
{
|
||||||
(void)arg;
|
(void)arg;
|
||||||
|
|
||||||
// Lets try valid hostnames first.
|
// Lets try valid hostnames first.
|
||||||
tt_assert(string_is_valid_hostname("torproject.org"));
|
tt_assert(string_is_valid_nonrfc_hostname("torproject.org"));
|
||||||
tt_assert(string_is_valid_hostname("ocw.mit.edu"));
|
tt_assert(string_is_valid_nonrfc_hostname("ocw.mit.edu"));
|
||||||
tt_assert(string_is_valid_hostname("i.4cdn.org"));
|
tt_assert(string_is_valid_nonrfc_hostname("i.4cdn.org"));
|
||||||
tt_assert(string_is_valid_hostname("stanford.edu"));
|
tt_assert(string_is_valid_nonrfc_hostname("stanford.edu"));
|
||||||
tt_assert(string_is_valid_hostname("multiple-words-with-hypens.jp"));
|
tt_assert(string_is_valid_nonrfc_hostname("multiple-words-with-hypens.jp"));
|
||||||
|
|
||||||
// Subdomain name cannot start with '-' or '_'.
|
// Subdomain name cannot start with '-' or '_'.
|
||||||
tt_assert(!string_is_valid_hostname("-torproject.org"));
|
tt_assert(!string_is_valid_nonrfc_hostname("-torproject.org"));
|
||||||
tt_assert(!string_is_valid_hostname("subdomain.-domain.org"));
|
tt_assert(!string_is_valid_nonrfc_hostname("subdomain.-domain.org"));
|
||||||
tt_assert(!string_is_valid_hostname("-subdomain.domain.org"));
|
tt_assert(!string_is_valid_nonrfc_hostname("-subdomain.domain.org"));
|
||||||
tt_assert(!string_is_valid_hostname("___abc.org"));
|
tt_assert(!string_is_valid_nonrfc_hostname("___abc.org"));
|
||||||
|
|
||||||
// Hostnames cannot contain non-alphanumeric characters.
|
// Hostnames cannot contain non-alphanumeric characters.
|
||||||
tt_assert(!string_is_valid_hostname("%%domain.\\org."));
|
tt_assert(!string_is_valid_nonrfc_hostname("%%domain.\\org."));
|
||||||
tt_assert(!string_is_valid_hostname("***x.net"));
|
tt_assert(!string_is_valid_nonrfc_hostname("***x.net"));
|
||||||
tt_assert(!string_is_valid_hostname("\xff\xffxyz.org"));
|
tt_assert(!string_is_valid_nonrfc_hostname("\xff\xffxyz.org"));
|
||||||
tt_assert(!string_is_valid_hostname("word1 word2.net"));
|
tt_assert(!string_is_valid_nonrfc_hostname("word1 word2.net"));
|
||||||
|
|
||||||
// Test workaround for nytimes.com stupidity, technically invalid,
|
// Test workaround for nytimes.com stupidity, technically invalid,
|
||||||
// but we allow it since they are big, even though they are failing to
|
// but we allow it since they are big, even though they are failing to
|
||||||
// comply with a ~30 year old standard.
|
// comply with a ~30 year old standard.
|
||||||
tt_assert(string_is_valid_hostname("core3_euw1.fabrik.nytimes.com"));
|
tt_assert(string_is_valid_nonrfc_hostname("core3_euw1.fabrik.nytimes.com"));
|
||||||
|
|
||||||
// Firefox passes FQDNs with trailing '.'s directly to the SOCKS proxy,
|
// Firefox passes FQDNs with trailing '.'s directly to the SOCKS proxy,
|
||||||
// which is redundant since the spec states DOMAINNAME addresses are fully
|
// which is redundant since the spec states DOMAINNAME addresses are fully
|
||||||
// qualified. While unusual, this should be tollerated.
|
// qualified. While unusual, this should be tollerated.
|
||||||
tt_assert(string_is_valid_hostname("core9_euw1.fabrik.nytimes.com."));
|
tt_assert(string_is_valid_nonrfc_hostname("core9_euw1.fabrik.nytimes.com."));
|
||||||
tt_assert(!string_is_valid_hostname("..washingtonpost.is.better.com"));
|
tt_assert(!string_is_valid_nonrfc_hostname(
|
||||||
tt_assert(!string_is_valid_hostname("so.is..ft.com"));
|
"..washingtonpost.is.better.com"));
|
||||||
tt_assert(!string_is_valid_hostname("..."));
|
tt_assert(!string_is_valid_nonrfc_hostname("so.is..ft.com"));
|
||||||
|
tt_assert(!string_is_valid_nonrfc_hostname("..."));
|
||||||
|
|
||||||
// XXX: do we allow single-label DNS names?
|
// XXX: do we allow single-label DNS names?
|
||||||
// We shouldn't for SOCKS (spec says "contains a fully-qualified domain name"
|
// We shouldn't for SOCKS (spec says "contains a fully-qualified domain name"
|
||||||
// but only test pathologically malformed traling '.' cases for now.
|
// but only test pathologically malformed traling '.' cases for now.
|
||||||
tt_assert(!string_is_valid_hostname("."));
|
tt_assert(!string_is_valid_nonrfc_hostname("."));
|
||||||
tt_assert(!string_is_valid_hostname(".."));
|
tt_assert(!string_is_valid_nonrfc_hostname(".."));
|
||||||
|
|
||||||
|
// IP address strings are not hostnames.
|
||||||
|
tt_assert(!string_is_valid_nonrfc_hostname("8.8.8.8"));
|
||||||
|
tt_assert(!string_is_valid_nonrfc_hostname("[2a00:1450:401b:800::200e]"));
|
||||||
|
tt_assert(!string_is_valid_nonrfc_hostname("2a00:1450:401b:800::200e"));
|
||||||
|
|
||||||
|
// We allow alphanumeric TLDs. For discussion, see ticket #25055.
|
||||||
|
tt_assert(string_is_valid_nonrfc_hostname("lucky.13"));
|
||||||
|
tt_assert(string_is_valid_nonrfc_hostname("luck.y13"));
|
||||||
|
tt_assert(string_is_valid_nonrfc_hostname("luck.y13."));
|
||||||
|
|
||||||
|
// We allow punycode TLDs. For examples, see
|
||||||
|
// http://data.iana.org/TLD/tlds-alpha-by-domain.txt
|
||||||
|
tt_assert(string_is_valid_nonrfc_hostname("example.xn--l1acc"));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return;
|
return;
|
||||||
@ -6208,6 +6235,7 @@ struct testcase_t util_tests[] = {
|
|||||||
&passthrough_setup, (void*)"1" },
|
&passthrough_setup, (void*)"1" },
|
||||||
UTIL_TEST(max_mem, 0),
|
UTIL_TEST(max_mem, 0),
|
||||||
UTIL_TEST(hostname_validation, 0),
|
UTIL_TEST(hostname_validation, 0),
|
||||||
|
UTIL_TEST(dest_validation_edgecase, 0),
|
||||||
UTIL_TEST(ipv4_validation, 0),
|
UTIL_TEST(ipv4_validation, 0),
|
||||||
UTIL_TEST(writepid, 0),
|
UTIL_TEST(writepid, 0),
|
||||||
UTIL_TEST(get_avail_disk_space, 0),
|
UTIL_TEST(get_avail_disk_space, 0),
|
||||||
|
Loading…
Reference in New Issue
Block a user