rpc endpoint for triggering quic tunnel

pull/1576/head
Jeff Becker 3 years ago
parent 838b968d8f
commit 7098f46d60
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -14,6 +14,11 @@
namespace llarp
{
namespace quic
{
class TunnelManager;
}
class EndpointBase
{
public:
@ -21,6 +26,9 @@ namespace llarp
using AddressVariant_t = std::variant<service::Address, RouterID>;
virtual quic::TunnelManager*
GetQUICTunnel() = 0;
virtual std::optional<AddressVariant_t>
GetEndpointWithConvoTag(service::ConvoTag tag) const = 0;

@ -96,6 +96,16 @@ namespace llarp
return false;
}
std::shared_ptr<handlers::ExitEndpoint>
Context::GetExitEndpoint(std::string name) const
{
if (auto itr = m_Exits.find(name); itr != m_Exits.end())
{
return itr->second;
}
return nullptr;
}
void
Context::AddExitEndpoint(
const std::string& name, const NetworkConfig& networkConfig, const DnsConfig& dnsConfig)

@ -44,6 +44,9 @@ namespace llarp
void
CalculateExitTraffic(TrafficStats& stats);
std::shared_ptr<handlers::ExitEndpoint>
GetExitEndpoint(std::string name) const;
private:
AbstractRouter* m_Router;
std::unordered_map<std::string, std::shared_ptr<handlers::ExitEndpoint>> m_Exits;

@ -129,12 +129,15 @@ namespace llarp
Flush();
quic::TunnelManager*
GetQUICTunnel();
GetQUICTunnel() override;
private:
huint128_t
GetIPForIdent(const PubKey pk);
/// async obtain snode session and call callback when it's ready to send
void
ObtainSNodeSession(const RouterID& router, exit::SessionReadyFunc obtainCb);
private:
huint128_t
AllocateNewAddress();
@ -143,10 +146,6 @@ namespace llarp
huint128_t
ObtainServiceNodeIP(const RouterID& router);
/// async obtain snode session and call callback when it's ready to send
void
ObtainSNodeSession(const RouterID& router, exit::SessionReadyFunc obtainCb);
bool
QueueSNodePacket(const llarp_buffer_t& buf, huint128_t from);

@ -1022,6 +1022,8 @@ namespace llarp
LogWarn("invalid incoming quic packet, dropping");
return false;
}
LogInfo("tag active T=", tag);
MarkConvoTagActive(tag);
quic->receive_packet(tag, buf);
return true;
}

@ -1248,7 +1248,7 @@ namespace llarp
LogInfo("accepting transit traffic");
paths.AllowTransit();
llarp_dht_allow_transit(dht());
_exitContext.AddExitEndpoint("default-connectivity", m_Config->network, m_Config->dns);
_exitContext.AddExitEndpoint("default", m_Config->network, m_Config->dns);
return true;
}

