diff --git a/CMakeLists.txt b/CMakeLists.txt index 34e18e5f1..793bbcca0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ else() endif() set(DEBUG_FLAGS "-g") -set(OPTIMIZE_FLAGS "-Os") +set(OPTIMIZE_FLAGS "-O0") if(ASAN) set(DEBUG_FLAGS "${DEBUG_FLAGS} -fsanitize=address -fno-omit-frame-pointer") @@ -155,6 +155,7 @@ set(LIB_SRC set(TEST_SRC test/main.cpp test/dht_unittest.cpp + test/encrypted_frame_unittest.cpp ) set(TEST_EXE testAll) set(GTEST_DIR test/gtest) diff --git a/Makefile b/Makefile index a0f07e4ab..a8a3df515 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,7 @@ testnet: testnet-build supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF) test: debug-configure + ninja ninja test format: diff --git a/contrib/testnet/genconf.py b/contrib/testnet/genconf.py index 3e87e7687..a9f39bf03 100644 --- a/contrib/testnet/genconf.py +++ b/contrib/testnet/genconf.py @@ -60,11 +60,11 @@ def main(): 'dir': 'netdb' } config['connect'] = {} - for otherid in range(args.svc): - if otherid % args.connect == 0: - name = svcNodeName(otherid) - config['connect'][name] = os.path.join( - basedir, name, 'rc.signed') + for otherid in range(args.connect): + otherid = (nodeid + otherid) % args.svc + name = svcNodeName(otherid) + config['connect'][name] = os.path.join( + basedir, name, 'rc.signed') d = os.path.join(args.dir, clientNodeName(nodeid)) if not os.path.exists(d): diff --git a/include/llarp/encrypted.hpp b/include/llarp/encrypted.hpp index 827635231..c58d2d467 100644 --- a/include/llarp/encrypted.hpp +++ b/include/llarp/encrypted.hpp @@ -21,6 +21,12 @@ namespace llarp return bencode_write_bytestring(buf, _data.data(), _data.size()); } + void + Fill(byte_t fill) + { + std::fill(_data.begin(), _data.end(), fill); + } + void Randomize() { diff --git a/include/llarp/encrypted_frame.hpp b/include/llarp/encrypted_frame.hpp index 896016b25..81252d215 100644 --- a/include/llarp/encrypted_frame.hpp +++ b/include/llarp/encrypted_frame.hpp @@ -102,6 +102,7 @@ namespace llarp llarp_crypto* crypto; byte_t* seckey; EncryptedFrame* target; + void AsyncDecrypt(llarp_threadpool* worker, EncryptedFrame* frame, User* user) { diff --git a/include/llarp/logger.hpp b/include/llarp/logger.hpp index 2d9dc3225..0d38cd546 100644 --- a/include/llarp/logger.hpp +++ b/include/llarp/logger.hpp @@ -90,7 +90,7 @@ namespace llarp _glog.out << "\n" << std::flush; #endif } -} +} // namespace llarp #define Debug(x, ...) _Log(llarp::eLogDebug, __FILE__, x, ##__VA_ARGS__) #define Info(x, ...) _Log(llarp::eLogInfo, __FILE__, x, ##__VA_ARGS__) diff --git a/include/llarp/nodedb.h b/include/llarp/nodedb.h index 442d2ce85..24080132b 100644 --- a/include/llarp/nodedb.h +++ b/include/llarp/nodedb.h @@ -54,8 +54,8 @@ 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); +llarp_nodedb_select_random_hop(struct llarp_nodedb *n, struct llarp_rc *prev, + struct llarp_rc *result, size_t N); /// return number of RC loaded size_t diff --git a/include/llarp/path.hpp b/include/llarp/path.hpp index f66bf4e66..1907058e0 100644 --- a/include/llarp/path.hpp +++ b/include/llarp/path.hpp @@ -169,30 +169,29 @@ namespace llarp LR_CommitMessage* LRCM = nullptr; static void - HandleDone(void* user) + HandleDone(void* u) { AsyncPathKeyExchangeContext< User >* ctx = - static_cast< AsyncPathKeyExchangeContext< User >* >(user); + static_cast< AsyncPathKeyExchangeContext< User >* >(u); ctx->result(ctx); - delete ctx; } static void - GenerateNextKey(void* user) + GenerateNextKey(void* u) { AsyncPathKeyExchangeContext< User >* ctx = - static_cast< AsyncPathKeyExchangeContext< User >* >(user); + static_cast< AsyncPathKeyExchangeContext< User >* >(u); auto& hop = ctx->path->hops[ctx->idx]; // generate key ctx->crypto->encryption_keygen(hop.commkey); + hop.nonce.Randomize(); // 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->user; - delete ctx; + abort(); return; } // randomize hop's path id @@ -210,13 +209,23 @@ namespace llarp { hop.upstream = hop.router.pubkey; } + auto buf = frame.Buffer(); + buf->cur = buf->base + EncryptedFrame::OverheadSize; // generate record - if(!record.BEncode(frame.Buffer())) + if(!record.BEncode(buf)) { // failed to encode? llarp::Error("Failed to generate Commit Record"); - delete ctx->user; - delete ctx; + abort(); + return; + } + // rewind + buf->cur = buf->base; + + if(!frame.EncryptInPlace(hop.commkey, hop.router.enckey, ctx->crypto)) + { + llarp::Error("Failed to encrypt LRCR"); + abort(); return; } diff --git a/include/llarp/pathbuilder.h b/include/llarp/pathbuilder.h index b249f30ee..d57ad0c54 100644 --- a/include/llarp/pathbuilder.h +++ b/include/llarp/pathbuilder.h @@ -34,8 +34,10 @@ 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 +// select hop function (nodedb, prevhop, result, hopnnumber) called in logic +// thread typedef void (*llarp_pathbuilder_select_hop_func)(struct llarp_nodedb*, + struct llarp_rc*, struct llarp_rc*, size_t); // request struct diff --git a/llarp/crypto_libsodium.cpp b/llarp/crypto_libsodium.cpp index 6e71cb769..e2f9a56ff 100644 --- a/llarp/crypto_libsodium.cpp +++ b/llarp/crypto_libsodium.cpp @@ -16,14 +16,14 @@ namespace llarp } static bool - dh(uint8_t *out, uint8_t *client_pk, uint8_t *server_pk, uint8_t *pubkey, - uint8_t *secret) + dh(uint8_t *out, uint8_t *client_pk, uint8_t *server_pk, uint8_t *themPub, + uint8_t *usSec) { llarp::SharedSecret shared; crypto_generichash_state h; const size_t outsz = SHAREDKEYSIZE; - if(crypto_scalarmult_curve25519(shared, secret, pubkey)) + if(crypto_scalarmult_curve25519(shared, usSec, themPub)) return false; crypto_generichash_init(&h, NULL, 0U, outsz); crypto_generichash_update(&h, client_pk, 32); @@ -34,31 +34,7 @@ namespace llarp } static bool - dh_client(byte_t *shared, byte_t *pk, byte_t *n, byte_t *sk) - { - if(dh(shared, llarp::seckey_topublic(sk), pk, pk, sk)) - { - return crypto_generichash(shared, SHAREDKEYSIZE, shared, SHAREDKEYSIZE, - n, TUNNONCESIZE) - != -1; - } - return false; - } - - static bool - dh_server(byte_t *shared, byte_t *pk, byte_t *n, byte_t *sk) - { - if(dh(shared, pk, llarp::seckey_topublic(sk), pk, sk)) - { - return crypto_generichash(shared, SHAREDKEYSIZE, shared, SHAREDKEYSIZE, - n, TUNNONCESIZE) - != -1; - } - return false; - } - - static bool - transport_dh_client(uint8_t *shared, uint8_t *pk, uint8_t *sk, uint8_t *n) + dh_client(uint8_t *shared, uint8_t *pk, uint8_t *sk, uint8_t *n) { llarp::SharedSecret dh_result; if(dh(dh_result, llarp::seckey_topublic(sk), pk, pk, sk)) @@ -69,7 +45,7 @@ namespace llarp } static bool - transport_dh_server(uint8_t *shared, uint8_t *pk, uint8_t *sk, uint8_t *n) + dh_server(uint8_t *shared, uint8_t *pk, uint8_t *sk, uint8_t *n) { llarp::SharedSecret dh_result; if(dh(dh_result, pk, llarp::seckey_topublic(sk), pk, sk)) @@ -155,34 +131,34 @@ namespace llarp } // namespace llarp -extern "C" { - -const byte_t * -llarp_seckey_topublic(const byte_t *secret) +extern "C" { - return secret + 32; -} + const byte_t * + llarp_seckey_topublic(const byte_t *secret) + { + return secret + 32; + } -void -llarp_crypto_libsodium_init(struct llarp_crypto *c) -{ - assert(sodium_init() != -1); - c->xchacha20 = llarp::sodium::xchacha20; - c->dh_client = llarp::sodium::dh_client; - c->dh_server = llarp::sodium::dh_server; - c->transport_dh_client = llarp::sodium::transport_dh_client; - c->transport_dh_server = llarp::sodium::transport_dh_server; - c->hash = llarp::sodium::hash; - c->shorthash = llarp::sodium::shorthash; - c->hmac = llarp::sodium::hmac; - c->sign = llarp::sodium::sign; - c->verify = llarp::sodium::verify; - c->randomize = llarp::sodium::randomize; - c->randbytes = llarp::sodium::randbytes; - c->identity_keygen = llarp::sodium::sigkeygen; - c->encryption_keygen = llarp::sodium::enckeygen; - int seed; - c->randbytes(&seed, sizeof(seed)); - srand(seed); -} + void + llarp_crypto_libsodium_init(struct llarp_crypto *c) + { + assert(sodium_init() != -1); + c->xchacha20 = llarp::sodium::xchacha20; + c->dh_client = llarp::sodium::dh_client; + c->dh_server = llarp::sodium::dh_server; + c->transport_dh_client = llarp::sodium::dh_client; + c->transport_dh_server = llarp::sodium::dh_server; + c->hash = llarp::sodium::hash; + c->shorthash = llarp::sodium::shorthash; + c->hmac = llarp::sodium::hmac; + c->sign = llarp::sodium::sign; + c->verify = llarp::sodium::verify; + c->randomize = llarp::sodium::randomize; + c->randbytes = llarp::sodium::randbytes; + c->identity_keygen = llarp::sodium::sigkeygen; + c->encryption_keygen = llarp::sodium::enckeygen; + int seed; + c->randbytes(&seed, sizeof(seed)); + srand(seed); + } } diff --git a/llarp/encrypted_frame.cpp b/llarp/encrypted_frame.cpp index 7b8625e9b..205b5fbc5 100644 --- a/llarp/encrypted_frame.cpp +++ b/llarp/encrypted_frame.cpp @@ -52,11 +52,12 @@ namespace llarp crypto->randbytes(nonce, TUNNONCESIZE); // derive shared key - if(!DH(shared, otherPubkey, nonce, ourSecretKey)) + if(!DH(shared, otherPubkey, ourSecretKey, nonce)) { llarp::Error("DH failed"); return false; } + // encrypt body if(!Encrypt(buf, shared, nonce)) { @@ -110,7 +111,7 @@ namespace llarp SharedSecret shared; ShortHash digest; - if(!DH(shared, otherPubkey, nonce, ourSecretKey)) + if(!DH(shared, otherPubkey, ourSecretKey, nonce)) { llarp::Error("DH failed"); return false; diff --git a/llarp/iwp_link.cpp b/llarp/iwp_link.cpp index 6a432cf3f..21592348b 100644 --- a/llarp/iwp_link.cpp +++ b/llarp/iwp_link.cpp @@ -30,8 +30,8 @@ namespace iwp { - // session activity timeout is 5s - constexpr llarp_time_t SESSION_TIMEOUT = 5000; + // session activity timeout is 10s + constexpr llarp_time_t SESSION_TIMEOUT = 10000; constexpr size_t MAX_PAD = 128; @@ -678,7 +678,7 @@ namespace iwp uint32_t establish_job_id = 0; uint32_t frames = 0; - + bool working = false; llarp::Addr addr; iwp_async_intro intro; iwp_async_introack introack; @@ -853,7 +853,7 @@ namespace iwp // when we are done doing stuff with all of our frames from the crypto // workers we are done llarp::Debug(addr, " timed out with ", frames, " frames left"); - return frames == 0; + return frames == 0 && !working; } if(is_invalidated()) { @@ -862,7 +862,7 @@ namespace iwp // are done llarp::Debug(addr, " invaldiated session with ", frames, " frames left"); - return frames == 0; + return frames == 0 && !working; } // send keepalive if we are established or a session is made if(state == eEstablished || state == eLIMSent) @@ -905,6 +905,7 @@ namespace iwp start.sessionkey = sessionkey; start.user = this; start.hook = &handle_verify_session_start; + working = true; iwp_call_async_verify_session_start(iwp, &start); } @@ -954,6 +955,7 @@ namespace iwp handle_generated_session_start(iwp_async_session_start *start) { session *link = static_cast< session * >(start->user); + link->working = false; if(llarp_ev_udp_sendto(link->udp, link->addr, start->buf, start->sz) == -1) llarp::Error("sendto failed"); @@ -983,6 +985,7 @@ namespace iwp start.sessionkey = sessionkey; start.user = this; start.hook = &handle_generated_session_start; + working = true; iwp_call_async_gen_session_start(iwp, &start); } @@ -1090,6 +1093,7 @@ namespace iwp // call introack.user = this; introack.hook = &handle_introack_generated; + working = true; iwp_call_async_gen_introack(iwp, &introack); } @@ -1119,6 +1123,7 @@ namespace iwp // call EnterState(eIntroRecv); + working = true; iwp_call_async_verify_intro(iwp, &intro); } @@ -1144,6 +1149,7 @@ namespace iwp introack.user = this; introack.hook = &handle_verify_introack; // async verify + working = true; iwp_call_async_verify_introack(iwp, &introack); } @@ -1154,6 +1160,7 @@ namespace iwp handle_generated_intro(iwp_async_intro *i) { session *link = static_cast< session * >(i->user); + link->working = false; if(i->buf) { llarp::Debug("send intro"); @@ -1195,6 +1202,7 @@ namespace iwp // async generate intro packet intro.user = this; intro.hook = &handle_generated_intro; + working = true; iwp_call_async_gen_intro(iwp, &intro); // start introduce timer establish_job_id = llarp_logic_call_later( @@ -1403,6 +1411,7 @@ namespace iwp { llarp::Debug("removing session ", addr); session *s = static_cast< session * >(itr->second.impl); + s->done(); if(s->frames) { llarp::Warn("session has ", s->frames, @@ -1531,6 +1540,7 @@ namespace iwp if(!impl->IsEstablished()) { impl->send_LIM(); + impl->session_established(); } } else @@ -1552,12 +1562,13 @@ namespace iwp delete rxmsg; rx.erase(id); return success; - } + } // namespace iwp void session::handle_verify_intro(iwp_async_intro *intro) { session *self = static_cast< session * >(intro->user); + self->working = false; if(!intro->buf) { llarp::Error("intro verify failed from ", self->addr, " via ", @@ -1570,6 +1581,8 @@ namespace iwp void session::session_established() { + llarp::RouterID remote = remote_router.pubkey; + llarp::Info("session to ", remote, " established"); EnterState(eEstablished); serv->MapAddr(addr, remote_router.pubkey); llarp_logic_cancel_call(logic, establish_job_id); @@ -1636,11 +1649,6 @@ namespace iwp { llarp::Debug("message transmitted msgid=", msgid); session *impl = static_cast< session * >(parent->impl); - if(msgid == 0) - { - // first message acked means we are established - impl->session_established(); - } tx.erase(msgid); delete msg; } @@ -1664,6 +1672,7 @@ namespace iwp session::handle_verify_introack(iwp_async_introack *introack) { session *link = static_cast< session * >(introack->user); + link->working = false; if(introack->buf == nullptr) { // invalid signature @@ -1678,6 +1687,7 @@ namespace iwp session::handle_verify_session_start(iwp_async_session_start *s) { session *self = static_cast< session * >(s->user); + self->working = false; if(!s->buf) { // verify fail @@ -1878,7 +1888,7 @@ namespace iwp self->establish_job->link = self->serv->parent; if(left) { - // timer cancelled + // timer cancelled which means we were established self->establish_job->session = self->parent; } else diff --git a/llarp/link_message.cpp b/llarp/link_message.cpp index 226e66c33..c3ecef582 100644 --- a/llarp/link_message.cpp +++ b/llarp/link_message.cpp @@ -49,6 +49,7 @@ namespace llarp return false; } // create the message to parse based off message type + llarp::Debug("inbound message ", *strbuf.cur); switch(*strbuf.cur) { case 'i': @@ -113,4 +114,4 @@ namespace llarp firstkey = true; return bencode_read_dict(&buf, &reader); } -} +} // namespace llarp diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index d2fc211c4..8b7ae3dd3 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -380,17 +380,38 @@ llarp_nodedb_num_loaded(struct llarp_nodedb *n) } void -llarp_nodedb_select_random_hop(struct llarp_nodedb *n, struct llarp_rc *result, - size_t N) +llarp_nodedb_select_random_hop(struct llarp_nodedb *n, struct llarp_rc *prev, + struct llarp_rc *result, size_t N) { /// TODO: check for "guard" status for N = 0? - auto sz = n->entries.size(); - auto itr = n->entries.begin(); - if(sz > 1) + auto sz = n->entries.size(); + + if(prev) { - std::advance(itr, rand() % (sz - 1)); + do + { + auto itr = n->entries.begin(); + if(sz > 1) + { + auto idx = rand() % (sz - 1); + std::advance(itr, idx); + } + if(memcmp(prev->pubkey, itr->second.pubkey, PUBKEYSIZE) == 0) + continue; + llarp_rc_copy(result, &itr->second); + return; + } while(true); + } + else + { + auto itr = n->entries.begin(); + if(sz > 1) + { + auto idx = rand() % (sz - 1); + std::advance(itr, idx); + } + llarp_rc_copy(result, &itr->second); } - llarp_rc_copy(result, &itr->second); } } // end extern diff --git a/llarp/path.cpp b/llarp/path.cpp index 6ba6e1560..0ee2381e6 100644 --- a/llarp/path.cpp +++ b/llarp/path.cpp @@ -5,15 +5,6 @@ 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->hops[idx].router); - } - } - PathContext::PathContext(llarp_router* router) : m_Router(router), m_AllowTransit(false) { @@ -69,6 +60,7 @@ namespace llarp PathContext::ForwardLRCM(const RouterID& nextHop, std::deque< EncryptedFrame >& frames) { + llarp::Info("fowarding LRCM to ", nextHop); LR_CommitMessage* msg = new LR_CommitMessage; while(frames.size()) { @@ -155,6 +147,14 @@ namespace llarp { } + Path::Path(llarp_path_hops* h) : hops(h->numHops) + { + for(size_t idx = 0; idx < h->numHops; ++idx) + { + llarp_rc_copy(&hops[idx].router, &h->hops[idx].router); + } + } + const PathID_t& Path::PathID() const { diff --git a/llarp/pathbuilder.cpp b/llarp/pathbuilder.cpp index a41fa077b..f8c7f5633 100644 --- a/llarp/pathbuilder.cpp +++ b/llarp/pathbuilder.cpp @@ -20,9 +20,14 @@ namespace llarp pathbuilder_generated_keys( AsyncPathKeyExchangeContext< llarp_pathbuild_job >* ctx) { - llarp::Debug("Generated LRCM"); + auto remote = ctx->path->Upstream(); + llarp::Debug("Generated LRCM to", remote); auto router = ctx->user->router; - router->SendToOrQueue(ctx->path->Upstream(), ctx->LRCM); + if(!router->SendToOrQueue(remote, ctx->LRCM)) + { + llarp::Error("failed to send LRCM"); + return; + } ctx->path->status = ePathBuilding; router->paths.AddOwnPath(ctx->path); ctx->user->pathBuildStarted(ctx->user); @@ -33,12 +38,14 @@ namespace llarp { llarp_pathbuild_job* job = static_cast< llarp_pathbuild_job* >(user); // select hops - size_t idx = 0; + size_t idx = 0; + llarp_rc* prev = nullptr; while(idx < job->hops.numHops) { - auto rc = &job->hops.hops[idx].router; + llarp_rc* rc = &job->hops.hops[idx].router; llarp_rc_clear(rc); - job->selectHop(job->router->nodedb, rc, idx); + job->selectHop(job->router->nodedb, prev, rc, idx); + prev = rc; ++idx; } @@ -54,9 +61,8 @@ namespace llarp llarp_pathbuilder_context::llarp_pathbuilder_context( llarp_router* p_router, struct llarp_dht_context* p_dht) + : router(p_router), dht(p_dht) { - this->router = p_router; - this->dht = p_dht; } extern "C" { diff --git a/llarp/relay_commit.cpp b/llarp/relay_commit.cpp index b80a03b88..40dbe4f4e 100644 --- a/llarp/relay_commit.cpp +++ b/llarp/relay_commit.cpp @@ -75,6 +75,7 @@ namespace llarp " when we are not allowing transit"); return false; } + llarp::Info("Got LRCM from ", remote); return AsyncDecrypt(&router->paths); } diff --git a/llarp/router.cpp b/llarp/router.cpp index ac463628d..d2abdb979 100644 --- a/llarp/router.cpp +++ b/llarp/router.cpp @@ -71,32 +71,33 @@ llarp_router::SendToOrQueue(const llarp::RouterID &remote, else chosen = outboundLink; + if(chosen) + { + SendTo(remote, msg, chosen); + delete msg; + return true; + } // this will create an entry in the obmq if it's not already there - outboundMesssageQueue[remote].push(msg); - if(!chosen) + // we don't have an open session to that router right now + auto rc = llarp_nodedb_get_rc(nodedb, remote); + if(rc) { - // we don't have an open session to that router right now - auto rc = llarp_nodedb_get_rc(nodedb, remote); - if(rc) - { - // try connecting directly as the rc is loaded from disk - llarp_router_try_connect(this, rc, 10); - return true; - } - // try requesting the rc from the disk - llarp_async_load_rc *job = new llarp_async_load_rc; - job->diskworker = disk; - job->nodedb = nodedb; - job->logic = logic; - job->user = this; - job->hook = &HandleAsyncLoadRCForSendTo; - memcpy(job->pubkey, remote, PUBKEYSIZE); - llarp_nodedb_async_load_rc(job); + // try connecting directly as the rc is loaded from disk + llarp_router_try_connect(this, rc, 10); + return true; } - else - FlushOutboundFor(remote, chosen); + // try requesting the rc from the disk + llarp_async_load_rc *job = new llarp_async_load_rc; + job->diskworker = disk; + job->nodedb = nodedb; + job->logic = logic; + job->user = this; + job->hook = &HandleAsyncLoadRCForSendTo; + memcpy(job->pubkey, remote, PUBKEYSIZE); + llarp_nodedb_async_load_rc(job); + return true; } @@ -280,10 +281,16 @@ llarp_router::connect_job_retry(void *user, uint64_t orig, uint64_t left) return; llarp_link_establish_job *job = static_cast< llarp_link_establish_job * >(user); - llarp::Addr remote = job->ai; - llarp::Info("trying to establish session again with ", remote); - job->link->try_establish(job->link, job); + if(job->link) + { + llarp::Info("trying to establish session again with ", remote); + job->link->try_establish(job->link, job); + } + else + { + llarp::Error("establish session retry failed, no link for ", remote); + } } void @@ -430,7 +437,8 @@ llarp_router::send_padded_message(llarp_link_session_iter *itr, } void -llarp_router::SendTo(llarp::RouterID remote, llarp::ILinkMessage *msg) +llarp_router::SendTo(llarp::RouterID remote, llarp::ILinkMessage *msg, + llarp_link *link) { llarp_buffer_t buf = llarp::StackBuffer< decltype(linkmsg_buffer) >(linkmsg_buffer); @@ -444,7 +452,11 @@ llarp_router::SendTo(llarp::RouterID remote, llarp::ILinkMessage *msg) // set size of message buf.sz = buf.cur - buf.base; buf.cur = buf.base; - + if(link) + { + link->sendto(link, remote, buf); + return; + } bool sent = outboundLink->sendto(outboundLink, remote, buf); if(!sent) { @@ -485,7 +497,10 @@ llarp_router::FlushOutboundFor(const llarp::RouterID &remote, llarp::Debug("Flush outbound for ", remote); auto itr = outboundMesssageQueue.find(remote); if(itr == outboundMesssageQueue.end()) + { + llarp::Error("outbound queue not found for ", remote); return; + } while(itr->second.size()) { auto buf = llarp::StackBuffer< decltype(linkmsg_buffer) >(linkmsg_buffer); @@ -700,209 +715,210 @@ llarp_router::HasPendingConnectJob(const llarp::RouterID &remote) return pendingEstablishJobs.find(remote) != pendingEstablishJobs.end(); } -extern "C" { -struct llarp_router * -llarp_init_router(struct llarp_threadpool *tp, struct llarp_ev_loop *netloop, - struct llarp_logic *logic) +extern "C" { - llarp_router *router = new llarp_router(); - if(router) + struct llarp_router * + llarp_init_router(struct llarp_threadpool *tp, struct llarp_ev_loop *netloop, + struct llarp_logic *logic) { - router->netloop = netloop; - router->tp = tp; - router->logic = logic; - // TODO: make disk io threadpool count configurable + 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; + router->disk = tp; #else - router->disk = llarp_init_threadpool(1, "llarp-diskio"); + router->disk = llarp_init_threadpool(1, "llarp-diskio"); #endif - llarp_crypto_libsodium_init(&router->crypto); + llarp_crypto_libsodium_init(&router->crypto); + } + return router; } - return router; -} -bool -llarp_configure_router(struct llarp_router *router, struct llarp_config *conf) -{ - llarp_config_iterator iter; - iter.user = router; - iter.visit = llarp::router_iter_config; - llarp_config_iter(conf, &iter); - if(!router->InitOutboundLink()) - return false; - if(!router->Ready()) + bool + llarp_configure_router(struct llarp_router *router, struct llarp_config *conf) { - return false; + 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(); } - return router->EnsureIdentity(); -} -void -llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb) -{ - router->nodedb = nodedb; - router->Run(); -} + void + llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb) + { + router->nodedb = nodedb; + router->Run(); + } -bool -llarp_router_try_connect(struct llarp_router *router, struct llarp_rc *remote, - uint16_t numretries) -{ - // do we already have a pending job for this remote? - if(router->HasPendingConnectJob(remote->pubkey)) + bool + llarp_router_try_connect(struct llarp_router *router, struct llarp_rc *remote, + uint16_t numretries) + { + // do we already have a pending job for this remote? + if(router->HasPendingConnectJob(remote->pubkey)) + return false; + // try first address only + llarp_ai addr; + if(llarp_ai_list_index(remote->addrs, 0, &addr)) + { + 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; - // try first address only - llarp_ai addr; - if(llarp_ai_list_index(remote->addrs, 0, &addr)) - { - auto link = router->outboundLink; - auto itr = router->pendingEstablishJobs.emplace( - std::make_pair(remote->pubkey, llarp_link_establish_job{})); - auto job = &itr.first->second; - llarp_ai_copy(&job->ai, &addr); - memcpy(job->pubkey, remote->pubkey, PUBKEYSIZE); - job->retries = numretries; - job->timeout = 10000; - job->result = &llarp_router::on_try_connect_result; - // give router as user pointer - job->user = router; - // try establishing - link->try_establish(link, job); - return true; } - return false; -} -void -llarp_rc_clear(struct llarp_rc *rc) -{ - // zero out router contact - llarp::Zero(rc, sizeof(llarp_rc)); -} + 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; -} + 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); -} + void + llarp_rc_set_addrs(struct llarp_rc *rc, struct llarp_alloc *mem, + struct llarp_ai_list *addr) + { + rc->addrs = llarp_ai_list_new(); + struct llarp_ai_list_iter ai_itr; + ai_itr.user = rc; + ai_itr.visit = &llarp_rc_addr_list_iter; + llarp_ai_list_iterate(addr, &ai_itr); + } -void -llarp_rc_set_pubkey(struct llarp_rc *rc, const uint8_t *pubkey) -{ - // set public key - memcpy(rc->pubkey, pubkey, 32); -} + void + llarp_rc_set_pubkey(struct llarp_rc *rc, const uint8_t *pubkey) + { + // 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)) + bool + llarp_findOrCreateIdentity(llarp_crypto *crypto, const char *fpath, + byte_t *secretkey) { - llarp::Info("regenerated identity key"); - crypto->identity_keygen(secretkey); - std::ofstream f(path, std::ios::binary); + 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 *)secretkey, SECKEYSIZE); + f.read((char *)secretkey, SECKEYSIZE); + return true; } + llarp::Info("failed to get identity key"); + return false; } - std::ifstream f(path, std::ios::binary); - if(f.is_open()) + + bool + llarp_rc_write(struct llarp_rc *rc, const char *fpath) { - f.read((char *)secretkey, SECKEYSIZE); - return true; - } - llarp::Info("failed to get identity key"); - return false; -} + fs::path our_rc_file(fpath); + byte_t tmp[MAX_RC_SIZE]; + auto buf = llarp::StackBuffer< decltype(tmp) >(tmp); -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); + 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; + } - if(llarp_rc_bencode(rc, &buf)) - { - std::ofstream f(our_rc_file, std::ios::binary); - if(f.is_open()) + 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)) { - f.write((char *)buf.base, buf.cur - buf.base); - return true; + // sign + signbuf.sz = signbuf.cur - signbuf.base; + crypto->sign(rc->signature, seckey, signbuf); } } - 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)) + void + llarp_stop_router(struct llarp_router *router) { - // sign - signbuf.sz = signbuf.cur - signbuf.base; - crypto->sign(rc->signature, seckey, signbuf); + if(router) + router->Close(); } -} - -void -llarp_stop_router(struct llarp_router *router) -{ - if(router) - router->Close(); -} -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_router_iterate_links(struct llarp_router *router, + struct llarp_router_link_iter i) + { + for(auto link : router->inboundLinks) + if(!i.visit(&i, router, link)) + return; + i.visit(&i, router, router->outboundLink); + } -void -llarp_free_router(struct llarp_router **router) -{ - if(*router) + void + llarp_free_router(struct llarp_router **router) { - delete *router; + if(*router) + { + delete *router; + } + *router = nullptr; } - *router = nullptr; -} -void -llarp_router_override_path_selection(struct llarp_router *router, - llarp_pathbuilder_select_hop_func func) -{ - if(func) - router->selectHopFunc = func; -} + void + llarp_router_override_path_selection(struct llarp_router *router, + llarp_pathbuilder_select_hop_func func) + { + if(func) + router->selectHopFunc = func; + } } namespace llarp diff --git a/llarp/router.hpp b/llarp/router.hpp index cc2f2e0d7..1930edf67 100644 --- a/llarp/router.hpp +++ b/llarp/router.hpp @@ -80,15 +80,12 @@ struct llarp_router typedef std::queue< llarp::ILinkMessage * > MessageQueue; /// outbound message queue - std::unordered_map< llarp::PubKey, MessageQueue, llarp::PubKeyHash > - outboundMesssageQueue; + std::map< llarp::PubKey, MessageQueue > outboundMesssageQueue; /// loki verified routers std::unordered_map< llarp::PubKey, llarp_rc, llarp::PubKeyHash > validRouters; - std::unordered_map< llarp::PubKey, llarp_link_establish_job, - llarp::PubKeyHash > - pendingEstablishJobs; + std::map< llarp::PubKey, llarp_link_establish_job > pendingEstablishJobs; llarp_router(); ~llarp_router(); @@ -149,7 +146,8 @@ struct llarp_router /// sendto or drop void - SendTo(llarp::RouterID remote, llarp::ILinkMessage *msg); + SendTo(llarp::RouterID remote, llarp::ILinkMessage *msg, + llarp_link *chosen = nullptr); /// manually flush outbound message queue for just 1 router void diff --git a/test/encrypted_frame_unittest.cpp b/test/encrypted_frame_unittest.cpp new file mode 100644 index 000000000..bddb5e834 --- /dev/null +++ b/test/encrypted_frame_unittest.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include + +using EncryptedFrame = llarp::EncryptedFrame; +using SecretKey = llarp::SecretKey; +using PubKey = llarp::PubKey; +using LRAR = llarp::LR_AcceptRecord; + +class FrameTest : public ::testing::Test +{ + public: + llarp_crypto crypto; + SecretKey alice, bob; + + FrameTest() + { + llarp_crypto_libsodium_init(&crypto); + } + + ~FrameTest() + { + } + + void + SetUp() + { + crypto.encryption_keygen(alice); + crypto.encryption_keygen(bob); + } + + void + TearDown() + { + } +}; + +TEST_F(FrameTest, TestFrameCrypto) +{ + EncryptedFrame f(256); + f.Fill(0); + LRAR record; + record.upstream.Fill(1); + record.downstream.Fill(2); + record.pathid.Fill(3); + + auto buf = f.Buffer(); + buf->cur = buf->base + EncryptedFrame::OverheadSize; + + ASSERT_TRUE(record.BEncode(buf)); + + buf->cur = buf->base; + // encrypt alice to bob + ASSERT_TRUE(f.EncryptInPlace(alice, llarp::seckey_topublic(bob), &crypto)); + ASSERT_TRUE(f.DecryptInPlace(bob, &crypto)); +}; \ No newline at end of file