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 480b8db92..c29f178eb 100644 --- a/Makefile +++ b/Makefile @@ -59,10 +59,9 @@ shadow: shadow-build bash -c "$(SHADOW_BIN) -w $$(cat /proc/cpuinfo | grep processor | wc -l) $(SHADOW_CONFIG) &> $(SHADOW_LOG) || true" testnet-configure: clean - cmake -GNinja -DCMAKE_BUILD_TYPE=Debug + cmake -GNinja -DCMAKE_BUILD_TYPE=Debug testnet-build: testnet-configure - ninja clean ninja testnet: testnet-build @@ -71,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/shadow/genconf.py b/contrib/shadow/genconf.py index 5f9358c40..b3194d78f 100644 --- a/contrib/shadow/genconf.py +++ b/contrib/shadow/genconf.py @@ -6,25 +6,34 @@ import os from xml.etree import ElementTree as etree -getSetting = lambda s, name, fallback : name in s and s[name] or fallback -shadowRoot = getSetting(os.environ, "SHADOW_ROOT", os.path.join(os.environ['HOME'], '.shadow')) +def getSetting(s, name, fallback): return name in s and s[name] or fallback + + +shadowRoot = getSetting(os.environ, "SHADOW_ROOT", + os.path.join(os.environ['HOME'], '.shadow')) libpath = 'libshadow-plugin-llarp.so' + def nodeconf(conf, baseDir, name, ifname=None, port=None): conf['netdb'] = {'dir': 'tmp-nodes'} - conf['router'] = {} - conf['router']['contact-file'] = os.path.join(baseDir, '{}.signed'.format(name)) - conf['router']['ident-privkey'] = os.path.join(baseDir, '{}-ident.key'.format(name)) - conf['router']['transport-privkey'] = os.path.join(baseDir, '{}-transport.key'.format(name)) + conf['router'] = {} + conf['router']['contact-file'] = os.path.join( + baseDir, '{}.signed'.format(name)) + conf['router']['ident-privkey'] = os.path.join( + baseDir, '{}-ident.key'.format(name)) + conf['router']['transport-privkey'] = os.path.join( + baseDir, '{}-transport.key'.format(name)) if ifname and port: conf['bind'] = {ifname: port} conf['connect'] = {} + def addPeer(conf, baseDir, peer): conf['connect'][peer] = os.path.join(baseDir, '{}.signed'.format(peer)) + def createNode(pluginName, root, peer): node = etree.SubElement(root, 'node') node.attrib['id'] = peer['name'] @@ -38,39 +47,42 @@ def createNode(pluginName, root, peer): def makeBase(settings, name, id): return { 'id': id, - 'name' : name, - 'contact-file' : os.path.join(getSetting(settings, 'baseDir', 'tmp'), '{}.signed'.format(name)), - 'configfile' : os.path.join(getSetting(settings, 'baseDir', 'tmp'), '{}.ini'.format(name)), + 'name': name, + 'contact-file': os.path.join(getSetting(settings, 'baseDir', 'tmp'), '{}.signed'.format(name)), + 'configfile': os.path.join(getSetting(settings, 'baseDir', 'tmp'), '{}.ini'.format(name)), 'config': configparser.ConfigParser() } + def makeClient(settings, name, id): peer = makeBase(settings, name, id) nodeconf(peer['config'], getSetting(settings, 'baseDir', 'tmp'), name) return peer + def makeSVCNode(settings, name, id, port): peer = makeBase(settings, name, id) - nodeconf(peer['config'], getSetting(settings, 'baseDir', 'tmp'), name, 'eth0', port) + nodeconf(peer['config'], getSetting( + settings, 'baseDir', 'tmp'), name, 'eth0', port) return peer def genconf(settings, outf): root = etree.Element('shadow') topology = etree.SubElement(root, 'topology') - topology.attrib['path'] = getSetting(settings, 'topology', os.path.join(shadowRoot, 'share', 'topology.graphml.xml')) - + topology.attrib['path'] = getSetting(settings, 'topology', os.path.join( + shadowRoot, 'share', 'topology.graphml.xml')) pluginName = getSetting(settings, 'name', 'llarpd') kill = etree.SubElement(root, 'kill') kill.attrib['time'] = getSetting(settings, 'runFor', '600') - + baseDir = getSetting(settings, 'baseDir', 'tmp') if not os.path.exists(baseDir): os.mkdir(baseDir) - + plugin = etree.SubElement(root, "plugin") plugin.attrib['id'] = pluginName plugin.attrib['path'] = libpath @@ -78,7 +90,8 @@ def genconf(settings, outf): svcNodeCount = getSetting(settings, 'service-nodes', 20) peers = list() for nodeid in range(svcNodeCount): - peers.append(makeSVCNode(settings, 'svc-node-{}'.format(nodeid), str(nodeid), basePort + 1)) + peers.append(makeSVCNode( + settings, 'svc-node-{}'.format(nodeid), str(nodeid), basePort + 1)) basePort += 1 # make all service nodes know each other @@ -86,14 +99,15 @@ def genconf(settings, outf): for nodeid in range(svcNodeCount): if str(nodeid) != peer['id']: addPeer(peer['config'], baseDir, 'svc-node-{}'.format(nodeid)) - + # add client nodes for nodeid in range(getSetting(settings, 'client-nodes', 200)): - peer = makeClient(settings, 'client-node-{}'.format(nodeid), str(nodeid)) + peer = makeClient( + settings, 'client-node-{}'.format(nodeid), str(nodeid)) peers.append(peer) - for p in range(getSetting(settings, 'client-connect-to', 3)): - addPeer(peer['config'], baseDir, 'svc-node-{}'.format((p + nodeid) % svcNodeCount)) - + for p in range(getSetting(settings, 'client-connect-to', 10)): + addPeer(peer['config'], baseDir, + 'svc-node-{}'.format((p + nodeid) % svcNodeCount)) # generate xml and settings files for peer in peers: @@ -105,9 +119,10 @@ def genconf(settings, outf): # render outf.write(etree.tostring(root).decode('utf-8')) + if __name__ == '__main__': settings = { - 'topology': os.path.join(shadowRoot, 'share', 'topology.graphml.xml') + 'topology': os.path.join(shadowRoot, 'share', 'topology.graphml.xml') } with open(sys.argv[1], 'w') as f: genconf(settings, f) diff --git a/contrib/testnet/genconf.py b/contrib/testnet/genconf.py index 01a2f4ba8..a9f39bf03 100644 --- a/contrib/testnet/genconf.py +++ b/contrib/testnet/genconf.py @@ -9,37 +9,44 @@ from configparser import ConfigParser as CP import os -svcNodeName = lambda id : 'svc-node-%03d' % id -clientNodeName = lambda id : 'client-node-%03d' % id + +def svcNodeName(id): return 'svc-node-%03d' % id + + +def clientNodeName(id): return 'client-node-%03d' % id + def main(): ap = AP() ap.add_argument('--dir', type=str, default='testnet_tmp') - ap.add_argument('--svc', type=int, default=20, help='number of service nodes') + ap.add_argument('--svc', type=int, default=20, + help='number of service nodes') ap.add_argument('--baseport', type=int, default=19000) - ap.add_argument('--clients', type=int, default=200, help='number of client nodes') + ap.add_argument('--clients', type=int, default=200, + help='number of client nodes') ap.add_argument('--bin', type=str, required=True) ap.add_argument('--out', type=str, required=True) - ap.add_argument('--connect', type=int, default=5) - + ap.add_argument('--connect', type=int, default=10) + args = ap.parse_args() basedir = os.path.abspath(args.dir) - + for nodeid in range(args.svc): config = CP() config['bind'] = { - 'lo' : str(args.baseport + nodeid) + 'lo': str(args.baseport + nodeid) } config['netdb'] = { - 'dir' : 'netdb' + 'dir': 'netdb' } config['connect'] = {} for otherid in range(args.svc): if otherid != nodeid: name = svcNodeName(otherid) - config['connect'][name] = os.path.join(basedir, name, 'rc.signed') - + config['connect'][name] = os.path.join( + basedir, name, 'rc.signed') + d = os.path.join(args.dir, svcNodeName(nodeid)) if not os.path.exists(d): os.mkdir(d) @@ -50,22 +57,22 @@ def main(): for nodeid in range(args.clients): config = CP() config['netdb'] = { - 'dir' : 'netdb' + '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): os.mkdir(d) fp = os.path.join(d, 'daemon.ini') with open(fp, 'w') as f: config.write(f) - - + with open(args.out, 'w') as f: f.write('''[program:svc-node] directory = {} @@ -86,6 +93,7 @@ process_name = client-node-%(process_num)03d numprocs = {} '''.format(os.path.join(args.dir, 'client-node-%(process_num)03d'), args.bin, args.clients)) f.write('[supervisord]\ndirectory=.\n') - + + if __name__ == '__main__': main() diff --git a/include/llarp/crypto.h b/include/llarp/crypto.h index 4f18f3374..e3bfd8c1f 100644 --- a/include/llarp/crypto.h +++ b/include/llarp/crypto.h @@ -26,6 +26,7 @@ extern "C" { #define SIGSIZE 64 #define TUNNONCESIZE 32 #define HMACSIZE 32 +#define PATHIDSIZE 16 /* typedef byte_t llarp_pubkey_t[PUBKEYSIZE]; @@ -42,7 +43,7 @@ typedef byte_t llarp_tunnel_nonce_t[TUNNONCESIZE]; /// label functors -/// PKE(result, publickey, nonce, secretkey) +/// PKE(result, publickey, secretkey, nonce) typedef bool (*llarp_path_dh_func)(byte_t *, byte_t *, byte_t *, byte_t *); /// TKE(result publickey, secretkey, nonce) diff --git a/include/llarp/encrypted.hpp b/include/llarp/encrypted.hpp index 3504eb585..c58d2d467 100644 --- a/include/llarp/encrypted.hpp +++ b/include/llarp/encrypted.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace llarp { @@ -13,19 +14,24 @@ namespace llarp Encrypted() = default; Encrypted(const byte_t* buf, size_t sz); Encrypted(size_t sz); - ~Encrypted(); bool BEncode(llarp_buffer_t* buf) const { - return bencode_write_bytestring(buf, data, size); + return bencode_write_bytestring(buf, _data.data(), _data.size()); + } + + void + Fill(byte_t fill) + { + std::fill(_data.begin(), _data.end(), fill); } void Randomize() { - if(data) - randombytes(data, size); + if(_data.size()) + randombytes(_data.data(), _data.size()); } bool @@ -36,11 +42,8 @@ namespace llarp return false; if(strbuf.sz == 0) return false; - if(data) - delete[] data; - size = strbuf.sz; - data = new byte_t[size]; - memcpy(data, strbuf.base, size); + _data.resize(strbuf.sz); + memcpy(_data.data(), strbuf.base, _data.size()); return true; } @@ -50,12 +53,29 @@ namespace llarp return &m_Buffer; } - byte_t* data = nullptr; - size_t size = 0; + size_t + size() + { + return _data.size(); + } + + size_t + size() const + { + return _data.size(); + } + + byte_t* + data() + { + return _data.data(); + } + + std::vector< byte_t > _data; private: llarp_buffer_t m_Buffer; }; -} +} // namespace llarp #endif \ No newline at end of file diff --git a/include/llarp/encrypted_frame.hpp b/include/llarp/encrypted_frame.hpp index e958d74a0..81252d215 100644 --- a/include/llarp/encrypted_frame.hpp +++ b/include/llarp/encrypted_frame.hpp @@ -44,7 +44,6 @@ namespace llarp ctx->handler(ctx->frame, ctx->user); else { - delete ctx->frame; ctx->handler(nullptr, ctx->user); } } @@ -68,8 +67,8 @@ namespace llarp // TODO: should we own otherKey? otherKey = other; frame = new EncryptedFrame(buf.sz); - memcpy(frame->data + PUBKEYSIZE + TUNNONCESIZE + SHORTHASHSIZE, buf.base, - buf.sz); + memcpy(frame->data() + PUBKEYSIZE + TUNNONCESIZE + SHORTHASHSIZE, + buf.base, buf.sz); user = u; llarp_threadpool_queue_job(worker, {this, &Encrypt}); } @@ -103,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/endpoint.hpp b/include/llarp/endpoint.hpp new file mode 100644 index 000000000..893ac16be --- /dev/null +++ b/include/llarp/endpoint.hpp @@ -0,0 +1,18 @@ +#ifndef LLARP_ENDPOINT_HANDLER_HPP +#define LLARP_ENDPOINT_HANDLER_HPP + +#include + +namespace llarp +{ + // hidden service endpoint handler + struct IEndpointHandler + { + ~IEndpointHandler(){}; + + virtual void + HandleMessage(llarp_buffer_t buf) = 0; + }; +} // namespace llarp + +#endif \ No newline at end of file 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 9d3e30ded..24080132b 100644 --- a/include/llarp/nodedb.h +++ b/include/llarp/nodedb.h @@ -54,8 +54,13 @@ 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 +llarp_nodedb_num_loaded(struct llarp_nodedb *n); + /** put an rc into the node db overwrites with new contents if already present diff --git a/include/llarp/path.h b/include/llarp/path.h index a367a6871..29522d220 100644 --- a/include/llarp/path.h +++ b/include/llarp/path.h @@ -8,12 +8,23 @@ extern "C" { #endif +struct llarp_path_hop +{ + struct llarp_rc router; + byte_t nextHop[PUBKEYSIZE]; + byte_t sessionkey[SHAREDKEYSIZE]; + byte_t pathid[PATHIDSIZE]; +}; + struct llarp_path_hops { - struct llarp_rc routers[MAXHOPS]; + struct llarp_path_hop hops[MAXHOPS]; size_t numHops; }; +void +llarp_path_hops_free(struct llarp_path_hops* hops); + #ifdef __cplusplus } #endif diff --git a/include/llarp/path.hpp b/include/llarp/path.hpp index b1f0a265a..65734ac11 100644 --- a/include/llarp/path.hpp +++ b/include/llarp/path.hpp @@ -5,11 +5,14 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -91,6 +94,14 @@ namespace llarp bool Expired(llarp_time_t now) const; + + // forward data in upstream direction + void + ForwardUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r); + + // forward data in downstream direction + void + ForwardDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r); }; /// configuration for a single hop when building a path @@ -113,12 +124,35 @@ namespace llarp PathHopConfig(); }; + enum PathStatus + { + ePathBuilding, + ePathEstablished, + ePathTimeout, + ePathExpired + }; + + /// A path we made struct Path { typedef std::vector< PathHopConfig > HopList; HopList hops; llarp_time_t buildStarted; + PathStatus status; + Path(llarp_path_hops* path); + + void + EncryptAndSend(llarp_buffer_t buf, llarp_router* r); + + void + DecryptAndRecv(llarp_buffer_t buf, IEndpointHandler* handler); + + const PathID_t& + PathID() const; + + RouterID + Upstream(); }; template < typename User > @@ -132,32 +166,32 @@ namespace llarp llarp_threadpool* worker = nullptr; llarp_logic* logic = nullptr; llarp_crypto* crypto = nullptr; - LR_CommitMessage LRCM; + 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)) + if(!ctx->crypto->dh_client(hop.shared, hop.router.enckey, hop.commkey, + hop.nonce)) { llarp::Error("Failed to generate shared key for path build"); - delete ctx; + abort(); return; } // randomize hop's path id @@ -165,7 +199,7 @@ namespace llarp LR_CommitRecord record; - auto& frame = ctx->LRCM.frames[ctx->idx]; + auto& frame = ctx->LRCM->frames[ctx->idx]; ++ctx->idx; if(ctx->idx < ctx->path->hops.size()) { @@ -175,12 +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; + 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; } @@ -210,11 +255,12 @@ namespace llarp user = u; result = func; worker = pool; + LRCM = new LR_CommitMessage; for(size_t idx = 0; idx < MAXHOPS; ++idx) { - LRCM.frames.emplace_back(256); - LRCM.frames.back().Randomize(); + LRCM->frames.emplace_back(256); + LRCM->frames.back().Randomize(); } llarp_threadpool_queue_job(pool, {this, &GenerateNextKey}); } @@ -227,56 +273,6 @@ namespace llarp ePathBuildReject }; - /// path selection algorithm - struct IPathSelectionAlgorithm - { - virtual ~IPathSelectionAlgorithm(){}; - /// select full path given an empty hop list to end at target - virtual bool - SelectFullPathTo(Path::HopList& hops, const RouterID& target) = 0; - - /// report to path builder the result of a path build - /// can be used to "improve" path building algoirthm in the - /// future - virtual void - ReportPathBuildStatus(const Path::HopList& hops, const RouterID& target, - PathBuildStatus status){}; - }; - - class PathBuildJob - { - public: - PathBuildJob(llarp_router* router, IPathSelectionAlgorithm* selector); - ~PathBuildJob(); - - void - Start(); - - private: - typedef AsyncPathKeyExchangeContext< PathBuildJob > KeyExchanger; - - LR_CommitMessage* - BuildLRCM(); - - static void - KeysGenerated(KeyExchanger* ctx); - - llarp_router* router; - IPathSelectionAlgorithm* m_HopSelector; - KeyExchanger m_KeyExchanger; - }; - - /// a pool of paths for a hidden service - struct PathPool - { - PathPool(llarp_router* router); - ~PathPool(); - - /// build a new path to a router by identity key - PathBuildJob* - BuildNewPathTo(const RouterID& router); - }; - struct PathContext { PathContext(llarp_router* router); @@ -300,28 +296,30 @@ namespace llarp bool HandleRelayCommit(const LR_CommitMessage* msg); + bool + HandleRelayAck(const LR_AckMessage* msg); + void PutTransitHop(const TransitHop& hop); bool ForwardLRCM(const RouterID& nextHop, std::deque< EncryptedFrame >& frames); - 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; + void + AddOwnPath(Path* p); + typedef std::unordered_multimap< PathID_t, TransitHop, PathIDHash > TransitHopsMap_t; typedef std::pair< std::mutex, TransitHopsMap_t > SyncTransitMap_t; + typedef std::map< PathID_t, Path* > OwnedPathsMap_t; + + typedef std::pair< std::mutex, OwnedPathsMap_t > SyncOwnedPathsMap_t; + llarp_threadpool* Worker(); @@ -340,6 +338,7 @@ namespace llarp private: llarp_router* m_Router; SyncTransitMap_t m_TransitPaths; + SyncOwnedPathsMap_t m_OurPaths; bool m_AllowTransit; }; diff --git a/include/llarp/path_types.hpp b/include/llarp/path_types.hpp index a54b7e7f6..77b0fee1a 100644 --- a/include/llarp/path_types.hpp +++ b/include/llarp/path_types.hpp @@ -1,11 +1,12 @@ #ifndef LLARP_PATH_TYPES_HPP #define LLARP_PATH_TYPES_HPP +#include #include namespace llarp { - typedef AlignedBuffer< 16 > PathID_t; + typedef AlignedBuffer< PATHIDSIZE > PathID_t; } #endif \ No newline at end of file diff --git a/include/llarp/pathbuilder.h b/include/llarp/pathbuilder.h index 6460789ee..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 @@ -49,10 +51,8 @@ struct llarp_pathbuild_job 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; + // called when the path build started + llarp_pathbuilder_hook pathBuildStarted; // path struct llarp_path_hops hops; }; diff --git a/llarp/crypto_async.cpp b/llarp/crypto_async.cpp index c5a75ae78..d02983ae7 100644 --- a/llarp/crypto_async.cpp +++ b/llarp/crypto_async.cpp @@ -27,10 +27,8 @@ namespace iwp { iwp_async_keygen *keygen = static_cast< iwp_async_keygen * >(user); keygen->iwp->crypto->encryption_keygen(keygen->keybuf); - llarp_thread_job job; - job.user = user; - job.work = &inform_keygen; - llarp_logic_queue_job(keygen->iwp->logic, job); + keygen->hook(keygen); + // llarp_logic_queue_job(keygen->iwp->logic, job); } void @@ -71,7 +69,8 @@ namespace iwp buf.sz = intro->sz - 32; crypto->hmac(intro->buf, buf, sharedkey); // inform result - llarp_logic_queue_job(intro->iwp->logic, {intro, &inform_intro}); + intro->hook(intro); + // llarp_logic_queue_job(intro->iwp->logic, {intro, &inform_intro}); } void @@ -128,7 +127,7 @@ namespace iwp { iwp_async_introack *introack = static_cast< iwp_async_introack * >(user); auto crypto = introack->iwp->crypto; - auto logic = introack->iwp->logic; + // auto logic = introack->iwp->logic; llarp::ShortHash digest; llarp::SharedSecret sharedkey; @@ -165,7 +164,8 @@ namespace iwp // copy token memcpy(introack->token, token, 32); } - llarp_logic_queue_job(logic, {introack, &inform_introack}); + introack->hook(introack); + // llarp_logic_queue_job(logic, {introack, &inform_introack}); } void @@ -193,8 +193,9 @@ namespace iwp buf.sz = introack->sz - 32; buf.cur = buf.base; crypto->hmac(introack->buf, buf, sharedkey); - - llarp_logic_queue_job(introack->iwp->logic, {introack, &inform_introack}); + introack->hook(introack); + // llarp_logic_queue_job(introack->iwp->logic, {introack, + // &inform_introack}); } void @@ -217,7 +218,7 @@ namespace iwp auto hmac = crypto->hmac; auto encrypt = crypto->xchacha20; - auto logic = session->iwp->logic; + // auto logic = session->iwp->logic; auto a_sK = session->secretkey; auto b_K = session->remote_pubkey; auto N = session->nonce; @@ -251,8 +252,8 @@ namespace iwp buf.base = (session->buf + 32); buf.sz = session->sz - 32; hmac(session->buf, buf, e_K); - - llarp_logic_queue_job(logic, {user, &inform_session_start}); + session->hook(session); + // llarp_logic_queue_job(logic, {user, &inform_session_start}); } void @@ -267,7 +268,7 @@ namespace iwp auto hmac = crypto->hmac; auto decrypt = crypto->xchacha20; - auto logic = session->iwp->logic; + // auto logic = session->iwp->logic; auto b_sK = session->secretkey; auto a_K = session->remote_pubkey; auto N = session->nonce; @@ -316,8 +317,8 @@ namespace iwp } else // hmac fail session->buf = nullptr; - - llarp_logic_queue_job(logic, {user, &inform_session_start}); + session->hook(session); + // llarp_logic_queue_job(logic, {user, &inform_session_start}); } void @@ -353,6 +354,9 @@ namespace iwp buf.cur = buf.base; buf.sz = frame->sz - 64; crypto->xchacha20(buf, frame->sessionkey, nonce); + // call result RIGHT HERE + // frame->hook(frame); + // delete frame; // inform result llarp_logic_queue_job(frame->iwp->logic, {frame, &inform_frame_done}); } diff --git a/llarp/crypto_libsodium.cpp b/llarp/crypto_libsodium.cpp index 6e71cb769..63877ca3e 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)) @@ -156,7 +132,6 @@ namespace llarp } // namespace llarp extern "C" { - const byte_t * llarp_seckey_topublic(const byte_t *secret) { @@ -170,8 +145,8 @@ llarp_crypto_libsodium_init(struct llarp_crypto *c) 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->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; diff --git a/llarp/encrypted_frame.cpp b/llarp/encrypted_frame.cpp index 9f1b3d3e8..205b5fbc5 100644 --- a/llarp/encrypted_frame.cpp +++ b/llarp/encrypted_frame.cpp @@ -5,29 +5,21 @@ namespace llarp { - Encrypted::Encrypted(const byte_t* buf, size_t sz) + Encrypted::Encrypted(const byte_t* buf, size_t sz) : _data(sz) { - size = sz; - data = new byte_t[sz]; if(buf) - memcpy(data, buf, sz); + memcpy(data(), buf, sz); else - llarp::Zero(data, sz); - m_Buffer.base = data; - m_Buffer.cur = data; - m_Buffer.sz = size; + llarp::Zero(data(), sz); + m_Buffer.base = data(); + m_Buffer.cur = data(); + m_Buffer.sz = size(); } Encrypted::Encrypted(size_t sz) : Encrypted(nullptr, sz) { } - Encrypted::~Encrypted() - { - if(data) - delete[] data; - } - bool EncryptedFrame::EncryptInPlace(byte_t* ourSecretKey, byte_t* otherPubkey, llarp_crypto* crypto) @@ -38,7 +30,7 @@ namespace llarp // <32 bytes pubkey> // // - byte_t* hash = data; + byte_t* hash = data(); byte_t* nonce = hash + SHORTHASHSIZE; byte_t* pubkey = nonce + TUNNONCESIZE; byte_t* body = pubkey + PUBKEYSIZE; @@ -52,7 +44,7 @@ namespace llarp llarp_buffer_t buf; buf.base = body; buf.cur = buf.base; - buf.sz = size - EncryptedFrame::OverheadSize; + buf.sz = size() - EncryptedFrame::OverheadSize; // set our pubkey memcpy(pubkey, llarp::seckey_topublic(ourSecretKey), PUBKEYSIZE); @@ -60,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)) { @@ -75,7 +68,7 @@ namespace llarp // generate message auth buf.base = nonce; buf.cur = buf.base; - buf.sz = size - SHORTHASHSIZE; + buf.sz = size() - SHORTHASHSIZE; if(!MDS(hash, buf, shared)) { @@ -88,9 +81,9 @@ namespace llarp bool EncryptedFrame::DecryptInPlace(byte_t* ourSecretKey, llarp_crypto* crypto) { - if(size <= size_t(EncryptedFrame::OverheadSize)) + if(size() <= size_t(EncryptedFrame::OverheadSize)) { - llarp::Warn("encrypted frame too small, ", size, + llarp::Warn("encrypted frame too small, ", size(), " <= ", size_t(EncryptedFrame::OverheadSize)); return false; } @@ -100,7 +93,7 @@ namespace llarp // <32 bytes pubkey> // // - byte_t* hash = data; + byte_t* hash = data(); byte_t* nonce = hash + SHORTHASHSIZE; byte_t* otherPubkey = nonce + TUNNONCESIZE; byte_t* body = otherPubkey + PUBKEYSIZE; @@ -113,12 +106,12 @@ namespace llarp llarp_buffer_t buf; buf.base = nonce; buf.cur = buf.base; - buf.sz = size - SHORTHASHSIZE; + buf.sz = size() - SHORTHASHSIZE; SharedSecret shared; ShortHash digest; - if(!DH(shared, otherPubkey, nonce, ourSecretKey)) + if(!DH(shared, otherPubkey, ourSecretKey, nonce)) { llarp::Error("DH failed"); return false; @@ -138,7 +131,7 @@ namespace llarp buf.base = body; buf.cur = body; - buf.sz = size - EncryptedFrame::OverheadSize; + buf.sz = size() - EncryptedFrame::OverheadSize; if(!Decrypt(buf, shared, nonce)) { diff --git a/llarp/iwp_link.cpp b/llarp/iwp_link.cpp index aa6823596..2434672a8 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; @@ -591,7 +591,7 @@ namespace iwp void queue_tx(uint64_t id, transit_message *msg) { - tx[id] = msg; + tx.insert(std::make_pair(id, msg)); msg->generate_xmit(sendqueue, txflags); } @@ -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,6 +853,8 @@ 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"); + if(working) + return false; return frames == 0; } if(is_invalidated()) @@ -862,12 +864,17 @@ namespace iwp // are done llarp::Debug(addr, " invaldiated session with ", frames, " frames left"); + if(working) + return false; return frames == 0; } // send keepalive if we are established or a session is made if(state == eEstablished || state == eLIMSent) - { send_keepalive(this); + + // pump frames + if(state == eEstablished) + { frame.retransmit(); pump(); } @@ -905,6 +912,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 +962,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 +992,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 +1100,7 @@ namespace iwp // call introack.user = this; introack.hook = &handle_introack_generated; + working = true; iwp_call_async_gen_introack(iwp, &introack); } @@ -1100,7 +1111,7 @@ namespace iwp { // too big? llarp::Error("intro too big"); - // TOOD: session destroy ? + delete this; return; } // copy so we own it @@ -1119,33 +1130,12 @@ namespace iwp // call EnterState(eIntroRecv); + working = true; iwp_call_async_verify_intro(iwp, &intro); } void - on_intro_ack(const void *buf, size_t sz) - { - if(sz >= sizeof(workbuf)) - { - // too big? - llarp::Error("introack too big"); - // TOOD: session destroy ? - return; - } - // copy buffer so we own it - memcpy(workbuf, buf, sz); - // set intro ack parameters - introack.buf = workbuf; - introack.sz = sz; - introack.nonce = workbuf + 32; - introack.remote_pubkey = remote; - introack.token = token; - introack.secretkey = eph_seckey; - introack.user = this; - introack.hook = &handle_verify_introack; - // async verify - iwp_call_async_verify_introack(iwp, &introack); - } + on_intro_ack(const void *buf, size_t sz); static llarp_link * get_parent(llarp_link_session *s); @@ -1154,6 +1144,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 +1186,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( @@ -1402,7 +1394,10 @@ namespace iwp if(itr != m_sessions.end()) { llarp::Debug("removing session ", addr); + UnmapAddr(addr); session *s = static_cast< session * >(itr->second.impl); + m_sessions.erase(itr); + s->done(); if(s->frames) { llarp::Warn("session has ", s->frames, @@ -1411,8 +1406,6 @@ namespace iwp } else delete s; - m_sessions.erase(itr); - UnmapAddr(addr); } } @@ -1479,7 +1472,6 @@ namespace iwp { // new inbound session s = link->create_session(*saddr); - llarp::Debug("new inbound session from ", s->addr); } s->recv(buf, sz); } @@ -1531,6 +1523,7 @@ namespace iwp if(!impl->IsEstablished()) { impl->send_LIM(); + impl->session_established(); } } else @@ -1552,16 +1545,18 @@ 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 ", self->serv->addr); + delete self; return; } self->intro_ack(); @@ -1570,6 +1565,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); @@ -1578,6 +1575,37 @@ namespace iwp void session::done() { + if(establish_job_id) + { + llarp_logic_remove_call(logic, establish_job_id); + handle_establish_timeout(this, 0, 0); + } + } + + void + session::on_intro_ack(const void *buf, size_t sz) + { + if(sz >= sizeof(workbuf)) + { + // too big? + llarp::Error("introack too big"); + serv->RemoveSessionByAddr(addr); + return; + } + // copy buffer so we own it + memcpy(workbuf, buf, sz); + // set intro ack parameters + introack.buf = workbuf; + introack.sz = sz; + introack.nonce = workbuf + 32; + introack.remote_pubkey = remote; + introack.token = token; + introack.secretkey = eph_seckey; + introack.user = this; + introack.hook = &handle_verify_introack; + // async verify + working = true; + iwp_call_async_verify_introack(iwp, &introack); } void @@ -1636,11 +1664,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,10 +1687,12 @@ 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 llarp::Error("introack verify failed from ", link->addr); + // link->serv->RemoveSessionByAddr(link->addr); return; } link->EnterState(eIntroAckRecv); @@ -1678,6 +1703,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 @@ -1871,14 +1897,15 @@ namespace iwp void session::handle_establish_timeout(void *user, uint64_t orig, uint64_t left) { + if(orig == 0) + return; session *self = static_cast< session * >(user); self->establish_job_id = 0; if(self->establish_job) { self->establish_job->link = self->serv->parent; - if(left) + if(self->IsEstablished()) { - // timer cancelled self->establish_job->session = self->parent; } else @@ -1921,7 +1948,7 @@ namespace iwp delete link; } } -} +} // namespace iwp extern "C" { void 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/net.hpp b/llarp/net.hpp index ca1870c88..55a88d919 100644 --- a/llarp/net.hpp +++ b/llarp/net.hpp @@ -204,10 +204,14 @@ namespace llarp std::size_t operator()(Addr const& a) const noexcept { + if(a.af() == AF_INET) + { + return a.port() + a.addr4()->s_addr; + } uint8_t empty[16] = {0}; return (a.af() + memcmp(a.addr6(), empty, 16)) ^ a.port(); } }; -} +} // namespace llarp #endif diff --git a/llarp/nodedb.cpp b/llarp/nodedb.cpp index 41b204bfc..8b7ae3dd3 100644 --- a/llarp/nodedb.cpp +++ b/llarp/nodedb.cpp @@ -292,7 +292,6 @@ nodedb_async_load_rc(void *user) } extern "C" { - struct llarp_nodedb * llarp_nodedb_new(struct llarp_crypto *crypto) { @@ -352,7 +351,8 @@ llarp_nodedb_load_dir(struct llarp_nodedb *n, const char *dir) void llarp_nodedb_async_verify(struct llarp_async_verify_rc *job) { - // switch to crypto threadpool and continue with crypto_threadworker_verifyrc + // switch to crypto threadpool and continue with + // crypto_threadworker_verifyrc llarp_threadpool_queue_job(job->cryptoworker, {job, &crypto_threadworker_verifyrc}); } @@ -373,4 +373,45 @@ llarp_nodedb_get_rc(struct llarp_nodedb *n, const byte_t *pk) return nullptr; } +size_t +llarp_nodedb_num_loaded(struct llarp_nodedb *n) +{ + return n->entries.size(); +} + +void +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(); + + if(prev) + { + 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); + } +} + } // end extern diff --git a/llarp/path.cpp b/llarp/path.cpp index e3e5ca3a2..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->routers[idx]); - } - } - 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()) { @@ -101,6 +93,12 @@ namespace llarp map.second.emplace(k, v); } + void + PathContext::AddOwnPath(Path* path) + { + MapPut(m_OurPaths, path->PathID(), path); + } + bool PathContext::HasTransitHop(const TransitHopInfo& info) { @@ -148,4 +146,25 @@ namespace llarp : pathID(record.pathid), upstream(record.nextHop), downstream(down) { } + + 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 + { + return hops[0].pathID; + } + + RouterID + Path::Upstream() + { + return hops[0].router.pubkey; + } + } // namespace llarp \ No newline at end of file diff --git a/llarp/pathbuilder.cpp b/llarp/pathbuilder.cpp index f2169a90c..dc2dbbb87 100644 --- a/llarp/pathbuilder.cpp +++ b/llarp/pathbuilder.cpp @@ -20,18 +20,32 @@ namespace llarp pathbuilder_generated_keys( AsyncPathKeyExchangeContext< llarp_pathbuild_job >* ctx) { - llarp::Debug("Generated keys for build"); + auto remote = ctx->path->Upstream(); + llarp::Debug("Generated LRCM to", remote); + auto router = ctx->user->router; + 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); } void pathbuilder_start_build(void* user) { - // select hops llarp_pathbuild_job* job = static_cast< llarp_pathbuild_job* >(user); - size_t idx = 0; + // select hops + size_t idx = 0; + llarp_rc* prev = nullptr; while(idx < job->hops.numHops) { - job->selectHop(job->router->nodedb, &job->hops.routers[idx], idx); + llarp_rc* rc = &job->hops.hops[idx].router; + llarp_rc_clear(rc); + job->selectHop(job->router->nodedb, prev, rc, idx); + prev = rc; ++idx; } @@ -42,21 +56,13 @@ namespace llarp 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) + : router(p_router), dht(p_dht) { - this->router = p_router; - this->dht = p_dht; } extern "C" { @@ -82,6 +88,8 @@ llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job) return; } job->router = job->context->router; + if(job->selectHop == nullptr) + job->selectHop = &llarp_nodedb_select_random_hop; llarp_logic_queue_job(job->router->logic, {job, &llarp::pathbuilder_start_build}); } diff --git a/llarp/relay_commit.cpp b/llarp/relay_commit.cpp index 987d8bc9d..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); } @@ -237,7 +238,7 @@ namespace llarp llarp::Info("Accepted ", self->hop.info); self->context->PutTransitHop(self->hop); - size_t sz = self->frames.front().size; + 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 diff --git a/llarp/router.cpp b/llarp/router.cpp index 0c9339c52..010de39fa 100644 --- a/llarp/router.cpp +++ b/llarp/router.cpp @@ -33,6 +33,7 @@ llarp_router::llarp_router() , paths(this) , dht(llarp_dht_context_new(this)) , inbound_msg_parser(this) + , explorePool(llarp_pathbuilder_context_new(this, dht)) { llarp_rc_clear(&rc); @@ -53,7 +54,7 @@ llarp_router::HandleRecvLinkMessage(llarp_link_session *session, bool llarp_router::SendToOrQueue(const llarp::RouterID &remote, - std::vector< llarp::ILinkMessage * > msgs) + llarp::ILinkMessage *msg) { llarp_link *chosen = nullptr; if(!outboundLink->has_session_to(outboundLink, remote)) @@ -70,34 +71,38 @@ llarp_router::SendToOrQueue(const llarp::RouterID &remote, else chosen = outboundLink; - for(const auto &msg : msgs) + if(chosen) { - // this will create an entry in the obmq if it's not already there - outboundMesssageQueue[remote].push(msg); + SendTo(remote, msg, chosen); + delete msg; + return true; + } + // this will create an entry in the obmq if it's not already there + auto itr = outboundMesssageQueue.find(remote); + if(itr == outboundMesssageQueue.end()) + { + outboundMesssageQueue.emplace(std::make_pair(remote, MessageQueue())); } + 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; } @@ -281,10 +286,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 @@ -359,13 +370,43 @@ llarp_router::handle_router_ticker(void *user, uint64_t orig, uint64_t left) self->ScheduleTicker(orig); } +void +llarp_router::HandleExploritoryPathBuildStarted(llarp_pathbuild_job *job) +{ + delete job; +} + +void +llarp_router::BuildExploritoryPath() +{ + llarp_pathbuild_job *job = new llarp_pathbuild_job; + job->context = explorePool; + job->selectHop = selectHopFunc; + job->hops.numHops = 4; + job->user = this; + job->pathBuildStarted = &HandleExploritoryPathBuildStarted; + llarp_pathbuilder_build_path(job); +} + void llarp_router::Tick() { llarp::Debug("tick router"); paths.ExpirePaths(); - llarp_pathbuild_job job; - llarp_pathbuilder_build_path(&job); + // TODO: don't do this if we have enough paths already + if(inboundLinks.size() == 0) + { + auto N = llarp_nodedb_num_loaded(nodedb); + if(N > 5) + { + BuildExploritoryPath(); + } + else + { + llarp::Warn("not enough nodes known to build exploritory paths, have ", N, + " nodes"); + } + } llarp_link_session_iter iter; iter.user = this; iter.visit = &send_padded_message; @@ -401,7 +442,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); @@ -415,7 +457,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) { @@ -456,7 +502,9 @@ llarp_router::FlushOutboundFor(const llarp::RouterID &remote, llarp::Debug("Flush outbound for ", remote); auto itr = outboundMesssageQueue.find(remote); if(itr == outboundMesssageQueue.end()) + { return; + } while(itr->second.size()) { auto buf = llarp::StackBuffer< decltype(linkmsg_buffer) >(linkmsg_buffer); @@ -599,15 +647,21 @@ llarp_router::Run() { // initialize as service node InitServiceNode(); + // immediate connect all for service node + auto delay = rand() % 100; + llarp_logic_call_later(logic, {delay, this, &ConnectAll}); + } + else + { // delayed connect all for clients + auto delay = ((rand() % 10) * 500) + 1000; + llarp_logic_call_later(logic, {delay, this, &ConnectAll}); } llarp::PubKey ourPubkey = pubkey(); llarp::Info("starting dht context as ", ourPubkey); llarp_dht_context_start(dht, ourPubkey); - llarp_logic_call_later(logic, {1000, this, &ConnectAll}); - - ScheduleTicker(500); + ScheduleTicker(1000); } void diff --git a/llarp/router.hpp b/llarp/router.hpp index 5b89e3116..1930edf67 100644 --- a/llarp/router.hpp +++ b/llarp/router.hpp @@ -72,6 +72,7 @@ struct llarp_router llarp::InboundMessageParser inbound_msg_parser; llarp_pathbuilder_select_hop_func selectHopFunc = nullptr; + llarp_pathbuilder_context *explorePool = nullptr; llarp_link *outboundLink = nullptr; std::list< llarp_link * > inboundLinks; @@ -79,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(); @@ -144,12 +142,12 @@ struct llarp_router /// NOT threadsafe /// MUST be called in the logic thread bool - SendToOrQueue(const llarp::RouterID &remote, - std::vector< llarp::ILinkMessage * > msgs); + SendToOrQueue(const llarp::RouterID &remote, llarp::ILinkMessage *msg); /// 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 @@ -171,6 +169,9 @@ struct llarp_router void Tick(); + void + BuildExploritoryPath(); + /// schedule ticker to call i ms from now void ScheduleTicker(uint64_t i = 1000); @@ -207,6 +208,9 @@ struct llarp_router static void HandleDHTLookupForSendTo(llarp_router_lookup_job *job); + + static void + HandleExploritoryPathBuildStarted(llarp_pathbuild_job *job); }; #endif 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