@ -2,8 +2,10 @@
#include <llarp/router/route_poker.hpp>
#include <llarp/constants/version.hpp>
#include <nlohmann/json.hpp>
#include <llarp/exit/context.hpp>
#include <llarp/net/ip_range.hpp>
#include <llarp/net/route.hpp>
#include <llarp/quic/tunnel.hpp>
#include <llarp/service/context.hpp>
#include <llarp/service/outbound_context.hpp>
#include <llarp/service/auth.hpp>
@ -53,6 +55,19 @@ namespace llarp::rpc
/// a function that replies to an rpc request
using ReplyFunction_t = std::function<void(std::string)>;
std::shared_ptr<EndpointBase>
GetEndpointByName(AbstractRouter* r, std::string name)
{
if (r->IsServiceNode())
{
return r->exitContext().GetExitEndpoint(name);
}
else
{
return r->hiddenServiceContext().GetEndpointByName(name);
}
}
void
HandleJSONRequest(
oxenmq::Message& msg, std::function<void(nlohmann::json, ReplyFunction_t)> handleRequest)
@ -118,6 +133,177 @@ namespace llarp::rpc
defer.reply(data);
});
})
.add_request_command(
"quic_connect",
[&](oxenmq::Message& msg) {
HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) {
std::string endpoint = "default";
if (auto itr = obj.find("endpoint"); itr != obj.end())
endpoint = itr->get<std::string>();
std::string remoteHost;
if (auto itr = obj.find("host"); itr != obj.end())
remoteHost = itr->get<std::string>();
uint16_t port = 0;
if (auto itr = obj.find("port"); itr != obj.end())
port = itr->get<uint16_t>();
int closeID = 0;
if (auto itr = obj.find("close"); itr != obj.end())
closeID = itr->get<int>();
if (port == 0 and closeID == 0)
{
reply(CreateJSONError("port not provided"));
return;
}
if (remoteHost.empty() and closeID == 0)
{
reply(CreateJSONError("host not provided"));
return;
}
r->loop()->call([reply, endpoint, r, remoteHost, port, closeID]() {
auto ep = GetEndpointByName(r, endpoint);
if (not ep)
{
reply(CreateJSONError("no such local endpoint"));
return;
}
auto quic = ep->GetQUICTunnel();
if (not quic)
{
reply(CreateJSONError("local endpoint has no quic tunnel"));
return;
}
if (closeID)
{
quic->close(closeID);
reply(CreateJSONResponse("OK"));
return;
}
auto status = std::make_shared<util::StatusObject>();
auto hook = [status, reply](bool success) {
if (success)
{
reply(CreateJSONResponse(*status));
}
else
{
reply(CreateJSONError("failed"));
}
};
auto [addr, id] = quic->open(remoteHost, port, hook);
status->operator[]("addr") = addr.toString();
status->operator[]("id") = id;
});
});
})
.add_request_command(
"quic_listener",
[&](oxenmq::Message& msg) {
HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) {
std::string endpoint = "default";
if (auto itr = obj.find("endpoint"); itr != obj.end())
endpoint = itr->get<std::string>();
uint16_t port = 0;
if (auto itr = obj.find("port"); itr != obj.end())
port = itr->get<uint16_t>();
int closeID = 0;
if (auto itr = obj.find("close"); itr != obj.end())
closeID = itr->get<int>();
if (port == 0 and closeID == 0)
{
reply(CreateJSONError("invalid arguments"));
return;
}
r->loop()->call([reply, endpoint, port, r, closeID]() {
auto ep = GetEndpointByName(r, endpoint);
if (not ep)
{
reply(CreateJSONError("no such local endpoint"));
return;
}
auto quic = ep->GetQUICTunnel();
if (not quic)
{
reply(CreateJSONError("no quic interface available on endpoint " + endpoint));
return;
}
if (port)
{
int id = 0;
try
{
id = quic->listen(port);
}
catch (std::exception& ex)
{
reply(CreateJSONError(ex.what()));
return;
}
util::StatusObject result{{"id", id}};
reply(CreateJSONResponse(result));
}
else if (closeID)
{
quic->forget(closeID);
reply(CreateJSONResponse("OK"));
}
});
});
})
.add_request_command(
"lookup_snode",
[&](oxenmq::Message& msg) {
HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) {
if (not r->IsServiceNode())
{
reply(CreateJSONError("not supported"));
return;
}
RouterID routerID;
if (auto itr = obj.find("snode"); itr != obj.end())
{
std::string remote = itr->get<std::string>();
if (not routerID.FromString(remote))
{
reply(CreateJSONError("invalid remote: " + remote));
return;
}
}
else
{
reply(CreateJSONError("no remote provided"));
return;
}
std::string endpoint = "default";
r->loop()->call([r, endpoint, routerID, reply]() {
auto ep = r->exitContext().GetExitEndpoint(endpoint);
if (ep == nullptr)
{
reply(CreateJSONError("cannot find local endpoint: " + endpoint));
return;
}
ep->ObtainSNodeSession(routerID, [routerID, ep, reply](auto session) {
if (session and session->IsReady())
{
const auto ip = net::TruncateV6(ep->GetIPForIdent(PubKey{routerID}));
util::StatusObject status{{"ip", ip.ToString()}};
reply(CreateJSONResponse(status));
}
else
reply(CreateJSONError("failed to obtain snode session"));
});
});
});
})
.add_request_command(
"endpoint",
[&](oxenmq::Message& msg) {

@ -399,7 +399,7 @@ namespace llarp
/// Returns a pointer to the quic::Tunnel object handling quic connections for this endpoint.
/// Returns nullptr if quic is not supported.
quic::TunnelManager*
GetQUICTunnel();
GetQUICTunnel() override;
protected:
/// parent context that owns this endpoint

@ -95,7 +95,7 @@ namespace llarp
itr->second->Tick(now);
if (itr->second->Pump(now))
{
LogInfo("marking session as dead T=", itr->first);
LogInfo("marking session as dead T=", itr->second->currentConvoTag);
itr->second->Stop();
sessions.erase(itr->second->currentConvoTag);
deadSessions.emplace(std::move(*itr));

@ -67,6 +67,8 @@ namespace llarp
if (intro.expiresAt > m_NextIntro.expiresAt)
m_NextIntro = intro;
}
currentConvoTag.Randomize();
}
OutboundContext::~OutboundContext() = default;
@ -182,12 +184,10 @@ namespace llarp
void
OutboundContext::AsyncGenIntro(const llarp_buffer_t& payload, ProtocolType t)
{
if (not currentConvoTag.IsZero())
return;
if (remoteIntro.router.IsZero())
SwapIntros();
auto path = m_PathSet->GetNewestPathByRouter(remoteIntro.router);
auto path = m_PathSet->GetPathByRouter(remoteIntro.router);
if (path == nullptr)
{
// try parent as fallback
@ -200,7 +200,6 @@ namespace llarp
return;
}
}
currentConvoTag.Randomize();
auto frame = std::make_shared<ProtocolFrame>();
auto ex = std::make_shared<AsyncKeyExchange>(
m_Endpoint->Loop(),

@ -412,7 +412,6 @@ namespace llarp
msg->handler = handler;
if (T.IsZero())
{
LogInfo("Got protocol frame with new convo");
// we need to dh
auto dh = std::make_shared<AsyncFrameDecrypt>(
loop, localIdent, handler, msg, *this, recvPath->intro);

Loading…
Cancel
Save