(upstream repo was broken)
pull/1/head
Ryan Tharp 6 years ago
commit 9dff277a7e

@ -125,6 +125,7 @@ set(LIB_SRC
llarp/nodedb.cpp
llarp/path.cpp
llarp/pathbuilder.cpp
llarp/path_confirm.cpp
llarp/proofofwork.cpp
llarp/relay_ack.cpp
llarp/relay_commit.cpp
@ -132,6 +133,7 @@ set(LIB_SRC
llarp/router_contact.cpp
llarp/router.cpp
llarp/threadpool.cpp
llarp/transit_hop.cpp
llarp/testnet.c
llarp/time.cpp
llarp/timer.cpp

@ -294,7 +294,8 @@ the path is extended by w.y seconds
c: "<32 byte public encryption key used for upstream>",
i: "<32 byte RC.k of next hop>",
n: "<32 bytes nounce for key exchange>",
p: "<16 bytes path id>",
r: "<16 bytes rx path id>",
t: "<16 bytes tx path id>",
v: 0,
w: proof of work
}
@ -427,18 +428,34 @@ originated from inside a LRDM.
ipv4 addresses are allowed via ipv4 mapped ipv6 addresses, i.e. ::ffff.10.0.0.1
path data message (PDM)
path confirm message (PCM)
sent as the first message down a path after it's built to confirm it was built
{
A: "P",
L: uint64_milliseconds_path_lifetime,
S: uint64_milliseconds_sent_timestamp,
V: 0
}
path latency message (PLM)
intermediate path data
forward N as LRUM if we got it in a LRUM
forward N as LRDM if we got it in a LRDM
a latency measurement message, reply with a PLM response if we are the far end of a path.
variant 1, request, generated by the path creator:
{
A: "D",
D: "<N bytes payload here>",
N: "<32 bytes next nonce>",
P: "<16 bytes next path id>",
R: number_of_bytes_Z_padding,
A: "L",
T: uint64_ping_transaction_id,
V: 0
}
variant 2, response, generated by the endpoint that recieved the request.
{
A: "L",
L: uint64_ping_transaction_id,
V: 0
}
@ -450,8 +467,10 @@ replies are sent down the path that messages originate from.
{
A: "X",
I: "<32 bytes signing public key for future communication>",
T: uint64_transaction_id,
V: 0,
X: lifetime_of_address_mapping_in_seconds_uint64,
Z: "<64 bytes signature using I>"
}
grant exit address messsage (GXAM)
@ -520,14 +539,13 @@ transfer data between paths.
{
A: "T",
P: path_id_uint64,
V: 0,
X: "<N bytes payload>",
Y: "<24 bytes nounce>",
Z: "<64 bytes signature>"
P: "<16 bytes path id>",
T: "<N bytes data>",
V: 0,
Y: "<32 bytes nounce>",
}
transfer data to another path with id P on the local router place Y and X values
transfer data to another path with id P on the local router place Y and T values
into y and z values into a LRDM message (respectively) and send it in the
downstream direction.

@ -19,6 +19,12 @@ namespace llarp
AlignedBuffer() = default;
AlignedBuffer(const AlignedBuffer& other)
{
for(size_t idx = 0; idx < (sz / 8); ++idx)
l[idx] = other.l[idx];
}
AlignedBuffer(const byte_t* data)
{
for(size_t idx = 0; idx < sz; ++idx)

@ -30,6 +30,9 @@ namespace llarp
{
}
bool
IsZero() const;
Key_t
operator^(const Key_t& other) const
{
@ -46,6 +49,8 @@ namespace llarp
}
};
extern Key_t ZeroKey;
struct Node
{
llarp_rc* rc;
@ -69,8 +74,9 @@ namespace llarp
SearchJob();
SearchJob(const Key_t& requestor, const Key_t& target,
llarp_router_lookup_job* job);
SearchJob(const Key_t& requester, uint64_t requesterTX,
const Key_t& target, llarp_router_lookup_job* job,
const std::set< Key_t >& excludes);
void
Completed(const llarp_rc* router, bool timeout = false) const;
@ -80,7 +86,8 @@ namespace llarp
llarp_router_lookup_job* job = nullptr;
llarp_time_t started;
Key_t requestor;
Key_t requester;
uint64_t requesterTX;
Key_t target;
std::set< Key_t > exclude;
};
@ -163,15 +170,16 @@ namespace llarp
void
LookupRouter(const Key_t& target, const Key_t& whoasked,
const Key_t& askpeer,
llarp_router_lookup_job* job = nullptr);
uint64_t whoaskedTX, const Key_t& askpeer,
llarp_router_lookup_job* job = nullptr,
bool iterative = false, std::set< Key_t > excludes = {});
void
LookupRouterViaJob(llarp_router_lookup_job* job);
void
LookupRouterRelayed(const Key_t& requester, uint64_t txid,
const Key_t& target,
const Key_t& target, bool recursive,
std::vector< IMessage* >& replies);
void
@ -190,6 +198,12 @@ namespace llarp
Bucket* nodes = nullptr;
bool allowTransit = false;
const Key_t&
OurKey() const
{
return ourKey;
}
private:
void
ScheduleCleanupTimer();
@ -201,18 +215,18 @@ namespace llarp
struct TXOwner
{
Key_t requester;
Key_t node;
uint64_t txid = 0;
bool
operator==(const TXOwner& other) const
{
return txid == other.txid && requester == other.requester;
return txid == other.txid && node == other.node;
}
bool
operator<(const TXOwner& other) const
{
return txid < other.txid && requester < other.requester;
return txid < other.txid || node < other.node;
}
};
@ -222,7 +236,7 @@ namespace llarp
operator()(TXOwner const& o) const noexcept
{
std::size_t sz2;
memcpy(&sz2, &o.requester[0], sizeof(std::size_t));
memcpy(&sz2, &o.node[0], sizeof(std::size_t));
return o.txid ^ (sz2 << 1);
}
};
@ -288,6 +302,7 @@ namespace llarp
std::vector< IMessage* >& replies) const;
Key_t K;
bool iterative = false;
uint64_t txid = 0;
uint64_t version = 0;
};

