initial path building stuff (broken)

pull/1/head
Jeff Becker 6 years ago
parent bdc043d2a2
commit 08c0318e82
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -6,12 +6,14 @@
"path": [
"${workspaceFolder}/llarp",
"${workspaceFolder}/daemon",
"${workspaceFolder}/include"
"${workspaceFolder}/include",
"${workspaceFolder}/vendor/cppbackport-master/lib"
],
"limitSymbolsToIncludedHeaders": true
},
"includePath": [
"${workspaceFolder}/include"
"${workspaceFolder}/include",
"${workspaceFolder}/vendor/cppbackport-master/lib"
],
"defines": [],
"compilerPath": "/usr/bin/clang",

@ -1,3 +1,59 @@
{
"editor.formatOnSave": true
"editor.formatOnSave": true,
"files.associations": {
"array": "cpp",
"limits": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"list": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"exception": "cpp",
"filesystem": "cpp",
"string_view": "cpp",
"fstream": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"memory": "cpp",
"mutex": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"system_error": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"type_traits": "cpp",
"tuple": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"utility": "cpp",
"__config": "cpp",
"__nullptr": "cpp",
"algorithm": "cpp",
"io": "cpp"
}
}

@ -7,7 +7,10 @@
"label": "build",
"type": "shell",
"command": "make",
"group": "build"
"group": "build",
"problemMatcher": [
"$gcc"
]
}
]
}

@ -59,8 +59,8 @@ if(SHADOW)
include_directories(${SHADOW_ROOT}/include)
endif()
add_cflags("-Wall ${OPTIMIZE_FLAGS}")
add_cxxflags("-Wall ${OPTIMIZE_FLAGS}")
add_cflags("-Wall -Wno-deprecated-declarations ${OPTIMIZE_FLAGS}")
add_cxxflags("-Wall -Wno-deprecated-declarations ${OPTIMIZE_FLAGS}")
if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
add_cflags("${DEBUG_FLAGS}")
@ -123,12 +123,13 @@ set(LIB_SRC
llarp/net.cpp
llarp/nodedb.cpp
llarp/path.cpp
llarp/pathbuilder.cpp
llarp/proofofwork.cpp
llarp/relay_ack.cpp
llarp/relay_commit.cpp
llarp/relay_up_down.cpp
llarp/router_contact.cpp
llarp/router.cpp
llarp/router_identity.c
llarp/threadpool.cpp
llarp/testnet.c
llarp/time.cpp

@ -145,7 +145,7 @@ main(int argc, char *argv[])
int c;
char *rcfname;
char defaultName[] = "other.signed";
rcfname = defaultName;
rcfname = defaultName;
while(1)
{
static struct option long_options[] = {

@ -142,6 +142,6 @@ namespace llarp
uint64_t l[sz / 8];
};
};
}
} // namespace llarp
#endif

@ -9,9 +9,6 @@ namespace llarp
{
struct LR_AckRecord
{
PubKey pubkey;
TunnelNonce nonce;
PathID_t rxPathID;
uint64_t version = 0;
bool
@ -23,9 +20,7 @@ namespace llarp
struct LR_AckMessage : public ILinkMessage
{
std::vector< EncryptedFrame > acks;
EncryptedFrame lasthopFrame;
PathID_t txPathID;
std::vector< EncryptedFrame > replies;
uint64_t version = 0;
LR_AckMessage(const RouterID& from);
@ -41,6 +36,6 @@ namespace llarp
bool
HandleMessage(llarp_router* router) const;
};
}
} // namespace llarp
#endif

@ -5,18 +5,21 @@
#include <llarp/encrypted_frame.hpp>
#include <llarp/link_message.hpp>
#include <llarp/path_types.hpp>
#include <llarp/pow.hpp>
#include <vector>
namespace llarp
{
// forward declare
struct PathContext;
struct LR_CommitRecord
{
PubKey commkey;
PubKey nextHop;
RouterID nextHop;
TunnelNonce tunnelNonce;
PathID_t txid;
SymmKey downstreamReplyKey;
SymmNonce downstreamReplyNonce;
PathID_t pathid;
PoW *work = nullptr;
uint64_t version;
bool
@ -25,6 +28,8 @@ namespace llarp
bool
BEncode(llarp_buffer_t *buf) const;
~LR_CommitRecord();
private:
static bool
OnKey(dict_reader *r, llarp_buffer_t *buf);
@ -32,9 +37,10 @@ namespace llarp
struct LR_AcceptRecord
{
uint64_t pathid;
uint64_t version;
std::vector< byte_t > padding;
RouterID upstream;
RouterID downstream;
PathID_t pathid;
uint64_t version = LLARP_PROTO_VERSION;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf);
@ -46,13 +52,12 @@ namespace llarp
struct LR_CommitMessage : public ILinkMessage
{
std::vector< EncryptedFrame > frames;
EncryptedFrame lasthopFrame;
std::vector< EncryptedAck > acks;
uint64_t version;
LR_CommitMessage() : ILinkMessage()
{
}
LR_CommitMessage(const RouterID &from) : ILinkMessage(from)
{
}
@ -70,7 +75,10 @@ namespace llarp
bool
HandleMessage(llarp_router *router) const;
bool
AsyncDecrypt(PathContext *context) const;
};
}
} // namespace llarp
#endif

