lokinet/llarp/exit/session.cpp

295 lines
8.1 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 <nodedb.hpp>
2019-01-11 01:19:36 +00:00
#include <path/path.hpp>
#include <router/abstractrouter.hpp>
namespace llarp
{
namespace exit
{
BaseSession::BaseSession(
const llarp::RouterID& router,
std::function< bool(const llarp_buffer_t&) > writepkt,
AbstractRouter* r, size_t numpaths, size_t hoplen)
: llarp::path::Builder(r, r->dht(), numpaths, hoplen)
2018-11-14 19:34:17 +00:00
, m_ExitRouter(router)
, m_WritePacket(writepkt)
2018-11-29 21:19:20 +00:00
, m_Counter(0)
2018-12-13 12:27:14 +00:00
, m_LastUse(0)
2018-11-14 19:34:17 +00:00
{
r->crypto()->identity_keygen(m_ExitIdentity);
2018-11-14 19:34:17 +00:00
}
BaseSession::~BaseSession()
{
}
2019-03-30 13:02:10 +00:00
void
2019-03-30 13:12:48 +00:00
BaseSession::HandlePathDied(path::Path*)
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
{
2019-02-11 17:14:43 +00:00
auto obj = path::Builder::ExtractStatus();
obj.Put("lastExitUse", m_LastUse);
2019-02-08 19:43:25 +00:00
auto pub = m_ExitIdentity.toPublic();
2019-02-11 17:14:43 +00:00
obj.Put("exitIdentity", pub.ToString());
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
{
2018-11-25 16:58:27 +00:00
const size_t expect = (1 + (m_NumPaths / 2));
2018-12-27 12:00:28 +00:00
// check 30 seconds into the future and see if we need more paths
const llarp_time_t future = now + (30 * 1000);
if(NumPathsExistingAt(future) < expect)
return llarp::randint() % 4
== 0; // 25% chance for build if we will run out soon
// if we don't have the expended number of paths right now try building
// some if the cooldown timer isn't hit
2018-11-25 16:58:27 +00:00
if(AvailablePaths(llarp::path::ePathRoleExit) < expect)
return !path::Builder::BuildCooldownHit(now);
2018-12-27 12:00:28 +00:00
// maintain regular number of paths
return path::Builder::ShouldBuildMore(now);
}
2018-11-14 19:34:17 +00:00
bool
BaseSession::SelectHop(llarp_nodedb* db, const RouterContact& prev,
RouterContact& cur, size_t hop,
llarp::path::PathRole roles)
{
if(hop == numHops - 1)
2018-12-10 15:44:18 +00:00
{
return db->Get(m_ExitRouter, cur);
2018-12-10 15:44:18 +00:00
}
else if(hop == numHops - 2)
{
return db->select_random_hop_excluding(cur,
{prev.pubkey, m_ExitRouter});
}
2018-11-14 19:34:17 +00:00
else
return path::Builder::SelectHop(db, prev, cur, hop, roles);
}
void
BaseSession::HandlePathBuilt(llarp::path::Path* p)
{
2018-12-10 15:31:58 +00:00
path::Builder::HandlePathBuilt(p);
2018-11-14 19:34:17 +00:00
p->SetDropHandler(std::bind(&BaseSession::HandleTrafficDrop, this,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3));
2018-12-20 12:41:17 +00:00
p->SetExitTrafficHandler(
std::bind(&BaseSession::HandleTraffic, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3));
2018-11-14 19:34:17 +00:00
p->AddObtainExitHandler(std::bind(&BaseSession::HandleGotExit, this,
std::placeholders::_1,
std::placeholders::_2));
llarp::routing::ObtainExitMessage obtain;
obtain.S = p->NextSeqNo();
obtain.T = llarp::randint();
2018-11-29 13:12:35 +00:00
PopulateRequest(obtain);
if(!obtain.Sign(router->crypto(), m_ExitIdentity))
2018-11-14 19:34:17 +00:00
{
llarp::LogError("Failed to sign exit request");
return;
}
if(p->SendExitRequest(&obtain, router))
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* p, llarp_time_t b)
{
2019-03-07 15:17:29 +00:00
m_LastUse = router->Now();
2018-11-14 19:34:17 +00:00
if(b == 0)
llarp::LogInfo("obtained an exit via ", p->Endpoint());
2019-03-07 15:17:29 +00:00
if(IsReady())
CallPendingCallbacks(true);
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)
{
for(auto& f : m_PendingCallbacks)
f(this);
}
else
{
for(auto& f : m_PendingCallbacks)
f(nullptr);
}
m_PendingCallbacks.clear();
2018-11-14 19:34:17 +00:00
}
bool
BaseSession::Stop()
{
2019-03-07 15:17:29 +00:00
CallPendingCallbacks(false);
auto sendExitClose = [&](llarp::path::Path* p) {
if(p->SupportsAnyRoles(llarp::path::ePathRoleExit))
{
2018-12-24 16:12:20 +00:00
llarp::LogInfo(p->Name(), " closing exit path");
llarp::routing::CloseExitMessage msg;
if(!(msg.Sign(router->crypto(), m_ExitIdentity)
&& p->SendExitClose(&msg, router)))
2018-12-24 16:12:20 +00:00
llarp::LogWarn(p->Name(), " failed to send exit close message");
}
};
ForEachPath(sendExitClose);
return llarp::path::Builder::Stop();
}
2018-11-14 19:34:17 +00:00
bool
BaseSession::HandleTraffic(llarp::path::Path* p, const llarp_buffer_t& buf,
2018-12-20 12:41:17 +00:00
uint64_t counter)
2018-11-14 19:34:17 +00:00
{
(void)p;
if(m_WritePacket)
2018-12-13 12:27:14 +00:00
{
2018-12-20 12:41:17 +00:00
llarp::net::IPv4Packet pkt;
if(!pkt.Load(buf))
2018-12-13 12:27:14 +00:00
return false;
2018-12-20 12:41:17 +00:00
m_Downstream.emplace(counter, pkt);
2018-12-13 12:27:14 +00:00
m_LastUse = router->Now();
return true;
}
2018-11-14 19:34:17 +00:00
return false;
}
bool
BaseSession::HandleTrafficDrop(llarp::path::Path* p, const PathID_t& path,
uint64_t s)
{
(void)p;
llarp::LogError("dropped traffic on exit ", m_ExitRouter, " S=", s,
" P=", path);
return true;
}
bool
BaseSession::QueueUpstreamTraffic(llarp::net::IPv4Packet pkt,
const size_t N)
2018-11-28 16:38:20 +00:00
{
2019-02-02 23:12:42 +00:00
const llarp_buffer_t& buf = pkt.Buffer();
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)
{
queue.emplace_back();
return queue.back().PutBuffer(buf, m_Counter++);
2018-11-28 16:38:20 +00:00
}
else
2018-11-29 21:19:20 +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-03-07 15:17:29 +00:00
const size_t expect = (1 + (m_NumPaths / 2));
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
{
return m_LastUse && now > m_LastUse && now - m_LastUse > LifeSpan;
}
bool
2018-12-20 12:41:17 +00:00
BaseSession::Flush()
2018-11-14 19:34:17 +00:00
{
2018-12-13 12:27:14 +00:00
auto now = router->Now();
2018-11-14 19:34:17 +00:00
auto path = PickRandomEstablishedPath(llarp::path::ePathRoleExit);
2018-12-27 12:00:28 +00:00
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!
2018-12-27 12:00:28 +00:00
while(queue.size())
{
auto& msg = queue.front();
msg.S = path->NextSeqNo();
if(path->SendRoutingMessage(&msg, router))
m_LastUse = now;
queue.pop_front();
}
}
2018-11-28 16:38:20 +00:00
}
2018-12-27 12:00:28 +00:00
else
{
if(m_Upstream.size())
llarp::LogWarn("no path for exit session");
// discard upstream
for(auto& item : m_Upstream)
item.second.clear();
m_Upstream.clear();
}
2018-12-20 12:41:17 +00:00
while(m_Downstream.size())
{
if(m_WritePacket)
m_WritePacket(m_Downstream.top().second.ConstBuffer());
m_Downstream.pop();
}
2018-11-28 16:38:20 +00:00
return true;
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)
: BaseSession(snodeRouter, writepkt, r, numpaths, hoplen)
{
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();
}
2018-11-14 19:34:17 +00:00
} // namespace exit
2018-12-10 15:31:58 +00:00
} // namespace llarp