lokinet/llarp/path.cpp

250 lines
6.5 KiB
C++
Raw Normal View History

2018-06-12 16:45:12 +00:00
#include <deque>
2018-06-10 14:05:48 +00:00
#include <llarp/encrypted_frame.hpp>
#include <llarp/path.hpp>
#include "router.hpp"
namespace llarp
{
PathContext::PathContext(llarp_router* router)
: m_Router(router), m_AllowTransit(false)
{
}
PathContext::~PathContext()
{
}
void
PathContext::AllowTransit()
{
m_AllowTransit = true;
}
struct LRCMFrameDecrypt
{
typedef AsyncFrameDecrypter< LRCMFrameDecrypt > Decrypter;
Decrypter* decrypter;
2018-06-12 16:45:12 +00:00
std::deque< EncryptedFrame > frames;
std::deque< EncryptedAck > acks;
EncryptedFrame lastFrame;
2018-06-10 14:05:48 +00:00
PathContext* context;
RouterID from;
LR_CommitRecord record;
TransitHopInfo info;
TransitHop hop;
2018-06-10 14:05:48 +00:00
LRCMFrameDecrypt(PathContext* ctx, Decrypter* dec,
const LR_CommitMessage* commit)
2018-06-12 16:45:12 +00:00
: decrypter(dec)
, lastFrame(commit->lasthopFrame)
, context(ctx)
, from(commit->remote)
2018-06-10 14:05:48 +00:00
{
2018-06-12 16:45:12 +00:00
for(const auto& f : commit->frames)
frames.push_front(f);
for(const auto& a : commit->acks)
acks.push_front(a);
2018-06-10 14:05:48 +00:00
}
~LRCMFrameDecrypt()
{
delete decrypter;
}
static void
AcceptLRCM(void* user)
{
LRCMFrameDecrypt* self = static_cast< LRCMFrameDecrypt* >(user);
llarp::Info("Accepted ", self->info);
self->context->PutPendingRelayCommit(self->info.upstream, self->info.txID,
self->info, self->hop);
size_t sz = self->frames.front().size;
// we pop the front element it was ours
self->frames.pop_front();
// put random on the end
// TODO: should this be an encrypted frame?
// TODO: should we change the size?
self->frames.emplace_back(sz);
self->frames.back().Randomize();
self->context->ForwardLRCM(self->info.upstream, self->frames, self->acks,
self->lastFrame);
delete self;
}
2018-06-10 14:05:48 +00:00
static void
HandleDecrypted(llarp_buffer_t* buf, LRCMFrameDecrypt* self)
{
2018-06-12 16:45:12 +00:00
if(!buf)
{
llarp::Error("LRCM decrypt failed from ", self->from);
delete self;
return;
}
llarp::Debug("decrypted LRCM from ", self->from);
// successful decrypt
if(!self->record.BDecode(buf))
2018-06-10 14:05:48 +00:00
{
2018-06-12 16:45:12 +00:00
llarp::Error("malformed frame inside LRCM from ", self->from);
delete self;
return;
}
self->info = TransitHopInfo(self->from, self->record);
if(self->context->HasTransitHop(self->info))
2018-06-12 16:45:12 +00:00
{
llarp::Error("duplicate transit hop ", self->info);
2018-06-12 16:45:12 +00:00
delete self;
return;
}
// choose rx id
// TODO: check for duplicates
self->info.rxID.Randomize();
2018-06-12 16:45:12 +00:00
// generate tx key as we are in a worker thread
auto DH = self->context->Crypto()->dh_server;
if(!DH(self->hop.txKey, self->record.commkey,
2018-06-12 16:45:12 +00:00
self->context->EncryptionSecretKey(), self->record.tunnelNonce))
{
llarp::Error("LRCM DH Failed ", self->info);
2018-06-12 16:45:12 +00:00
delete self;
return;
}
if(self->context->HopIsUs(self->record.nextHop))
{
// we are the farthest hop
llarp::Info("We are the farthest hop for ", self->info);
// TODO: implement
delete self;
2018-06-10 14:05:48 +00:00
}
else
2018-06-12 16:45:12 +00:00
{
// TODO: generate rx path
2018-06-12 16:45:12 +00:00
// forward upstream
// XXX: we are still in the worker thread so post job to logic
llarp_logic_queue_job(self->context->Logic(), {self, &AcceptLRCM});
2018-06-12 16:45:12 +00:00
}
2018-06-10 14:05:48 +00:00
}
};
bool
PathContext::HandleRelayCommit(const LR_CommitMessage* commit)
{
if(!m_AllowTransit)
{
llarp::Error("got LRCM from ", commit->remote,
" when not allowing transit traffic");
return false;
}
if(commit->frames.size() <= 1)
{
llarp::Error("got LRCM with too few frames from ", commit->remote);
return false;
}
LRCMFrameDecrypt::Decrypter* decrypter =
new LRCMFrameDecrypt::Decrypter(&m_Router->crypto, m_Router->encryption,
&LRCMFrameDecrypt::HandleDecrypted);
// copy frames so we own them
LRCMFrameDecrypt* frames = new LRCMFrameDecrypt(this, decrypter, commit);
// decrypt frames async
2018-06-12 16:45:12 +00:00
decrypter->AsyncDecrypt(m_Router->tp, &frames->frames.front(), frames);
2018-06-10 14:05:48 +00:00
return true;
}
2018-06-12 16:45:12 +00:00
llarp_threadpool*
PathContext::Worker()
{
return m_Router->tp;
}
llarp_crypto*
PathContext::Crypto()
{
return &m_Router->crypto;
}
llarp_logic*
PathContext::Logic()
{
return m_Router->logic;
}
2018-06-12 16:45:12 +00:00
byte_t*
PathContext::EncryptionSecretKey()
{
return m_Router->encryption;
}
bool
PathContext::HopIsUs(const PubKey& k) const
{
return memcmp(k, m_Router->pubkey(), PUBKEYSIZE) == 0;
}
bool
PathContext::ForwardLRCM(const RouterID& nextHop,
std::deque< EncryptedFrame >& frames,
std::deque< EncryptedAck >& acks,
EncryptedFrame& lastHop)
{
LR_CommitMessage* msg = new LR_CommitMessage;
while(frames.size())
{
msg->frames.push_back(frames.back());
frames.pop_back();
2018-06-12 16:45:12 +00:00
}
while(acks.size())
{
msg->acks.push_back(acks.back());
acks.pop_back();
2018-06-12 16:45:12 +00:00
}
msg->lasthopFrame = lastHop;
return m_Router->SendToOrQueue(nextHop, {msg});
}
template < typename Map_t, typename Value_t >
bool
MapHas(Map_t& map, const Value_t& val)
{
std::unique_lock< std::mutex > lock(map.first);
return map.second.find(val) != map.second.end();
}
template < typename Map_t, typename Key_t, typename Value_t >
void
MapPut(Map_t& map, const Key_t& k, const Value_t& v)
{
std::unique_lock< std::mutex > lock(map.first);
map.second[k] = v;
}
2018-06-10 14:05:48 +00:00
bool
PathContext::HasTransitHop(const TransitHopInfo& info)
{
2018-06-12 16:45:12 +00:00
return MapHas(m_TransitPaths, info);
}
void
PathContext::PutPendingRelayCommit(const RouterID& upstream,
const PathID_t& txid,
const TransitHopInfo& info,
const TransitHop& hop)
{
MapPut(m_WaitingForAcks, PendingPathKey(upstream, txid),
std::make_pair(info, hop));
}
bool
PathContext::HasPendingRelayCommit(const RouterID& upstream,
const PathID_t& txid)
{
return MapHas(m_WaitingForAcks, PendingPathKey(upstream, txid));
2018-06-10 14:05:48 +00:00
}
TransitHopInfo::TransitHopInfo(const RouterID& down,
const LR_CommitRecord& record)
: txID(record.txid), upstream(record.nextHop), downstream(down)
{
}
}