@ -11,119 +11,129 @@
*/
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_nodedb;
/// create an empty nodedb
struct llarp_nodedb *
llarp_nodedb_new(struct llarp_crypto *crypto);
/// free a nodedb and all loaded rc
void
llarp_nodedb_free(struct llarp_nodedb **n);
/// ensure a nodedb fs skiplist structure is at dir
/// create if not there.
bool
llarp_nodedb_ensure_dir(const char *dir);
/// load entire nodedb from fs skiplist at dir
ssize_t
llarp_nodedb_load_dir(struct llarp_nodedb *n, const char *dir);
/// store entire nodedb to fs skiplist at dir
ssize_t
llarp_nodedb_store_dir(struct llarp_nodedb *n, const char *dir);
struct llarp_nodedb_iter
extern "C"
{
void *user;
struct llarp_rc *rc;
bool (*visit)(struct llarp_nodedb_iter *);
};
/// iterate over all loaded rc with an iterator
void
llarp_nodedb_iterate_all(struct llarp_nodedb *n, struct llarp_nodedb_iter i);
/**
put an rc into the node db
overwrites with new contents if already present
flushes the single entry to disk
returns true on success and false on error
*/
bool
llarp_nodedb_put_rc(struct llarp_nodedb *n, struct llarp_rc *rc);
/// return a pointer to an already loaded RC or nullptr if it's not there
struct llarp_rc *
llarp_nodedb_get_rc(struct llarp_nodedb *n, const byte_t *pk);
/// struct for async rc verification
struct llarp_async_verify_rc;
typedef void (*llarp_async_verify_rc_hook_func)(struct llarp_async_verify_rc *);
/// verify rc request
struct llarp_async_verify_rc
{
/// async_verify_context
void *user;
/// nodedb storage
struct llarp_nodedb *nodedb;
// llarp_logic for llarp_logic_queue_job
struct llarp_logic *logic; // includes a llarp_threadpool
// struct llarp_crypto *crypto; // probably don't need this because we have it
// in the nodedb
struct llarp_threadpool *cryptoworker;
struct llarp_threadpool *diskworker;
/// router contact (should this be a pointer?)
struct llarp_rc rc;
/// result
bool valid;
/// hook
llarp_async_verify_rc_hook_func hook;
};
/**
struct for async rc verification
data is loaded in disk io threadpool
crypto is done on the crypto worker threadpool
result is called on the logic thread
*/
void
llarp_nodedb_async_verify(struct llarp_async_verify_rc *job);
struct llarp_async_load_rc;
typedef void (*llarp_async_load_rc_hook_func)(struct llarp_async_load_rc *);
#endif
struct llarp_async_load_rc
{
/// async_verify_context
void *user;
/// nodedb storage
struct llarp_nodedb *nodedb;
/// llarp_logic for calling hook
struct llarp_logic *logic;
/// disk worker threadpool
struct llarp_threadpool *diskworker;
/// target pubkey
byte_t pubkey[PUBKEYSIZE];
/// router contact result
struct llarp_rc rc;
/// set to true if we loaded the rc
bool loaded;
/// hook function called in logic thread
llarp_async_load_rc_hook_func hook;
};
/// asynchronously load an rc from disk
void
llarp_nodedb_async_load_rc(struct llarp_async_load_rc *job);
struct llarp_nodedb;
/// create an empty nodedb
struct llarp_nodedb *
llarp_nodedb_new(struct llarp_crypto *crypto);
/// free a nodedb and all loaded rc
void
llarp_nodedb_free(struct llarp_nodedb **n);
/// ensure a nodedb fs skiplist structure is at dir
/// create if not there.
bool
llarp_nodedb_ensure_dir(const char *dir);
/// load entire nodedb from fs skiplist at dir
ssize_t
llarp_nodedb_load_dir(struct llarp_nodedb *n, const char *dir);
/// store entire nodedb to fs skiplist at dir
ssize_t
llarp_nodedb_store_dir(struct llarp_nodedb *n, const char *dir);
struct llarp_nodedb_iter
{
void *user;
struct llarp_rc *rc;
bool (*visit)(struct llarp_nodedb_iter *);
};
/// iterate over all loaded rc with an iterator
void
llarp_nodedb_iterate_all(struct llarp_nodedb *n, struct llarp_nodedb_iter i);
/// get a random rc that is loaded
void
llarp_nodedb_get_random_rc(struct llarp_nodedb *n, struct llarp_rc *result);
/// select a random rc at hop number N
void
llarp_nodedb_select_random_hop(struct llarp_nodedb *n,
struct llarp_rc *result, size_t N);
/**
put an rc into the node db
overwrites with new contents if already present
flushes the single entry to disk
returns true on success and false on error
*/
bool
llarp_nodedb_put_rc(struct llarp_nodedb *n, struct llarp_rc *rc);
/// return a pointer to an already loaded RC or nullptr if it's not there
struct llarp_rc *
llarp_nodedb_get_rc(struct llarp_nodedb *n, const byte_t *pk);
/// struct for async rc verification
struct llarp_async_verify_rc;
typedef void (*llarp_async_verify_rc_hook_func)(
struct llarp_async_verify_rc *);
/// verify rc request
struct llarp_async_verify_rc
{
/// async_verify_context
void *user;
/// nodedb storage
struct llarp_nodedb *nodedb;
// llarp_logic for llarp_logic_queue_job
struct llarp_logic *logic; // includes a llarp_threadpool
// struct llarp_crypto *crypto; // probably don't need this because we have
// it in the nodedb
struct llarp_threadpool *cryptoworker;
struct llarp_threadpool *diskworker;
/// router contact (should this be a pointer?)
struct llarp_rc rc;
/// result
bool valid;
/// hook
llarp_async_verify_rc_hook_func hook;
};
/**
struct for async rc verification
data is loaded in disk io threadpool
crypto is done on the crypto worker threadpool
result is called on the logic thread
*/
void
llarp_nodedb_async_verify(struct llarp_async_verify_rc *job);
struct llarp_async_load_rc;
typedef void (*llarp_async_load_rc_hook_func)(struct llarp_async_load_rc *);
struct llarp_async_load_rc
{
/// async_verify_context
void *user;
/// nodedb storage
struct llarp_nodedb *nodedb;
/// llarp_logic for calling hook
struct llarp_logic *logic;
/// disk worker threadpool
struct llarp_threadpool *diskworker;
/// target pubkey
byte_t pubkey[PUBKEYSIZE];
/// router contact result
struct llarp_rc rc;
/// set to true if we loaded the rc
bool loaded;
/// hook function called in logic thread
llarp_async_load_rc_hook_func hook;
};
/// asynchronously load an rc from disk
void
llarp_nodedb_async_load_rc(struct llarp_async_load_rc *job);
#ifdef __cplusplus
}

@ -0,0 +1,21 @@
#ifndef LLARP_PATH_H
#define LLARP_PATH_H
#include <llarp/router_contact.h>
#define MAXHOPS (8)
#ifdef __cplusplus
extern "C"
{
#endif
struct llarp_path_hops
{
struct llarp_rc routers[MAXHOPS];
size_t numHops;
};
#ifdef __cplusplus
}
#endif
#endif