@ -12,7 +12,7 @@ namespace llarp
struct Encrypted
{
Encrypted(Encrypted&&) = delete;
Encrypted();
Encrypted(const byte_t* buf, size_t sz);
Encrypted(size_t sz);
~Encrypted();
@ -23,6 +23,18 @@ namespace llarp
return bencode_write_bytestring(buf, _data, _sz);
}
Encrypted&
operator=(llarp_buffer_t buf)
{
if(_data)
delete[] _data;
_sz = buf.sz;
_data = new byte_t[_sz];
memcpy(_data, buf.base, _sz);
UpdateBuffer();
return *this;
}
void
Fill(byte_t fill)
{
@ -61,6 +73,12 @@ namespace llarp
return &m_Buffer;
}
llarp_buffer_t
Buffer() const
{
return m_Buffer;
}
size_t
size()
{

@ -12,4 +12,6 @@
#include <llarp/messages/relay_ack.hpp>
#include <llarp/messages/relay_commit.hpp>
#include <llarp/messages/path_confirm.hpp>
#endif

@ -0,0 +1,30 @@
#ifndef LLARP_MESSAGE_PATH_CONFIRM_HPP
#define LLARP_MESSAGE_PATH_CONFIRM_HPP
#include <llarp/routing_message.hpp>
namespace llarp
{
namespace routing
{
struct PathConfirmMessage : public IMessage
{
uint64_t pathLifetime;
uint64_t pathCreated;
PathConfirmMessage(uint64_t lifetime);
~PathConfirmMessage(){};
bool
BEncode(llarp_buffer_t* buf) const;
bool
BDecode(llarp_buffer_t* buf);
bool
HandleMessage(llarp_router* r) const;
};
} // namespace routing
} // namespace llarp
#endif

@ -2,10 +2,20 @@
#define LLARP_MESSAGES_RELAY_HPP
#include <llarp/link_message.hpp>
#include <llarp/crypto.hpp>
#include <llarp/encrypted.hpp>
#include <llarp/path_types.hpp>
#include <vector>
namespace llarp
{
struct RelayUpstreamMessage : public ILinkMessage
{
PathID_t pathid;
Encrypted X;
TunnelNonce Y;
RelayUpstreamMessage();
RelayUpstreamMessage(const RouterID& from);
~RelayUpstreamMessage();
@ -21,6 +31,10 @@ namespace llarp
struct RelayDownstreamMessage : public ILinkMessage
{
PathID_t pathid;
Encrypted X;
TunnelNonce Y;
RelayDownstreamMessage();
RelayDownstreamMessage(const RouterID& from);
~RelayDownstreamMessage();
@ -33,6 +47,6 @@ namespace llarp
bool
HandleMessage(llarp_router* router) const;
};
}
} // namespace llarp
#endif

@ -18,7 +18,8 @@ namespace llarp
PubKey commkey;
RouterID nextHop;
TunnelNonce tunnelNonce;
PathID_t pathid;
PathID_t txid, rxid;
PoW *work = nullptr;
uint64_t version = 0;

@ -6,10 +6,11 @@
#include <llarp/aligned.hpp>
#include <llarp/crypto.hpp>
#include <llarp/endpoint.hpp>
#include <llarp/messages/relay_ack.hpp>
#include <llarp/messages/relay.hpp>
#include <llarp/messages/relay_commit.hpp>
#include <llarp/path_types.hpp>
#include <llarp/router_id.hpp>
#include <llarp/routing_message.hpp>
#include <list>
#include <map>
@ -17,21 +18,24 @@
#include <unordered_map>
#include <vector>
#define DEFAULT_PATH_LIFETIME (10 * 60 * 1000)
namespace llarp
{
struct TransitHopInfo
{
TransitHopInfo() = default;
TransitHopInfo(const TransitHopInfo& other);
TransitHopInfo(const RouterID& down, const LR_CommitRecord& record);
PathID_t pathID;
PathID_t txID, rxID;
RouterID upstream;
RouterID downstream;
friend std::ostream&
operator<<(std::ostream& out, const TransitHopInfo& info)
{
out << "<Transit Hop id=" << info.pathID;
out << "<tx=" << info.txID << " rx=" << info.rxID;
out << " upstream=" << info.upstream << " downstream=" << info.downstream;
return out << ">";
}
@ -39,8 +43,8 @@ namespace llarp
bool
operator==(const TransitHopInfo& other) const
{
return pathID == other.pathID && upstream == other.upstream
&& downstream == other.downstream;
return txID == other.txID && rxID == other.rxID
&& upstream == other.upstream && downstream == other.downstream;
}
bool
@ -52,7 +56,7 @@ namespace llarp
bool
operator<(const TransitHopInfo& other) const
{
return pathID < other.pathID || upstream < other.upstream
return txID < other.txID || rxID < other.rxID || upstream < other.upstream
|| downstream < other.downstream;
}
@ -61,10 +65,11 @@ namespace llarp
std::size_t
operator()(TransitHopInfo const& a) const
{
std::size_t idx0, idx1, idx2;
std::size_t idx0, idx1, idx2, idx3;
memcpy(&idx0, a.upstream, sizeof(std::size_t));
memcpy(&idx1, a.downstream, sizeof(std::size_t));
memcpy(&idx2, a.pathID, sizeof(std::size_t));
memcpy(&idx2, a.txID, sizeof(std::size_t));
memcpy(&idx3, a.rxID, sizeof(std::size_t));
return idx0 ^ idx1 ^ idx2;
}
};
@ -81,34 +86,67 @@ namespace llarp
}
};
struct TransitHop
struct IHopHandler
{
virtual ~IHopHandler(){};
virtual bool
Expired(llarp_time_t now) const = 0;
virtual bool
SendRoutingMessage(const llarp::routing::IMessage* msg,
llarp_router* r) = 0;
// handle data in upstream direction
virtual bool
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r) = 0;
// handle data in downstream direction
virtual bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y,
llarp_router* r) = 0;
};
struct TransitHop : public IHopHandler
{
TransitHop() = default;
TransitHop(const TransitHop& other);
TransitHopInfo info;
SharedSecret pathKey;
llarp_time_t started;
llarp_time_t started = 0;
// 10 minutes default
llarp_time_t lifetime = 360000;
llarp_time_t lifetime = DEFAULT_PATH_LIFETIME;
llarp_proto_version_t version;
friend std::ostream&
operator<<(std::ostream& out, const TransitHop& h)
{
return out << "[TransitHop " << h.info << " started=" << h.started
<< " lifetime=" << h.lifetime << "]";
}
bool
Expired(llarp_time_t now) const;
// forward data in upstream direction
void
ForwardUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
bool
SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r);
// forward data in downstream direction
void
ForwardDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
// handle data in upstream direction
bool
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
// handle data in downstream direction
bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
};
/// configuration for a single hop when building a path
struct PathHopConfig
{
/// path id
PathID_t pathID;
PathID_t txID, rxID;
// router contact of router
llarp_rc router;
// temp public encryption key
@ -119,6 +157,8 @@ namespace llarp
RouterID upstream;
/// nonce for key exchange
TunnelNonce nonce;
// lifetime
llarp_time_t lifetime = DEFAULT_PATH_LIFETIME;
~PathHopConfig();
PathHopConfig();
@ -133,7 +173,7 @@ namespace llarp
};
/// A path we made
struct Path
struct Path : public IHopHandler
{
typedef std::vector< PathHopConfig > HopList;
HopList hops;
@ -142,17 +182,28 @@ namespace llarp
Path(llarp_path_hops* path);
void
EncryptAndSend(llarp_buffer_t buf, llarp_router* r);
bool
Expired(llarp_time_t now) const;
void
DecryptAndRecv(llarp_buffer_t buf, IEndpointHandler* handler);
bool
SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r);
bool
HandleRoutingMessage(llarp_buffer_t buf, llarp_router* r);
// handle data in upstream direction
bool
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
// handle data in downstream direction
bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
const PathID_t&
PathID() const;
RouterID
Upstream();
Upstream() const;
};
enum PathBuildStatus
@ -185,11 +236,14 @@ namespace llarp
bool
HandleRelayCommit(const LR_CommitMessage* msg);
bool
HandleRelayAck(const LR_AckMessage* msg);
void
PutTransitHop(const TransitHop& hop);
PutTransitHop(TransitHop* hop);
IHopHandler*
GetByUpstream(const RouterID& id, const PathID_t& path);
IHopHandler*
GetDownstream(const RouterID& id, const PathID_t& path);
bool
ForwardLRCM(const RouterID& nextHop, std::deque< EncryptedFrame >& frames);
@ -197,11 +251,16 @@ namespace llarp
bool
HopIsUs(const PubKey& k) const;
bool
HandleLRUM(const RelayUpstreamMessage* msg);
bool
HandleLRDM(const RelayDownstreamMessage* msg);
void
AddOwnPath(Path* p);
typedef std::unordered_multimap< PathID_t, TransitHop, PathIDHash >
TransitHopsMap_t;
typedef std::multimap< PathID_t, TransitHop* > TransitHopsMap_t;
typedef std::pair< std::mutex, TransitHopsMap_t > SyncTransitMap_t;
@ -218,6 +277,9 @@ namespace llarp
llarp_logic*
Logic();
llarp_router*
Router();
byte_t*
EncryptionSecretKey();
@ -227,6 +289,7 @@ namespace llarp
private:
llarp_router* m_Router;
SyncTransitMap_t m_TransitPaths;
SyncTransitMap_t m_Paths;
SyncOwnedPathsMap_t m_OurPaths;
bool m_AllowTransit;

