diff --git a/llarp/link/utp.cpp b/llarp/link/utp.cpp index 8901656d1..4b8c81b9b 100644 --- a/llarp/link/utp.cpp +++ b/llarp/link/utp.cpp @@ -230,12 +230,12 @@ namespace llarp { if(state == eClose) return true; - if(now < lastActive) + if(now <= lastActive) return false; auto dlt = now - lastActive; if(dlt >= sessionTimeout) { - LogInfo("session timeout reached for ", remoteAddr); + LogInfo("session timeout reached for ", remoteAddr, " dlt=", dlt); return true; } return false; diff --git a/llarp/path/transit_hop.cpp b/llarp/path/transit_hop.cpp index 28d098b9b..4f7f0bdeb 100644 --- a/llarp/path/transit_hop.cpp +++ b/llarp/path/transit_hop.cpp @@ -293,7 +293,7 @@ namespace llarp { auto path = r->pathContext().GetPathForTransfer(msg->P); llarp::routing::DataDiscardMessage discarded(msg->P, msg->S); - if(!path) + if(path == nullptr || msg->T.F != info.txID) { return SendRoutingMessage(&discarded, r); } diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 60c6688f8..7b624d3ef 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -978,12 +978,43 @@ namespace llarp return false; } + void + Endpoint::RemoveConvoTag(const ConvoTag& t) + { + m_Sessions.erase(t); + } + bool Endpoint::HandleHiddenServiceFrame(path::Path* p, const ProtocolFrame* frame) { - return frame->AsyncDecryptAndVerify(EndpointLogic(), Crypto(), p->RXID(), - Worker(), m_Identity, m_DataHandler); + if(frame->R) + { + // handle discard + ServiceInfo si; + if(!GetSenderFor(frame->T, si)) + return false; + // verify source + if(!frame->Verify(Crypto(), si)) + return false; + // remove convotag it doesn't exist + RemoveConvoTag(frame->T); + return true; + } + if(!frame->AsyncDecryptAndVerify(EndpointLogic(), Crypto(), p->RXID(), + Worker(), m_Identity, m_DataHandler)) + { + // send discard + ProtocolFrame f; + f.R = 1; + f.T = frame->T; + f.F = p->intro.pathID; + if(!f.Sign(Crypto(), m_Identity)) + return false; + const routing::PathTransferMessage d(f, frame->F); + return p->SendRoutingMessage(&d, router); + } + return true; } Endpoint::SendContext::SendContext(const ServiceInfo& ident, @@ -1298,16 +1329,17 @@ namespace llarp { // TODO: check expiration of our end ProtocolMessage m(f.T); - m.proto = t; - m.introReply = p->intro; PutReplyIntroFor(f.T, m.introReply); - m.sender = m_Identity.pub; m.PutBuffer(data); f.N.Randomize(); - f.S = GetSeqNoForConvo(f.T); f.C.Zero(); transfer.Y.Randomize(); - transfer.P = remoteIntro.pathID; + m.proto = t; + m.introReply = p->intro; + m.sender = m_Identity.pub; + f.F = m.introReply.pathID; + f.S = GetSeqNoForConvo(f.T); + transfer.P = remoteIntro.pathID; if(!f.EncryptAndSign(Router()->crypto(), m, K, m_Identity)) { llarp::LogError("failed to encrypt and sign"); @@ -1826,6 +1858,14 @@ namespace llarp { if(markedBad) return false; + if(path::Builder::ShouldBuildMore(now)) + return true; + return !ReadyToSend(); + } + + bool + Endpoint::ShouldBuildMore(llarp_time_t now) const + { bool should = path::Builder::ShouldBuildMore(now); // determine newest intro Introduction intro; @@ -1875,17 +1915,14 @@ namespace llarp if(m_DataHandler->GetCachedSessionKeyFor(f.T, shared)) { ProtocolMessage m; - m.proto = t; - if(!m_DataHandler->GetReplyIntroFor(f.T, m.introReply)) - { - m_DataHandler->PutReplyIntroFor(f.T, path->intro); - m.introReply = path->intro; - } m_DataHandler->PutIntroFor(f.T, remoteIntro); - m.sender = m_Endpoint->m_Identity.pub; + m_DataHandler->PutReplyIntroFor(f.T, path->intro); + m.proto = t; + m.introReply = path->intro; + f.F = m.introReply.pathID; + m.sender = m_Endpoint->m_Identity.pub; + m.tag = f.T; m.PutBuffer(payload); - m.tag = f.T; - if(!f.EncryptAndSign(crypto, m, shared, m_Endpoint->m_Identity)) { llarp::LogError("failed to sign"); diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 342417120..c2574c1f3 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -261,6 +261,9 @@ namespace llarp static void HandlePathDead(void*); + bool + ShouldBuildMore(llarp_time_t now) const override; + /// context needed to initiate an outbound hidden service session struct OutboundContext : public path::Builder, public SendContext { @@ -390,6 +393,9 @@ namespace llarp bool GetIntroFor(const ConvoTag& remote, Introduction& intro) const override; + void + RemoveConvoTag(const ConvoTag& remote) override; + void PutReplyIntroFor(const ConvoTag& remote, const Introduction& intro) override; diff --git a/llarp/service/handler.hpp b/llarp/service/handler.hpp index 25e3a28d9..e7503f1a7 100644 --- a/llarp/service/handler.hpp +++ b/llarp/service/handler.hpp @@ -25,6 +25,9 @@ namespace llarp PutCachedSessionKeyFor(const ConvoTag& remote, const SharedSecret& secret) = 0; + virtual void + RemoveConvoTag(const ConvoTag& remote) = 0; + virtual void PutSenderFor(const ConvoTag& remote, const ServiceInfo& si) = 0; diff --git a/llarp/service/protocol.cpp b/llarp/service/protocol.cpp index 2eb678520..a86d04eee 100644 --- a/llarp/service/protocol.cpp +++ b/llarp/service/protocol.cpp @@ -105,11 +105,23 @@ namespace llarp if(!BEncodeWriteDictEntry("C", C, buf)) return false; } - if(!BEncodeWriteDictEntry("D", D, buf)) - return false; - - if(!BEncodeWriteDictEntry("N", N, buf)) + if(D.size() > 0) + { + if(!BEncodeWriteDictEntry("D", D, buf)) + return false; + } + if(!BEncodeWriteDictEntry("F", F, buf)) return false; + if(!N.IsZero()) + { + if(!BEncodeWriteDictEntry("N", N, buf)) + return false; + } + if(R) + { + if(!BEncodeWriteDictInt("R", R, buf)) + return false; + } if(!T.IsZero()) { if(!BEncodeWriteDictEntry("T", T, buf)) @@ -137,12 +149,16 @@ namespace llarp } if(!BEncodeMaybeReadDictEntry("D", D, read, key, val)) return false; + if(!BEncodeMaybeReadDictEntry("F", F, read, key, val)) + return false; if(!BEncodeMaybeReadDictEntry("C", C, read, key, val)) return false; if(!BEncodeMaybeReadDictEntry("N", N, read, key, val)) return false; if(!BEncodeMaybeReadDictInt("S", S, read, key, val)) return false; + if(!BEncodeMaybeReadDictInt("R", R, read, key, val)) + return false; if(!BEncodeMaybeReadDictEntry("T", T, read, key, val)) return false; if(!BEncodeMaybeReadVersion("V", version, LLARP_PROTO_VERSION, read, key, @@ -164,6 +180,25 @@ namespace llarp return msg.BDecode(buf); } + bool + ProtocolFrame::Sign(llarp::Crypto* crypto, const Identity& localIdent) + { + Z.Zero(); + std::array< byte_t, MAX_PROTOCOL_MESSAGE_SIZE > tmp; + llarp_buffer_t buf(tmp); + // encode + if(!BEncode(&buf)) + { + llarp::LogError("message too big to encode"); + return false; + } + // rewind + buf.sz = buf.cur - buf.base; + buf.cur = buf.base; + // sign + return localIdent.Sign(crypto, Z, buf); + } + bool ProtocolFrame::EncryptAndSign(llarp::Crypto* crypto, const ProtocolMessage& msg, @@ -304,9 +339,11 @@ namespace llarp { C = other.C; D = other.D; + F = other.F; N = other.N; Z = other.Z; T = other.T; + R = other.R; S = other.S; version = other.version; return *this; diff --git a/llarp/service/protocol.hpp b/llarp/service/protocol.hpp index f962ac931..d4e0453d7 100644 --- a/llarp/service/protocol.hpp +++ b/llarp/service/protocol.hpp @@ -65,16 +65,20 @@ namespace llarp using Encrypted_t = Encrypted< 2048 >; PQCipherBlock C; Encrypted_t D; + uint64_t R; KeyExchangeNonce N; Signature Z; + PathID_t F; service::ConvoTag T; ProtocolFrame(const ProtocolFrame& other) : routing::IMessage() , C(other.C) , D(other.D) + , R(other.R) , N(other.N) , Z(other.Z) + , F(other.F) , T(other.T) { S = other.S; @@ -104,6 +108,9 @@ namespace llarp EncryptAndSign(Crypto* c, const ProtocolMessage& msg, const SharedSecret& sharedkey, const Identity& localIdent); + bool + Sign(Crypto* c, const Identity& localIdent); + bool AsyncDecryptAndVerify(Logic* logic, Crypto* c, const PathID_t& srcpath, llarp_threadpool* worker, @@ -125,9 +132,11 @@ namespace llarp { C.Zero(); D.Clear(); + F.Zero(); T.Zero(); N.Zero(); Z.Zero(); + R = 0; } bool