#pragma once #include #include #include #include #include #include #include #include "address.hpp" #include "handler.hpp" #include "identity.hpp" #include "pendingbuffer.hpp" #include "protocol.hpp" #include "sendcontext.hpp" #include "service/protocol_type.hpp" #include "session.hpp" #include "lookup.hpp" #include #include #include #include #include #include "endpoint_types.hpp" #include "llarp/endpoint_base.hpp" #include "auth.hpp" #include // minimum time between introset shifts #ifndef MIN_SHIFT_INTERVAL #define MIN_SHIFT_INTERVAL 5s #endif namespace llarp { namespace quic { class TunnelManager; } namespace service { struct AsyncKeyExchange; struct Context; struct EndpointState; struct OutboundContext; /// minimum interval for publishing introsets static constexpr auto IntrosetPublishInterval = path::intro_path_spread / 2; /// how agressively should we retry publishing introset on failure static constexpr auto IntrosetPublishRetryCooldown = 1s; /// how aggressively should we retry looking up introsets static constexpr auto IntrosetLookupCooldown = 250ms; struct Endpoint : public path::Builder, public ILookupHolder, public IDataHandler, public EndpointBase { Endpoint(AbstractRouter* r, Context* parent); ~Endpoint() override; /// return true if we are ready to recv packets from the void bool IsReady() const; void QueueRecvData(RecvDataEvent ev) override; /// return true if our introset has expired intros bool IntrosetIsStale() const; /// construct parameters for notify hooks virtual std::unordered_map NotifyParams() const; virtual util::StatusObject ExtractStatus() const; void SetHandler(IDataHandler* h); virtual bool Configure(const NetworkConfig& conf, const DnsConfig& dnsConf); void Tick(llarp_time_t now) override; /// return true if we have a resolvable ip address virtual bool HasIfAddr() const { return false; } virtual std::string GetIfName() const = 0; std::optional GetBestConvoTagFor(std::variant addr) const override; /// get our ifaddr if it is set virtual huint128_t GetIfAddr() const { return {0}; } /// get the exit policy for our exit if we have one /// override me virtual std::optional GetExitPolicy() const { return std::nullopt; }; /// get the ip ranges we claim to own /// override me virtual std::set GetOwnedRanges() const { return {}; }; virtual void Thaw(){}; void ResetInternalState() override; /// loop (via router) /// use when sending any data on a path const EventLoop_ptr& Loop() override; AbstractRouter* Router(); virtual bool LoadKeyFile(); virtual bool Start(); std::string Name() const override; AddressVariant_t LocalAddress() const override; std::optional GetStatFor(AddressVariant_t remote) const override; std::unordered_set AllRemoteEndpoints() const override; bool ShouldPublishDescriptors(llarp_time_t now) const override; void SRVRecordsChanged() override; void HandlePathDied(path::Path_ptr p) override; virtual vpn::EgresPacketRouter* EgresPacketRouter() { return nullptr; }; bool PublishIntroSet(const EncryptedIntroSet& i, AbstractRouter* r) override; bool PublishIntroSetVia( const EncryptedIntroSet& i, AbstractRouter* r, path::Path_ptr p, uint64_t relayOrder); bool HandleGotIntroMessage(std::shared_ptr msg) override; bool HandleGotRouterMessage(std::shared_ptr msg) override; bool HandleGotNameMessage(std::shared_ptr msg) override; bool HandleHiddenServiceFrame(path::Path_ptr p, const service::ProtocolFrame& msg); void SetEndpointAuth(std::shared_ptr policy); /// sets how we authenticate with remote address void SetAuthInfoForEndpoint(Address remote, AuthInfo info); virtual huint128_t ObtainIPForAddr(std::variant) = 0; /// get a key for ip address virtual std::optional> ObtainAddrForIP(huint128_t ip) const = 0; // virtual bool // HasServiceAddress(const AlignedBuffer< 32 >& addr) const = 0; /// return true if we have a pending job to build to a hidden service but /// it's not done yet bool HasPendingPathToService(const Address& remote) const; bool HandleDataMessage( path::Path_ptr path, const PathID_t from, std::shared_ptr msg) override; /// handle packet io from service node or hidden service to frontend virtual bool HandleInboundPacket( const ConvoTag tag, const llarp_buffer_t& pkt, ProtocolType t, uint64_t seqno) = 0; // virtual bool // HandleWriteIPPacket(const llarp_buffer_t& pkt, // std::function< huint128_t(void) > getFromIP) = 0; bool ProcessDataMessage(std::shared_ptr msg); /// ensure that we know a router, looks up if it doesn't void EnsureRouterIsKnown(const RouterID& router); /// lookup a router via closest path bool LookupRouterAnon(RouterID router, RouterLookupHandler handler); void LookupNameAsync( std::string name, std::function>)> resultHandler) override; void LookupServiceAsync( std::string name, std::string service, std::function)> resultHandler) override; /// called on event loop pump virtual void Pump(llarp_time_t now); /// stop this endpoint bool Stop() override; const Identity& GetIdentity() const { return m_Identity; } void MapExitRange(IPRange range, service::Address exit); void UnmapExitRange(IPRange range); void PutLookup(IServiceLookup* lookup, uint64_t txid) override; void HandlePathBuilt(path::Path_ptr path) override; bool HandleDataDrop(path::Path_ptr p, const PathID_t& dst, uint64_t s); bool CheckPathIsDead(path::Path_ptr p, llarp_time_t latency); using PendingBufferQueue = std::deque; size_t RemoveAllConvoTagsFor(service::Address remote); bool WantsOutboundSession(const Address&) const override; /// this MUST be called if you want to call EnsurePathTo on the given address void MarkAddressOutbound(AddressVariant_t) override; bool ShouldBundleRC() const override { return false; } void BlacklistSNode(const RouterID snode) override; /// maybe get an endpoint variant given its convo tag std::optional> GetEndpointWithConvoTag(ConvoTag t) const override; bool HasConvoTag(const ConvoTag& t) const override; bool ShouldBuildMore(llarp_time_t now) const override; virtual llarp_time_t PathAlignmentTimeout() const { constexpr auto DefaultPathAlignmentTimeout = 30s; return DefaultPathAlignmentTimeout; } bool EnsurePathTo( std::variant addr, std::function)> hook, llarp_time_t timeout) override; // passed a sendto context when we have a path established otherwise // nullptr if the path was not made before the timeout using PathEnsureHook = std::function; static constexpr auto DefaultPathEnsureTimeout = 2s; /// return false if we have already called this function before for this /// address bool EnsurePathToService( const Address remote, PathEnsureHook h, llarp_time_t timeoutMS = DefaultPathEnsureTimeout); using SNodeEnsureHook = std::function; void InformPathToService(const Address remote, OutboundContext* ctx); /// ensure a path to a service node by public key bool EnsurePathToSNode(const RouterID remote, SNodeEnsureHook h); /// return true if this endpoint is trying to lookup this router right now bool HasPendingRouterLookup(const RouterID remote) const; bool HasPathToSNode(const RouterID remote) const; void PutSenderFor(const ConvoTag& tag, const ServiceInfo& info, bool inbound) override; bool HasInboundConvo(const Address& addr) const override; bool HasOutboundConvo(const Address& addr) const override; bool GetCachedSessionKeyFor(const ConvoTag& remote, SharedSecret& secret) const override; void PutCachedSessionKeyFor(const ConvoTag& remote, const SharedSecret& secret) override; bool GetSenderFor(const ConvoTag& remote, ServiceInfo& si) const override; void PutIntroFor(const ConvoTag& remote, const Introduction& intro) override; bool GetIntroFor(const ConvoTag& remote, Introduction& intro) const override; void RemoveConvoTag(const ConvoTag& remote) override; void ConvoTagTX(const ConvoTag& remote) override; void ConvoTagRX(const ConvoTag& remote) override; void PutReplyIntroFor(const ConvoTag& remote, const Introduction& intro) override; bool GetReplyIntroFor(const ConvoTag& remote, Introduction& intro) const override; bool GetConvoTagsForService(const Address& si, std::set& tag) const override; void PutNewOutboundContext(const IntroSet& introset, llarp_time_t timeLeftToAlign); std::optional GetSeqNoForConvo(const ConvoTag& tag); /// count unique endpoints we are talking to size_t UniqueEndpoints() const; bool HasExit() const; std::optional> GetHopsForBuild() override; std::optional> GetHopsForBuildWithEndpoint(RouterID endpoint); virtual void PathBuildStarted(path::Path_ptr path) override; virtual void IntroSetPublishFail(); virtual void IntroSetPublished(); void AsyncProcessAuthMessage( std::shared_ptr msg, std::function hook); void SendAuthResult(path::Path_ptr path, PathID_t replyPath, ConvoTag tag, AuthResult st); uint64_t GenTXID(); void ResetConvoTag(ConvoTag tag, path::Path_ptr path, PathID_t from); const std::set& SnodeBlacklist() const; // Looks up the ConvoTag and, if it exists, calls SendToOrQueue to send it to a remote client // or a snode (or nothing, if the convo tag is unknown). bool SendToOrQueue(ConvoTag tag, const llarp_buffer_t& payload, ProtocolType t) override; // Send a to (or queues for sending) to either an address or router id bool SendToOrQueue( const std::variant& addr, const llarp_buffer_t& payload, ProtocolType t); // Sends to (or queues for sending) to a remote client bool SendToOrQueue(const Address& addr, const llarp_buffer_t& payload, ProtocolType t); // Sends to (or queues for sending) to a router bool SendToOrQueue(const RouterID& addr, const llarp_buffer_t& payload, ProtocolType t); std::optional MaybeGetAuthInfoForEndpoint(service::Address addr); /// Returns a pointer to the quic::Tunnel object handling quic connections for this endpoint. /// Returns nullptr if quic is not supported. quic::TunnelManager* GetQUICTunnel() override; protected: /// parent context that owns this endpoint Context* const context; virtual bool SupportsV6() const = 0; void RegenAndPublishIntroSet(); IServiceLookup* GenerateLookupByTag(const Tag& tag); void PrefetchServicesByTag(const Tag& tag); private: void HandleVerifyGotRouter(dht::GotRouterMessage_constptr msg, RouterID id, bool valid); bool OnLookup( const service::Address& addr, std::optional i, const RouterID& endpoint, llarp_time_t timeLeft, uint64_t relayOrder); bool DoNetworkIsolation(bool failed); virtual bool SetupNetworking() { // XXX: override me return true; } virtual bool IsolationFailed() { // XXX: override me return false; } protected: IDataHandler* m_DataHandler = nullptr; Identity m_Identity; net::IPRangeMap m_ExitMap; bool m_PublishIntroSet = true; std::unique_ptr m_state; std::shared_ptr m_AuthPolicy; std::unordered_map m_RemoteAuthInfos; std::unique_ptr m_quic; /// (lns name, optional exit range, optional auth info) for looking up on startup std::unordered_map, std::optional>> m_StartupLNSMappings; RecvPacketQueue_t m_InboundTrafficQueue; public: SendMessageQueue_t m_SendQueue; private: llarp_time_t m_LastIntrosetRegenAttempt = 0s; protected: void FlushRecvData(); friend struct EndpointUtil; // clang-format off const IntroSet& introSet() const; IntroSet& introSet(); using ConvoMap = std::unordered_map; const ConvoMap& Sessions() const; ConvoMap& Sessions(); // clang-format on thread::Queue m_RecvQueue; /// for rate limiting introset lookups util::DecayingHashSet
m_IntrosetLookupFilter; }; using Endpoint_ptr = std::shared_ptr; } // namespace service } // namespace llarp