Skip to content

Commit 7f31762

Browse files
committed
net: add an internal subnet for representing unresolved hostnames
We currently do two resolves for dns seeds: one for the results, and one to serve in addrman as the source for those addresses. There's no requirement that the source hostname resolves to the stored identifier, only that the mapping is unique. So rather than incurring the second lookup, combine a private subnet with a hash of the hostname. The resulting v6 ip is guaranteed not to be publicy routable, and has only a negligible chance of colliding with a user's internal network (which would be of no consequence anyway).
1 parent fbf5d3b commit 7f31762

File tree

5 files changed

+64
-9
lines changed

5 files changed

+64
-9
lines changed

src/net.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ bool RemoveLocal(const CService& addr)
240240
/** Make a particular network entirely off-limits (no automatic connects to it) */
241241
void SetLimited(enum Network net, bool fLimited)
242242
{
243-
if (net == NET_UNROUTABLE)
243+
if (net == NET_UNROUTABLE || net == NET_INTERNAL)
244244
return;
245245
LOCK(cs_mapLocalHost);
246246
vfLimited[net] = fLimited;

src/netaddress.cpp

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
1616
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
1717

18+
// 0xFD + sha256("bitcoin")[0:5]
19+
static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
20+
1821
void CNetAddr::Init()
1922
{
2023
memset(ip, 0, sizeof(ip));
@@ -42,6 +45,18 @@ void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
4245
}
4346
}
4447

48+
bool CNetAddr::SetInternal(const std::string &name)
49+
{
50+
if (name.empty()) {
51+
return false;
52+
}
53+
unsigned char hash[32] = {};
54+
CSHA256().Write((const unsigned char*)name.data(), name.size()).Finalize(hash);
55+
memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix));
56+
memcpy(ip + sizeof(g_internal_prefix), hash, sizeof(ip) - sizeof(g_internal_prefix));
57+
return true;
58+
}
59+
4560
bool CNetAddr::SetSpecial(const std::string &strName)
4661
{
4762
if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
@@ -84,7 +99,7 @@ bool CNetAddr::IsIPv4() const
8499

85100
bool CNetAddr::IsIPv6() const
86101
{
87-
return (!IsIPv4() && !IsTor());
102+
return (!IsIPv4() && !IsTor() && !IsInternal());
88103
}
89104

90105
bool CNetAddr::IsRFC1918() const
@@ -199,6 +214,9 @@ bool CNetAddr::IsValid() const
199214
if (IsRFC3849())
200215
return false;
201216

217+
if (IsInternal())
218+
return false;
219+
202220
if (IsIPv4())
203221
{
204222
// INADDR_NONE
@@ -217,11 +235,19 @@ bool CNetAddr::IsValid() const
217235

218236
bool CNetAddr::IsRoutable() const
219237
{
220-
return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());
238+
return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal() || IsInternal());
239+
}
240+
241+
bool CNetAddr::IsInternal() const
242+
{
243+
return memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0;
221244
}
222245

