lokinet/llarp/exit/session.cpp

384 lines
10 KiB
C++
Raw Normal View History

2018-12-12 01:06:46 +00:00
#include <exit/session.hpp>
2019-01-16 00:24:16 +00:00
#include <crypto/crypto.hpp>
#include <nodedb.hpp>
2019-06-17 23:19:39 +00:00
#include <path/path_context.hpp>
2019-01-11 01:19:36 +00:00
#include <path/path.hpp>
#include <router/abstractrouter.hpp>
2019-09-01 12:38:03 +00:00
#include <util/meta/memfn.hpp>
2019-07-30 23:42:13 +00:00
#include <utility>
namespace llarp
{
namespace exit
{
BaseSession::BaseSession(
2019-08-02 09:27:27 +00:00
const llarp::RouterID& routerId,
std::function<bool(const llarp_buffer_t&)> writepkt,
AbstractRouter* r,
size_t numpaths,
size_t hoplen,
bool bundleRC)
2019-06-20 16:22:29 +00:00
: llarp::path::Builder(r, numpaths, hoplen)
2019-08-02 09:27:27 +00:00
, m_ExitRouter(routerId)
2019-07-30 23:42:13 +00:00
, m_WritePacket(std::move(writepkt))
2018-11-29 21:19:20 +00:00
, m_Counter(0)
, m_LastUse(r->Now())
, m_BundleRC(bundleRC)
2018-11-14 19:34:17 +00:00
{
CryptoManager::instance()->identity_keygen(m_ExitIdentity);
2018-11-14 19:34:17 +00:00
}
2019-07-30 23:42:13 +00:00
BaseSession::~BaseSession() = default;
2018-11-14 19:34:17 +00:00
2019-05-06 14:54:05 +00:00
void
BaseSession::HandlePathDied(path::Path_ptr p)
2019-03-30 13:02:10 +00:00
{
2019-05-06 14:54:05 +00:00
p->Rebuild();
2019-03-30 13:02:10 +00:00
}
2019-02-11 17:14:43 +00:00
util::StatusObject
BaseSession::ExtractStatus() const
2019-02-08 19:43:25 +00:00
{
auto obj = path::Builder::ExtractStatus();
obj["lastExitUse"] = to_json(m_LastUse);
auto pub = m_ExitIdentity.toPublic();
obj["exitIdentity"] = pub.ToString();
2019-02-11 17:14:43 +00:00
return obj;
2019-02-08 19:43:25 +00:00
}
bool
BaseSession::LoadIdentityFromFile(const char* fname)
{
return m_ExitIdentity.LoadFromFile(fname);
}
bool
BaseSession::ShouldBuildMore(llarp_time_t now) const
{
if (BuildCooldownHit(now))
2020-03-09 21:31:43 +00:00
return false;
2019-07-18 16:28:17 +00:00
const size_t expect = (1 + (numPaths / 2));
2018-12-27 12:00:28 +00:00
// check 30 seconds into the future and see if we need more paths
2020-02-24 19:40:45 +00:00
const llarp_time_t future = now + 30s + buildIntervalLimit;
2020-03-09 21:31:43 +00:00
return NumPathsExistingAt(future) < expect;
}
2019-05-10 16:19:33 +00:00
void
2020-05-21 14:18:23 +00:00
BaseSession::BlacklistSNode(const RouterID snode)
2019-05-10 16:19:33 +00:00
{
m_SnodeBlacklist.insert(std::move(snode));
}
2018-11-14 19:34:17 +00:00
bool
BaseSession::SelectHop(
llarp_nodedb* db,
const std::set<RouterID>& prev,
RouterContact& cur,
size_t hop,
llarp::path::PathRole roles)
2018-11-14 19:34:17 +00:00
{
std::set<RouterID> exclude = prev;
for (const auto& snode : m_SnodeBlacklist)
2019-05-10 16:19:33 +00:00
{
if (snode != m_ExitRouter)
2019-05-10 16:19:33 +00:00
exclude.insert(snode);
}
2019-05-08 14:01:31 +00:00
exclude.insert(m_ExitRouter);
if (hop == numHops - 1)
2018-12-10 15:44:18 +00:00
{
if (db->Get(m_ExitRouter, cur))
2019-04-30 21:36:27 +00:00
return true;
2019-08-02 09:27:27 +00:00
m_router->LookupRouter(m_ExitRouter, nullptr);
2019-04-30 21:36:27 +00:00
return false;
2018-12-10 15:44:18 +00:00
}
2019-07-06 17:03:40 +00:00
return path::Builder::SelectHop(db, exclude, cur, hop, roles);
2018-11-14 19:34:17 +00:00
}
2019-04-16 19:39:58 +00:00
bool
BaseSession::CheckPathDead(path::Path_ptr, llarp_time_t dlt)
2019-04-16 19:39:58 +00:00
{
2020-05-21 14:18:23 +00:00
return dlt >= path::alive_timeout;
2019-04-16 19:39:58 +00:00
}
2018-11-14 19:34:17 +00:00
void
BaseSession::HandlePathBuilt(llarp::path::Path_ptr p)
2018-11-14 19:34:17 +00:00
{
2018-12-10 15:31:58 +00:00
path::Builder::HandlePathBuilt(p);
2019-06-02 21:19:10 +00:00
p->SetDropHandler(util::memFn(&BaseSession::HandleTrafficDrop, this));
p->SetDeadChecker(util::memFn(&BaseSession::CheckPathDead, this));
p->SetExitTrafficHandler(util::memFn(&BaseSession::HandleTraffic, this));
p->AddObtainExitHandler(util::memFn(&BaseSession::HandleGotExit, this));
2018-12-20 12:41:17 +00:00
routing::ObtainExitMessage obtain;
2018-11-14 19:34:17 +00:00
obtain.S = p->NextSeqNo();
obtain.T = llarp::randint();
2018-11-29 13:12:35 +00:00
PopulateRequest(obtain);
if (!obtain.Sign(m_ExitIdentity))
2018-11-14 19:34:17 +00:00
{
llarp::LogError("Failed to sign exit request");
return;
}
if (p->SendExitRequest(obtain, m_router))
2018-11-14 19:34:17 +00:00
llarp::LogInfo("asking ", m_ExitRouter, " for exit");
else
2019-01-16 00:24:16 +00:00
llarp::LogError("failed to send exit request");
2018-11-14 19:34:17 +00:00
}
void
BaseSession::AddReadyHook(SessionReadyFunc func)
{
m_PendingCallbacks.emplace_back(func);
}
2018-11-14 19:34:17 +00:00
bool
BaseSession::HandleGotExit(llarp::path::Path_ptr p, llarp_time_t b)
2018-11-14 19:34:17 +00:00
{
if (b == 0s)
2019-04-30 21:36:27 +00:00
{
2018-11-14 19:34:17 +00:00
llarp::LogInfo("obtained an exit via ", p->Endpoint());
2019-03-07 15:17:29 +00:00
CallPendingCallbacks(true);
2019-04-30 21:36:27 +00:00
}
2019-03-07 15:17:29 +00:00
return true;
}
2018-12-13 12:27:14 +00:00
2019-03-07 15:17:29 +00:00
void
BaseSession::CallPendingCallbacks(bool success)
{
if (success)
2019-03-07 15:17:29 +00:00
{
2019-04-23 16:13:22 +00:00
auto self = shared_from_this();
for (auto& f : m_PendingCallbacks)
2019-04-23 16:13:22 +00:00
f(self);
2019-03-07 15:17:29 +00:00
}
else
{
for (auto& f : m_PendingCallbacks)
2019-03-07 15:17:29 +00:00
f(nullptr);
}
m_PendingCallbacks.clear();
2018-11-14 19:34:17 +00:00
}
2019-05-07 18:15:22 +00:00
void
BaseSession::ResetInternalState()
{
auto sendExitClose = [&](const llarp::path::Path_ptr p) {
const static auto roles = llarp::path::ePathRoleExit | llarp::path::ePathRoleSVC;
if (p->SupportsAnyRoles(roles))
2019-05-07 18:15:22 +00:00
{
llarp::LogInfo(p->Name(), " closing exit path");
routing::CloseExitMessage msg;
if (msg.Sign(m_ExitIdentity) && p->SendExitClose(msg, m_router))
{
p->ClearRoles(roles);
}
else
2019-05-07 18:15:22 +00:00
llarp::LogWarn(p->Name(), " failed to send exit close message");
}
};
ForEachPath(sendExitClose);
path::Builder::ResetInternalState();
}
bool
BaseSession::Stop()
{
2019-03-07 15:17:29 +00:00
CallPendingCallbacks(false);
auto sendExitClose = [&](const path::Path_ptr p) {
if (p->SupportsAnyRoles(path::ePathRoleExit))
{
LogInfo(p->Name(), " closing exit path");
routing::CloseExitMessage msg;
if (!(msg.Sign(m_ExitIdentity) && p->SendExitClose(msg, m_router)))
LogWarn(p->Name(), " failed to send exit close message");
}
};
ForEachPath(sendExitClose);
2019-08-02 09:27:27 +00:00
m_router->pathContext().RemovePathSet(shared_from_this());
return path::Builder::Stop();
}
2018-11-14 19:34:17 +00:00
bool
BaseSession::HandleTraffic(llarp::path::Path_ptr, const llarp_buffer_t& buf, uint64_t counter)
2018-11-14 19:34:17 +00:00
{
if (m_WritePacket)
2018-12-13 12:27:14 +00:00
{
2019-06-11 16:44:05 +00:00
llarp::net::IPPacket pkt;
if (!pkt.Load(buf))
2018-12-13 12:27:14 +00:00
return false;
2019-08-02 09:27:27 +00:00
m_LastUse = m_router->Now();
m_Downstream.emplace(counter, pkt);
2018-12-13 12:27:14 +00:00
return true;
}
2018-11-14 19:34:17 +00:00
return false;
}
bool
BaseSession::HandleTrafficDrop(llarp::path::Path_ptr p, const PathID_t& path, uint64_t s)
2018-11-14 19:34:17 +00:00
{
llarp::LogError("dropped traffic on exit ", m_ExitRouter, " S=", s, " P=", path);
2019-08-02 09:27:27 +00:00
p->EnterState(path::ePathIgnore, m_router->Now());
2018-11-14 19:34:17 +00:00
return true;
}
bool
2019-06-11 16:44:05 +00:00
BaseSession::QueueUpstreamTraffic(llarp::net::IPPacket pkt, const size_t N)
2018-11-28 16:38:20 +00:00
{
const auto pktbuf = pkt.ConstBuffer();
const llarp_buffer_t& buf = pktbuf;
auto& queue = m_Upstream[buf.sz / N];
2018-11-29 13:12:35 +00:00
// queue overflow
if (queue.size() >= MaxUpstreamQueueLength)
2018-11-29 13:12:35 +00:00
return false;
if (queue.size() == 0)
{
queue.emplace_back();
2018-11-29 21:19:20 +00:00
return queue.back().PutBuffer(buf, m_Counter++);
}
auto& back = queue.back();
2018-11-28 16:38:20 +00:00
// pack to nearest N
if (back.Size() + buf.sz > N)
2018-11-28 16:38:20 +00:00
{
queue.emplace_back();
return queue.back().PutBuffer(buf, m_Counter++);
2018-11-28 16:38:20 +00:00
}
2019-07-06 17:03:40 +00:00
return back.PutBuffer(buf, m_Counter++);
2018-11-28 16:38:20 +00:00
}
2018-11-29 13:12:35 +00:00
bool
BaseSession::IsReady() const
2018-11-29 13:12:35 +00:00
{
2019-07-18 16:28:17 +00:00
const size_t expect = (1 + (numPaths / 2));
2019-03-07 15:17:29 +00:00
return AvailablePaths(llarp::path::ePathRoleExit) >= expect;
2018-11-29 13:12:35 +00:00
}
2018-12-13 12:27:14 +00:00
bool
BaseSession::IsExpired(llarp_time_t now) const
{
2020-01-08 16:05:29 +00:00
return now > m_LastUse && now - m_LastUse > LifeSpan;
2018-12-13 12:27:14 +00:00
}
2019-05-07 15:08:57 +00:00
bool
BaseSession::UrgentBuild(llarp_time_t now) const
{
if (BuildCooldownHit(now))
2020-03-09 21:31:43 +00:00
return false;
if (!IsReady())
2019-07-18 16:28:17 +00:00
return NumInStatus(path::ePathBuilding) < numPaths;
2019-05-07 15:08:57 +00:00
return path::Builder::UrgentBuild(now);
}
bool
2019-04-30 13:56:39 +00:00
BaseSession::FlushUpstream()
2018-11-14 19:34:17 +00:00
{
auto now = m_router->Now();
2018-11-14 19:34:17 +00:00
auto path = PickRandomEstablishedPath(llarp::path::ePathRoleExit);
if (path)
2018-11-28 16:38:20 +00:00
{
for (auto& item : m_Upstream)
{
2019-01-19 01:04:47 +00:00
auto& queue = item.second; // XXX: uninitialised memory here!
while (queue.size())
2018-12-27 12:00:28 +00:00
{
auto& msg = queue.front();
if (path)
{
2019-05-22 16:20:50 +00:00
msg.S = path->NextSeqNo();
path->SendRoutingMessage(msg, m_router);
}
2018-12-27 12:00:28 +00:00
queue.pop_front();
2019-05-06 17:32:53 +00:00
// spread across all paths
path = PickRandomEstablishedPath(llarp::path::ePathRoleExit);
2018-12-27 12:00:28 +00:00
}
}
2018-11-28 16:38:20 +00:00
}
2018-12-27 12:00:28 +00:00
else
{
if (m_Upstream.size())
2018-12-27 12:00:28 +00:00
llarp::LogWarn("no path for exit session");
// discard upstream
for (auto& item : m_Upstream)
2018-12-27 12:00:28 +00:00
item.second.clear();
m_Upstream.clear();
if (numHops == 1)
2019-05-03 13:15:03 +00:00
{
2019-08-02 09:27:27 +00:00
auto r = m_router;
2019-05-03 17:42:48 +00:00
RouterContact rc;
if (r->nodedb()->Get(m_ExitRouter, rc))
2019-05-03 17:42:48 +00:00
r->TryConnectAsync(rc, 5);
else
r->LookupRouter(m_ExitRouter, [r](const std::vector<RouterContact>& results) {
if (results.size())
r->TryConnectAsync(results[0], 5);
});
2019-05-03 13:15:03 +00:00
}
else if (UrgentBuild(now))
BuildOneAlignedTo(m_ExitRouter);
2018-12-27 12:00:28 +00:00
}
2019-04-30 13:56:39 +00:00
return true;
}
void
BaseSession::FlushDownstream()
{
while (m_Downstream.size())
2018-12-20 12:41:17 +00:00
{
if (m_WritePacket)
2018-12-20 12:41:17 +00:00
m_WritePacket(m_Downstream.top().second.ConstBuffer());
m_Downstream.pop();
}
2018-11-14 19:34:17 +00:00
}
SNodeSession::SNodeSession(
const llarp::RouterID& snodeRouter,
std::function<bool(const llarp_buffer_t&)> writepkt,
AbstractRouter* r,
size_t numpaths,
size_t hoplen,
bool useRouterSNodeKey,
bool bundleRC)
: BaseSession(snodeRouter, writepkt, r, numpaths, hoplen, bundleRC)
{
if (useRouterSNodeKey)
{
m_ExitIdentity = r->identity();
}
}
2019-03-22 14:10:30 +00:00
std::string
SNodeSession::Name() const
{
return "SNode::" + m_ExitRouter.ToString();
}
std::string
ExitSession::Name() const
{
return "Exit::" + m_ExitRouter.ToString();
}
2020-05-21 14:18:23 +00:00
void
SNodeSession::SendPacketToRemote(const llarp_buffer_t& buf)
{
net::IPPacket pkt;
if (not pkt.Load(buf))
return;
pkt.ZeroAddresses();
QueueUpstreamTraffic(std::move(pkt), llarp::routing::ExitPadSize);
}
void
ExitSession::SendPacketToRemote(const llarp_buffer_t& buf)
{
net::IPPacket pkt;
if (not pkt.Load(buf))
return;
pkt.ZeroSourceAddress();
QueueUpstreamTraffic(std::move(pkt), llarp::routing::ExitPadSize);
}
2018-11-14 19:34:17 +00:00
} // namespace exit
2018-12-10 15:31:58 +00:00
} // namespace llarp