@ -0,0 +1,30 @@
#ifndef LLARP_ROUTING_MESSAGE_HPP
#define LLARP_ROUTING_MESSAGE_HPP
#include <llarp/buffer.h>
#include <llarp/router.h>
#include <llarp/path_types.hpp>
namespace llarp
{
namespace routing
{
struct IMessage
{
llarp::PathID_t from;
virtual ~IMessage(){};
virtual bool
BEncode(llarp_buffer_t* buf) const = 0;
virtual bool
BDecode(llarp_buffer_t* buf) = 0;
virtual bool
HandleMessage(llarp_router* r) const = 0;
};
} // namespace routing
} // namespace llarp
#endif

@ -81,6 +81,14 @@ namespace llarp
namespace dht
{
Key_t ZeroKey;
bool
Key_t::IsZero() const
{
return memcmp(l, ZeroKey.l, 32) == 0;
}
GotRouterMessage::~GotRouterMessage()
{
for(auto &rc : R)
@ -115,7 +123,20 @@ namespace llarp
bool
GotRouterMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
{
return false;
if(llarp_buffer_eq(key, "R"))
{
return BEncodeReadList(R, val);
}
if(llarp_buffer_eq(key, "T"))
{
return bencode_read_integer(val, &txid);
}
bool read = false;
if(!BEncodeMaybeReadVersion("V", version, LLARP_PROTO_VERSION, read, key,
val))
return false;
return read;
}
bool
@ -127,22 +148,41 @@ namespace llarp
if(pending)
{
if(R.size())
{
pending->Completed(&R[0]);
if(pending->requester != dht.OurKey())
{
replies.push_back(new GotRouterMessage(
pending->target, pending->requesterTX, &R[0]));
}
}
else
{
// iterate to next closest peer
Key_t nextPeer;
pending->exclude.insert(From);
if(dht.nodes->FindCloseExcluding(pending->target, nextPeer,
pending->exclude))
if(pending->exclude.size() < 3
&& dht.nodes->FindCloseExcluding(pending->target, nextPeer,
pending->exclude))
{
llarp::Info(pending->target, "was not found via ", From,
" iterating to next peer ", nextPeer);
dht.LookupRouter(pending->target, pending->requestor, nextPeer,
pending->job);
llarp::Info(pending->target, " was not found via ", From,
" iterating to next peer ", nextPeer, " already asked ",
pending->exclude.size(), " other peers");
dht.LookupRouter(pending->target, pending->requester,
pending->requesterTX, nextPeer, nullptr, true,
pending->exclude);
}
else
{
llarp::Info(pending->target, " was not found via ", From,
" and we won't look it up");
pending->Completed(nullptr);
if(pending->requester != dht.OurKey())
{
replies.push_back(new GotRouterMessage(
pending->target, pending->requesterTX, nullptr));
}
}
}
dht.RemovePendingLookup(From, txid);
return true;
@ -168,6 +208,12 @@ namespace llarp
if(!bencode_write_bytestring(buf, "R", 1))
return false;
// iterative or not?
if(!bencode_write_bytestring(buf, "I", 1))
return false;
if(!bencode_write_int(buf, iterative ? 1 : 0))
return false;
// key
if(!bencode_write_bytestring(buf, "K", 1))
return false;
@ -193,6 +239,16 @@ namespace llarp
FindRouterMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
{
llarp_buffer_t strbuf;
if(llarp_buffer_eq(key, "I"))
{
uint64_t result;
if(!bencode_read_integer(val, &result))
return false;
iterative = result != 0;
return true;
}
if(llarp_buffer_eq(key, "K"))
{
if(!bencode_read_string(val, &strbuf))
@ -231,7 +287,7 @@ namespace llarp
llarp::Warn("Got duplicate DHT lookup from ", From, " txid=", txid);
return false;
}
dht.LookupRouterRelayed(From, txid, K, replies);
dht.LookupRouterRelayed(From, txid, K, !iterative, replies);
return true;
}
@ -342,13 +398,19 @@ namespace llarp
SearchJob::SearchJob()
{
started = 0;
requestor.Zero();
requester.Zero();
target.Zero();
}
SearchJob::SearchJob(const Key_t &asker, const Key_t &key,
llarp_router_lookup_job *j)
: job(j), started(llarp_time_now_ms()), requestor(asker), target(key)
SearchJob::SearchJob(const Key_t &asker, uint64_t tx, const Key_t &key,
llarp_router_lookup_job *j,
const std::set< Key_t > &excludes)
: job(j)
, started(llarp_time_now_ms())
, requester(asker)
, requesterTX(tx)
, target(key)
, exclude(excludes)
{
}
@ -449,7 +511,7 @@ namespace llarp
void
Context::LookupRouterRelayed(const Key_t &requester, uint64_t txid,
const Key_t &target,
const Key_t &target, bool recursive,
std::vector< IMessage * > &replies)
{
if(target == ourKey)
@ -458,33 +520,57 @@ namespace llarp
replies.push_back(new GotRouterMessage(requester, txid, &router->rc));
return;
}
Key_t next = ourKey;
nodes->FindClosest(target, next);
if(next == ourKey)
Key_t next;
std::set< Key_t > excluding = {requester, ourKey};
if(nodes->FindCloseExcluding(target, next, excluding))
{
// we are closest and don't have a match
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
return;
if(next == target)
{
// we know it
replies.push_back(
new GotRouterMessage(requester, txid, nodes->nodes[target].rc));
}
else if(recursive) // are we doing a recursive lookup?
{
if((requester ^ target) < (ourKey ^ target))
{
// we aren't closer to the target than next hop
// so we won't ask neighboor recursively, tell them we don't have it
llarp::Info("we aren't closer to ", target, " than ", next,
" so we end it here");
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
}
else
{
// yeah, ask neighboor recursively
LookupRouter(target, requester, txid, next);
}
}
else // otherwise tell them we don't have it
{
llarp::Info("we don't have ", target,
" and this was an iterative request so telling ",
requester, " that we don't have it");
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
}
}
if(next == target)
else
{
// we know it
replies.push_back(
new GotRouterMessage(requester, txid, nodes->nodes[target].rc));
return;
// we don't know it and have no closer peers
llarp::Info("we don't have ", target,
" and have no closer peers so telling ", requester,
" that we don't have it");
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
}
// ask neighbor
LookupRouter(target, requester, next);
}
void
Context::RemovePendingLookup(const Key_t &owner, uint64_t id)
{
TXOwner search;
search.requester = owner;
search.txid = id;
auto itr = pendingTX.find(search);
search.node = owner;
search.txid = id;
auto itr = pendingTX.find(search);
if(itr == pendingTX.end())
return;
pendingTX.erase(itr);
@ -494,9 +580,9 @@ namespace llarp
Context::FindPendingTX(const Key_t &owner, uint64_t id)
{
TXOwner search;
search.requester = owner;
search.txid = id;
auto itr = pendingTX.find(search);
search.node = owner;
search.txid = id;
auto itr = pendingTX.find(search);
if(itr == pendingTX.end())
return nullptr;
else
@ -508,16 +594,17 @@ namespace llarp
{
auto now = llarp_time_now_ms();
llarp::Debug("DHT tick");
std::set< TXOwner > expired;
for(auto &item : pendingTX)
if(item.second.IsExpired(now))
expired.insert(item.first);
for(const auto &e : expired)
auto itr = pendingTX.begin();
while(itr != pendingTX.end())
{
pendingTX[e].Completed(nullptr, true);
RemovePendingLookup(e.requester, e.txid);
if(itr->second.IsExpired(now))
{
itr->second.Completed(nullptr, true);
itr = pendingTX.erase(itr);
}
else
++itr;
}
}
@ -539,20 +626,29 @@ namespace llarp
void
Context::LookupRouter(const Key_t &target, const Key_t &whoasked,
const Key_t &askpeer, llarp_router_lookup_job *job)
uint64_t txid, const Key_t &askpeer,
llarp_router_lookup_job *job, bool iterative,
std::set< Key_t > excludes)
{
if(target.IsZero() || whoasked.IsZero() || askpeer.IsZero())
{
return;
}
auto id = ++ids;
TXOwner ownerKey;
ownerKey.requester = whoasked;
ownerKey.txid = id;
ownerKey.node = askpeer;
ownerKey.txid = id;
if(txid == 0)
txid = id;
pendingTX[ownerKey] = SearchJob(whoasked, target, job);
pendingTX[ownerKey] = SearchJob(whoasked, txid, target, job, excludes);
llarp::Info("Asking ", askpeer, " for router ", target, " for ",
whoasked);
auto msg = new llarp::DHTImmeidateMessage(askpeer);
msg->msgs.push_back(new FindRouterMessage(askpeer, target, id));
auto msg = new llarp::DHTImmeidateMessage(askpeer);
auto dhtmsg = new FindRouterMessage(askpeer, target, id);
dhtmsg->iterative = iterative;
msg->msgs.push_back(dhtmsg);
router->SendToOrQueue(askpeer, msg);
}
@ -561,7 +657,7 @@ namespace llarp
{
Key_t peer;
if(nodes->FindClosest(job->target, peer))
LookupRouter(job->target, ourKey, peer, job);
LookupRouter(job->target, ourKey, 0, peer, job);
else if(job->hook)
{
job->found = false;
@ -576,8 +672,9 @@ namespace llarp
static_cast< llarp_router_lookup_job * >(user);
job->dht->impl.LookupRouterViaJob(job);
}
}
}
} // namespace dht
} // namespace llarp
llarp_dht_context::llarp_dht_context(llarp_router *router)
{
@ -585,7 +682,6 @@ llarp_dht_context::llarp_dht_context(llarp_router *router)
}
extern "C" {
struct llarp_dht_context *
llarp_dht_context_new(struct llarp_router *router)
{

@ -5,6 +5,11 @@
namespace llarp
{
Encrypted::Encrypted()
{
UpdateBuffer();
}
Encrypted::Encrypted(const byte_t* buf, size_t sz) : _sz(sz)
{
_data = new byte_t[sz];

@ -1396,8 +1396,8 @@ namespace iwp
llarp::Debug("removing session ", addr);
UnmapAddr(addr);
session *s = static_cast< session * >(itr->second.impl);
m_sessions.erase(itr);
s->done();
m_sessions.erase(itr);
if(s->frames)
{
llarp::Warn("session has ", s->frames,
@ -1903,18 +1903,19 @@ namespace iwp
self->establish_job_id = 0;
if(self->establish_job)
{
self->establish_job->link = self->serv->parent;
auto job = self->establish_job;
self->establish_job = nullptr;
job->link = self->serv->parent;
if(self->IsEstablished())
{
self->establish_job->session = self->parent;
job->session = self->parent;
}
else
{
// timer timeout
self->establish_job->session = nullptr;
job->session = nullptr;
}
self->establish_job->result(self->establish_job);
self->establish_job = nullptr;
job->result(job);
}
}

@ -1,6 +1,7 @@
#include <deque>
#include <llarp/encrypted_frame.hpp>
#include <llarp/path.hpp>
#include "buffer.hpp"
#include "router.hpp"
namespace llarp
@ -69,6 +70,20 @@ namespace llarp
}
return m_Router->SendToOrQueue(nextHop, msg);
}
template < typename Map_t, typename Key_t, typename CheckValue_t >
IHopHandler*
MapGet(Map_t& map, const Key_t& k, CheckValue_t check)
{
std::unique_lock< std::mutex > lock(map.first);
auto itr = map.second.find(k);
while(itr != map.second.end())
{
if(check(itr->second))
return itr->second;
++itr;
}
return nullptr;
}
template < typename Map_t, typename Key_t, typename CheckValue_t >
bool
@ -93,6 +108,21 @@ namespace llarp
map.second.emplace(k, v);
}
template < typename Map_t, typename Key_t, typename Check_t >
void
MapDel(Map_t& map, const Key_t& k, Check_t check)
{
std::unique_lock< std::mutex > lock(map.first);
auto itr = map.second.find(k);
while(itr != map.second.end())
{
if(check(itr->second))
itr = map.second.erase(itr);
else
++itr;
}
}
void
PathContext::AddOwnPath(Path* path)
{
@ -102,9 +132,22 @@ namespace llarp
bool
PathContext::HasTransitHop(const TransitHopInfo& info)
{
return MapHas(
m_TransitPaths, info.pathID,
[info](const TransitHop& hop) -> bool { return info == hop.info; });
return MapHas(m_TransitPaths, info.pathID, [info](TransitHop* hop) -> bool {
return info == hop->info;
});
}
IHopHandler*
PathContext::GetByUpstream(const RouterID& remote, const PathID_t& id)
{
auto own = MapGet(m_OurPaths, id, [remote](const Path* p) -> bool {
return p->Upstream() == remote;
});
if(own)
return own;
return MapGet(m_TransitPaths, id, [remote](const TransitHop* hop) -> bool {
return hop->info.upstream == remote;
});
}
const byte_t*
@ -113,10 +156,17 @@ namespace llarp
return m_Router->pubkey();
}
llarp_router*
PathContext::Router()
{
return m_Router;
}
void
PathContext::PutTransitHop(const TransitHop& hop)
PathContext::PutTransitHop(TransitHop* hop)
{
MapPut(m_TransitPaths, hop.info.pathID, hop);
MapPut(m_TransitPaths, hop->info.txID, hop);
MapPut(m_TransitPaths, hop->info.rxID, hop);
}
void
@ -126,45 +176,110 @@ namespace llarp
auto now = llarp_time_now_ms();
auto& map = m_TransitPaths.second;
auto itr = map.begin();
std::set< TransitHop* > removePaths;
while(itr != map.end())
{
if(itr->second.Expired(now))
itr = map.erase(itr);
else
++itr;
if(itr->second->Expired(now))
{
TransitHop* path = itr->second;
llarp::Info("transit path expired ", path);
removePaths.insert(path);
}
++itr;
}
for(auto& p : removePaths)
{
map.erase(p->info.txID);
map.erase(p->info.rxID);
delete p;
}
}
Path::Path(llarp_path_hops* h) : hops(h->numHops)
{
for(size_t idx = 0; idx < h->numHops; ++idx)
{
llarp_rc_copy(&hops[idx].router, &h->hops[idx].router);
}
}
const PathID_t&
Path::TXID() const
{
return hops[0].pathTX;
}
const PathID_t&
Path::RXID() const
{
return hops[0].pathRX;
}
RouterID
Path::Upstream() const
{
return hops[0].router.pubkey;
}
bool
TransitHop::Expired(llarp_time_t now) const
Path::HandleUpstream(llarp_buffer_t buf, const TunnelNonce& Y,
llarp_router* r)
{
return now - started > lifetime;
for(const auto& hop : hops)
{
r->crypto.xchacha20(buf, hop.shared, Y);
}
RelayUpstreamMessage* msg = new RelayUpstreamMessage;
msg->X = buf;
msg->Y = Y;
msg->pathid = PathID();
msg->pathid.data_l()[1] = 0;
return r->SendToOrQueue(Upstream(), msg);
}
TransitHopInfo::TransitHopInfo(const RouterID& down,
const LR_CommitRecord& record)
: pathID(record.pathid), upstream(record.nextHop), downstream(down)
bool
Path::Expired(llarp_time_t now) const
{
return now - buildStarted > hops[0].lifetime;
}
Path::Path(llarp_path_hops* h) : hops(h->numHops)
bool
Path::HandleDownstream(llarp_buffer_t buf, const TunnelNonce& Y,
llarp_router* r)
{
for(size_t idx = 0; idx < h->numHops; ++idx)
size_t idx = hops.size() - 1;
while(idx >= 0)
{
llarp_rc_copy(&hops[idx].router, &h->hops[idx].router);
r->crypto.xchacha20(buf, hops[idx].shared, Y);
if(idx)
idx--;
else
break;
}
return HandleRoutingMessage(buf, r);
}
const PathID_t&
Path::PathID() const
bool
Path::HandleRoutingMessage(llarp_buffer_t buf, llarp_router* r)
{
return hops[0].pathID;
// TODO: implement me
return true;
}
RouterID
Path::Upstream()
bool
Path::SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r)
{
return hops[0].router.pubkey;
byte_t tmp[MAX_LINK_MSG_SIZE / 2];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!msg->BEncode(&buf))
return false;
// rewind
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// make nonce
TunnelNonce N;
N.Randomize();
return HandleUpstream(buf, N, r);
}
} // namespace llarp