223246
enum Network CNetAddr::GetNetwork() const
224247
{
248+
if (IsInternal())
249+
return NET_INTERNAL;
250+
225251
if (!IsRoutable())
226252
return NET_UNROUTABLE;
227253

@@ -238,6 +264,8 @@ std::string CNetAddr::ToStringIP() const
238264
{
239265
if (IsTor())
240266
return EncodeBase32(&ip[6], 10) + ".onion";
267+
if (IsInternal())
268+
return EncodeBase32(ip + sizeof(g_internal_prefix), sizeof(ip) - sizeof(g_internal_prefix)) + ".internal";
241269
CService serv(*this, 0);
242270
struct sockaddr_storage sockaddr;
243271
socklen_t socklen = sizeof(sockaddr);
@@ -305,9 +333,15 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
305333
nClass = 255;
306334
nBits = 0;
307335
}
308-
309-
// all unroutable addresses belong to the same group
310-
if (!IsRoutable())
336+
// all internal-usage addresses get their own group
337+
if (IsInternal())
338+
{
339+
nClass = NET_INTERNAL;
340+
nStartByte = sizeof(g_internal_prefix);
341+
nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
342+
}
343+
// all other unroutable addresses belong to the same group
344+
else if (!IsRoutable())
311345
{
312346
nClass = NET_UNROUTABLE;
313347
nBits = 0;
@@ -393,7 +427,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
393427
REACH_PRIVATE
394428
};
395429

396-
if (!IsRoutable())
430+
if (!IsRoutable() || IsInternal())
397431
return REACH_UNREACHABLE;
398432

399433
int ourNet = GetExtNetwork(this);
@@ -552,7 +586,7 @@ std::string CService::ToStringPort() const
552586

553587
std::string CService::ToStringIPPort() const
554588
{
555-
if (IsIPv4() || IsTor()) {
589+
if (IsIPv4() || IsTor() || IsInternal()) {
556590
return ToStringIP() + ":" + ToStringPort();
557591
} else {
558592
return "[" + ToStringIP() + "]:" + ToStringPort();

src/netaddress.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum Network
2222
NET_IPV4,
2323
NET_IPV6,
2424
NET_TOR,
25+
NET_INTERNAL,
2526

2627
NET_MAX,
2728
};
@@ -45,6 +46,12 @@ class CNetAddr
4546
*/
4647
void SetRaw(Network network, const uint8_t *data);
4748

49+
/**
50+
* Transform an arbitrary string into a non-routable ipv6 address.
51+
* Useful for mapping resolved addresses back to their source.
52+
*/
53+
bool SetInternal(const std::string& name);
54+
4855
bool SetSpecial(const std::string &strName); // for Tor addresses
4956
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
5057
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor)
@@ -64,6 +71,7 @@ class CNetAddr
6471
bool IsTor() const;
6572
bool IsLocal() const;
6673
bool IsRoutable() const;
74+
bool IsInternal() const;
6775
bool IsValid() const;
6876
enum Network GetNetwork() const;
6977
std::string ToString() const;

src/rpc/net.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ static UniValue GetNetworksInfo()
397397
for(int n=0; n<NET_MAX; ++n)
398398
{
399399
enum Network network = static_cast<enum Network>(n);
400-
if(network == NET_UNROUTABLE)
400+
if(network == NET_UNROUTABLE || network == NET_INTERNAL)
401401
continue;
402402
proxyType proxy;
403403
UniValue obj(UniValue::VOBJ);

src/test/netbase_tests.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,21 @@ static CSubNet ResolveSubNet(const char* subnet)
2525
return ret;
2626
}
2727

28+
static CNetAddr CreateInternal(const char* host)
29+
{
30+
CNetAddr addr;
31+
addr.SetInternal(host);
32+
return addr;
33+
}
34+
2835
BOOST_AUTO_TEST_CASE(netbase_networks)
2936
{
3037
BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
3138
BOOST_CHECK(ResolveIP("::1").GetNetwork() == NET_UNROUTABLE);
3239
BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4);
3340
BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6);
3441
BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR);
42+
BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL);
3543

3644
}
3745

@@ -58,6 +66,8 @@ BOOST_AUTO_TEST_CASE(netbase_properties)
5866
BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable());
5967
BOOST_CHECK(ResolveIP("2001::1").IsRoutable());
6068
BOOST_CHECK(ResolveIP("127.0.0.1").IsValid());
69+
BOOST_CHECK(CreateInternal("FD6B:88C0:8724:edb1:8e4:3588:e546:35ca").IsInternal());
70+
BOOST_CHECK(CreateInternal("bar.com").IsInternal());
6171

6272
}
6373

@@ -281,6 +291,9 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup)
281291
BOOST_CHECK(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net
282292
BOOST_CHECK(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6
283293

294+
// baz.net sha256 hash: 12929400eb4607c4ac075f087167e75286b179c693eb059a01774b864e8fe505
295+
std::vector<unsigned char> internal_group = {NET_INTERNAL, 0x12, 0x92, 0x94, 0x00, 0xeb, 0x46, 0x07, 0xc4, 0xac, 0x07};
296+
BOOST_CHECK(CreateInternal("baz.net").GetGroup() == internal_group);
284297
}
285298

286299
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)