asmap bucketing ported from Komodo
This commit is contained in:
107
src/netbase.cpp
107
src/netbase.cpp
@@ -30,6 +30,7 @@
|
||||
#include "random.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
#include "crypto/common.h" // for ReadBE32
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifdef HAVE_GETADDRINFO_A
|
||||
@@ -65,6 +66,9 @@ bool fNameLookup = false;
|
||||
|
||||
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
|
||||
|
||||
// 0xFD + sha256("bitcoin")[0:5]
|
||||
static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
|
||||
|
||||
// Need ample time for negotiation for very slow proxies such as Tor (milliseconds)
|
||||
static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
|
||||
|
||||
@@ -72,7 +76,7 @@ enum Network ParseNetwork(std::string net) {
|
||||
boost::to_lower(net);
|
||||
if (net == "ipv4") return NET_IPV4;
|
||||
if (net == "ipv6") return NET_IPV6;
|
||||
if (net == "tor" || net == "onion") return NET_TOR;
|
||||
if (net == "tor" || net == "onion") return NET_ONION;
|
||||
return NET_UNROUTABLE;
|
||||
}
|
||||
|
||||
@@ -81,7 +85,7 @@ std::string GetNetworkName(enum Network net) {
|
||||
{
|
||||
case NET_IPV4: return "ipv4";
|
||||
case NET_IPV6: return "ipv6";
|
||||
case NET_TOR: return "onion";
|
||||
case NET_ONION: return "onion";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
@@ -879,6 +883,11 @@ bool CNetAddr::IsRoutable() const
|
||||
return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());
|
||||
}
|
||||
|
||||
bool CNetAddr::IsInternal() const
|
||||
{
|
||||
return memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0;
|
||||
}
|
||||
|
||||
enum Network CNetAddr::GetNetwork() const
|
||||
{
|
||||
if (!IsRoutable())
|
||||
@@ -888,7 +897,7 @@ enum Network CNetAddr::GetNetwork() const
|
||||
return NET_IPV4;
|
||||
|
||||
if (IsTor())
|
||||
return NET_TOR;
|
||||
return NET_ONION;
|
||||
|
||||
return NET_IPV6;
|
||||
}
|
||||
@@ -949,11 +958,88 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CNetAddr::HasLinkedIPv4() const
|
||||
{
|
||||
return IsRoutable() && (IsIPv4() || IsRFC6145() || IsRFC6052() || IsRFC3964() || IsRFC4380());
|
||||
}
|
||||
|
||||
uint32_t CNetAddr::GetLinkedIPv4() const
|
||||
{
|
||||
if (IsIPv4() || IsRFC6145() || IsRFC6052()) {
|
||||
// IPv4, mapped IPv4, SIIT translated IPv4: the IPv4 address is the last 4 bytes of the address
|
||||
return ReadBE32(ip + 12);
|
||||
} else if (IsRFC3964()) {
|
||||
// 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6
|
||||
return ReadBE32(ip + 2);
|
||||
} else if (IsRFC4380()) {
|
||||
// Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the address, but bitflipped
|
||||
return ~ReadBE32(ip + 12);
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
uint32_t CNetAddr::GetNetClass() const {
|
||||
uint32_t net_class = NET_IPV6;
|
||||
if (IsLocal()) {
|
||||
net_class = 255;
|
||||
}
|
||||
if (IsInternal()) {
|
||||
net_class = NET_INTERNAL;
|
||||
} else if (!IsRoutable()) {
|
||||
net_class = NET_UNROUTABLE;
|
||||
} else if (HasLinkedIPv4()) {
|
||||
net_class = NET_IPV4;
|
||||
} else if (IsTor()) {
|
||||
net_class = NET_ONION;
|
||||
}
|
||||
return net_class;
|
||||
}
|
||||
|
||||
uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
|
||||
uint32_t net_class = GetNetClass();
|
||||
if (asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) {
|
||||
return 0; // Indicates not found, safe because AS0 is reserved per RFC7607.
|
||||
}
|
||||
std::vector<bool> ip_bits(128);
|
||||
if (HasLinkedIPv4()) {
|
||||
// For lookup, treat as if it was just an IPv4 address (pchIPv4 prefix + IPv4 bits)
|
||||
for (int8_t byte_i = 0; byte_i < 12; ++byte_i) {
|
||||
for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
|
||||
ip_bits[byte_i * 8 + bit_i] = (pchIPv4[byte_i] >> (7 - bit_i)) & 1;
|
||||
}
|
||||
}
|
||||
uint32_t ipv4 = GetLinkedIPv4();
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1;
|
||||
}
|
||||
} else {
|
||||
// Use all 128 bits of the IPv6 address otherwise
|
||||
for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
|
||||
uint8_t cur_byte = GetByte(15 - byte_i);
|
||||
for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
|
||||
ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t mapped_as = Interpret(asmap, ip_bits);
|
||||
return mapped_as;
|
||||
}
|
||||
|
||||
// get canonical identifier of an address' group
|
||||
// no two connections will be attempted to addresses with the same group
|
||||
std::vector<unsigned char> CNetAddr::GetGroup() const
|
||||
std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) const
|
||||
{
|
||||
std::vector<unsigned char> vchRet;
|
||||
// If non-empty asmap is supplied and the address is IPv4/IPv6,
|
||||
// return ASN to be used for bucketing.
|
||||
uint32_t asn = GetMappedAS(asmap);
|
||||
if (asn != 0) { // Either asmap was empty, or address has non-asmappable net class (e.g. TOR).
|
||||
vchRet.push_back(NET_IPV6); // IPv4 and IPv6 with same ASN should be in the same bucket
|
||||
for (int i = 0; i < 4; i++) {
|
||||
vchRet.push_back((asn >> (8 * i)) & 0xFF);
|
||||
}
|
||||
return vchRet;
|
||||
}
|
||||
int nClass = NET_IPV6;
|
||||
int nStartByte = 0;
|
||||
int nBits = 16;
|
||||
@@ -994,7 +1080,7 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
|
||||
}
|
||||
else if (IsTor())
|
||||
{
|
||||
nClass = NET_TOR;
|
||||
nClass = NET_ONION;
|
||||
nStartByte = 6;
|
||||
nBits = 4;
|
||||
}
|
||||
@@ -1072,11 +1158,11 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
|
||||
case NET_IPV4: return REACH_IPV4;
|
||||
case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled
|
||||
}
|
||||
case NET_TOR:
|
||||
case NET_ONION:
|
||||
switch(ourNet) {
|
||||
default: return REACH_DEFAULT;
|
||||
case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well
|
||||
case NET_TOR: return REACH_PRIVATE;
|
||||
case NET_ONION: return REACH_PRIVATE;
|
||||
}
|
||||
case NET_TEREDO:
|
||||
switch(ourNet) {
|
||||
@@ -1093,7 +1179,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
|
||||
case NET_TEREDO: return REACH_TEREDO;
|
||||
case NET_IPV6: return REACH_IPV6_WEAK;
|
||||
case NET_IPV4: return REACH_IPV4;
|
||||
case NET_TOR: return REACH_PRIVATE; // either from Tor, or don't care about our address
|
||||
case NET_ONION: return REACH_PRIVATE; // either from Tor, or don't care about our address
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1443,3 +1529,8 @@ bool SetSocketNonBlocking(SOCKET& hSocket, bool fNonBlocking)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SanityCheckASMap(const std::vector<bool>& asmap)
|
||||
{
|
||||
return SanityCheckASMap(asmap, 128); // For IP address lookups, the input is 128 bits
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user