@ -0,0 +1,41 @@
#include <llarp/time.h>
#include <llarp/bencode.hpp>
#include <llarp/messages/path_confirm.hpp>
namespace llarp
{
namespace routing
{
PathConfirmMessage::PathConfirmMessage(uint64_t lifetime)
: pathLifetime(lifetime), pathCreated(llarp_time_now_ms())
{
}
bool
PathConfirmMessage::BEncode(llarp_buffer_t* buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "P"))
return false;
if(!BEncodeWriteDictInt(buf, "L", pathLifetime))
return false;
if(!BEncodeWriteDictInt(buf, "S", pathCreated))
return false;
return bencode_end(buf);
}
bool
PathConfirmMessage::BDecode(llarp_buffer_t* buf)
{
return false;
}
bool
PathConfirmMessage::HandleMessage(llarp_router* r) const
{
return true;
}
} // namespace routing
} // namespace llarp

@ -33,6 +33,7 @@ namespace llarp
AsyncPathKeyExchangeContext< User >* ctx =
static_cast< AsyncPathKeyExchangeContext< User >* >(u);
// current hop
auto& hop = ctx->path->hops[ctx->idx];
auto& frame = ctx->LRCM->frames[ctx->idx];
// generate key
@ -46,23 +47,32 @@ namespace llarp
abort();
return;
}
// randomize hop's path id
hop.pathID.Randomize();
LR_CommitRecord record;
++ctx->idx;
if(ctx->idx < ctx->path->hops.size())
bool isFarthestHop = ctx->idx == ctx->path->hops.size() - 1;
if(isFarthestHop)
{
hop.upstream = ctx->path->hops[ctx->idx].router.pubkey;
hop.upstream = hop.router.pubkey;
}
else
{
hop.upstream = hop.router.pubkey;
hop.upstream = ctx->path->hops[ctx->idx].router.pubkey;
}
// build record
LR_CommitRecord record;
record.version = LLARP_PROTO_VERSION;
// FIXME: pathID was split into txID/rxID
//record.pathid = hop.pathID;
record.tunnelNonce = hop.nonce;
record.nextHop = hop.upstream;
record.commkey = llarp::seckey_topublic(hop.commkey);
auto buf = frame.Buffer();
buf->cur = buf->base + EncryptedFrame::OverheadSize;
// generate record
// encode record
if(!record.BEncode(buf))
{
// failed to encode?
@ -78,15 +88,15 @@ namespace llarp
return;
}
if(ctx->idx < ctx->path->hops.size())
if(isFarthestHop)
{
// next hop
llarp_threadpool_queue_job(ctx->worker, {ctx, &GenerateNextKey});
// farthest hop
llarp_logic_queue_job(ctx->logic, {ctx, &HandleDone});
}
else
{
// farthest hop
llarp_logic_queue_job(ctx->logic, {ctx, &HandleDone});
// next hop
llarp_threadpool_queue_job(ctx->worker, {ctx, &GenerateNextKey});
}
}
@ -174,33 +184,32 @@ llarp_pathbuilder_context::llarp_pathbuilder_context(
{
}
extern "C"
extern "C" {
struct llarp_pathbuilder_context*
llarp_pathbuilder_context_new(struct llarp_router* router,
struct llarp_dht_context* dht)
{
struct llarp_pathbuilder_context*
llarp_pathbuilder_context_new(struct llarp_router* router,
struct llarp_dht_context* dht)
{
return new llarp_pathbuilder_context(router, dht);
}
return new llarp_pathbuilder_context(router, dht);
}
void
llarp_pathbuilder_context_free(struct llarp_pathbuilder_context* ctx)
{
delete ctx;
}
void
llarp_pathbuilder_context_free(struct llarp_pathbuilder_context* ctx)
{
delete ctx;
}
void
llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job)
void
llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job)
{
if (!job->context)
{
if (!job->context)
{
llarp::Error("failed to build path because no context is set in job");
return;
}
job->router = job->context->router;
if(job->selectHop == nullptr)
job->selectHop = &llarp_nodedb_select_random_hop;
llarp_logic_queue_job(job->router->logic,
{job, &llarp::pathbuilder_start_build});
llarp::Error("failed to build path because no context is set in job");
return;
}
job->router = job->context->router;
if(job->selectHop == nullptr)
job->selectHop = &llarp_nodedb_select_random_hop;
llarp_logic_queue_job(job->router->logic,
{job, &llarp::pathbuilder_start_build});
}
} // end extern c

