// get canonical identifier of an address' group // no two connections will be attempted to addresses with the same group std::vector<unsigned char> CNetAddr::GetGroup() const { std::vector<unsigned char> 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; } // all unroutable addresses belong to the same group if (!IsRoutable()) { nClass = NET_UNROUTABLE; nBits = 0; } // for IPv4 addresses, '1' + the 16 higher-order bits of the IP // includes mapped IPv4, SIIT translated IPv4, and the well-known prefix else if (IsIPv4() || IsRFC6145() || IsRFC6052()) { nClass = NET_IPV4; nStartByte = 12; } // for 6to4 tunnelled addresses, use the encapsulated IPv4 address else if (IsRFC3964()) { nClass = NET_IPV4; nStartByte = 2; } // for Teredo-tunnelled IPv6 addresses, use the encapsulated IPv4 address else if (IsRFC4380()) { vchRet.push_back(NET_IPV4); vchRet.push_back(GetByte(3) ^ 0xFF); vchRet.push_back(GetByte(2) ^ 0xFF); return vchRet; } // for he.net, use /36 groups else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70) nBits = 36; // for the rest of the IPv6 network, use /32 groups else 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 << nBits) - 1)); return vchRet; }
/** 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()) 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; case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunnelled } case NET_TOR: switch(ourNet) { default: return REACH_DEFAULT; case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well case NET_TOR: 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; case NET_TOR: return REACH_PRIVATE; // either from Tor, or don't care about our address } } }
enum Network CNetAddr::GetNetwork() const { if (!IsRoutable()) return NET_UNROUTABLE; if (IsIPv4()) return NET_IPV4; return NET_IPV6; }
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; }