|
|
@ -114,6 +114,8 @@ namespace transport |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (m_State == eSSU2SessionStateUnknown || m_State == eSSU2SessionStateTokenReceived) |
|
|
|
if (m_State == eSSU2SessionStateUnknown || m_State == eSSU2SessionStateTokenReceived) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
LogPrint(eLogDebug, "SSU2: Connecting to ", GetRemoteEndpoint (), |
|
|
|
|
|
|
|
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ")"); |
|
|
|
ScheduleConnectTimer (); |
|
|
|
ScheduleConnectTimer (); |
|
|
|
auto token = m_Server.FindOutgoingToken (m_RemoteEndpoint); |
|
|
|
auto token = m_Server.FindOutgoingToken (m_RemoteEndpoint); |
|
|
|
if (token) |
|
|
|
if (token) |
|
|
@ -243,7 +245,7 @@ namespace transport |
|
|
|
if (IsEstablished ()) |
|
|
|
if (IsEstablished ()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
uint8_t payload[20]; |
|
|
|
uint8_t payload[20]; |
|
|
|
size_t payloadSize = CreatePaddingBlock (payload, 20, 5); |
|
|
|
size_t payloadSize = CreatePaddingBlock (payload, 20, 8); |
|
|
|
SendData (payload, payloadSize); |
|
|
|
SendData (payload, payloadSize); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -269,7 +271,16 @@ namespace transport |
|
|
|
m_ReceivedI2NPMsgIDs.clear (); |
|
|
|
m_ReceivedI2NPMsgIDs.clear (); |
|
|
|
m_Server.RemoveSession (m_SourceConnID); |
|
|
|
m_Server.RemoveSession (m_SourceConnID); |
|
|
|
transports.PeerDisconnected (shared_from_this ()); |
|
|
|
transports.PeerDisconnected (shared_from_this ()); |
|
|
|
LogPrint (eLogDebug, "SSU2: Session terminated"); |
|
|
|
auto remoteIdentity = GetRemoteIdentity (); |
|
|
|
|
|
|
|
if (remoteIdentity) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), |
|
|
|
|
|
|
|
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") terminated"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), " terminated"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -298,6 +309,8 @@ namespace transport |
|
|
|
m_OnEstablished (); |
|
|
|
m_OnEstablished (); |
|
|
|
m_OnEstablished = nullptr; |
|
|
|
m_OnEstablished = nullptr; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
LogPrint(eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), |
|
|
|
|
|
|
|
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") established"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void SSU2Session::Done () |
|
|
|
void SSU2Session::Done () |
|
|
@ -1053,6 +1066,17 @@ namespace transport |
|
|
|
LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block"); |
|
|
|
LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block"); |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
auto ts = i2p::util::GetMillisecondsSinceEpoch(); |
|
|
|
|
|
|
|
if (ts > ri->GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is too old for ", (ts - ri->GetTimestamp ())/1000LL, " seconds"); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri->GetTimestamp ()) // 2 minutes
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is from future for ", (ri->GetTimestamp () - ts)/1000LL, " seconds"); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address (); |
|
|
|
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address (); |
|
|
|
if (!m_Address || memcmp (S, m_Address->s, 32)) |
|
|
|
if (!m_Address || memcmp (S, m_Address->s, 32)) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -1486,7 +1510,7 @@ namespace transport |
|
|
|
auto size = bufbe16toh (buf + offset); |
|
|
|
auto size = bufbe16toh (buf + offset); |
|
|
|
offset += 2; |
|
|
|
offset += 2; |
|
|
|
LogPrint (eLogDebug, "SSU2: Block type ", (int)blk, " of size ", size); |
|
|
|
LogPrint (eLogDebug, "SSU2: Block type ", (int)blk, " of size ", size); |
|
|
|
if (size > len) |
|
|
|
if (offset + size > len) |
|
|
|
{ |
|
|
|
{ |
|
|
|
LogPrint (eLogError, "SSU2: Unexpected block length ", size); |
|
|
|
LogPrint (eLogError, "SSU2: Unexpected block length ", size); |
|
|
|
break; |
|
|
|
break; |
|
|
@ -1532,7 +1556,9 @@ namespace transport |
|
|
|
break; |
|
|
|
break; |
|
|
|
case eSSU2BlkTermination: |
|
|
|
case eSSU2BlkTermination: |
|
|
|
{ |
|
|
|
{ |
|
|
|
uint8_t rsn = buf[11]; // reason
|
|
|
|
if (size >= 9) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
uint8_t rsn = buf[offset + 8]; // reason
|
|
|
|
LogPrint (eLogDebug, "SSU2: Termination reason=", (int)rsn); |
|
|
|
LogPrint (eLogDebug, "SSU2: Termination reason=", (int)rsn); |
|
|
|
if (IsEstablished () && rsn != eSSU2TerminationReasonTerminationReceived) |
|
|
|
if (IsEstablished () && rsn != eSSU2TerminationReasonTerminationReceived) |
|
|
|
RequestTermination (eSSU2TerminationReasonTerminationReceived); |
|
|
|
RequestTermination (eSSU2TerminationReasonTerminationReceived); |
|
|
@ -1542,6 +1568,9 @@ namespace transport |
|
|
|
m_State = eSSU2SessionStateClosingConfirmed; |
|
|
|
m_State = eSSU2SessionStateClosingConfirmed; |
|
|
|
Done (); |
|
|
|
Done (); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
LogPrint(eLogWarning, "SSU2: Unexpected termination block size ", size); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
case eSSU2BlkRelayRequest: |
|
|
|
case eSSU2BlkRelayRequest: |
|
|
@ -1635,8 +1664,8 @@ namespace transport |
|
|
|
break; |
|
|
|
break; |
|
|
|
case eSSU2SessionStateSessionCreatedReceived: |
|
|
|
case eSSU2SessionStateSessionCreatedReceived: |
|
|
|
case eSSU2SessionStateTokenReceived: |
|
|
|
case eSSU2SessionStateTokenReceived: |
|
|
|
if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting) || |
|
|
|
if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetTesting ()) || |
|
|
|
(m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting)) |
|
|
|
(m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetTestingV6 ())) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (m_Server.IsSyncClockFromPeers ()) |
|
|
|
if (m_Server.IsSyncClockFromPeers ()) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -1734,14 +1763,14 @@ namespace transport |
|
|
|
LogPrint (eLogInfo, "SSU2: Our port ", ep.port (), " received from ", m_RemoteEndpoint, " is different from ", m_Server.GetPort (isV4)); |
|
|
|
LogPrint (eLogInfo, "SSU2: Our port ", ep.port (), " received from ", m_RemoteEndpoint, " is different from ", m_Server.GetPort (isV4)); |
|
|
|
if (isV4) |
|
|
|
if (isV4) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (i2p::context.GetStatus () == eRouterStatusTesting) |
|
|
|
if (i2p::context.GetTesting ()) |
|
|
|
i2p::context.SetError (eRouterErrorSymmetricNAT); |
|
|
|
i2p::context.SetError (eRouterErrorSymmetricNAT); |
|
|
|
else if (m_State == eSSU2SessionStatePeerTest) |
|
|
|
else if (m_State == eSSU2SessionStatePeerTest) |
|
|
|
i2p::context.SetError (eRouterErrorFullConeNAT); |
|
|
|
i2p::context.SetError (eRouterErrorFullConeNAT); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (i2p::context.GetStatusV6 () == eRouterStatusTesting) |
|
|
|
if (i2p::context.GetTestingV6 ()) |
|
|
|
i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT); |
|
|
|
i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT); |
|
|
|
else if (m_State == eSSU2SessionStatePeerTest) |
|
|
|
else if (m_State == eSSU2SessionStatePeerTest) |
|
|
|
i2p::context.SetErrorV6 (eRouterErrorFullConeNAT); |
|
|
|
i2p::context.SetErrorV6 (eRouterErrorFullConeNAT); |
|
|
@ -2214,7 +2243,7 @@ namespace transport |
|
|
|
if (buf[1] == eSSU2PeerTestCodeAccept) |
|
|
|
if (buf[1] == eSSU2PeerTestCodeAccept) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (GetRouterStatus () == eRouterStatusUnknown) |
|
|
|
if (GetRouterStatus () == eRouterStatusUnknown) |
|
|
|
SetRouterStatus (eRouterStatusTesting); |
|
|
|
SetTestingState (true); |
|
|
|
auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie
|
|
|
|
auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie
|
|
|
|
if (r && it->second.first) |
|
|
|
if (r && it->second.first) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -2240,7 +2269,10 @@ namespace transport |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (GetRouterStatus () == eRouterStatusTesting) |
|
|
|
if (GetTestingState ()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
SetTestingState (false); |
|
|
|
|
|
|
|
if (GetRouterStatus () != eRouterStatusFirewalled) |
|
|
|
{ |
|
|
|
{ |
|
|
|
SetRouterStatus (eRouterStatusFirewalled); |
|
|
|
SetRouterStatus (eRouterStatusFirewalled); |
|
|
|
if (m_Address->IsV4 ()) |
|
|
|
if (m_Address->IsV4 ()) |
|
|
@ -2249,6 +2281,7 @@ namespace transport |
|
|
|
m_Server.RescheduleIntroducersUpdateTimerV6 (); |
|
|
|
m_Server.RescheduleIntroducersUpdateTimerV6 (); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), |
|
|
|
LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), |
|
|
|
" with information about ", i2p::data::GetIdentHashAbbreviation (i2p::data::IdentHash (buf + 3))); |
|
|
|
" with information about ", i2p::data::GetIdentHashAbbreviation (i2p::data::IdentHash (buf + 3))); |
|
|
|
} |
|
|
|
} |
|
|
@ -2275,7 +2308,7 @@ namespace transport |
|
|
|
{ |
|
|
|
{ |
|
|
|
LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ", |
|
|
|
LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ", |
|
|
|
i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3))); |
|
|
|
i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3))); |
|
|
|
if (GetRouterStatus () == eRouterStatusTesting) |
|
|
|
if (GetTestingState ()) |
|
|
|
SetRouterStatus (eRouterStatusUnknown); |
|
|
|
SetRouterStatus (eRouterStatusUnknown); |
|
|
|
it->second.first->Done (); |
|
|
|
it->second.first->Done (); |
|
|
|
} |
|
|
|
} |
|
|
@ -2429,6 +2462,29 @@ namespace transport |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool SSU2Session::GetTestingState () const |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (m_Address) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (m_Address->IsV4 ()) |
|
|
|
|
|
|
|
return i2p::context.GetTesting (); |
|
|
|
|
|
|
|
if (m_Address->IsV6 ()) |
|
|
|
|
|
|
|
return i2p::context.GetTestingV6 (); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SSU2Session::SetTestingState (bool testing) const |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (m_Address) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (m_Address->IsV4 ()) |
|
|
|
|
|
|
|
i2p::context.SetTesting (testing); |
|
|
|
|
|
|
|
else if (m_Address->IsV6 ()) |
|
|
|
|
|
|
|
i2p::context.SetTestingV6 (testing); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep) |
|
|
|
size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (len < 9) return 0; |
|
|
|
if (len < 9) return 0; |
|
|
@ -2841,7 +2897,7 @@ namespace transport |
|
|
|
|
|
|
|
|
|
|
|
void SSU2Session::SendPathResponse (const uint8_t * data, size_t len) |
|
|
|
void SSU2Session::SendPathResponse (const uint8_t * data, size_t len) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (len < 8 || len > m_MaxPayloadSize - 3) |
|
|
|
if (len > m_MaxPayloadSize - 3) |
|
|
|
{ |
|
|
|
{ |
|
|
|
LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len); |
|
|
|
LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len); |
|
|
|
return; |
|
|
|
return; |
|
|
@ -2850,7 +2906,10 @@ namespace transport |
|
|
|
payload[0] = eSSU2BlkPathResponse; |
|
|
|
payload[0] = eSSU2BlkPathResponse; |
|
|
|
htobe16buf (payload + 1, len); |
|
|
|
htobe16buf (payload + 1, len); |
|
|
|
memcpy (payload + 3, data, len); |
|
|
|
memcpy (payload + 3, data, len); |
|
|
|
SendData (payload, len + 3); |
|
|
|
size_t payloadSize = len + 3; |
|
|
|
|
|
|
|
if (payloadSize < m_MaxPayloadSize) |
|
|
|
|
|
|
|
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, payloadSize < 8 ? 8 : 0); |
|
|
|
|
|
|
|
SendData (payload, payloadSize); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void SSU2Session::SendPathChallenge () |
|
|
|
void SSU2Session::SendPathChallenge () |
|
|
@ -2868,7 +2927,7 @@ namespace transport |
|
|
|
} |
|
|
|
} |
|
|
|
len += 3; |
|
|
|
len += 3; |
|
|
|
if (len < m_MaxPayloadSize) |
|
|
|
if (len < m_MaxPayloadSize) |
|
|
|
len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len); |
|
|
|
len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len, len < 8 ? 8 : 0); |
|
|
|
SendData (payload, len); |
|
|
|
SendData (payload, len); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|