lokinet/llarp/service/endpoint.hpp

538 lines
14 KiB
C++
Raw Normal View History

#pragma once
#include <llarp/dns/server.hpp>
2023-10-16 16:55:51 +00:00
#include <llarp/endpoint_base.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/pathbuilder.hpp>
#include <llarp/service/address.hpp>
#include <llarp/service/auth.hpp>
#include <llarp/service/endpoint_types.hpp>
#include <llarp/service/identity.hpp>
#include <llarp/service/pendingbuffer.hpp>
#include <llarp/service/protocol.hpp>
#include <llarp/service/protocol_type.hpp>
#include <llarp/service/session.hpp>
#include <llarp/util/compare_ptr.hpp>
#include <llarp/vpn/egres_packet_router.hpp>
#include <oxenc/variant.h>
2023-10-19 21:59:57 +00:00
#include <optional>
#include <unordered_map>
#include <variant>
2021-09-23 18:01:04 +00:00
2019-03-29 01:02:41 +00:00
// minimum time between introset shifts
2018-09-18 17:48:26 +00:00
#ifndef MIN_SHIFT_INTERVAL
2020-02-24 19:40:45 +00:00
#define MIN_SHIFT_INTERVAL 5s
2018-09-18 17:48:26 +00:00
#endif
2018-07-09 17:32:11 +00:00
namespace llarp
{
QUIC lokinet integration refactor Refactors how quic packets get handled: the actual tunnels now live in tunnel.hpp's TunnelManager which holds and manages all the quic<->tcp tunnelling. service::Endpoint now holds a TunnelManager rather than a quic::Server. We only need one quic server, but we need a separate quic client instance per outgoing quic tunnel, and TunnelManager handles all that glue now. Adds QUIC packet handling to get to the right tunnel code. This required multiplexing incoming quic packets, as follows: Adds a very small quic tunnel packet header of 4 bytes: [1, SPORT, ECN] for client->server packets, where SPORT is our source "port" (really: just a uint16_t unique quic instance identifier) or [2, DPORT, ECN] for server->client packets where the DPORT is the SPORT from above. (This also reworks ECN bits to get properly carried over lokinet.) We don't need a destination/source port for the server-side because there is only ever one quic server (and we know we're going to it when the first byte of the header is 1). Removes the config option for quic exposing ports; a full lokinet will simply accept anything incoming on quic and tunnel it to the requested port on the the local endpoint IP (this handler will come in a following commit). Replace ConvoTags with full addresses: we need to carry the port, as well, which the ConvoTag can't give us, so change those to more general SockAddrs from which we can extract both the ConvoTag *and* the port. Add a pending connection queue along with new quic-side handlers to call when a stream becomes available (TunnelManager uses this to wire up pending incoming conns with quic streams as streams open up). Completely get rid of tunnel_server/tunnel_client.cpp code; it is now moved to tunnel.hpp. Add listen()/forget() methods in TunnelManager for setting up quic listening sockets (for liblokinet usage). Add open()/close() methods in TunnelManager for spinning up new quic clients for outgoing quic connections.
2021-03-23 19:26:32 +00:00
namespace quic
{
class TunnelManager;
}
2018-07-09 17:32:11 +00:00
namespace service
{
struct AsyncKeyExchange;
2023-10-19 21:59:57 +00:00
struct Context;
struct EndpointState;
struct OutboundContext;
2020-02-24 19:40:45 +00:00
/// minimum interval for publishing introsets
inline constexpr auto IntrosetPublishInterval = path::INTRO_PATH_SPREAD / 2;
2020-02-24 19:40:45 +00:00
/// how agressively should we retry publishing introset on failure
inline constexpr auto IntrosetPublishRetryCooldown = 1s;
2020-02-24 19:40:45 +00:00
/// 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_ONS_LOOKUP_ENDPOINTS = 2;
inline constexpr size_t MAX_ONS_LOOKUP_ENDPOINTS = 7;
2023-10-03 20:00:23 +00:00
// TODO: delete this, it is copied from the late llarp/service/handler.hpp
struct RecvDataEvent
{
path::Path_ptr fromPath;
PathID_t pathid;
std::shared_ptr<ProtocolMessage> msg;
};
struct Endpoint : public path::Builder, public EndpointBase
// public std::enable_shared_from_this<Endpoint>
2018-07-09 17:32:11 +00:00
{
Endpoint(Router* r, Context* parent);
~Endpoint() override;
2018-07-09 17:32:11 +00:00
/// 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
is_ready() const;
2019-11-28 23:08:02 +00:00
void
2023-10-03 20:00:23 +00:00
QueueRecvData(RecvDataEvent ev);
2019-11-28 23:08:02 +00:00
/// 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
2019-04-19 15:10:26 +00:00
ExtractStatus() const;
2019-02-08 19:43:25 +00:00
2018-08-16 14:34:15 +00:00
virtual bool
Configure(const NetworkConfig& conf, const DnsConfig& dnsConf);
2018-07-09 17:32:11 +00:00
2019-07-30 23:42:13 +00:00
void
2019-04-23 16:13:22 +00:00
Tick(llarp_time_t now) override;
/// return true if we have a resolvable ip address
virtual bool
HasIfAddr() const
{
return false;
}
2020-08-21 15:07:37 +00:00
virtual std::string
GetIfName() const = 0;
2021-02-17 19:26:39 +00:00
std::optional<ConvoTag>
2021-03-26 14:18:39 +00:00
GetBestConvoTagFor(std::variant<Address, RouterID> addr) const override;
2021-02-17 19:26:39 +00:00
/// get our ifaddr if it is set
2019-06-11 16:44:05 +00:00
virtual huint128_t
GetIfAddr() const
{
2019-07-01 13:44:25 +00:00
return {0};
}
2021-04-14 15:07:06 +00:00
/// 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
2021-04-14 19:40:57 +00:00
virtual std::set<IPRange>
2021-04-14 15:07:06 +00:00
GetOwnedRanges() const
{
return {};
};
virtual void
Thaw(){};
2019-07-30 23:42:13 +00:00
void
2019-05-07 17:46:38 +00:00
ResetInternalState() override;
/// loop (via router)
/// use when sending any data on a path
const EventLoop_ptr&
2021-03-26 14:18:39 +00:00
Loop() override;
Router*
router();
2018-07-22 23:14:29 +00:00
virtual bool
LoadKeyFile();
2018-08-16 14:34:15 +00:00
virtual bool
2018-07-09 17:32:11 +00:00
Start();
2019-07-30 23:42:13 +00:00
std::string
2019-03-25 01:54:37 +00:00
Name() const override;
2018-07-16 03:32:13 +00:00
AddressVariant_t
LocalAddress() const override;
std::optional<SendStat>
GetStatFor(AddressVariant_t remote) const override;
std::unordered_set<AddressVariant_t>
AllRemoteEndpoints() const override;
2018-07-18 03:10:21 +00:00
bool
2018-12-24 21:10:35 +00:00
ShouldPublishDescriptors(llarp_time_t now) const override;
2018-07-18 03:10:21 +00:00
void
SRVRecordsChanged() override;
2019-03-30 13:02:10 +00:00
void
HandlePathDied(path::Path_ptr p) override;
2019-03-30 13:02:10 +00:00
2021-09-23 18:01:04 +00:00
virtual vpn::EgresPacketRouter*
EgresPacketRouter()
{
return nullptr;
};
virtual vpn::NetworkInterface*
GetVPNInterface()
{
return nullptr;
}
2018-07-18 03:10:21 +00:00
bool
2023-10-03 20:00:23 +00:00
publish_introset(const EncryptedIntroSet& i);
2018-09-18 14:48:06 +00:00
2018-07-12 18:21:44 +00:00
bool
HandleHiddenServiceFrame(path::Path_ptr p, const service::ProtocolFrameMessage& msg);
2018-07-12 18:21:44 +00:00
2020-05-28 11:07:32 +00:00
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;
2018-10-23 18:06:55 +00:00
2019-07-01 13:44:25 +00:00
// virtual bool
// HasServiceAddress(const AlignedBuffer< 32 >& addr) const = 0;
2018-08-10 03:51:38 +00:00
/// 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;
2018-09-18 17:48:26 +00:00
bool
HandleDataMessage(
2023-10-03 20:00:23 +00:00
path::Path_ptr path, const PathID_t from, std::shared_ptr<ProtocolMessage> msg);
2018-08-09 19:02:17 +00:00
/// 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;
2019-07-01 13:44:25 +00:00
// virtual bool
// HandleWriteIPPacket(const llarp_buffer_t& pkt,
// std::function< huint128_t(void) > getFromIP) = 0;
2018-11-29 13:12:35 +00:00
bool
ProcessDataMessage(std::shared_ptr<ProtocolMessage> msg);
2018-09-18 17:48:26 +00:00
2018-08-10 21:34:11 +00:00
/// ensure that we know a router, looks up if it doesn't
void
EnsureRouterIsKnown(const RouterID& router);
// "find router" via closest path
bool
lookup_router(RouterID router, std::function<void(RouterContact, bool)> func = nullptr);
// "find name"
void
lookup_name(std::string name, std::function<void(std::string, bool)> func = nullptr) override;
2023-10-12 20:37:45 +00:00
// "find introset?"
2021-04-12 11:39:07 +00:00
void
LookupServiceAsync(
std::string name,
std::string service,
std::function<void(std::vector<dns::SRVData>)> resultHandler) override;
2019-04-25 17:15:56 +00:00
/// called on event loop pump
virtual void
Pump(llarp_time_t now);
/// stop this endpoint
bool
Stop() override;
const Identity&
2018-11-21 14:30:14 +00:00
GetIdentity() const
2018-07-22 23:14:29 +00:00
{
return _identity;
2018-07-22 23:14:29 +00:00
}
2018-07-19 04:58:39 +00:00
void
MapExitRange(IPRange range, service::Address exit);
void
UnmapExitRange(IPRange range);
void
UnmapRangeByExit(IPRange range, std::string exit);
2023-01-24 18:14:00 +00:00
void
map_exit(
std::string name,
std::string token,
std::vector<IPRange> ranges,
std::function<void(bool, std::string)> result);
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>;
2018-08-22 15:52:10 +00:00
size_t
RemoveAllConvoTagsFor(service::Address remote);
2020-02-18 16:00:45 +00:00
bool
2023-10-03 20:00:23 +00:00
WantsOutboundSession(const Address&) const;
2020-02-18 16:00:45 +00:00
/// this MUST be called if you want to call EnsurePathTo on the given address
void MarkAddressOutbound(service::Address) override;
2020-02-18 16:00:45 +00:00
2020-05-21 14:18:23 +00:00
void
BlacklistSNode(const RouterID snode) override;
/// maybe get an endpoint variant given its convo tag
std::optional<std::variant<Address, RouterID>>
2021-03-26 14:18:39 +00:00
GetEndpointWithConvoTag(ConvoTag t) const override;
2019-03-08 17:00:13 +00:00
bool
2023-10-03 20:00:23 +00:00
HasConvoTag(const ConvoTag& t) const;
2019-03-08 17:00:13 +00:00
2019-03-08 14:36:24 +00:00
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,
2021-03-26 14:18:39 +00:00
llarp_time_t timeout) override;
static constexpr auto DefaultPathEnsureTimeout = 2s;
2018-07-12 18:21:44 +00:00
/// return false if we have already called this function before for this
/// address
bool
EnsurePathToService(
const Address remote,
std::function<void(Address, OutboundContext*)> h,
llarp_time_t timeoutMS = DefaultPathEnsureTimeout);
2018-07-12 18:21:44 +00:00
void
InformPathToService(const Address remote, OutboundContext* ctx);
2018-11-29 13:12:35 +00:00
/// ensure a path to a service node by public key
bool
EnsurePathToSNode(
const RouterID remote,
std::function<void(const RouterID, exit::BaseSession_ptr, ConvoTag)> h);
2018-11-29 13:12:35 +00:00
/// return true if this endpoint is trying to lookup this router right now
bool
HasPendingRouterLookup(const RouterID remote) const;
2018-11-29 13:12:35 +00:00
bool
2019-07-01 13:44:25 +00:00
HasPathToSNode(const RouterID remote) const;
2018-11-29 13:12:35 +00:00
bool
HasFlowToService(const Address remote) const;
2018-08-09 19:02:17 +00:00
void
2023-10-03 20:00:23 +00:00
PutSenderFor(const ConvoTag& tag, const ServiceInfo& info, bool inbound);
bool
2023-10-03 20:00:23 +00:00
HasInboundConvo(const Address& addr) const;
bool
2023-10-03 20:00:23 +00:00
HasOutboundConvo(const Address& addr) const;
2018-08-09 19:02:17 +00:00
bool
2023-10-03 20:00:23 +00:00
GetCachedSessionKeyFor(const ConvoTag& remote, SharedSecret& secret) const;
2018-08-09 19:02:17 +00:00
void
2023-10-03 20:00:23 +00:00
PutCachedSessionKeyFor(const ConvoTag& remote, const SharedSecret& secret);
2018-08-09 19:02:17 +00:00
bool
2023-10-03 20:00:23 +00:00
GetSenderFor(const ConvoTag& remote, ServiceInfo& si) const;
2018-08-09 19:02:17 +00:00
void
2023-10-03 20:00:23 +00:00
PutIntroFor(const ConvoTag& remote, const Introduction& intro);
2018-08-09 19:02:17 +00:00
bool
2023-10-03 20:00:23 +00:00
GetIntroFor(const ConvoTag& remote, Introduction& intro) const;
2018-08-09 19:02:17 +00:00
2019-03-08 16:00:45 +00:00
void
2023-10-03 20:00:23 +00:00
RemoveConvoTag(const ConvoTag& remote);
2019-03-08 16:00:45 +00:00
2019-09-19 20:28:12 +00:00
void
2023-10-03 20:00:23 +00:00
ConvoTagTX(const ConvoTag& remote);
void
2023-10-03 20:00:23 +00:00
ConvoTagRX(const ConvoTag& remote);
2019-09-19 20:28:12 +00:00
2019-02-21 16:45:33 +00:00
void
2023-10-03 20:00:23 +00:00
PutReplyIntroFor(const ConvoTag& remote, const Introduction& intro);
2019-02-21 16:45:33 +00:00
bool
2023-10-03 20:00:23 +00:00
GetReplyIntroFor(const ConvoTag& remote, Introduction& intro) const;
2019-02-21 16:45:33 +00:00
2018-08-09 19:02:17 +00:00
bool
2023-10-03 20:00:23 +00:00
GetConvoTagsForService(const Address& si, std::set<ConvoTag>& tag) const;
2018-08-09 19:02:17 +00:00
void
PutNewOutboundContext(const IntroSet& introset, llarp_time_t timeLeftToAlign);
std::optional<uint64_t>
2019-04-19 16:02:32 +00:00
GetSeqNoForConvo(const ConvoTag& tag);
/// count unique endpoints we are talking to
size_t
UniqueEndpoints() const;
bool
HasExit() const;
std::optional<std::vector<RemoteRC>>
GetHopsForBuild() override;
std::optional<std::vector<RemoteRC>>
GetHopsForBuildWithEndpoint(RouterID endpoint);
2019-05-10 16:19:33 +00:00
2020-05-28 11:07:32 +00:00
void
2020-06-17 13:07:05 +00:00
AsyncProcessAuthMessage(
std::shared_ptr<ProtocolMessage> msg, std::function<void(std::string, bool)> hook);
2020-05-28 11:07:32 +00:00
void
SendAuthResult(
path::Path_ptr path, PathID_t replyPath, ConvoTag tag, std::string result, bool success);
2020-05-28 11:07:32 +00:00
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
2023-10-12 20:37:45 +00:00
send_to(ConvoTag tag, std::string payload) override;
std::optional<AuthInfo>
MaybeGetAuthInfoForEndpoint(service::Address addr);
QUIC lokinet integration refactor Refactors how quic packets get handled: the actual tunnels now live in tunnel.hpp's TunnelManager which holds and manages all the quic<->tcp tunnelling. service::Endpoint now holds a TunnelManager rather than a quic::Server. We only need one quic server, but we need a separate quic client instance per outgoing quic tunnel, and TunnelManager handles all that glue now. Adds QUIC packet handling to get to the right tunnel code. This required multiplexing incoming quic packets, as follows: Adds a very small quic tunnel packet header of 4 bytes: [1, SPORT, ECN] for client->server packets, where SPORT is our source "port" (really: just a uint16_t unique quic instance identifier) or [2, DPORT, ECN] for server->client packets where the DPORT is the SPORT from above. (This also reworks ECN bits to get properly carried over lokinet.) We don't need a destination/source port for the server-side because there is only ever one quic server (and we know we're going to it when the first byte of the header is 1). Removes the config option for quic exposing ports; a full lokinet will simply accept anything incoming on quic and tunnel it to the requested port on the the local endpoint IP (this handler will come in a following commit). Replace ConvoTags with full addresses: we need to carry the port, as well, which the ConvoTag can't give us, so change those to more general SockAddrs from which we can extract both the ConvoTag *and* the port. Add a pending connection queue along with new quic-side handlers to call when a stream becomes available (TunnelManager uses this to wire up pending incoming conns with quic streams as streams open up). Completely get rid of tunnel_server/tunnel_client.cpp code; it is now moved to tunnel.hpp. Add listen()/forget() methods in TunnelManager for setting up quic listening sockets (for liblokinet usage). Add open()/close() methods in TunnelManager for spinning up new quic clients for outgoing quic connections.
2021-03-23 19:26:32 +00:00
/// Returns a pointer to the quic::Tunnel object handling quic connections for this endpoint.
/// Returns nullptr if quic is not supported.
link::TunnelManager*
GetQUICTunnel() override;
QUIC lokinet integration refactor Refactors how quic packets get handled: the actual tunnels now live in tunnel.hpp's TunnelManager which holds and manages all the quic<->tcp tunnelling. service::Endpoint now holds a TunnelManager rather than a quic::Server. We only need one quic server, but we need a separate quic client instance per outgoing quic tunnel, and TunnelManager handles all that glue now. Adds QUIC packet handling to get to the right tunnel code. This required multiplexing incoming quic packets, as follows: Adds a very small quic tunnel packet header of 4 bytes: [1, SPORT, ECN] for client->server packets, where SPORT is our source "port" (really: just a uint16_t unique quic instance identifier) or [2, DPORT, ECN] for server->client packets where the DPORT is the SPORT from above. (This also reworks ECN bits to get properly carried over lokinet.) We don't need a destination/source port for the server-side because there is only ever one quic server (and we know we're going to it when the first byte of the header is 1). Removes the config option for quic exposing ports; a full lokinet will simply accept anything incoming on quic and tunnel it to the requested port on the the local endpoint IP (this handler will come in a following commit). Replace ConvoTags with full addresses: we need to carry the port, as well, which the ConvoTag can't give us, so change those to more general SockAddrs from which we can extract both the ConvoTag *and* the port. Add a pending connection queue along with new quic-side handlers to call when a stream becomes available (TunnelManager uses this to wire up pending incoming conns with quic streams as streams open up). Completely get rid of tunnel_server/tunnel_client.cpp code; it is now moved to tunnel.hpp. Add listen()/forget() methods in TunnelManager for setting up quic listening sockets (for liblokinet usage). Add open()/close() methods in TunnelManager for spinning up new quic clients for outgoing quic connections.
2021-03-23 19:26:32 +00:00
2020-03-07 01:20:11 +00:00
protected:
/// parent context that owns this endpoint
Context* const context;
2019-06-11 16:44:05 +00:00
virtual bool
SupportsV6() const = 0;
void
regen_and_publish_introset();
2018-07-18 03:10:21 +00:00
IServiceLookup*
GenerateLookupByTag(const Tag& tag);
void
PrefetchServicesByTag(const Tag& tag);
private:
2018-08-09 19:02:17 +00:00
bool
2018-08-18 14:01:21 +00:00
DoNetworkIsolation(bool failed);
2018-08-09 19:02:17 +00:00
2018-08-16 14:34:15 +00:00
virtual bool
SetupNetworking()
{
// XXX: override me
return true;
}
2018-08-18 14:01:21 +00:00
virtual bool
IsolationFailed()
{
// XXX: override me
return false;
}
/// return true if we are ready to do outbound and inbound traffic
2022-10-25 00:39:05 +00:00
bool
ReadyForNetwork() const;
2022-10-25 00:39:05 +00:00
protected:
bool
ReadyToDoLookup(size_t num_paths) const;
2023-10-16 16:55:51 +00:00
auto
GetUniqueEndpointsForLookup() const;
Identity _identity;
net::IPRangeMap<service::Address> _exit_map;
bool _publish_introset = true;
std::unique_ptr<EndpointState> _state;
std::shared_ptr<IAuthPolicy> _auth_policy;
std::unordered_map<Address, AuthInfo> _remote_auth_infos;
std::unique_ptr<link::TunnelManager> _tunnel_manager;
/// (ons 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>>>
_startup_ons_mappings;
RecvPacketQueue_t _inbound_queue;
2021-01-01 18:55:31 +00:00
public:
2023-10-03 20:00:23 +00:00
SendMessageEventQueue _send_queue;
private:
llarp_time_t _last_introset_regen_attempt = 0s;
2021-01-01 18:55:31 +00:00
protected:
2019-11-28 23:08:02 +00:00
void
FlushRecvData();
friend struct EndpointUtil;
2023-10-16 16:55:51 +00:00
const IntroSet&
intro_set() const;
IntroSet&
intro_set();
const std::unordered_map<ConvoTag, Session>&
Sessions() const;
std::unordered_map<ConvoTag, Session>&
Sessions();
2019-05-07 08:29:47 +00:00
thread::Queue<RecvDataEvent> _recv_event_queue;
/// for rate limiting introset lookups
util::DecayingHashSet<Address> _introset_lookup_filter;
2018-07-09 17:32:11 +00:00
};
using Endpoint_ptr = std::shared_ptr<Endpoint>;
2018-07-09 17:32:11 +00:00
} // namespace service
} // namespace llarp