SSU2Session.cpp
1 /* 2 * Copyright (c) 2022-2026, The PurpleI2P Project 3 * 4 * This file is part of Purple i2pd project and licensed under BSD3 5 * 6 * See full license text in LICENSE file at top of project tree 7 */ 8 9 #include <string.h> 10 #include <openssl/rand.h> 11 #include "Log.h" 12 #include "Transports.h" 13 #include "Gzip.h" 14 #include "NetDb.hpp" 15 #include "SSU2.h" 16 #include "SSU2Session.h" 17 18 namespace i2p 19 { 20 namespace transport 21 { 22 void SSU2IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize) 23 { 24 if (msg->len + fragmentSize > msg->maxLen) 25 { 26 LogPrint (eLogInfo, "SSU2: I2NP message size ", msg->maxLen, " is not enough"); 27 auto newMsg = NewI2NPMessage (msg->len + fragmentSize); 28 *newMsg = *msg; 29 msg = newMsg; 30 } 31 if (msg->Concat (fragment, fragmentSize) < fragmentSize) 32 LogPrint (eLogError, "SSU2: I2NP buffer overflow ", msg->maxLen); 33 nextFragmentNum++; 34 } 35 36 bool SSU2IncompleteMessage::ConcatOutOfSequenceFragments () 37 { 38 bool isLast = false; 39 while (outOfSequenceFragments) 40 { 41 if (outOfSequenceFragments->fragmentNum == nextFragmentNum) 42 { 43 AttachNextFragment (outOfSequenceFragments->buf, outOfSequenceFragments->len); 44 isLast = outOfSequenceFragments->isLast; 45 if (isLast) 46 outOfSequenceFragments = nullptr; 47 else 48 outOfSequenceFragments = outOfSequenceFragments->next; 49 } 50 else 51 break; 52 } 53 return isLast; 54 } 55 56 void SSU2IncompleteMessage::AddOutOfSequenceFragment (std::shared_ptr<SSU2IncompleteMessage::Fragment> fragment) 57 { 58 if (!fragment || !fragment->fragmentNum) return; // fragment 0 not allowed 59 if (fragment->fragmentNum < nextFragmentNum) return; // already processed 60 if (!outOfSequenceFragments) 61 outOfSequenceFragments = fragment; 62 else 63 { 64 auto frag = outOfSequenceFragments; 65 std::shared_ptr<Fragment> prev; 66 do 67 { 68 if (fragment->fragmentNum < frag->fragmentNum) break; // found 69 if (fragment->fragmentNum == frag->fragmentNum) return; // duplicate 70 prev = frag; frag = frag->next; 71 } 72 while (frag); 73 fragment->next = frag; 74 if (prev) 75 prev->next = fragment; 76 else 77 outOfSequenceFragments = fragment; 78 } 79 lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch (); 80 } 81 82 SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter, 83 std::shared_ptr<const i2p::data::RouterInfo::Address> addr, bool noise): 84 TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT), 85 m_Server (server), m_Address (addr), m_RemoteTransports (0), m_RemotePeerTestTransports (0), 86 m_RemoteVersion (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), 87 m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0), 88 m_IsDataReceived (false), m_RTT (SSU2_UNKNOWN_RTT), 89 m_MsgLocalExpirationTimeout (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX), 90 m_MsgLocalSemiExpirationTimeout (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX / 2), 91 m_WindowSize (SSU2_MIN_WINDOW_SIZE), 92 m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0),m_ConnectTimer (server.GetService ()), 93 m_TerminationReason (eSSU2TerminationReasonNormalClose), 94 m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32), // min size 95 m_LastResendTime (0), m_LastResendAttemptTime (0), m_NumRanges (0) 96 { 97 if (noise) 98 m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); 99 if (in_RemoteRouter && m_Address) 100 { 101 // outgoing 102 if (noise) 103 InitNoiseXKState1 (*m_NoiseState, m_Address->s); 104 m_RemoteEndpoint = boost::asio::ip::udp::endpoint (m_Address->host, m_Address->port); 105 m_RemoteTransports = in_RemoteRouter->GetCompatibleTransports (false); 106 m_RemoteVersion = in_RemoteRouter->GetVersion (); 107 if (in_RemoteRouter->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4; 108 if (in_RemoteRouter->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6; 109 RAND_bytes ((uint8_t *)&m_DestConnID, 8); 110 RAND_bytes ((uint8_t *)&m_SourceConnID, 8); 111 } 112 else 113 { 114 // incoming 115 if (noise) 116 InitNoiseXKState1 (*m_NoiseState, i2p::context.GetSSU2StaticPublicKey ()); 117 } 118 } 119 120 SSU2Session::~SSU2Session () 121 { 122 } 123 124 void SSU2Session::Connect () 125 { 126 if (m_State == eSSU2SessionStateUnknown || m_State == eSSU2SessionStateTokenReceived) 127 { 128 LogPrint(eLogDebug, "SSU2: Connecting to ", GetRemoteEndpoint (), 129 " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ")"); 130 ScheduleConnectTimer (); 131 auto token = m_Server.FindOutgoingToken (m_RemoteEndpoint); 132 if (token) 133 SendSessionRequest (token); 134 else 135 { 136 m_State = eSSU2SessionStateUnknown; 137 SendTokenRequest (); 138 } 139 } 140 } 141 142 void SSU2Session::ScheduleConnectTimer () 143 { 144 m_ConnectTimer.cancel (); 145 m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU2_CONNECT_TIMEOUT)); 146 m_ConnectTimer.async_wait (std::bind (&SSU2Session::HandleConnectTimer, 147 shared_from_this (), std::placeholders::_1)); 148 } 149 150 void SSU2Session::HandleConnectTimer (const boost::system::error_code& ecode) 151 { 152 if (!ecode && m_State != eSSU2SessionStateTerminated) 153 { 154 // timeout expired 155 if (m_State == eSSU2SessionStateIntroduced) // WaitForIntroducer 156 LogPrint (eLogWarning, "SSU2: Session was not introduced after ", SSU2_CONNECT_TIMEOUT, " seconds"); 157 else 158 LogPrint (eLogWarning, "SSU2: Session with ", m_RemoteEndpoint, " was not established after ", SSU2_CONNECT_TIMEOUT, " seconds"); 159 Terminate (); 160 } 161 } 162 163 bool SSU2Session::Introduce (std::shared_ptr<SSU2Session> session, uint32_t relayTag) 164 { 165 // we are Alice 166 if (!session || !relayTag) return false; 167 // find local address to introduce 168 auto localAddress = session->FindLocalAddress (); 169 if (!localAddress || localAddress->host.is_unspecified () || !localAddress->port) 170 { 171 // can't introduce invalid endpoint 172 LogPrint (eLogWarning, "SSU2: Can't find local address to introduce"); 173 return false; 174 } 175 // create nonce 176 uint32_t nonce; 177 RAND_bytes ((uint8_t *)&nonce, 4); 178 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 179 // payload 180 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 181 uint8_t * payload = packet->payload; 182 payload[0] = eSSU2BlkRelayRequest; 183 payload[3] = 0; // flag 184 htobe32buf (payload + 4, nonce); 185 htobe32buf (payload + 8, relayTag); 186 htobe32buf (payload + 12, ts/1000); 187 payload[16] = 2; // ver 188 size_t asz = CreateEndpoint (payload + 18, m_MaxPayloadSize - 18, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port)); 189 if (!asz) return false; 190 payload[17] = asz; 191 packet->payloadSize = asz + 18; 192 SignedData<128> s; 193 s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue 194 s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash 195 s.Insert (session->GetRemoteIdentity ()->GetIdentHash (), 32); // chash 196 s.Insert (payload + 4, 14 + asz); // nonce, relay tag, timestamp, ver, asz and Alice's endpoint 197 s.Sign (i2p::context.GetPrivateKeys (), payload + packet->payloadSize); 198 packet->payloadSize += i2p::context.GetIdentity ()->GetSignatureLen (); 199 htobe16buf (payload + 1, packet->payloadSize - 3); // size 200 packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 201 // send 202 m_RelaySessions.emplace (nonce, std::make_pair (session, ts/1000)); 203 session->m_SourceConnID = htobe64 (((uint64_t)nonce << 32) | nonce); 204 session->m_DestConnID = ~session->m_SourceConnID; 205 m_Server.AddSession (session); 206 int32_t packetNum = SendData (packet->payload, packet->payloadSize); 207 packet->sendTime = ts; 208 m_SentPackets.emplace (packetNum, packet); 209 210 return true; 211 } 212 213 void SSU2Session::WaitForIntroduction () 214 { 215 m_State = eSSU2SessionStateIntroduced; 216 ScheduleConnectTimer (); 217 } 218 219 void SSU2Session::ConnectAfterIntroduction () 220 { 221 if (m_State == eSSU2SessionStateIntroduced) 222 { 223 // we are Alice 224 // keep ConnIDs used for introduction, because Charlie waits for SessionRequest from us 225 m_State = eSSU2SessionStateTokenReceived; 226 // move session to pending outgoing 227 if (m_Server.AddPendingOutgoingSession (shared_from_this ())) 228 { 229 m_Server.RemoveSession (GetConnID ()); 230 // update endpoint in profile because we know it now 231 auto identity = GetRemoteIdentity (); 232 if (identity) 233 { 234 auto profile = i2p::data::GetRouterProfile (identity->GetIdentHash ()); 235 if (profile) profile->SetLastEndpoint (m_RemoteEndpoint); 236 } 237 // connect 238 LogPrint (eLogDebug, "SSU2: Connecting after introduction to ", GetIdentHashBase64()); 239 Connect (); 240 } 241 else 242 { 243 LogPrint (eLogError, "SSU2: Session ", GetConnID (), " is already pending"); 244 m_Server.RequestRemoveSession (GetConnID ()); 245 } 246 } 247 } 248 249 void SSU2Session::SendPeerTest () 250 { 251 // we are Alice 252 uint32_t nonce; 253 RAND_bytes ((uint8_t *)&nonce, 4); 254 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 255 // session for message 5 256 auto session = std::make_shared<SSU2PeerTestSession> (m_Server, 257 htobe64 (((uint64_t)nonce << 32) | nonce), 0); 258 m_Server.AddRequestedPeerTest (nonce, session, ts/1000); 259 m_Server.AddSession (session); 260 // peer test block 261 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 262 packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, nonce); 263 if (packet->payloadSize > 0) 264 { 265 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 266 uint32_t packetNum = SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); 267 packet->sendTime = ts; 268 m_SentPackets.emplace (packetNum, packet); 269 LogPrint (eLogDebug, "SSU2: PeerTest msg=1 sent to ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ())); 270 } 271 } 272 273 void SSU2Session::SendKeepAlive () 274 { 275 if (IsEstablished ()) 276 { 277 uint8_t payload[20]; 278 size_t payloadSize = CreatePaddingBlock (payload, 20, 8); 279 SendData (payload, payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); 280 } 281 } 282 283 void SSU2Session::Terminate () 284 { 285 if (m_State != eSSU2SessionStateTerminated) 286 { 287 m_State = eSSU2SessionStateTerminated; 288 m_ConnectTimer.cancel (); 289 m_OnEstablished = nullptr; 290 if (m_RelayTag) 291 m_Server.RemoveRelay (m_RelayTag); 292 m_Server.AddConnectedRecently (m_RemoteEndpoint, GetLastActivityTimestamp ()); 293 m_SentHandshakePacket.reset (nullptr); 294 m_SessionConfirmedFragment.reset (nullptr); 295 m_PathChallenge.reset (nullptr); 296 if (!m_IntermediateQueue.empty ()) 297 m_SendQueue.splice (m_SendQueue.end (), m_IntermediateQueue); 298 for (auto& it: m_SendQueue) 299 it->Drop (); 300 m_SendQueue.clear (); 301 SetSendQueueSize (0); 302 m_SentPackets.clear (); 303 m_IncompleteMessages.clear (); 304 m_RelaySessions.clear (); 305 m_ReceivedI2NPMsgIDs.clear (); 306 m_Server.RemoveSession (m_SourceConnID); 307 transports.PeerDisconnected (shared_from_this ()); 308 auto remoteIdentity = GetRemoteIdentity (); 309 if (remoteIdentity) 310 LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), 311 " (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated"); 312 else 313 LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), " terminated"); 314 } 315 } 316 317 void SSU2Session::RequestTermination (SSU2TerminationReason reason) 318 { 319 if (m_State == eSSU2SessionStateEstablished || m_State == eSSU2SessionStateClosing) 320 { 321 m_TerminationReason = reason; 322 SendTermination (); 323 m_State = eSSU2SessionStateClosing; 324 } 325 else 326 Done (); 327 } 328 329 void SSU2Session::Established () 330 { 331 m_State = eSSU2SessionStateEstablished; 332 m_EphemeralKeys = nullptr; 333 m_NoiseState.reset (nullptr); 334 m_SessionConfirmedFragment.reset (nullptr); 335 m_SentHandshakePacket.reset (nullptr); 336 m_ConnectTimer.cancel (); 337 SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT); 338 SendQueue (); 339 transports.PeerConnected (shared_from_this ()); 340 341 LogPrint(eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), 342 " (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") established"); 343 if (m_OnEstablished) 344 { 345 m_OnEstablished (); 346 m_OnEstablished = nullptr; 347 } 348 } 349 350 void SSU2Session::Done () 351 { 352 boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::Terminate, shared_from_this ())); 353 } 354 355 void SSU2Session::SendLocalRouterInfo (bool update) 356 { 357 if (update || !IsOutgoing ()) 358 { 359 auto s = shared_from_this (); 360 boost::asio::post (m_Server.GetService (), [s]() 361 { 362 if (!s->IsEstablished ()) return; 363 uint8_t payload[SSU2_MAX_PACKET_SIZE]; 364 size_t payloadSize = s->CreateRouterInfoBlock (payload, s->m_MaxPayloadSize - 32, i2p::context.CopyRouterInfoBuffer ()); 365 if (payloadSize) 366 { 367 if (payloadSize < s->m_MaxPayloadSize) 368 payloadSize += s->CreatePaddingBlock (payload + payloadSize, s->m_MaxPayloadSize - payloadSize); 369 s->SendData (payload, payloadSize); 370 } 371 else 372 s->SendFragmentedMessage (CreateDatabaseStoreMsg ()); 373 }); 374 } 375 376 } 377 378 void SSU2Session::SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) 379 { 380 if (m_State == eSSU2SessionStateTerminated || msgs.empty ()) 381 { 382 msgs.clear (); 383 return; 384 } 385 bool empty = false; 386 { 387 std::lock_guard<std::mutex> l(m_IntermediateQueueMutex); 388 empty = m_IntermediateQueue.empty (); 389 m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs); 390 } 391 if (empty) 392 boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ())); 393 } 394 395 void SSU2Session::PostI2NPMessages () 396 { 397 if (m_State == eSSU2SessionStateTerminated) return; 398 std::list<std::shared_ptr<I2NPMessage> > msgs; 399 { 400 std::lock_guard<std::mutex> l(m_IntermediateQueueMutex); 401 m_IntermediateQueue.swap (msgs); 402 } 403 uint64_t mts = i2p::util::GetMonotonicMicroseconds (); 404 bool isSemiFull = false; 405 if (m_SendQueue.size ()) 406 { 407 int64_t queueLag = (int64_t)mts - (int64_t)m_SendQueue.front ()->GetEnqueueTime (); 408 isSemiFull = queueLag > m_MsgLocalSemiExpirationTimeout; 409 if (isSemiFull) 410 { 411 LogPrint (eLogWarning, "SSU2: Outgoing messages queue to ", 412 i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), 413 " is semi-full (size = ", m_SendQueue.size (), ", lag = ", queueLag / 1000, ", rtt = ", (int)m_RTT, ")"); 414 } 415 } 416 if (isSemiFull) 417 { 418 for (auto it: msgs) 419 { 420 if (it->onDrop) 421 it->Drop (); // drop earlier because we can handle it 422 else 423 { 424 it->SetEnqueueTime (mts); 425 m_SendQueue.push_back (std::move (it)); 426 } 427 } 428 } 429 else 430 { 431 for (auto& it: msgs) it->SetEnqueueTime (mts); 432 m_SendQueue.splice (m_SendQueue.end (), msgs); 433 } 434 if (IsEstablished ()) 435 { 436 SendQueue (); 437 if (m_SendQueue.size () > 0) // windows is full 438 Resend (i2p::util::GetMillisecondsSinceEpoch ()); 439 } 440 SetSendQueueSize (m_SendQueue.size ()); 441 } 442 443 void SSU2Session::MoveSendQueue (std::shared_ptr<SSU2Session> other) 444 { 445 if (!other || m_SendQueue.empty ()) return; 446 std::list<std::shared_ptr<I2NPMessage> > msgs; 447 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 448 for (auto it: m_SendQueue) 449 if (!it->IsExpired (ts)) 450 msgs.push_back (it); 451 else 452 it->Drop (); 453 m_SendQueue.clear (); 454 if (!msgs.empty ()) 455 other->SendI2NPMessages (msgs); 456 } 457 458 bool SSU2Session::SendQueue () 459 { 460 if (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize && IsEstablished ()) 461 { 462 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 463 uint64_t mts = i2p::util::GetMonotonicMicroseconds (); 464 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 465 size_t ackBlockSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); 466 bool ackBlockSent = false; 467 packet->payloadSize += ackBlockSize; 468 while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) 469 { 470 auto msg = m_SendQueue.front (); 471 if (!msg || msg->IsExpired (ts) || msg->GetEnqueueTime() + I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_TRANSIT < mts) 472 { 473 // drop null or expired message 474 if (msg) msg->Drop (); 475 m_SendQueue.pop_front (); 476 continue; 477 } 478 size_t len = msg->GetNTCP2Length () + 3; 479 if (len > m_MaxPayloadSize) // message too long 480 { 481 m_SendQueue.pop_front (); 482 if (SendFragmentedMessage (msg)) 483 ackBlockSent = true; 484 } 485 else if (packet->payloadSize + len <= m_MaxPayloadSize) 486 { 487 m_SendQueue.pop_front (); 488 packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg)); 489 } 490 else 491 { 492 // create new packet and copy ack block 493 auto newPacket = m_Server.GetSentPacketsPool ().AcquireShared (); 494 memcpy (newPacket->payload, packet->payload, ackBlockSize); 495 newPacket->payloadSize = ackBlockSize; 496 // complete current packet 497 if (packet->payloadSize > ackBlockSize) // more than just ack block 498 { 499 ackBlockSent = true; 500 // try to add padding 501 if (packet->payloadSize + 16 < m_MaxPayloadSize) 502 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 503 } 504 else 505 { 506 // reduce ack block 507 if (len + 8 < m_MaxPayloadSize) 508 { 509 // keep Ack block and drop some ranges 510 ackBlockSent = true; 511 packet->payloadSize = m_MaxPayloadSize - len; 512 if (packet->payloadSize & 0x01) packet->payloadSize--; // make it even 513 htobe16buf (packet->payload + 1, packet->payloadSize - 3); // new block size 514 } 515 else // drop Ack block completely 516 packet->payloadSize = 0; 517 // msg fits single packet 518 m_SendQueue.pop_front (); 519 packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg)); 520 } 521 // send right a way 522 uint32_t packetNum = SendData (packet->payload, packet->payloadSize); 523 packet->sendTime = ts; 524 m_SentPackets.emplace (packetNum, packet); 525 packet = newPacket; // just ack block 526 } 527 }; 528 if (packet->payloadSize > ackBlockSize) 529 { 530 // last 531 ackBlockSent = true; 532 if (packet->payloadSize + 16 < m_MaxPayloadSize) 533 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 534 uint32_t packetNum = SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); 535 packet->sendTime = ts; 536 m_SentPackets.emplace (packetNum, packet); 537 } 538 return ackBlockSent; 539 } 540 return false; 541 } 542 543 bool SSU2Session::SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg) 544 { 545 if (!msg) return false; 546 size_t lastFragmentSize = (msg->GetNTCP2Length () + 3 - m_MaxPayloadSize) % (m_MaxPayloadSize - 8); 547 size_t extraSize = m_MaxPayloadSize - lastFragmentSize; 548 bool ackBlockSent = false; 549 uint32_t msgID; 550 memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); 551 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 552 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 553 if (extraSize >= 8) 554 { 555 packet->payloadSize = CreateAckBlock (packet->payload, extraSize); 556 ackBlockSent = true; 557 if (packet->payloadSize + 12 < m_MaxPayloadSize) 558 { 559 uint32_t packetNum = SendData (packet->payload, packet->payloadSize); 560 packet->sendTime = ts; 561 m_SentPackets.emplace (packetNum, packet); 562 packet = m_Server.GetSentPacketsPool ().AcquireShared (); 563 } 564 else 565 extraSize -= packet->payloadSize; 566 } 567 size_t offset = extraSize > 0 ? (m_Server.GetRng ()() % extraSize) : 0; 568 if (offset + packet->payloadSize >= m_MaxPayloadSize) offset = 0; 569 auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - offset - packet->payloadSize, msg); 570 if (!size) return false; 571 extraSize -= offset; 572 packet->payloadSize += size; 573 uint32_t firstPacketNum = SendData (packet->payload, packet->payloadSize); 574 packet->sendTime = ts; 575 m_SentPackets.emplace (firstPacketNum, packet); 576 uint8_t fragmentNum = 0; 577 while (msg->offset < msg->len) 578 { 579 offset = extraSize > 0 ? (m_Server.GetRng ()() % extraSize) : 0; 580 packet = m_Server.GetSentPacketsPool ().AcquireShared (); 581 packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - offset, msg, fragmentNum, msgID); 582 extraSize -= offset; 583 uint8_t flags = 0; 584 if (msg->offset >= msg->len && packet->payloadSize + 16 < m_MaxPayloadSize) // last fragment 585 { 586 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 587 if (fragmentNum > 2) // 3 or more fragments 588 flags |= SSU2_FLAG_IMMEDIATE_ACK_REQUESTED; 589 } 590 uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize, flags); 591 packet->sendTime = ts; 592 m_SentPackets.emplace (followonPacketNum, packet); 593 } 594 return ackBlockSent; 595 } 596 597 size_t SSU2Session::Resend (uint64_t ts) 598 { 599 if (ts + SSU2_RESEND_ATTEMPT_MIN_INTERVAL < m_LastResendAttemptTime) return 0; 600 m_LastResendAttemptTime = ts; 601 // resend handshake packet 602 if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->sendTime + SSU2_HANDSHAKE_RESEND_INTERVAL) 603 { 604 LogPrint (eLogDebug, "SSU2: Resending ", (int)m_State); 605 ResendHandshakePacket (); 606 m_SentHandshakePacket->sendTime = ts; 607 return 0; 608 } 609 // resend data packets 610 if (m_SentPackets.empty ()) return 0; 611 std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > resentPackets; 612 for (auto it = m_SentPackets.begin (); it != m_SentPackets.end (); ) 613 if (ts >= it->second->sendTime + (it->second->numResends + 1) * m_RTO) 614 { 615 if (it->second->numResends > SSU2_MAX_NUM_RESENDS) 616 { 617 LogPrint (eLogInfo, "SSU2: Packet was not Acked after ", it->second->numResends, " attempts. Terminate session"); 618 m_SentPackets.clear (); 619 m_SendQueue.clear (); 620 SetSendQueueSize (0); 621 RequestTermination (eSSU2TerminationReasonTimeout); 622 return resentPackets.size (); 623 } 624 else 625 { 626 uint32_t packetNum = SendData (it->second->payload, it->second->payloadSize, 627 it->second->numResends > 1 ? SSU2_FLAG_IMMEDIATE_ACK_REQUESTED : 0); 628 it->second->numResends++; 629 it->second->sendTime = ts; 630 resentPackets.emplace (packetNum, it->second); 631 it = m_SentPackets.erase (it); 632 } 633 } 634 else 635 it++; 636 if (!resentPackets.empty ()) 637 { 638 m_LastResendTime = ts; 639 m_SentPackets.merge (resentPackets); 640 m_WindowSize >>= 1; // /2 641 if (m_WindowSize < SSU2_MIN_WINDOW_SIZE) m_WindowSize = SSU2_MIN_WINDOW_SIZE; 642 return resentPackets.size (); 643 } 644 return 0; 645 } 646 647 void SSU2Session::ResendHandshakePacket () 648 { 649 if (m_SentHandshakePacket) 650 { 651 m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48, 652 m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint); 653 if (m_SessionConfirmedFragment && m_State == eSSU2SessionStateSessionConfirmedSent) 654 // resend second fragment of SessionConfirmed 655 m_Server.Send (m_SessionConfirmedFragment->header.buf, 16, 656 m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint); 657 } 658 } 659 660 bool SSU2Session::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) 661 { 662 // we are Bob 663 m_SourceConnID = connID; 664 Header header; 665 header.h.connID = connID; 666 memcpy (header.buf + 8, buf + 8, 8); 667 header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12)); 668 switch (header.h.type) 669 { 670 case eSSU2SessionRequest: 671 ProcessSessionRequest (header, buf, len); 672 break; 673 case eSSU2TokenRequest: 674 ProcessTokenRequest (header, buf, len); 675 break; 676 case eSSU2PeerTest: 677 { 678 // TODO: remove later 679 if (len < 32) 680 { 681 LogPrint (eLogWarning, "SSU2: PeerTest message too short ", len); 682 break; 683 } 684 const uint8_t nonce[12] = {0}; 685 uint64_t headerX[2]; 686 m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); 687 LogPrint (eLogWarning, "SSU2: Unexpected PeerTest message SourceConnID=", connID, " DestConnID=", headerX[0]); 688 break; 689 } 690 case eSSU2HolePunch: 691 LogPrint (eLogDebug, "SSU2: Late HolePunch for ", connID); 692 break; 693 default: 694 { 695 LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " from ", m_RemoteEndpoint, " of ", len, " bytes"); 696 return false; 697 } 698 } 699 return true; 700 } 701 702 void SSU2Session::SendSessionRequest (uint64_t token) 703 { 704 // we are Alice 705 m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); 706 m_SentHandshakePacket.reset (new HandshakePacket); 707 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 708 m_SentHandshakePacket->sendTime = ts; 709 710 Header& header = m_SentHandshakePacket->header; 711 uint8_t * headerX = m_SentHandshakePacket->headerX, 712 * payload = m_SentHandshakePacket->payload; 713 // fill packet 714 header.h.connID = m_DestConnID; // dest id 715 RAND_bytes (header.buf + 8, 4); // random packet num 716 header.h.type = eSSU2SessionRequest; 717 header.h.flags[0] = 2; // ver 718 header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID 719 header.h.flags[2] = 0; // flag 720 memcpy (headerX, &m_SourceConnID, 8); // source id 721 memcpy (headerX + 8, &token, 8); // token 722 memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // X 723 // payload 724 payload[0] = eSSU2BlkDateTime; 725 htobe16buf (payload + 1, 4); 726 htobe32buf (payload + 3, (ts + 500)/1000); 727 size_t payloadSize = 7; 728 if (GetRouterStatus () == eRouterStatusFirewalled && m_Address->IsIntroducer ()) 729 { 730 if (!m_Server.IsMaxNumIntroducers (m_RemoteEndpoint.address ().is_v4 ()) || 731 m_Server.GetRng ()() & 0x01) // request tag with probability 1/2 if we have enough introducers 732 { 733 // relay tag request 734 payload[payloadSize] = eSSU2BlkRelayTagRequest; 735 memset (payload + payloadSize + 1, 0, 2); // size = 0 736 payloadSize += 3; 737 } 738 } 739 payloadSize += CreatePaddingBlock (payload + payloadSize, 40 - payloadSize, 1); 740 // KDF for session request 741 m_NoiseState->MixHash ({ {header.buf, 16}, {headerX, 16} }); // h = SHA256(h || header) 742 m_NoiseState->MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk); 743 uint8_t sharedSecret[32]; 744 m_EphemeralKeys->Agree (m_Address->s, sharedSecret); 745 m_NoiseState->MixKey (sharedSecret); 746 // encrypt 747 const uint8_t nonce[12] = {0}; // always 0 748 i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true); 749 payloadSize += 16; 750 header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24)); 751 header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12)); 752 m_Server.ChaCha20 (headerX, 48, m_Address->i, nonce, headerX); 753 m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted payload from Session Request) for SessionCreated 754 m_SentHandshakePacket->payloadSize = payloadSize; 755 // send 756 if (m_State == eSSU2SessionStateTokenReceived || m_Server.AddPendingOutgoingSession (shared_from_this ())) 757 { 758 m_State = eSSU2SessionStateSessionRequestSent; 759 m_HandshakeInterval = ts; 760 m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); 761 } 762 else 763 { 764 LogPrint (eLogWarning, "SSU2: SessionRequest request to ", m_RemoteEndpoint, " already pending"); 765 Terminate (); 766 } 767 } 768 769 void SSU2Session::ProcessSessionRequest (Header& header, uint8_t * buf, size_t len) 770 { 771 // we are Bob 772 if (len < 88) 773 { 774 LogPrint (eLogWarning, "SSU2: SessionRequest message too short ", len); 775 return; 776 } 777 if (header.h.flags[0] != 2) // ver 778 { 779 LogPrint (eLogInfo, "SSU2: SessionRequest protocol version ", header.h.flags[0], " is not supported"); 780 return; 781 } 782 const uint8_t nonce[12] = {0}; 783 uint8_t headerX[48]; 784 m_Server.ChaCha20 (buf + 16, 48, i2p::context.GetSSU2IntroKey (), nonce, headerX); 785 memcpy (&m_DestConnID, headerX, 8); 786 uint64_t token; 787 memcpy (&token, headerX + 8, 8); 788 if (!token || token != m_Server.GetIncomingToken (m_RemoteEndpoint)) 789 { 790 LogPrint (eLogDebug, "SSU2: SessionRequest token mismatch. Retry"); 791 SendRetry (); 792 return; 793 } 794 // KDF for session request 795 m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header) 796 m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || aepk); 797 uint8_t sharedSecret[32]; 798 i2p::context.GetSSU2StaticKeys ().Agree (headerX + 16, sharedSecret); 799 m_NoiseState->MixKey (sharedSecret); 800 // decrypt 801 uint8_t * payload = buf + 64; 802 std::vector<uint8_t> decryptedPayload(len - 80); 803 if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 80, m_NoiseState->m_H, 32, 804 m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false)) 805 { 806 LogPrint (eLogWarning, "SSU2: SessionRequest AEAD verification failed "); 807 return; 808 } 809 m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from Session Request) for SessionCreated 810 // payload 811 m_State = eSSU2SessionStateSessionRequestReceived; 812 HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); 813 814 if (m_TerminationReason == eSSU2TerminationReasonNormalClose) 815 { 816 m_Server.AddSession (shared_from_this ()); 817 SendSessionCreated (headerX + 16); 818 } 819 else 820 SendRetry (); 821 } 822 823 void SSU2Session::SendSessionCreated (const uint8_t * X) 824 { 825 // we are Bob 826 m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); 827 m_SentHandshakePacket.reset (new HandshakePacket); 828 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 829 m_SentHandshakePacket->sendTime = ts; 830 831 uint8_t kh2[32]; 832 i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32) 833 // fill packet 834 Header& header = m_SentHandshakePacket->header; 835 uint8_t * headerX = m_SentHandshakePacket->headerX, 836 * payload = m_SentHandshakePacket->payload; 837 header.h.connID = m_DestConnID; // dest id 838 RAND_bytes (header.buf + 8, 4); // random packet num 839 header.h.type = eSSU2SessionCreated; 840 header.h.flags[0] = 2; // ver 841 header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID 842 header.h.flags[2] = 0; // flag 843 memcpy (headerX, &m_SourceConnID, 8); // source id 844 memset (headerX + 8, 0, 8); // token = 0 845 memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // Y 846 // payload 847 size_t maxPayloadSize = m_MaxPayloadSize - 48; 848 payload[0] = eSSU2BlkDateTime; 849 htobe16buf (payload + 1, 4); 850 htobe32buf (payload + 3, (ts + 500)/1000); 851 size_t payloadSize = 7; 852 payloadSize += CreateAddressBlock (payload + payloadSize, maxPayloadSize - payloadSize, m_RemoteEndpoint); 853 if (m_RelayTag) 854 { 855 payload[payloadSize] = eSSU2BlkRelayTag; 856 htobe16buf (payload + payloadSize + 1, 4); 857 htobe32buf (payload + payloadSize + 3, m_RelayTag); 858 payloadSize += 7; 859 } 860 auto token = m_Server.NewIncomingToken (m_RemoteEndpoint); 861 if (ts + SSU2_TOKEN_EXPIRATION_THRESHOLD > token.second) // not expired? 862 { 863 payload[payloadSize] = eSSU2BlkNewToken; 864 htobe16buf (payload + payloadSize + 1, 12); 865 htobe32buf (payload + payloadSize + 3, token.second - SSU2_TOKEN_EXPIRATION_THRESHOLD); // expires 866 memcpy (payload + payloadSize + 7, &token.first, 8); // token 867 payloadSize += 15; 868 } 869 payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize); 870 // KDF for SessionCreated 871 m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header) 872 m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || bepk); 873 uint8_t sharedSecret[32]; 874 m_EphemeralKeys->Agree (X, sharedSecret); 875 m_NoiseState->MixKey (sharedSecret); 876 // encrypt 877 const uint8_t nonce[12] = {0}; // always zero 878 i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true); 879 payloadSize += 16; 880 m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted Noise payload from Session Created) 881 header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24)); 882 header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12)); 883 m_Server.ChaCha20 (headerX, 48, kh2, nonce, headerX); 884 m_State = eSSU2SessionStateSessionCreatedSent; 885 m_SentHandshakePacket->payloadSize = payloadSize; 886 // send 887 m_HandshakeInterval = ts; 888 m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); 889 } 890 891 bool SSU2Session::ProcessSessionCreated (uint8_t * buf, size_t len) 892 { 893 // we are Alice 894 Header header; 895 memcpy (header.buf, buf, 16); 896 header.ll[0] ^= CreateHeaderMask (m_Address->i, buf + (len - 24)); 897 uint8_t kh2[32]; 898 i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32) 899 header.ll[1] ^= CreateHeaderMask (kh2, buf + (len - 12)); 900 if (header.h.type != eSSU2SessionCreated) 901 // this situation is valid, because it might be Retry with different encryption 902 return false; 903 if (len < 80) 904 { 905 LogPrint (eLogWarning, "SSU2: SessionCreated message too short ", len); 906 return false; 907 } 908 m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval; 909 const uint8_t nonce[12] = {0}; 910 uint8_t headerX[48]; 911 m_Server.ChaCha20 (buf + 16, 48, kh2, nonce, headerX); 912 // KDF for SessionCreated 913 m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header) 914 m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || bepk); 915 uint8_t sharedSecret[32]; 916 m_EphemeralKeys->Agree (headerX + 16, sharedSecret); 917 m_NoiseState->MixKey (sharedSecret); 918 // decrypt 919 uint8_t * payload = buf + 64; 920 std::vector<uint8_t> decryptedPayload(len - 80); 921 if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 80, m_NoiseState->m_H, 32, 922 m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false)) 923 { 924 LogPrint (eLogWarning, "SSU2: SessionCreated AEAD verification failed "); 925 if (GetRemoteIdentity ()) 926 i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key 927 return false; 928 } 929 m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from SessionCreated) for SessionConfirmed 930 // payload 931 m_State = eSSU2SessionStateSessionCreatedReceived; 932 HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); 933 934 m_Server.AddSession (shared_from_this ()); 935 AdjustMaxPayloadSize (); 936 SendSessionConfirmed (headerX + 16); 937 KDFDataPhase (m_KeyDataSend, m_KeyDataReceive); 938 939 return true; 940 } 941 942 void SSU2Session::SendSessionConfirmed (const uint8_t * Y) 943 { 944 // we are Alice 945 m_SentHandshakePacket.reset (new HandshakePacket); 946 m_SentHandshakePacket->sendTime = i2p::util::GetMillisecondsSinceEpoch (); 947 948 uint8_t kh2[32]; 949 i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessionConfirmed", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32) 950 // fill packet 951 Header& header = m_SentHandshakePacket->header; 952 header.h.connID = m_DestConnID; // dest id 953 header.h.packetNum = 0; // always zero 954 header.h.type = eSSU2SessionConfirmed; 955 memset (header.h.flags, 0, 3); 956 header.h.flags[0] = 1; // frag, total fragments always 1 957 // payload 958 size_t maxPayloadSize = m_MaxPayloadSize - 48; // for part 2, 48 is part1 959 uint8_t * payload = m_SentHandshakePacket->payload; 960 size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ()); 961 if (!payloadSize) 962 { 963 // split by two fragments 964 maxPayloadSize += m_MaxPayloadSize; 965 payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ()); 966 header.h.flags[0] = 0x02; // frag 0, total fragments 2 967 // TODO: check if we need more fragments 968 } 969 if (payloadSize < maxPayloadSize) 970 payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize); 971 // KDF for Session Confirmed part 1 972 m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header) 973 // Encrypt part 1 974 uint8_t * part1 = m_SentHandshakePacket->headerX; 975 uint8_t nonce[12]; 976 CreateNonce (1, nonce); // always one 977 i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetSSU2StaticPublicKey (), 32, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, part1, 48, true); 978 m_NoiseState->MixHash (part1, 48); // h = SHA256(h || ciphertext); 979 // KDF for Session Confirmed part 2 980 uint8_t sharedSecret[32]; 981 i2p::context.GetSSU2StaticKeys ().Agree (Y, sharedSecret); 982 m_NoiseState->MixKey (sharedSecret); 983 // Encrypt part2 984 memset (nonce, 0, 12); // always zero 985 i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true); 986 payloadSize += 16; 987 m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || ciphertext); 988 m_SentHandshakePacket->payloadSize = payloadSize; 989 if (header.h.flags[0] > 1) 990 { 991 if (payloadSize > m_MaxPayloadSize - 48) 992 { 993 payloadSize = m_MaxPayloadSize - 48 - (m_Server.GetRng ()() % 16); 994 if (m_SentHandshakePacket->payloadSize - payloadSize < 24) 995 payloadSize -= 24; 996 } 997 else 998 header.h.flags[0] = 1; 999 } 1000 // Encrypt header 1001 header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24)); 1002 header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12)); 1003 m_State = eSSU2SessionStateSessionConfirmedSent; 1004 // send 1005 m_Server.Send (header.buf, 16, part1, 48, payload, payloadSize, m_RemoteEndpoint); 1006 m_SendPacketNum++; 1007 if (m_SentHandshakePacket->payloadSize > payloadSize) 1008 { 1009 // send second fragment 1010 m_SessionConfirmedFragment.reset (new HandshakePacket); 1011 Header& header = m_SessionConfirmedFragment->header; 1012 header.h.connID = m_DestConnID; // dest id 1013 header.h.packetNum = 0; 1014 header.h.type = eSSU2SessionConfirmed; 1015 memset (header.h.flags, 0, 3); 1016 header.h.flags[0] = 0x12; // frag 1, total fragments 2 1017 m_SessionConfirmedFragment->payloadSize = m_SentHandshakePacket->payloadSize - payloadSize; 1018 memcpy (m_SessionConfirmedFragment->payload, m_SentHandshakePacket->payload + payloadSize, m_SessionConfirmedFragment->payloadSize); 1019 m_SentHandshakePacket->payloadSize = payloadSize; 1020 header.ll[0] ^= CreateHeaderMask (m_Address->i, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 24)); 1021 header.ll[1] ^= CreateHeaderMask (kh2, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 12)); 1022 m_Server.Send (header.buf, 16, m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint); 1023 } 1024 } 1025 1026 bool SSU2Session::ProcessSessionConfirmed (uint8_t * buf, size_t len) 1027 { 1028 // we are Bob 1029 Header header; 1030 memcpy (header.buf, buf, 16); 1031 header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24)); 1032 uint8_t kh2[32]; 1033 i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessionConfirmed", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32) 1034 header.ll[1] ^= CreateHeaderMask (kh2, buf + (len - 12)); 1035 if (header.h.type != eSSU2SessionConfirmed) 1036 { 1037 LogPrint (eLogInfo, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2SessionConfirmed); 1038 // TODO: queue up 1039 return true; 1040 } 1041 // packet num must be always zero 1042 if (header.h.packetNum) 1043 { 1044 LogPrint (eLogError, "SSU2: Non zero packet number in SessionConfirmed"); 1045 return false; 1046 } 1047 // check if fragmented 1048 uint8_t numFragments = header.h.flags[0] & 0x0F; 1049 if (numFragments > 1) 1050 { 1051 // fragmented 1052 if (numFragments > 2) 1053 { 1054 LogPrint (eLogError, "SSU2: Too many fragments ", (int)numFragments, " in SessionConfirmed from ", m_RemoteEndpoint); 1055 return false; 1056 } 1057 if (len < 32) 1058 { 1059 LogPrint (eLogWarning, "SSU2: SessionConfirmed fragment too short ", len); 1060 if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr); 1061 return false; 1062 } 1063 if (!(header.h.flags[0] & 0xF0)) 1064 { 1065 // first fragment 1066 if (!m_SessionConfirmedFragment) 1067 { 1068 m_SessionConfirmedFragment.reset (new HandshakePacket); 1069 m_SessionConfirmedFragment->header = header; 1070 memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); 1071 m_SessionConfirmedFragment->payloadSize = len - 16; 1072 return true; // wait for second fragment 1073 } 1074 else if (m_SessionConfirmedFragment->isSecondFragment) 1075 { 1076 // we have second fragment 1077 m_SessionConfirmedFragment->header = header; 1078 memmove (m_SessionConfirmedFragment->payload + (len - 16), m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize); 1079 memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); 1080 m_SessionConfirmedFragment->payloadSize += (len - 16); 1081 m_SessionConfirmedFragment->isSecondFragment = false; 1082 buf = m_SessionConfirmedFragment->payload - 16; 1083 len = m_SessionConfirmedFragment->payloadSize + 16; 1084 } 1085 else 1086 return true; 1087 } 1088 else 1089 { 1090 // second fragment 1091 if (!m_SessionConfirmedFragment) 1092 { 1093 // out of sequence, save it 1094 m_SessionConfirmedFragment.reset (new HandshakePacket); 1095 memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16); 1096 m_SessionConfirmedFragment->payloadSize = len - 16; 1097 m_SessionConfirmedFragment->isSecondFragment = true; 1098 return true; 1099 } 1100 header = m_SessionConfirmedFragment->header; 1101 if (m_SessionConfirmedFragment->payloadSize + (len - 16) <= SSU2_MAX_PACKET_SIZE*2) 1102 { 1103 memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16); 1104 m_SessionConfirmedFragment->payloadSize += (len - 16); 1105 } 1106 buf = m_SessionConfirmedFragment->payload - 16; 1107 len = m_SessionConfirmedFragment->payloadSize + 16; 1108 } 1109 } 1110 if (len < 80) 1111 { 1112 LogPrint (eLogWarning, "SSU2: SessionConfirmed message too short ", len); 1113 if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr); 1114 return false; 1115 } 1116 m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval; 1117 // KDF for Session Confirmed part 1 1118 m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header) 1119 // decrypt part1 1120 uint8_t nonce[12]; 1121 CreateNonce (1, nonce); 1122 uint8_t S[32]; 1123 if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 16, 32, m_NoiseState->m_H, 32, 1124 m_NoiseState->m_CK + 32, nonce, S, 32, false)) 1125 { 1126 LogPrint (eLogWarning, "SSU2: SessionConfirmed part 1 AEAD verification failed "); 1127 if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr); 1128 return false; 1129 } 1130 m_NoiseState->MixHash (buf + 16, 48); // h = SHA256(h || ciphertext); 1131 // KDF for Session Confirmed part 2 and data phase 1132 uint8_t sharedSecret[32]; 1133 m_EphemeralKeys->Agree (S, sharedSecret); 1134 m_NoiseState->MixKey (sharedSecret); 1135 KDFDataPhase (m_KeyDataReceive, m_KeyDataSend); 1136 // decrypt part2 1137 memset (nonce, 0, 12); 1138 uint8_t * payload = buf + 64; 1139 std::vector<uint8_t> decryptedPayload(len - 80); 1140 if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 80, m_NoiseState->m_H, 32, 1141 m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false)) 1142 { 1143 LogPrint (eLogWarning, "SSU2: SessionConfirmed part 2 AEAD verification failed "); 1144 if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr); 1145 return false; 1146 } 1147 m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || ciphertext); 1148 if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr); 1149 // payload 1150 // handle RouterInfo block that must be first 1151 if (decryptedPayload[0] != eSSU2BlkRouterInfo) 1152 { 1153 LogPrint (eLogError, "SSU2: SessionConfirmed unexpected first block type ", (int)decryptedPayload[0]); 1154 return false; 1155 } 1156 size_t riSize = bufbe16toh (decryptedPayload.data () + 1); 1157 if (riSize + 3 > decryptedPayload.size ()) 1158 { 1159 LogPrint (eLogError, "SSU2: SessionConfirmed RouterInfo block is too long ", riSize); 1160 return false; 1161 } 1162 LogPrint (eLogDebug, "SSU2: RouterInfo in SessionConfirmed"); 1163 auto ri = ExtractRouterInfo (decryptedPayload.data () + 3, riSize); 1164 if (!ri) 1165 { 1166 LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block"); 1167 return false; 1168 } 1169 auto ts = i2p::util::GetMillisecondsSinceEpoch(); 1170 if (ts > ri->GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes 1171 { 1172 LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is too old for ", (ts - ri->GetTimestamp ())/1000LL, " seconds"); 1173 return false; 1174 } 1175 if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri->GetTimestamp ()) // 2 minutes 1176 { 1177 LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is from future for ", (ri->GetTimestamp () - ts)/1000LL, " seconds"); 1178 return false; 1179 } 1180 if (ri->GetVersion () < i2p::data::NETDB_MIN_ALLOWED_VERSION && !ri->IsHighBandwidth ()) 1181 { 1182 LogPrint (eLogInfo, "SSU2: Router version ", ri->GetVersion (), " is too old in SessionConfirmed"); 1183 return false; 1184 } 1185 // update RouterInfo in netdb 1186 auto ri1 = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // ri points to one from netdb now 1187 if (!ri1) 1188 { 1189 LogPrint (eLogError, "SSU2: Couldn't update RouterInfo from SessionConfirmed in netdb"); 1190 return false; 1191 } 1192 1193 bool isOlder = false; 1194 if (ri->GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ()) 1195 { 1196 // received RouterInfo is older than one in netdb 1197 isOlder = true; 1198 if (ri->HasProfile ()) 1199 { 1200 auto profile = i2p::data::GetRouterProfile (ri->GetIdentHash ()); // retrieve profile 1201 if (profile && profile->IsDuplicated ()) 1202 return false; 1203 } 1204 } 1205 ri = ri1; 1206 1207 m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address (); 1208 if (!m_Address) 1209 { 1210 LogPrint (eLogError, "SSU2: Address not found in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ())); 1211 return false; 1212 } 1213 if (m_Address->published && m_RemoteEndpoint.address () != m_Address->host && 1214 (!m_RemoteEndpoint.address ().is_v6 () || 1215 memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), m_Address->host.to_v6 ().to_bytes ().data (), 8))) // temporary address 1216 { 1217 if (isOlder) // older router? 1218 i2p::data::UpdateRouterProfile (ri->GetIdentHash (), 1219 [](std::shared_ptr<i2p::data::RouterProfile> profile) 1220 { 1221 if (profile) profile->Duplicated (); // mark router as duplicated in profile 1222 }); 1223 else 1224 LogPrint (eLogInfo, "SSU2: Host mismatch between published address ", m_Address->host, 1225 " and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ())); 1226 return false; 1227 } 1228 if (memcmp (S, m_Address->s, 32)) 1229 { 1230 LogPrint (eLogError, "SSU2: Wrong static key in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ())); 1231 if (m_Address->published) 1232 i2p::transport::transports.AddBan (m_RemoteEndpoint.address ()); 1233 return false; 1234 } 1235 if (!m_Address->published) 1236 { 1237 if (ri->HasProfile ()) 1238 ri->GetProfile ()->SetLastEndpoint (m_RemoteEndpoint); 1239 else 1240 i2p::data::UpdateRouterProfile (ri->GetIdentHash (), 1241 [ep = m_RemoteEndpoint](std::shared_ptr<i2p::data::RouterProfile> profile) 1242 { 1243 if (profile) profile->SetLastEndpoint (ep); 1244 }); 1245 } 1246 SetRemoteIdentity (ri->GetRouterIdentity ()); 1247 AdjustMaxPayloadSize (); 1248 m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now 1249 m_RemoteTransports = ri->GetCompatibleTransports (false); 1250 m_RemotePeerTestTransports = 0; 1251 if (ri->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4; 1252 if (ri->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6; 1253 m_RemoteVersion = ri->GetVersion (); 1254 1255 // handle other blocks 1256 HandlePayload (decryptedPayload.data () + riSize + 3, decryptedPayload.size () - riSize - 3); 1257 1258 Established (); 1259 if (ri->GetCongestion () == i2p::data::RouterInfo::eRejectAll) 1260 { 1261 auto terminationTimeout = GetTerminationTimeout ()/2; 1262 if (terminationTimeout < SSU2_CONNECT_TIMEOUT) terminationTimeout = SSU2_CONNECT_TIMEOUT; 1263 SetTerminationTimeout (terminationTimeout); 1264 } 1265 SendQuickAck (); 1266 1267 return true; 1268 } 1269 1270 void SSU2Session::KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba) 1271 { 1272 uint8_t keydata[64]; 1273 i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) 1274 // ab 1275 i2p::crypto::HKDF (keydata, nullptr, 0, "HKDFSSU2DataKeys", keydata_ab); // keydata_ab = HKDF(keydata, ZEROLEN, "HKDFSSU2DataKeys", 64) 1276 // ba 1277 i2p::crypto::HKDF (keydata + 32, nullptr, 0, "HKDFSSU2DataKeys", keydata_ba); // keydata_ba = HKDF(keydata + 32, ZEROLEN, "HKDFSSU2DataKeys", 64) 1278 } 1279 1280 void SSU2Session::SendTokenRequest () 1281 { 1282 // we are Alice 1283 Header header; 1284 uint8_t h[32], payload[41]; 1285 // fill packet 1286 header.h.connID = m_DestConnID; // dest id 1287 RAND_bytes (header.buf + 8, 4); // random packet num 1288 header.h.type = eSSU2TokenRequest; 1289 header.h.flags[0] = 2; // ver 1290 header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID 1291 header.h.flags[2] = 0; // flag 1292 memcpy (h, header.buf, 16); 1293 memcpy (h + 16, &m_SourceConnID, 8); // source id 1294 memset (h + 24, 0, 8); // zero token 1295 // payload 1296 payload[0] = eSSU2BlkDateTime; 1297 htobe16buf (payload + 1, 4); 1298 htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); 1299 size_t payloadSize = 7; 1300 payloadSize += CreatePaddingBlock (payload + payloadSize, 25 - payloadSize, 1); 1301 // encrypt 1302 uint8_t nonce[12]; 1303 CreateNonce (be32toh (header.h.packetNum), nonce); 1304 i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, m_Address->i, nonce, payload, payloadSize + 16, true); 1305 payloadSize += 16; 1306 header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24)); 1307 header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12)); 1308 memset (nonce, 0, 12); 1309 m_Server.ChaCha20 (h + 16, 16, m_Address->i, nonce, h + 16); 1310 // send 1311 if (m_Server.AddPendingOutgoingSession (shared_from_this ())) 1312 m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint); 1313 else 1314 { 1315 LogPrint (eLogWarning, "SSU2: TokenRequest request to ", m_RemoteEndpoint, " already pending"); 1316 Terminate (); 1317 } 1318 } 1319 1320 void SSU2Session::ProcessTokenRequest (Header& header, uint8_t * buf, size_t len) 1321 { 1322 // we are Bob 1323 if (len < 48) 1324 { 1325 LogPrint (eLogWarning, "SSU2: Incorrect TokenRequest len ", len); 1326 return; 1327 } 1328 uint8_t nonce[12] = {0}; 1329 uint8_t h[32]; 1330 memcpy (h, header.buf, 16); 1331 m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16); 1332 memcpy (&m_DestConnID, h + 16, 8); 1333 // decrypt 1334 CreateNonce (be32toh (header.h.packetNum), nonce); 1335 uint8_t * payload = buf + 32; 1336 if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32, 1337 i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false)) 1338 { 1339 LogPrint (eLogWarning, "SSU2: TokenRequest AEAD verification failed "); 1340 return; 1341 } 1342 // payload 1343 m_State = eSSU2SessionStateTokenRequestReceived; 1344 HandlePayload (payload, len - 48); 1345 SendRetry (); 1346 } 1347 1348 void SSU2Session::SendRetry () 1349 { 1350 // we are Bob 1351 Header header; 1352 uint8_t h[32], payload[72]; 1353 // fill packet 1354 header.h.connID = m_DestConnID; // dest id 1355 RAND_bytes (header.buf + 8, 4); // random packet num 1356 header.h.type = eSSU2Retry; 1357 header.h.flags[0] = 2; // ver 1358 header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID 1359 header.h.flags[2] = 0; // flag 1360 memcpy (h, header.buf, 16); 1361 memcpy (h + 16, &m_SourceConnID, 8); // source id 1362 uint64_t token = 0; 1363 if (m_TerminationReason == eSSU2TerminationReasonNormalClose) 1364 token = m_Server.GetIncomingToken (m_RemoteEndpoint); 1365 memcpy (h + 24, &token, 8); // token 1366 // payload 1367 payload[0] = eSSU2BlkDateTime; 1368 htobe16buf (payload + 1, 4); 1369 htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); 1370 size_t payloadSize = 7; 1371 payloadSize += CreateAddressBlock (payload + payloadSize, 56 - payloadSize, m_RemoteEndpoint); 1372 if (m_TerminationReason != eSSU2TerminationReasonNormalClose) 1373 payloadSize += CreateTerminationBlock (payload + payloadSize, 56 - payloadSize); 1374 payloadSize += CreatePaddingBlock (payload + payloadSize, 56 - payloadSize); 1375 // encrypt 1376 uint8_t nonce[12]; 1377 CreateNonce (be32toh (header.h.packetNum), nonce); 1378 i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, i2p::context.GetSSU2IntroKey (), nonce, payload, payloadSize + 16, true); 1379 payloadSize += 16; 1380 header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24)); 1381 header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 12)); 1382 memset (nonce, 0, 12); 1383 m_Server.ChaCha20 (h + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16); 1384 // send 1385 m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint); 1386 } 1387 1388 bool SSU2Session::ProcessRetry (uint8_t * buf, size_t len) 1389 { 1390 // we are Alice 1391 Header header; 1392 memcpy (header.buf, buf, 16); 1393 header.ll[0] ^= CreateHeaderMask (m_Address->i, buf + (len - 24)); 1394 header.ll[1] ^= CreateHeaderMask (m_Address->i, buf + (len - 12)); 1395 if (header.h.type != eSSU2Retry) 1396 { 1397 LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2Retry); 1398 return false; 1399 } 1400 if (len < 48) 1401 { 1402 LogPrint (eLogWarning, "SSU2: Retry message too short ", len); 1403 return false; 1404 } 1405 uint8_t nonce[12] = {0}; 1406 uint64_t headerX[2]; // sourceConnID, token 1407 m_Server.ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX); 1408 uint64_t token = headerX[1]; 1409 if (token) 1410 m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); 1411 // decrypt and handle payload 1412 uint8_t * payload = buf + 32; 1413 CreateNonce (be32toh (header.h.packetNum), nonce); 1414 uint8_t h[32]; 1415 memcpy (h, header.buf, 16); 1416 memcpy (h + 16, &headerX, 16); 1417 if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32, 1418 m_Address->i, nonce, payload, len - 48, false)) 1419 { 1420 LogPrint (eLogWarning, "SSU2: Retry AEAD verification failed"); 1421 return false; 1422 } 1423 m_State = eSSU2SessionStateTokenReceived; 1424 HandlePayload (payload, len - 48); 1425 if (!token) 1426 { 1427 // we should handle payload even for zero token to handle Datetime block and adjust clock in case of clock skew 1428 LogPrint (eLogWarning, "SSU2: Retry token is zero"); 1429 return false; 1430 } 1431 InitNoiseXKState1 (*m_NoiseState, m_Address->s); // reset Noise TODO: check state 1432 SendSessionRequest (token); 1433 return true; 1434 } 1435 1436 bool SSU2Session::ProcessHolePunch (uint8_t * buf, size_t len) 1437 { 1438 // we are Alice 1439 LogPrint (eLogDebug, "SSU2: HolePunch"); 1440 Header header; 1441 memcpy (header.buf, buf, 16); 1442 header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24)); 1443 header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12)); 1444 if (header.h.type != eSSU2HolePunch) 1445 { 1446 LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2HolePunch); 1447 return false; 1448 } 1449 if (len < 48) 1450 { 1451 LogPrint (eLogWarning, "SSU2: HolePunch message too short ", len); 1452 return false; 1453 } 1454 uint8_t nonce[12] = {0}; 1455 uint64_t headerX[2]; // sourceConnID, token 1456 m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX); 1457 m_DestConnID = headerX[0]; 1458 // decrypt and handle payload 1459 uint8_t * payload = buf + 32; 1460 CreateNonce (be32toh (header.h.packetNum), nonce); 1461 uint8_t h[32]; 1462 memcpy (h, header.buf, 16); 1463 memcpy (h + 16, &headerX, 16); 1464 if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32, 1465 i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false)) 1466 { 1467 LogPrint (eLogWarning, "SSU2: HolePunch AEAD verification failed "); 1468 return false; 1469 } 1470 HandlePayload (payload, len - 48); 1471 m_IsDataReceived = false; 1472 // connect to Charlie 1473 ConnectAfterIntroduction (); 1474 1475 return true; 1476 } 1477 1478 bool SSU2Session::ProcessPeerTest (uint8_t * buf, size_t len) 1479 { 1480 LogPrint (eLogWarning, "SSU2: Unexpected peer test message for this session type"); 1481 return false; 1482 } 1483 1484 uint32_t SSU2Session::SendData (const uint8_t * buf, size_t len, uint8_t flags) 1485 { 1486 if (len < 8) 1487 { 1488 LogPrint (eLogWarning, "SSU2: Data message payload is too short ", (int)len); 1489 return 0; 1490 } 1491 Header header; 1492 header.h.connID = m_DestConnID; 1493 header.h.packetNum = htobe32 (m_SendPacketNum); 1494 header.h.type = eSSU2Data; 1495 memset (header.h.flags, 0, 3); 1496 if (flags) header.h.flags[0] = flags; 1497 uint8_t nonce[12]; 1498 CreateNonce (m_SendPacketNum, nonce); 1499 uint8_t payload[SSU2_MAX_PACKET_SIZE]; 1500 m_Server.AEADChaCha20Poly1305Encrypt (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE); 1501 header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (len - 8)); 1502 header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4)); 1503 m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint); 1504 m_SendPacketNum++; 1505 UpdateNumSentBytes (len + 32); 1506 return m_SendPacketNum - 1; 1507 } 1508 1509 void SSU2Session::ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from) 1510 { 1511 Header header; 1512 header.ll[0] = m_SourceConnID; 1513 memcpy (header.buf + 8, buf + 8, 8); 1514 header.ll[1] ^= CreateHeaderMask (m_KeyDataReceive + 32, buf + (len - 12)); 1515 if (header.h.type != eSSU2Data) 1516 { 1517 LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2Data); 1518 if (IsEstablished ()) 1519 SendQuickAck (); // in case it was SessionConfirmed 1520 else 1521 ResendHandshakePacket (); // assume we receive 1522 return; 1523 } 1524 if (from != m_RemoteEndpoint && !i2p::transport::transports.IsInReservedRange (from.address ()) && 1525 (!m_PathChallenge || from != m_PathChallenge->second)) // path challenge was not sent to this endpoint yet 1526 { 1527 LogPrint (eLogInfo, "SSU2: Remote endpoint update ", m_RemoteEndpoint, "->", from); 1528 SendPathChallenge (from); 1529 } 1530 if (len < 32) 1531 { 1532 LogPrint (eLogWarning, "SSU2: Data message too short ", len); 1533 return; 1534 } 1535 uint8_t payload[SSU2_MAX_PACKET_SIZE]; 1536 size_t payloadSize = len - 32; 1537 uint32_t packetNum = be32toh (header.h.packetNum); 1538 uint8_t nonce[12]; 1539 CreateNonce (packetNum, nonce); 1540 if (!m_Server.AEADChaCha20Poly1305Decrypt (buf + 16, payloadSize, header.buf, 16, 1541 m_KeyDataReceive, nonce, payload, payloadSize)) 1542 { 1543 LogPrint (eLogWarning, "SSU2: Data AEAD verification failed "); 1544 return; 1545 } 1546 UpdateNumReceivedBytes (len); 1547 if (header.h.flags[0] & SSU2_FLAG_IMMEDIATE_ACK_REQUESTED) m_IsDataReceived = true; 1548 if (!packetNum || UpdateReceivePacketNum (packetNum)) 1549 HandlePayload (payload, payloadSize); 1550 } 1551 1552 void SSU2Session::HandlePayload (const uint8_t * buf, size_t len) 1553 { 1554 size_t offset = 0; 1555 while (offset < len) 1556 { 1557 uint8_t blk = buf[offset]; 1558 offset++; 1559 auto size = bufbe16toh (buf + offset); 1560 offset += 2; 1561 LogPrint (eLogDebug, "SSU2: Block type ", (int)blk, " of size ", size); 1562 if (offset + size > len) 1563 { 1564 LogPrint (eLogError, "SSU2: Unexpected block length ", size); 1565 break; 1566 } 1567 switch (blk) 1568 { 1569 case eSSU2BlkDateTime: 1570 LogPrint (eLogDebug, "SSU2: Datetime"); 1571 HandleDateTime (buf + offset, size); 1572 break; 1573 case eSSU2BlkOptions: 1574 LogPrint (eLogDebug, "SSU2: Options"); 1575 break; 1576 case eSSU2BlkRouterInfo: 1577 LogPrint (eLogDebug, "SSU2: RouterInfo"); 1578 HandleRouterInfo (buf + offset, size); 1579 break; 1580 case eSSU2BlkI2NPMessage: 1581 { 1582 LogPrint (eLogDebug, "SSU2: I2NP message"); 1583 auto nextMsg = (buf[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage (); 1584 nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header 1585 memcpy (nextMsg->GetNTCP2Header (), buf + offset, size); 1586 nextMsg->FromNTCP2 (); // SSU2 has the same format as NTCP2 1587 HandleI2NPMsg (std::move (nextMsg)); 1588 m_IsDataReceived = true; 1589 break; 1590 } 1591 case eSSU2BlkFirstFragment: 1592 LogPrint (eLogDebug, "SSU2: First fragment"); 1593 HandleFirstFragment (buf + offset, size); 1594 m_IsDataReceived = true; 1595 break; 1596 case eSSU2BlkFollowOnFragment: 1597 LogPrint (eLogDebug, "SSU2: Follow-on fragment"); 1598 HandleFollowOnFragment (buf + offset, size); 1599 m_IsDataReceived = true; 1600 break; 1601 case eSSU2BlkTermination: 1602 { 1603 if (size >= 9) 1604 { 1605 uint8_t rsn = buf[offset + 8]; // reason 1606 LogPrint (eLogDebug, "SSU2: Termination reason=", (int)rsn); 1607 if (IsEstablished () && rsn != eSSU2TerminationReasonTerminationReceived) 1608 RequestTermination (eSSU2TerminationReasonTerminationReceived); 1609 else if (m_State != eSSU2SessionStateTerminated) 1610 { 1611 if (m_State == eSSU2SessionStateClosing && rsn == eSSU2TerminationReasonTerminationReceived) 1612 m_State = eSSU2SessionStateClosingConfirmed; 1613 Done (); 1614 } 1615 } 1616 else 1617 LogPrint(eLogWarning, "SSU2: Unexpected termination block size ", size); 1618 break; 1619 } 1620 case eSSU2BlkRelayRequest: 1621 LogPrint (eLogDebug, "SSU2: RelayRequest"); 1622 HandleRelayRequest (buf + offset, size); 1623 m_IsDataReceived = true; 1624 break; 1625 case eSSU2BlkRelayResponse: 1626 LogPrint (eLogDebug, "SSU2: RelayResponse"); 1627 HandleRelayResponse (buf + offset, size); 1628 m_IsDataReceived = true; 1629 break; 1630 case eSSU2BlkRelayIntro: 1631 LogPrint (eLogDebug, "SSU2: RelayIntro"); 1632 HandleRelayIntro (buf + offset, size); 1633 m_IsDataReceived = true; 1634 break; 1635 case eSSU2BlkPeerTest: 1636 LogPrint (eLogDebug, "SSU2: PeerTest msg=", (int)buf[offset], " code=", (int)buf[offset+1]); 1637 HandlePeerTest (buf + offset, size); 1638 if (buf[offset] < 5) 1639 m_IsDataReceived = true; 1640 break; 1641 case eSSU2BlkNextNonce: 1642 break; 1643 case eSSU2BlkAck: 1644 LogPrint (eLogDebug, "SSU2: Ack"); 1645 HandleAck (buf + offset, size); 1646 break; 1647 case eSSU2BlkAddress: 1648 LogPrint (eLogDebug, "SSU2: Address"); 1649 HandleAddress (buf + offset, size); 1650 break; 1651 case eSSU2BlkIntroKey: 1652 break; 1653 case eSSU2BlkRelayTagRequest: 1654 LogPrint (eLogDebug, "SSU2: RelayTagRequest"); 1655 if (!m_RelayTag) 1656 { 1657 if (i2p::context.AcceptsTunnels()) 1658 { 1659 auto addr = FindLocalAddress (); 1660 if (addr && addr->IsIntroducer ()) 1661 { 1662 RAND_bytes ((uint8_t *)&m_RelayTag, 4); 1663 m_Server.AddRelay (m_RelayTag, shared_from_this ()); 1664 } 1665 } 1666 } 1667 break; 1668 case eSSU2BlkRelayTag: 1669 LogPrint (eLogDebug, "SSU2: RelayTag"); 1670 m_RelayTag = bufbe32toh (buf + offset); 1671 break; 1672 case eSSU2BlkNewToken: 1673 { 1674 LogPrint (eLogDebug, "SSU2: New token"); 1675 uint64_t token; 1676 memcpy (&token, buf + offset + 4, 8); 1677 m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, bufbe32toh (buf + offset)); 1678 break; 1679 } 1680 case eSSU2BlkPathChallenge: 1681 LogPrint (eLogDebug, "SSU2: Path challenge"); 1682 SendPathResponse (buf + offset, size); 1683 break; 1684 case eSSU2BlkPathResponse: 1685 { 1686 LogPrint (eLogDebug, "SSU2: Path response"); 1687 if (m_PathChallenge) 1688 { 1689 if (buf64toh (buf + offset) == m_PathChallenge->first) 1690 { 1691 m_RemoteEndpoint = m_PathChallenge->second; 1692 m_PathChallenge.reset (nullptr); 1693 } 1694 } 1695 break; 1696 } 1697 case eSSU2BlkFirstPacketNumber: 1698 break; 1699 case eSSU2BlkPadding: 1700 LogPrint (eLogDebug, "SSU2: Padding"); 1701 break; 1702 default: 1703 LogPrint (eLogWarning, "SSU2: Unknown block type ", (int)blk); 1704 } 1705 offset += size; 1706 } 1707 } 1708 1709 void SSU2Session::HandleDateTime (const uint8_t * buf, size_t len) 1710 { 1711 int64_t offset = (int64_t)i2p::util::GetSecondsSinceEpoch () - (int64_t)bufbe32toh (buf); 1712 switch (m_State) 1713 { 1714 case eSSU2SessionStateSessionRequestReceived: 1715 case eSSU2SessionStateTokenRequestReceived: 1716 case eSSU2SessionStateEstablished: 1717 if (std::abs (offset) > SSU2_CLOCK_SKEW) 1718 m_TerminationReason = eSSU2TerminationReasonClockSkew; 1719 break; 1720 case eSSU2SessionStateSessionCreatedReceived: 1721 case eSSU2SessionStateTokenReceived: 1722 if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetTesting ()) || 1723 (m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetTestingV6 ())) 1724 { 1725 if (m_Server.IsSyncClockFromPeers ()) 1726 { 1727 if (std::abs (offset) > SSU2_CLOCK_THRESHOLD) 1728 { 1729 LogPrint (eLogWarning, "SSU2: Time offset ", offset, " from ", m_RemoteEndpoint); 1730 m_Server.AdjustTimeOffset (-offset, GetRemoteIdentity ()); 1731 } 1732 else 1733 m_Server.AdjustTimeOffset (0, nullptr); 1734 } 1735 else if (std::abs (offset) > SSU2_CLOCK_SKEW) 1736 { 1737 LogPrint (eLogError, "SSU2: Clock skew detected ", offset, ". Check your clock"); 1738 i2p::context.SetError (eRouterErrorClockSkew); 1739 } 1740 } 1741 break; 1742 default: ; 1743 }; 1744 } 1745 1746 void SSU2Session::HandleRouterInfo (const uint8_t * buf, size_t len) 1747 { 1748 if (len < 2) return; 1749 // not from SessionConfirmed, we must add it instantly to use in next block 1750 std::shared_ptr<const i2p::data::RouterInfo> newRi; 1751 if (buf[0] & SSU2_ROUTER_INFO_FLAG_GZIP) // compressed? 1752 { 1753 auto ri = ExtractRouterInfo (buf, len); 1754 if (ri) 1755 newRi = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); 1756 } 1757 else // use buffer directly. TODO: handle frag 1758 newRi = i2p::data::netdb.AddRouterInfo (buf + 2, len - 2); 1759 1760 if (newRi) 1761 { 1762 auto remoteIdentity = GetRemoteIdentity (); 1763 if (remoteIdentity && remoteIdentity->GetIdentHash () == newRi->GetIdentHash ()) 1764 { 1765 // peer's RouterInfo update 1766 SetRemoteIdentity (newRi->GetIdentity ()); 1767 auto address = m_RemoteEndpoint.address ().is_v6 () ? newRi->GetSSU2V6Address () : newRi->GetSSU2V4Address (); 1768 if (address) 1769 { 1770 m_Address = address; 1771 if (IsOutgoing () && m_RelayTag && !address->IsIntroducer ()) 1772 m_RelayTag = 0; // not longer introducer 1773 } 1774 } 1775 i2p::transport::transports.UpdatePeerParams (newRi); 1776 } 1777 } 1778 1779 void SSU2Session::HandleAck (const uint8_t * buf, size_t len) 1780 { 1781 if (m_State == eSSU2SessionStateSessionConfirmedSent) 1782 { 1783 Established (); 1784 return; 1785 } 1786 if (m_SentPackets.empty ()) return; 1787 if (len < 5) return; 1788 // acnt 1789 uint32_t ackThrough = bufbe32toh (buf); 1790 uint32_t firstPacketNum = ackThrough > buf[4] ? ackThrough - buf[4] : 0; 1791 HandleAckRange (firstPacketNum, ackThrough, i2p::util::GetMillisecondsSinceEpoch ()); // acnt 1792 // ranges 1793 len -= 5; 1794 if (!len || m_SentPackets.empty ()) return; // don't handle ranges if nothing to acknowledge 1795 const uint8_t * ranges = buf + 5; 1796 while (len > 0 && firstPacketNum && ackThrough - firstPacketNum < SSU2_MAX_NUM_ACK_PACKETS) 1797 { 1798 uint32_t lastPacketNum = firstPacketNum - 1; 1799 if (*ranges > lastPacketNum) break; 1800 lastPacketNum -= *ranges; ranges++; // nacks 1801 if (*ranges > lastPacketNum + 1) break; 1802 firstPacketNum = lastPacketNum - *ranges + 1; ranges++; // acks 1803 len -= 2; 1804 HandleAckRange (firstPacketNum, lastPacketNum, 0); 1805 } 1806 } 1807 1808 void SSU2Session::HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts) 1809 { 1810 if (firstPacketNum > lastPacketNum) return; 1811 auto it = m_SentPackets.begin (); 1812 while (it != m_SentPackets.end () && it->first < firstPacketNum) it++; // find first acked packet 1813 if (it == m_SentPackets.end () || it->first > lastPacketNum) return; // not found 1814 auto it1 = it; 1815 int numPackets = 0; 1816 while (it1 != m_SentPackets.end () && it1->first <= lastPacketNum) 1817 { 1818 if (ts && !it1->second->numResends) 1819 { 1820 if (ts > it1->second->sendTime) 1821 { 1822 auto rtt = ts - it1->second->sendTime; 1823 if (m_RTT != SSU2_UNKNOWN_RTT) 1824 m_RTT = SSU2_RTT_EWMA_ALPHA * rtt + (1.0 - SSU2_RTT_EWMA_ALPHA) * m_RTT; 1825 else 1826 m_RTT = rtt; 1827 m_RTO = m_RTT*SSU2_kAPPA; 1828 m_MsgLocalExpirationTimeout = std::max (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MIN, 1829 std::min (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX, 1830 (unsigned int)(m_RTT * 1000 * I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_FACTOR))); 1831 m_MsgLocalSemiExpirationTimeout = m_MsgLocalExpirationTimeout / 2; 1832 if (m_RTO < SSU2_MIN_RTO) m_RTO = SSU2_MIN_RTO; 1833 if (m_RTO > SSU2_MAX_RTO) m_RTO = SSU2_MAX_RTO; 1834 } 1835 ts = 0; // update RTT one time per range 1836 } 1837 it1++; 1838 numPackets++; 1839 } 1840 m_SentPackets.erase (it, it1); 1841 if (numPackets > 0) 1842 { 1843 m_WindowSize += numPackets; 1844 if (m_WindowSize > SSU2_MAX_WINDOW_SIZE) m_WindowSize = SSU2_MAX_WINDOW_SIZE; 1845 } 1846 } 1847 1848 void SSU2Session::HandleAddress (const uint8_t * buf, size_t len) 1849 { 1850 boost::asio::ip::udp::endpoint ep; 1851 if (ExtractEndpoint (buf, len, ep)) 1852 { 1853 LogPrint (eLogInfo, "SSU2: Our external address is ", ep); 1854 if (!i2p::transport::transports.IsInReservedRange (ep.address ())) 1855 { 1856 i2p::context.UpdateAddress (ep.address ()); 1857 // check our port 1858 bool isV4 = ep.address ().is_v4 (); 1859 if (ep.port () != m_Server.GetPort (isV4)) 1860 { 1861 LogPrint (eLogInfo, "SSU2: Our port ", ep.port (), " received from ", m_RemoteEndpoint, " is different from ", m_Server.GetPort (isV4)); 1862 if (isV4) 1863 { 1864 if (i2p::context.GetTesting ()) 1865 i2p::context.SetError (eRouterErrorSymmetricNAT); 1866 else if (m_State == eSSU2SessionStatePeerTest) 1867 { 1868 i2p::context.SetError (eRouterErrorFullConeNAT); // TODO: Full-Cone NAT detection isn't working. 1869 // i2p::context.PublishNTCP2Address (TCP_PORT, true, true, false, false); // TODO: TCP_PORT to be filled similar to ep.port() 1870 i2p::context.PublishSSU2Address (ep.port(), true, true, false); 1871 } 1872 } 1873 else 1874 { 1875 if (i2p::context.GetTestingV6 ()) 1876 i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT); 1877 else if (m_State == eSSU2SessionStatePeerTest) 1878 { 1879 i2p::context.SetErrorV6 (eRouterErrorFullConeNAT); 1880 // i2p::context.PublishNTCP2Address (TCP_PORT, true, false, true, false); // TODO: TCP_PORT to be filled similar to ep.port() 1881 i2p::context.PublishSSU2Address (ep.port(), true, false, true); 1882 } 1883 } 1884 } 1885 else 1886 { 1887 if (isV4) 1888 { 1889 if (i2p::context.GetError () == eRouterErrorSymmetricNAT) 1890 { 1891 if (m_State == eSSU2SessionStatePeerTest) 1892 i2p::context.SetStatus (eRouterStatusOK); 1893 i2p::context.SetError (eRouterErrorNone); 1894 } 1895 else if (i2p::context.GetError () == eRouterErrorFullConeNAT) 1896 i2p::context.SetError (eRouterErrorNone); 1897 } 1898 else 1899 { 1900 if (i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT) 1901 { 1902 if (m_State == eSSU2SessionStatePeerTest) 1903 i2p::context.SetStatusV6 (eRouterStatusOK); 1904 i2p::context.SetErrorV6 (eRouterErrorNone); 1905 } 1906 else if (i2p::context.GetErrorV6 () == eRouterErrorFullConeNAT) 1907 i2p::context.SetErrorV6 (eRouterErrorNone); 1908 } 1909 } 1910 } 1911 } 1912 } 1913 1914 void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len) 1915 { 1916 auto msg = (buf[0] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage (); 1917 uint32_t msgID; memcpy (&msgID, buf + 1, 4); 1918 // same format as I2NP message block 1919 msg->len = msg->offset + len + 7; 1920 memcpy (msg->GetNTCP2Header (), buf, len); 1921 std::shared_ptr<SSU2IncompleteMessage> m; 1922 bool found = false; 1923 auto it = m_IncompleteMessages.find (msgID); 1924 if (it != m_IncompleteMessages.end ()) 1925 { 1926 found = true; 1927 m = it->second; 1928 } 1929 else 1930 { 1931 m = m_Server.GetIncompleteMessagesPool ().AcquireShared (); 1932 m_IncompleteMessages.emplace (msgID, m); 1933 } 1934 m->msg = msg; 1935 m->nextFragmentNum = 1; 1936 m->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch (); 1937 if (found && m->ConcatOutOfSequenceFragments ()) 1938 { 1939 // we have all follow-on fragments already 1940 m->msg->FromNTCP2 (); 1941 HandleI2NPMsg (std::move (m->msg)); 1942 m_IncompleteMessages.erase (it); 1943 } 1944 } 1945 1946 void SSU2Session::HandleFollowOnFragment (const uint8_t * buf, size_t len) 1947 { 1948 if (len < 5) return; 1949 uint8_t fragmentNum = buf[0] >> 1; 1950 if (!fragmentNum || fragmentNum >= SSU2_MAX_NUM_FRAGMENTS) 1951 { 1952 LogPrint (eLogWarning, "SSU2: Invalid follow-on fragment num ", fragmentNum); 1953 return; 1954 } 1955 bool isLast = buf[0] & 0x01; 1956 uint32_t msgID; memcpy (&msgID, buf + 1, 4); 1957 auto it = m_IncompleteMessages.find (msgID); 1958 if (it != m_IncompleteMessages.end ()) 1959 { 1960 if (fragmentNum < it->second->nextFragmentNum) return; // duplicate 1961 if (it->second->nextFragmentNum == fragmentNum && fragmentNum < SSU2_MAX_NUM_FRAGMENTS && 1962 it->second->msg) 1963 { 1964 // in sequence 1965 it->second->AttachNextFragment (buf + 5, len - 5); 1966 if (isLast) 1967 { 1968 it->second->msg->FromNTCP2 (); 1969 HandleI2NPMsg (std::move (it->second->msg)); 1970 m_IncompleteMessages.erase (it); 1971 } 1972 else 1973 { 1974 if (it->second->ConcatOutOfSequenceFragments ()) 1975 { 1976 HandleI2NPMsg (std::move (it->second->msg)); 1977 m_IncompleteMessages.erase (it); 1978 } 1979 else 1980 it->second->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch (); 1981 } 1982 return; 1983 } 1984 } 1985 else 1986 { 1987 // follow-on fragment before first fragment 1988 auto msg = m_Server.GetIncompleteMessagesPool ().AcquireShared (); 1989 msg->nextFragmentNum = 0; 1990 it = m_IncompleteMessages.emplace (msgID, msg).first; 1991 } 1992 // insert out of sequence fragment 1993 auto fragment = m_Server.GetFragmentsPool ().AcquireShared (); 1994 memcpy (fragment->buf, buf + 5, len -5); 1995 fragment->len = len - 5; 1996 fragment->fragmentNum = fragmentNum; 1997 fragment->isLast = isLast; 1998 it->second->AddOutOfSequenceFragment (fragment); 1999 } 2000 2001 void SSU2Session::HandleRelayRequest (const uint8_t * buf, size_t len) 2002 { 2003 // we are Bob 2004 if (len < 9) return; 2005 auto mts = i2p::util::GetMillisecondsSinceEpoch (); 2006 uint32_t nonce = bufbe32toh (buf + 1); // nonce 2007 uint32_t relayTag = bufbe32toh (buf + 5); // relay tag 2008 auto session = m_Server.FindRelaySession (relayTag); 2009 if (!session) 2010 { 2011 LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found"); 2012 // send relay response back to Alice 2013 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 2014 packet->payloadSize = CreateAckBlock (packet->payload, m_MaxPayloadSize); 2015 packet->payloadSize += CreateRelayResponseBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, 2016 eSSU2RelayResponseCodeBobRelayTagNotFound, nonce, 0, false); 2017 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 2018 uint32_t packetNum = SendData (packet->payload, packet->payloadSize); 2019 if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION) 2020 { 2021 // sometimes Alice doesn't ack this RelayResponse in older versions 2022 packet->sendTime = mts; 2023 m_SentPackets.emplace (packetNum, packet); 2024 } 2025 return; 2026 } 2027 if (session->m_RelaySessions.emplace (nonce, std::make_pair (shared_from_this (), mts/1000)).second) 2028 { 2029 // send relay intro to Charlie 2030 auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI 2031 if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; 2032 if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); 2033 2034 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 2035 packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; 2036 if (!packet->payloadSize && r) 2037 session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); 2038 packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len - 1); 2039 if (packet->payloadSize < m_MaxPayloadSize) 2040 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 2041 uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize); 2042 packet->sendTime = mts; 2043 // Charlie always responds with RelayResponse 2044 session->m_SentPackets.emplace (packetNum, packet); 2045 } 2046 else 2047 LogPrint (eLogInfo, "SSU2: Relay request nonce ", nonce, " already exists. Ignore"); 2048 } 2049 2050 void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts) 2051 { 2052 // we are Charlie 2053 if (len < 47) return; 2054 SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept; 2055 boost::asio::ip::udp::endpoint ep; 2056 std::shared_ptr<const i2p::data::RouterInfo::Address> addr; 2057 auto r = i2p::data::netdb.FindRouter (buf + 1); // Alice 2058 if (r) 2059 { 2060 SignedData<128> s; 2061 s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue 2062 s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash 2063 s.Insert (i2p::context.GetIdentHash (), 32); // chash 2064 s.Insert (buf + 33, 14); // nonce, relay tag, timestamp, ver, asz 2065 uint8_t asz = buf[46]; 2066 if (asz + 47 + r->GetIdentity ()->GetSignatureLen () > len) 2067 { 2068 LogPrint (eLogWarning, "SSU2: Malformed RelayIntro len=", len); 2069 return; 2070 } 2071 s.Insert (buf + 47, asz); // Alice Port, Alice IP 2072 if (s.Verify (r->GetIdentity (), buf + 47 + asz)) 2073 { 2074 // obtain and check endpoint and address for HolePunch 2075 if (ExtractEndpoint (buf + 47, asz, ep)) 2076 { 2077 if (!ep.address ().is_unspecified () && ep.port ()) 2078 { 2079 if (m_Server.IsSupported (ep.address ())) 2080 { 2081 addr = ep.address ().is_v6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address (); 2082 if (!addr) 2083 { 2084 LogPrint (eLogWarning, "SSU2: RelayIntro address for endpoint not found"); 2085 code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; 2086 } 2087 } 2088 else 2089 { 2090 LogPrint (eLogWarning, "SSU2: RelayIntro unsupported address"); 2091 code = eSSU2RelayResponseCodeCharlieUnsupportedAddress; 2092 } 2093 } 2094 else 2095 { 2096 LogPrint (eLogWarning, "SSU2: RelayIntro invalid endpoint"); 2097 code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; 2098 } 2099 } 2100 else 2101 { 2102 LogPrint (eLogWarning, "SSU2: RelayIntro can't extract endpoint"); 2103 code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; 2104 } 2105 } 2106 else 2107 { 2108 LogPrint (eLogWarning, "SSU2: RelayIntro signature verification failed"); 2109 code = eSSU2RelayResponseCodeCharlieSignatureFailure; 2110 } 2111 } 2112 else if (!attempts) 2113 { 2114 // RouterInfo might come in the next packet, try again 2115 auto vec = std::make_shared<std::vector<uint8_t> >(len); 2116 memcpy (vec->data (), buf, len); 2117 auto s = shared_from_this (); 2118 boost::asio::post (m_Server.GetService (), [s, vec, attempts]() 2119 { 2120 LogPrint (eLogDebug, "SSU2: RelayIntro attempt ", attempts + 1); 2121 s->HandleRelayIntro (vec->data (), vec->size (), attempts + 1); 2122 }); 2123 return; 2124 } 2125 else 2126 { 2127 LogPrint (eLogWarning, "SSU2: RelayIntro unknown router to introduce"); 2128 code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; 2129 } 2130 // send relay response to Bob 2131 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 2132 uint32_t nonce = bufbe32toh (buf + 33); 2133 packet->payloadSize = CreateRelayResponseBlock (packet->payload, m_MaxPayloadSize, 2134 code, nonce, m_Server.GetIncomingToken (ep), ep.address ().is_v4 ()); 2135 if (code == eSSU2RelayResponseCodeAccept && addr) 2136 { 2137 // send HolePunch 2138 auto holePunchSession = std::make_shared<SSU2HolePunchSession>(m_Server, nonce, ep, addr); 2139 if (m_Server.AddSession (holePunchSession)) 2140 holePunchSession->SendHolePunch (packet->payload, packet->payloadSize); // relay response block 2141 else 2142 { 2143 LogPrint (eLogInfo, "SSU2: Relay intro nonce ", nonce, " already exists. Ignore"); 2144 return; 2145 } 2146 } 2147 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 2148 uint32_t packetNum = SendData (packet->payload, packet->payloadSize); 2149 if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION) 2150 { 2151 // sometimes Bob doesn't ack this RelayResponse in older versions 2152 packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); 2153 m_SentPackets.emplace (packetNum, packet); 2154 } 2155 } 2156 2157 void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len) 2158 { 2159 if (len < 6) return; 2160 uint32_t nonce = bufbe32toh (buf + 2); 2161 if (m_State == eSSU2SessionStateIntroduced) 2162 { 2163 // HolePunch from Charlie 2164 // TODO: verify address and signature 2165 // verify nonce 2166 if (~htobe64 (((uint64_t)nonce << 32) | nonce) != m_DestConnID) 2167 LogPrint (eLogWarning, "SSU2: Relay response nonce mismatch ", nonce, " connID=", m_DestConnID); 2168 if (len >= 8) 2169 { 2170 // new token 2171 uint64_t token; 2172 memcpy (&token, buf + len - 8, 8); 2173 m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); 2174 } 2175 return; 2176 } 2177 auto it = m_RelaySessions.find (nonce); 2178 if (it != m_RelaySessions.end ()) 2179 { 2180 auto relaySession = it->second.first; 2181 m_RelaySessions.erase (it); 2182 if (relaySession && relaySession->IsEstablished ()) 2183 { 2184 // we are Bob, message from Charlie 2185 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 2186 uint8_t * payload = packet->payload; 2187 payload[0] = eSSU2BlkRelayResponse; 2188 htobe16buf (payload + 1, len); 2189 memcpy (payload + 3, buf, len); // forward to Alice as is 2190 packet->payloadSize = len + 3; 2191 packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 2192 uint32_t packetNum = relaySession->SendData (packet->payload, packet->payloadSize); 2193 if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION) 2194 { 2195 // sometimes Alice doesn't ack this RelayResponse in older versions 2196 packet->sendTime = i2p::util::GetMillisecondsSinceEpoch (); 2197 relaySession->m_SentPackets.emplace (packetNum, packet); 2198 } 2199 } 2200 else 2201 { 2202 // we are Alice, message from Bob 2203 if (!buf[1]) // status code accepted? 2204 { 2205 // verify signature 2206 uint8_t csz = (len >= 12) ? buf[11] : 0; 2207 if (csz + 12 + relaySession->GetRemoteIdentity ()->GetSignatureLen () > len) 2208 { 2209 LogPrint (eLogWarning, "SSU2: Malformed RelayResponse len=", len); 2210 relaySession->Done (); 2211 return; 2212 } 2213 SignedData<128> s; 2214 s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue 2215 s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash 2216 s.Insert (buf + 2, 10 + csz); // nonce, timestamp, ver, csz and Charlie's endpoint 2217 if (s.Verify (relaySession->GetRemoteIdentity (), buf + 12 + csz)) 2218 { 2219 if (relaySession->m_State == eSSU2SessionStateIntroduced) // HolePunch not received yet 2220 { 2221 // update Charlie's endpoint 2222 if (ExtractEndpoint (buf + 12, csz, relaySession->m_RemoteEndpoint)) 2223 { 2224 // update token 2225 uint64_t token; 2226 memcpy (&token, buf + len - 8, 8); 2227 m_Server.UpdateOutgoingToken (relaySession->m_RemoteEndpoint, 2228 token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT); 2229 // connect to Charlie, HolePunch will be ignored 2230 relaySession->ConnectAfterIntroduction (); 2231 } 2232 else 2233 LogPrint (eLogWarning, "SSU2: RelayResponse can't extract endpoint"); 2234 } 2235 } 2236 else 2237 { 2238 LogPrint (eLogWarning, "SSU2: RelayResponse signature verification failed"); 2239 relaySession->Done (); 2240 } 2241 } 2242 else 2243 { 2244 LogPrint (eLogInfo, "SSU2: RelayResponse status code=", (int)buf[1], " nonce=", bufbe32toh (buf + 2)); 2245 relaySession->Done (); 2246 } 2247 } 2248 } 2249 else 2250 LogPrint (eLogDebug, "SSU2: RelayResponse unknown nonce ", bufbe32toh (buf + 2)); 2251 } 2252 2253 void SSU2Session::HandlePeerTest (const uint8_t * buf, size_t len) 2254 { 2255 // msgs 1-4 2256 if (len < 3) return; 2257 uint8_t msg = buf[0]; 2258 size_t offset = 3; // points to signed data 2259 if (msg == 2 || msg == 4) offset += 32; // hash is presented for msg 2 and 4 only 2260 if (len < offset + 5) return; 2261 auto ts = i2p::util::GetMillisecondsSinceEpoch (); 2262 uint32_t nonce = bufbe32toh (buf + offset + 1); 2263 switch (msg) // msg 2264 { 2265 case 1: // Bob from Alice 2266 { 2267 auto session = m_Server.GetRandomPeerTestSession ((buf[12] == 6) ? i2p::data::RouterInfo::eSSU2V4 : i2p::data::RouterInfo::eSSU2V6, 2268 GetRemoteIdentity ()->GetIdentHash ()); 2269 if (session) // session with Charlie 2270 { 2271 if (m_Server.AddPeerTest (nonce, shared_from_this (), ts/1000)) 2272 { 2273 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 2274 // Alice's RouterInfo 2275 auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); 2276 if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; 2277 packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; 2278 if (!packet->payloadSize && r) 2279 session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); 2280 if (packet->payloadSize + len + 48 > m_MaxPayloadSize) 2281 { 2282 // doesn't fit one message, send RouterInfo in separate message 2283 uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); 2284 packet->sendTime = ts; 2285 session->m_SentPackets.emplace (packetNum, packet); 2286 packet = m_Server.GetSentPacketsPool ().AcquireShared (); // new packet 2287 } 2288 // PeerTest to Charlie 2289 packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, 2, 2290 eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); 2291 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 2292 uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED); 2293 packet->sendTime = ts; 2294 session->m_SentPackets.emplace (packetNum, packet); 2295 } 2296 else 2297 LogPrint (eLogInfo, "SSU2: Peer test 1 nonce ", nonce, " already exists. Ignored"); 2298 } 2299 else 2300 { 2301 // Charlie not found, send error back to Alice 2302 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 2303 uint8_t zeroHash[32] = {0}; 2304 packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, 4, 2305 eSSU2PeerTestCodeBobNoCharlieAvailable, zeroHash, buf + offset, len - offset); 2306 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 2307 uint32_t packetNum = SendData (packet->payload, packet->payloadSize); 2308 packet->sendTime = ts; 2309 m_SentPackets.emplace (packetNum, packet); 2310 } 2311 break; 2312 } 2313 case 2: // Charlie from Bob 2314 { 2315 // sign with Charlie's key 2316 if (len < offset + 9) return; 2317 uint8_t asz = buf[offset + 9]; 2318 size_t l = asz + 10 + i2p::context.GetIdentity ()->GetSignatureLen (); 2319 if (len < offset + l) return; 2320 std::vector<uint8_t> newSignedData (l); 2321 memcpy (newSignedData.data (), buf + offset, asz + 10); 2322 SignedData<128> s; 2323 s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue 2324 s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash 2325 s.Insert (buf + 3, 32); // ahash 2326 s.Insert (newSignedData.data (), asz + 10); // ver, nonce, ts, asz, Alice's endpoint 2327 s.Sign (i2p::context.GetPrivateKeys (), newSignedData.data () + 10 + asz); 2328 // send response (msg 3) back and msg 5 if accepted 2329 SSU2PeerTestCode code = eSSU2PeerTestCodeAccept; 2330 auto r = i2p::data::netdb.FindRouter (buf + 3); // find Alice 2331 if (r) 2332 { 2333 size_t signatureLen = r->GetIdentity ()->GetSignatureLen (); 2334 if (len >= offset + asz + 10 + signatureLen) 2335 { 2336 s.Reset (); 2337 s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue 2338 s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash 2339 s.Insert (buf + offset, asz + 10); // signed data 2340 if (s.Verify (r->GetIdentity (), buf + offset + asz + 10)) 2341 { 2342 if (!m_Server.FindSession (r->GetIdentity ()->GetIdentHash ())) 2343 { 2344 boost::asio::ip::udp::endpoint ep; 2345 std::shared_ptr<const i2p::data::RouterInfo::Address> addr; 2346 if (ExtractEndpoint (buf + offset + 10, asz, ep) && !ep.address ().is_unspecified () && ep.port ()) 2347 addr = r->GetSSU2Address (ep.address ().is_v4 ()); 2348 if (addr && m_Server.IsSupported (ep.address ()) && 2349 i2p::context.GetRouterInfo ().IsSSU2PeerTesting (ep.address ().is_v4 ())) 2350 { 2351 if (!m_Server.IsConnectedRecently (ep)) // no alive hole punch 2352 { 2353 // send msg 5 to Alice 2354 auto session = std::make_shared<SSU2PeerTestSession> (m_Server, 2355 0, htobe64 (((uint64_t)nonce << 32) | nonce)); 2356 session->m_RemoteEndpoint = ep; // might be different 2357 m_Server.AddSession (session); 2358 session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr); 2359 } 2360 else 2361 code = eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected; 2362 } 2363 else 2364 code = eSSU2PeerTestCodeCharlieUnsupportedAddress; 2365 } 2366 else 2367 code = eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected; 2368 } 2369 else 2370 code = eSSU2PeerTestCodeCharlieSignatureFailure; 2371 } 2372 else // maformed message 2373 code = eSSU2PeerTestCodeCharlieReasonUnspecified; 2374 } 2375 else 2376 code = eSSU2PeerTestCodeCharlieAliceIsUnknown; 2377 // send msg 3 back to Bob 2378 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 2379 packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, 3, 2380 code, nullptr, newSignedData.data (), newSignedData.size ()); 2381 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 2382 uint32_t packetNum = SendData (packet->payload, packet->payloadSize); 2383 packet->sendTime = ts; 2384 m_SentPackets.emplace (packetNum, packet); 2385 break; 2386 } 2387 case 3: // Bob from Charlie 2388 { 2389 auto aliceSession = m_Server.GetPeerTest (nonce); 2390 if (aliceSession && aliceSession->IsEstablished ()) 2391 { 2392 auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); 2393 // Charlie's RouterInfo 2394 auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); 2395 if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; 2396 packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; 2397 if (!packet->payloadSize && r) 2398 aliceSession->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); 2399 if (packet->payloadSize + len + 16 > m_MaxPayloadSize) 2400 { 2401 // doesn't fit one message, send RouterInfo in separate message 2402 uint32_t packetNum = aliceSession->SendData (packet->payload, packet->payloadSize); 2403 packet->sendTime = ts; 2404 aliceSession->m_SentPackets.emplace (packetNum, packet); 2405 packet = m_Server.GetSentPacketsPool ().AcquireShared (); 2406 } 2407 // PeerTest to Alice 2408 packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize, 4, 2409 (SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); 2410 if (packet->payloadSize < m_MaxPayloadSize) 2411 packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize); 2412 uint32_t packetNum = aliceSession->SendData (packet->payload, packet->payloadSize); 2413 packet->sendTime = ts; 2414 aliceSession->m_SentPackets.emplace (packetNum, packet); 2415 } 2416 else 2417 LogPrint (eLogDebug, "SSU2: Unknown peer test 3 nonce ", nonce); 2418 break; 2419 } 2420 case 4: // Alice from Bob 2421 { 2422 auto session = m_Server.GetRequestedPeerTest (nonce); 2423 if (session) 2424 { 2425 if (buf[1] == eSSU2PeerTestCodeAccept) 2426 { 2427 if (GetRouterStatus () == eRouterStatusUnknown) 2428 SetTestingState (true); 2429 auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie 2430 if (r && len >= offset + 9) 2431 { 2432 uint8_t asz = buf[offset + 9]; 2433 if (len < offset + asz + 10 + r->GetIdentity ()->GetSignatureLen ()) 2434 { 2435 LogPrint (eLogWarning, "Malformed PeerTest 4 len=", len); 2436 session->Done (); 2437 return; 2438 } 2439 SignedData<128> s; 2440 s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue 2441 s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash 2442 s.Insert (i2p::context.GetIdentity ()->GetIdentHash (), 32); // ahash 2443 s.Insert (buf + offset, asz + 10); // ver, nonce, ts, asz, Alice's endpoint 2444 if (s.Verify (r->GetIdentity (), buf + offset + asz + 10)) 2445 { 2446 session->SetRemoteIdentity (r->GetIdentity ()); 2447 auto addr = r->GetSSU2Address (m_Address->IsV4 ()); 2448 if (addr && addr->IsPeerTesting ()) 2449 { 2450 if (session->GetMsgNumReceived () >= 5) 2451 { 2452 // msg 5 already received and we know remote endpoint 2453 if (session->GetMsgNumReceived () == 5) 2454 { 2455 if (!session->IsConnectedRecently ()) 2456 SetRouterStatus (eRouterStatusOK); 2457 // send msg 6 immeditely 2458 session->SendPeerTest (6, buf + offset, len - offset, addr); 2459 } 2460 else 2461 LogPrint (eLogWarning, "SSU2: PeerTest 4 received, but msg ", session->GetMsgNumReceived (), " already received"); 2462 } 2463 else 2464 { 2465 session->m_Address = addr; 2466 if (GetTestingState ()) 2467 { 2468 // schedule msg 6 with delay 2469 if (!addr->host.is_unspecified () && addr->port) 2470 { 2471 session->SetRemoteEndpoint (boost::asio::ip::udp::endpoint (addr->host, addr->port)); 2472 session->SendPeerTest (6, buf + offset, len - offset, addr, true); 2473 } 2474 SetTestingState (false); 2475 if (i2p::context.GetError () == eRouterErrorFullConeNAT) 2476 SetRouterStatus (eRouterStatusOK); 2477 else if (GetRouterStatus () != eRouterStatusFirewalled && addr->IsPeerTesting ()) 2478 { 2479 SetRouterStatus (eRouterStatusFirewalled); 2480 session->SetStatusChanged (); 2481 if (m_Address->IsV4 ()) 2482 m_Server.RescheduleIntroducersUpdateTimer (); 2483 else 2484 m_Server.RescheduleIntroducersUpdateTimerV6 (); 2485 } 2486 } 2487 } 2488 LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), 2489 " with information about ", i2p::data::GetIdentHashAbbreviation (i2p::data::IdentHash (buf + 3))); 2490 } 2491 else 2492 { 2493 LogPrint (eLogWarning, "SSU2: Peer test 4 address not found or not supported"); 2494 session->Done (); 2495 } 2496 } 2497 else 2498 { 2499 LogPrint (eLogWarning, "SSU2: Peer test 4 signature verification failed"); 2500 session->Done (); 2501 } 2502 } 2503 else 2504 { 2505 LogPrint (eLogWarning, "SSU2: Peer test 4 router not found"); 2506 session->Done (); 2507 } 2508 } 2509 else 2510 { 2511 LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ", 2512 i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3))); 2513 if (GetTestingState () && GetRouterStatus () != eRouterStatusFirewalled) 2514 SetRouterStatus (eRouterStatusUnknown); 2515 session->Done (); 2516 } 2517 } 2518 else 2519 LogPrint (eLogDebug, "SSU2: Unknown peer test 4 nonce ", nonce); 2520 break; 2521 } 2522 default: 2523 LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", buf[0]); 2524 } 2525 } 2526 2527 void SSU2Session::HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg) 2528 { 2529 if (!msg) return; 2530 uint32_t msgID = msg->GetMsgID (); 2531 if (!msg->IsExpired ()) 2532 { 2533 // m_LastActivityTimestamp is updated in ProcessData before 2534 if (m_ReceivedI2NPMsgIDs.emplace (msgID, (uint32_t)GetLastActivityTimestamp ()).second) 2535 m_Handler.PutNextMessage (std::move (msg)); 2536 else 2537 LogPrint (eLogDebug, "SSU2: Message ", msgID, " already received"); 2538 } 2539 else 2540 LogPrint (eLogDebug, "SSU2: Message ", msgID, " expired"); 2541 } 2542 2543 bool SSU2Session::ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep) 2544 { 2545 if (size < 2) return false; 2546 int port = bufbe16toh (buf); 2547 if (size == 6) 2548 { 2549 boost::asio::ip::address_v4::bytes_type bytes; 2550 memcpy (bytes.data (), buf + 2, 4); 2551 ep = boost::asio::ip::udp::endpoint (boost::asio::ip::address_v4 (bytes), port); 2552 } 2553 else if (size == 18) 2554 { 2555 boost::asio::ip::address_v6::bytes_type bytes; 2556 memcpy (bytes.data (), buf + 2, 16); 2557 ep = boost::asio::ip::udp::endpoint (boost::asio::ip::address_v6 (bytes), port); 2558 } 2559 else 2560 { 2561 LogPrint (eLogWarning, "SSU2: Address size ", int(size), " is not supported"); 2562 return false; 2563 } 2564 return true; 2565 } 2566 2567 size_t SSU2Session::CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep) 2568 { 2569 if (len < 6) return 0; 2570 htobe16buf (buf, ep.port ()); 2571 size_t size = 0; 2572 if (ep.address ().is_v4 ()) 2573 { 2574 memcpy (buf + 2, ep.address ().to_v4 ().to_bytes ().data (), 4); 2575 size = 6; 2576 } 2577 else if (ep.address ().is_v6 ()) 2578 { 2579 if (len < 18) return 0; 2580 memcpy (buf + 2, ep.address ().to_v6 ().to_bytes ().data (), 16); 2581 size = 18; 2582 } 2583 else 2584 { 2585 LogPrint (eLogWarning, "SSU2: Wrong address type ", ep.address ().to_string ()); 2586 return 0; 2587 } 2588 return size; 2589 } 2590 2591 std::shared_ptr<const i2p::data::RouterInfo::Address> SSU2Session::FindLocalAddress () const 2592 { 2593 if (m_Address) 2594 return i2p::context.GetRouterInfo ().GetSSU2Address (m_Address->IsV4 ()); 2595 else if (!m_RemoteEndpoint.address ().is_unspecified ()) 2596 return i2p::context.GetRouterInfo ().GetSSU2Address (m_RemoteEndpoint.address ().is_v4 ()); 2597 return nullptr; 2598 } 2599 2600 void SSU2Session::AdjustMaxPayloadSize (size_t maxMtu) 2601 { 2602 auto addr = FindLocalAddress (); 2603 if (addr && addr->ssu) 2604 { 2605 int mtu = addr->ssu->mtu; 2606 if (!mtu && addr->IsV4 ()) mtu = SSU2_MAX_PACKET_SIZE; 2607 if (mtu > (int)maxMtu) mtu = maxMtu; 2608 if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu)) 2609 mtu = m_Address->ssu->mtu; 2610 if (mtu) 2611 { 2612 if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE; 2613 if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE; 2614 m_MaxPayloadSize = mtu - (addr->IsV6 () ? IPV6_HEADER_SIZE: IPV4_HEADER_SIZE) - UDP_HEADER_SIZE - 32; 2615 LogPrint (eLogDebug, "SSU2: Session MTU=", mtu, ", max payload size=", m_MaxPayloadSize); 2616 } 2617 } 2618 } 2619 2620 RouterStatus SSU2Session::GetRouterStatus () const 2621 { 2622 if (m_Address) 2623 { 2624 if (m_Address->IsV4 ()) 2625 return i2p::context.GetStatus (); 2626 if (m_Address->IsV6 ()) 2627 return i2p::context.GetStatusV6 (); 2628 } 2629 return eRouterStatusUnknown; 2630 } 2631 2632 void SSU2Session::SetRouterStatus (RouterStatus status) const 2633 { 2634 if (m_Address) 2635 { 2636 if (m_Address->IsV4 ()) 2637 i2p::context.SetStatus (status); 2638 else if (m_Address->IsV6 ()) 2639 i2p::context.SetStatusV6 (status); 2640 } 2641 } 2642 2643 bool SSU2Session::GetTestingState () const 2644 { 2645 if (m_Address) 2646 { 2647 if (m_Address->IsV4 ()) 2648 return i2p::context.GetTesting (); 2649 if (m_Address->IsV6 ()) 2650 return i2p::context.GetTestingV6 (); 2651 } 2652 return false; 2653 } 2654 2655 void SSU2Session::SetTestingState (bool testing) const 2656 { 2657 if (m_Address) 2658 { 2659 if (m_Address->IsV4 ()) 2660 i2p::context.SetTesting (testing); 2661 else if (m_Address->IsV6 ()) 2662 i2p::context.SetTestingV6 (testing); 2663 } 2664 if (!testing) 2665 m_Server.AdjustTimeOffset (0, nullptr); // reset time offset when testing is over 2666 } 2667 2668 size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep) 2669 { 2670 if (len < 9) return 0; 2671 buf[0] = eSSU2BlkAddress; 2672 size_t size = CreateEndpoint (buf + 3, len - 3, ep); 2673 if (!size) return 0; 2674 htobe16buf (buf + 1, size); 2675 return size + 3; 2676 } 2677 2678 size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r) 2679 { 2680 if (!r || len < 5) return 0; 2681 return CreateRouterInfoBlock (buf, len, r->GetSharedBuffer ()); 2682 } 2683 2684 size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo::Buffer> riBuffer) 2685 { 2686 if (!riBuffer || len < 5) return 0; 2687 buf[0] = eSSU2BlkRouterInfo; 2688 size_t size = riBuffer->GetBufferLen (); 2689 if (size + 5 < len) 2690 { 2691 memcpy (buf + 5, riBuffer->data (), size); 2692 buf[3] = 0; // flag 2693 } 2694 else 2695 { 2696 i2p::data::GzipDeflator deflator; 2697 deflator.SetCompressionLevel (9); 2698 size = deflator.Deflate (riBuffer->data (), riBuffer->GetBufferLen (), buf + 5, len - 5); 2699 if (!size) return 0; // doesn't fit 2700 buf[3] = SSU2_ROUTER_INFO_FLAG_GZIP; // flag 2701 } 2702 htobe16buf (buf + 1, size + 2); // size 2703 buf[4] = 1; // frag 2704 return size + 5; 2705 } 2706 2707 2708 size_t SSU2Session::CreateAckBlock (uint8_t * buf, size_t len) 2709 { 2710 if (len < 8) return 0; 2711 buf[0] = eSSU2BlkAck; 2712 uint32_t ackThrough = m_OutOfSequencePackets.empty () ? m_ReceivePacketNum : *m_OutOfSequencePackets.rbegin (); 2713 htobe32buf (buf + 3, ackThrough); // Ack Through 2714 uint16_t acnt = 0; 2715 if (ackThrough) 2716 { 2717 if (m_OutOfSequencePackets.empty ()) 2718 { 2719 acnt = std::min ((int)ackThrough, SSU2_MAX_NUM_ACNT); // no gaps 2720 m_NumRanges = 0; 2721 } 2722 else 2723 { 2724 auto it = m_OutOfSequencePackets.rbegin (); it++; // prev packet num 2725 while (it != m_OutOfSequencePackets.rend () && *it == ackThrough - acnt - 1) 2726 { 2727 acnt++; 2728 if (acnt >= SSU2_MAX_NUM_ACK_PACKETS) 2729 break; 2730 else 2731 it++; 2732 } 2733 // ranges 2734 if (!m_NumRanges) 2735 { 2736 int maxNumRanges = (len - 8) >> 1; 2737 if (maxNumRanges > SSU2_MAX_NUM_ACK_RANGES) maxNumRanges = SSU2_MAX_NUM_ACK_RANGES; 2738 int numRanges = 0; 2739 uint32_t lastNum = ackThrough - acnt; 2740 if (acnt > SSU2_MAX_NUM_ACNT) 2741 { 2742 auto d = std::div (acnt - SSU2_MAX_NUM_ACNT, SSU2_MAX_NUM_ACNT); 2743 acnt = SSU2_MAX_NUM_ACNT; 2744 if (d.quot > maxNumRanges) 2745 { 2746 d.quot = maxNumRanges; 2747 d.rem = 0; 2748 } 2749 // Acks only ranges for acnt 2750 for (int i = 0; i < d.quot; i++) 2751 { 2752 m_Ranges[numRanges*2] = 0; m_Ranges[numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // NACKs 0, Acks 255 2753 numRanges++; 2754 } 2755 if (d.rem > 0) 2756 { 2757 m_Ranges[numRanges*2] = 0; m_Ranges[numRanges*2 + 1] = d.rem; 2758 numRanges++; 2759 } 2760 } 2761 int numPackets = acnt + numRanges*SSU2_MAX_NUM_ACNT; 2762 while (it != m_OutOfSequencePackets.rend () && 2763 numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS) 2764 { 2765 if (lastNum - (*it) > SSU2_MAX_NUM_ACNT) 2766 { 2767 // NACKs only ranges 2768 if (lastNum > (*it) + SSU2_MAX_NUM_ACNT*(maxNumRanges - numRanges)) break; // too many NACKs 2769 while (lastNum - (*it) > SSU2_MAX_NUM_ACNT) 2770 { 2771 m_Ranges[numRanges*2] = SSU2_MAX_NUM_ACNT; m_Ranges[numRanges*2 + 1] = 0; // NACKs 255, Acks 0 2772 lastNum -= SSU2_MAX_NUM_ACNT; 2773 numRanges++; 2774 numPackets += SSU2_MAX_NUM_ACNT; 2775 } 2776 } 2777 // NACKs and Acks ranges 2778 m_Ranges[numRanges*2] = lastNum - (*it) - 1; // NACKs 2779 numPackets += m_Ranges[numRanges*2]; 2780 lastNum = *it; it++; 2781 int numAcks = 1; 2782 while (it != m_OutOfSequencePackets.rend () && lastNum > 0 && *it == lastNum - 1) 2783 { 2784 numAcks++; lastNum--; 2785 it++; 2786 } 2787 while (numAcks > SSU2_MAX_NUM_ACNT) 2788 { 2789 // Acks only ranges 2790 m_Ranges[numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // Acks 255 2791 numAcks -= SSU2_MAX_NUM_ACNT; 2792 numRanges++; 2793 numPackets += SSU2_MAX_NUM_ACNT; 2794 m_Ranges[numRanges*2] = 0; // NACKs 0 2795 if (numRanges >= maxNumRanges || numPackets >= SSU2_MAX_NUM_ACK_PACKETS) break; 2796 } 2797 if (numAcks > SSU2_MAX_NUM_ACNT) numAcks = SSU2_MAX_NUM_ACNT; 2798 m_Ranges[numRanges*2 + 1] = (uint8_t)numAcks; // Acks 2799 numPackets += numAcks; 2800 numRanges++; 2801 } 2802 if (it == m_OutOfSequencePackets.rend () && 2803 numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS) 2804 { 2805 // add range between out-of-sequence and received 2806 int nacks = *m_OutOfSequencePackets.begin () - m_ReceivePacketNum - 1; 2807 if (nacks > 0) 2808 { 2809 if (nacks > SSU2_MAX_NUM_ACNT) nacks = SSU2_MAX_NUM_ACNT; 2810 m_Ranges[numRanges*2] = nacks; 2811 m_Ranges[numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, SSU2_MAX_NUM_ACNT); 2812 numRanges++; 2813 } 2814 } 2815 m_NumRanges = numRanges; 2816 } 2817 if (m_NumRanges) 2818 memcpy (buf + 8, m_Ranges, m_NumRanges*2); 2819 } 2820 } 2821 buf[7] = (uint8_t)acnt; // acnt 2822 htobe16buf (buf + 1, 5 + m_NumRanges*2); 2823 return 8 + m_NumRanges*2; 2824 } 2825 2826 size_t SSU2Session::CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize) 2827 { 2828 if (len < 3 || len < minSize) return 0; 2829 size_t paddingSize = m_Server.GetRng ()() & 0x1F; // 0 - 31 2830 if (paddingSize + 3 > len) paddingSize = len - 3; 2831 else if (paddingSize + 3 < minSize) paddingSize = minSize - 3; 2832 buf[0] = eSSU2BlkPadding; 2833 htobe16buf (buf + 1, paddingSize); 2834 memset (buf + 3, 0, paddingSize); 2835 return paddingSize + 3; 2836 } 2837 2838 size_t SSU2Session::CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg) 2839 { 2840 msg->ToNTCP2 (); 2841 auto msgBuf = msg->GetNTCP2Header (); 2842 auto msgLen = msg->GetNTCP2Length (); 2843 if (msgLen + 3 > len) msgLen = len - 3; 2844 buf[0] = eSSU2BlkI2NPMessage; 2845 htobe16buf (buf + 1, msgLen); // size 2846 memcpy (buf + 3, msgBuf, msgLen); 2847 return msgLen + 3; 2848 } 2849 2850 size_t SSU2Session::CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg) 2851 { 2852 if (len < 12) return 0; 2853 msg->ToNTCP2 (); 2854 auto msgBuf = msg->GetNTCP2Header (); 2855 auto msgLen = msg->GetNTCP2Length (); 2856 if (msgLen + 3 <= len) return 0; 2857 msgLen = len - 3; 2858 buf[0] = eSSU2BlkFirstFragment; 2859 htobe16buf (buf + 1, msgLen); // size 2860 memcpy (buf + 3, msgBuf, msgLen); 2861 msg->offset = (msgBuf - msg->buf) + msgLen; 2862 return msgLen + 3; 2863 } 2864 2865 size_t SSU2Session::CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID) 2866 { 2867 if (len < 8) return 0; 2868 bool isLast = true; 2869 auto msgLen = msg->len - msg->offset; 2870 if (msgLen + 8 > len) 2871 { 2872 msgLen = len - 8; 2873 isLast = false; 2874 } 2875 buf[0] = eSSU2BlkFollowOnFragment; 2876 htobe16buf (buf + 1, msgLen + 5); // size 2877 fragmentNum++; 2878 buf[3] = fragmentNum << 1; 2879 if (isLast) buf[3] |= 0x01; 2880 memcpy (buf + 4, &msgID, 4); 2881 memcpy (buf + 8, msg->buf + msg->offset, msgLen); 2882 msg->offset += msgLen; 2883 return msgLen + 8; 2884 } 2885 2886 size_t SSU2Session::CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen) 2887 { 2888 buf[0] = eSSU2BlkRelayIntro; 2889 size_t payloadSize = 1/* flag */ + 32/* Alice router hash */ + introDataLen; 2890 if (payloadSize + 3 > len) return 0; 2891 htobe16buf (buf + 1, payloadSize); // size 2892 buf[3] = 0; // flag 2893 memcpy (buf + 4, GetRemoteIdentity ()->GetIdentHash (), 32); // Alice router hash 2894 memcpy (buf + 36, introData, introDataLen); 2895 return payloadSize + 3; 2896 } 2897 2898 size_t SSU2Session::CreateRelayResponseBlock (uint8_t * buf, size_t len, 2899 SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4) 2900 { 2901 buf[0] = eSSU2BlkRelayResponse; 2902 buf[3] = 0; // flag 2903 buf[4] = code; // code 2904 htobe32buf (buf + 5, nonce); // nonce 2905 htobe32buf (buf + 9, i2p::util::GetSecondsSinceEpoch ()); // timestamp 2906 buf[13] = 2; // ver 2907 size_t csz = 0; 2908 if (code == eSSU2RelayResponseCodeAccept) 2909 { 2910 auto addr = i2p::context.GetRouterInfo ().GetSSU2Address (v4); 2911 if (!addr) 2912 { 2913 LogPrint (eLogError, "SSU2: Can't find local address for RelayResponse"); 2914 return 0; 2915 } 2916 csz = CreateEndpoint (buf + 15, len - 15, boost::asio::ip::udp::endpoint (addr->host, addr->port)); 2917 if (!csz) 2918 { 2919 LogPrint (eLogError, "SSU2: Can't create local endpoint for RelayResponse"); 2920 return 0; 2921 } 2922 } 2923 buf[14] = csz; // csz 2924 // signature 2925 size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen (); 2926 if (15 + csz + signatureLen > len) 2927 { 2928 LogPrint (eLogError, "SSU2: Buffer for RelayResponse signature is too small ", len); 2929 return 0; 2930 } 2931 SignedData<128> s; 2932 s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue 2933 if (code == eSSU2RelayResponseCodeAccept || code >= 64) // Charlie 2934 s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash 2935 else // Bob's reject 2936 s.Insert (i2p::context.GetIdentity ()->GetIdentHash (), 32); // bhash 2937 s.Insert (buf + 5, 10 + csz); // nonce, timestamp, ver, csz and Charlie's endpoint 2938 s.Sign (i2p::context.GetPrivateKeys (), buf + 15 + csz); 2939 size_t payloadSize = 12 + csz + signatureLen; 2940 if (!code) 2941 { 2942 if (payloadSize + 11 > len) 2943 { 2944 LogPrint (eLogError, "SSU2: Buffer for RelayResponse token is too small ", len); 2945 return 0; 2946 } 2947 memcpy (buf + 3 + payloadSize, &token, 8); 2948 payloadSize += 8; 2949 } 2950 htobe16buf (buf + 1, payloadSize); // size 2951 return payloadSize + 3; 2952 } 2953 2954 size_t SSU2Session::CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, 2955 const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen) 2956 { 2957 buf[0] = eSSU2BlkPeerTest; 2958 size_t payloadSize = 3/* msg, code, flag */ + signedDataLen; 2959 if (routerHash) payloadSize += 32; // router hash 2960 if (payloadSize + 3 > len) return 0; 2961 htobe16buf (buf + 1, payloadSize); // size 2962 buf[3] = msg; // msg 2963 buf[4] = (uint8_t)code; // code 2964 buf[5] = 0; //flag 2965 size_t offset = 6; 2966 if (routerHash) 2967 { 2968 memcpy (buf + offset, routerHash, 32); // router hash 2969 offset += 32; 2970 } 2971 memcpy (buf + offset, signedData, signedDataLen); 2972 return payloadSize + 3; 2973 } 2974 2975 size_t SSU2Session::CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce) 2976 { 2977 auto localAddress = FindLocalAddress (); 2978 if (!localAddress || !localAddress->port || localAddress->host.is_unspecified () || 2979 localAddress->host.is_v4 () != m_RemoteEndpoint.address ().is_v4 ()) 2980 { 2981 LogPrint (eLogWarning, "SSU2: Can't find local address for peer test"); 2982 return 0; 2983 } 2984 // signed data 2985 auto ts = i2p::util::GetSecondsSinceEpoch (); 2986 uint8_t signedData[96]; 2987 signedData[0] = 2; // ver 2988 htobe32buf (signedData + 1, nonce); 2989 htobe32buf (signedData + 5, ts); 2990 size_t asz = CreateEndpoint (signedData + 10, 86, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port)); 2991 signedData[9] = asz; 2992 // signature 2993 SignedData<128> s; 2994 s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue 2995 s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash 2996 s.Insert (signedData, 10 + asz); // ver, nonce, ts, asz, Alice's endpoint 2997 s.Sign (i2p::context.GetPrivateKeys (), signedData + 10 + asz); 2998 return CreatePeerTestBlock (buf, len, 1, eSSU2PeerTestCodeAccept, nullptr, 2999 signedData, 10 + asz + i2p::context.GetIdentity ()->GetSignatureLen ()); 3000 } 3001 3002 size_t SSU2Session::CreateTerminationBlock (uint8_t * buf, size_t len) 3003 { 3004 buf[0] = eSSU2BlkTermination; 3005 htobe16buf (buf + 1, 9); 3006 htobe64buf (buf + 3, m_ReceivePacketNum); 3007 buf[11] = (uint8_t)m_TerminationReason; 3008 return 12; 3009 } 3010 3011 std::shared_ptr<const i2p::data::RouterInfo> SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size) 3012 { 3013 if (size < 2) return nullptr; 3014 // TODO: handle frag 3015 std::shared_ptr<const i2p::data::RouterInfo> ri; 3016 if (buf[0] & SSU2_ROUTER_INFO_FLAG_GZIP) 3017 { 3018 i2p::data::GzipInflator inflator; 3019 uint8_t uncompressed[i2p::data::MAX_RI_BUFFER_SIZE]; 3020 size_t uncompressedSize = inflator.Inflate (buf + 2, size - 2, uncompressed, i2p::data::MAX_RI_BUFFER_SIZE); 3021 if (uncompressedSize && uncompressedSize <= i2p::data::MAX_RI_BUFFER_SIZE) 3022 ri = std::make_shared<i2p::data::RouterInfo>(uncompressed, uncompressedSize); 3023 else 3024 LogPrint (eLogInfo, "SSU2: RouterInfo decompression failed ", uncompressedSize); 3025 } 3026 else if (size <= i2p::data::MAX_RI_BUFFER_SIZE + 2) 3027 ri = std::make_shared<i2p::data::RouterInfo>(buf + 2, size - 2); 3028 else 3029 LogPrint (eLogInfo, "SSU2: RouterInfo is too long ", size); 3030 return ri; 3031 } 3032 3033 bool SSU2Session::UpdateReceivePacketNum (uint32_t packetNum) 3034 { 3035 if (packetNum <= m_ReceivePacketNum) return false; // duplicate 3036 if (packetNum == m_ReceivePacketNum + 1) 3037 { 3038 if (!m_OutOfSequencePackets.empty ()) 3039 { 3040 auto it = m_OutOfSequencePackets.begin (); 3041 if (*it == packetNum + 1) 3042 { 3043 // first out of sequence packet is in sequence now 3044 packetNum++; it++; 3045 while (it != m_OutOfSequencePackets.end ()) 3046 { 3047 if (*it == packetNum + 1) 3048 { 3049 packetNum++; 3050 it++; 3051 } 3052 else // next out of sequence 3053 break; 3054 } 3055 m_OutOfSequencePackets.erase (m_OutOfSequencePackets.begin (), it); 3056 } 3057 m_NumRanges = 0; // recalculate ranges when create next Ack 3058 } 3059 m_ReceivePacketNum = packetNum; 3060 } 3061 else 3062 { 3063 if (m_NumRanges && (m_OutOfSequencePackets.empty () || 3064 packetNum != (*m_OutOfSequencePackets.rbegin ()) + 1)) 3065 m_NumRanges = 0; // reset ranges if received packet is not next 3066 m_OutOfSequencePackets.insert (packetNum); 3067 } 3068 return true; 3069 } 3070 3071 void SSU2Session::SendQuickAck () 3072 { 3073 uint8_t payload[SSU2_MAX_PACKET_SIZE]; 3074 size_t payloadSize = 0; 3075 if (m_SendPacketNum > m_LastDatetimeSentPacketNum + SSU2_SEND_DATETIME_NUM_PACKETS) 3076 { 3077 payload[0] = eSSU2BlkDateTime; 3078 htobe16buf (payload + 1, 4); 3079 htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); 3080 payloadSize += 7; 3081 m_LastDatetimeSentPacketNum = m_SendPacketNum; 3082 } 3083 payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); 3084 payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); 3085 SendData (payload, payloadSize); 3086 } 3087 3088 void SSU2Session::SendTermination () 3089 { 3090 uint8_t payload[32]; 3091 size_t payloadSize = CreateTerminationBlock (payload, 32); 3092 payloadSize += CreatePaddingBlock (payload + payloadSize, 32 - payloadSize); 3093 SendData (payload, payloadSize); 3094 } 3095 3096 void SSU2Session::SendPathResponse (const uint8_t * data, size_t len) 3097 { 3098 uint8_t payload[SSU2_MAX_PACKET_SIZE]; 3099 size_t payloadSize = 0; 3100 // datetime block 3101 payload[0] = eSSU2BlkDateTime; 3102 htobe16buf (payload + 1, 4); 3103 htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); 3104 payloadSize += 7; 3105 // address block 3106 payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, m_RemoteEndpoint); 3107 // path response 3108 if (payloadSize + len > m_MaxPayloadSize) 3109 { 3110 LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len); 3111 return; 3112 } 3113 payload[payloadSize] = eSSU2BlkPathResponse; 3114 htobe16buf (payload + payloadSize + 1, len); 3115 memcpy (payload + payloadSize + 3, data, len); 3116 payloadSize += len + 3; 3117 // ack block 3118 if (payloadSize < m_MaxPayloadSize) 3119 payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); 3120 // padding 3121 if (payloadSize < m_MaxPayloadSize) 3122 payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); 3123 SendData (payload, payloadSize); 3124 } 3125 3126 void SSU2Session::SendPathChallenge (const boost::asio::ip::udp::endpoint& to) 3127 { 3128 AdjustMaxPayloadSize (SSU2_MIN_PACKET_SIZE); // reduce to minimum 3129 m_WindowSize = SSU2_MIN_WINDOW_SIZE; // reduce window to minimum 3130 3131 uint8_t payload[SSU2_MAX_PACKET_SIZE]; 3132 size_t payloadSize = 0; 3133 // datetime block 3134 payload[0] = eSSU2BlkDateTime; 3135 htobe16buf (payload + 1, 4); 3136 htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); 3137 payloadSize += 7; 3138 // address block with new address 3139 payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, to); 3140 // path challenge block 3141 payload[payloadSize] = eSSU2BlkPathChallenge; 3142 uint64_t challenge; 3143 RAND_bytes ((uint8_t *)&challenge, 8); 3144 htobe16buf (payload + payloadSize + 1, 8); // always 8 bytes 3145 htobuf64 (payload + payloadSize + 3, challenge); 3146 payloadSize += 11; 3147 m_PathChallenge = std::make_unique<std::pair<uint64_t, boost::asio::ip::udp::endpoint> >(challenge, to); 3148 // ack block 3149 if (payloadSize < m_MaxPayloadSize) 3150 payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); 3151 // padding block 3152 if (payloadSize < m_MaxPayloadSize) 3153 payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); 3154 // send to new endpoint 3155 auto existing = m_RemoteEndpoint; 3156 m_RemoteEndpoint = to; // send path challenge to new endpoint 3157 SendData (payload, payloadSize); 3158 m_RemoteEndpoint = existing; // restore endpoint back until path response received 3159 } 3160 3161 void SSU2Session::CleanUp (uint64_t ts) 3162 { 3163 for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();) 3164 { 3165 if (ts > it->second->lastFragmentInsertTime + SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT) 3166 { 3167 LogPrint (eLogWarning, "SSU2: message ", it->first, " was not completed in ", SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted"); 3168 it = m_IncompleteMessages.erase (it); 3169 } 3170 else 3171 ++it; 3172 } 3173 if (m_ReceivedI2NPMsgIDs.size () > SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS || ts > GetLastActivityTimestamp () + SSU2_DECAY_INTERVAL) 3174 // decay 3175 m_ReceivedI2NPMsgIDs.clear (); 3176 else 3177 { 3178 // delete old received msgIDs 3179 for (auto it = m_ReceivedI2NPMsgIDs.begin (); it != m_ReceivedI2NPMsgIDs.end ();) 3180 { 3181 if (ts > it->second + SSU2_RECEIVED_I2NP_MSGIDS_CLEANUP_TIMEOUT) 3182 it = m_ReceivedI2NPMsgIDs.erase (it); 3183 else 3184 ++it; 3185 } 3186 } 3187 if (!m_OutOfSequencePackets.empty ()) 3188 { 3189 int ranges = 0; 3190 while (ranges < 8 && !m_OutOfSequencePackets.empty () && 3191 (m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES || 3192 *m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + SSU2_MAX_NUM_ACK_PACKETS)) 3193 { 3194 uint32_t packet = *m_OutOfSequencePackets.begin (); 3195 if (packet > m_ReceivePacketNum + 1) 3196 { 3197 // like we've just received all packets before first 3198 packet--; 3199 m_ReceivePacketNum = packet - 1; 3200 UpdateReceivePacketNum (packet); 3201 ranges++; 3202 } 3203 else 3204 { 3205 LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum); 3206 break; 3207 } 3208 } 3209 if (m_OutOfSequencePackets.size () > 255*4) 3210 { 3211 // seems we have a serious network issue 3212 m_ReceivePacketNum = *m_OutOfSequencePackets.rbegin (); 3213 m_OutOfSequencePackets.clear (); 3214 } 3215 } 3216 3217 for (auto it = m_RelaySessions.begin (); it != m_RelaySessions.end ();) 3218 { 3219 if (ts > it->second.second + SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT) 3220 { 3221 LogPrint (eLogInfo, "SSU2: Relay nonce ", it->first, " was not responded in ", SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT, " seconds, deleted"); 3222 it = m_RelaySessions.erase (it); 3223 } 3224 else 3225 ++it; 3226 } 3227 if (m_PathChallenge) 3228 RequestTermination (eSSU2TerminationReasonNormalClose); 3229 } 3230 3231 void SSU2Session::FlushData () 3232 { 3233 bool sent = SendQueue (); // if we have something to send 3234 if (sent) 3235 SetSendQueueSize (m_SendQueue.size ()); 3236 if (m_IsDataReceived) 3237 { 3238 if (!sent) SendQuickAck (); 3239 m_Handler.Flush (); 3240 m_IsDataReceived = false; 3241 } 3242 else if (!sent && !m_SentPackets.empty ()) // if only acks received, nothing sent and we still have something to resend 3243 Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend 3244 } 3245 3246 i2p::data::RouterInfo::SupportedTransports SSU2Session::GetTransportType () const 3247 { 3248 return m_RemoteEndpoint.address ().is_v4 () ? i2p::data::RouterInfo::eSSU2V4 : i2p::data::RouterInfo::eSSU2V6; 3249 } 3250 } 3251 }