merge bitcoin#22050: remove tor v2 support

This commit is contained in:
Kittywhiskers Van Gogh 2023-09-20 16:31:53 +05:30 committed by PastaPastaPasta
parent 546f7557d8
commit 5d7367e366
7 changed files with 60 additions and 130 deletions

View File

@ -36,7 +36,7 @@ import re
class BIP155Network(Enum):
IPV4 = 1
IPV6 = 2
TORV2 = 3
TORV2 = 3 # no longer supported
TORV3 = 4
I2P = 5
CJDNS = 6
@ -45,11 +45,11 @@ def name_to_bip155(addr):
'''Convert address string to BIP155 (networkID, addr) tuple.'''
if addr.endswith('.onion'):
vchAddr = b32decode(addr[0:-6], True)
if len(vchAddr) == 10:
return (BIP155Network.TORV2, vchAddr)
elif len(vchAddr) == 35:
assert(vchAddr[34] == 3)
if len(vchAddr) == 35:
assert vchAddr[34] == 3
return (BIP155Network.TORV3, vchAddr[:32])
elif len(vchAddr) == 10:
return (BIP155Network.TORV2, vchAddr)
else:
raise ValueError('Invalid onion %s' % vchAddr)
elif '.' in addr: # IPv4
@ -93,7 +93,10 @@ def parse_spec(s):
host = name_to_bip155(host)
return host + (port, )
if host[0] == BIP155Network.TORV2:
return None # TORV2 is no longer supported, so we ignore it
else:
return host + (port, )
def ser_compact_size(l):
r = b""
@ -129,6 +132,8 @@ def process_nodes(g, f, structname):
continue
spec = parse_spec(line)
if spec is None: # ignore this entry (e.g. no longer supported addresses like TORV2)
continue
blob = bip155_serialize(spec)
hoststr = ','.join(('0x%02x' % b) for b in blob)
g.write(f' {hoststr},\n')

View File