@ -1,5 +1,7 @@
#include <llarp/bencode.hpp>
#include <llarp/messages/path_confirm.hpp>
#include <llarp/messages/relay_commit.hpp>
#include "buffer.hpp"
#include "logger.hpp"
#include "router.hpp"
@ -73,7 +75,9 @@ namespace llarp
return false;
if(!BEncodeWriteDictEntry("n", tunnelNonce, buf))
return false;
if(!BEncodeWriteDictEntry("p", pathid, buf))
if(!BEncodeWriteDictEntry("r", rxid, buf))
return false;
if(!BEncodeWriteDictEntry("t", txid, buf))
return false;
if(!bencode_write_version_entry(buf))
return false;
@ -106,7 +110,9 @@ namespace llarp
if(!BEncodeMaybeReadDictEntry("n", self->tunnelNonce, read, *key,
r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("p", self->pathid, read, *key, r->buffer))
if(!BEncodeMaybeReadDictEntry("r", self->rxid, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("t", self->txid, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadVersion("v", self->version, LLARP_PROTO_VERSION, read,
*key, r->buffer))
@ -144,7 +150,7 @@ namespace llarp
return false;
}
return nextHop == other.nextHop && commkey == other.commkey
&& pathid == other.pathid;
&& txid == other.txid && rxid == other.rxid;
}
struct LRCMFrameDecrypt
@ -156,15 +162,15 @@ namespace llarp
// decrypted record
LR_CommitRecord record;
// the actual hop
TransitHop hop;
TransitHop* hop;
LRCMFrameDecrypt(PathContext* ctx, Decrypter* dec,
const LR_CommitMessage* commit)
: decrypter(dec), context(ctx)
: decrypter(dec), context(ctx), hop(new TransitHop)
{
for(const auto& f : commit->frames)
frames.push_back(f);
hop.info.downstream = commit->remote;
hop->info.downstream = commit->remote;
}
~LRCMFrameDecrypt()
@ -177,19 +183,26 @@ namespace llarp
SendLRCM(void* user)
{
LRCMFrameDecrypt* self = static_cast< LRCMFrameDecrypt* >(user);
self->context->ForwardLRCM(self->hop.info.upstream, self->frames);
self->context->ForwardLRCM(self->hop->info.upstream, self->frames);
delete self;
}
static void
SendLRAM(void* user)
SendPathConfirm(void* user)
{
LRCMFrameDecrypt* self = static_cast< LRCMFrameDecrypt* >(user);
llarp::routing::PathConfirmMessage confirm(self->hop->lifetime);
if(!self->hop->SendRoutingMessage(&confirm, self->context->Router()))
{
llarp::Error("failed to send path confirmation for ", self->hop->info);
}
delete self;
}
static void
HandleDecrypted(llarp_buffer_t* buf, LRCMFrameDecrypt* self)
{
auto& info = self->hop.info;
auto& info = self->hop->info;
if(!buf)
{
llarp::Error("LRCM decrypt failed from ", info.downstream);
@ -206,7 +219,8 @@ namespace llarp
return;
}
info.pathID = self->record.pathid;
info.txID = self->record.txid;
info.rxID = self->record.rxid;
info.upstream = self->record.nextHop;
if(self->context->HasTransitHop(info))
{
@ -216,7 +230,7 @@ namespace llarp
}
// generate path key as we are in a worker thread
auto DH = self->context->Crypto()->dh_server;
if(!DH(self->hop.pathKey, self->record.commkey,
if(!DH(self->hop->pathKey, self->record.commkey,
self->context->EncryptionSecretKey(), self->record.tunnelNonce))
{
llarp::Error("LRCM DH Failed ", info);
@ -229,12 +243,12 @@ namespace llarp
{
llarp::Info("LRCM extended lifetime by ",
self->record.work->extendedLifetime, " seconds for ", info);
self->hop.lifetime += 1000 * self->record.work->extendedLifetime;
self->hop->lifetime += 1000 * self->record.work->extendedLifetime;
}
// TODO: check if we really want to accept it
self->hop.started = llarp_time_now_ms();
llarp::Info("Accepted ", self->hop.info);
self->hop->started = llarp_time_now_ms();
llarp::Info("Accepted ", self->hop->info);
self->context->PutTransitHop(self->hop);
size_t sz = self->frames.front().size();
@ -250,7 +264,7 @@ namespace llarp
// we are the farthest hop
llarp::Info("We are the farthest hop for ", info);
// send a LRAM down the path
llarp_logic_queue_job(self->context->Logic(), {self, &SendLRAM});
llarp_logic_queue_job(self->context->Logic(), {self, &SendPathConfirm});
}
else
{

@ -1,5 +1,8 @@
#include <llarp/bencode.hpp>
#include <llarp/messages/relay.hpp>
#include "router.hpp"
namespace llarp
{
RelayUpstreamMessage::RelayUpstreamMessage(const RouterID &from)
@ -7,6 +10,10 @@ namespace llarp
{
}
RelayUpstreamMessage::RelayUpstreamMessage() : ILinkMessage()
{
}
RelayUpstreamMessage::~RelayUpstreamMessage()
{
}
@ -35,25 +42,62 @@ namespace llarp
{
}
RelayDownstreamMessage::RelayDownstreamMessage() : ILinkMessage()
{
}
RelayDownstreamMessage::~RelayDownstreamMessage()
{
}
bool
RelayDownstreamMessage::BEncode(llarp_buffer_t *buf) const
{
// TODO: implement me
return false;
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "a", "d"))
return false;
if(!BEncodeWriteDictEntry("p", pathid, buf))
return false;
if(!BEncodeWriteDictInt(buf, "v", LLARP_PROTO_VERSION))
return false;
if(!BEncodeWriteDictEntry("x", X, buf))
return false;
if(!BEncodeWriteDictEntry("y", Y, buf))
return false;
return bencode_end(buf);
}
bool
RelayDownstreamMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
{
return false;
bool read = false;
if(!BEncodeMaybeReadDictEntry("p", pathid, read, key, buf))
return false;
if(!BEncodeMaybeReadVersion("v", version, LLARP_PROTO_VERSION, read, key,
buf))
return false;
if(!BEncodeMaybeReadDictEntry("x", X, read, key, buf))
return false;
if(!BEncodeMaybeReadDictEntry("y", Y, read, key, buf))
return false;
return read;
}
bool
RelayDownstreamMessage::HandleMessage(llarp_router *router) const
{
PathID_t id = pathid;
id.data_l()[0] = 0;
auto path = router->paths.GetByUpstream(remote, id);
if(path)
{
return path->HandleDownstream(X.Buffer(), Y, router);
}
else
{
llarp::Warn("No such path upstream=", remote, " pathid=", id);
}
return false;
}
}
} // namespace llarp

@ -54,7 +54,7 @@ llarp_router::HandleRecvLinkMessage(llarp_link_session *session,
bool
llarp_router::SendToOrQueue(const llarp::RouterID &remote,
llarp::ILinkMessage *msg)
const llarp::ILinkMessage *msg)
{
llarp_link *chosen = nullptr;
if(!outboundLink->has_session_to(outboundLink, remote))
@ -422,7 +422,7 @@ llarp_router::send_padded_message(llarp_link_session_iter *itr,
}
void
llarp_router::SendTo(llarp::RouterID remote, llarp::ILinkMessage *msg,
llarp_router::SendTo(llarp::RouterID remote, const llarp::ILinkMessage *msg,
llarp_link *link)
{
llarp_buffer_t buf =
@ -717,266 +717,263 @@ llarp_router::HasPendingConnectJob(const llarp::RouterID &remote)
return pendingEstablishJobs.find(remote) != pendingEstablishJobs.end();
}
extern "C"
extern "C" {
struct llarp_router *
llarp_init_router(struct llarp_threadpool *tp, struct llarp_ev_loop *netloop,
struct llarp_logic *logic)
{
struct llarp_router *
llarp_init_router(struct llarp_threadpool *tp, struct llarp_ev_loop *netloop,
struct llarp_logic *logic)
llarp_router *router = new llarp_router();
if(router)
{
llarp_router *router = new llarp_router();
if(router)
{
router->netloop = netloop;
router->tp = tp;
router->logic = logic;
// TODO: make disk io threadpool count configurable
router->netloop = netloop;
router->tp = tp;
router->logic = logic;
// TODO: make disk io threadpool count configurable
#ifdef TESTNET
router->disk = tp;
router->disk = tp;
#else
router->disk = llarp_init_threadpool(1, "llarp-diskio");
router->disk = llarp_init_threadpool(1, "llarp-diskio");
#endif
llarp_crypto_libsodium_init(&router->crypto);
}
return router;
}
bool
llarp_configure_router(struct llarp_router *router, struct llarp_config *conf)
{
llarp_config_iterator iter;
iter.user = router;
iter.visit = llarp::router_iter_config;
llarp_config_iter(conf, &iter);
if(!router->InitOutboundLink())
return false;
if(!router->Ready())
{
return false;
}
return router->EnsureIdentity();
}
void
llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb)
{
router->nodedb = nodedb;
router->Run();
llarp_crypto_libsodium_init(&router->crypto);
}
return router;
}
bool
llarp_router_try_connect(struct llarp_router *router, struct llarp_rc *remote,
uint16_t numretries)
bool
llarp_configure_router(struct llarp_router *router, struct llarp_config *conf)
{
llarp_config_iterator iter;
iter.user = router;
iter.visit = llarp::router_iter_config;
llarp_config_iter(conf, &iter);
if(!router->InitOutboundLink())
return false;
if(!router->Ready())
{
// do we already have a pending job for this remote?
if(router->HasPendingConnectJob(remote->pubkey))
return false;
// try first address only
llarp_ai addr;
if(llarp_ai_list_index(remote->addrs, 0, &addr))
{
auto link = router->outboundLink;
auto itr = router->pendingEstablishJobs.emplace(
std::make_pair(remote->pubkey, llarp_link_establish_job{}));
auto job = &itr.first->second;
llarp_ai_copy(&job->ai, &addr);
memcpy(job->pubkey, remote->pubkey, PUBKEYSIZE);
job->retries = numretries;
job->timeout = 10000;
job->result = &llarp_router::on_try_connect_result;
// give router as user pointer
job->user = router;
// try establishing
link->try_establish(link, job);
return true;
}
return false;
}
return router->EnsureIdentity();
}
void
llarp_rc_clear(struct llarp_rc *rc)
{
// zero out router contact
llarp::Zero(rc, sizeof(llarp_rc));
}
void
llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb)
{
router->nodedb = nodedb;
router->Run();
}
bool
llarp_rc_addr_list_iter(struct llarp_ai_list_iter *iter, struct llarp_ai *ai)
bool
llarp_router_try_connect(struct llarp_router *router, struct llarp_rc *remote,
uint16_t numretries)
{
// do we already have a pending job for this remote?
if(router->HasPendingConnectJob(remote->pubkey))
return false;
// try first address only
llarp_ai addr;
if(llarp_ai_list_index(remote->addrs, 0, &addr))
{
struct llarp_rc *rc = (llarp_rc *)iter->user;
llarp_ai_list_pushback(rc->addrs, ai);
auto link = router->outboundLink;
auto itr = router->pendingEstablishJobs.emplace(
std::make_pair(remote->pubkey, llarp_link_establish_job()));
auto job = &itr.first->second;
llarp_ai_copy(&job->ai, &addr);
memcpy(job->pubkey, remote->pubkey, PUBKEYSIZE);
job->retries = numretries;
job->timeout = 10000;
job->result = &llarp_router::on_try_connect_result;
// give router as user pointer
job->user = router;
// try establishing
link->try_establish(link, job);
return true;
}
return false;
}
void
llarp_rc_set_addrs(struct llarp_rc *rc, struct llarp_alloc *mem,
struct llarp_ai_list *addr)
{
rc->addrs = llarp_ai_list_new();
struct llarp_ai_list_iter ai_itr;
ai_itr.user = rc;
ai_itr.visit = &llarp_rc_addr_list_iter;
llarp_ai_list_iterate(addr, &ai_itr);
}
void
llarp_rc_clear(struct llarp_rc *rc)
{
// zero out router contact
llarp::Zero(rc, sizeof(llarp_rc));
}
void
llarp_rc_set_pubenckey(struct llarp_rc *rc, const uint8_t *pubenckey)
{
// set public encryption key
memcpy(rc->enckey, pubenckey, PUBKEYSIZE);
}
void
llarp_rc_set_pubenckey(struct llarp_rc *rc, const uint8_t *pubenckey)
{
// set public encryption key
memcpy(rc->enckey, pubenckey, PUBKEYSIZE);
}
void
llarp_rc_set_pubsigkey(struct llarp_rc *rc, const uint8_t *pubsigkey)
void
llarp_rc_set_pubsigkey(struct llarp_rc *rc, const uint8_t *pubsigkey)
{
// set public signing key
memcpy(rc->pubkey, pubsigkey, PUBKEYSIZE);
}
void
llarp_rc_set_pubkey(struct llarp_rc *rc, const uint8_t *pubenckey,
const uint8_t *pubsigkey)
{
// set public encryption key
llarp_rc_set_pubenckey(rc, pubenckey);
// set public signing key
llarp_rc_set_pubsigkey(rc, pubsigkey);
}
struct llarp_rc *
llarp_rc_read(const char *fpath)
{
fs::path our_rc_file(fpath);
std::error_code ec;
if(!fs::exists(our_rc_file, ec))
{
// set public signing key
memcpy(rc->pubkey, pubsigkey, PUBKEYSIZE);
printf("File[%s] not found\n", fpath);
return 0;
}
void
llarp_rc_set_pubkey(struct llarp_rc *rc, const uint8_t *pubenckey,
const uint8_t *pubsigkey)
std::ifstream f(our_rc_file, std::ios::binary);
if(!f.is_open())
{
// set public encryption key
llarp_rc_set_pubenckey(rc, pubenckey);
// set public signing key
llarp_rc_set_pubsigkey(rc, pubsigkey);
printf("Can't open file [%s]\n", fpath);
return 0;
}
struct llarp_rc *
llarp_rc_read(const char *fpath)
byte_t tmp[MAX_RC_SIZE];
llarp_buffer_t buf = llarp::StackBuffer< decltype(tmp) >(tmp);
f.seekg(0, std::ios::end);
size_t sz = f.tellg();
f.seekg(0, std::ios::beg);
if(sz > buf.sz)
return 0;
f.read((char *)buf.base, sz);
//printf("contents[%s]\n", tmpc);
llarp_rc *rc = new llarp_rc;
llarp::Zero(rc, sizeof(llarp_rc));
if(!llarp_rc_bdecode(rc, &buf))
{
fs::path our_rc_file(fpath);
std::error_code ec;
if(!fs::exists(our_rc_file, ec))
{
printf("File[%s] not found\n", fpath);
return 0;
}
std::ifstream f(our_rc_file, std::ios::binary);
if(!f.is_open())
{
printf("Can't open file [%s]\n", fpath);
return 0;
}
byte_t tmp[MAX_RC_SIZE];
llarp_buffer_t buf = llarp::StackBuffer< decltype(tmp) >(tmp);
f.seekg(0, std::ios::end);
size_t sz = f.tellg();
f.seekg(0, std::ios::beg);
if(sz > buf.sz)
return 0;
f.read((char *)buf.base, sz);
//printf("contents[%s]\n", tmpc);
llarp_rc *rc = new llarp_rc;
llarp::Zero(rc, sizeof(llarp_rc));
if(!llarp_rc_bdecode(rc, &buf))
{
printf("Can't decode [%s]\n", fpath);
return 0;
}
return rc;
printf("Can't decode [%s]\n", fpath);
return 0;
}
return rc;
}
bool
llarp_rc_addr_list_iter(struct llarp_ai_list_iter *iter, struct llarp_ai *ai)
{
struct llarp_rc *rc = (llarp_rc *)iter->user;
llarp_ai_list_pushback(rc->addrs, ai);
return true;
}
bool
llarp_rc_write(struct llarp_rc *rc, const char *fpath)
{
fs::path our_rc_file(fpath);
byte_t tmp[MAX_RC_SIZE];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
void
llarp_rc_set_addrs(struct llarp_rc *rc, struct llarp_alloc *mem,
struct llarp_ai_list *addr)
{
rc->addrs = llarp_ai_list_new();
struct llarp_ai_list_iter ai_itr;
ai_itr.user = rc;
ai_itr.visit = &llarp_rc_addr_list_iter;
llarp_ai_list_iterate(addr, &ai_itr);
}
if(llarp_rc_bencode(rc, &buf))
{
std::ofstream f(our_rc_file, std::ios::binary);
if(f.is_open())
{
f.write((char *)buf.base, buf.cur - buf.base);
return true;
}
}
return false;
}
bool
llarp_rc_write(struct llarp_rc *rc, const char *fpath)
{
fs::path our_rc_file(fpath);
byte_t tmp[MAX_RC_SIZE];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
void
llarp_rc_sign(llarp_crypto *crypto, const byte_t *seckey, struct llarp_rc *rc)
if(llarp_rc_bencode(rc, &buf))
{
byte_t buf[MAX_RC_SIZE];
auto signbuf = llarp::StackBuffer< decltype(buf) >(buf);
// zero out previous signature
llarp::Zero(rc->signature, sizeof(rc->signature));
// encode
if(llarp_rc_bencode(rc, &signbuf))
std::ofstream f(our_rc_file, std::ios::binary);
if(f.is_open())
{
// sign
signbuf.sz = signbuf.cur - signbuf.base;
crypto->sign(rc->signature, seckey, signbuf);
f.write((char *)buf.base, buf.cur - buf.base);
return true;
}
}
return false;
}
void
llarp_stop_router(struct llarp_router *router)
void
llarp_rc_sign(llarp_crypto *crypto, const byte_t *seckey, struct llarp_rc *rc)
{
byte_t buf[MAX_RC_SIZE];
auto signbuf = llarp::StackBuffer< decltype(buf) >(buf);
// zero out previous signature
llarp::Zero(rc->signature, sizeof(rc->signature));
// encode
if(llarp_rc_bencode(rc, &signbuf))
{
if(router)
router->Close();
// sign
signbuf.sz = signbuf.cur - signbuf.base;
crypto->sign(rc->signature, seckey, signbuf);
}
}
void
llarp_router_iterate_links(struct llarp_router *router,
struct llarp_router_link_iter i)
{
for(auto link : router->inboundLinks)
if(!i.visit(&i, router, link))
return;
i.visit(&i, router, router->outboundLink);
}
void
llarp_stop_router(struct llarp_router *router)
{
if(router)
router->Close();
}
void
llarp_free_router(struct llarp_router **router)
void
llarp_router_iterate_links(struct llarp_router *router,
struct llarp_router_link_iter i)
{
for(auto link : router->inboundLinks)
if(!i.visit(&i, router, link))
return;
i.visit(&i, router, router->outboundLink);
}
void
llarp_free_router(struct llarp_router **router)
{
if(*router)
{
if(*router)
{
delete *router;
}
*router = nullptr;
delete *router;
}
*router = nullptr;
}
bool
llarp_findOrCreateIdentity(llarp_crypto *crypto, const char *fpath,
byte_t *secretkey)
void
llarp_router_override_path_selection(struct llarp_router *router,
llarp_pathbuilder_select_hop_func func)
{
if(func)
router->selectHopFunc = func;
}
bool
llarp_findOrCreateIdentity(llarp_crypto *crypto, const char *fpath,
byte_t *secretkey)
{
llarp::Debug("find or create ", fpath);
fs::path path(fpath);
std::error_code ec;
if(!fs::exists(path, ec))
{
llarp::Debug("find or create ", fpath);
fs::path path(fpath);
std::error_code ec;
if(!fs::exists(path, ec))
{
llarp::Info("generating new identity key");
crypto->identity_keygen(secretkey);
std::ofstream f(path, std::ios::binary);
if(f.is_open())
{
f.write((char *)secretkey, SECKEYSIZE);
}
}
std::ifstream f(path, std::ios::binary);
llarp::Info("generating new identity key");
crypto->identity_keygen(secretkey);
std::ofstream f(path, std::ios::binary);
if(f.is_open())
{
f.read((char *)secretkey, SECKEYSIZE);
return true;
f.write((char *)secretkey, SECKEYSIZE);
}
llarp::Info("failed to get identity key");
return false;
}
void
llarp_router_override_path_selection(struct llarp_router *router,
llarp_pathbuilder_select_hop_func func)
std::ifstream f(path, std::ios::binary);
if(f.is_open())
{
if(func)
router->selectHopFunc = func;
f.read((char *)secretkey, SECKEYSIZE);
return true;
}
llarp::Info("failed to get identity key");
return false;
}
} // end extern C

@ -82,13 +82,13 @@ struct llarp_router
llarp_link *outboundLink = nullptr;
std::list< llarp_link * > inboundLinks;
typedef std::queue< llarp::ILinkMessage * > MessageQueue;
typedef std::queue< const llarp::ILinkMessage * > MessageQueue;
/// outbound message queue
std::map< llarp::PubKey, MessageQueue > outboundMesssageQueue;
std::map< llarp::RouterID, MessageQueue > outboundMesssageQueue;
/// loki verified routers
std::unordered_map< llarp::PubKey, llarp_rc, llarp::PubKeyHash > validRouters;
std::map< llarp::RouterID, llarp_rc > validRouters;
std::map< llarp::PubKey, llarp_link_establish_job > pendingEstablishJobs;
@ -147,11 +147,11 @@ struct llarp_router
/// NOT threadsafe
/// MUST be called in the logic thread
bool
SendToOrQueue(const llarp::RouterID &remote, llarp::ILinkMessage *msg);
SendToOrQueue(const llarp::RouterID &remote, const llarp::ILinkMessage *msg);
/// sendto or drop
void
SendTo(llarp::RouterID remote, llarp::ILinkMessage *msg,
SendTo(llarp::RouterID remote, const llarp::ILinkMessage *msg,
llarp_link *chosen = nullptr);
/// manually flush outbound message queue for just 1 router

@ -0,0 +1,84 @@
#include <llarp/path.hpp>
#include "buffer.hpp"
#include "router.hpp"
namespace llarp
{
bool
TransitHop::Expired(llarp_time_t now) const
{
return now - started > lifetime;
}
TransitHopInfo::TransitHopInfo(const TransitHopInfo& other)
: pathID(other.pathID)
, upstream(other.upstream)
, downstream(other.downstream)
{
}
TransitHopInfo::TransitHopInfo(const RouterID& down,
const LR_CommitRecord& record)
: pathID(record.pathid), upstream(record.nextHop), downstream(down)
{
}
TransitHop::TransitHop(const TransitHop& other)
: info(other.info)
, pathKey(other.pathKey)
, started(other.started)
, lifetime(other.lifetime)
, version(other.version)
{
}
bool
TransitHop::SendRoutingMessage(const llarp::routing::IMessage* msg,
llarp_router* r)
{
byte_t tmp[MAX_LINK_MSG_SIZE / 2];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!msg->BEncode(&buf))
{
llarp::Error("failed to encode routing message");
return false;
}
TunnelNonce N;
N.Randomize();
// rewind
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return HandleDownstream(buf, N, r);
}
bool
TransitHop::HandleDownstream(llarp_buffer_t buf, const TunnelNonce& Y,
llarp_router* r)
{
RelayDownstreamMessage* msg = new RelayDownstreamMessage;
msg->pathid = info.rxID;
msg->Y = Y;
r->crypto.xchacha20(buf, pathKey, Y);
msg->X = buf;
llarp::Info("relay ", msg->X.size(), " bytes downstream from ",
info.upstream, " to ", info.downstream);
return r->SendToOrQueue(info.downstream, msg);
}
bool
TransitHop::HandleUpstream(llarp_buffer_t buf, const TunnelNonce& Y,
llarp_router* r)
{
RelayUpstreamMessage* msg = new RelayUpstreamMessage;
msg->pathid = info.txID;
msg->Y = Y;
r->crypto.xchacha20(buf, pathKey, Y);
msg->X = buf;
llarp::Info("relay ", msg->X.size(), " bytes upstream from ",
info.downstream, " to ", info.upstream);
return r->SendToOrQueue(info.upstream, msg);
}
} // namespace llarp

@ -43,7 +43,8 @@ TEST_F(FrameTest, TestFrameCrypto)
LRCR record;
record.nextHop.Fill(1);
record.tunnelNonce.Fill(2);
record.pathid.Fill(3);
record.rxid.Fill(3);
record.txid.Fill(4);
auto buf = f.Buffer();
buf->cur = buf->base + EncryptedFrame::OverheadSize;

Loading…
Cancel
Save