From 08c0318e82dbdbb7ee5607f8b34c714c3225891d Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 18 Jun 2018 18:03:50 -0400 Subject: [PATCH] initial path building stuff (broken) --- .vscode/c_cpp_properties.json | 6 +- .vscode/settings.json | 58 +++- .vscode/tasks.json | 5 +- CMakeLists.txt | 7 +- daemon/rcutil.cpp | 2 +- include/llarp/aligned.hpp | 2 +- include/llarp/messages/relay_ack.hpp | 9 +- include/llarp/messages/relay_commit.hpp | 28 +- include/llarp/nodedb.h | 232 ++++++++-------- include/llarp/path.h | 21 ++ include/llarp/path.hpp | 210 ++++++++------ include/llarp/pathbuilder.h | 69 +++++ include/llarp/pathfinder.h | 52 ---- include/llarp/pow.hpp | 30 ++ include/llarp/router.h | 6 + llarp/crypto_async.cpp | 164 +++++------ llarp/encrypted_frame.cpp | 8 +- llarp/path.cpp | 207 ++++---------- llarp/pathbuilder.cpp | 84 ++++++ llarp/pathbuilder.hpp | 14 + llarp/pathfinder.cpp | 26 -- llarp/pathfinder.hpp | 12 - llarp/proofofwork.cpp | 47 ++++ llarp/relay_ack.cpp | 8 +- llarp/relay_commit.cpp | 228 ++++++++++++++-- llarp/router.cpp | 348 ++++++++++++------------ llarp/router.hpp | 2 + 27 files changed, 1136 insertions(+), 749 deletions(-) create mode 100644 include/llarp/path.h create mode 100644 include/llarp/pathbuilder.h delete mode 100644 include/llarp/pathfinder.h create mode 100644 include/llarp/pow.hpp create mode 100644 llarp/pathbuilder.cpp create mode 100644 llarp/pathbuilder.hpp delete mode 100644 llarp/pathfinder.hpp create mode 100644 llarp/proofofwork.cpp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index f5547f9e1..eb2974c33 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -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", diff --git a/.vscode/settings.json b/.vscode/settings.json index cac0e10e6..139978ee1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" + } } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 1f97d7477..7e2c2059b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,10 @@ "label": "build", "type": "shell", "command": "make", - "group": "build" + "group": "build", + "problemMatcher": [ + "$gcc" + ] } ] } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 547569422..34e18e5f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/daemon/rcutil.cpp b/daemon/rcutil.cpp index 7e617eee7..413b0f4b1 100644 --- a/daemon/rcutil.cpp +++ b/daemon/rcutil.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[] = { diff --git a/include/llarp/aligned.hpp b/include/llarp/aligned.hpp index c41748195..f705c1323 100644 --- a/include/llarp/aligned.hpp +++ b/include/llarp/aligned.hpp @@ -142,6 +142,6 @@ namespace llarp uint64_t l[sz / 8]; }; }; -} +} // namespace llarp #endif diff --git a/include/llarp/messages/relay_ack.hpp b/include/llarp/messages/relay_ack.hpp index 8ee5a492d..b6c561ece 100644 --- a/include/llarp/messages/relay_ack.hpp +++ b/include/llarp/messages/relay_ack.hpp @@ -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 diff --git a/include/llarp/messages/relay_commit.hpp b/include/llarp/messages/relay_commit.hpp index ba2453c79..90d4438a5 100644 --- a/include/llarp/messages/relay_commit.hpp +++ b/include/llarp/messages/relay_commit.hpp @@ -5,18 +5,21 @@ #include #include #include +#include #include 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 diff --git a/include/llarp/nodedb.h b/include/llarp/nodedb.h index 5c49a8b25..f6eefd688 100644 --- a/include/llarp/nodedb.h +++ b/include/llarp/nodedb.h @@ -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 } diff --git a/include/llarp/path.h b/include/llarp/path.h new file mode 100644 index 000000000..d261d20ff --- /dev/null +++ b/include/llarp/path.h @@ -0,0 +1,21 @@ +#ifndef LLARP_PATH_H +#define LLARP_PATH_H + +#include + +#define MAXHOPS (8) +#ifdef __cplusplus +extern "C" +{ +#endif + + struct llarp_path_hops + { + struct llarp_rc routers[MAXHOPS]; + size_t numHops; + }; + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/include/llarp/path.hpp b/include/llarp/path.hpp index 023a49ef6..b1f0a265a 100644 --- a/include/llarp/path.hpp +++ b/include/llarp/path.hpp @@ -1,5 +1,6 @@ #ifndef LLARP_PATH_HPP #define LLARP_PATH_HPP +#include #include #include #include @@ -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 << ""; } @@ -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 diff --git a/include/llarp/pathbuilder.h b/include/llarp/pathbuilder.h new file mode 100644 index 000000000..4f455df09 --- /dev/null +++ b/include/llarp/pathbuilder.h @@ -0,0 +1,69 @@ +#ifndef LLARP_PATHFINDER_H_ +#define LLARP_PATHFINDER_H_ + +#include +#include + +/** + * 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 diff --git a/include/llarp/pathfinder.h b/include/llarp/pathfinder.h deleted file mode 100644 index c5ddd33f1..000000000 --- a/include/llarp/pathfinder.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef LLARP_PATHFINDER_H_ -#define LLARP_PATHFINDER_H_ - -#include -#include -#include - -/** - * path_base.h - * - * path api functions - */ - -#ifdef __cplusplus -extern "C" { -#endif - -// fwd declr -struct llarp_pathfinder_context; - -/// alloc -struct llarp_pathfinder_context * - llarp_pathfinder_context_new(struct llarp_router* router, - struct llarp_dht_context* dht); -/// dealloc -void - llarp_pathfinder_context_free(struct llarp_pathfinder_context* ctx); - -// fwd declr -struct llarp_get_route; - -/// response callback -typedef void (*llarp_pathfinder_response)(struct llarp_get_route *); - -// request struct -struct llarp_get_route -{ - // context - struct llarp_pathfinder_context* pathfinder; - // parameter - byte_t destination[PUBKEYSIZE]; - // result - std::vector route; -}; -/// request func -// or find_path but thought pathfinder_find_path was a bit redundant -void llarp_pathfinder_get_route(struct llarp_pathfinder_context* pathfinder); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/include/llarp/pow.hpp b/include/llarp/pow.hpp new file mode 100644 index 000000000..92f7cf6fb --- /dev/null +++ b/include/llarp/pow.hpp @@ -0,0 +1,30 @@ +#ifndef LLARP_POW_HPP +#define LLARP_POW_HPP +#include +#include +#include + +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 \ No newline at end of file diff --git a/include/llarp/router.h b/include/llarp/router.h index d65c56fbe..6032ca76e 100644 --- a/include/llarp/router.h +++ b/include/llarp/router.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -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); diff --git a/llarp/crypto_async.cpp b/llarp/crypto_async.cpp index 05a016a78..3e9238608 100644 --- a/llarp/crypto_async.cpp +++ b/llarp/crypto_async.cpp @@ -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; + } } diff --git a/llarp/encrypted_frame.cpp b/llarp/encrypted_frame.cpp index b4bea62c6..9f1b3d3e8 100644 --- a/llarp/encrypted_frame.cpp +++ b/llarp/encrypted_frame.cpp @@ -1,6 +1,7 @@ #include #include #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 diff --git a/llarp/path.cpp b/llarp/path.cpp index 9d2270622..e3e5ca3a2 100644 --- a/llarp/path.cpp +++ b/llarp/path.cpp @@ -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) { } -} \ No newline at end of file +} // namespace llarp \ No newline at end of file diff --git a/llarp/pathbuilder.cpp b/llarp/pathbuilder.cpp new file mode 100644 index 000000000..66c7933f7 --- /dev/null +++ b/llarp/pathbuilder.cpp @@ -0,0 +1,84 @@ +#include +#include + +#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}); + } +} \ No newline at end of file diff --git a/llarp/pathbuilder.hpp b/llarp/pathbuilder.hpp new file mode 100644 index 000000000..fa01cd1c2 --- /dev/null +++ b/llarp/pathbuilder.hpp @@ -0,0 +1,14 @@ +#ifndef LLARP_PATHFINDER_HPP_ +#define LLARP_PATHFINDER_HPP_ +#include + +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 diff --git a/llarp/pathfinder.cpp b/llarp/pathfinder.cpp index 4d1ddc36f..0c233652c 100644 --- a/llarp/pathfinder.cpp +++ b/llarp/pathfinder.cpp @@ -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; - } -} diff --git a/llarp/pathfinder.hpp b/llarp/pathfinder.hpp deleted file mode 100644 index 910076391..000000000 --- a/llarp/pathfinder.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef LLARP_PATHFINDER_HPP_ -#define LLARP_PATHFINDER_HPP_ -#include - -struct llarp_pathfinder_context { - struct llarp_router* router; - struct llarp_dht_context* dht; - /// copy cstr - llarp_pathfinder_context(llarp_router *p_router, struct llarp_dht_context* p_dht); -}; - -#endif diff --git a/llarp/proofofwork.cpp b/llarp/proofofwork.cpp new file mode 100644 index 000000000..ab340106f --- /dev/null +++ b/llarp/proofofwork.cpp @@ -0,0 +1,47 @@ +#include +#include +#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 \ No newline at end of file diff --git a/llarp/relay_ack.cpp b/llarp/relay_ack.cpp index 54a0c290e..0632a2802 100644 --- a/llarp/relay_ack.cpp +++ b/llarp/relay_ack.cpp @@ -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; } diff --git a/llarp/relay_commit.cpp b/llarp/relay_commit.cpp index fbc244824..987d8bc9d 100644 --- a/llarp/relay_commit.cpp +++ b/llarp/relay_commit.cpp @@ -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 diff --git a/llarp/router.cpp b/llarp/router.cpp index 1630fea5d..0915e850f 100644 --- a/llarp/router.cpp +++ b/llarp/router.cpp @@ -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 diff --git a/llarp/router.hpp b/llarp/router.hpp index 626d842aa..5b89e3116 100644 --- a/llarp/router.hpp +++ b/llarp/router.hpp @@ -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;