Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ class CMainParams : public CChainParams {
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));

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

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

base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
Expand Down
4 changes: 2 additions & 2 deletions src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
#include <vector>

struct CDNSSeedData {
std::string name, host;
std::string host;
bool supportsServiceBitsFiltering;
CDNSSeedData(const std::string &strName, const std::string &strHost, bool supportsServiceBitsFilteringIn = false) : name(strName), host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {}
CDNSSeedData(const std::string &strHost, bool supportsServiceBitsFilteringIn) : host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {}
};

struct SeedSpec6 {
Expand Down
24 changes: 9 additions & 15 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ bool RemoveLocal(const CService& addr)
/** Make a particular network entirely off-limits (no automatic connects to it) */
void SetLimited(enum Network net, bool fLimited)
{
if (net == NET_UNROUTABLE)
if (net == NET_UNROUTABLE || net == NET_INTERNAL)
return;
LOCK(cs_mapLocalHost);
vfLimited[net] = fLimited;
Expand Down Expand Up @@ -1604,7 +1604,12 @@ void CConnman::ThreadDNSAddressSeed()
std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd;
ServiceFlags requiredServiceBits = nRelevantServices;
if (LookupHost(GetDNSHost(seed, &requiredServiceBits).c_str(), vIPs, 0, true))
std::string host = GetDNSHost(seed, &requiredServiceBits);
CNetAddr resolveSource;
if (!resolveSource.SetInternal(host)) {
continue;
}
if (LookupHost(host.c_str(), vIPs, 0, true))
{
BOOST_FOREACH(const CNetAddr& ip, vIPs)
{
Expand All @@ -1614,18 +1619,7 @@ void CConnman::ThreadDNSAddressSeed()
vAdd.push_back(addr);
found++;
}
}
if (interruptNet) {
return;
}
// TODO: The seed name resolve may fail, yielding an IP of [::], which results in
// addrman assigning the same source to results from different seeds.
// This should switch to a hard-coded stable dummy IP for each seed name, so that the
// resolve is not required at all.
if (!vIPs.empty()) {
CService seedSource;
Lookup(seed.name.c_str(), seedSource, 0, true);
addrman.Add(vAdd, seedSource);
addrman.Add(vAdd, resolveSource);
}
}
}
Expand Down Expand Up @@ -1724,7 +1718,7 @@ void CConnman::ThreadOpenConnections()
if (!done) {
LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n");
CNetAddr local;
LookupHost("127.0.0.1", local, false);
local.SetInternal("fixedseeds");
addrman.Add(convertSeed6(Params().FixedSeeds()), local);
done = true;
}
Expand Down
48 changes: 41 additions & 7 deletions src/netaddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};

// 0xFD + sha256("bitcoin")[0:5]
static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };

void CNetAddr::Init()
{
memset(ip, 0, sizeof(ip));
Expand Down Expand Up @@ -42,6 +45,18 @@ void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
}
}

bool CNetAddr::SetInternal(const std::string &name)
{
if (name.empty()) {
return false;
}
unsigned char hash[32] = {};
CSHA256().Write((const unsigned char*)name.data(), name.size()).Finalize(hash);
memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix));
memcpy(ip + sizeof(g_internal_prefix), hash, sizeof(ip) - sizeof(g_internal_prefix));
return true;
}

bool CNetAddr::SetSpecial(const std::string &strName)
{
if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
Expand Down Expand Up @@ -84,7 +99,7 @@ bool CNetAddr::IsIPv4() const

bool CNetAddr::IsIPv6() const
{
return (!IsIPv4() && !IsTor());
return (!IsIPv4() && !IsTor() && !IsInternal());
}

bool CNetAddr::IsRFC1918() const
Expand Down Expand Up @@ -199,6 +214,9 @@ bool CNetAddr::IsValid() const
if (IsRFC3849())
return false;

if (IsInternal())
return false;

if (IsIPv4())
{
// INADDR_NONE
Expand All @@ -217,11 +235,19 @@ bool CNetAddr::IsValid() const

bool CNetAddr::IsRoutable() const
{
return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());
return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal() || IsInternal());
}

bool CNetAddr::IsInternal() const
{
return memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0;
}

