Rewrite CNetAddr::GetReachabilityFrom()

Add support for Tor/I2P networks, and make code more readable.
This commit is contained in:
Pieter Wuille 2012-05-01 17:32:42 +02:00
parent 70f7f00385
commit d077dd2a6e
2 changed files with 74 additions and 31 deletions

View File

@ -910,39 +910,82 @@ void CNetAddr::print() const
printf("CNetAddr(%s)\n", ToString().c_str()); printf("CNetAddr(%s)\n", ToString().c_str());
} }
// for IPv6 partners: for unknown/Teredo partners: for IPv4 partners: for Tor partners: for I2P partners: // private extensions to enum Network, only returned by GetExtNetwork,
// 0 - unroutable // 0 - unroutable // 0 - unroutable // 0 - unroutable // 0 - unroutable // and only used in GetReachabilityFrom
// 1 - teredo // 1 - teredo // 1 - ipv4 // 1 - the rest // 1 - the rest static const int NET_UNKNOWN = NET_MAX + 0;
// 2 - tunneled ipv6 // 2 - tunneled ipv6 // 2 - ip4 // 2 - I2P static const int NET_TEREDO = NET_MAX + 1;
// 3 - ipv4 // 3 - ipv6 // 3 - tor int static GetExtNetwork(const CNetAddr *addr)
// 4 - ipv6 // 4 - ipv4 {
if (addr == NULL)
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 int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
{ {
if (!IsValid() || !IsRoutable()) enum Reachability {
return 0; REACH_UNREACHABLE,
if (paddrPartner && paddrPartner->IsIPv4()) REACH_DEFAULT,
return IsIPv4() ? 1 : 0; REACH_TEREDO,
if (paddrPartner && paddrPartner->IsTor()) { REACH_IPV6_WEAK,
if (IsIPv4()) REACH_IPV4,
return 2; REACH_IPV6_STRONG,
if (IsTor()) REACH_PRIVATE
return 3; };
return 1;
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 tunneled
}
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_I2P:
switch(ourNet) {
default: return REACH_DEFAULT;
case NET_I2P: 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_I2P: return REACH_PRIVATE; // assume connections from unroutable addresses are
case NET_TOR: return REACH_PRIVATE; // either from Tor/I2P, or don't care about our address
} }
if (paddrPartner && paddrPartner->IsI2P()) {
if (IsI2P())
return 2;
return 1;
} }
if (IsRFC4380())
return 1;
if (IsRFC3964() || IsRFC6052())
return 2;
bool fRealIPv6 = paddrPartner && !paddrPartner->IsRFC4380() && paddrPartner->IsValid() && paddrPartner->IsRoutable();
if (fRealIPv6)
return IsIPv4() ? 3 : 4;
else
return IsIPv4() ? 4 : 3;
} }
void CService::Init() void CService::Init()

View File

@ -25,7 +25,7 @@ enum Network
NET_TOR, NET_TOR,
NET_I2P, NET_I2P,
NET_MAX NET_MAX,
}; };
extern int nConnectTimeout; extern int nConnectTimeout;