Changeset View
Changeset View
Standalone View
Standalone View
src/netaddress.cpp
Show All 20 Lines | |||||
* | * | ||||
* @note This address is considered invalid by CNetAddr::IsValid() | * @note This address is considered invalid by CNetAddr::IsValid() | ||||
*/ | */ | ||||
CNetAddr::CNetAddr() { | CNetAddr::CNetAddr() { | ||||
memset(ip, 0, sizeof(ip)); | memset(ip, 0, sizeof(ip)); | ||||
} | } | ||||
void CNetAddr::SetIP(const CNetAddr &ipIn) { | void CNetAddr::SetIP(const CNetAddr &ipIn) { | ||||
m_net = ipIn.m_net; | |||||
memcpy(ip, ipIn.ip, sizeof(ip)); | memcpy(ip, ipIn.ip, sizeof(ip)); | ||||
} | } | ||||
void CNetAddr::SetLegacyIPv6(const uint8_t ipv6[16]) { | |||||
if (memcmp(ipv6, pchIPv4, sizeof(pchIPv4)) == 0) { | |||||
m_net = NET_IPV4; | |||||
} else if (memcmp(ipv6, pchOnionCat, sizeof(pchOnionCat)) == 0) { | |||||
m_net = NET_ONION; | |||||
} else if (memcmp(ipv6, g_internal_prefix, sizeof(g_internal_prefix)) == | |||||
0) { | |||||
m_net = NET_INTERNAL; | |||||
} else { | |||||
m_net = NET_IPV6; | |||||
} | |||||
memcpy(ip, ipv6, 16); | |||||
} | |||||
void CNetAddr::SetRaw(Network network, const uint8_t *ip_in) { | void CNetAddr::SetRaw(Network network, const uint8_t *ip_in) { | ||||
switch (network) { | switch (network) { | ||||
case NET_IPV4: | case NET_IPV4: | ||||
m_net = NET_IPV4; | |||||
memcpy(ip, pchIPv4, 12); | memcpy(ip, pchIPv4, 12); | ||||
memcpy(ip + 12, ip_in, 4); | memcpy(ip + 12, ip_in, 4); | ||||
break; | break; | ||||
case NET_IPV6: | case NET_IPV6: | ||||
memcpy(ip, ip_in, 16); | SetLegacyIPv6(ip_in); | ||||
break; | break; | ||||
default: | default: | ||||
assert(!"invalid network"); | assert(!"invalid network"); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Try to make this a dummy address that maps the specified name into IPv6 like | * Try to make this a dummy address that maps the specified name into IPv6 like | ||||
* so: (0xFD + %sha256("bitcoin")[0:5]) + %sha256(name)[0:10]. Such dummy | * so: (0xFD + %sha256("bitcoin")[0:5]) + %sha256(name)[0:10]. Such dummy | ||||
* addresses have a prefix of fd6b:88c0:8724::/48 and are guaranteed to not be | * addresses have a prefix of fd6b:88c0:8724::/48 and are guaranteed to not be | ||||
* publicly routable as it falls under RFC4193's fc00::/7 subnet allocated to | * publicly routable as it falls under RFC4193's fc00::/7 subnet allocated to | ||||
* unique-local addresses. | * unique-local addresses. | ||||
* | * | ||||
* CAddrMan uses these fake addresses to keep track of which DNS seeds were | * CAddrMan uses these fake addresses to keep track of which DNS seeds were | ||||
* used. | * used. | ||||
* | * | ||||
* @returns Whether or not the operation was successful. | * @returns Whether or not the operation was successful. | ||||
* | * | ||||
* @see CNetAddr::IsInternal(), CNetAddr::IsRFC4193() | * @see CNetAddr::IsInternal(), CNetAddr::IsRFC4193() | ||||
*/ | */ | ||||
bool CNetAddr::SetInternal(const std::string &name) { | bool CNetAddr::SetInternal(const std::string &name) { | ||||
if (name.empty()) { | if (name.empty()) { | ||||
return false; | return false; | ||||
} | } | ||||
m_net = NET_INTERNAL; | |||||
uint8_t hash[32] = {}; | uint8_t hash[32] = {}; | ||||
CSHA256().Write((const uint8_t *)name.data(), name.size()).Finalize(hash); | CSHA256().Write((const uint8_t *)name.data(), name.size()).Finalize(hash); | ||||
memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix)); | memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix)); | ||||
memcpy(ip + sizeof(g_internal_prefix), hash, | memcpy(ip + sizeof(g_internal_prefix), hash, | ||||
sizeof(ip) - sizeof(g_internal_prefix)); | sizeof(ip) - sizeof(g_internal_prefix)); | ||||
return true; | return true; | ||||
} | } | ||||
Show All 10 Lines | |||||
bool CNetAddr::SetSpecial(const std::string &strName) { | bool CNetAddr::SetSpecial(const std::string &strName) { | ||||
if (strName.size() > 6 && | if (strName.size() > 6 && | ||||
strName.substr(strName.size() - 6, 6) == ".onion") { | strName.substr(strName.size() - 6, 6) == ".onion") { | ||||
std::vector<uint8_t> vchAddr = | std::vector<uint8_t> vchAddr = | ||||
DecodeBase32(strName.substr(0, strName.size() - 6).c_str()); | DecodeBase32(strName.substr(0, strName.size() - 6).c_str()); | ||||
if (vchAddr.size() != 16 - sizeof(pchOnionCat)) { | if (vchAddr.size() != 16 - sizeof(pchOnionCat)) { | ||||
return false; | return false; | ||||
} | } | ||||
m_net = NET_ONION; | |||||
memcpy(ip, pchOnionCat, sizeof(pchOnionCat)); | memcpy(ip, pchOnionCat, sizeof(pchOnionCat)); | ||||
for (unsigned int i = 0; i < 16 - sizeof(pchOnionCat); i++) { | for (unsigned int i = 0; i < 16 - sizeof(pchOnionCat); i++) { | ||||
ip[i + sizeof(pchOnionCat)] = vchAddr[i]; | ip[i + sizeof(pchOnionCat)] = vchAddr[i]; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
Show All 18 Lines | for (int i = 0; i < cmplen; ++i) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CNetAddr::IsIPv4() const { | bool CNetAddr::IsIPv4() const { | ||||
return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); | return m_net == NET_IPV4; | ||||
} | } | ||||
bool CNetAddr::IsIPv6() const { | bool CNetAddr::IsIPv6() const { | ||||
return !IsIPv4() && !IsTor() && !IsInternal(); | return m_net == NET_IPV6; | ||||
} | } | ||||
bool CNetAddr::IsRFC1918() const { | bool CNetAddr::IsRFC1918() const { | ||||
return IsIPv4() && | return IsIPv4() && | ||||
(GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) || | (GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) || | ||||
(GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); | (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); | ||||
} | } | ||||
Show All 14 Lines | |||||
bool CNetAddr::IsRFC5737() const { | bool CNetAddr::IsRFC5737() const { | ||||
return IsIPv4() && | return IsIPv4() && | ||||
((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) || | ((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) || | ||||
(GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) || | (GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) || | ||||
(GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113)); | (GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113)); | ||||
} | } | ||||
bool CNetAddr::IsRFC3849() const { | bool CNetAddr::IsRFC3849() const { | ||||
return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D && | return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 && | ||||
GetByte(12) == 0xB8; | GetByte(13) == 0x0D && GetByte(12) == 0xB8; | ||||
} | } | ||||
bool CNetAddr::IsRFC3964() const { | bool CNetAddr::IsRFC3964() const { | ||||
return (GetByte(15) == 0x20 && GetByte(14) == 0x02); | return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x02; | ||||
} | } | ||||
bool CNetAddr::IsRFC6052() const { | bool CNetAddr::IsRFC6052() const { | ||||
static const uint8_t pchRFC6052[] = {0, 0x64, 0xFF, 0x9B, 0, 0, | static const uint8_t pchRFC6052[] = {0, 0x64, 0xFF, 0x9B, 0, 0, | ||||
0, 0, 0, 0, 0, 0}; | 0, 0, 0, 0, 0, 0}; | ||||
return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0); | return IsIPv6() && memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0; | ||||
} | } | ||||
bool CNetAddr::IsRFC4380() const { | bool CNetAddr::IsRFC4380() const { | ||||
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 && | return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 && | ||||
GetByte(12) == 0); | GetByte(13) == 0 && GetByte(12) == 0; | ||||
} | } | ||||
bool CNetAddr::IsRFC4862() const { | bool CNetAddr::IsRFC4862() const { | ||||
static const uint8_t pchRFC4862[] = {0xFE, 0x80, 0, 0, 0, 0, 0, 0}; | static const uint8_t pchRFC4862[] = {0xFE, 0x80, 0, 0, 0, 0, 0, 0}; | ||||
return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0); | return IsIPv6() && memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0; | ||||
} | } | ||||
bool CNetAddr::IsRFC4193() const { | bool CNetAddr::IsRFC4193() const { | ||||
return ((GetByte(15) & 0xFE) == 0xFC); | return IsIPv6() && (GetByte(15) & 0xFE) == 0xFC; | ||||
} | } | ||||
bool CNetAddr::IsRFC6145() const { | bool CNetAddr::IsRFC6145() const { | ||||
static const uint8_t pchRFC6145[] = {0, 0, 0, 0, 0, 0, | static const uint8_t pchRFC6145[] = {0, 0, 0, 0, 0, 0, | ||||
0, 0, 0xFF, 0xFF, 0, 0}; | 0, 0, 0xFF, 0xFF, 0, 0}; | ||||
return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0); | return IsIPv6() && memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0; | ||||
} | } | ||||
bool CNetAddr::IsRFC4843() const { | bool CNetAddr::IsRFC4843() const { | ||||
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && | return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 && | ||||
(GetByte(12) & 0xF0) == 0x10); | GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10; | ||||
} | } | ||||
bool CNetAddr::IsRFC7343() const { | bool CNetAddr::IsRFC7343() const { | ||||
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && | return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 && | ||||
(GetByte(12) & 0xF0) == 0x20); | GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x20; | ||||
} | } | ||||
bool CNetAddr::IsHeNet() const { | bool CNetAddr::IsHeNet() const { | ||||
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && | return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && | ||||
GetByte(12) == 0x70); | GetByte(12) == 0x70); | ||||
} | } | ||||
/** | /** | ||||
* @returns Whether or not this is a dummy address that maps an onion address | * @returns Whether or not this is a dummy address that maps an onion address | ||||
* into IPv6. | * into IPv6. | ||||
* | * | ||||
* @see CNetAddr::SetSpecial(const std::string &) | * @see CNetAddr::SetSpecial(const std::string &) | ||||
*/ | */ | ||||
bool CNetAddr::IsTor() const { | bool CNetAddr::IsTor() const { | ||||
return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); | return m_net == NET_ONION; | ||||
} | } | ||||
bool CNetAddr::IsLocal() const { | bool CNetAddr::IsLocal() const { | ||||
// IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8) | // IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8) | ||||
if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) { | if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) { | ||||
return true; | return true; | ||||
} | } | ||||
// IPv6 loopback (::1/128) | // IPv6 loopback (::1/128) | ||||
static const uint8_t pchLocal[16] = {0, 0, 0, 0, 0, 0, 0, 0, | static const uint8_t pchLocal[16] = {0, 0, 0, 0, 0, 0, 0, 0, | ||||
0, 0, 0, 0, 0, 0, 0, 1}; | 0, 0, 0, 0, 0, 0, 0, 1}; | ||||
if (memcmp(ip, pchLocal, 16) == 0) { | if (IsIPv6() && memcmp(ip, pchLocal, 16) == 0) { | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
/** | /** | ||||
* @returns Whether or not this network address is a valid address that @a could | * @returns Whether or not this network address is a valid address that @a could | ||||
* be used to refer to an actual host. | * be used to refer to an actual host. | ||||
* | * | ||||
* @note A valid address may or may not be publicly routable on the global | * @note A valid address may or may not be publicly routable on the global | ||||
* internet. As in, the set of valid addresses is a superset of the set of | * internet. As in, the set of valid addresses is a superset of the set of | ||||
* publicly routable addresses. | * publicly routable addresses. | ||||
* | * | ||||
* @see CNetAddr::IsRoutable() | * @see CNetAddr::IsRoutable() | ||||
*/ | */ | ||||
bool CNetAddr::IsValid() const { | bool CNetAddr::IsValid() const { | ||||
// Cleanup 3-byte shifted addresses caused by garbage in size field of addr | // Cleanup 3-byte shifted addresses caused by garbage in size field of addr | ||||
// messages from versions before 0.2.9 checksum. | // messages from versions before 0.2.9 checksum. | ||||
// Two consecutive addr messages look like this: | // Two consecutive addr messages look like this: | ||||
// header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 | // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26 | ||||
// addr26 addr26... so if the first length field is garbled, it reads the | // addr26 addr26... so if the first length field is garbled, it reads the | ||||
// second batch of addr misaligned by 3 bytes. | // second batch of addr misaligned by 3 bytes. | ||||
if (memcmp(ip, pchIPv4 + 3, sizeof(pchIPv4) - 3) == 0) { | if (IsIPv6() && memcmp(ip, pchIPv4 + 3, sizeof(pchIPv4) - 3) == 0) { | ||||
return false; | return false; | ||||
} | } | ||||
// unspecified IPv6 address (::/128) | // unspecified IPv6 address (::/128) | ||||
uint8_t ipNone6[16] = {}; | uint8_t ipNone6[16] = {}; | ||||
if (memcmp(ip, ipNone6, 16) == 0) { | if (IsIPv6() && memcmp(ip, ipNone6, 16) == 0) { | ||||
return false; | return false; | ||||
} | } | ||||
// documentation IPv6 address | // documentation IPv6 address | ||||
if (IsRFC3849()) { | if (IsRFC3849()) { | ||||
return false; | return false; | ||||
} | } | ||||
Show All 35 Lines | |||||
} | } | ||||
/** | /** | ||||
* @returns Whether or not this is a dummy address that maps a name into IPv6. | * @returns Whether or not this is a dummy address that maps a name into IPv6. | ||||
* | * | ||||
* @see CNetAddr::SetInternal(const std::string &) | * @see CNetAddr::SetInternal(const std::string &) | ||||
*/ | */ | ||||
bool CNetAddr::IsInternal() const { | bool CNetAddr::IsInternal() const { | ||||
return memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0; | return m_net == NET_INTERNAL; | ||||
} | } | ||||
enum Network CNetAddr::GetNetwork() const { | enum Network CNetAddr::GetNetwork() const { | ||||
if (IsInternal()) { | if (IsInternal()) { | ||||
return NET_INTERNAL; | return NET_INTERNAL; | ||||
} | } | ||||
if (!IsRoutable()) { | if (!IsRoutable()) { | ||||
return NET_UNROUTABLE; | return NET_UNROUTABLE; | ||||
} | } | ||||
if (IsIPv4()) { | return m_net; | ||||
return NET_IPV4; | |||||
} | |||||
if (IsTor()) { | |||||
return NET_ONION; | |||||
} | |||||
return NET_IPV6; | |||||
} | } | ||||
std::string CNetAddr::ToStringIP() const { | std::string CNetAddr::ToStringIP() const { | ||||
if (IsTor()) { | if (IsTor()) { | ||||
return EncodeBase32(&ip[6], 10) + ".onion"; | return EncodeBase32(&ip[6], 10) + ".onion"; | ||||
} | } | ||||
if (IsInternal()) { | if (IsInternal()) { | ||||
return EncodeBase32(ip + sizeof(g_internal_prefix), | return EncodeBase32(ip + sizeof(g_internal_prefix), | ||||
Show All 23 Lines | return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", GetByte(15) << 8 | GetByte(14), | ||||
GetByte(1) << 8 | GetByte(0)); | GetByte(1) << 8 | GetByte(0)); | ||||
} | } | ||||
std::string CNetAddr::ToString() const { | std::string CNetAddr::ToString() const { | ||||
return ToStringIP(); | return ToStringIP(); | ||||
} | } | ||||
bool operator==(const CNetAddr &a, const CNetAddr &b) { | bool operator==(const CNetAddr &a, const CNetAddr &b) { | ||||
return (memcmp(a.ip, b.ip, 16) == 0); | return a.m_net == b.m_net && memcmp(a.ip, b.ip, 16) == 0; | ||||
} | } | ||||
bool operator<(const CNetAddr &a, const CNetAddr &b) { | bool operator<(const CNetAddr &a, const CNetAddr &b) { | ||||
return (memcmp(a.ip, b.ip, 16) < 0); | return a.m_net < b.m_net || | ||||
(a.m_net == b.m_net && memcmp(a.ip, b.ip, 16) < 0); | |||||
} | } | ||||
/** | /** | ||||
* Try to get our IPv4 address. | * Try to get our IPv4 address. | ||||
* | * | ||||
* @param[out] pipv4Addr The in_addr struct to which to copy. | * @param[out] pipv4Addr The in_addr struct to which to copy. | ||||
* | * | ||||
* @returns Whether or not the operation was successful, in particular, whether | * @returns Whether or not the operation was successful, in particular, whether | ||||
▲ Show 20 Lines • Show All 454 Lines • ▼ Show 20 Lines | CSubNet::CSubNet(const CNetAddr &addr) : valid(addr.IsValid()) { | ||||
network = addr; | network = addr; | ||||
} | } | ||||
/** | /** | ||||
* @returns True if this subnet is valid, the specified address is valid, and | * @returns True if this subnet is valid, the specified address is valid, and | ||||
* the specified address belongs in this subnet. | * the specified address belongs in this subnet. | ||||
*/ | */ | ||||
bool CSubNet::Match(const CNetAddr &addr) const { | bool CSubNet::Match(const CNetAddr &addr) const { | ||||
if (!valid || !addr.IsValid()) { | if (!valid || !addr.IsValid() || network.m_net != addr.m_net) { | ||||
return false; | return false; | ||||
} | } | ||||
for (int x = 0; x < 16; ++x) { | for (int x = 0; x < 16; ++x) { | ||||
if ((addr.ip[x] & netmask[x]) != network.ip[x]) { | if ((addr.ip[x] & netmask[x]) != network.ip[x]) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 93 Lines • Show Last 20 Lines |