diff --git a/llarp/endpoint_base.hpp b/llarp/endpoint_base.hpp new file mode 100644 index 000000000..ea42a49df --- /dev/null +++ b/llarp/endpoint_base.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "llarp/service/address.hpp" +#include "llarp/service/convotag.hpp" +#include "llarp/service/protocol_type.hpp" +#include "router_id.hpp" +#include "ev/ev.hpp" + +#include +#include +#include +#include +#include "oxenmq/variant.h" + +namespace llarp +{ + class EndpointBase + { + public: + virtual ~EndpointBase() = default; + + using AddressVariant_t = std::variant; + + virtual std::optional + GetEndpointWithConvoTag(service::ConvoTag tag) const = 0; + + virtual std::optional + GetBestConvoTagFor(AddressVariant_t addr) const = 0; + + virtual bool + EnsurePathTo( + AddressVariant_t addr, + std::function)> hook, + llarp_time_t timeout) = 0; + + virtual void + LookupNameAsync( + std::string name, std::function)> resultHandler) = 0; + + virtual const EventLoop_ptr& + Loop() = 0; + + virtual bool + SendToOrQueue( + service::ConvoTag tag, const llarp_buffer_t& payload, service::ProtocolType t) = 0; + }; + +} // namespace llarp diff --git a/llarp/exit/endpoint.cpp b/llarp/exit/endpoint.cpp index ad15885b4..eba2ed778 100644 --- a/llarp/exit/endpoint.cpp +++ b/llarp/exit/endpoint.cpp @@ -108,8 +108,10 @@ namespace llarp } bool - Endpoint::QueueOutboundTraffic(ManagedBuffer buf, uint64_t counter) + Endpoint::QueueOutboundTraffic(ManagedBuffer buf, uint64_t counter, service::ProtocolType t) { + if (t == service::ProtocolType::QUIC) + return false; // queue overflow if (m_UpstreamQueue.size() > MaxUpstreamQueueSize) return false; diff --git a/llarp/exit/endpoint.hpp b/llarp/exit/endpoint.hpp index b27a4fd4f..489071e80 100644 --- a/llarp/exit/endpoint.hpp +++ b/llarp/exit/endpoint.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -65,7 +66,7 @@ namespace llarp /// queue outbound traffic /// does ip rewrite here bool - QueueOutboundTraffic(ManagedBuffer pkt, uint64_t counter); + QueueOutboundTraffic(ManagedBuffer pkt, uint64_t counter, service::ProtocolType t); /// update local path id and cascade information to parent /// return true if success diff --git a/llarp/exit/session.cpp b/llarp/exit/session.cpp index 77d191903..b4f27d4c9 100644 --- a/llarp/exit/session.cpp +++ b/llarp/exit/session.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -18,13 +19,14 @@ namespace llarp AbstractRouter* r, size_t numpaths, size_t hoplen, - bool bundleRC) - : llarp::path::Builder(r, numpaths, hoplen) - , m_ExitRouter(routerId) - , m_WritePacket(std::move(writepkt)) - , m_Counter(0) - , m_LastUse(r->Now()) - , m_BundleRC(bundleRC) + quic::TunnelManager* quictun) + : llarp::path::Builder{r, numpaths, hoplen} + , m_ExitRouter{routerId} + , m_WritePacket{std::move(writepkt)} + , m_Counter{0} + , m_LastUse{r->Now()} + , m_BundleRC{false} + , m_QUIC{quictun} { CryptoManager::instance()->identity_keygen(m_ExitIdentity); } @@ -180,8 +182,21 @@ namespace llarp } bool - BaseSession::HandleTraffic(llarp::path::Path_ptr, const llarp_buffer_t& buf, uint64_t counter) + BaseSession::HandleTraffic( + llarp::path::Path_ptr path, + const llarp_buffer_t& buf, + uint64_t counter, + service::ProtocolType t) { + if (t == service::ProtocolType::QUIC) + { + if (buf.sz < 4 or not m_QUIC) + return false; + service::ConvoTag tag{path->TXID().as_array()}; + m_QUIC->receive_packet(tag, buf); + return true; + } + if (m_WritePacket) { llarp::net::IPPacket pkt; @@ -321,8 +336,8 @@ namespace llarp size_t numpaths, size_t hoplen, bool useRouterSNodeKey, - bool bundleRC) - : BaseSession(snodeRouter, writepkt, r, numpaths, hoplen, bundleRC) + quic::TunnelManager* quictun) + : BaseSession{snodeRouter, writepkt, r, numpaths, hoplen, quictun} { if (useRouterSNodeKey) { diff --git a/llarp/exit/session.hpp b/llarp/exit/session.hpp index 0c0e7dba6..ee01db5e2 100644 --- a/llarp/exit/session.hpp +++ b/llarp/exit/session.hpp @@ -12,6 +12,11 @@ namespace llarp { + namespace quic + { + class TunnelManager; + } + namespace exit { struct BaseSession; @@ -34,7 +39,7 @@ namespace llarp AbstractRouter* r, size_t numpaths, size_t hoplen, - bool bundleRC); + quic::TunnelManager* quictun); ~BaseSession() override; @@ -131,7 +136,11 @@ namespace llarp HandleGotExit(llarp::path::Path_ptr p, llarp_time_t b); bool - HandleTraffic(llarp::path::Path_ptr p, const llarp_buffer_t& buf, uint64_t seqno); + HandleTraffic( + llarp::path::Path_ptr p, + const llarp_buffer_t& buf, + uint64_t seqno, + service::ProtocolType t); private: std::set m_SnodeBlacklist; @@ -160,6 +169,7 @@ namespace llarp std::vector m_PendingCallbacks; const bool m_BundleRC; + quic::TunnelManager* const m_QUIC; void CallPendingCallbacks(bool success); @@ -173,8 +183,8 @@ namespace llarp AbstractRouter* r, size_t numpaths, size_t hoplen, - bool bundleRC) - : BaseSession(snodeRouter, writepkt, r, numpaths, hoplen, bundleRC) + quic::TunnelManager* quictun) + : BaseSession{snodeRouter, writepkt, r, numpaths, hoplen, quictun} {} ~ExitSession() override = default; @@ -204,7 +214,7 @@ namespace llarp size_t numpaths, size_t hoplen, bool useRouterSNodeKey, - bool bundleRC); + quic::TunnelManager* quictun); ~SNodeSession() override = default; diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 26f825991..59126e7eb 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include "service/protocol_type.hpp" @@ -19,14 +21,114 @@ namespace llarp , m_Resolver(std::make_shared(r->loop(), this)) , m_Name(std::move(name)) , m_LocalResolverAddr("127.0.0.1", 53) + , m_QUIC{std::make_shared(*this)} , m_InetToNetwork(name + "_exit_rx", r->loop(), r->loop()) { m_ShouldInitTun = true; + m_QUIC = std::make_shared(*this); } ExitEndpoint::~ExitEndpoint() = default; + void + ExitEndpoint::LookupNameAsync( + std::string, std::function)> resultHandler) + { + // TODO: implement me + resultHandler(std::nullopt); + } + + std::optional + ExitEndpoint::GetEndpointWithConvoTag(service::ConvoTag tag) const + { + for (const auto& [rid, session] : m_SNodeSessions) + { + PathID_t pathID{tag.as_array()}; + if (session->GetPathByID(pathID)) + return rid; + } + return std::nullopt; + } + + std::optional + ExitEndpoint::GetBestConvoTagFor(AddressVariant_t addr) const + { + if (auto* rid = std::get_if(&addr)) + { + auto itr = m_SNodeSessions.find(*rid); + if (itr == m_SNodeSessions.end()) + return std::nullopt; + if (auto path = itr->second->GetPathByRouter(*rid)) + { + return service::ConvoTag{path->TXID().as_array()}; + } + return std::nullopt; + } + else + return std::nullopt; + } + + const EventLoop_ptr& + ExitEndpoint::Loop() + { + return m_Router->loop(); + } + + bool + ExitEndpoint::SendToOrQueue( + service::ConvoTag tag, const llarp_buffer_t& payload, service::ProtocolType type) + { + if (auto maybeAddr = GetEndpointWithConvoTag(tag)) + { + if (std::holds_alternative(*maybeAddr)) + return false; + if (auto* rid = std::get_if(&*maybeAddr)) + { + std::vector data{}; + data.resize(payload.sz); + std::copy_n(payload.base, data.size(), data.data()); + ObtainSNodeSession(*rid, [data, type](auto session) { + if (session and session->IsReady()) + { + session->SendPacketToRemote(data, type); + } + }); + } + return true; + } + else + return false; + } + + bool + ExitEndpoint::EnsurePathTo( + AddressVariant_t addr, + std::function)> hook, + llarp_time_t) + { + if (std::holds_alternative(addr)) + return false; + if (auto* rid = std::get_if(&addr)) + { + ObtainSNodeSession( + *rid, [hook, routerID = *rid](std::shared_ptr session) { + if (session and session->IsReady()) + { + if (auto path = session->GetPathByRouter(routerID)) + { + hook(service::ConvoTag{path->TXID().as_array()}); + } + else + hook(std::nullopt); + } + else + hook(std::nullopt); + }); + } + return true; + } + util::StatusObject ExitEndpoint::ExtractStatus() const { @@ -236,7 +338,6 @@ namespace llarp auto itr = m_SNodeSessions.find(pk); if (itr != m_SNodeSessions.end()) { - // TODO: quic (?) itr->second->SendPacketToRemote(pkt.ConstBuffer(), service::ProtocolType::TrafficV4); return; } @@ -576,13 +677,19 @@ namespace llarp 2, 1, true, - false); + GetQUICTunnel()); // this is a new service node make an outbound session to them m_SNodeSessions.emplace(other, session); } return ip; } + quic::TunnelManager* + ExitEndpoint::GetQUICTunnel() + { + return m_QUIC.get(); + } + bool ExitEndpoint::AllocateNewExit(const PubKey pk, const PathID_t& path, bool wantInternet) { diff --git a/llarp/handlers/exit.hpp b/llarp/handlers/exit.hpp index 7b066a2e4..79cd662b7 100644 --- a/llarp/handlers/exit.hpp +++ b/llarp/handlers/exit.hpp @@ -10,11 +10,35 @@ namespace llarp struct AbstractRouter; namespace handlers { - struct ExitEndpoint : public dns::IQueryHandler + struct ExitEndpoint : public dns::IQueryHandler, public EndpointBase { ExitEndpoint(std::string name, AbstractRouter* r); ~ExitEndpoint() override; + std::optional + GetEndpointWithConvoTag(service::ConvoTag tag) const override; + + std::optional + GetBestConvoTagFor(AddressVariant_t addr) const override; + + bool + EnsurePathTo( + AddressVariant_t addr, + std::function)> hook, + llarp_time_t timeout) override; + + void + LookupNameAsync( + std::string name, + std::function)> resultHandler) override; + + const EventLoop_ptr& + Loop() override; + + bool + SendToOrQueue( + service::ConvoTag tag, const llarp_buffer_t& payload, service::ProtocolType t) override; + void Tick(llarp_time_t now); @@ -104,6 +128,9 @@ namespace llarp void Flush(); + quic::TunnelManager* + GetQUICTunnel(); + private: huint128_t GetIPForIdent(const PubKey pk); @@ -168,6 +195,8 @@ namespace llarp IpAddress m_LocalResolverAddr; std::vector m_UpstreamResolvers; + std::shared_ptr m_QUIC; + using Pkt_t = net::IPPacket; using PacketQueue_t = util::CoDelQueue< Pkt_t, diff --git a/llarp/path/path.cpp b/llarp/path/path.cpp index 4772b8b34..f147b336d 100644 --- a/llarp/path/path.cpp +++ b/llarp/path/path.cpp @@ -823,7 +823,8 @@ namespace llarp if (pkt.size() <= 8) return false; uint64_t counter = bufbe64toh(pkt.data()); - if (m_ExitTrafficHandler(self, llarp_buffer_t(pkt.data() + 8, pkt.size() - 8), counter)) + if (m_ExitTrafficHandler( + self, llarp_buffer_t(pkt.data() + 8, pkt.size() - 8), counter, msg.protocol)) { MarkActive(r->Now()); EnterState(ePathEstablished, r->Now()); diff --git a/llarp/path/path.hpp b/llarp/path/path.hpp index 2da623079..f8c488832 100644 --- a/llarp/path/path.hpp +++ b/llarp/path/path.hpp @@ -80,7 +80,8 @@ namespace llarp using DataHandlerFunc = std::function; using ExitUpdatedFunc = std::function; using ExitClosedFunc = std::function; - using ExitTrafficHandlerFunc = std::function; + using ExitTrafficHandlerFunc = + std::function; /// (path, backoff) backoff is 0 on success using ObtainedExitHandler = std::function; diff --git a/llarp/path/path_types.hpp b/llarp/path/path_types.hpp index 917379ad4..63a5bb24e 100644 --- a/llarp/path/path_types.hpp +++ b/llarp/path/path_types.hpp @@ -6,7 +6,9 @@ namespace llarp { struct PathID_t final : public AlignedBuffer - {}; + { + using AlignedBuffer::AlignedBuffer; + }; } // namespace llarp diff --git a/llarp/path/transit_hop.cpp b/llarp/path/transit_hop.cpp index fa14c393a..dab5878dd 100644 --- a/llarp/path/transit_hop.cpp +++ b/llarp/path/transit_hop.cpp @@ -416,7 +416,7 @@ namespace llarp continue; uint64_t counter = bufbe64toh(pkt.data()); sent &= endpoint->QueueOutboundTraffic( - ManagedBuffer(llarp_buffer_t(pkt.data() + 8, pkt.size() - 8)), counter); + ManagedBuffer(llarp_buffer_t(pkt.data() + 8, pkt.size() - 8)), counter, msg.protocol); } return sent; } diff --git a/llarp/quic/client.cpp b/llarp/quic/client.cpp index 13dc7a169..09fc22855 100644 --- a/llarp/quic/client.cpp +++ b/llarp/quic/client.cpp @@ -13,7 +13,7 @@ namespace llarp::quic { - Client::Client(service::Endpoint& ep, const SockAddr& remote, uint16_t pseudo_port) : Endpoint{ep} + Client::Client(EndpointBase& ep, const SockAddr& remote, uint16_t pseudo_port) : Endpoint{ep} { default_stream_buffer_size = 0; // We steal uvw's provided buffers so don't need an outgoing data buffer diff --git a/llarp/quic/client.hpp b/llarp/quic/client.hpp index ff94e7ed7..522460689 100644 --- a/llarp/quic/client.hpp +++ b/llarp/quic/client.hpp @@ -1,7 +1,7 @@ #pragma once #include "endpoint.hpp" -#include "service/endpoint.hpp" +#include "llarp/endpoint_base.hpp" #include @@ -20,7 +20,7 @@ namespace llarp::quic // `remote.getPort()` on the remote's lokinet address. `pseudo_port` is *our* unique local // identifier which we include in outgoing packets (so that the remote server knows where to // send the back to *this* client). - Client(service::Endpoint& ep, const SockAddr& remote, uint16_t pseudo_port); + Client(EndpointBase& ep, const SockAddr& remote, uint16_t pseudo_port); // Returns a reference to the client's connection to the server. Returns a nullptr if there is // no connection. diff --git a/llarp/quic/connection.cpp b/llarp/quic/connection.cpp index f7e116146..813e1eb54 100644 --- a/llarp/quic/connection.cpp +++ b/llarp/quic/connection.cpp @@ -331,6 +331,7 @@ namespace llarp::quic #pragma GCC diagnostic pop } // namespace +#if 0 #ifndef NDEBUG extern "C" inline void ngtcp_trace_logger([[maybe_unused]] void* user_data, const char* fmt, ...) @@ -344,6 +345,7 @@ namespace llarp::quic } va_end(ap); } +#endif #endif io_result @@ -409,9 +411,10 @@ namespace llarp::quic cb.update_key = update_key; ngtcp2_settings_default(&settings); - +#if 0 #ifndef NDEBUG settings.log_printf = ngtcp_trace_logger; +#endif #endif settings.initial_ts = get_timestamp(); // FIXME: IPv6 diff --git a/llarp/quic/endpoint.cpp b/llarp/quic/endpoint.cpp index b8be36f70..ddb0ca3f0 100644 --- a/llarp/quic/endpoint.cpp +++ b/llarp/quic/endpoint.cpp @@ -22,7 +22,7 @@ extern "C" namespace llarp::quic { - Endpoint::Endpoint(service::Endpoint& ep) : service_endpoint{ep} + Endpoint::Endpoint(EndpointBase& ep) : service_endpoint{ep} { randombytes_buf(static_secret.data(), static_secret.size()); diff --git a/llarp/quic/endpoint.hpp b/llarp/quic/endpoint.hpp index aad7fcaca..53a850ea4 100644 --- a/llarp/quic/endpoint.hpp +++ b/llarp/quic/endpoint.hpp @@ -18,10 +18,10 @@ #include #include -namespace llarp::service +namespace llarp { - struct Endpoint; -} // namespace llarp::service + class EndpointBase; +} // namespace llarp namespace llarp::quic { @@ -51,7 +51,7 @@ namespace llarp::quic protected: /// the service endpoint we are owned by - service::Endpoint& service_endpoint; + EndpointBase& service_endpoint; /// local "address" is the IPv6 unspecified address since we don't have (or care about) the /// actual local address for building quic packets. The port of this address must be set to our @@ -105,7 +105,7 @@ namespace llarp::quic friend class Connection; - explicit Endpoint(service::Endpoint& service_endpoint_); + explicit Endpoint(EndpointBase& service_endpoint_); virtual ~Endpoint(); diff --git a/llarp/quic/server.hpp b/llarp/quic/server.hpp index 7e6e1db3b..979d15262 100644 --- a/llarp/quic/server.hpp +++ b/llarp/quic/server.hpp @@ -1,7 +1,7 @@ #pragma once #include "endpoint.hpp" - +#include "llarp/endpoint_base.hpp" #include namespace llarp::quic @@ -11,7 +11,7 @@ namespace llarp::quic public: using stream_open_callback_t = std::function; - Server(service::Endpoint& service_endpoint) : Endpoint{service_endpoint} + Server(EndpointBase& service_endpoint) : Endpoint{service_endpoint} {} // Stream callback: takes the server, the (just-created) stream, and the connection port. diff --git a/llarp/quic/tunnel.cpp b/llarp/quic/tunnel.cpp index cff5badb1..6119edf3f 100644 --- a/llarp/quic/tunnel.cpp +++ b/llarp/quic/tunnel.cpp @@ -184,7 +184,7 @@ namespace llarp::quic } // namespace - TunnelManager::TunnelManager(service::Endpoint& se) : service_endpoint_{se} + TunnelManager::TunnelManager(EndpointBase& se) : service_endpoint_{se} { // Cleanup callback to clear out closed tunnel connections service_endpoint_.Loop()->call_every(500ms, timer_keepalive_, [this] { diff --git a/llarp/quic/tunnel.hpp b/llarp/quic/tunnel.hpp index 7bcaccc2c..ed51cde61 100644 --- a/llarp/quic/tunnel.hpp +++ b/llarp/quic/tunnel.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "stream.hpp" #include "address.hpp" #include "client.hpp" @@ -49,7 +49,7 @@ namespace llarp::quic // includes the resolution time. std::chrono::milliseconds open_timeout = 10s; - TunnelManager(service::Endpoint& endpoint); + TunnelManager(EndpointBase& endpoint); /// Adds an incoming listener callback. When a new incoming quic connection is initiated to us /// by some remote we invoke these callback(s) in order of registration. Each one has three @@ -132,7 +132,7 @@ namespace llarp::quic receive_packet(const service::ConvoTag& tag, const llarp_buffer_t& buf); private: - service::Endpoint& service_endpoint_; + EndpointBase& service_endpoint_; struct ClientTunnel { diff --git a/llarp/service/convotag.hpp b/llarp/service/convotag.hpp index 3c77cecb6..ec9cdbab8 100644 --- a/llarp/service/convotag.hpp +++ b/llarp/service/convotag.hpp @@ -9,6 +9,8 @@ namespace llarp::service { struct ConvoTag final : AlignedBuffer<16> { + using AlignedBuffer<16>::AlignedBuffer; + void Randomize() override; diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 04217cef0..e42ed23cd 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -1304,7 +1304,7 @@ namespace llarp numDesiredPaths, numHops, false, - ShouldBundleRC()); + GetQUICTunnel()); m_state->m_SNodeSessions.emplace(snode, std::make_pair(session, tag)); } diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 8faa440e2..b73ce0351 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -23,6 +23,7 @@ #include #include #include "endpoint_types.hpp" +#include "llarp/endpoint_base.hpp" #include "auth.hpp" @@ -55,7 +56,10 @@ namespace llarp static constexpr auto INTROSET_LOOKUP_RETRY_COOLDOWN = 3s; - struct Endpoint : public path::Builder, public ILookupHolder, public IDataHandler + struct Endpoint : public path::Builder, + public ILookupHolder, + public IDataHandler, + public EndpointBase { static const size_t MAX_OUTBOUND_CONTEXT_COUNT = 4;