@ -31,14 +31,7 @@ CNetAddr::BIP155Network CNetAddr::GetBIP155Network() const
case NET_IPV6:
return BIP155Network::IPV6;
case NET_ONION:
switch (m_addr.size()) {
case ADDR_TORV2_SIZE:
return BIP155Network::TORV2;
case ADDR_TORV3_SIZE:
return BIP155Network::TORV3;
default:
assert(false);
}
return BIP155Network::TORV3;
case NET_I2P:
return BIP155Network::I2P;
case NET_CJDNS:
@ -71,14 +64,6 @@ bool CNetAddr::SetNetFromBIP155Network(uint8_t possible_bip155_net, size_t addre
throw std::ios_base::failure(
strprintf("BIP155 IPv6 address with length %u (should be %u)", address_size,
ADDR_IPV6_SIZE));
case BIP155Network::TORV2:
if (address_size == ADDR_TORV2_SIZE) {
m_net = NET_ONION;
return true;
}
throw std::ios_base::failure(
strprintf("BIP155 TORv2 address with length %u (should be %u)", address_size,
ADDR_TORV2_SIZE));
case BIP155Network::TORV3:
if (address_size == ADDR_TORV3_SIZE) {
m_net = NET_ONION;
@ -131,7 +116,7 @@ void CNetAddr::SetIP(const CNetAddr& ipIn)
assert(ipIn.m_addr.size() == ADDR_IPV6_SIZE);
break;
case NET_ONION:
assert(ipIn.m_addr.size() == ADDR_TORV2_SIZE || ipIn.m_addr.size() == ADDR_TORV3_SIZE);
assert(ipIn.m_addr.size() == ADDR_TORV3_SIZE);
break;
case NET_I2P:
assert(ipIn.m_addr.size() == ADDR_I2P_SIZE);
@ -162,9 +147,12 @@ void CNetAddr::SetLegacyIPv6(Span<const uint8_t> ipv6)
m_net = NET_IPV4;
skip = sizeof(IPV4_IN_IPV6_PREFIX);
} else if (HasPrefix(ipv6, TORV2_IN_IPV6_PREFIX)) {
// TORv2-in-IPv6
m_net = NET_ONION;
skip = sizeof(TORV2_IN_IPV6_PREFIX);
// TORv2-in-IPv6 (unsupported). Unserialize as !IsValid(), thus ignoring them.
// Mimic a default-constructed CNetAddr object which is !IsValid() and thus
// will not be gossiped, but continue reading next addresses from the stream.
m_net = NET_IPV6;
m_addr.assign(ADDR_IPV6_SIZE, 0x0);
return;
} else if (HasPrefix(ipv6, INTERNAL_IN_IPV6_PREFIX)) {
// Internal-in-IPv6
m_net = NET_INTERNAL;
@ -255,12 +243,7 @@ bool CNetAddr::SetTor(const std::string& addr)
return false;
}
switch (input.size()) {
case ADDR_TORV2_SIZE:
m_net = NET_ONION;
m_addr.assign(input.begin(), input.end());
return true;
case torv3::TOTAL_LEN: {
if (input.size() == torv3::TOTAL_LEN) {
Span<const uint8_t> input_pubkey{input.data(), ADDR_TORV3_SIZE};
Span<const uint8_t> input_checksum{input.data() + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN};
Span<const uint8_t> input_version{input.data() + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof(torv3::VERSION)};
@ -280,7 +263,6 @@ bool CNetAddr::SetTor(const std::string& addr)
m_addr.assign(input_pubkey.begin(), input_pubkey.end());
return true;
}
}
return false;
}
@ -533,7 +515,6 @@ bool CNetAddr::IsAddrV1Compatible() const
case NET_INTERNAL:
return true;
case NET_ONION:
return m_addr.size() == ADDR_TORV2_SIZE;
case NET_I2P:
case NET_CJDNS:
return false;
@ -577,6 +558,17 @@ static std::string IPv6ToString(Span<const uint8_t> a)
// clang-format on
}
static std::string OnionToString(const Span<const uint8_t>& addr)
{
uint8_t checksum[torv3::CHECKSUM_LEN];
torv3::Checksum(addr, checksum);
// TORv3 onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
prevector<torv3::TOTAL_LEN, uint8_t> address{addr.begin(), addr.end()};
address.insert(address.end(), checksum, checksum + torv3::CHECKSUM_LEN);
address.insert(address.end(), torv3::VERSION, torv3::VERSION + sizeof(torv3::VERSION));
return EncodeBase32(address) + ".onion";
}
std::string CNetAddr::ToStringIP(bool fUseGetnameinfo) const
{
switch (m_net) {
@ -597,24 +589,7 @@ std::string CNetAddr::ToStringIP(bool fUseGetnameinfo) const
return IPv6ToString(m_addr);
}
case NET_ONION:
switch (m_addr.size()) {
case ADDR_TORV2_SIZE:
return EncodeBase32(m_addr) + ".onion";
case ADDR_TORV3_SIZE: {
uint8_t checksum[torv3::CHECKSUM_LEN];
torv3::Checksum(m_addr, checksum);
// TORv3 onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
prevector<torv3::TOTAL_LEN, uint8_t> address{m_addr.begin(), m_addr.end()};
address.insert(address.end(), checksum, checksum + torv3::CHECKSUM_LEN);
address.insert(address.end(), torv3::VERSION, torv3::VERSION + sizeof(torv3::VERSION));
return EncodeBase32(address) + ".onion";
}
default:
assert(false);
}
return OnionToString(m_addr);
case NET_I2P:
return EncodeBase32(m_addr, false /* don't pad with = */) + ".b32.i2p";
case NET_CJDNS:

View File

@ -98,9 +98,6 @@ static constexpr size_t ADDR_IPV4_SIZE = 4;
/// Size of IPv6 address (in bytes).
static constexpr size_t ADDR_IPV6_SIZE = 16;
/// Size of TORv2 address (in bytes).
static constexpr size_t ADDR_TORV2_SIZE = 10;
/// Size of TORv3 address (in bytes). This is the length of just the address
/// as used in BIP155, without the checksum and the version byte.
static constexpr size_t ADDR_TORV3_SIZE = 32;
@ -262,8 +259,7 @@ class CNetAddr
/**
* Parse a Tor address and set this object to it.
* @param[in] addr Address to parse, must be a valid C string, for example
* pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion or
* 6hzph5hv6337r6p2.onion.
* pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.
* @returns Whether the operation was successful.
* @see CNetAddr::IsTor()
*/
@ -305,7 +301,7 @@ class CNetAddr
/**
* Get the BIP155 network id of this address.
* Must not be called for IsInternal() objects.
* @returns BIP155 network id
* @returns BIP155 network id, except TORV2 which is no longer supported.
*/
BIP155Network GetBIP155Network() const;
@ -336,23 +332,14 @@ class CNetAddr
memcpy(arr, IPV4_IN_IPV6_PREFIX.data(), prefix_size);
memcpy(arr + prefix_size, m_addr.data(), m_addr.size());
return;
case NET_ONION:
if (m_addr.size() == ADDR_TORV3_SIZE) {
break;
}
prefix_size = sizeof(TORV2_IN_IPV6_PREFIX);
assert(prefix_size + m_addr.size() == sizeof(arr));
memcpy(arr, TORV2_IN_IPV6_PREFIX.data(), prefix_size);
memcpy(arr + prefix_size, m_addr.data(), m_addr.size());
return;
case NET_INTERNAL:
prefix_size = sizeof(INTERNAL_IN_IPV6_PREFIX);
assert(prefix_size + m_addr.size() == sizeof(arr));
memcpy(arr, INTERNAL_IN_IPV6_PREFIX.data(), prefix_size);
memcpy(arr + prefix_size, m_addr.data(), m_addr.size());
return;
case NET_ONION:
case NET_I2P:
break;
case NET_CJDNS:
break;
case NET_UNROUTABLE:
@ -360,7 +347,7 @@ class CNetAddr
assert(false);
} // no default case, so the compiler can warn about missing cases
// Serialize TORv3, I2P and CJDNS as all-zeros.
// Serialize ONION, I2P and CJDNS as all-zeros.
memset(arr, 0x0, V1_SERIALIZATION_SIZE);
}