@ -1,5 +1,6 @@
#ifndef LLARP_PATH_HPP
#define LLARP_PATH_HPP
#include <llarp/path.h>
#include <llarp/router.h>
#include <llarp/time.h>
#include <llarp/aligned.hpp>
@ -20,15 +21,14 @@ namespace llarp
TransitHopInfo() = default;
TransitHopInfo(const RouterID& down, const LR_CommitRecord& record);
PathID_t rxID;
PathID_t txID;
PathID_t pathID;
RouterID upstream;
RouterID downstream;
friend std::ostream&
operator<<(std::ostream& out, const TransitHopInfo& info)
{
out << "<Transit Hop rxid=" << info.rxID << " txid=" << info.txID;
out << "<Transit Hop id=" << info.pathID;
out << " upstream=" << info.upstream << " downstream=" << info.downstream;
return out << ">";
}
@ -36,8 +36,8 @@ namespace llarp
bool
operator==(const TransitHopInfo& other) const
{
return rxID == other.rxID && txID == other.txID
&& upstream == other.upstream && downstream == other.downstream;
return pathID == other.pathID && upstream == other.upstream
&& downstream == other.downstream;
}
bool
@ -46,41 +46,71 @@ namespace llarp
return !(*this == other);
}
bool
operator<(const TransitHopInfo& other) const
{
return pathID < other.pathID || upstream < other.upstream
|| downstream < other.downstream;
}
struct Hash
{
std::size_t
operator()(TransitHopInfo const& a) const
{
std::size_t idx0, idx1, idx2, idx3;
std::size_t idx0, idx1, idx2;
memcpy(&idx0, a.upstream, sizeof(std::size_t));
memcpy(&idx1, a.downstream, sizeof(std::size_t));
memcpy(&idx2, a.rxID, sizeof(std::size_t));
memcpy(&idx3, a.txID, sizeof(std::size_t));
return idx0 ^ idx1 ^ idx2 ^ idx3;
memcpy(&idx2, a.pathID, sizeof(std::size_t));
return idx0 ^ idx1 ^ idx2;
}
};
};
struct PathIDHash
{
std::size_t
operator()(const PathID_t& a) const
{
std::size_t idx0;
memcpy(&idx0, a, sizeof(std::size_t));
return idx0;
}
};
struct TransitHop
{
TransitHop() = default;
SharedSecret rxKey;
SharedSecret txKey;
TransitHopInfo info;
SharedSecret pathKey;
llarp_time_t started;
// 10 minutes default
llarp_time_t lifetime = 360000;
llarp_proto_version_t version;
bool
Expired(llarp_time_t now) const;
};
/// configuration for a single hop when building a path
struct PathHopConfig
{
/// path id
PathID_t txID;
/// router identity key
PubKey encryptionKey;
PathID_t pathID;
// router contact of router
llarp_rc router;
// temp public encryption key
SecretKey commkey;
/// shared secret at this hop
SharedSecret shared;
/// next hop's router id
RouterID upstream;
/// nonce for key exchange
TunnelNonce nonce;
~PathHopConfig();
PathHopConfig();
};
struct Path
@ -88,19 +118,30 @@ namespace llarp
typedef std::vector< PathHopConfig > HopList;
HopList hops;
llarp_time_t buildStarted;
Path(llarp_path_hops* path);
};
template < typename User >
struct AsyncPathKeyExchangeContext
{
Path path;
typedef void (*Handler)(AsyncPathKeyExchangeContext*);
Path* path = nullptr;
typedef void (*Handler)(AsyncPathKeyExchangeContext< User >*);
User* user = nullptr;
Handler result = nullptr;
const byte_t* secretkey = nullptr;
size_t idx = 0;
llarp_threadpool* worker = nullptr;
llarp_path_dh_func dh = nullptr;
llarp_logic* logic = nullptr;
llarp_crypto* crypto = nullptr;
LR_CommitMessage LRCM;
static void
HandleDone(void* user)
{
AsyncPathKeyExchangeContext< User >* ctx =
static_cast< AsyncPathKeyExchangeContext< User >* >(user);
ctx->result(ctx);
delete ctx;
}
static void
GenerateNextKey(void* user)
@ -108,38 +149,73 @@ namespace llarp
AsyncPathKeyExchangeContext< User >* ctx =
static_cast< AsyncPathKeyExchangeContext< User >* >(user);
auto& hop = ctx->path.hops[ctx->idx];
ctx->dh(hop.shared, hop.encryptionKey, hop.nonce, ctx->secretkey);
auto& hop = ctx->path->hops[ctx->idx];
// generate key
ctx->crypto->encryption_keygen(hop.commkey);
// do key exchange
if(!ctx->crypto->dh_client(hop.shared, hop.router.enckey, hop.nonce,
hop.commkey))
{
llarp::Error("Failed to generate shared key for path build");
delete ctx;
return;
}
// randomize hop's path id
hop.pathID.Randomize();
LR_CommitRecord record;
auto& frame = ctx->LRCM.frames[ctx->idx];
++ctx->idx;
if(ctx->idx < ctx->path.hops.size())
if(ctx->idx < ctx->path->hops.size())
{
llarp_threadpool_queue_job(ctx->worker, {ctx, &GenerateNextKey});
hop.upstream = ctx->path->hops[ctx->idx].router.pubkey;
}
else
{
ctx->Done();
hop.upstream = hop.router.pubkey;
}
// generate record
if(!record.BEncode(frame.Buffer()))
{
// failed to encode?
llarp::Error("Failed to generate Commit Record");
delete ctx;
return;
}
}
AsyncPathKeyExchangeContext(const byte_t* secret, llarp_crypto* crypto)
: secretkey(secret), dh(crypto->dh_client)
{
if(ctx->idx < ctx->path->hops.size())
{
// next hop
llarp_threadpool_queue_job(ctx->worker, {ctx, &GenerateNextKey});
}
else
{
// farthest hop
llarp_logic_queue_job(ctx->logic, {ctx, &HandleDone});
}
}
void
Done()
AsyncPathKeyExchangeContext(llarp_crypto* c) : crypto(c)
{
idx = 0;
result(this);
}
/// Generate all keys asynchronously and call hadler when done
void
AsyncGenerateKeys(llarp_threadpool* pool, User* u, Handler func) const
AsyncGenerateKeys(Path* p, llarp_logic* l, llarp_threadpool* pool, User* u,
Handler func)
{
path = p;
logic = l;
user = u;
result = func;
worker = pool;
for(size_t idx = 0; idx < MAXHOPS; ++idx)
{
LRCM.frames.emplace_back(256);
LRCM.frames.back().Randomize();
}
llarp_threadpool_queue_job(pool, {this, &GenerateNextKey});
}
};
@ -206,76 +282,46 @@ namespace llarp
PathContext(llarp_router* router);
~PathContext();
/// called from router tick function
void
ExpirePaths();
void
AllowTransit();
void
RejectTransit();
bool
HasTransitHop(const TransitHopInfo& info);
AllowingTransit() const;
bool
HandleRelayCommit(const LR_CommitMessage* msg);
HasTransitHop(const TransitHopInfo& info);
bool
HandleRelayAck(const LR_AckMessage* msg);
HandleRelayCommit(const LR_CommitMessage* msg);
void
PutPendingRelayCommit(const RouterID& router, const PathID_t& txid,
const TransitHopInfo& info, const TransitHop& hop);
PutTransitHop(const TransitHop& hop);
bool
HasPendingRelayCommit(const RouterID& upstream, const PathID_t& txid);
ForwardLRCM(const RouterID& nextHop, std::deque< EncryptedFrame >& frames);
bool
ForwardLRCM(const RouterID& nextHop, std::deque< EncryptedFrame >& frames,
std::deque< EncryptedAck >& acks, EncryptedFrame& lastFrame);
void
ForwradLRUM(const PathID_t& id, const RouterID& from, llarp_buffer_t X,
const TunnelNonce& nonce);
void
ForwradLRDM(const PathID_t& id, const RouterID& from, llarp_buffer_t X,
const TunnelNonce& nonce);
bool
HopIsUs(const PubKey& k) const;
typedef std::unordered_map< TransitHopInfo, TransitHop,
TransitHopInfo::Hash >
typedef std::unordered_multimap< PathID_t, TransitHop, PathIDHash >
TransitHopsMap_t;
typedef std::pair< std::mutex, TransitHopsMap_t > SyncTransitMap_t;
struct PendingPathKey
{
RouterID upstream;
PathID_t txID;
PendingPathKey(const RouterID& up, const PathID_t& id)
: upstream(up), txID(id)
{
}
bool
operator==(const PendingPathKey& other) const
{
return upstream == other.upstream && txID == other.txID;
}
struct Hash
{
std::size_t
operator()(PendingPathKey const& a) const
{
std::size_t idx0, idx1;
memcpy(&idx0, a.upstream, sizeof(std::size_t));
memcpy(&idx1, a.txID, sizeof(std::size_t));
return idx0 ^ idx1;
}
};
};
typedef std::pair< TransitHopInfo, TransitHop > PendingCommit_t;
typedef std::pair< std::mutex,
std::unordered_map< PendingPathKey, PendingCommit_t,
PendingPathKey::Hash > >
SyncPendingCommitMap_t;
llarp_threadpool*
Worker();
@ -288,13 +334,15 @@ namespace llarp
byte_t*
EncryptionSecretKey();
const byte_t*
OurRouterID() const;
private:
llarp_router* m_Router;
SyncTransitMap_t m_TransitPaths;
SyncPendingCommitMap_t m_WaitingForAcks;
bool m_AllowTransit;
};
}
} // namespace llarp
#endif

