Changeset View
Changeset View
Standalone View
Standalone View
src/netaddress.cpp
Show First 20 Lines • Show All 398 Lines • ▼ Show 20 Lines | |||||
bool CNetAddr::GetIn6Addr(struct in6_addr *pipv6Addr) const { | bool CNetAddr::GetIn6Addr(struct in6_addr *pipv6Addr) const { | ||||
if (!IsIPv6()) { | if (!IsIPv6()) { | ||||
return false; | return false; | ||||
} | } | ||||
memcpy(pipv6Addr, ip, 16); | memcpy(pipv6Addr, ip, 16); | ||||
return true; | return true; | ||||
} | } | ||||
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 (IsIPv4() || IsRFC6145() || IsRFC6052() || IsRFC3964() || | |||||
IsRFC4380()) { | |||||
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); | |||||
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 the canonical identifier of our network group | * Get the canonical identifier of our network group | ||||
* | * | ||||
* The groups are assigned in a way where it should be costly for an attacker to | * The groups are assigned in a way where it should be costly for an attacker to | ||||
* obtain addresses with many different group identifiers, even if it is cheap | * obtain addresses with many different group identifiers, even if it is cheap | ||||
* to obtain addresses with the same identifier. | * to obtain addresses with the same identifier. | ||||
* | * | ||||
* @note No two connections will be attempted to addresses with the same network | * @note No two connections will be attempted to addresses with the same network | ||||
* group. | * group. | ||||
*/ | */ | ||||
std::vector<uint8_t> CNetAddr::GetGroup(const std::vector<bool> &asmap) const { | std::vector<uint8_t> CNetAddr::GetGroup(const std::vector<bool> &asmap) const { | ||||
std::vector<uint8_t> vchRet; | std::vector<uint8_t> vchRet; | ||||
int nClass = NET_IPV6; | uint32_t net_class = GetNetClass(); | ||||
// 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; | |||||
} | |||||
vchRet.push_back(net_class); | |||||
int nStartByte = 0; | int nStartByte = 0; | ||||
int nBits = 16; | int nBits = 16; | ||||
// all local addresses belong to the same group | // all local addresses belong to the same group | ||||
if (IsLocal()) { | if (IsLocal()) { | ||||
nClass = 255; | |||||
nBits = 0; | nBits = 0; | ||||
} | } | ||||
if (IsInternal()) { | if (IsInternal()) { | ||||
// all internal-usage addresses get their own group | // all internal-usage addresses get their own group | ||||
nClass = NET_INTERNAL; | |||||
nStartByte = sizeof(g_internal_prefix); | nStartByte = sizeof(g_internal_prefix); | ||||
nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8; | nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8; | ||||
} else if (!IsRoutable()) { | } else if (!IsRoutable()) { | ||||
// all other unroutable addresses belong to the same group | // all other unroutable addresses belong to the same group | ||||
nClass = NET_UNROUTABLE; | |||||
nBits = 0; | nBits = 0; | ||||
} else if (IsIPv4() || IsRFC6145() || IsRFC6052()) { | } else if (IsIPv4() || IsRFC6145() || IsRFC6052()) { | ||||
// for IPv4 addresses, '1' + the 16 higher-order bits of the IP includes | // for IPv4 addresses, '1' + the 16 higher-order bits of the IP includes | ||||
// mapped IPv4, SIIT translated IPv4, and the well-known prefix | // mapped IPv4, SIIT translated IPv4, and the well-known prefix | ||||
nClass = NET_IPV4; | |||||
nStartByte = 12; | nStartByte = 12; | ||||
} else if (IsRFC3964()) { | } else if (IsRFC3964()) { | ||||
// for 6to4 tunnelled addresses, use the encapsulated IPv4 address | // for 6to4 tunnelled addresses, use the encapsulated IPv4 address | ||||
nClass = NET_IPV4; | |||||
nStartByte = 2; | nStartByte = 2; | ||||
} else if (IsRFC4380()) { | } else if (IsRFC4380()) { | ||||
// for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 | // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 | ||||
// address | // address | ||||
vchRet.push_back(NET_IPV4); | |||||
vchRet.push_back(GetByte(3) ^ 0xFF); | vchRet.push_back(GetByte(3) ^ 0xFF); | ||||
vchRet.push_back(GetByte(2) ^ 0xFF); | vchRet.push_back(GetByte(2) ^ 0xFF); | ||||
return vchRet; | return vchRet; | ||||
} else if (IsTor()) { | } else if (IsTor()) { | ||||
nClass = NET_ONION; | |||||
nStartByte = 6; | nStartByte = 6; | ||||
nBits = 4; | nBits = 4; | ||||
} else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && | } else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && | ||||
GetByte(13) == 0x04 && GetByte(12) == 0x70) { | GetByte(13) == 0x04 && GetByte(12) == 0x70) { | ||||
// for he.net, use /36 groups | // for he.net, use /36 groups | ||||
nBits = 36; | nBits = 36; | ||||
} else { | } else { | ||||
// for the rest of the IPv6 network, use /32 groups | // for the rest of the IPv6 network, use /32 groups | ||||
nBits = 32; | nBits = 32; | ||||
} | } | ||||
// If asmap is supplied and the address is IPv4/IPv6, | |||||
// ignore nBits and use 32/128 bits to obtain ASN from asmap. | |||||
// ASN is then returned to be used for bucketing. | |||||
if (asmap.size() != 0 && (nClass == NET_IPV4 || nClass == NET_IPV6)) { | |||||
nClass = NET_IPV6; | |||||
std::vector<bool> ip_bits(128); | |||||
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 asn = Interpret(asmap, ip_bits); | |||||
vchRet.push_back(nClass); | |||||
for (int i = 0; i < 4; i++) { | |||||
vchRet.push_back((asn >> (8 * i)) & 0xFF); | |||||
} | |||||
return vchRet; | |||||
} | |||||
vchRet.push_back(nClass); | |||||
// push our ip onto vchRet byte by byte... | // push our ip onto vchRet byte by byte... | ||||
while (nBits >= 8) { | while (nBits >= 8) { | ||||
vchRet.push_back(GetByte(15 - nStartByte)); | vchRet.push_back(GetByte(15 - nStartByte)); | ||||
nStartByte++; | nStartByte++; | ||||
nBits -= 8; | nBits -= 8; | ||||
} | } | ||||
// ...for the last byte, push nBits and for the rest of the byte push 1's | // ...for the last byte, push nBits and for the rest of the byte push 1's | ||||
if (nBits > 0) { | if (nBits > 0) { | ||||
▲ Show 20 Lines • Show All 395 Lines • Show Last 20 Lines |