From e88a1102e2fcf498cdf6d942723743953dd0e15d Mon Sep 17 00:00:00 2001 From: Ryan Tharp Date: Mon, 18 Jun 2018 01:35:57 -0700 Subject: [PATCH] pathfinder interface design --- include/llarp/pathfinder.h | 52 ++++++++ llarp/pathfinder.cpp | 250 +++++++++++++++++++++++++++++++++++++ llarp/pathfinder.hpp | 12 ++ 3 files changed, 314 insertions(+) create mode 100644 include/llarp/pathfinder.h create mode 100644 llarp/pathfinder.cpp create mode 100644 llarp/pathfinder.hpp diff --git a/include/llarp/pathfinder.h b/include/llarp/pathfinder.h new file mode 100644 index 000000000..c5ddd33f1 --- /dev/null +++ b/include/llarp/pathfinder.h @@ -0,0 +1,52 @@ +#ifndef LLARP_PATHFINDER_H_ +#define LLARP_PATHFINDER_H_ + +#include +#include +#include + +/** + * path_base.h + * + * path api functions + */ + +#ifdef __cplusplus +extern "C" { +#endif + +// fwd declr +struct llarp_pathfinder_context; + +/// alloc +struct llarp_pathfinder_context * + llarp_pathfinder_context_new(struct llarp_router* router, + struct llarp_dht_context* dht); +/// dealloc +void + llarp_pathfinder_context_free(struct llarp_pathfinder_context* ctx); + +// fwd declr +struct llarp_get_route; + +/// response callback +typedef void (*llarp_pathfinder_response)(struct llarp_get_route *); + +// request struct +struct llarp_get_route +{ + // context + struct llarp_pathfinder_context* pathfinder; + // parameter + byte_t destination[PUBKEYSIZE]; + // result + std::vector route; +}; +/// request func +// or find_path but thought pathfinder_find_path was a bit redundant +void llarp_pathfinder_get_route(struct llarp_pathfinder_context* pathfinder); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/llarp/pathfinder.cpp b/llarp/pathfinder.cpp new file mode 100644 index 000000000..9d2270622 --- /dev/null +++ b/llarp/pathfinder.cpp @@ -0,0 +1,250 @@ +#include +#include +#include +#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; + std::deque< EncryptedFrame > frames; + std::deque< EncryptedAck > acks; + EncryptedFrame lastFrame; + PathContext* context; + RouterID from; + LR_CommitRecord record; + TransitHopInfo info; + TransitHop hop; + + LRCMFrameDecrypt(PathContext* ctx, Decrypter* dec, + const LR_CommitMessage* commit) + : decrypter(dec) + , lastFrame(commit->lasthopFrame) + , context(ctx) + , from(commit->remote) + { + for(const auto& f : commit->frames) + frames.push_front(f); + for(const auto& a : commit->acks) + acks.push_front(a); + } + + ~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; + } + + static void + HandleDecrypted(llarp_buffer_t* buf, LRCMFrameDecrypt* self) + { + 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)) + { + 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)) + { + llarp::Error("duplicate transit hop ", self->info); + delete self; + return; + } + // choose rx id + // TODO: check for duplicates + self->info.rxID.Randomize(); + + // 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, + self->context->EncryptionSecretKey(), self->record.tunnelNonce)) + { + llarp::Error("LRCM DH Failed ", self->info); + 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; + } + else + { + // TODO: generate rx path + + // forward upstream + // XXX: we are still in the worker thread so post job to logic + llarp_logic_queue_job(self->context->Logic(), {self, &AcceptLRCM}); + } + } + }; + + 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 + decrypter->AsyncDecrypt(m_Router->tp, &frames->frames.front(), frames); + + return true; + } + + llarp_threadpool* + PathContext::Worker() + { + return m_Router->tp; + } + + llarp_crypto* + PathContext::Crypto() + { + return &m_Router->crypto; + } + + llarp_logic* + PathContext::Logic() + { + return m_Router->logic; + } + + 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(); + } + while(acks.size()) + { + msg->acks.push_back(acks.back()); + acks.pop_back(); + } + 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; + } + + bool + PathContext::HasTransitHop(const TransitHopInfo& info) + { + 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)); + } + + TransitHopInfo::TransitHopInfo(const RouterID& down, + const LR_CommitRecord& record) + : txID(record.txid), upstream(record.nextHop), downstream(down) + { + } +} \ No newline at end of file diff --git a/llarp/pathfinder.hpp b/llarp/pathfinder.hpp new file mode 100644 index 000000000..910076391 --- /dev/null +++ b/llarp/pathfinder.hpp @@ -0,0 +1,12 @@ +#ifndef LLARP_PATHFINDER_HPP_ +#define LLARP_PATHFINDER_HPP_ +#include + +struct llarp_pathfinder_context { + struct llarp_router* router; + struct llarp_dht_context* dht; + /// copy cstr + llarp_pathfinder_context(llarp_router *p_router, struct llarp_dht_context* p_dht); +}; + +#endif