fix: parsing of ipv6 tracker announce URLs (#5174)

This commit is contained in:
Charles Kerr 2023-03-07 12:19:12 -06:00 committed by GitHub
parent 39e3e1d87b
commit 033d698306
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 3 deletions

View File

@ -292,7 +292,6 @@ std::string_view getSiteName(std::string_view host)
return host;
}
} // namespace
std::optional<tr_url_parsed_t> tr_urlParse(std::string_view url)
@ -335,8 +334,31 @@ std::optional<tr_url_parsed_t> tr_urlParse(std::string_view url)
parsed.authority = url.substr(0, pos);
url = pos == std::string_view::npos ? ""sv : url.substr(pos);
// A host identified by an Internet Protocol literal address, version 6
// [RFC3513] or later, is distinguished by enclosing the IP literal
// within square brackets ("[" and "]"). This is the only place where
// square bracket characters are allowed in the URI syntax.
auto remain = parsed.authority;
parsed.host = tr_strvSep(&remain, ':');
if (tr_strvStartsWith(remain, '['))
{
remain.remove_prefix(1); // '['
parsed.host = tr_strvSep(&remain, ']');
if (tr_strvStartsWith(remain, ':'))
{
remain.remove_prefix(1);
}
}
// Not legal by RFC3986 standards, but sometimes users omit
// square brackets for an IPv6 address with an implicit port
else if (std::count(std::begin(remain), std::end(remain), ':') > 1U)
{
parsed.host = remain;
remain = ""sv;
}
else
{
parsed.host = tr_strvSep(&remain, ':');
}
parsed.sitename = getSiteName(parsed.host);
parsed.port = parsePort(!std::empty(remain) ? remain : getPortForScheme(parsed.scheme));
}

View File

@ -111,7 +111,7 @@ TEST_F(WebUtilsTest, urlParse)
EXPECT_EQ("/some/other/path"sv, parsed->path);
EXPECT_EQ(80, parsed->port);
// test a host with an IP address
// test a host with an IPv4 address
url = "https://127.0.0.1:8080/some/path"sv;
parsed = tr_urlParse(url);
EXPECT_TRUE(parsed);
@ -120,6 +120,33 @@ TEST_F(WebUtilsTest, urlParse)
EXPECT_EQ("127.0.0.1"sv, parsed->host);
EXPECT_EQ("/some/path"sv, parsed->path);
EXPECT_EQ(8080, parsed->port);
// test a host with a bracketed IPv6 address and explicit port
url = "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]:8080/announce"sv;
parsed = tr_urlParse(url);
EXPECT_EQ("http"sv, parsed->scheme);
EXPECT_EQ("2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d"sv, parsed->sitename);
EXPECT_EQ("2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d"sv, parsed->host);
EXPECT_EQ("/announce"sv, parsed->path);
EXPECT_EQ(8080, parsed->port);
// test a host with a bracketed IPv6 address and implicit port
url = "http://[2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d]/announce"sv;
parsed = tr_urlParse(url);
EXPECT_EQ("http"sv, parsed->scheme);
EXPECT_EQ("2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d"sv, parsed->sitename);
EXPECT_EQ("2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d"sv, parsed->host);
EXPECT_EQ("/announce"sv, parsed->path);
EXPECT_EQ(80, parsed->port);
// test a host with an unbracketed IPv6 address and implicit port
url = "http://2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d/announce"sv;
parsed = tr_urlParse(url);
EXPECT_EQ("http"sv, parsed->scheme);
EXPECT_EQ("2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d"sv, parsed->sitename);
EXPECT_EQ("2001:0db8:11a3:09d7:1f34:8a2e:07a0:765d"sv, parsed->host);
EXPECT_EQ("/announce"sv, parsed->path);
EXPECT_EQ(80, parsed->port);
}
TEST(WebUtilsTest, urlParseFuzz)