diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index d33592c1..2d85ab76 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1045,6 +1045,12 @@ namespace transport void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len) { // we are Charlie + auto r = i2p::data::netdb.FindRouter (buf + 1); // Alice + if (!r) + { + LogPrint (eLogError, "SSU2: RelayIntro unknown router to introduce"); + return; + } SignedData s; s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash @@ -1052,14 +1058,19 @@ namespace transport s.Insert (buf + 33, 14); // nonce, relay tag, timestamp, ver, asz uint8_t asz = buf[46]; s.Insert (buf + 47, asz); // Alice Port, Alice IP - if (!s.Verify (GetRemoteIdentity (), buf + 47 + asz)) + if (!s.Verify (r->GetIdentity (), buf + 47 + asz)) { LogPrint (eLogWarning, "SSU2: RelayIntro signature verification failed"); return; // TODO: send relay response } - // TODO: send RelayResponse to Bob - + // send relay response to Bob + uint8_t payload[SSU2_MTU]; + size_t payloadSize = CreateRelayResponseBlock (payload, SSU2_MTU, bufbe32toh (buf + 33), bufbe32toh (buf + 37)); + payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MTU - payloadSize); + SendData (payload, payloadSize); + + // send HolePunch boost::asio::ip::udp::endpoint ep; if (ExtractEndpoint (buf + 47, asz, ep)) m_Server.SendHolePunch (ep); @@ -1089,28 +1100,36 @@ namespace transport return true; } - size_t SSU2Session::CreateAddressBlock (const boost::asio::ip::udp::endpoint& ep, uint8_t * buf, size_t len) + size_t SSU2Session::CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep) { - if (len < 9) return 0; - buf[0] = eSSU2BlkAddress; - htobe16buf (buf + 3, ep.port ()); + if (len < 6) return 0; + htobe16buf (buf, ep.port ()); size_t size = 0; if (ep.address ().is_v4 ()) { - memcpy (buf + 5, ep.address ().to_v4 ().to_bytes ().data (), 4); + memcpy (buf + 2, ep.address ().to_v4 ().to_bytes ().data (), 4); size = 6; } else if (ep.address ().is_v6 ()) { - if (len < 21) return 0; - memcpy (buf + 5, ep.address ().to_v6 ().to_bytes ().data (), 16); + if (len < 18) return 0; + memcpy (buf + 2, ep.address ().to_v6 ().to_bytes ().data (), 16); size = 18; } else { LogPrint (eLogWarning, "SSU2: Wrong address type ", ep.address ().to_string ()); return 0; - } + } + return size; + } + + size_t SSU2Session::CreateAddressBlock (const boost::asio::ip::udp::endpoint& ep, uint8_t * buf, size_t len) + { + if (len < 9) return 0; + buf[0] = eSSU2BlkAddress; + size_t size = CreateEndpoint (buf + 3, len - 3, ep); + if (!size) return 0; htobe16buf (buf + 1, size); return size + 3; } @@ -1240,6 +1259,29 @@ namespace transport memcpy (buf + 36, introData, introDataLen); return payloadSize + 3; } + + size_t SSU2Session::CreateRelayResponseBlock (uint8_t * buf, size_t len, uint32_t nonce, uint32_t relayTag) + { + buf[0] = eSSU2BlkRelayResponse; + buf[3] = 0; // flag + buf[4] = 0; // code, accept + htobe32buf (buf + 5, nonce); // nonce + htobe32buf (buf + 9, relayTag); // relayTag + htobe32buf (buf + 13, i2p::util::GetSecondsSinceEpoch ()); // timestamp + buf[17] = 2; // ver + size_t csz = CreateEndpoint (buf + 19, len - 19, boost::asio::ip::udp::endpoint (m_Address->host, m_Address->port)); + if (!csz) return 0; + buf[18] = csz; // csz + // signature + SignedData s; + s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue + s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash + s.Insert (buf + 9, 10 + csz); // relay tag, timestamp, ver, csz and Charlie's endpoint + s.Sign (i2p::context.GetPrivateKeys (), buf + 19 + csz); + size_t payloadSize = 16 + csz + i2p::context.GetIdentity ()->GetSignatureLen (); + htobe16buf (buf + 1, payloadSize); // size + return payloadSize + 3; + } std::shared_ptr SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size) { diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 1bd930f6..792db0b8 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -179,6 +179,7 @@ namespace transport void HandleAck (const uint8_t * buf, size_t len); void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum); bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); + size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); std::shared_ptr ExtractRouterInfo (const uint8_t * buf, size_t size); void CreateNonce (uint64_t seqn, uint8_t * nonce); bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate @@ -195,6 +196,7 @@ namespace transport size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg); size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr msg, uint8_t& fragmentNum, uint32_t msgID); size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen); + size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, uint32_t nonce, uint32_t relayTag); // Charlie private: