diff --git a/daemon.ini b/daemon.ini index f27c11acc..01d39cc25 100644 --- a/daemon.ini +++ b/daemon.ini @@ -6,7 +6,7 @@ contact-file=router-contact.signed dir=./tmp-nodes [iwp-connect] -#named-node0=/path/to/routercontact0 +named-node0=remote-rc.signed #named-node1=/path/to/routercontact1 [iwp-links] diff --git a/daemon/main.cpp b/daemon/main.cpp index 006f55bc1..ba27d680a 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -12,6 +12,7 @@ static void progress() { struct llarp_main { struct llarp_alloc mem; + struct llarp_crypto crypto; struct llarp_router *router = nullptr; struct llarp_threadpool *worker = nullptr; struct llarp_threadpool *thread = nullptr; @@ -111,17 +112,18 @@ int main(int argc, char *argv[]) { const char *conffname = "daemon.ini"; if (argc > 1) conffname = argv[1]; llarp_mem_jemalloc(&llarp.mem); - struct llarp_alloc * mem = &llarp.mem; + auto mem = &llarp.mem; llarp_new_config(&llarp.config); llarp_ev_loop_alloc(&llarp.mainloop); + llarp_crypto_libsodium_init(&llarp.crypto); printf("%s loading config file %s\n", LLARP_VERSION, conffname); if (!llarp_load_config(llarp.config, conffname)) { - struct llarp_config_iterator iter; + llarp_config_iterator iter; iter.user = &llarp; iter.visit = iter_main_config; llarp_config_iter(llarp.config, &iter); - llarp.nodedb = llarp_nodedb_new(mem); + llarp.nodedb = llarp_nodedb_new(mem, &llarp.crypto); if (llarp.nodedb_dir[0]) { llarp.nodedb_dir[sizeof(llarp.nodedb_dir) - 1] = 0; @@ -129,7 +131,7 @@ int main(int argc, char *argv[]) { if (llarp_nodedb_ensure_dir(dir)) { // ensure worker thread pool if (!llarp.worker) llarp.worker = llarp_init_threadpool(2); - // ensure thread + // ensure logic thread llarp.thread = llarp_init_threadpool(1); llarp.logic = llarp_init_logic(mem); @@ -140,11 +142,7 @@ int main(int argc, char *argv[]) { printf("starting router\n"); llarp_run_router(llarp.router); // run mainloop - struct llarp_thread_job job = { - .user = llarp.mainloop, - .work = &run_net - }; - llarp_threadpool_queue_job(llarp.thread, job); + llarp_threadpool_queue_job(llarp.thread, {llarp.mainloop, &run_net}); printf("running\n"); llarp.exitcode = 0; llarp_logic_mainloop(llarp.logic); diff --git a/include/llarp/address_info.h b/include/llarp/address_info.h index 87a90e08f..a38e9bc53 100644 --- a/include/llarp/address_info.h +++ b/include/llarp/address_info.h @@ -27,11 +27,13 @@ struct llarp_ai_list; struct llarp_ai_list *llarp_ai_list_new(struct llarp_alloc * mem); void llarp_ai_list_free(struct llarp_ai_list **l); +void llarp_ai_copy(struct llarp_ai * dst, struct llarp_ai * src); + bool llarp_ai_list_bencode(struct llarp_ai_list *l, llarp_buffer_t *buff); bool llarp_ai_list_bdecode(struct llarp_ai_list *l, llarp_buffer_t *buff); struct llarp_ai llarp_ai_list_popfront(struct llarp_ai_list *l); -void llarp_ai_list_pushback(struct llarp_ai_list *l, struct llarp_ai *ai); +void llarp_ai_list_pushback(struct llarp_ai_list *l, struct llarp_ai ai); size_t llarp_ai_list_size(struct llarp_ai_list *l); struct llarp_ai *llarp_ai_list_index(struct llarp_ai_list *l, ssize_t idx); diff --git a/include/llarp/crypto.h b/include/llarp/crypto.h index 79c65681e..f628d0a6a 100644 --- a/include/llarp/crypto.h +++ b/include/llarp/crypto.h @@ -51,7 +51,7 @@ typedef bool (*llarp_shorthash_func)(llarp_shorthash_t *, llarp_buffer_t); typedef bool (*llarp_hmac_func)(uint8_t *, llarp_buffer_t, const uint8_t *); -typedef bool (*llarp_sign_func)(uint8_t *, llarp_seckey_t, llarp_buffer_t); +typedef bool (*llarp_sign_func)(uint8_t *, const uint8_t *, llarp_buffer_t); typedef bool (*llarp_verify_func)(const uint8_t *, llarp_buffer_t, const uint8_t *); diff --git a/include/llarp/link.h b/include/llarp/link.h index 3186d14f9..cace6894a 100644 --- a/include/llarp/link.h +++ b/include/llarp/link.h @@ -64,6 +64,7 @@ struct llarp_link_ev_listener { struct llarp_link { void *impl; const char *(*name)(void); + void (*get_our_address)(struct llarp_link *, struct llarp_ai *); /* int (*register_listener)(struct llarp_link *, struct llarp_link_ev_listener); void (*deregister_listener)(struct llarp_link *, int); diff --git a/include/llarp/nodedb.h b/include/llarp/nodedb.h index d764c633a..bf1abb8b3 100644 --- a/include/llarp/nodedb.h +++ b/include/llarp/nodedb.h @@ -9,7 +9,7 @@ extern "C" { struct llarp_nodedb; /** create an empty nodedb */ -struct llarp_nodedb *llarp_nodedb_new(struct llarp_alloc * mem); +struct llarp_nodedb *llarp_nodedb_new(struct llarp_alloc * mem, struct llarp_crypto * crypto); /** free a nodedb and all loaded rc */ void llarp_nodedb_free(struct llarp_nodedb **n); diff --git a/include/llarp/router_contact.h b/include/llarp/router_contact.h index bec5f43b0..2021e8500 100644 --- a/include/llarp/router_contact.h +++ b/include/llarp/router_contact.h @@ -7,6 +7,8 @@ extern "C" { #endif +const size_t MAX_RC_SIZE = 1024; + struct llarp_rc { struct llarp_ai_list *addrs; llarp_pubkey_t pubkey; @@ -17,7 +19,7 @@ struct llarp_rc { bool llarp_rc_bdecode(struct llarp_alloc * mem, struct llarp_rc *rc, llarp_buffer_t *buf); bool llarp_rc_bencode(struct llarp_rc *rc, llarp_buffer_t *buf); void llarp_rc_free(struct llarp_rc *rc); -bool llarp_rc_verify_sig(struct llarp_rc *rc); +bool llarp_rc_verify_sig(struct llarp_crypto * crypto, struct llarp_rc *rc); #ifdef __cplusplus } diff --git a/llarp/address_info.c b/llarp/address_info.c index 606b17629..baf7de406 100644 --- a/llarp/address_info.c +++ b/llarp/address_info.c @@ -87,6 +87,30 @@ void llarp_ai_list_free(struct llarp_ai_list **l) { } } +void llarp_ai_copy(struct llarp_ai * dst, struct llarp_ai * src) +{ + memcpy(dst, src, sizeof(struct llarp_ai)); +} + +void llarp_ai_list_pushback(struct llarp_ai_list * l, struct llarp_ai a) +{ + struct llarp_ai_list_node *cur = l->root; + if(cur) + { + // go to the end of the list + while(cur->next) + cur = cur->next; + + cur->next = l->mem->alloc(l->mem, sizeof(struct llarp_ai_list_node), 16); + cur = cur->next; + } + else + cur = l->mem->alloc(l->mem, sizeof(struct llarp_ai_list_node), 16); + + llarp_ai_copy(&cur->data, &a); + cur->next = 0; +} + void llarp_ai_list_iterate(struct llarp_ai_list *l, struct llarp_ai_list_iter *itr) { struct llarp_ai_list_node *cur = l->root; diff --git a/llarp/buffer.cpp b/llarp/buffer.cpp index 868ba011d..520f73e3b 100644 --- a/llarp/buffer.cpp +++ b/llarp/buffer.cpp @@ -17,10 +17,10 @@ bool llarp_buffer_writef(llarp_buffer_t* buff, const char* fmt, ...) { size_t sz = llarp_buffer_size_left(buff); va_list args; va_start(args, fmt); - written = snprintf(buff->cur, sz, fmt, args); + written = vsnprintf(buff->cur, sz, fmt, args); va_end(args); if (written == -1) return false; - buff->sz += written; + buff->cur += written; return true; } diff --git a/llarp/crypto_libsodium.cpp b/llarp/crypto_libsodium.cpp index 91cf96c91..a8bd3eabb 100644 --- a/llarp/crypto_libsodium.cpp +++ b/llarp/crypto_libsodium.cpp @@ -77,7 +77,7 @@ static bool hmac(uint8_t *result, llarp_buffer_t buff, secret, HMACSECSIZE) != -1; } -static bool sign(uint8_t *result, llarp_seckey_t secret, +static bool sign(uint8_t *result, const uint8_t * secret, llarp_buffer_t buff) { const uint8_t *base = (const uint8_t *)buff.base; return crypto_sign_detached(result, nullptr, base, buff.sz, secret) != -1; diff --git a/llarp/iwp_link.cpp b/llarp/iwp_link.cpp index 347cd930f..b5862bc20 100644 --- a/llarp/iwp_link.cpp +++ b/llarp/iwp_link.cpp @@ -569,6 +569,11 @@ struct server printf("cleanup dead\n"); } + uint8_t * pubkey() + { + return llarp_seckey_topublic(seckey); + } + bool ensure_privkey() { std::error_code ec; @@ -662,10 +667,21 @@ server * link_alloc(struct llarp_alloc * mem, struct llarp_msg_muxer * muxer, co const char * link_name() { - return "iwp"; + return "IWP"; } +void link_get_addr(struct llarp_link * l, struct llarp_ai * addr) +{ + server * link = static_cast(l->impl); + llarp::Addr linkaddr(link->udp.addr); + addr->rank = 1; + strncpy(addr->dialect, link_name(), sizeof(addr->dialect)); + memcpy(addr->enc_key, link->pubkey(), 32); + memcpy(addr->ip.s6_addr, linkaddr.addr.s6_addr, 16); + addr->port = linkaddr.port; +} + bool link_configure(struct llarp_link * l, struct llarp_ev_loop * netloop, const char * ifname, int af, uint16_t port) { server * link = static_cast(l->impl); @@ -768,6 +784,7 @@ void iwp_link_init(struct llarp_link * link, struct llarp_iwp_args args, struct { link->impl = iwp::link_alloc(args.mem, muxer, args.keyfile, args.crypto, args.logic, args.cryptoworker); link->name = iwp::link_name; + link->get_our_address = iwp::link_get_addr; link->configure = iwp::link_configure; link->start_link = iwp::link_start; link->stop_link = iwp::link_stop; diff --git a/llarp/link.c b/llarp/link.c index 6a6f1bf2e..5e5c1d056 100644 --- a/llarp/link.c +++ b/llarp/link.c @@ -2,7 +2,7 @@ bool llarp_link_initialized(struct llarp_link * link) { - return link && link->impl && link->name && link->configure && link->start_link && link->stop_link && link->iter_sessions && link->try_establish && link->acquire_session_for_addr && link->mark_session_active && link->free_impl; + return link && link->impl && link->name && link->get_our_address && link->configure && link->start_link && link->stop_link && link->iter_sessions && link->try_establish && link->acquire_session_for_addr && link->mark_session_active && link->free_impl; } bool llarp_link_session_initialized(struct llarp_link_session * s) diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index 17754558a..5bbbf24bf 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -9,9 +9,10 @@ static const char skiplist_subdirs[] = "0123456789ABCDEF"; struct llarp_nodedb { - llarp_nodedb(struct llarp_alloc * m) : mem(m) {} + llarp_nodedb(llarp_alloc * m, llarp_crypto * c) : mem(m), crypto(c) {} llarp_alloc * mem; + llarp_crypto * crypto; std::map entries; void Clear() @@ -51,8 +52,9 @@ struct llarp_nodedb { } fclose(f); llarp_rc *rc = llarp::Alloc(mem); + llarp::Zero(rc, sizeof(llarp_rc)); if (llarp_rc_bdecode(mem, rc, &buff)) { - if (llarp_rc_verify_sig(rc)) { + if (llarp_rc_verify_sig(crypto, rc)) { llarp::pubkey pk; memcpy(pk.data(), rc->pubkey, pk.size()); entries[pk] = rc; @@ -75,10 +77,10 @@ struct llarp_nodedb { extern "C" { -struct llarp_nodedb *llarp_nodedb_new(struct llarp_alloc * mem) { +struct llarp_nodedb *llarp_nodedb_new(struct llarp_alloc * mem, struct llarp_crypto * crypto) { void * ptr = mem->alloc(mem, sizeof(llarp_nodedb), llarp::alignment()); if(!ptr) return nullptr; - return new (ptr) llarp_nodedb(mem); + return new (ptr) llarp_nodedb(mem, crypto); } void llarp_nodedb_free(struct llarp_nodedb **n) { diff --git a/llarp/router.cpp b/llarp/router.cpp index ddaf5b8c1..b1ad4fe9e 100644 --- a/llarp/router.cpp +++ b/llarp/router.cpp @@ -7,6 +7,8 @@ #include #include "str.hpp" +#include + namespace llarp { void router_iter_config(llarp_config_iterator *iter, const char *section, const char *key, const char *val); @@ -33,6 +35,54 @@ void llarp_router::AddLink(struct llarp_link *link) { bool llarp_router::Ready() { return ready; } +bool llarp_router::EnsureIdentity() +{ + std::error_code ec; + if(!fs::exists(ident_keyfile, ec)) + { + crypto.keygen(identity); + std::ofstream f(ident_keyfile, std::ios::binary); + if(f.is_open()) + { + f.write((char*)identity, sizeof(identity)); + } + } + std::ifstream f(ident_keyfile, std::ios::binary); + if(f.is_open()) + { + f.read((char*)identity, sizeof(identity)); + return true; + } + return false; +} + +bool llarp_router::SaveRC() +{ + printf("verify rc signature... "); + if(!llarp_rc_verify_sig(&crypto, &rc)) + { + printf(" BAD!\n"); + return false; + } + printf(" OK.\n"); + + uint8_t tmp[MAX_RC_SIZE]; + llarp_buffer_t buf; + buf.base = (char*)tmp; + buf.cur = (char*) tmp; + buf.sz = sizeof(tmp); + if(llarp_rc_bencode(&rc, &buf)) + { + std::ofstream f(our_rc_file, std::ios::binary); + if(f.is_open()) + { + f.write(buf.base, buf.cur - buf.base); + return true; + } + } + return false; +} + void llarp_router::ForEachLink(std::function visitor) { llarp::router_links *cur = &links; do { @@ -66,15 +116,48 @@ bool llarp_configure_router(struct llarp_router *router, iter.user = router; iter.visit = llarp::router_iter_config; llarp_config_iter(conf, &iter); - return router->Ready(); + if(!router->Ready()) return false; + return router->EnsureIdentity(); } void llarp_run_router(struct llarp_router *router) { - llarp_logic * logic = router->logic; - router->ForEachLink([logic](llarp_link *link) { - int result = link->start_link(link, logic); - if (result == -1) printf("link %s failed to start\n", link->name()); + + // zero out router contact + llarp::Zero(&router->rc, sizeof(llarp_rc)); + // fill our address list + router->rc.addrs = llarp_ai_list_new(router->mem); + router->ForEachLink([router](llarp_link *link) { + llarp_ai addr; + link->get_our_address(link, &addr); + llarp_ai_list_pushback(router->rc.addrs, addr); }); + // set public key + memcpy(router->rc.pubkey, router->pubkey(), 32); + + // sign router contact + llarp_buffer_t signbuf; + char buf[MAX_RC_SIZE]; + signbuf.base = buf; + signbuf.cur = buf; + signbuf.sz = sizeof(buf); + // encode + if(llarp_rc_bencode(&router->rc, &signbuf)) + { + // sign + signbuf.sz = signbuf.cur - signbuf.base; + router->crypto.sign(router->rc.signature, router->identity, signbuf); + if(router->SaveRC()) + { + printf("saved router contact\n"); + llarp_logic * logic = router->logic; + router->ForEachLink([logic](llarp_link *link) { + int result = link->start_link(link, logic); + if (result == -1) printf("link %s failed to start\n", link->name()); + }); + return; + } + } + printf("failed to generate rc\n"); } void llarp_stop_router(struct llarp_router *router) { @@ -113,7 +196,7 @@ void router_iter_config(llarp_config_iterator *iter, const char *section, proto = std::atoi(val); } - struct llarp_link *link; + struct llarp_link *link = nullptr; if (StrEq(section, "iwp-links")) { link = llarp::Alloc(self->mem); @@ -124,10 +207,28 @@ void router_iter_config(llarp_config_iterator *iter, const char *section, .crypto = &self->crypto, .logic = self->logic, .cryptoworker = self->tp, - .keyfile=self->transport_keyfile, + .keyfile = self->transport_keyfile.c_str(), }; iwp_link_init(link, args, &self->muxer); } + else if (StrEq(section, "iwp-connect")) + { + std::error_code ec; + if(fs::exists(val, ec)) + self->connect.try_emplace(key, val); + else + printf("cannot read %s\n", val); + return; + } + else if (StrEq(section, "router")) + { + if(StrEq(key, "contact-file")) + { + self->our_rc_file = val; + printf("storing signed rc at %s\n", self->our_rc_file.c_str()); + } + return; + } else return; diff --git a/llarp/router.hpp b/llarp/router.hpp index d02cf091f..f438127c5 100644 --- a/llarp/router.hpp +++ b/llarp/router.hpp @@ -2,9 +2,12 @@ #define LLARP_ROUTER_HPP #include #include +#include #include +#include #include "mem.hpp" +#include "fs.hpp" namespace llarp { struct router_links { @@ -16,8 +19,21 @@ struct router_links { struct llarp_router { bool ready; - const char * transport_keyfile = "transport.key"; - const char * transport_certfile = "transport.pem"; + // transient iwp encryption key + fs::path transport_keyfile = "transport.key"; + + // nodes to connect to on startup + std::map connect; + + // long term identity key + fs::path ident_keyfile = "identity.key"; + + // path to write our self signed rc to + fs::path our_rc_file = "rc.signed"; + + + llarp_rc rc; + llarp_ev_loop * netloop; llarp_threadpool *tp; llarp_logic * logic; @@ -26,6 +42,7 @@ struct llarp_router { llarp_msg_muxer muxer; llarp_path_context *paths; llarp_alloc * mem; + llarp_seckey_t identity; llarp_router(llarp_alloc * mem); ~llarp_router(); @@ -37,6 +54,11 @@ struct llarp_router { void Close(); bool Ready(); + + bool EnsureIdentity(); + bool SaveRC(); + + uint8_t * pubkey() { return llarp_seckey_topublic(identity); } }; #endif diff --git a/llarp/router_contact.c b/llarp/router_contact.c index ce9ededa7..c1778f51b 100644 --- a/llarp/router_contact.c +++ b/llarp/router_contact.c @@ -77,9 +77,32 @@ bool llarp_rc_bdecode(struct llarp_alloc * mem, struct llarp_rc * rc, llarp_buff return bdecode_read_dict(buff, &r); } -bool llarp_rc_verify_sig(struct llarp_rc * rc) + +bool llarp_rc_verify_sig(struct llarp_crypto * crypto, struct llarp_rc * rc) { - return false; + bool result = false; + llarp_sig_t sig; + char tmp[MAX_RC_SIZE]; + llarp_buffer_t buf; + buf.base = tmp; + buf.cur = tmp; + buf.sz = sizeof(tmp); + // copy sig + memcpy(sig, rc->signature, sizeof(llarp_sig_t)); + // zero sig + memset(rc->signature, 0, sizeof(llarp_sig_t)); + + // bencode + if(llarp_rc_bencode(rc, &buf)) + { + buf.sz = buf.cur - buf.base; + buf.cur = buf.base; + // verify + result = crypto->verify(rc->pubkey, buf, sig); + // restore sig + memcpy(rc->signature, sig, sizeof(llarp_sig_t)); + } + return result; } bool llarp_rc_bencode(struct llarp_rc *rc, llarp_buffer_t *buff) {