lokinet/llarp/service/endpoint.hpp
Jeff Becker 2403ab8f86
ipv6
2019-06-11 12:44:05 -04:00

502 lines
13 KiB
C++

#ifndef LLARP_SERVICE_ENDPOINT_HPP
#define LLARP_SERVICE_ENDPOINT_HPP
#include <dht/messages/gotrouter.hpp>
#include <ev/ev.h>
#include <exit/session.hpp>
#include <net/net.hpp>
#include <path/path.hpp>
#include <path/pathbuilder.hpp>
#include <service/address.hpp>
#include <service/handler.hpp>
#include <service/identity.hpp>
#include <service/pendingbuffer.hpp>
#include <service/protocol.hpp>
#include <service/sendcontext.hpp>
#include <service/session.hpp>
#include <service/tag_lookup_job.hpp>
#include <hook/ihook.hpp>
#include <util/compare_ptr.hpp>
#include <util/logic.hpp>
// minimum time between introset shifts
#ifndef MIN_SHIFT_INTERVAL
#define MIN_SHIFT_INTERVAL (5 * 1000)
#endif
struct llarp_async_verify_rc;
namespace llarp
{
namespace service
{
struct AsyncKeyExchange;
struct Context;
struct OutboundContext;
struct Endpoint : public path::Builder,
public ILookupHolder,
public IDataHandler
{
/// minimum interval for publishing introsets
static const llarp_time_t INTROSET_PUBLISH_INTERVAL =
path::default_lifetime / 8;
static const llarp_time_t INTROSET_PUBLISH_RETRY_INTERVAL = 5000;
static const size_t MAX_OUTBOUND_CONTEXT_COUNT = 4;
Endpoint(const std::string& nickname, AbstractRouter* r, Context* parent);
~Endpoint();
/// return true if we are ready to recv packets from the void
bool
IsReady() const;
/// return true if our introset has expired intros
bool
IntrosetIsStale() const;
/// construct parameters for notify hooks
virtual std::unordered_map< std::string, std::string >
NotifyParams() const;
util::StatusObject
ExtractStatus() const;
void
SetHandler(IDataHandler* h);
virtual bool
SetOption(const std::string& k, const std::string& v);
virtual void
Tick(llarp_time_t now) override;
/// return true if we have a resolvable ip address
virtual bool
HasIfAddr() const
{
return false;
}
/// get our ifaddr if it is set
virtual huint128_t
GetIfAddr() const
{
return huint128_t{0};
}
virtual void
ResetInternalState() override;
/// router's logic
/// use when sending any data on a path
std::shared_ptr< Logic >
RouterLogic();
/// endpoint's logic
/// use when writing any data to local network interfaces
std::shared_ptr< Logic >
EndpointLogic();
/// borrow endpoint's net loop for sending data to user on local network
/// interface
llarp_ev_loop_ptr
EndpointNetLoop();
/// crypto worker threadpool
llarp_threadpool*
CryptoWorker();
AbstractRouter*
Router()
{
return m_Router;
}
virtual bool
LoadKeyFile();
virtual bool
Start();
virtual std::string
Name() const override;
bool
ShouldPublishDescriptors(llarp_time_t now) const override;
void
HandlePathDied(path::Path_ptr p) override;
void
EnsureReplyPath(const ServiceInfo& addr);
bool
PublishIntroSet(AbstractRouter* r) override;
bool
PublishIntroSetVia(AbstractRouter* r, path::Path_ptr p);
bool
HandleGotIntroMessage(
std::shared_ptr< const dht::GotIntroMessage > msg) override;
bool
HandleGotRouterMessage(
std::shared_ptr< const dht::GotRouterMessage > msg) override;
bool
HandleHiddenServiceFrame(path::Path_ptr p,
const service::ProtocolFrame& msg);
virtual huint128_t
ObtainIPForAddr(const AlignedBuffer< 32 >& addr, bool serviceNode) = 0;
virtual bool
HasAddress(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;
/// return false if we don't have a path to the service
/// return true if we did and we removed it
bool
ForgetPathToService(const Address& remote);
bool
HandleDataMessage(const PathID_t&,
std::shared_ptr< ProtocolMessage > msg) override;
virtual bool
HandleWriteIPPacket(const llarp_buffer_t& pkt,
std::function< huint128_t(void) > getFromIP) = 0;
bool
ProcessDataMessage(std::shared_ptr< ProtocolMessage > 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);
/// 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
PutLookup(IServiceLookup* lookup, uint64_t txid) override;
void
HandlePathBuilt(path::Path_ptr path) override;
bool
SendToServiceOrQueue(const service::Address& addr,
const llarp_buffer_t& payload, ProtocolType t);
bool
SendToSNodeOrQueue(const RouterID& addr, const llarp_buffer_t& payload);
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< PendingBuffer >;
bool
ShouldBundleRC() const override;
static void
HandlePathDead(void*);
bool
HasConvoTag(const ConvoTag& t) const override;
bool
ShouldBuildMore(llarp_time_t now) const 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< void(Address, OutboundContext*) >;
/// return false if we have already called this function before for this
/// address
bool
EnsurePathToService(const Address& remote, PathEnsureHook h,
uint64_t timeoutMS, bool lookupOnRandomPath = false);
using SNodeEnsureHook =
std::function< void(RouterID, exit::BaseSession_ptr) >;
/// ensure a path to a service node by public key
void
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) 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
PutReplyIntroFor(const ConvoTag& remote,
const Introduction& intro) override;
bool
GetReplyIntroFor(const ConvoTag& remote,
Introduction& intro) const override;
bool
GetConvoTagsForService(const ServiceInfo& si,
std::set< ConvoTag >& tag) const override;
void
PutNewOutboundContext(const IntroSet& introset);
uint64_t
GetSeqNoForConvo(const ConvoTag& tag);
virtual bool
SelectHop(llarp_nodedb* db, const std::set< RouterID >& prev,
RouterContact& cur, size_t hop, path::PathRole roles) override;
virtual void
IntroSetPublishFail();
virtual void
IntroSetPublished();
uint64_t
GenTXID();
protected:
/// parent context that owns this endpoint
Context* const context;
virtual bool
SupportsV6() const = 0;
void
RegenAndPublishIntroSet(llarp_time_t now, bool forceRebuild = false);
IServiceLookup*
GenerateLookupByTag(const Tag& tag);
void
PrefetchServicesByTag(const Tag& tag);
/// spawn a new process that contains a network isolated process
/// return true if we set up isolation and the event loop is up
/// otherwise return false
virtual bool
SpawnIsolatedNetwork()
{
return false;
}
bool
NetworkIsIsolated() const;
/// this runs in the isolated network process
void
IsolatedNetworkMainLoop();
private:
void
HandleVerifyGotRouter(dht::GotRouterMessage_constptr msg,
llarp_async_verify_rc* j);
bool
OnLookup(const service::Address& addr, const IntroSet* i,
const RouterID& endpoint); /* */
bool
DoNetworkIsolation(bool failed);
virtual bool
SetupNetworking()
{
// XXX: override me
return true;
}
virtual bool
IsolationFailed()
{
// XXX: override me
return false;
}
public:
std::set< RouterID > m_SnodeBlacklist;
protected:
IDataHandler* m_DataHandler = nullptr;
Identity m_Identity;
std::shared_ptr< exit::BaseSession > m_Exit;
hooks::Backend_ptr m_OnUp;
hooks::Backend_ptr m_OnDown;
hooks::Backend_ptr m_OnReady;
private:
friend struct EndpointUtil;
struct RouterLookupJob
{
RouterLookupJob(Endpoint* p, RouterLookupHandler h) : handler(h)
{
started = p->Now();
txid = p->GenTXID();
}
RouterLookupHandler handler;
uint64_t txid;
llarp_time_t started;
bool
IsExpired(llarp_time_t now) const
{
if(now < started)
return false;
return now - started > 30000;
}
void
InformResult(std::vector< RouterContact > result)
{
if(handler)
handler(result);
}
};
using Msg_ptr = std::shared_ptr< const routing::PathTransferMessage >;
using SendEvent_t = std::pair< Msg_ptr, path::Path_ptr >;
using PendingTraffic =
std::unordered_map< Address, PendingBufferQueue, Address::Hash >;
using ProtocolMessagePtr = std::shared_ptr< ProtocolMessage >;
using RecvPacketQueue_t =
std::priority_queue< ProtocolMessagePtr,
std::vector< ProtocolMessagePtr >,
ComparePtr< ProtocolMessagePtr > >;
util::Mutex m_InboundTrafficQueueMutex;
/// ordered queue for inbound hidden service traffic
RecvPacketQueue_t m_InboundTrafficQueue
GUARDED_BY(m_InboundTrafficQueueMutex);
using PendingRouters =
std::unordered_map< RouterID, RouterLookupJob, RouterID::Hash >;
using PendingLookups =
std::unordered_map< uint64_t,
std::unique_ptr< service::IServiceLookup > >;
using Sessions =
std::unordered_multimap< Address, std::shared_ptr< OutboundContext >,
Address::Hash >;
using SNodeSessions = std::unordered_multimap<
RouterID, std::shared_ptr< exit::BaseSession >, RouterID::Hash >;
using ConvoMap = std::unordered_map< ConvoTag, Session, ConvoTag::Hash >;
AbstractRouter* m_Router;
std::shared_ptr< Logic > m_IsolatedLogic = nullptr;
llarp_ev_loop_ptr m_IsolatedNetLoop = nullptr;
std::string m_Keyfile;
std::string m_Name;
std::string m_NetNS;
bool m_BundleRC = false;
util::Mutex m_SendQueueMutex;
std::deque< SendEvent_t > m_SendQueue GUARDED_BY(m_SendQueueMutex);
PendingTraffic m_PendingTraffic;
Sessions m_RemoteSessions;
Sessions m_DeadSessions;
SNodeSessions m_SNodeSessions;
std::unordered_map< Address, ServiceInfo, Address::Hash >
m_AddressToService;
std::unordered_multimap< Address, PathEnsureHook, Address::Hash >
m_PendingServiceLookups;
std::unordered_map< RouterID, uint32_t, RouterID::Hash >
m_ServiceLookupFails;
PendingRouters m_PendingRouters;
uint64_t m_CurrentPublishTX = 0;
llarp_time_t m_LastPublish = 0;
llarp_time_t m_LastPublishAttempt = 0;
llarp_time_t m_MinPathLatency = (5 * 1000);
/// our introset
service::IntroSet m_IntroSet;
/// pending remote service lookups by id
PendingLookups m_PendingLookups;
/// prefetch remote address list
std::set< Address > m_PrefetchAddrs;
/// hidden service tag
Tag m_Tag;
/// prefetch descriptors for these hidden service tags
std::set< Tag > m_PrefetchTags;
/// on initialize functions
std::list< std::function< bool(void) > > m_OnInit;
/// conversations
ConvoMap m_Sessions;
std::unordered_map< Tag, CachedTagResult, Tag::Hash > m_PrefetchedTags;
};
using Endpoint_ptr = std::shared_ptr< Endpoint >;
} // namespace service
} // namespace llarp
#endif