Changeset View
Changeset View
Standalone View
Standalone View
src/netaddress.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <netaddress.h> | #include <netaddress.h> | ||||
#include <hash.h> | #include <hash.h> | ||||
#include <tinyformat.h> | |||||
#include <util/asmap.h> | #include <util/asmap.h> | ||||
#include <util/strencodings.h> | #include <util/strencodings.h> | ||||
static const uint8_t pchIPv4[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; | #include <tinyformat.h> | ||||
static const uint8_t pchOnionCat[] = {0xFD, 0x87, 0xD8, 0x7E, 0xEB, 0x43}; | |||||
#include <algorithm> | |||||
#include <array> | |||||
#include <cstdint> | |||||
#include <iterator> | |||||
#include <tuple> | |||||
// 0xFD + sha256("bitcoin")[0:5] | constexpr size_t CNetAddr::V1_SERIALIZATION_SIZE; | ||||
static const uint8_t g_internal_prefix[] = {0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24}; | |||||
/** | /** | ||||
* Construct an unspecified IPv6 network address (::/128). | * Construct an unspecified IPv6 network address (::/128). | ||||
* | * | ||||
* @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)); | |||||
} | |||||
void CNetAddr::SetIP(const CNetAddr &ipIn) { | void CNetAddr::SetIP(const CNetAddr &ipIn) { | ||||
// Size check. | |||||
switch (ipIn.m_net) { | |||||
case NET_IPV4: | |||||
assert(ipIn.m_addr.size() == ADDR_IPV4_SIZE); | |||||
break; | |||||
case NET_IPV6: | |||||
assert(ipIn.m_addr.size() == ADDR_IPV6_SIZE); | |||||
break; | |||||
case NET_ONION: | |||||
assert(ipIn.m_addr.size() == ADDR_TORV2_SIZE); | |||||
break; | |||||
case NET_INTERNAL: | |||||
assert(ipIn.m_addr.size() == ADDR_INTERNAL_SIZE); | |||||
break; | |||||
case NET_UNROUTABLE: | |||||
case NET_MAX: | |||||
assert(false); | |||||
} // no default case, so the compiler can warn about missing cases | |||||
m_net = ipIn.m_net; | m_net = ipIn.m_net; | ||||
memcpy(ip, ipIn.ip, sizeof(ip)); | m_addr = ipIn.m_addr; | ||||
} | |||||
template <typename T1, size_t PREFIX_LEN> | |||||
inline bool HasPrefix(const T1 &obj, | |||||
const std::array<uint8_t, PREFIX_LEN> &prefix) { | |||||
return obj.size() >= PREFIX_LEN && | |||||
std::equal(std::begin(prefix), std::end(prefix), std::begin(obj)); | |||||
} | } | ||||
void CNetAddr::SetLegacyIPv6(const uint8_t ipv6[16]) { | void CNetAddr::SetLegacyIPv6(Span<const uint8_t> ipv6) { | ||||
if (memcmp(ipv6, pchIPv4, sizeof(pchIPv4)) == 0) { | assert(ipv6.size() == ADDR_IPV6_SIZE); | ||||
size_t skip{0}; | |||||
if (HasPrefix(ipv6, IPV4_IN_IPV6_PREFIX)) { | |||||
// IPv4-in-IPv6 | |||||
m_net = NET_IPV4; | m_net = NET_IPV4; | ||||
} else if (memcmp(ipv6, pchOnionCat, sizeof(pchOnionCat)) == 0) { | skip = sizeof(IPV4_IN_IPV6_PREFIX); | ||||
} else if (HasPrefix(ipv6, TORV2_IN_IPV6_PREFIX)) { | |||||
// TORv2-in-IPv6 | |||||
m_net = NET_ONION; | m_net = NET_ONION; | ||||
} else if (memcmp(ipv6, g_internal_prefix, sizeof(g_internal_prefix)) == | skip = sizeof(TORV2_IN_IPV6_PREFIX); | ||||
0) { | } else if (HasPrefix(ipv6, INTERNAL_IN_IPV6_PREFIX)) { | ||||
// Internal-in-IPv6 | |||||
m_net = NET_INTERNAL; | m_net = NET_INTERNAL; | ||||
skip = sizeof(INTERNAL_IN_IPV6_PREFIX); | |||||
} else { | } else { | ||||
// IPv6 | |||||
m_net = NET_IPV6; | m_net = NET_IPV6; | ||||
} | } | ||||
memcpy(ip, ipv6, 16); | |||||
} | |||||
void CNetAddr::SetRaw(Network network, const uint8_t *ip_in) { | m_addr.assign(ipv6.begin() + skip, ipv6.end()); | ||||
switch (network) { | |||||
case NET_IPV4: | |||||
m_net = NET_IPV4; | |||||
memcpy(ip, pchIPv4, 12); | |||||
memcpy(ip + 12, ip_in, 4); | |||||
break; | |||||
case NET_IPV6: | |||||
SetLegacyIPv6(ip_in); | |||||
break; | |||||
default: | |||||
assert(!"invalid network"); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
* Try to make this a dummy address that maps the specified name into IPv6 like | * Create an "internal" address that represents a name or FQDN. CAddrMan uses | ||||
* so: (0xFD + %sha256("bitcoin")[0:5]) + %sha256(name)[0:10]. Such dummy | * these fake addresses to keep track of which DNS seeds were used. | ||||
* 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 | |||||
* unique-local addresses. | |||||
* | |||||
* CAddrMan uses these fake addresses to keep track of which DNS seeds were | |||||
* used. | |||||
* | |||||
* @returns Whether or not the operation was successful. | * @returns Whether or not the operation was successful. | ||||
* | * @see NET_INTERNAL, INTERNAL_IN_IPV6_PREFIX, CNetAddr::IsInternal(), | ||||
* @see CNetAddr::IsInternal(), CNetAddr::IsRFC4193() | * 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; | 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)); | m_addr.assign(hash, hash + ADDR_INTERNAL_SIZE); | ||||
memcpy(ip + sizeof(g_internal_prefix), hash, | |||||
sizeof(ip) - sizeof(g_internal_prefix)); | |||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* Try to make this a dummy address that maps the specified onion address into | * Parse a TORv2 address and set this object to it. | ||||
* IPv6 using OnionCat's range and encoding. Such dummy addresses have a prefix | |||||
* of fd87:d87e:eb43::/48 and are guaranteed to not be publicly routable as they | |||||
* fall under RFC4193's fc00::/7 subnet allocated to unique-local addresses. | |||||
* | * | ||||
* @returns Whether or not the operation was successful. | * @returns Whether or not the operation was successful. | ||||
* | * | ||||
* @see CNetAddr::IsTor(), CNetAddr::IsRFC4193() | * @see CNetAddr::IsTor() | ||||
*/ | */ | ||||
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() != ADDR_TORV2_SIZE) { | ||||
return false; | return false; | ||||
} | } | ||||
m_net = NET_ONION; | m_net = NET_ONION; | ||||
memcpy(ip, pchOnionCat, sizeof(pchOnionCat)); | m_addr.assign(vchAddr.begin(), vchAddr.end()); | ||||
for (unsigned int i = 0; i < 16 - sizeof(pchOnionCat); i++) { | |||||
ip[i + sizeof(pchOnionCat)] = vchAddr[i]; | |||||
} | |||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
CNetAddr::CNetAddr(const struct in_addr &ipv4Addr) { | CNetAddr::CNetAddr(const struct in_addr &ipv4Addr) { | ||||
SetRaw(NET_IPV4, (const uint8_t *)&ipv4Addr); | m_net = NET_IPV4; | ||||
const uint8_t *ptr = reinterpret_cast<const uint8_t *>(&ipv4Addr); | |||||
m_addr.assign(ptr, ptr + ADDR_IPV4_SIZE); | |||||
} | } | ||||
CNetAddr::CNetAddr(const struct in6_addr &ipv6Addr, const uint32_t scope) { | CNetAddr::CNetAddr(const struct in6_addr &ipv6Addr, const uint32_t scope) { | ||||
SetRaw(NET_IPV6, (const uint8_t *)&ipv6Addr); | SetLegacyIPv6(Span<const uint8_t>( | ||||
reinterpret_cast<const uint8_t *>(&ipv6Addr), sizeof(ipv6Addr))); | |||||
scopeId = scope; | scopeId = scope; | ||||
} | } | ||||
unsigned int CNetAddr::GetByte(int n) const { | |||||
return ip[15 - n]; | |||||
} | |||||
bool CNetAddr::IsBindAny() const { | bool CNetAddr::IsBindAny() const { | ||||
const int cmplen = IsIPv4() ? 4 : 16; | if (!IsIPv4() && !IsIPv6()) { | ||||
for (int i = 0; i < cmplen; ++i) { | |||||
if (GetByte(i)) { | |||||
return false; | return false; | ||||
} | } | ||||
} | return std::all_of(m_addr.begin(), m_addr.end(), | ||||
[](uint8_t b) { return b == 0; }); | |||||
return true; | |||||
} | } | ||||
bool CNetAddr::IsIPv4() const { | bool CNetAddr::IsIPv4() const { | ||||
return m_net == NET_IPV4; | return m_net == NET_IPV4; | ||||
} | } | ||||
bool CNetAddr::IsIPv6() const { | bool CNetAddr::IsIPv6() const { | ||||
return m_net == NET_IPV6; | 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) || | (m_addr[0] == 10 || (m_addr[0] == 192 && m_addr[1] == 168) || | ||||
(GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31))); | (m_addr[0] == 172 && m_addr[1] >= 16 && m_addr[1] <= 31)); | ||||
} | } | ||||
bool CNetAddr::IsRFC2544() const { | bool CNetAddr::IsRFC2544() const { | ||||
return IsIPv4() && GetByte(3) == 198 && | return IsIPv4() && m_addr[0] == 198 && (m_addr[1] == 18 || m_addr[1] == 19); | ||||
(GetByte(2) == 18 || GetByte(2) == 19); | |||||
} | } | ||||
bool CNetAddr::IsRFC3927() const { | bool CNetAddr::IsRFC3927() const { | ||||
return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254); | return IsIPv4() && HasPrefix(m_addr, std::array<uint8_t, 2>{{169, 254}}); | ||||
} | } | ||||
bool CNetAddr::IsRFC6598() const { | bool CNetAddr::IsRFC6598() const { | ||||
return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 && | return IsIPv4() && m_addr[0] == 100 && m_addr[1] >= 64 && m_addr[1] <= 127; | ||||
GetByte(2) <= 127; | |||||
} | } | ||||
bool CNetAddr::IsRFC5737() const { | bool CNetAddr::IsRFC5737() const { | ||||
return IsIPv4() && | return IsIPv4() && | ||||
((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) || | (HasPrefix(m_addr, std::array<uint8_t, 3>{{192, 0, 2}}) || | ||||
(GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) || | HasPrefix(m_addr, std::array<uint8_t, 3>{{198, 51, 100}}) || | ||||
(GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113)); | HasPrefix(m_addr, std::array<uint8_t, 3>{{203, 0, 113}})); | ||||
} | } | ||||
bool CNetAddr::IsRFC3849() const { | bool CNetAddr::IsRFC3849() const { | ||||
return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 && | return IsIPv6() && | ||||
GetByte(13) == 0x0D && GetByte(12) == 0xB8; | HasPrefix(m_addr, std::array<uint8_t, 4>{{0x20, 0x01, 0x0D, 0xB8}}); | ||||
} | } | ||||
bool CNetAddr::IsRFC3964() const { | bool CNetAddr::IsRFC3964() const { | ||||
return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x02; | return IsIPv6() && HasPrefix(m_addr, std::array<uint8_t, 2>{{0x20, 0x02}}); | ||||
} | } | ||||
bool CNetAddr::IsRFC6052() const { | bool CNetAddr::IsRFC6052() const { | ||||
static const uint8_t pchRFC6052[] = {0, 0x64, 0xFF, 0x9B, 0, 0, | return IsIPv6() && | ||||
0, 0, 0, 0, 0, 0}; | HasPrefix(m_addr, std::array<uint8_t, 12>{{0x00, 0x64, 0xFF, 0x9B, | ||||
return IsIPv6() && memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0; | 0x00, 0x00, 0x00, 0x00, | ||||
0x00, 0x00, 0x00, 0x00}}); | |||||
} | } | ||||
bool CNetAddr::IsRFC4380() const { | bool CNetAddr::IsRFC4380() const { | ||||
return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 && | return IsIPv6() && | ||||
GetByte(13) == 0 && GetByte(12) == 0; | HasPrefix(m_addr, std::array<uint8_t, 4>{{0x20, 0x01, 0x00, 0x00}}); | ||||
} | } | ||||
bool CNetAddr::IsRFC4862() const { | bool CNetAddr::IsRFC4862() const { | ||||
static const uint8_t pchRFC4862[] = {0xFE, 0x80, 0, 0, 0, 0, 0, 0}; | return IsIPv6() && | ||||
return IsIPv6() && memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0; | HasPrefix(m_addr, std::array<uint8_t, 8>{{0xFE, 0x80, 0x00, 0x00, | ||||
0x00, 0x00, 0x00, 0x00}}); | |||||
} | } | ||||
bool CNetAddr::IsRFC4193() const { | bool CNetAddr::IsRFC4193() const { | ||||
return IsIPv6() && (GetByte(15) & 0xFE) == 0xFC; | return IsIPv6() && (m_addr[0] & 0xFE) == 0xFC; | ||||
} | } | ||||
bool CNetAddr::IsRFC6145() const { | bool CNetAddr::IsRFC6145() const { | ||||
static const uint8_t pchRFC6145[] = {0, 0, 0, 0, 0, 0, | return IsIPv6() && | ||||
0, 0, 0xFF, 0xFF, 0, 0}; | HasPrefix(m_addr, std::array<uint8_t, 12>{{0x00, 0x00, 0x00, 0x00, | ||||
return IsIPv6() && memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0; | 0x00, 0x00, 0x00, 0x00, | ||||
0xFF, 0xFF, 0x00, 0x00}}); | |||||
} | } | ||||
bool CNetAddr::IsRFC4843() const { | bool CNetAddr::IsRFC4843() const { | ||||
return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 && | return IsIPv6() && | ||||
GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10; | HasPrefix(m_addr, std::array<uint8_t, 3>{{0x20, 0x01, 0x00}}) && | ||||
(m_addr[3] & 0xF0) == 0x10; | |||||
} | } | ||||
bool CNetAddr::IsRFC7343() const { | bool CNetAddr::IsRFC7343() const { | ||||
return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 && | return IsIPv6() && | ||||
GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x20; | HasPrefix(m_addr, std::array<uint8_t, 3>{{0x20, 0x01, 0x00}}) && | ||||
(m_addr[3] & 0xF0) == 0x20; | |||||
} | } | ||||
bool CNetAddr::IsHeNet() const { | bool CNetAddr::IsHeNet() const { | ||||
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && | return IsIPv6() && | ||||
GetByte(12) == 0x70); | HasPrefix(m_addr, std::array<uint8_t, 4>{{0x20, 0x01, 0x04, 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 m_net == NET_ONION; | 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() && (m_addr[0] == 127 || m_addr[0] == 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 (IsIPv6() && memcmp(ip, pchLocal, 16) == 0) { | if (IsIPv6() && memcmp(m_addr.data(), pchLocal, sizeof(pchLocal)) == 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 (IsIPv6() && memcmp(ip, pchIPv4 + 3, sizeof(pchIPv4) - 3) == 0) { | if (IsIPv6() && memcmp(m_addr.data(), IPV4_IN_IPV6_PREFIX.data() + 3, | ||||
sizeof(IPV4_IN_IPV6_PREFIX) - 3) == 0) { | |||||
return false; | return false; | ||||
} | } | ||||
// unspecified IPv6 address (::/128) | // unspecified IPv6 address (::/128) | ||||
uint8_t ipNone6[16] = {}; | uint8_t ipNone6[16] = {}; | ||||
if (IsIPv6() && memcmp(ip, ipNone6, 16) == 0) { | if (IsIPv6() && memcmp(m_addr.data(), ipNone6, sizeof(ipNone6)) == 0) { | ||||
return false; | return false; | ||||
} | } | ||||
// documentation IPv6 address | // documentation IPv6 address | ||||
if (IsRFC3849()) { | if (IsRFC3849()) { | ||||
return false; | return false; | ||||
} | } | ||||
if (IsInternal()) { | if (IsInternal()) { | ||||
return false; | return false; | ||||
} | } | ||||
if (IsIPv4()) { | if (IsIPv4()) { | ||||
// INADDR_NONE | const uint32_t addr = ReadBE32(m_addr.data()); | ||||
uint32_t ipNone = INADDR_NONE; | if (addr == INADDR_ANY || addr == INADDR_NONE) { | ||||
if (memcmp(ip + 12, &ipNone, 4) == 0) { | |||||
return false; | |||||
} | |||||
// 0 | |||||
ipNone = 0; | |||||
if (memcmp(ip + 12, &ipNone, 4) == 0) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* @returns Whether or not this network address is publicly routable on the | * @returns Whether or not this network address is publicly routable on the | ||||
* global internet. | * global internet. | ||||
* | * | ||||
* @note A routable address is always valid. As in, the set of routable | * @note A routable address is always valid. As in, the set of routable | ||||
* addresses is a subset of the set of valid addresses. | * addresses is a subset of the set of valid addresses. | ||||
* | * | ||||
* @see CNetAddr::IsValid() | * @see CNetAddr::IsValid() | ||||
*/ | */ | ||||
bool CNetAddr::IsRoutable() const { | bool CNetAddr::IsRoutable() const { | ||||
return IsValid() && | return IsValid() && | ||||
!(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || | !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || | ||||
IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || | IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || | ||||
IsRFC4843() || IsRFC7343() || IsLocal() || IsInternal()); | IsRFC4843() || IsRFC7343() || IsLocal() || IsInternal()); | ||||
} | } | ||||
/** | /** | ||||
* @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 represents a name. | ||||
* | * | ||||
* @see CNetAddr::SetInternal(const std::string &) | * @see CNetAddr::SetInternal(const std::string &) | ||||
*/ | */ | ||||
bool CNetAddr::IsInternal() const { | bool CNetAddr::IsInternal() const { | ||||
return m_net == NET_INTERNAL; | 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; | ||||
} | } | ||||
return m_net; | return m_net; | ||||
} | } | ||||
std::string CNetAddr::ToStringIP() const { | std::string CNetAddr::ToStringIP() const { | ||||
if (IsTor()) { | if (IsTor()) { | ||||
return EncodeBase32(&ip[6], 10) + ".onion"; | return EncodeBase32(m_addr.data(), m_addr.size()) + ".onion"; | ||||
} | } | ||||
if (IsInternal()) { | if (IsInternal()) { | ||||
return EncodeBase32(ip + sizeof(g_internal_prefix), | return EncodeBase32(m_addr.data(), m_addr.size()) + ".internal"; | ||||
sizeof(ip) - sizeof(g_internal_prefix)) + | |||||
".internal"; | |||||
} | } | ||||
CService serv(*this, 0); | CService serv(*this, 0); | ||||
struct sockaddr_storage sockaddr; | struct sockaddr_storage sockaddr; | ||||
socklen_t socklen = sizeof(sockaddr); | socklen_t socklen = sizeof(sockaddr); | ||||
if (serv.GetSockAddr((struct sockaddr *)&sockaddr, &socklen)) { | if (serv.GetSockAddr((struct sockaddr *)&sockaddr, &socklen)) { | ||||
char name[1025] = ""; | char name[1025] = ""; | ||||
if (!getnameinfo((const struct sockaddr *)&sockaddr, socklen, name, | if (!getnameinfo((const struct sockaddr *)&sockaddr, socklen, name, | ||||
sizeof(name), nullptr, 0, NI_NUMERICHOST)) { | sizeof(name), nullptr, 0, NI_NUMERICHOST)) { | ||||
return std::string(name); | return std::string(name); | ||||
} | } | ||||
} | } | ||||
if (IsIPv4()) { | if (IsIPv4()) { | ||||
return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), | return strprintf("%u.%u.%u.%u", m_addr[0], m_addr[1], m_addr[2], | ||||
GetByte(0)); | m_addr[3]); | ||||
} | } | ||||
assert(IsIPv6()); | |||||
return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", GetByte(15) << 8 | GetByte(14), | return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", m_addr[0] << 8 | m_addr[1], | ||||
GetByte(13) << 8 | GetByte(12), | m_addr[2] << 8 | m_addr[3], m_addr[4] << 8 | m_addr[5], | ||||
GetByte(11) << 8 | GetByte(10), | m_addr[6] << 8 | m_addr[7], m_addr[8] << 8 | m_addr[9], | ||||
GetByte(9) << 8 | GetByte(8), GetByte(7) << 8 | GetByte(6), | m_addr[10] << 8 | m_addr[11], m_addr[12] << 8 | m_addr[13], | ||||
GetByte(5) << 8 | GetByte(4), GetByte(3) << 8 | GetByte(2), | m_addr[14] << 8 | m_addr[15]); | ||||
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 a.m_net == b.m_net && memcmp(a.ip, b.ip, 16) == 0; | return a.m_net == b.m_net && a.m_addr == b.m_addr; | ||||
} | } | ||||
bool operator<(const CNetAddr &a, const CNetAddr &b) { | bool operator<(const CNetAddr &a, const CNetAddr &b) { | ||||
return a.m_net < b.m_net || | return std::tie(a.m_net, a.m_addr) < std::tie(b.m_net, b.m_addr); | ||||
(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 | ||||
* or not our address was an IPv4 address. | * or not our address was an IPv4 address. | ||||
* | * | ||||
* @see CNetAddr::IsIPv4() | * @see CNetAddr::IsIPv4() | ||||
*/ | */ | ||||
bool CNetAddr::GetInAddr(struct in_addr *pipv4Addr) const { | bool CNetAddr::GetInAddr(struct in_addr *pipv4Addr) const { | ||||
if (!IsIPv4()) { | if (!IsIPv4()) { | ||||
return false; | return false; | ||||
} | } | ||||
memcpy(pipv4Addr, ip + 12, 4); | assert(sizeof(*pipv4Addr) == m_addr.size()); | ||||
memcpy(pipv4Addr, m_addr.data(), m_addr.size()); | |||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* Try to get our IPv6 address. | * Try to get our IPv6 address. | ||||
* | * | ||||
* @param[out] pipv6Addr The in6_addr struct to which to copy. | * @param[out] pipv6Addr The in6_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 | ||||
* or not our address was an IPv6 address. | * or not our address was an IPv6 address. | ||||
* | * | ||||
* @see CNetAddr::IsIPv6() | * @see CNetAddr::IsIPv6() | ||||
*/ | */ | ||||
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); | assert(sizeof(*pipv6Addr) == m_addr.size()); | ||||
memcpy(pipv6Addr, m_addr.data(), m_addr.size()); | |||||
return true; | return true; | ||||
} | } | ||||
bool CNetAddr::HasLinkedIPv4() const { | bool CNetAddr::HasLinkedIPv4() const { | ||||
return IsRoutable() && (IsIPv4() || IsRFC6145() || IsRFC6052() || | return IsRoutable() && (IsIPv4() || IsRFC6145() || IsRFC6052() || | ||||
IsRFC3964() || IsRFC4380()); | IsRFC3964() || IsRFC4380()); | ||||
} | } | ||||
uint32_t CNetAddr::GetLinkedIPv4() const { | uint32_t CNetAddr::GetLinkedIPv4() const { | ||||
if (IsIPv4() || IsRFC6145() || IsRFC6052()) { | if (IsIPv4()) { | ||||
// IPv4, mapped IPv4, SIIT translated IPv4: the IPv4 address is the last | return ReadBE32(m_addr.data()); | ||||
// 4 bytes of the address | } else if (IsRFC6052() || IsRFC6145()) { | ||||
return ReadBE32(ip + 12); | // mapped IPv4, SIIT translated IPv4: the IPv4 address is the last 4 | ||||
// bytes of the address | |||||
return ReadBE32(MakeSpan(m_addr).last(ADDR_IPV4_SIZE).data()); | |||||
} else if (IsRFC3964()) { | } else if (IsRFC3964()) { | ||||
// 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6 | // 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6 | ||||
return ReadBE32(ip + 2); | return ReadBE32(MakeSpan(m_addr).subspan(2, ADDR_IPV4_SIZE).data()); | ||||
} else if (IsRFC4380()) { | } else if (IsRFC4380()) { | ||||
// Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the | // Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the | ||||
// address, but bitflipped | // address, but bitflipped | ||||
return ~ReadBE32(ip + 12); | return ~ReadBE32(MakeSpan(m_addr).last(ADDR_IPV4_SIZE).data()); | ||||
} | } | ||||
assert(false); | assert(false); | ||||
} | } | ||||
uint32_t CNetAddr::GetNetClass() const { | uint32_t CNetAddr::GetNetClass() const { | ||||
uint32_t net_class = NET_IPV6; | uint32_t net_class = NET_IPV6; | ||||
if (IsLocal()) { | if (IsLocal()) { | ||||
net_class = 255; | net_class = 255; | ||||
Show All 13 Lines | |||||
uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const { | uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const { | ||||
uint32_t net_class = GetNetClass(); | uint32_t net_class = GetNetClass(); | ||||
if (asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) { | if (asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) { | ||||
return 0; // Indicates not found, safe because AS0 is reserved per | return 0; // Indicates not found, safe because AS0 is reserved per | ||||
// RFC7607. | // RFC7607. | ||||
} | } | ||||
std::vector<bool> ip_bits(128); | std::vector<bool> ip_bits(128); | ||||
if (HasLinkedIPv4()) { | if (HasLinkedIPv4()) { | ||||
// For lookup, treat as if it was just an IPv4 address (pchIPv4 prefix + | // For lookup, treat as if it was just an IPv4 address | ||||
// IPv4 bits) | // (IPV4_IN_IPV6_PREFIX + IPv4 bits) | ||||
for (int8_t byte_i = 0; byte_i < 12; ++byte_i) { | for (int8_t byte_i = 0; byte_i < 12; ++byte_i) { | ||||
for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) { | for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) { | ||||
ip_bits[byte_i * 8 + bit_i] = | ip_bits[byte_i * 8 + bit_i] = | ||||
(pchIPv4[byte_i] >> (7 - bit_i)) & 1; | (IPV4_IN_IPV6_PREFIX[byte_i] >> (7 - bit_i)) & 1; | ||||
} | } | ||||
} | } | ||||
uint32_t ipv4 = GetLinkedIPv4(); | uint32_t ipv4 = GetLinkedIPv4(); | ||||
for (int i = 0; i < 32; ++i) { | for (int i = 0; i < 32; ++i) { | ||||
ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1; | ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1; | ||||
} | } | ||||
} else { | } else { | ||||
// Use all 128 bits of the IPv6 address otherwise | // Use all 128 bits of the IPv6 address otherwise | ||||
assert(IsIPv6()); | |||||
for (int8_t byte_i = 0; byte_i < 16; ++byte_i) { | for (int8_t byte_i = 0; byte_i < 16; ++byte_i) { | ||||
uint8_t cur_byte = GetByte(15 - byte_i); | uint8_t cur_byte = m_addr[byte_i]; | ||||
for (uint8_t bit_i = 0; bit_i < 8; ++bit_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; | ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
uint32_t mapped_as = Interpret(asmap, ip_bits); | uint32_t mapped_as = Interpret(asmap, ip_bits); | ||||
return mapped_as; | return mapped_as; | ||||
} | } | ||||
Show All 20 Lines | if (asn != 0) { // Either asmap was empty, or address has non-asmappable net | ||||
// the same bucket | // the same bucket | ||||
for (int i = 0; i < 4; i++) { | for (int i = 0; i < 4; i++) { | ||||
vchRet.push_back((asn >> (8 * i)) & 0xFF); | vchRet.push_back((asn >> (8 * i)) & 0xFF); | ||||
} | } | ||||
return vchRet; | return vchRet; | ||||
} | } | ||||
vchRet.push_back(net_class); | vchRet.push_back(net_class); | ||||
int nStartByte = 0; | int nBits{0}; | ||||
int nBits = 16; | |||||
if (IsLocal()) { | if (IsLocal()) { | ||||
// all local addresses belong to the same group | // all local addresses belong to the same group | ||||
nBits = 0; | |||||
} else if (IsInternal()) { | } else if (IsInternal()) { | ||||
// all internal-usage addresses get their own group | // all internal-usage addresses get their own group | ||||
nStartByte = sizeof(g_internal_prefix); | nBits = ADDR_INTERNAL_SIZE * 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 | ||||
nBits = 0; | |||||
} else if (HasLinkedIPv4()) { | } else if (HasLinkedIPv4()) { | ||||
// IPv4 addresses (and mapped IPv4 addresses) use /16 groups | // IPv4 addresses (and mapped IPv4 addresses) use /16 groups | ||||
uint32_t ipv4 = GetLinkedIPv4(); | uint32_t ipv4 = GetLinkedIPv4(); | ||||
vchRet.push_back((ipv4 >> 24) & 0xFF); | vchRet.push_back((ipv4 >> 24) & 0xFF); | ||||
vchRet.push_back((ipv4 >> 16) & 0xFF); | vchRet.push_back((ipv4 >> 16) & 0xFF); | ||||
return vchRet; | return vchRet; | ||||
} else if (IsTor()) { | } else if (IsTor()) { | ||||
nStartByte = 6; | |||||
nBits = 4; | nBits = 4; | ||||
} else if (IsHeNet()) { | } else if (IsHeNet()) { | ||||
// 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; | ||||
} | } | ||||
// push our ip onto vchRet byte by byte... | // Push our address onto vchRet. | ||||
while (nBits >= 8) { | const size_t num_bytes = nBits / 8; | ||||
vchRet.push_back(GetByte(15 - nStartByte)); | vchRet.insert(vchRet.end(), m_addr.begin(), m_addr.begin() + num_bytes); | ||||
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) { | ||||
vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1)); | assert(num_bytes < m_addr.size()); | ||||
vchRet.push_back(m_addr[num_bytes] | ((1 << (8 - nBits)) - 1)); | |||||
} | } | ||||
return vchRet; | return vchRet; | ||||
} | } | ||||
std::vector<uint8_t> CNetAddr::GetAddrBytes() const { | |||||
uint8_t serialized[V1_SERIALIZATION_SIZE]; | |||||
SerializeV1Array(serialized); | |||||
return {std::begin(serialized), std::end(serialized)}; | |||||
} | |||||
uint64_t CNetAddr::GetHash() const { | uint64_t CNetAddr::GetHash() const { | ||||
uint256 hash = Hash(ip); | uint256 hash = Hash(m_addr); | ||||
uint64_t nRet; | uint64_t nRet; | ||||
memcpy(&nRet, &hash, sizeof(nRet)); | memcpy(&nRet, &hash, sizeof(nRet)); | ||||
return nRet; | return nRet; | ||||
} | } | ||||
// private extensions to enum Network, only returned by GetExtNetwork, and only | // private extensions to enum Network, only returned by GetExtNetwork, and only | ||||
// used in GetReachabilityFrom | // used in GetReachabilityFrom | ||||
static const int NET_UNKNOWN = NET_MAX + 0; | static const int NET_UNKNOWN = NET_MAX + 0; | ||||
▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | |||||
std::string CService::ToString() const { | std::string CService::ToString() const { | ||||
return ToStringIPPort(); | return ToStringIPPort(); | ||||
} | } | ||||
CSubNet::CSubNet() : valid(false) { | CSubNet::CSubNet() : valid(false) { | ||||
memset(netmask, 0, sizeof(netmask)); | memset(netmask, 0, sizeof(netmask)); | ||||
} | } | ||||
CSubNet::CSubNet(const CNetAddr &addr, int32_t mask) { | CSubNet::CSubNet(const CNetAddr &addr, uint8_t mask) : CSubNet() { | ||||
valid = true; | valid = (addr.IsIPv4() && mask <= ADDR_IPV4_SIZE * 8) || | ||||
network = addr; | (addr.IsIPv6() && mask <= ADDR_IPV6_SIZE * 8); | ||||
// Default to /32 (IPv4) or /128 (IPv6), i.e. match single address | if (!valid) { | ||||
memset(netmask, 255, sizeof(netmask)); | return; | ||||
// IPv4 addresses start at offset 12, and first 12 bytes must match, so just | |||||
// offset n | |||||
const int astartofs = network.IsIPv4() ? 12 : 0; | |||||
// Only valid if in range of bits of address | |||||
int32_t n = mask; | |||||
if (n >= 0 && n <= (128 - astartofs * 8)) { | |||||
n += astartofs * 8; | |||||
// Clear bits [n..127] | |||||
for (; n < 128; ++n) { | |||||
netmask[n >> 3] &= ~(1 << (7 - (n & 7))); | |||||
} | |||||
} else { | |||||
valid = false; | |||||
} | } | ||||
// Normalize network according to netmask | assert(mask <= sizeof(netmask) * 8); | ||||
for (int x = 0; x < 16; ++x) { | |||||
network.ip[x] &= netmask[x]; | network = addr; | ||||
uint8_t n = mask; | |||||
for (size_t i = 0; i < network.m_addr.size(); ++i) { | |||||
const uint8_t bits = n < 8 ? n : 8; | |||||
// Set first bits. | |||||
netmask[i] = (uint8_t)((uint8_t)0xFF << (8 - bits)); | |||||
// Normalize network according to netmask. | |||||
network.m_addr[i] &= netmask[i]; | |||||
n -= bits; | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* @returns The number of 1-bits in the prefix of the specified subnet mask. If | * @returns The number of 1-bits in the prefix of the specified subnet mask. If | ||||
* the specified subnet mask is not a valid one, -1. | * the specified subnet mask is not a valid one, -1. | ||||
*/ | */ | ||||
static inline int NetmaskBits(uint8_t x) { | static inline int NetmaskBits(uint8_t x) { | ||||
Show All 16 Lines | switch (x) { | ||||
return 7; | return 7; | ||||
case 0xff: | case 0xff: | ||||
return 8; | return 8; | ||||
default: | default: | ||||
return -1; | return -1; | ||||
} | } | ||||
} | } | ||||
CSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask) { | CSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask) : CSubNet() { | ||||
valid = true; | valid = (addr.IsIPv4() || addr.IsIPv6()) && addr.m_net == mask.m_net; | ||||
if (!valid) { | |||||
return; | |||||
} | |||||
// Check if `mask` contains 1-bits after 0-bits (which is an invalid | // Check if `mask` contains 1-bits after 0-bits (which is an invalid | ||||
// netmask). | // netmask). | ||||
bool zeros_found = false; | bool zeros_found = false; | ||||
for (size_t i = mask.IsIPv4() ? 12 : 0; i < sizeof(mask.ip); ++i) { | for (auto b : mask.m_addr) { | ||||
const int num_bits = NetmaskBits(mask.ip[i]); | const int num_bits = NetmaskBits(b); | ||||
if (num_bits == -1 || (zeros_found && num_bits != 0)) { | if (num_bits == -1 || (zeros_found && num_bits != 0)) { | ||||
valid = false; | valid = false; | ||||
return; | return; | ||||
} | } | ||||
if (num_bits < 8) { | if (num_bits < 8) { | ||||
zeros_found = true; | zeros_found = true; | ||||
} | } | ||||
} | } | ||||
network = addr; | |||||
// Default to /32 (IPv4) or /128 (IPv6), i.e. match single address | |||||
memset(netmask, 255, sizeof(netmask)); | |||||
// IPv4 addresses start at offset 12, and first 12 bytes must match, so just | assert(mask.m_addr.size() <= sizeof(netmask)); | ||||
// offset n | |||||
const int astartofs = network.IsIPv4() ? 12 : 0; | |||||
for (int x = astartofs; x < 16; ++x) { | memcpy(netmask, mask.m_addr.data(), mask.m_addr.size()); | ||||
netmask[x] = mask.ip[x]; | |||||
} | network = addr; | ||||
// Normalize network according to netmask | // Normalize network according to netmask | ||||
for (int x = 0; x < 16; ++x) { | for (size_t x = 0; x < network.m_addr.size(); ++x) { | ||||
network.ip[x] &= netmask[x]; | network.m_addr[x] &= netmask[x]; | ||||
} | } | ||||
} | } | ||||
CSubNet::CSubNet(const CNetAddr &addr) : valid(addr.IsValid()) { | CSubNet::CSubNet(const CNetAddr &addr) : CSubNet() { | ||||
memset(netmask, 255, sizeof(netmask)); | valid = addr.IsIPv4() || addr.IsIPv6(); | ||||
if (!valid) { | |||||
return; | |||||
} | |||||
assert(addr.m_addr.size() <= sizeof(netmask)); | |||||
memset(netmask, 0xFF, addr.m_addr.size()); | |||||
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() || network.m_net != addr.m_net) { | if (!valid || !addr.IsValid() || network.m_net != addr.m_net) { | ||||
return false; | return false; | ||||
} | } | ||||
for (int x = 0; x < 16; ++x) { | assert(network.m_addr.size() == addr.m_addr.size()); | ||||
if ((addr.ip[x] & netmask[x]) != network.ip[x]) { | for (size_t x = 0; x < addr.m_addr.size(); ++x) { | ||||
if ((addr.m_addr[x] & netmask[x]) != network.m_addr[x]) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
std::string CSubNet::ToString() const { | std::string CSubNet::ToString() const { | ||||
assert(network.m_addr.size() <= sizeof(netmask)); | |||||
uint8_t cidr = 0; | uint8_t cidr = 0; | ||||
for (size_t i = network.IsIPv4() ? 12 : 0; i < sizeof(netmask); ++i) { | for (size_t i = 0; i < network.m_addr.size(); ++i) { | ||||
if (netmask[i] == 0x00) { | if (netmask[i] == 0x00) { | ||||
break; | break; | ||||
} | } | ||||
cidr += NetmaskBits(netmask[i]); | cidr += NetmaskBits(netmask[i]); | ||||
} | } | ||||
return network.ToString() + strprintf("/%u", cidr); | return network.ToString() + strprintf("/%u", cidr); | ||||
} | } | ||||
Show All 19 Lines |