View File

@ -145,7 +145,7 @@ FUZZ_TARGET_DESERIALIZE(script_deserialize, {
CScript script;
DeserializeFromFuzzingInput(buffer, script);
})
FUZZ_TARGET_DESERIALIZE(sub_net_deserialize, {
FUZZ_TARGET_DESERIALIZE(subnet_deserialize, {
CSubNet sub_net_1;
DeserializeFromFuzzingInput(buffer, sub_net_1, INIT_PROTO_VERSION);
AssertEqualAfterSerializeDeserialize(sub_net_1, INIT_PROTO_VERSION);
@ -227,7 +227,7 @@ FUZZ_TARGET_DESERIALIZE(coins_deserialize, {
Coin coin;
DeserializeFromFuzzingInput(buffer, coin);
})
FUZZ_TARGET_DESERIALIZE(netaddr_deserialize, {
FUZZ_TARGET_DESERIALIZE(net_address_deserialize, {
CNetAddr na;
DeserializeFromFuzzingInput(buffer, na);
if (na.IsAddrV1Compatible()) {
@ -235,7 +235,7 @@ FUZZ_TARGET_DESERIALIZE(netaddr_deserialize, {
}
AssertEqualAfterSerializeDeserialize(na, INIT_PROTO_VERSION | ADDRV2_FORMAT);
})
FUZZ_TARGET_DESERIALIZE(service_deserialize, {
FUZZ_TARGET_DESERIALIZE(net_service_deserialize, {
CService s;
DeserializeFromFuzzingInput(buffer, s);
if (s.IsAddrV1Compatible()) {

View File

@ -281,15 +281,8 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic)
BOOST_CHECK(!addr.IsBindAny());
BOOST_CHECK_EQUAL(addr.ToString(), link_local);
// TORv2
BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion"));
BOOST_REQUIRE(addr.IsValid());
BOOST_REQUIRE(addr.IsTor());
BOOST_CHECK(!addr.IsI2P());
BOOST_CHECK(!addr.IsBindAny());
BOOST_CHECK(addr.IsAddrV1Compatible());
BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion");
// TORv2, no longer supported
BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
// TORv3
const char* torv3_addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion";
@ -379,10 +372,8 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v1)
BOOST_CHECK_EQUAL(HexStr(s), "1a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
s.clear();
BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion"));
s << addr;
BOOST_CHECK_EQUAL(HexStr(s), "fd87d87eeb43f1f2f3f4f5f6f7f8f9fa");
s.clear();
// TORv2, no longer supported
BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
BOOST_REQUIRE(addr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
s << addr;
@ -417,10 +408,8 @@ BOOST_AUTO_TEST_CASE(cnetaddr_serialize_v2)
BOOST_CHECK_EQUAL(HexStr(s), "02101a1b2a2b3a3b4a4b5a5b6a6b7a7b8a8b");
s.clear();
BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion"));
s << addr;
BOOST_CHECK_EQUAL(HexStr(s), "030af1f2f3f4f5f6f7f8f9fa");
s.clear();
// TORv2, no longer supported
BOOST_CHECK(!addr.SetSpecial("6hzph5hv6337r6p2.onion"));
BOOST_REQUIRE(addr.SetSpecial("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion"));
s << addr;
@ -526,26 +515,14 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2)
BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty());
// Valid TORv2.
// TORv2, no longer supported.
s << MakeSpan(ParseHex("03" // network type (TORv2)
"0a" // address length
"f1f2f3f4f5f6f7f8f9fa")); // address
s >> addr;
BOOST_CHECK(addr.IsValid());
BOOST_CHECK(addr.IsTor());
BOOST_CHECK(addr.IsAddrV1Compatible());
BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion");
BOOST_CHECK(!addr.IsValid());
BOOST_REQUIRE(s.empty());
// Invalid TORv2, with bogus length.
s << MakeSpan(ParseHex("03" // network type (TORv2)
"07" // address length
"00")); // address
BOOST_CHECK_EXCEPTION(s >> addr, std::ios_base::failure,
HasReason("BIP155 TORv2 address with length 7 (should be 10)"));
BOOST_REQUIRE(!s.empty()); // The stream is not consumed on invalid input.
s.clear();
// Valid TORv3.
s << MakeSpan(ParseHex("04" // network type (TORv3)
"20" // address length

View File

@ -45,13 +45,12 @@ static CNetAddr CreateInternal(const std::string& host)
BOOST_AUTO_TEST_CASE(netbase_networks)
{
BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
BOOST_CHECK(ResolveIP("::1").GetNetwork() == NET_UNROUTABLE);
BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4);
BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6);
BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_ONION);
BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL);
BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
BOOST_CHECK(ResolveIP("::1").GetNetwork() == NET_UNROUTABLE);
BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4);
BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6);
BOOST_CHECK(ResolveIP("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion").GetNetwork() == NET_ONION);
BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL);
}
BOOST_AUTO_TEST_CASE(netbase_properties)
@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(netbase_properties)
BOOST_CHECK(ResolveIP("2001:20::").IsRFC7343());
BOOST_CHECK(ResolveIP("FE80::").IsRFC4862());
BOOST_CHECK(ResolveIP("64:FF9B::").IsRFC6052());
BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor());
BOOST_CHECK(ResolveIP("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion").IsTor());
BOOST_CHECK(ResolveIP("127.0.0.1").IsLocal());
BOOST_CHECK(ResolveIP("::1").IsLocal());
BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable());
@ -134,18 +133,6 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
BOOST_CHECK(TestParse("[fd6c:88c0:8724:1:2:3:4:5]", "[fd6c:88c0:8724:1:2:3:4:5]:65535"));
}
BOOST_AUTO_TEST_CASE(onioncat_test)
{
// values from https://web.archive.org/web/20121122003543/http://www.cypherpunk.at/onioncat/wiki/OnionCat
CNetAddr addr1(ResolveIP("5wyqrzbvrdsumnok.onion"));
CNetAddr addr2(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca"));
BOOST_CHECK(addr1 == addr2);
BOOST_CHECK(addr1.IsTor());
BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion");
BOOST_CHECK(addr1.IsRoutable());
}
BOOST_AUTO_TEST_CASE(embedded_test)
{
CNetAddr addr1(ResolveIP("1.2.3.4"));
@ -339,7 +326,6 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup)
BOOST_CHECK(ResolveIP("64:FF9B::102:304").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6052
BOOST_CHECK(ResolveIP("2002:102:304:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC3964
BOOST_CHECK(ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC4380
BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_ONION, 239})); // Tor
BOOST_CHECK(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net
BOOST_CHECK(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6
@ -559,10 +545,10 @@ BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0"s, ret));
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com"s, ret));
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com\0"s, ret));
BOOST_CHECK(LookupSubNet("5wyqrzbvrdsumnok.onion"s, ret));
BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0"s, ret));
BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com"s, ret));
BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com\0"s, ret));
BOOST_CHECK(LookupSubNet("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"s, ret));
BOOST_CHECK(!LookupSubNet("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion\0"s, ret));
BOOST_CHECK(!LookupSubNet("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion\0example.com"s, ret));
BOOST_CHECK(!LookupSubNet("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion\0example.com\0"s, ret));
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -147,13 +147,13 @@ class ProxyTest(BitcoinTestFramework):
self.network_test(node, addr, network=NET_IPV6)
if test_onion:
addr = "bitcoinostk4e4re.onion:8333"
addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:8333"
self.log.debug("Test: outgoing onion connection through node for address {}".format(addr))
node.addnode(addr, "onetry")
cmd = proxies[2].queue.get()
assert isinstance(cmd, Socks5Command)
assert_equal(cmd.atyp, AddressType.DOMAINNAME)
assert_equal(cmd.addr, b"bitcoinostk4e4re.onion")
assert_equal(cmd.addr, b"pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion")
assert_equal(cmd.port, 8333)
if not auth:
assert_equal(cmd.username, None)