#ifndef LLARP_LINK_IWP_INTERNAL_HPP #define LLARP_LINK_IWP_INTERNAL_HPP #include #include #include #include #include #include #include #include #include namespace llarp { struct Crypto; namespace iwp { struct LinkLayer; using FlowID_t = llarp::AlignedBuffer< 32 >; using OuterCommand_t = byte_t; constexpr OuterCommand_t eOCMD_ObtainFlowID = 'O'; constexpr OuterCommand_t eOCMD_GiveFlowID = 'G'; constexpr OuterCommand_t eOCMD_Reject = 'R'; constexpr OuterCommand_t eOCMD_SessionNegotiate = 'S'; constexpr OuterCommand_t eOCMD_TransmitData = 'D'; using InnerCommand_t = byte_t; constexpr InnerCommand_t eICMD_KeepAlive = 'k'; constexpr InnerCommand_t eICMD_KeepAliveAck = 'l'; constexpr InnerCommand_t eICMD_Congestion = 'c'; constexpr InnerCommand_t eICMD_AntiCongestion = 'd'; constexpr InnerCommand_t eICMD_Transmit = 't'; constexpr InnerCommand_t eICMD_Ack = 'a'; constexpr InnerCommand_t eICMD_RotateKeys = 'r'; constexpr InnerCommand_t eICMD_UpgradeProtocol = 'u'; constexpr InnerCommand_t eICMD_VersionUpgrade = 'v'; struct OuterMessage { // required memebers byte_t command; FlowID_t flow; OuterMessage(); ~OuterMessage(); // static members static std::array< byte_t, 6 > obtain_flow_id_magic; static std::array< byte_t, 6 > give_flow_id_magic; void CreateReject(const char *msg, llarp_time_t now, const PubKey &pk); // optional memebers follow std::array< byte_t, 6 > magic; NetID netid; // either timestamp or counter uint64_t uinteger; std::array< byte_t, 14 > reject; AlignedBuffer< 24 > N; PubKey pubkey; std::unique_ptr< AlignedBuffer< 32 > > A; static constexpr size_t ipv6_mtu = 1280; static constexpr size_t overhead_size = 16 + 24 + 32; static constexpr size_t payload_size = ipv6_mtu - overhead_size; AlignedBuffer< payload_size > X; size_t Xsize; ShortHash Zhash; Signature Zsig; /// encode to buffer bool Encode(llarp_buffer_t *buf) const; /// decode from buffer bool Decode(llarp_buffer_t *buf); /// clear members void Clear(); }; /// TODO: fixme constexpr size_t MaxFrags = 8; using MessageBuffer_t = AlignedBuffer< MAX_LINK_MSG_SIZE >; using FragmentLen_t = uint16_t; using SequenceNum_t = uint32_t; using WritePacketFunc = std::function< void(const llarp_buffer_t &) >; struct MessageState { /// default MessageState(); /// inbound MessageState(const ShortHash &digest, SequenceNum_t num); /// outbound MessageState(const ShortHash &digest, const llarp_buffer_t &buf, SequenceNum_t num); /// the expected hash of the message const ShortHash expectedHash; /// which fragments have we got std::bitset< MaxFrags > acks; /// the message buffer MessageBuffer_t msg; /// the message's size FragmentLen_t sz; /// the last activity we have had llarp_time_t lastActiveAt; // sequence number const SequenceNum_t seqno; /// return true if this message is to be removed /// because of inactivity bool IsExpired(llarp_time_t now) const; /// return true if we have recvieved or sent the underlying message in /// full. bool IsDone() const; /// return true if we should retransmit some packets bool ShouldRetransmit(llarp_time_t now) const; /// transmit unacked fragments bool TransmitUnacked(WritePacketFunc write_pkt) const; /// transmit acks packet bool TransmitAcks(WritePacketFunc write_pkt); }; struct Session final : public llarp::ILinkSession { /// base Session(LinkLayer *parent); /// inbound Session(LinkLayer *parent, const llarp::Addr &from); /// outbound Session(LinkLayer *parent, const RouterContact &rc, const AddressInfo &ai); ~Session(); util::StatusObject ExtractStatus() const override { // TODO: fill me in. return {}; } /// pump ll io void PumpIO(); /// tick every 1 s void TickIO(llarp_time_t now); /// queue full message bool QueueMessageBuffer(const llarp_buffer_t &buf); /// return true if the session is established and handshaked and all that /// jazz bool SessionIsEstablished(); /// inbound start void Accept(); /// sendclose void Close(); /// start outbound handshake void Connect(); // set tls config void Configure(); /// low level recv void Recv_ll(const void *buf, size_t sz); /// verify a lim bool VerfiyLIM(const llarp::LinkIntroMessage *msg); SharedSecret m_TXKey; SharedSecret m_RXKey; LinkLayer *m_Parent; llarp::Crypto *const crypto; llarp::RouterContact remoteRC; llarp::Addr remoteAddr; using MessageBuffer_t = llarp::AlignedBuffer< MAX_LINK_MSG_SIZE >; using Seqno_t = uint32_t; using Proto_t = uint8_t; using FragLen_t = uint16_t; using Flags_t = uint8_t; using Fragno_t = uint8_t; using Cmd_t = uint8_t; static constexpr size_t fragoverhead = sizeof(Proto_t) + sizeof(Cmd_t) + sizeof(Flags_t) + sizeof(Fragno_t) + sizeof(FragLen_t) + sizeof(Seqno_t); /// keepalive command static constexpr Cmd_t PING = 0; /// transmit fragment command static constexpr Cmd_t XMIT = 1; /// fragment ack command static constexpr Cmd_t FACK = 2; /// maximum number of fragments static constexpr uint8_t maxfrags = 8; /// maximum fragment size static constexpr FragLen_t fragsize = MAX_LINK_MSG_SIZE / maxfrags; using MessageHolder_t = std::unordered_map< Seqno_t, MessageState >; MessageHolder_t m_Inbound; MessageHolder_t m_Outbound; using Buf_t = std::vector< byte_t >; using IOQueue_t = std::deque< Buf_t >; IOQueue_t ll_recv; IOQueue_t ll_send; }; struct LinkLayer final : public llarp::ILinkLayer { LinkLayer(llarp::Crypto *crypto, const SecretKey &encryptionSecretKey, llarp::GetRCFunc getrc, llarp::LinkMessageHandler h, llarp::SessionEstablishedHandler established, llarp::SessionRenegotiateHandler reneg, llarp::SignBufferFunc sign, llarp::TimeoutHandler timeout, llarp::SessionClosedHandler closed); ~LinkLayer(); llarp::Crypto *const crypto; bool Start(llarp::Logic *l) override; ILinkSession * NewOutboundSession(const llarp::RouterContact &rc, const llarp::AddressInfo &ai) override; void Pump() override; bool KeyGen(SecretKey &k) override; const char * Name() const override; uint16_t Rank() const override; /// verify that a new flow id matches addresses and pubkey bool VerifyFlowID(const PubKey &pk, const Addr &from, const FlowID_t &flow) const; void RecvFrom(const llarp::Addr &from, const void *buf, size_t sz) override; private: bool GenFlowIDFor(const PubKey &pk, const Addr &from, FlowID_t &flow) const; bool ShouldSendFlowID(const Addr &from) const; void SendReject(const Addr &to, const char *msg); void SendFlowID(const Addr &to, const FlowID_t &flow); using ActiveFlows_t = std::unordered_map< FlowID_t, RouterID, FlowID_t::Hash >; ActiveFlows_t m_ActiveFlows; using PendingFlows_t = std::unordered_map< Addr, FlowID_t, Addr::Hash >; /// flows that are pending authentication PendingFlows_t m_PendingFlows; /// cookie used in flow id computation AlignedBuffer< 32 > m_FlowCookie; OuterMessage m_OuterMsg; }; } // namespace iwp } // namespace llarp #endif