@ -0,0 +1,69 @@
#ifndef LLARP_PATHFINDER_H_
#define LLARP_PATHFINDER_H_
#include <llarp/buffer.h>
#include <llarp/path.h>
/**
* path_base.h
*
* path api functions
*/
#ifdef __cplusplus
extern "C"
{
#endif
/// forard declare
struct llarp_router;
struct llarp_dht_context;
// fwd declr
struct llarp_pathbuilder_context;
/// alloc
struct llarp_pathbuilder_context*
llarp_pathbuilder_context_new(struct llarp_router* router,
struct llarp_dht_context* dht);
/// dealloc
void
llarp_pathbuilder_context_free(struct llarp_pathbuilder_context* ctx);
// fwd declr
struct llarp_pathbuild_job;
/// response callback
typedef void (*llarp_pathbuilder_hook)(struct llarp_pathbuild_job*);
// select hop function (nodedb, result, hopnnumber) called in logic thread
typedef void (*llarp_pathbuilder_select_hop_func)(struct llarp_nodedb*,
struct llarp_rc*, size_t);
// request struct
struct llarp_pathbuild_job
{
// opaque pointer for user data
void* user;
// router context (set by llarp_pathbuilder_build_path)
struct llarp_router* router;
// context
struct llarp_pathbuilder_context* context;
// path hop selection
llarp_pathbuilder_select_hop_func selectHop;
// result handler
llarp_pathbuilder_hook result;
// encryption secret key for hidden service
byte_t* secretkey;
// path
struct llarp_path_hops hops;
};
/// request func
// or find_path but thought pathfinder_find_path was a bit redundant
void
llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job);
#ifdef __cplusplus
}
#endif
#endif

