Page MenuHomePhabricator

No OneTemporary

diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 116e6c42d..16084d43e 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -1,736 +1,735 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifdef HAVE_CONFIG_H
#include <config/bitcoin-config.h>
#endif
#include <hash.h>
#include <netaddress.h>
#include <tinyformat.h>
#include <util/strencodings.h>
static const uint8_t pchIPv4[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
static const uint8_t pchOnionCat[] = {0xFD, 0x87, 0xD8, 0x7E, 0xEB, 0x43};
// 0xFD + sha256("bitcoin")[0:5]
static const uint8_t g_internal_prefix[] = {0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24};
CNetAddr::CNetAddr() {
memset(ip, 0, sizeof(ip));
- scopeId = 0;
}
void CNetAddr::SetIP(const CNetAddr &ipIn) {
memcpy(ip, ipIn.ip, sizeof(ip));
}
void CNetAddr::SetRaw(Network network, const uint8_t *ip_in) {
switch (network) {
case NET_IPV4:
memcpy(ip, pchIPv4, 12);
memcpy(ip + 12, ip_in, 4);
break;
case NET_IPV6:
memcpy(ip, ip_in, 16);
break;
default:
assert(!"invalid network");
}
}
bool CNetAddr::SetInternal(const std::string &name) {
if (name.empty()) {
return false;
}
uint8_t hash[32] = {};
CSHA256().Write((const uint8_t *)name.data(), name.size()).Finalize(hash);
memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix));
memcpy(ip + sizeof(g_internal_prefix), hash,
sizeof(ip) - sizeof(g_internal_prefix));
return true;
}
bool CNetAddr::SetSpecial(const std::string &strName) {
if (strName.size() > 6 &&
strName.substr(strName.size() - 6, 6) == ".onion") {
std::vector<uint8_t> vchAddr =
DecodeBase32(strName.substr(0, strName.size() - 6).c_str());
if (vchAddr.size() != 16 - sizeof(pchOnionCat)) {
return false;
}
memcpy(ip, pchOnionCat, sizeof(pchOnionCat));
for (unsigned int i = 0; i < 16 - sizeof(pchOnionCat); i++) {
ip[i + sizeof(pchOnionCat)] = vchAddr[i];
}
return true;
}
return false;
}
CNetAddr::CNetAddr(const struct in_addr &ipv4Addr) {
SetRaw(NET_IPV4, (const uint8_t *)&ipv4Addr);
}
CNetAddr::CNetAddr(const struct in6_addr &ipv6Addr, const uint32_t scope) {
SetRaw(NET_IPV6, (const uint8_t *)&ipv6Addr);
scopeId = scope;
}
unsigned int CNetAddr::GetByte(int n) const {
return ip[15 - n];
}
bool CNetAddr::IsIPv4() const {
return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0);
}
bool CNetAddr::IsIPv6() const {
return !IsIPv4() && !IsTor() && !IsInternal();
}
bool CNetAddr::IsRFC1918() const {
return IsIPv4() &&
(GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) ||
(GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));
}
bool CNetAddr::IsRFC2544() const {
return IsIPv4() && GetByte(3) == 198 &&
(GetByte(2) == 18 || GetByte(2) == 19);
}
bool CNetAddr::IsRFC3927() const {
return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
}
bool CNetAddr::IsRFC6598() const {
return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 &&
GetByte(2) <= 127;
}
bool CNetAddr::IsRFC5737() const {
return IsIPv4() &&
((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) ||
(GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) ||
(GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113));
}
bool CNetAddr::IsRFC3849() const {
return GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x0D &&
GetByte(12) == 0xB8;
}
bool CNetAddr::IsRFC3964() const {
return (GetByte(15) == 0x20 && GetByte(14) == 0x02);
}
bool CNetAddr::IsRFC6052() const {
static const uint8_t pchRFC6052[] = {0, 0x64, 0xFF, 0x9B, 0, 0,
0, 0, 0, 0, 0, 0};
return (memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0);
}
bool CNetAddr::IsRFC4380() const {
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0 &&
GetByte(12) == 0);
}
bool CNetAddr::IsRFC4862() const {
static const uint8_t pchRFC4862[] = {0xFE, 0x80, 0, 0, 0, 0, 0, 0};
return (memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0);
}
bool CNetAddr::IsRFC4193() const {
return ((GetByte(15) & 0xFE) == 0xFC);
}
bool CNetAddr::IsRFC6145() const {
static const uint8_t pchRFC6145[] = {0, 0, 0, 0, 0, 0,
0, 0, 0xFF, 0xFF, 0, 0};
return (memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0);
}
bool CNetAddr::IsRFC4843() const {
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 &&
(GetByte(12) & 0xF0) == 0x10);
}
bool CNetAddr::IsTor() const {
return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
}
bool CNetAddr::IsLocal() const {
// IPv4 loopback
if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) return true;
// IPv6 loopback (::1/128)
static const uint8_t pchLocal[16] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1};
if (memcmp(ip, pchLocal, 16) == 0) return true;
return false;
}
bool CNetAddr::IsValid() const {
// Cleanup 3-byte shifted addresses caused by garbage in size field of addr
// messages from versions before 0.2.9 checksum.
// Two consecutive addr messages look like this:
// header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26
// addr26 addr26... so if the first length field is garbled, it reads the
// second batch of addr misaligned by 3 bytes.
if (memcmp(ip, pchIPv4 + 3, sizeof(pchIPv4) - 3) == 0) {
return false;
}
// unspecified IPv6 address (::/128)
uint8_t ipNone6[16] = {};
if (memcmp(ip, ipNone6, 16) == 0) {
return false;
}
// documentation IPv6 address
if (IsRFC3849()) {
return false;
}
if (IsInternal()) {
return false;
}
if (IsIPv4()) {
// INADDR_NONE
uint32_t ipNone = INADDR_NONE;
if (memcmp(ip + 12, &ipNone, 4) == 0) {
return false;
}
// 0
ipNone = 0;
if (memcmp(ip + 12, &ipNone, 4) == 0) {
return false;
}
}
return true;
}
bool CNetAddr::IsRoutable() const {
return IsValid() &&
!(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() ||
IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) ||
IsRFC4843() || IsLocal() || IsInternal());
}
bool CNetAddr::IsInternal() const {
return memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0;
}
enum Network CNetAddr::GetNetwork() const {
if (IsInternal()) {
return NET_INTERNAL;
}
if (!IsRoutable()) {
return NET_UNROUTABLE;
}
if (IsIPv4()) {
return NET_IPV4;
}
if (IsTor()) {
return NET_ONION;
}
return NET_IPV6;
}
std::string CNetAddr::ToStringIP() const {
if (IsTor()) {
return EncodeBase32(&ip[6], 10) + ".onion";
}
if (IsInternal()) {
return EncodeBase32(ip + sizeof(g_internal_prefix),
sizeof(ip) - sizeof(g_internal_prefix)) +
".internal";
}
CService serv(*this, 0);
struct sockaddr_storage sockaddr;
socklen_t socklen = sizeof(sockaddr);
if (serv.GetSockAddr((struct sockaddr *)&sockaddr, &socklen)) {
char name[1025] = "";
if (!getnameinfo((const struct sockaddr *)&sockaddr, socklen, name,
sizeof(name), nullptr, 0, NI_NUMERICHOST)) {
return std::string(name);
}
}
if (IsIPv4()) {
return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1),
GetByte(0));
}
return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", GetByte(15) << 8 | GetByte(14),
GetByte(13) << 8 | GetByte(12),
GetByte(11) << 8 | GetByte(10),
GetByte(9) << 8 | GetByte(8), GetByte(7) << 8 | GetByte(6),
GetByte(5) << 8 | GetByte(4), GetByte(3) << 8 | GetByte(2),
GetByte(1) << 8 | GetByte(0));
}
std::string CNetAddr::ToString() const {
return ToStringIP();
}
bool operator==(const CNetAddr &a, const CNetAddr &b) {
return (memcmp(a.ip, b.ip, 16) == 0);
}
bool operator<(const CNetAddr &a, const CNetAddr &b) {
return (memcmp(a.ip, b.ip, 16) < 0);
}
bool CNetAddr::GetInAddr(struct in_addr *pipv4Addr) const {
if (!IsIPv4()) {
return false;
}
memcpy(pipv4Addr, ip + 12, 4);
return true;
}
bool CNetAddr::GetIn6Addr(struct in6_addr *pipv6Addr) const {
memcpy(pipv6Addr, ip, 16);
return true;
}
// get canonical identifier of an address' group no two connections will be
// attempted to addresses with the same group
std::vector<uint8_t> CNetAddr::GetGroup() const {
std::vector<uint8_t> vchRet;
int nClass = NET_IPV6;
int nStartByte = 0;
int nBits = 16;
// all local addresses belong to the same group
if (IsLocal()) {
nClass = 255;
nBits = 0;
}
if (IsInternal()) {
// all internal-usage addresses get their own group
nClass = NET_INTERNAL;
nStartByte = sizeof(g_internal_prefix);
nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
} else if (!IsRoutable()) {
// all other unroutable addresses belong to the same group
nClass = NET_UNROUTABLE;
nBits = 0;
} else if (IsIPv4() || IsRFC6145() || IsRFC6052()) {
// for IPv4 addresses, '1' + the 16 higher-order bits of the IP includes
// mapped IPv4, SIIT translated IPv4, and the well-known prefix
nClass = NET_IPV4;
nStartByte = 12;
} else if (IsRFC3964()) {
// for 6to4 tunnelled addresses, use the encapsulated IPv4 address
nClass = NET_IPV4;
nStartByte = 2;
} else if (IsRFC4380()) {
// for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4
// address
vchRet.push_back(NET_IPV4);
vchRet.push_back(GetByte(3) ^ 0xFF);
vchRet.push_back(GetByte(2) ^ 0xFF);
return vchRet;
} else if (IsTor()) {
nClass = NET_ONION;
nStartByte = 6;
nBits = 4;
} else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 &&
GetByte(13) == 0x04 && GetByte(12) == 0x70) {
// for he.net, use /36 groups
nBits = 36;
} else {
// for the rest of the IPv6 network, use /32 groups
nBits = 32;
}
vchRet.push_back(nClass);
while (nBits >= 8) {
vchRet.push_back(GetByte(15 - nStartByte));
nStartByte++;
nBits -= 8;
}
if (nBits > 0) {
vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1));
}
return vchRet;
}
uint64_t CNetAddr::GetHash() const {
uint256 hash = Hash(&ip[0], &ip[16]);
uint64_t nRet;
memcpy(&nRet, &hash, sizeof(nRet));
return nRet;
}
// private extensions to enum Network, only returned by GetExtNetwork, and only
// used in GetReachabilityFrom
static const int NET_UNKNOWN = NET_MAX + 0;
static const int NET_TEREDO = NET_MAX + 1;
static int GetExtNetwork(const CNetAddr *addr) {
if (addr == nullptr) {
return NET_UNKNOWN;
}
if (addr->IsRFC4380()) {
return NET_TEREDO;
}
return addr->GetNetwork();
}
/** Calculates a metric for how reachable (*this) is from a given partner */
int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const {
enum Reachability {
REACH_UNREACHABLE,
REACH_DEFAULT,
REACH_TEREDO,
REACH_IPV6_WEAK,
REACH_IPV4,
REACH_IPV6_STRONG,
REACH_PRIVATE
};
if (!IsRoutable() || IsInternal()) {
return REACH_UNREACHABLE;
}
int ourNet = GetExtNetwork(this);
int theirNet = GetExtNetwork(paddrPartner);
bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();
switch (theirNet) {
case NET_IPV4:
switch (ourNet) {
default:
return REACH_DEFAULT;
case NET_IPV4:
return REACH_IPV4;
}
case NET_IPV6:
switch (ourNet) {
default:
return REACH_DEFAULT;
case NET_TEREDO:
return REACH_TEREDO;
case NET_IPV4:
return REACH_IPV4;
// only prefer giving our IPv6 address if it's not tunnelled
case NET_IPV6:
return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG;
}
case NET_ONION:
switch (ourNet) {
default:
return REACH_DEFAULT;
// Tor users can connect to IPv4 as well
case NET_IPV4:
return REACH_IPV4;
case NET_ONION:
return REACH_PRIVATE;
}
case NET_TEREDO:
switch (ourNet) {
default:
return REACH_DEFAULT;
case NET_TEREDO:
return REACH_TEREDO;
case NET_IPV6:
return REACH_IPV6_WEAK;
case NET_IPV4:
return REACH_IPV4;
}
case NET_UNKNOWN:
case NET_UNROUTABLE:
default:
switch (ourNet) {
default:
return REACH_DEFAULT;
case NET_TEREDO:
return REACH_TEREDO;
case NET_IPV6:
return REACH_IPV6_WEAK;
case NET_IPV4:
return REACH_IPV4;
// either from Tor, or don't care about our address
case NET_ONION:
return REACH_PRIVATE;
}
}
}
CService::CService() : port(0) {}
CService::CService(const CNetAddr &cip, unsigned short portIn)
: CNetAddr(cip), port(portIn) {}
CService::CService(const struct in_addr &ipv4Addr, unsigned short portIn)
: CNetAddr(ipv4Addr), port(portIn) {}
CService::CService(const struct in6_addr &ipv6Addr, unsigned short portIn)
: CNetAddr(ipv6Addr), port(portIn) {}
CService::CService(const struct sockaddr_in &addr)
: CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) {
assert(addr.sin_family == AF_INET);
}
CService::CService(const struct sockaddr_in6 &addr)
: CNetAddr(addr.sin6_addr, addr.sin6_scope_id),
port(ntohs(addr.sin6_port)) {
assert(addr.sin6_family == AF_INET6);
}
bool CService::SetSockAddr(const struct sockaddr *paddr) {
switch (paddr->sa_family) {
case AF_INET:
*this =
CService(*reinterpret_cast<const struct sockaddr_in *>(paddr));
return true;
case AF_INET6:
*this =
CService(*reinterpret_cast<const struct sockaddr_in6 *>(paddr));
return true;
default:
return false;
}
}
unsigned short CService::GetPort() const {
return port;
}
bool operator==(const CService &a, const CService &b) {
return static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) &&
a.port == b.port;
}
bool operator<(const CService &a, const CService &b) {
return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) ||
(static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) &&
a.port < b.port);
}
bool CService::GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const {
if (IsIPv4()) {
if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) {
return false;
}
*addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in *paddrin =
reinterpret_cast<struct sockaddr_in *>(paddr);
memset(paddrin, 0, *addrlen);
if (!GetInAddr(&paddrin->sin_addr)) {
return false;
}
paddrin->sin_family = AF_INET;
paddrin->sin_port = htons(port);
return true;
}
if (IsIPv6()) {
if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) {
return false;
}
*addrlen = sizeof(struct sockaddr_in6);
struct sockaddr_in6 *paddrin6 =
reinterpret_cast<struct sockaddr_in6 *>(paddr);
memset(paddrin6, 0, *addrlen);
if (!GetIn6Addr(&paddrin6->sin6_addr)) {
return false;
}
paddrin6->sin6_scope_id = scopeId;
paddrin6->sin6_family = AF_INET6;
paddrin6->sin6_port = htons(port);
return true;
}
return false;
}
std::vector<uint8_t> CService::GetKey() const {
std::vector<uint8_t> vKey;
vKey.resize(18);
memcpy(vKey.data(), ip, 16);
vKey[16] = port / 0x100;
vKey[17] = port & 0x0FF;
return vKey;
}
std::string CService::ToStringPort() const {
return strprintf("%u", port);
}
std::string CService::ToStringIPPort() const {
if (IsIPv4() || IsTor() || IsInternal()) {
return ToStringIP() + ":" + ToStringPort();
} else {
return "[" + ToStringIP() + "]:" + ToStringPort();
}
}
std::string CService::ToString() const {
return ToStringIPPort();
}
CSubNet::CSubNet() : valid(false) {
memset(netmask, 0, sizeof(netmask));
}
CSubNet::CSubNet(const CNetAddr &addr, int32_t mask) {
valid = 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
// 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
for (int x = 0; x < 16; ++x) {
network.ip[x] &= netmask[x];
}
}
CSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask) {
valid = 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
// offset n
const int astartofs = network.IsIPv4() ? 12 : 0;
for (int x = astartofs; x < 16; ++x) {
netmask[x] = mask.ip[x];
}
// Normalize network according to netmask
for (int x = 0; x < 16; ++x) {
network.ip[x] &= netmask[x];
}
}
CSubNet::CSubNet(const CNetAddr &addr) : valid(addr.IsValid()) {
memset(netmask, 255, sizeof(netmask));
network = addr;
}
bool CSubNet::Match(const CNetAddr &addr) const {
if (!valid || !addr.IsValid()) {
return false;
}
for (int x = 0; x < 16; ++x) {
if ((addr.ip[x] & netmask[x]) != network.ip[x]) {
return false;
}
}
return true;
}
static inline int NetmaskBits(uint8_t x) {
switch (x) {
case 0x00:
return 0;
case 0x80:
return 1;
case 0xc0:
return 2;
case 0xe0:
return 3;
case 0xf0:
return 4;
case 0xf8:
return 5;
case 0xfc:
return 6;
case 0xfe:
return 7;
case 0xff:
return 8;
default:
return -1;
}
}
std::string CSubNet::ToString() const {
/* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */
int cidr = 0;
bool valid_cidr = true;
int n = network.IsIPv4() ? 12 : 0;
for (; n < 16 && netmask[n] == 0xff; ++n) {
cidr += 8;
}
if (n < 16) {
int bits = NetmaskBits(netmask[n]);
if (bits < 0) {
valid_cidr = false;
} else {
cidr += bits;
}
++n;
}
for (; n < 16 && valid_cidr; ++n) {
if (netmask[n] != 0x00) {
valid_cidr = false;
}
}
/* Format output */
std::string strNetmask;
if (valid_cidr) {
strNetmask = strprintf("%u", cidr);
} else {
if (network.IsIPv4()) {
strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13],
netmask[14], netmask[15]);
} else {
strNetmask = strprintf(
"%x:%x:%x:%x:%x:%x:%x:%x", netmask[0] << 8 | netmask[1],
netmask[2] << 8 | netmask[3], netmask[4] << 8 | netmask[5],
netmask[6] << 8 | netmask[7], netmask[8] << 8 | netmask[9],
netmask[10] << 8 | netmask[11], netmask[12] << 8 | netmask[13],
netmask[14] << 8 | netmask[15]);
}
}
return network.ToString() + "/" + strNetmask;
}
bool CSubNet::IsValid() const {
return valid;
}
bool operator==(const CSubNet &a, const CSubNet &b) {
return a.valid == b.valid && a.network == b.network &&
!memcmp(a.netmask, b.netmask, 16);
}
bool operator<(const CSubNet &a, const CSubNet &b) {
return (a.network < b.network ||
(a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
}
diff --git a/src/netaddress.h b/src/netaddress.h
index 0fad0040d..b8b46fe4d 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -1,202 +1,202 @@
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_NETADDRESS_H
#define BITCOIN_NETADDRESS_H
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
#include <compat.h>
#include <serialize.h>
#include <span.h>
#include <cstdint>
#include <string>
#include <vector>
enum Network {
NET_UNROUTABLE = 0,
NET_IPV4,
NET_IPV6,
NET_ONION,
NET_INTERNAL,
NET_MAX,
};
/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */
class CNetAddr {
protected:
// in network byte order
uint8_t ip[16];
// for scoped/link-local ipv6 addresses
- uint32_t scopeId;
+ uint32_t scopeId{0};
public:
CNetAddr();
explicit CNetAddr(const struct in_addr &ipv4Addr);
void SetIP(const CNetAddr &ip);
private:
/**
* Set raw IPv4 or IPv6 address (in network byte order)
* @note Only NET_IPV4 and NET_IPV6 are allowed for network.
*/
void SetRaw(Network network, const uint8_t *data);
public:
/**
* Transform an arbitrary string into a non-routable ipv6 address.
* Useful for mapping resolved addresses back to their source.
*/
bool SetInternal(const std::string &name);
// for Tor addresses
bool SetSpecial(const std::string &strName);
// IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv4() const;
// IPv6 address (not mapped IPv4, not Tor)
bool IsIPv6() const;
// IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
bool IsRFC1918() const;
// IPv4 inter-network communications (192.18.0.0/15)
bool IsRFC2544() const;
// IPv4 ISP-level NAT (100.64.0.0/10)
bool IsRFC6598() const;
// IPv4 documentation addresses (192.0.2.0/24, 198.51.100.0/24,
// 203.0.113.0/24)
bool IsRFC5737() const;
// IPv6 documentation address (2001:0DB8::/32)
bool IsRFC3849() const;
// IPv4 autoconfig (169.254.0.0/16)
bool IsRFC3927() const;
// IPv6 6to4 tunnelling (2002::/16)
bool IsRFC3964() const;
// IPv6 unique local (FC00::/7)
bool IsRFC4193() const;
// IPv6 Teredo tunnelling (2001::/32)
bool IsRFC4380() const;
// IPv6 ORCHID (2001:10::/28)
bool IsRFC4843() const;
// IPv6 autoconfig (FE80::/64)
bool IsRFC4862() const;
// IPv6 well-known prefix (64:FF9B::/96)
bool IsRFC6052() const;
// IPv6 IPv4-translated address (::FFFF:0:0:0/96)
bool IsRFC6145() const;
bool IsTor() const;
bool IsLocal() const;
bool IsRoutable() const;
bool IsInternal() const;
bool IsValid() const;
enum Network GetNetwork() const;
std::string ToString() const;
std::string ToStringIP() const;
unsigned int GetByte(int n) const;
uint64_t GetHash() const;
bool GetInAddr(struct in_addr *pipv4Addr) const;
std::vector<uint8_t> GetGroup() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
explicit CNetAddr(const struct in6_addr &pipv6Addr,
const uint32_t scope = 0);
bool GetIn6Addr(struct in6_addr *pipv6Addr) const;
friend bool operator==(const CNetAddr &a, const CNetAddr &b);
friend bool operator!=(const CNetAddr &a, const CNetAddr &b) {
return !(a == b);
}
friend bool operator<(const CNetAddr &a, const CNetAddr &b);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream &s, Operation ser_action) {
READWRITE(ip);
}
friend class CSubNet;
};
class CSubNet {
protected:
/// Network (base) address
CNetAddr network;
/// Netmask, in network byte order
uint8_t netmask[16];
/// Is this value valid? (only used to signal parse errors)
bool valid;
public:
CSubNet();
CSubNet(const CNetAddr &addr, int32_t mask);
CSubNet(const CNetAddr &addr, const CNetAddr &mask);
// constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)
explicit CSubNet(const CNetAddr &addr);
bool Match(const CNetAddr &addr) const;
std::string ToString() const;
bool IsValid() const;
friend bool operator==(const CSubNet &a, const CSubNet &b);
friend bool operator!=(const CSubNet &a, const CSubNet &b) {
return !(a == b);
}
friend bool operator<(const CSubNet &a, const CSubNet &b);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream &s, Operation ser_action) {
READWRITE(network);
READWRITE(netmask);
READWRITE(valid);
}
};
/** A combination of a network address (CNetAddr) and a (TCP) port */
class CService : public CNetAddr {
protected:
// host order
unsigned short port;
public:
CService();
CService(const CNetAddr &ip, unsigned short port);
CService(const struct in_addr &ipv4Addr, unsigned short port);
explicit CService(const struct sockaddr_in &addr);
unsigned short GetPort() const;
bool GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const;
bool SetSockAddr(const struct sockaddr *paddr);
friend bool operator==(const CService &a, const CService &b);
friend bool operator!=(const CService &a, const CService &b) {
return !(a == b);
}
friend bool operator<(const CService &a, const CService &b);
std::vector<uint8_t> GetKey() const;
std::string ToString() const;
std::string ToStringPort() const;
std::string ToStringIPPort() const;
CService(const struct in6_addr &ipv6Addr, unsigned short port);
explicit CService(const struct sockaddr_in6 &addr);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream &s, Operation ser_action) {
READWRITE(ip);
unsigned short portN = htons(port);
READWRITE(Span<uint8_t>((uint8_t *)&portN, 2));
if (ser_action.ForRead()) {
port = ntohs(portN);
}
}
};
#endif // BITCOIN_NETADDRESS_H
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 23875b19f..64077f0f4 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -1,299 +1,340 @@
// Copyright (c) 2012-2016 The Bitcoin Core developers
// Copyright (c) 2017-2018 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <net.h>
#include <addrman.h>
#include <chainparams.h>
#include <clientversion.h>
#include <config.h>
#include <hash.h>
#include <netbase.h>
#include <serialize.h>
#include <streams.h>
#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <string>
class CAddrManSerializationMock : public CAddrMan {
public:
virtual void Serialize(CDataStream &s) const = 0;
//! Ensure that bucket placement is always the same for testing purposes.
void MakeDeterministic() {
nKey.SetNull();
insecure_rand = FastRandomContext(true);
}
};
class CAddrManUncorrupted : public CAddrManSerializationMock {
public:
void Serialize(CDataStream &s) const override { CAddrMan::Serialize(s); }
};
class CAddrManCorrupted : public CAddrManSerializationMock {
public:
void Serialize(CDataStream &s) const override {
// Produces corrupt output that claims addrman has 20 addrs when it only
// has one addr.
uint8_t nVersion = 1;
s << nVersion;
s << uint8_t(32);
s << nKey;
s << 10; // nNew
s << 10; // nTried
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
s << nUBuckets;
CService serv;
Lookup("252.1.1.1", serv, 7777, false);
CAddress addr = CAddress(serv, NODE_NONE);
CNetAddr resolved;
LookupHost("252.2.2.2", resolved, false);
CAddrInfo info = CAddrInfo(addr, resolved);
s << info;
}
};
class NetTestConfig : public DummyConfig {
public:
bool SetMaxBlockSize(uint64_t maxBlockSize) override {
nMaxBlockSize = maxBlockSize;
return true;
}
uint64_t GetMaxBlockSize() const override { return nMaxBlockSize; }
private:
uint64_t nMaxBlockSize;
};
static CDataStream AddrmanToStream(CAddrManSerializationMock &_addrman) {
CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION);
ssPeersIn << Params().DiskMagic();
ssPeersIn << _addrman;
std::string str = ssPeersIn.str();
std::vector<uint8_t> vchData(str.begin(), str.end());
return CDataStream(vchData, SER_DISK, CLIENT_VERSION);
}
BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(cnode_listen_port) {
// test default
unsigned short port = GetListenPort();
BOOST_CHECK(port == Params().GetDefaultPort());
// test set port
unsigned short altPort = 12345;
gArgs.SoftSetArg("-port", std::to_string(altPort));
port = GetListenPort();
BOOST_CHECK(port == altPort);
}
BOOST_AUTO_TEST_CASE(caddrdb_read) {
CAddrManUncorrupted addrmanUncorrupted;
addrmanUncorrupted.MakeDeterministic();
CService addr1, addr2, addr3;
Lookup("250.7.1.1", addr1, 8333, false);
Lookup("250.7.2.2", addr2, 9999, false);
Lookup("250.7.3.3", addr3, 9999, false);
// Add three addresses to new table.
CService source;
Lookup("252.5.1.1", source, 8333, false);
addrmanUncorrupted.Add(CAddress(addr1, NODE_NONE), source);
addrmanUncorrupted.Add(CAddress(addr2, NODE_NONE), source);
addrmanUncorrupted.Add(CAddress(addr3, NODE_NONE), source);
// Test that the de-serialization does not throw an exception.
CDataStream ssPeers1 = AddrmanToStream(addrmanUncorrupted);
bool exceptionThrown = false;
CAddrMan addrman1;
BOOST_CHECK(addrman1.size() == 0);
try {
uint8_t pchMsgTmp[4];
ssPeers1 >> pchMsgTmp;
ssPeers1 >> addrman1;
} catch (const std::exception &e) {
exceptionThrown = true;
}
BOOST_CHECK(addrman1.size() == 3);
BOOST_CHECK(exceptionThrown == false);
// Test that CAddrDB::Read creates an addrman with the correct number of
// addrs.
CDataStream ssPeers2 = AddrmanToStream(addrmanUncorrupted);
CAddrMan addrman2;
CAddrDB adb(Params());
BOOST_CHECK(addrman2.size() == 0);
adb.Read(addrman2, ssPeers2);
BOOST_CHECK(addrman2.size() == 3);
}
BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted) {
CAddrManCorrupted addrmanCorrupted;
addrmanCorrupted.MakeDeterministic();
// Test that the de-serialization of corrupted addrman throws an exception.
CDataStream ssPeers1 = AddrmanToStream(addrmanCorrupted);
bool exceptionThrown = false;
CAddrMan addrman1;
BOOST_CHECK(addrman1.size() == 0);
try {
uint8_t pchMsgTmp[4];
ssPeers1 >> pchMsgTmp;
ssPeers1 >> addrman1;
} catch (const std::exception &e) {
exceptionThrown = true;
}
// Even through de-serialization failed addrman is not left in a clean
// state.
BOOST_CHECK(addrman1.size() == 1);
BOOST_CHECK(exceptionThrown);
// Test that CAddrDB::Read leaves addrman in a clean state if
// de-serialization fails.
CDataStream ssPeers2 = AddrmanToStream(addrmanCorrupted);
CAddrMan addrman2;
CAddrDB adb(Params());
BOOST_CHECK(addrman2.size() == 0);
adb.Read(addrman2, ssPeers2);
BOOST_CHECK(addrman2.size() == 0);
}
BOOST_AUTO_TEST_CASE(cnode_simple_test) {
SOCKET hSocket = INVALID_SOCKET;
NodeId id = 0;
int height = 0;
in_addr ipv4Addr;
ipv4Addr.s_addr = 0xa0b0c001;
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
std::string pszDest;
bool fInboundIn = false;
// Test that fFeeler is false by default.
auto pnode1 =
std::make_unique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0,
CAddress(), pszDest, fInboundIn);
BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false);
fInboundIn = true;
auto pnode2 =
std::make_unique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 1, 1,
CAddress(), pszDest, fInboundIn);
BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false);
}
BOOST_AUTO_TEST_CASE(test_getSubVersionEB) {
BOOST_CHECK_EQUAL(getSubVersionEB(13800000000), "13800.0");
BOOST_CHECK_EQUAL(getSubVersionEB(3800000000), "3800.0");
BOOST_CHECK_EQUAL(getSubVersionEB(14000000), "14.0");
BOOST_CHECK_EQUAL(getSubVersionEB(1540000), "1.5");
BOOST_CHECK_EQUAL(getSubVersionEB(1560000), "1.5");
BOOST_CHECK_EQUAL(getSubVersionEB(210000), "0.2");
BOOST_CHECK_EQUAL(getSubVersionEB(10000), "0.0");
BOOST_CHECK_EQUAL(getSubVersionEB(0), "0.0");
}
BOOST_AUTO_TEST_CASE(test_userAgent) {
NetTestConfig config;
config.SetMaxBlockSize(8000000);
const std::string uacomment = "A very nice comment";
gArgs.ForceSetMultiArg("-uacomment", uacomment);
const std::string versionMessage =
"/Bitcoin ABC:" + std::to_string(CLIENT_VERSION_MAJOR) + "." +
std::to_string(CLIENT_VERSION_MINOR) + "." +
std::to_string(CLIENT_VERSION_REVISION) + "(EB8.0; " + uacomment + ")/";
BOOST_CHECK_EQUAL(userAgent(config), versionMessage);
}
BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network) {
BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true);
BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true);
BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true);
SetReachable(NET_IPV4, false);
SetReachable(NET_IPV6, false);
SetReachable(NET_ONION, false);
BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), false);
BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), false);
BOOST_CHECK_EQUAL(IsReachable(NET_ONION), false);
SetReachable(NET_IPV4, true);
SetReachable(NET_IPV6, true);
SetReachable(NET_ONION, true);
BOOST_CHECK_EQUAL(IsReachable(NET_IPV4), true);
BOOST_CHECK_EQUAL(IsReachable(NET_IPV6), true);
BOOST_CHECK_EQUAL(IsReachable(NET_ONION), true);
}
BOOST_AUTO_TEST_CASE(LimitedAndReachable_NetworkCaseUnroutableAndInternal) {
BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true);
BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true);
SetReachable(NET_UNROUTABLE, false);
SetReachable(NET_INTERNAL, false);
// Ignored for both networks
BOOST_CHECK_EQUAL(IsReachable(NET_UNROUTABLE), true);
BOOST_CHECK_EQUAL(IsReachable(NET_INTERNAL), true);
}
CNetAddr UtilBuildAddress(uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4) {
uint8_t ip[] = {p1, p2, p3, p4};
struct sockaddr_in sa;
// initialize the memory block
memset(&sa, 0, sizeof(sockaddr_in));
memcpy(&(sa.sin_addr), &ip, sizeof(ip));
return CNetAddr(sa.sin_addr);
}
BOOST_AUTO_TEST_CASE(LimitedAndReachable_CNetAddr) {
// 1.1.1.1
CNetAddr addr = UtilBuildAddress(0x001, 0x001, 0x001, 0x001);
SetReachable(NET_IPV4, true);
BOOST_CHECK_EQUAL(IsReachable(addr), true);
SetReachable(NET_IPV4, false);
BOOST_CHECK_EQUAL(IsReachable(addr), false);
// have to reset this, because this is stateful.
SetReachable(NET_IPV4, true);
}
BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle) {
// 2.1.1.1:1000
CService addr =
CService(UtilBuildAddress(0x002, 0x001, 0x001, 0x001), 1000);
SetReachable(NET_IPV4, true);
BOOST_CHECK_EQUAL(IsLocal(addr), false);
BOOST_CHECK_EQUAL(AddLocal(addr, 1000), true);
BOOST_CHECK_EQUAL(IsLocal(addr), true);
RemoveLocal(addr);
BOOST_CHECK_EQUAL(IsLocal(addr), false);
}
+// prior to PR #14728, this test triggers an undefined behavior
+BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) {
+ // set up local addresses; all that's necessary to reproduce the bug is
+ // that a normal IPv4 address is among the entries, but if this address is
+ // !IsRoutable the undefined behavior is easier to trigger deterministically
+ {
+ LOCK(cs_mapLocalHost);
+ in_addr ipv4AddrLocal;
+ ipv4AddrLocal.s_addr = 0x0100007f;
+ CNetAddr addr = CNetAddr(ipv4AddrLocal);
+ LocalServiceInfo lsi;
+ lsi.nScore = 23;
+ lsi.nPort = 42;
+ mapLocalHost[addr] = lsi;
+ }
+
+ // create a peer with an IPv4 address
+ in_addr ipv4AddrPeer;
+ ipv4AddrPeer.s_addr = 0xa0b0c001;
+ CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
+ std::unique_ptr<CNode> pnode =
+ std::make_unique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0,
+ CAddress{}, std::string{}, false);
+ pnode->fSuccessfullyConnected.store(true);
+
+ // the peer claims to be reaching us via IPv6
+ in6_addr ipv6AddrLocal;
+ memset(ipv6AddrLocal.s6_addr, 0, 16);
+ ipv6AddrLocal.s6_addr[0] = 0xcc;
+ CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK);
+ pnode->SetAddrLocal(addrLocal);
+
+ // before patch, this causes undefined behavior detectable with clang's
+ // -fsanitize=memory
+ AdvertiseLocal(&*pnode);
+
+ // suppress no-checks-run warning; if this test fails, it's by triggering a
+ // sanitizer
+ BOOST_CHECK(1);
+}
+
BOOST_AUTO_TEST_SUITE_END()

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jan 29, 17:07 (11 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5053371
Default Alt Text
(39 KB)

Event Timeline