Changeset View
Changeset View
Standalone View
Standalone View
src/netaddress.cpp
Show First 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | |||||
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) return false; | if (memcmp(ip, pchIPv4 + 3, sizeof(pchIPv4) - 3) == 0) { | ||||
return false; | |||||
} | |||||
// unspecified IPv6 address (::/128) | // unspecified IPv6 address (::/128) | ||||
uint8_t ipNone6[16] = {}; | uint8_t ipNone6[16] = {}; | ||||
if (memcmp(ip, ipNone6, 16) == 0) return false; | if (memcmp(ip, ipNone6, 16) == 0) { | ||||
return false; | |||||
} | |||||
// documentation IPv6 address | // documentation IPv6 address | ||||
if (IsRFC3849()) return false; | if (IsRFC3849()) { | ||||
return false; | |||||
} | |||||
if (IsInternal()) { | if (IsInternal()) { | ||||
return false; | return false; | ||||
} | } | ||||
if (IsIPv4()) { | if (IsIPv4()) { | ||||
// INADDR_NONE | // INADDR_NONE | ||||
uint32_t ipNone = INADDR_NONE; | uint32_t ipNone = INADDR_NONE; | ||||
if (memcmp(ip + 12, &ipNone, 4) == 0) return false; | if (memcmp(ip + 12, &ipNone, 4) == 0) { | ||||
return false; | |||||
} | |||||
// 0 | // 0 | ||||
ipNone = 0; | ipNone = 0; | ||||
if (memcmp(ip + 12, &ipNone, 4) == 0) return false; | if (memcmp(ip + 12, &ipNone, 4) == 0) { | ||||
return false; | |||||
} | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CNetAddr::IsRoutable() const { | bool CNetAddr::IsRoutable() const { | ||||
return IsValid() && | return IsValid() && | ||||
!(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || | !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | bool operator==(const CNetAddr &a, const CNetAddr &b) { | ||||
return (memcmp(a.ip, b.ip, 16) == 0); | return (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 (memcmp(a.ip, b.ip, 16) < 0); | ||||
} | } | ||||
bool CNetAddr::GetInAddr(struct in_addr *pipv4Addr) const { | bool CNetAddr::GetInAddr(struct in_addr *pipv4Addr) const { | ||||
if (!IsIPv4()) return false; | if (!IsIPv4()) { | ||||
return false; | |||||
} | |||||
memcpy(pipv4Addr, ip + 12, 4); | memcpy(pipv4Addr, ip + 12, 4); | ||||
return true; | return true; | ||||
} | } | ||||
bool CNetAddr::GetIn6Addr(struct in6_addr *pipv6Addr) const { | bool CNetAddr::GetIn6Addr(struct in6_addr *pipv6Addr) const { | ||||
memcpy(pipv6Addr, ip, 16); | memcpy(pipv6Addr, ip, 16); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | uint64_t CNetAddr::GetHash() const { | ||||
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; | ||||
static const int NET_TEREDO = NET_MAX + 1; | static const int NET_TEREDO = NET_MAX + 1; | ||||
static int GetExtNetwork(const CNetAddr *addr) { | static int GetExtNetwork(const CNetAddr *addr) { | ||||
if (addr == nullptr) return NET_UNKNOWN; | if (addr == nullptr) { | ||||
if (addr->IsRFC4380()) return NET_TEREDO; | return NET_UNKNOWN; | ||||
} | |||||
if (addr->IsRFC4380()) { | |||||
return NET_TEREDO; | |||||
} | |||||
return addr->GetNetwork(); | return addr->GetNetwork(); | ||||
} | } | ||||
/** Calculates a metric for how reachable (*this) is from a given partner */ | /** Calculates a metric for how reachable (*this) is from a given partner */ | ||||
int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const { | int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const { | ||||
enum Reachability { | enum Reachability { | ||||
REACH_UNREACHABLE, | REACH_UNREACHABLE, | ||||
REACH_DEFAULT, | REACH_DEFAULT, | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||
bool operator<(const CService &a, const CService &b) { | bool operator<(const CService &a, const CService &b) { | ||||
return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) || | return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) || | ||||
(static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && | (static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && | ||||
a.port < b.port); | a.port < b.port); | ||||
} | } | ||||
bool CService::GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const { | bool CService::GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const { | ||||
if (IsIPv4()) { | if (IsIPv4()) { | ||||
if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) return false; | if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) { | ||||
return false; | |||||
} | |||||
*addrlen = sizeof(struct sockaddr_in); | *addrlen = sizeof(struct sockaddr_in); | ||||
struct sockaddr_in *paddrin = | struct sockaddr_in *paddrin = | ||||
reinterpret_cast<struct sockaddr_in *>(paddr); | reinterpret_cast<struct sockaddr_in *>(paddr); | ||||
memset(paddrin, 0, *addrlen); | memset(paddrin, 0, *addrlen); | ||||
if (!GetInAddr(&paddrin->sin_addr)) return false; | if (!GetInAddr(&paddrin->sin_addr)) { | ||||
return false; | |||||
} | |||||
paddrin->sin_family = AF_INET; | paddrin->sin_family = AF_INET; | ||||
paddrin->sin_port = htons(port); | paddrin->sin_port = htons(port); | ||||
return true; | return true; | ||||
} | } | ||||
if (IsIPv6()) { | if (IsIPv6()) { | ||||
if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) return false; | if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) { | ||||
return false; | |||||
} | |||||
*addrlen = sizeof(struct sockaddr_in6); | *addrlen = sizeof(struct sockaddr_in6); | ||||
struct sockaddr_in6 *paddrin6 = | struct sockaddr_in6 *paddrin6 = | ||||
reinterpret_cast<struct sockaddr_in6 *>(paddr); | reinterpret_cast<struct sockaddr_in6 *>(paddr); | ||||
memset(paddrin6, 0, *addrlen); | memset(paddrin6, 0, *addrlen); | ||||
if (!GetIn6Addr(&paddrin6->sin6_addr)) return false; | if (!GetIn6Addr(&paddrin6->sin6_addr)) { | ||||
return false; | |||||
} | |||||
paddrin6->sin6_scope_id = scopeId; | paddrin6->sin6_scope_id = scopeId; | ||||
paddrin6->sin6_family = AF_INET6; | paddrin6->sin6_family = AF_INET6; | ||||
paddrin6->sin6_port = htons(port); | paddrin6->sin6_port = htons(port); | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
Show All 36 Lines | CSubNet::CSubNet(const CNetAddr &addr, int32_t mask) { | ||||
// offset n | // offset n | ||||
const int astartofs = network.IsIPv4() ? 12 : 0; | const int astartofs = network.IsIPv4() ? 12 : 0; | ||||
// Only valid if in range of bits of address | // Only valid if in range of bits of address | ||||
int32_t n = mask; | int32_t n = mask; | ||||
if (n >= 0 && n <= (128 - astartofs * 8)) { | if (n >= 0 && n <= (128 - astartofs * 8)) { | ||||
n += astartofs * 8; | n += astartofs * 8; | ||||
// Clear bits [n..127] | // Clear bits [n..127] | ||||
for (; n < 128; ++n) | for (; n < 128; ++n) { | ||||
netmask[n >> 3] &= ~(1 << (7 - (n & 7))); | netmask[n >> 3] &= ~(1 << (7 - (n & 7))); | ||||
} | |||||
} else { | } else { | ||||
valid = false; | valid = false; | ||||
} | } | ||||
// Normalize network according to netmask | // Normalize network according to netmask | ||||
for (int x = 0; x < 16; ++x) { | for (int x = 0; x < 16; ++x) { | ||||
network.ip[x] &= netmask[x]; | network.ip[x] &= netmask[x]; | ||||
} | } | ||||
} | } | ||||
CSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask) { | CSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask) { | ||||
valid = true; | valid = true; | ||||
network = addr; | network = addr; | ||||
// Default to /32 (IPv4) or /128 (IPv6), i.e. match single address | // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address | ||||
memset(netmask, 255, sizeof(netmask)); | memset(netmask, 255, sizeof(netmask)); | ||||
// IPv4 addresses start at offset 12, and first 12 bytes must match, so just | // IPv4 addresses start at offset 12, and first 12 bytes must match, so just | ||||
// offset n | // offset n | ||||
const int astartofs = network.IsIPv4() ? 12 : 0; | const int astartofs = network.IsIPv4() ? 12 : 0; | ||||
for (int x = astartofs; x < 16; ++x) | for (int x = astartofs; x < 16; ++x) { | ||||
netmask[x] = mask.ip[x]; | netmask[x] = mask.ip[x]; | ||||
} | |||||
// Normalize network according to netmask | // Normalize network according to netmask | ||||
for (int x = 0; x < 16; ++x) | for (int x = 0; x < 16; ++x) { | ||||
network.ip[x] &= netmask[x]; | network.ip[x] &= netmask[x]; | ||||
} | } | ||||
} | |||||
CSubNet::CSubNet(const CNetAddr &addr) : valid(addr.IsValid()) { | CSubNet::CSubNet(const CNetAddr &addr) : valid(addr.IsValid()) { | ||||
memset(netmask, 255, sizeof(netmask)); | memset(netmask, 255, sizeof(netmask)); | ||||
network = addr; | network = addr; | ||||
} | } | ||||
bool CSubNet::Match(const CNetAddr &addr) const { | bool CSubNet::Match(const CNetAddr &addr) const { | ||||
if (!valid || !addr.IsValid()) return false; | if (!valid || !addr.IsValid()) { | ||||
for (int x = 0; x < 16; ++x) | return false; | ||||
if ((addr.ip[x] & netmask[x]) != network.ip[x]) return false; | } | ||||
for (int x = 0; x < 16; ++x) { | |||||
if ((addr.ip[x] & netmask[x]) != network.ip[x]) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | return true; | ||||
} | } | ||||
static inline int NetmaskBits(uint8_t x) { | static inline int NetmaskBits(uint8_t x) { | ||||
switch (x) { | switch (x) { | ||||
case 0x00: | case 0x00: | ||||
return 0; | return 0; | ||||
case 0x80: | case 0x80: | ||||
Show All 17 Lines | static inline int NetmaskBits(uint8_t x) { | ||||
} | } | ||||
} | } | ||||
std::string CSubNet::ToString() const { | std::string CSubNet::ToString() const { | ||||
/* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */ | /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */ | ||||
int cidr = 0; | int cidr = 0; | ||||
bool valid_cidr = true; | bool valid_cidr = true; | ||||
int n = network.IsIPv4() ? 12 : 0; | int n = network.IsIPv4() ? 12 : 0; | ||||
for (; n < 16 && netmask[n] == 0xff; ++n) | for (; n < 16 && netmask[n] == 0xff; ++n) { | ||||
cidr += 8; | cidr += 8; | ||||
} | |||||
if (n < 16) { | if (n < 16) { | ||||
int bits = NetmaskBits(netmask[n]); | int bits = NetmaskBits(netmask[n]); | ||||
if (bits < 0) | if (bits < 0) { | ||||
valid_cidr = false; | valid_cidr = false; | ||||
else | } else { | ||||
cidr += bits; | cidr += bits; | ||||
} | |||||
++n; | ++n; | ||||
} | } | ||||
for (; n < 16 && valid_cidr; ++n) | for (; n < 16 && valid_cidr; ++n) { | ||||
if (netmask[n] != 0x00) valid_cidr = false; | if (netmask[n] != 0x00) { | ||||
valid_cidr = false; | |||||
} | |||||
} | |||||
/* Format output */ | /* Format output */ | ||||
std::string strNetmask; | std::string strNetmask; | ||||
if (valid_cidr) { | if (valid_cidr) { | ||||
strNetmask = strprintf("%u", cidr); | strNetmask = strprintf("%u", cidr); | ||||
} else { | } else { | ||||
if (network.IsIPv4()) | if (network.IsIPv4()) { | ||||
strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], | strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], | ||||
netmask[14], netmask[15]); | netmask[14], netmask[15]); | ||||
else | } else { | ||||
strNetmask = strprintf( | strNetmask = strprintf( | ||||
"%x:%x:%x:%x:%x:%x:%x:%x", netmask[0] << 8 | netmask[1], | "%x:%x:%x:%x:%x:%x:%x:%x", netmask[0] << 8 | netmask[1], | ||||
netmask[2] << 8 | netmask[3], netmask[4] << 8 | netmask[5], | netmask[2] << 8 | netmask[3], netmask[4] << 8 | netmask[5], | ||||
netmask[6] << 8 | netmask[7], netmask[8] << 8 | netmask[9], | netmask[6] << 8 | netmask[7], netmask[8] << 8 | netmask[9], | ||||
netmask[10] << 8 | netmask[11], netmask[12] << 8 | netmask[13], | netmask[10] << 8 | netmask[11], netmask[12] << 8 | netmask[13], | ||||
netmask[14] << 8 | netmask[15]); | netmask[14] << 8 | netmask[15]); | ||||
} | } | ||||
} | |||||
return network.ToString() + "/" + strNetmask; | return network.ToString() + "/" + strNetmask; | ||||
} | } | ||||
bool CSubNet::IsValid() const { | bool CSubNet::IsValid() const { | ||||
return valid; | return valid; | ||||
} | } | ||||
Show All 9 Lines |