@ -1,52 +0,0 @@
#ifndef LLARP_PATHFINDER_H_
#define LLARP_PATHFINDER_H_
#include <llarp/buffer.h>
#include <llarp/router.h>
#include <vector>
/**
* 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<llarp_rc> 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

@ -0,0 +1,30 @@
#ifndef LLARP_POW_HPP
#define LLARP_POW_HPP
#include <llarp/buffer.h>
#include <llarp/crypto.h>
#include <llarp/router_id.hpp>
namespace llarp
{
/// proof of work
struct PoW
{
static constexpr size_t MaxSize = 128;
RouterID router;
uint64_t version = 0;
uint32_t extendedLifetime = 0;
byte_t nonce[32];
bool
BEncode(llarp_buffer_t* buf) const;
bool
BDecode(llarp_buffer_t* buf);
bool
IsValid(llarp_shorthash_func hashfunc, const RouterID& us) const;
};
} // namespace llarp
#endif

@ -5,6 +5,7 @@
#include <llarp/link.h>
#include <llarp/logic.h>
#include <llarp/nodedb.h>
#include <llarp/pathbuilder.h>
#include <llarp/router_contact.h>
#include <llarp/threadpool.h>
@ -28,6 +29,11 @@ bool
llarp_router_try_connect(struct llarp_router *router, struct llarp_rc *remote,
uint16_t numretries);
/// override default path builder function (FFI)
void
llarp_router_override_path_selection(struct llarp_router *router,
llarp_pathbuilder_select_hop_func func);
bool
llarp_configure_router(struct llarp_router *router, struct llarp_config *conf);

@ -384,100 +384,100 @@ namespace iwp
frame->hook(frame);
delete frame;
}
}
extern "C" {
} // namespace iwp
void
iwp_call_async_keygen(struct llarp_async_iwp *iwp,
struct iwp_async_keygen *keygen)
extern "C"
{
keygen->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {keygen, &iwp::keygen});
}
void
iwp_call_async_keygen(struct llarp_async_iwp *iwp,
struct iwp_async_keygen *keygen)
{
keygen->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {keygen, &iwp::keygen});
}
void
iwp_call_async_gen_intro(struct llarp_async_iwp *iwp,
struct iwp_async_intro *intro)
{
intro->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {intro, &iwp::gen_intro});
}
void
iwp_call_async_gen_intro(struct llarp_async_iwp *iwp,
struct iwp_async_intro *intro)
{
intro->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {intro, &iwp::gen_intro});
}
void
iwp_call_async_verify_introack(struct llarp_async_iwp *iwp,
struct iwp_async_introack *introack)
{
introack->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {introack, &iwp::verify_introack});
}
void
iwp_call_async_verify_introack(struct llarp_async_iwp *iwp,
struct iwp_async_introack *introack)
{
introack->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {introack, &iwp::verify_introack});
}
void
iwp_call_async_gen_session_start(struct llarp_async_iwp *iwp,
struct iwp_async_session_start *session)
{
session->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {session, &iwp::gen_session_start});
}
void
iwp_call_async_gen_session_start(struct llarp_async_iwp *iwp,
struct iwp_async_session_start *session)
{
session->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {session, &iwp::gen_session_start});
}
void
iwp_call_async_verify_intro(struct llarp_async_iwp *iwp,
struct iwp_async_intro *intro)
{
intro->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {intro, &iwp::verify_intro});
}
void
iwp_call_async_verify_intro(struct llarp_async_iwp *iwp,
struct iwp_async_intro *intro)
{
intro->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {intro, &iwp::verify_intro});
}
void
iwp_call_async_gen_introack(struct llarp_async_iwp *iwp,
struct iwp_async_introack *introack)
{
introack->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {introack, &iwp::gen_introack});
}
void
iwp_call_async_gen_introack(struct llarp_async_iwp *iwp,
struct iwp_async_introack *introack)
{
introack->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {introack, &iwp::gen_introack});
}
void
iwp_call_async_frame_decrypt(struct llarp_async_iwp *iwp,
struct iwp_async_frame *frame)
{
frame->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {frame, &iwp::hmac_then_decrypt});
}
void
iwp_call_async_frame_decrypt(struct llarp_async_iwp *iwp,
struct iwp_async_frame *frame)
{
frame->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {frame, &iwp::hmac_then_decrypt});
}
void
iwp_call_async_frame_encrypt(struct llarp_async_iwp *iwp,
struct iwp_async_frame *frame)
{
frame->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {frame, &iwp::encrypt_then_hmac});
}
void
iwp_call_async_frame_encrypt(struct llarp_async_iwp *iwp,
struct iwp_async_frame *frame)
{
frame->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {frame, &iwp::encrypt_then_hmac});
}
void
iwp_call_async_verify_session_start(struct llarp_async_iwp *iwp,
struct iwp_async_session_start *session)
{
session->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker,
{session, &iwp::verify_session_start});
}
void
iwp_call_async_verify_session_start(struct llarp_async_iwp *iwp,
struct iwp_async_session_start *session)
{
session->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker,
{session, &iwp::verify_session_start});
}
struct llarp_async_iwp *
llarp_async_iwp_new(struct llarp_crypto *crypto, struct llarp_logic *logic,
struct llarp_threadpool *worker)
{
llarp_async_iwp *iwp = new llarp_async_iwp;
if(iwp)
struct llarp_async_iwp *
llarp_async_iwp_new(struct llarp_crypto *crypto, struct llarp_logic *logic,
struct llarp_threadpool *worker)
{
iwp->crypto = crypto;
iwp->logic = logic;
iwp->worker = worker;
llarp_async_iwp *iwp = new llarp_async_iwp;
if(iwp)
{
iwp->crypto = crypto;
iwp->logic = logic;
iwp->worker = worker;
}
return iwp;
}
return iwp;
}
void
llarp_async_iwp_free(struct llarp_async_iwp *iwp)
{
delete iwp;
}
void
llarp_async_iwp_free(struct llarp_async_iwp *iwp)
{
delete iwp;
}
}

@ -1,6 +1,7 @@
#include <llarp/crypto.hpp>
#include <llarp/encrypted_frame.hpp>
#include "logger.hpp"
#include "mem.hpp"
namespace llarp
{
@ -10,6 +11,8 @@ namespace llarp
data = new byte_t[sz];
if(buf)
memcpy(data, buf, sz);
else
llarp::Zero(data, sz);
m_Buffer.base = data;
m_Buffer.cur = data;
m_Buffer.sz = size;
@ -87,7 +90,8 @@ namespace llarp
{
if(size <= size_t(EncryptedFrame::OverheadSize))
{
llarp::Warn("encrypted frame too small, ", size, " <= ", size_t(EncryptedFrame::OverheadSize));
llarp::Warn("encrypted frame too small, ", size,
" <= ", size_t(EncryptedFrame::OverheadSize));
return false;
}
// format of frame is
@ -143,4 +147,4 @@ namespace llarp
}
return true;
}
}
} // namespace llarp

@ -5,6 +5,15 @@
namespace llarp
{
Path::Path(llarp_path_hops* h)
{
for(size_t idx = 0; idx < h->numHops; ++idx)
{
hops.emplace_back();
llarp_rc_copy(&hops[idx].router, &h->routers[idx]);
}
}
PathContext::PathContext(llarp_router* router)
: m_Router(router), m_AllowTransit(false)
{
@ -20,136 +29,10 @@ namespace llarp
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)
PathContext::AllowingTransit() const
{
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;
return m_AllowTransit;
}
llarp_threadpool*
@ -184,9 +67,7 @@ namespace llarp
bool
PathContext::ForwardLRCM(const RouterID& nextHop,
std::deque< EncryptedFrame >& frames,
std::deque< EncryptedAck >& acks,
EncryptedFrame& lastHop)
std::deque< EncryptedFrame >& frames)
{
LR_CommitMessage* msg = new LR_CommitMessage;
while(frames.size())
@ -194,21 +75,22 @@ namespace llarp
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 >
template < typename Map_t, typename Key_t, typename CheckValue_t >
bool
MapHas(Map_t& map, const Value_t& val)
MapHas(Map_t& map, const Key_t& k, CheckValue_t check)
{
std::unique_lock< std::mutex > lock(map.first);
return map.second.find(val) != map.second.end();
auto itr = map.second.find(k);
while(itr != map.second.end())
{
if(check(itr->second))
return true;
++itr;
}
return false;
}
template < typename Map_t, typename Key_t, typename Value_t >
@ -216,35 +98,54 @@ namespace llarp
MapPut(Map_t& map, const Key_t& k, const Value_t& v)
{
std::unique_lock< std::mutex > lock(map.first);
map.second[k] = v;
map.second.emplace(k, v);
}
bool
PathContext::HasTransitHop(const TransitHopInfo& info)
{
return MapHas(m_TransitPaths, info);
return MapHas(
m_TransitPaths, info.pathID,
[info](const TransitHop& hop) -> bool { return info == hop.info; });
}
const byte_t*
PathContext::OurRouterID() const
{
return m_Router->pubkey();
}
void
PathContext::PutPendingRelayCommit(const RouterID& upstream,
const PathID_t& txid,
const TransitHopInfo& info,
const TransitHop& hop)
PathContext::PutTransitHop(const TransitHop& hop)
{
MapPut(m_WaitingForAcks, PendingPathKey(upstream, txid),
std::make_pair(info, hop));
MapPut(m_TransitPaths, hop.info.pathID, hop);
}
void
PathContext::ExpirePaths()
{
std::unique_lock< std::mutex > lock(m_TransitPaths.first);
auto now = llarp_time_now_ms();
auto& map = m_TransitPaths.second;
auto itr = map.begin();
while(itr != map.end())
{
if(itr->second.Expired(now))
itr = map.erase(itr);
else
++itr;
}
}
bool
PathContext::HasPendingRelayCommit(const RouterID& upstream,
const PathID_t& txid)
TransitHop::Expired(llarp_time_t now) const
{
return MapHas(m_WaitingForAcks, PendingPathKey(upstream, txid));
return now - started > lifetime;
}
TransitHopInfo::TransitHopInfo(const RouterID& down,
const LR_CommitRecord& record)
: txID(record.txid), upstream(record.nextHop), downstream(down)
: pathID(record.pathid), upstream(record.nextHop), downstream(down)
{
}
}
} // namespace llarp

@ -0,0 +1,84 @@
#include <llarp/nodedb.h>
#include <llarp/path.hpp>
#include "pathbuilder.hpp"
#include "router.hpp"
namespace llarp
{
PathHopConfig::PathHopConfig()
{
llarp_rc_clear(&router);
}
PathHopConfig::~PathHopConfig()
{
llarp_rc_free(&router);
}
void
pathbuilder_generated_keys(
AsyncPathKeyExchangeContext< llarp_pathbuild_job >* ctx)
{
llarp::Debug("Generated keys for build");
}
void
pathbuilder_start_build(void* user)
{
// select hops
llarp_pathbuild_job* job = static_cast< llarp_pathbuild_job* >(user);
size_t idx = 0;
while(idx < job->hops.numHops)
{
job->selectHop(job->router->nodedb, &job->hops.routers[idx], idx);
++idx;
}
// async generate keys
AsyncPathKeyExchangeContext< llarp_pathbuild_job >* ctx =
new AsyncPathKeyExchangeContext< llarp_pathbuild_job >(
&job->router->crypto);
ctx->AsyncGenerateKeys(new Path(&job->hops), job->router->logic,
job->router->tp, job, &pathbuilder_generated_keys);
// free rc
idx = 0;
while(idx < job->hops.numHops)
{
llarp_rc_free(&job->hops.routers[idx]);
++idx;
}
}
} // namespace llarp
llarp_pathbuilder_context::llarp_pathbuilder_context(
llarp_router* p_router, struct llarp_dht_context* p_dht)
{
this->router = p_router;
this->dht = p_dht;
}
extern "C"
{
struct llarp_pathbuilder_context*
llarp_pathbuilder_context_new(struct llarp_router* router,
struct llarp_dht_context* dht)
{
return new llarp_pathbuilder_context(router, dht);
}
void
llarp_pathbuilder_context_free(struct llarp_pathbuilder_context* ctx)
{
delete ctx;
}
void
llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job)
{
job->router = job->context->router;
llarp_logic_queue_job(job->router->logic,
{job, &llarp::pathbuilder_start_build});
}
}

@ -0,0 +1,14 @@
#ifndef LLARP_PATHFINDER_HPP_
#define LLARP_PATHFINDER_HPP_
#include <llarp/pathbuilder.h>
struct llarp_pathbuilder_context
{
struct llarp_router* router;
struct llarp_dht_context* dht;
/// copy cstr
llarp_pathbuilder_context(llarp_router* p_router,
struct llarp_dht_context* p_dht);
};
#endif

@ -1,28 +1,2 @@
#include "pathfinder.hpp"
namespace llarp
{
void llarp_pathfinder_get_route(struct llarp_pathfinder_context* pathfinder) {
// what thread do pathfinder run in?
}
}
llarp_pathfinder_context::llarp_pathfinder_context(llarp_router *p_router, struct llarp_dht_context* p_dht)
{
this->router = p_router;
this->dht = p_dht;
}
extern "C" {
struct llarp_pathfinder_context *
llarp_pathfinder_context_new(struct llarp_router* router,
struct llarp_dht_context* dht) {
return new llarp_pathfinder_context(router, dht);
}
void
llarp_pathfinder_context_free(struct llarp_pathfinder_context* ctx) {
delete ctx;
}
}

@ -1,12 +0,0 @@
#ifndef LLARP_PATHFINDER_HPP_
#define LLARP_PATHFINDER_HPP_
#include <llarp/pathfinder.h>
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

@ -0,0 +1,47 @@
#include <cmath>
#include <llarp/pow.hpp>
#include "buffer.hpp"
namespace llarp
{
bool
PoW::BDecode(llarp_buffer_t* buf)
{
return false;
}
bool
PoW::BEncode(llarp_buffer_t* buf) const
{
return false;
}
bool
PoW::IsValid(llarp_shorthash_func hashfunc, const RouterID& us) const
{
// is it for us?
if(router != us)
return false;
byte_t digest[SHORTHASHSIZE];
byte_t tmp[MaxSize];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
// encode
if(!BEncode(&buf))
return false;
// rewind
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// hash
if(!hashfunc(digest, buf))
return false;
// check bytes required
uint32_t required = std::floor(std::log(extendedLifetime));
for(uint32_t idx = 0; idx < required; ++idx)
{
if(digest[idx])
return false;
}
return true;
}
} // namespace llarp

@ -77,14 +77,8 @@ namespace llarp
bool
LR_AckMessage::HandleMessage(llarp_router* router) const
{
if(!router->paths.HasPendingRelayCommit(remote, txPathID))
{
llarp::Warn("got LRAM from ", remote,
" with no previous LRCM txid=", txPathID);
return false;
}
// TODO: use different private key for different path contexts as client
LRAM_Decrypt* lram = new LRAM_Decrypt(router, router->encryption, acks);
LRAM_Decrypt* lram = new LRAM_Decrypt(router, router->encryption, replies);
lram->decrypt->AsyncDecrypt(router->tp, &lram->frames[0], lram);
return true;
}

@ -5,6 +5,24 @@
namespace llarp
{
bool
LR_AcceptRecord::BEncode(llarp_buffer_t* buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "c", "a"))
return false;
if(!BEncodeWriteDictEntry("p", pathid, buf))
return false;
if(!BEncodeWriteDictEntry("r", downstream, buf))
return false;
if(!BEncodeWriteDictEntry("t", upstream, buf))
return false;
if(!BEncodeWriteDictInt(buf, "v", LLARP_PROTO_VERSION))
return false;
return bencode_end(buf);
}
LR_CommitMessage::~LR_CommitMessage()
{
}
@ -16,14 +34,6 @@ namespace llarp
{
return BEncodeReadList(frames, buf);
}
if(llarp_buffer_eq(key, "f"))
{
return lasthopFrame.BDecode(buf);
}
if(llarp_buffer_eq(key, "r"))
{
return BEncodeReadList(acks, buf);
}
bool read = false;
if(!BEncodeMaybeReadVersion("v", version, LLARP_PROTO_VERSION, read, key,
buf))
@ -43,12 +53,6 @@ namespace llarp
// frames
if(!BEncodeWriteDictList("c", frames, buf))
return false;
// last hop
if(!BEncodeWriteDictEntry("f", lasthopFrame, buf))
return false;
// acks
if(!BEncodeWriteDictList("r", acks, buf))
return false;
// version
if(!bencode_write_version_entry(buf))
return false;
@ -59,7 +63,19 @@ namespace llarp
bool
LR_CommitMessage::HandleMessage(llarp_router* router) const
{
return router->paths.HandleRelayCommit(this);
if(frames.size() != MAXHOPS)
{
llarp::Error("LRCM invalid number of records, ", frames.size(),
"!=", MAXHOPS);
return false;
}
if(!router->paths.AllowingTransit())
{
llarp::Error("got an LRCM from ", remote,
" when we are not allowing transit");
return false;
}
return AsyncDecrypt(&router->paths);
}
bool
@ -74,18 +90,22 @@ namespace llarp
return false;
if(!BEncodeWriteDictEntry("n", tunnelNonce, buf))
return false;
if(!BEncodeWriteDictEntry("p", txid, buf))
return false;
if(!BEncodeWriteDictEntry("s", downstreamReplyKey, buf))
return false;
if(!BEncodeWriteDictEntry("u", downstreamReplyNonce, buf))
if(!BEncodeWriteDictEntry("p", pathid, buf))
return false;
if(!bencode_write_version_entry(buf))
return false;
if(work && !BEncodeWriteDictEntry("w", *work, buf))
return false;
return bencode_end(buf);
}
LR_CommitRecord::~LR_CommitRecord()
{
if(work)
delete work;
}
bool
LR_CommitRecord::OnKey(dict_reader* r, llarp_buffer_t* key)
{
@ -102,18 +122,20 @@ namespace llarp
return false;
if(BEncodeMaybeReadDictEntry("n", self->tunnelNonce, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("p", self->txid, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("s", self->downstreamReplyKey, read, *key,
r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("u", self->downstreamReplyNonce, read, *key,
r->buffer))
if(!BEncodeMaybeReadDictEntry("p", self->pathid, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadVersion("v", self->version, LLARP_PROTO_VERSION, read,
*key, r->buffer))
return false;
if(llarp_buffer_eq(*key, "w"))
{
// check for duplicate
if(self->work)
return false;
self->work = new PoW;
return self->work->BDecode(r->buffer);
}
return read;
}
@ -125,4 +147,154 @@ namespace llarp
r.on_key = &OnKey;
return bencode_read_dict(buf, &r);
}
}
struct LRCMFrameDecrypt
{
typedef AsyncFrameDecrypter< LRCMFrameDecrypt > Decrypter;
Decrypter* decrypter;
std::deque< EncryptedFrame > frames;
PathContext* context;
// decrypted record
LR_CommitRecord record;
// the actual hop
TransitHop hop;
LRCMFrameDecrypt(PathContext* ctx, Decrypter* dec,
const LR_CommitMessage* commit)
: decrypter(dec), context(ctx)
{
for(const auto& f : commit->frames)
frames.push_front(f);
hop.info.downstream = commit->remote;
}
~LRCMFrameDecrypt()
{
delete decrypter;
}
/// this must be done from logic thread
static void
SendLRCM(void* user)
{
LRCMFrameDecrypt* self = static_cast< LRCMFrameDecrypt* >(user);
self->context->ForwardLRCM(self->hop.info.upstream, self->frames);
delete self;
}
static void
SendLRAM(void* user)
{
}
static void
HandleDecrypted(llarp_buffer_t* buf, LRCMFrameDecrypt* self)
{
auto& info = self->hop.info;
if(!buf)
{
llarp::Error("LRCM decrypt failed from ", info.downstream);
delete self;
return;
}
llarp::Debug("decrypted LRCM from ", info.downstream);
// successful decrypt
if(!self->record.BDecode(buf))
{
llarp::Error("malformed frame inside LRCM from ", info.downstream);
delete self;
return;
}
info.pathID = self->record.pathid;
info.upstream = self->record.nextHop;
if(self->context->HasTransitHop(info))
{
llarp::Error("duplicate transit hop ", info);
delete self;
return;
}
// 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,
self->context->EncryptionSecretKey(), self->record.tunnelNonce))
{
llarp::Error("LRCM DH Failed ", info);
delete self;
return;
}
if(self->record.work
&& self->record.work->IsValid(self->context->Crypto()->shorthash,
self->context->OurRouterID()))
{
llarp::Info("LRCM extended lifetime by ",
self->record.work->extendedLifetime, " seconds for ", info);
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->context->PutTransitHop(self->hop);
size_t sz = self->frames.front().size;
// we pop the front element it was ours
self->frames.pop_front();
// put our response on the end
self->frames.emplace_back(sz);
auto& reply = self->frames.back();
auto replybuf = reply.Buffer();
LR_AcceptRecord replyrecord;
replyrecord.upstream = info.upstream;
replyrecord.downstream = info.downstream;
replyrecord.pathid = info.pathID;
if(!replyrecord.BEncode(replybuf))
{
llarp::Error("failed to encode reply to LRCM, buffer too small?");
delete self;
return;
}
// randomize leftover data inside reply
auto left = llarp_buffer_size_left(*replybuf);
if(left)
self->context->Crypto()->randbytes(replybuf->cur, left);
// encrypt in place since we are in the worker thread
if(!reply.EncryptInPlace(self->context->EncryptionSecretKey(),
self->record.commkey, self->context->Crypto()))
{
// failed to encrypt wtf?
llarp::Error("Failed to encrypt reply to LRCM");
delete self;
return;
}
if(self->context->HopIsUs(info.upstream))
{
// 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});
}
else
{
// forward upstream
// we are still in the worker thread so post job to logic
llarp_logic_queue_job(self->context->Logic(), {self, &SendLRCM});
}
}
};
bool
LR_CommitMessage::AsyncDecrypt(PathContext* context) const
{
LRCMFrameDecrypt::Decrypter* decrypter = new LRCMFrameDecrypt::Decrypter(
context->Crypto(), context->EncryptionSecretKey(),
&LRCMFrameDecrypt::HandleDecrypted);
// copy frames so we own them
LRCMFrameDecrypt* frames = new LRCMFrameDecrypt(context, decrypter, this);
// decrypt frames async
decrypter->AsyncDecrypt(context->Worker(), &frames->frames.front(), frames);
return true;
}
} // namespace llarp

@ -363,6 +363,9 @@ void
llarp_router::Tick()
{
llarp::Debug("tick router");
paths.ExpirePaths();
llarp_pathbuild_job job;
llarp_pathbuilder_build_path(&job);
llarp_link_session_iter iter;
iter.user = this;
iter.visit = &send_padded_message;
@ -627,30 +630,6 @@ llarp_router::ConnectAll(void *user, uint64_t orig, uint64_t left)
self->try_connect(itr.second);
}
}
extern "C" {
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)
{
router->netloop = netloop;
router->tp = tp;
router->logic = logic;
// TODO: make disk io threadpool count configurable
#ifdef TESTNET
router->disk = tp;
#else
router->disk = llarp_init_threadpool(1, "llarp-diskio");
#endif
llarp_crypto_libsodium_init(&router->crypto);
}
return router;
}
bool
llarp_router::InitOutboundLink()
{
@ -686,185 +665,216 @@ llarp_router::InitOutboundLink()
return false;
}
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();
}
bool
llarp_router::HasPendingConnectJob(const llarp::RouterID &remote)
{
return pendingEstablishJobs.find(remote) != pendingEstablishJobs.end();
}
bool
llarp_router_try_connect(struct llarp_router *router, struct llarp_rc *remote,
uint16_t numretries)
extern "C"
{
// 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;
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)
{
router->netloop = netloop;
router->tp = tp;
router->logic = logic;
// TODO: make disk io threadpool count configurable
#ifdef TESTNET
router->disk = tp;
#else
router->disk = llarp_init_threadpool(1, "llarp-diskio");
#endif
llarp_crypto_libsodium_init(&router->crypto);
}
return router;
}
return false;
}
void
llarp_rc_clear(struct llarp_rc *rc)
{
// zero out router contact
llarp::Zero(rc, sizeof(llarp_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;
}
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);
}
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_rc_set_pubkey(struct llarp_rc *rc, const uint8_t *pubkey)
{
// set public key
memcpy(rc->pubkey, pubkey, 32);
}
void
llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb)
{
router->nodedb = nodedb;
router->Run();
}
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))
bool
llarp_router_try_connect(struct llarp_router *router, struct llarp_rc *remote,
uint16_t numretries)
{
llarp::Info("regenerated identity key");
crypto->identity_keygen(secretkey);
std::ofstream f(path, std::ios::binary);
if(f.is_open())
// 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))
{
f.write((char *)secretkey, SECKEYSIZE);
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;
}
std::ifstream f(path, std::ios::binary);
if(f.is_open())
void
llarp_rc_clear(struct llarp_rc *rc)
{
f.read((char *)secretkey, SECKEYSIZE);
// zero out router contact
llarp::Zero(rc, sizeof(llarp_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;
}
llarp::Info("failed to get identity key");
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_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))
void
llarp_rc_set_pubkey(struct llarp_rc *rc, const uint8_t *pubkey)
{
std::ofstream f(our_rc_file, std::ios::binary);
// set public key
memcpy(rc->pubkey, pubkey, 32);
}
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::Info("regenerated 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);
if(f.is_open())
{
f.write((char *)buf.base, buf.cur - buf.base);
f.read((char *)secretkey, SECKEYSIZE);
return true;
}
llarp::Info("failed to get identity key");
return false;
}
return false;
}
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))
bool
llarp_rc_write(struct llarp_rc *rc, const char *fpath)
{
// sign
signbuf.sz = signbuf.cur - signbuf.base;
crypto->sign(rc->signature, seckey, signbuf);
fs::path our_rc_file(fpath);
byte_t tmp[MAX_RC_SIZE];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
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;
}
}
void
llarp_stop_router(struct llarp_router *router)
{
if(router)
router->Close();
}
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))
{
// 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)
{
if(*router)
void
llarp_router_iterate_links(struct llarp_router *router,
struct llarp_router_link_iter i)
{
delete *router;
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)
{
delete *router;
}
*router = nullptr;
}
void
llarp_router_override_path_selection(struct llarp_router *router,
llarp_pathbuilder_select_hop_func func)
{
if(func)
router->selectHopFunc = func;
}
*router = nullptr;
}
}
namespace llarp

@ -71,6 +71,8 @@ struct llarp_router
llarp::InboundMessageParser inbound_msg_parser;
llarp_pathbuilder_select_hop_func selectHopFunc = nullptr;
llarp_link *outboundLink = nullptr;
std::list< llarp_link * > inboundLinks;

Loading…
Cancel
Save