enum Network CNetAddr::GetNetwork() const
{
if (IsInternal())
return NET_INTERNAL;

if (!IsRoutable())
return NET_UNROUTABLE;

Expand All @@ -238,6 +264,8 @@ std::string CNetAddr::ToStringIP() const
{
if (IsTor())
return EncodeBase32(&ip[6], 10) + ".onion";
if (IsInternal())
return EncodeBase32(ip + sizeof(g_internal_prefix), sizeof(ip) - sizeof(g_internal_prefix)) + ".internal";
CService serv(*this, 0);
struct sockaddr_storage sockaddr;
socklen_t socklen = sizeof(sockaddr);
Expand Down Expand Up @@ -305,9 +333,15 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
nClass = 255;
nBits = 0;
}

// all unroutable addresses belong to the same group
if (!IsRoutable())
// all internal-usage addresses get their own group
if (IsInternal())
{
nClass = NET_INTERNAL;
nStartByte = sizeof(g_internal_prefix);
nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
}
// all other unroutable addresses belong to the same group
else if (!IsRoutable())
{
nClass = NET_UNROUTABLE;
nBits = 0;
Expand Down Expand Up @@ -393,7 +427,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
REACH_PRIVATE
};

if (!IsRoutable())
if (!IsRoutable() || IsInternal())
return REACH_UNREACHABLE;

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

std::string CService::ToStringIPPort() const
{
if (IsIPv4() || IsTor()) {
if (IsIPv4() || IsTor() || IsInternal()) {
return ToStringIP() + ":" + ToStringPort();
} else {
return "[" + ToStringIP() + "]:" + ToStringPort();
Expand Down
8 changes: 8 additions & 0 deletions src/netaddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum Network
NET_IPV4,
NET_IPV6,
NET_TOR,
NET_INTERNAL,

NET_MAX,
};
Expand All @@ -45,6 +46,12 @@ class CNetAddr
*/
void SetRaw(Network network, const uint8_t *data);

/**
* Transform an arbitrary string into a non-routable ipv6 address.
* Useful for mapping resolved addresses back to their source.
*/
bool SetInternal(const std::string& name);

bool SetSpecial(const std::string &strName); // for Tor addresses
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor)
Expand All @@ -64,6 +71,7 @@ class CNetAddr
bool IsTor() const;
bool IsLocal() const;
bool IsRoutable() const;
bool IsInternal() const;
bool IsValid() const;
enum Network GetNetwork() const;
std::string ToString() const;
Expand Down
9 changes: 7 additions & 2 deletions src/netbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,22 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
struct addrinfo *aiTrav = aiRes;
while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
{
CNetAddr resolved;
if (aiTrav->ai_family == AF_INET)
{
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr));
resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
}

if (aiTrav->ai_family == AF_INET6)
{
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
vIP.push_back(CNetAddr(s6->sin6_addr, s6->sin6_scope_id));
resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
}
/* Never allow resolving to an internal address. Consider any such result invalid */
if (!resolved.IsInternal()) {
vIP.push_back(resolved);
}

aiTrav = aiTrav->ai_next;
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ static UniValue GetNetworksInfo()
for(int n=0; n<NET_MAX; ++n)
{
enum Network network = static_cast<enum Network>(n);
if(network == NET_UNROUTABLE)
if(network == NET_UNROUTABLE || network == NET_INTERNAL)
continue;
proxyType proxy;
UniValue obj(UniValue::VOBJ);
Expand Down
18 changes: 18 additions & 0 deletions src/test/netbase_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,21 @@ static CSubNet ResolveSubNet(const char* subnet)
return ret;
}

static CNetAddr CreateInternal(const char* host)
{
CNetAddr addr;
addr.SetInternal(host);
return addr;
}

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_TOR);
BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL);

}

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

}

Expand Down Expand Up @@ -103,6 +113,11 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
BOOST_CHECK(TestParse(":::", "[::]:0"));

// verify that an internal address fails to resolve
BOOST_CHECK(TestParse("[fd6b:88c0:8724:1:2:3:4:5]", "[::]:0"));
// and that a one-off resolves correctly
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)
Expand Down Expand Up @@ -281,6 +296,9 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup)
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
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

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

BOOST_AUTO_TEST_SUITE_END()