Skip to content

Commit 2772dc9

Browse files
committed
Merge #10446: net: avoid extra dns query per seed
c1be285 chainparams: make supported service bits option explicit (Cory Fields) d5c7c1c net: use an internal address for fixed seeds (Cory Fields) 6cdc488 net: switch to dummy internal ip for dns seed source (Cory Fields) 6d0bd5b net: do not allow resolving to an internal address (Cory Fields) 7f31762 net: add an internal subnet for representing unresolved hostnames (Cory Fields) Tree-SHA512: 9bf1042bef546ac3ef0e0d3a9a5555eb21628ff2674a0cf8c6367194b22bfdab477adf452c0e7c56f44e0fb37debc5e14bdb623452e076fb9c492c7702601d7a
2 parents 232508f + c1be285 commit 2772dc9

File tree

8 files changed

+96
-37
lines changed

8 files changed

+96
-37
lines changed

src/chainparams.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,12 @@ class CMainParams : public CChainParams {
124124
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
125125

126126
// Note that of those with the service bits flag, most only support a subset of possible options
127-
vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be", true)); // Pieter Wuille, only supports x1, x5, x9, and xd
128-
vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me", true)); // Matt Corallo, only supports x9
129-
vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr
130-
vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com", true)); // Christian Decker, supports x1 - xf
131-
vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli, only supports x1, x5, x9, and xd
132-
vSeeds.push_back(CDNSSeedData("petertodd.org", "seed.btc.petertodd.org", true)); // Peter Todd, only supports x1, x5, x9, and xd
127+
vSeeds.emplace_back("seed.bitcoin.sipa.be", true); // Pieter Wuille, only supports x1, x5, x9, and xd
128+
vSeeds.emplace_back("dnsseed.bluematt.me", true); // Matt Corallo, only supports x9
129+
vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org", false); // Luke Dashjr
130+
vSeeds.emplace_back("seed.bitcoinstats.com", true); // Christian Decker, supports x1 - xf
131+
vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch", true); // Jonas Schnelli, only supports x1, x5, x9, and xd
132+
vSeeds.emplace_back("seed.btc.petertodd.org", true); // Peter Todd, only supports x1, x5, x9, and xd
133133

134134
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
135135
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
@@ -225,10 +225,10 @@ class CTestNetParams : public CChainParams {
225225
vFixedSeeds.clear();
226226
vSeeds.clear();
227227
// nodes with support for servicebits filtering should be at the top
228-
vSeeds.push_back(CDNSSeedData("testnetbitcoin.jonasschnelli.ch", "testnet-seed.bitcoin.jonasschnelli.ch", true));
229-
vSeeds.push_back(CDNSSeedData("petertodd.org", "seed.tbtc.petertodd.org", true));
230-
vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me"));
231-
vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de"));
228+
vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch", true);
229+
vSeeds.emplace_back("seed.tbtc.petertodd.org", true);
230+
vSeeds.emplace_back("testnet-seed.bluematt.me", false);
231+
vSeeds.emplace_back("testnet-seed.bitcoin.schildbach.de", false);
232232

233233
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
234234
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);

src/chainparams.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
#include <vector>
1616

1717
struct CDNSSeedData {
18-
std::string name, host;
18+
std::string host;
1919
bool supportsServiceBitsFiltering;
20-
CDNSSeedData(const std::string &strName, const std::string &strHost, bool supportsServiceBitsFilteringIn = false) : name(strName), host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {}
20+
CDNSSeedData(const std::string &strHost, bool supportsServiceBitsFilteringIn) : host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {}
2121
};
2222

2323
struct SeedSpec6 {

src/net.cpp

Lines changed: 9 additions & 15 deletions
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;
@@ -1604,7 +1604,12 @@ void CConnman::ThreadDNSAddressSeed()
16041604
std::vector<CNetAddr> vIPs;
16051605
std::vector<CAddress> vAdd;
16061606
ServiceFlags requiredServiceBits = nRelevantServices;
1607-
if (LookupHost(GetDNSHost(seed, &requiredServiceBits).c_str(), vIPs, 0, true))
1607+
std::string host = GetDNSHost(seed, &requiredServiceBits);
1608+
CNetAddr resolveSource;
1609+
if (!resolveSource.SetInternal(host)) {
1610+
continue;
1611+
}
1612+
if (LookupHost(host.c_str(), vIPs, 0, true))
16081613
{
16091614
for (const CNetAddr& ip : vIPs)
16101615
{
@@ -1614,18 +1619,7 @@ void CConnman::ThreadDNSAddressSeed()
16141619
vAdd.push_back(addr);
16151620
found++;
16161621
}
1617-
}
1618-
if (interruptNet) {
1619-
return;
1620-
}
1621-
// TODO: The seed name resolve may fail, yielding an IP of [::], which results in
1622-
// addrman assigning the same source to results from different seeds.
1623-
// This should switch to a hard-coded stable dummy IP for each seed name, so that the
1624-
// resolve is not required at all.
1625-
if (!vIPs.empty()) {
1626-
CService seedSource;
1627-
Lookup(seed.name.c_str(), seedSource, 0, true);
1628-
addrman.Add(vAdd, seedSource);
1622+
addrman.Add(vAdd, resolveSource);
16291623
}
16301624
}
16311625
}
@@ -1724,7 +1718,7 @@ void CConnman::ThreadOpenConnections()
17241718
if (!done) {
17251719
LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n");
17261720
CNetAddr local;
1727-
LookupHost("127.0.0.1", local, false);
1721+
local.SetInternal("fixedseeds");
17281722
addrman.Add(convertSeed6(Params().FixedSeeds()), local);
17291723
done = true;
17301724
}

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/netbase.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,22 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
108108
struct addrinfo *aiTrav = aiRes;
109109
while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
110110
{
111+
CNetAddr resolved;
111112
if (aiTrav->ai_family == AF_INET)
112113
{
113114
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
114-
vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr));
115+
resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
115116
}
116117

117118
if (aiTrav->ai_family == AF_INET6)
118119
{
119120
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
120121
struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
121-
vIP.push_back(CNetAddr(s6->sin6_addr, s6->sin6_scope_id));
122+
resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
123+
}
124+
/* Never allow resolving to an internal address. Consider any such result invalid */
125+
if (!resolved.IsInternal()) {
126+
vIP.push_back(resolved);
122127
}
123128

124129
aiTrav = aiTrav->ai_next;

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: 18 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

@@ -103,6 +113,11 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
103113
BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
104114
BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
105115
BOOST_CHECK(TestParse(":::", "[::]:0"));
116+
117+
// verify that an internal address fails to resolve
118+
BOOST_CHECK(TestParse("[fd6b:88c0:8724:1:2:3:4:5]", "[::]:0"));
119+
// and that a one-off resolves correctly
120+
BOOST_CHECK(TestParse("[fd6c:88c0:8724:1:2:3:4:5]", "[fd6c:88c0:8724:1:2:3:4:5]:65535"));
106121
}
107122

108123
BOOST_AUTO_TEST_CASE(onioncat_test)
@@ -281,6 +296,9 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup)
281296
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
282297
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
283298

299+
// baz.net sha256 hash: 12929400eb4607c4ac075f087167e75286b179c693eb059a01774b864e8fe505
300+
std::vector<unsigned char> internal_group = {NET_INTERNAL, 0x12, 0x92, 0x94, 0x00, 0xeb, 0x46, 0x07, 0xc4, 0xac, 0x07};
301+
BOOST_CHECK(CreateInternal("baz.net").GetGroup() == internal_group);
284302
}
285303

286304
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)