diff --git a/libi2pd/Profiling.cpp b/libi2pd/Profiling.cpp index ec9540c0..bb40ae41 100644 --- a/libi2pd/Profiling.cpp +++ b/libi2pd/Profiling.cpp @@ -278,6 +278,15 @@ namespace data return it->second->IsUnreachable (); return false; } + + bool IsRouterDuplicated (const IdentHash& identHash) + { + std::lock_guard l(g_ProfilesMutex); + auto it = g_Profiles.find (identHash); + if (it != g_Profiles.end ()) + return it->second->IsDuplicated (); + return false; + } void InitProfilesStorage () { diff --git a/libi2pd/Profiling.h b/libi2pd/Profiling.h index 014d3dea..32d760a6 100644 --- a/libi2pd/Profiling.h +++ b/libi2pd/Profiling.h @@ -113,6 +113,7 @@ namespace data std::shared_ptr GetRouterProfile (const IdentHash& identHash); bool IsRouterBanned (const IdentHash& identHash); // check only existing profiles + bool IsRouterDuplicated (const IdentHash& identHash); // check only existing profiles void InitProfilesStorage (); std::future DeleteObsoleteProfiles (); void SaveProfiles (); diff --git a/libi2pd/TransitTunnel.cpp b/libi2pd/TransitTunnel.cpp index e8ac7f5b..57fd8513 100644 --- a/libi2pd/TransitTunnel.cpp +++ b/libi2pd/TransitTunnel.cpp @@ -349,15 +349,23 @@ namespace tunnel if (!retCode) { - // create new transit tunnel - transitTunnel = i2p::tunnel::CreateTransitTunnel ( - bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), - clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, - bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), - layerKey, ivKey, - clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, - clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); - if (!AddTransitTunnel (transitTunnel)) + i2p::data::IdentHash nextIdent(clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET); + bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; + if (isEndpoint || !i2p::data::IsRouterDuplicated (nextIdent)) + { + // create new transit tunnel + transitTunnel = CreateTransitTunnel ( + bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), + nextIdent, + bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + layerKey, ivKey, + clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, + isEndpoint); + if (!AddTransitTunnel (transitTunnel)) + retCode = 30; + } + else + // decline tunnel going to duplicated router retCode = 30; } @@ -477,23 +485,32 @@ namespace tunnel accept = false; } } - // replace record to reply + if (accept) { - auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( - bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), - clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), - clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, - clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, - clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, - clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); - if (!AddTransitTunnel (transitTunnel)) + i2p::data::IdentHash nextIdent(clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET); + bool isEndpoint = clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; + if (isEndpoint || !i2p::data::IsRouterDuplicated (nextIdent)) + { + auto transitTunnel = CreateTransitTunnel ( + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), + nextIdent, + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, + clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, + clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, + isEndpoint); + if (!AddTransitTunnel (transitTunnel)) + retCode = 30; + } + else + // decline tunnel going to duplicated router retCode = 30; } else retCode = 30; // always reject with bandwidth reason (30) + // replace record to reply memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode; // encrypt reply