mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-15 12:13:24 +00:00
e5efe793ca
previously we had a checking style function that passes in an optional defaulting to nullopt as a micro optimzation, this makes the code unnessarily obtuse. simplify this by splitting up into 2 functions, one for getting the unique endpoints and one for checking if the number of them is above the minimum. add overload for ReadyToDoLookup() that checks against constant but can do more in the future if desired to reduce the burden on future contributors.
584 lines
16 KiB
C++
584 lines
16 KiB
C++
#pragma once
|
|
#include <llarp/dht/messages/gotrouter.hpp>
|
|
#include <llarp/ev/ev.hpp>
|
|
#include <llarp/exit/session.hpp>
|
|
#include <llarp/net/ip_range_map.hpp>
|
|
#include <llarp/net/net.hpp>
|
|
#include <llarp/path/path.hpp>
|
|
#include <llarp/path/pathbuilder.hpp>
|
|
#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 <llarp/util/compare_ptr.hpp>
|
|
#include <optional>
|
|
#include <unordered_map>
|
|
#include <variant>
|
|
#include <oxenc/variant.h>
|
|
#include "endpoint_types.hpp"
|
|
#include "llarp/endpoint_base.hpp"
|
|
|
|
#include "auth.hpp"
|
|
|
|
#include <llarp/vpn/egres_packet_router.hpp>
|
|
#include <llarp/dns/server.hpp>
|
|
|
|
// 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
|
|
inline constexpr auto IntrosetPublishInterval = path::intro_path_spread / 2;
|
|
|
|
/// how agressively should we retry publishing introset on failure
|
|
inline constexpr auto IntrosetPublishRetryCooldown = 1s;
|
|
|
|
/// how aggressively should we retry looking up introsets
|
|
inline constexpr auto IntrosetLookupCooldown = 250ms;
|
|
|
|
/// number of unique snodes we want to talk to do to ons lookups
|
|
inline constexpr size_t MIN_ENDPOINTS_FOR_LNS_LOOKUP = 2;
|
|
|
|
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.
|
|
/// really should be ReadyForInboundTraffic() but the diff is HUGE and we need to rewrite this
|
|
/// component anyways.
|
|
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<std::string, std::string>
|
|
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<ConvoTag>
|
|
GetBestConvoTagFor(std::variant<Address, RouterID> 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<net::TrafficPolicy>
|
|
GetExitPolicy() const
|
|
{
|
|
return std::nullopt;
|
|
};
|
|
|
|
/// get the ip ranges we claim to own
|
|
/// override me
|
|
virtual std::set<IPRange>
|
|
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<SendStat>
|
|
GetStatFor(AddressVariant_t remote) const override;
|
|
|
|
std::unordered_set<AddressVariant_t>
|
|
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;
|
|
};
|
|
|
|
virtual vpn::NetworkInterface*
|
|
GetVPNInterface()
|
|
{
|
|
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<const dht::GotIntroMessage> msg) override;
|
|
|
|
bool
|
|
HandleGotRouterMessage(std::shared_ptr<const dht::GotRouterMessage> msg) override;
|
|
|
|
bool
|
|
HandleGotNameMessage(std::shared_ptr<const dht::GotNameMessage> msg) override;
|
|
|
|
bool
|
|
HandleHiddenServiceFrame(path::Path_ptr p, const service::ProtocolFrame& msg);
|
|
|
|
void
|
|
SetEndpointAuth(std::shared_ptr<IAuthPolicy> policy);
|
|
|
|
/// sets how we authenticate with remote address
|
|
void
|
|
SetAuthInfoForEndpoint(Address remote, AuthInfo info);
|
|
|
|
virtual huint128_t ObtainIPForAddr(std::variant<Address, RouterID>) = 0;
|
|
|
|
/// get a key for ip address
|
|
virtual std::optional<std::variant<service::Address, RouterID>>
|
|
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<ProtocolMessage> 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<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);
|
|
|
|
void
|
|
LookupNameAsync(
|
|
std::string name,
|
|
std::function<void(std::optional<std::variant<Address, RouterID>>)> resultHandler)
|
|
override;
|
|
|
|
void
|
|
LookupServiceAsync(
|
|
std::string name,
|
|
std::string service,
|
|
std::function<void(std::vector<dns::SRVData>)> 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<PendingBuffer>;
|
|
|
|
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<std::variant<Address, RouterID>>
|
|
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<Address, RouterID> addr,
|
|
std::function<void(std::optional<ConvoTag>)> 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<void(Address, OutboundContext*)>;
|
|
|
|
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(const RouterID, exit::BaseSession_ptr, ConvoTag)>;
|
|
|
|
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;
|
|
|
|
bool
|
|
HasFlowToService(const Address 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<ConvoTag>& tag) const override;
|
|
|
|
void
|
|
PutNewOutboundContext(const IntroSet& introset, llarp_time_t timeLeftToAlign);
|
|
|
|
std::optional<uint64_t>
|
|
GetSeqNoForConvo(const ConvoTag& tag);
|
|
|
|
/// count unique endpoints we are talking to
|
|
size_t
|
|
UniqueEndpoints() const;
|
|
|
|
bool
|
|
HasExit() const;
|
|
|
|
std::optional<std::vector<RouterContact>>
|
|
GetHopsForBuild() override;
|
|
|
|
std::optional<std::vector<RouterContact>>
|
|
GetHopsForBuildWithEndpoint(RouterID endpoint);
|
|
|
|
virtual void
|
|
PathBuildStarted(path::Path_ptr path) override;
|
|
|
|
virtual void
|
|
IntroSetPublishFail();
|
|
virtual void
|
|
IntroSetPublished();
|
|
|
|
void
|
|
AsyncProcessAuthMessage(
|
|
std::shared_ptr<ProtocolMessage> msg, std::function<void(AuthResult)> 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<RouterID>&
|
|
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<Address, RouterID>& 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<AuthInfo>
|
|
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<IntroSet> 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;
|
|
}
|
|
|
|
/// return true if we are ready to do outbound and inbound traffic
|
|
bool
|
|
ReadyForNetwork() const;
|
|
|
|
protected:
|
|
bool
|
|
ReadyToDoLookup(size_t num_paths) const;
|
|
path::Path::UniqueEndpointSet_t
|
|
GetUniqueEndpointsForLookup() const;
|
|
|
|
IDataHandler* m_DataHandler = nullptr;
|
|
Identity m_Identity;
|
|
net::IPRangeMap<service::Address> m_ExitMap;
|
|
bool m_PublishIntroSet = true;
|
|
std::unique_ptr<EndpointState> m_state;
|
|
std::shared_ptr<IAuthPolicy> m_AuthPolicy;
|
|
std::unordered_map<Address, AuthInfo> m_RemoteAuthInfos;
|
|
std::unique_ptr<quic::TunnelManager> m_quic;
|
|
|
|
/// (lns name, optional exit range, optional auth info) for looking up on startup
|
|
std::unordered_map<std::string, std::pair<std::optional<IPRange>, std::optional<AuthInfo>>>
|
|
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<ConvoTag, Session>;
|
|
const ConvoMap& Sessions() const;
|
|
ConvoMap& Sessions();
|
|
// clang-format on
|
|
thread::Queue<RecvDataEvent> m_RecvQueue;
|
|
|
|
/// for rate limiting introset lookups
|
|
util::DecayingHashSet<Address> m_IntrosetLookupFilter;
|
|
};
|
|
|
|
using Endpoint_ptr = std::shared_ptr<Endpoint>;
|
|
|
|
} // namespace service
|
|
} // namespace llarp
|