Merge #15718: docs: Improve netaddress comments

303372c41a docs: Improve netaddress comments (Carl Dong)

Pull request description:

  Improves comments for `netaddress`, making them available to Doxygen.

  I think this is worthwhile because a lot of the code require some context (e.g., A lot of the things that we do to fit hostnames and tor addresses into `CNetAddr` is non-obvious, and documenting it is beneficial).

ACKs for commit 303372:

Tree-SHA512: 2a35784a01ed8ec5fdbe111a540192d31bde16afa96e4be97b0385daf290fc7469a66d7cb8905a70b920fad6a0e7400ca4e5da082d6e4af1d1aaccc0e8297720
This commit is contained in:
Wladimir J. van der Laan 2019-04-11 16:02:03 +02:00
commit bb68abe784
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
2 changed files with 119 additions and 10 deletions

View file

@ -14,6 +14,11 @@ static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
// 0xFD + sha256("bitcoin")[0:5] // 0xFD + sha256("bitcoin")[0:5]
static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 }; static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
/**
* Construct an unspecified IPv6 network address (::/128).
*
* @note This address is considered invalid by CNetAddr::IsValid()
*/
CNetAddr::CNetAddr() CNetAddr::CNetAddr()
{ {
memset(ip, 0, sizeof(ip)); memset(ip, 0, sizeof(ip));
@ -40,6 +45,20 @@ void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
} }
} }
/**
* 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
* 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.
*
* @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()) {
@ -52,6 +71,16 @@ bool CNetAddr::SetInternal(const std::string &name)
return true; return true;
} }
/**
* Try to make this a dummy address that maps the specified onion address into
* 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.
*
* @see CNetAddr::IsTor(), CNetAddr::IsRFC4193()
*/
bool CNetAddr::SetSpecial(const std::string &strName) bool CNetAddr::SetSpecial(const std::string &strName)
{ {
if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") { if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
@ -175,6 +204,12 @@ bool CNetAddr::IsRFC4843() const
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
} }
/**
* @returns Whether or not this is a dummy address that maps an onion address
* into IPv6.
*
* @see CNetAddr::SetSpecial(const std::string &)
*/
bool CNetAddr::IsTor() const bool CNetAddr::IsTor() const
{ {
return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
@ -194,6 +229,16 @@ bool CNetAddr::IsLocal() const
return false; return false;
} }
/**
* @returns Whether or not this network address is a valid address that @a could
* be used to refer to an actual host.
*
* @note A valid address may or may not be publicly routable on the global
* internet. As in, the set of valid addreses is a superset of the set of
* publicly routable addresses.
*
* @see CNetAddr::IsRoutable()
*/
bool CNetAddr::IsValid() const bool CNetAddr::IsValid() const
{ {
// Cleanup 3-byte shifted addresses caused by garbage in size field // Cleanup 3-byte shifted addresses caused by garbage in size field
@ -233,11 +278,25 @@ bool CNetAddr::IsValid() const
return true; return true;
} }
/**
* @returns Whether or not this network address is publicly routable on the
* global internet.
*
* @note A routable address is always valid. As in, the set of routable addreses
* is a subset of the set of valid addresses.
*
* @see CNetAddr::IsValid()
*/
bool CNetAddr::IsRoutable() const bool CNetAddr::IsRoutable() const
{ {
return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal() || IsInternal()); return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal() || IsInternal());
} }
/**
* @returns Whether or not this is a dummy address that maps a name into IPv6.
*
* @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 memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0;
@ -299,6 +358,16 @@ bool operator<(const CNetAddr& a, const CNetAddr& b)
return (memcmp(a.ip, b.ip, 16) < 0); return (memcmp(a.ip, b.ip, 16) < 0);
} }
/**
* Try to get our IPv4 address.
*
* @param[out] pipv4Addr The in_addr struct to which to copy.
*
* @returns Whether or not the operation was successful, in particular, whether
* or not our address was an IPv4 address.
*
* @see CNetAddr::IsIPv4()
*/
bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
{ {
if (!IsIPv4()) if (!IsIPv4())
@ -307,6 +376,16 @@ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
return true; return true;
} }
/**
* Try to get our IPv6 address.
*
* @param[out] pipv6Addr The in6_addr struct to which to copy.
*
* @returns Whether or not the operation was successful, in particular, whether
* or not our address was an IPv6 address.
*
* @see CNetAddr::IsIPv6()
*/
bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
{ {
if (!IsIPv6()) { if (!IsIPv6()) {
@ -316,8 +395,16 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
return true; return true;
} }
// get canonical identifier of an address' group /**
// no two connections will be attempted to addresses with the same group * Get the canonical identifier of our network group
*
* The groups are assigned in a way where it should be costly for an attacker to
* obtain addresses with many different group identifiers, even if it is cheap
* to obtain addresses with the same identifier.
*
* @note No two connections will be attempted to addresses with the same network
* group.
*/
std::vector<unsigned char> CNetAddr::GetGroup() const std::vector<unsigned char> CNetAddr::GetGroup() const
{ {
std::vector<unsigned char> vchRet; std::vector<unsigned char> vchRet;
@ -379,12 +466,15 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
nBits = 32; nBits = 32;
vchRet.push_back(nClass); vchRet.push_back(nClass);
// push our ip onto vchRet byte by byte...
while (nBits >= 8) while (nBits >= 8)
{ {
vchRet.push_back(GetByte(15 - nStartByte)); vchRet.push_back(GetByte(15 - nStartByte));
nStartByte++; nStartByte++;
nBits -= 8; nBits -= 8;
} }
// ...for the last byte, push nBits and for the rest of the byte push 1's
if (nBits > 0) if (nBits > 0)
vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1)); vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1));
@ -526,6 +616,18 @@ 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); return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) || (static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port < b.port);
} }
/**
* Obtain the IPv4/6 socket address this represents.
*
* @param[out] paddr The obtained socket address.
* @param[in,out] addrlen The size, in bytes, of the address structure pointed
* to by paddr. The value that's pointed to by this
* parameter might change after calling this function if
* the size of the corresponding address structure
* changed.
*
* @returns Whether or not the operation was successful.
*/
bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
{ {
if (IsIPv4()) { if (IsIPv4()) {
@ -556,13 +658,16 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
return false; return false;
} }
/**
* @returns An identifier unique to this service's address and port number.
*/
std::vector<unsigned char> CService::GetKey() const std::vector<unsigned char> CService::GetKey() const
{ {
std::vector<unsigned char> vKey; std::vector<unsigned char> vKey;
vKey.resize(18); vKey.resize(18);
memcpy(vKey.data(), ip, 16); memcpy(vKey.data(), ip, 16);
vKey[16] = port / 0x100; vKey[16] = port / 0x100; // most significant byte of our port
vKey[17] = port & 0x0FF; vKey[17] = port & 0x0FF; // least significant byte of our port
return vKey; return vKey;
} }
@ -641,6 +746,10 @@ CSubNet::CSubNet(const CNetAddr &addr):
network = addr; network = addr;
} }
/**
* @returns True if this subnet is valid, the specified address is valid, and
* 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())
@ -651,6 +760,10 @@ bool CSubNet::Match(const CNetAddr &addr) const
return true; return true;
} }
/**
* @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.
*/
static inline int NetmaskBits(uint8_t x) static inline int NetmaskBits(uint8_t x)
{ {
switch(x) { switch(x) {

View file

@ -48,10 +48,6 @@ class CNetAddr
void SetRaw(Network network, const uint8_t *data); void SetRaw(Network network, const uint8_t *data);
public: 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); bool SetInternal(const std::string& name);
bool SetSpecial(const std::string &strName); // for Tor addresses bool SetSpecial(const std::string &strName); // for Tor addresses
@ -69,8 +65,8 @@ class CNetAddr
bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32) bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32)
bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28) bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) bool IsRFC6052() const; // IPv6 well-known prefix for IPv4-embedded address (64:FF9B::/96)
bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) (actually defined in RFC2765)
bool IsTor() const; bool IsTor() const;
bool IsLocal() const; bool IsLocal() const;
bool IsRoutable() const; bool IsRoutable() const;