pull/3/head
Ryan Tharp 6 years ago
commit 3241655ed9

@ -54,6 +54,9 @@
"__config": "cpp", "__config": "cpp",
"__nullptr": "cpp", "__nullptr": "cpp",
"algorithm": "cpp", "algorithm": "cpp",
"io": "cpp" "io": "cpp",
"strstream": "cpp",
"numeric": "cpp",
"valarray": "cpp"
} }
} }

@ -125,6 +125,7 @@ set(LIB_SRC
llarp/nodedb.cpp llarp/nodedb.cpp
llarp/path.cpp llarp/path.cpp
llarp/pathbuilder.cpp llarp/pathbuilder.cpp
llarp/pathset.cpp
llarp/proofofwork.cpp llarp/proofofwork.cpp
llarp/relay_ack.cpp llarp/relay_ack.cpp
llarp/relay_commit.cpp llarp/relay_commit.cpp

@ -59,14 +59,14 @@ shadow: shadow-build
bash -c "$(SHADOW_BIN) -w $$(cat /proc/cpuinfo | grep processor | wc -l) $(SHADOW_CONFIG) &> $(SHADOW_LOG) || true" bash -c "$(SHADOW_BIN) -w $$(cat /proc/cpuinfo | grep processor | wc -l) $(SHADOW_CONFIG) &> $(SHADOW_LOG) || true"
testnet-configure: clean testnet-configure: clean
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug cmake -GNinja -DCMAKE_BUILD_TYPE=Debug
testnet-build: testnet-configure testnet-build: testnet-configure
ninja ninja
testnet: testnet-build testnet: testnet-build
mkdir -p $(TESTNET_ROOT) mkdir -p $(TESTNET_ROOT)
python3 contrib/testnet/genconf.py --bin=$(REPO)/llarpd --svc=30 --clients=1 --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF) python3 contrib/testnet/genconf.py --bin=$(REPO)/llarpd --svc=30 --clients=300 --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF)
supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF) supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF)
test: debug-configure test: debug-configure

@ -21,21 +21,22 @@ handle_signal(int sig)
#include <llarp/router_contact.h> #include <llarp/router_contact.h>
#include <llarp/time.h> #include <llarp/time.h>
#include <fstream> #include <fstream>
#include "fs.hpp"
#include "buffer.hpp" #include "buffer.hpp"
#include "crypto.hpp" #include "crypto.hpp"
#include "fs.hpp"
#include "router.hpp" #include "router.hpp"
bool printNode(struct llarp_nodedb_iter *iter) { bool
printNode(struct llarp_nodedb_iter *iter)
{
char ftmp[68] = {0}; char ftmp[68] = {0};
const char *hexname = const char *hexname =
llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(iter->rc->pubkey, ftmp); llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(iter->rc->pubkey, ftmp);
printf("[%zu]=>[%s]\n", iter->index, hexname); printf("[%zu]=>[%s]\n", iter->index, hexname);
return false; return false;
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -61,9 +62,9 @@ main(int argc, char *argv[])
"\n"); "\n");
return 0; return 0;
} }
bool genMode = false; bool genMode = false;
bool updMode = false; bool updMode = false;
bool listMode = false; bool listMode = false;
bool importMode = false; bool importMode = false;
bool exportMode = false; bool exportMode = false;
int c; int c;
@ -71,8 +72,8 @@ main(int argc, char *argv[])
char defaultConfName[] = "daemon.ini"; char defaultConfName[] = "daemon.ini";
conffname = defaultConfName; conffname = defaultConfName;
char *rcfname; char *rcfname;
char defaultRcName[] = "other.signed"; char defaultRcName[] = "other.signed";
rcfname = defaultRcName; rcfname = defaultRcName;
bool haveRequiredOptions = false; bool haveRequiredOptions = false;
while(1) while(1)
{ {
@ -97,49 +98,51 @@ main(int argc, char *argv[])
break; break;
case 'l': case 'l':
haveRequiredOptions = true; haveRequiredOptions = true;
listMode = true; listMode = true;
break; break;
case 'i': case 'i':
// printf ("option -g with value `%s'\n", optarg); // printf ("option -g with value `%s'\n", optarg);
rcfname = optarg; rcfname = optarg;
haveRequiredOptions = true; haveRequiredOptions = true;
importMode = true; importMode = true;
break; break;
case 'e': case 'e':
// printf ("option -g with value `%s'\n", optarg); // printf ("option -g with value `%s'\n", optarg);
rcfname = optarg; rcfname = optarg;
haveRequiredOptions = true; haveRequiredOptions = true;
exportMode = true; exportMode = true;
break; break;
case 'g': case 'g':
// printf ("option -g with value `%s'\n", optarg); // printf ("option -g with value `%s'\n", optarg);
rcfname = optarg; rcfname = optarg;
haveRequiredOptions = true; haveRequiredOptions = true;
genMode = true; genMode = true;
break; break;
case 'u': case 'u':
// printf ("option -u with value `%s'\n", optarg); // printf ("option -u with value `%s'\n", optarg);
rcfname = optarg; rcfname = optarg;
haveRequiredOptions = true; haveRequiredOptions = true;
updMode = true; updMode = true;
break; break;
default: default:
abort(); abort();
} }
} }
if (!haveRequiredOptions) { if(!haveRequiredOptions)
{
llarp::Error("Parameters dont all have their required parameters.\n"); llarp::Error("Parameters dont all have their required parameters.\n");
return 0; return 0;
} }
printf("parsed options\n"); printf("parsed options\n");
if(!genMode && !updMode && !listMode &&!importMode && !exportMode) if(!genMode && !updMode && !listMode && !importMode && !exportMode)
{ {
llarp::Error("I don't know what to do, no generate or update parameter\n"); llarp::Error("I don't know what to do, no generate or update parameter\n");
return 0; return 0;
} }
ctx = llarp_main_init(conffname, !TESTNET); ctx = llarp_main_init(conffname, !TESTNET);
if (!ctx) { if(!ctx)
{
llarp::Error("Cant set up context"); llarp::Error("Cant set up context");
return 0; return 0;
} }
@ -162,10 +165,12 @@ main(int argc, char *argv[])
llarp_crypto crypt; llarp_crypto crypt;
llarp_crypto_libsodium_init(&crypt); llarp_crypto_libsodium_init(&crypt);
// which is in daemon.ini config: router.encryption-privkey (defaults "encryption.key") // which is in daemon.ini config: router.encryption-privkey (defaults
// "encryption.key")
fs::path encryption_keyfile = "encryption.key"; fs::path encryption_keyfile = "encryption.key";
llarp::SecretKey encryption; llarp::SecretKey encryption;
llarp_findOrCreateEncryption(&crypt, encryption_keyfile.c_str(), &encryption); llarp_findOrCreateEncryption(&crypt, encryption_keyfile.c_str(),
&encryption);
llarp_rc_set_pubenckey(&tmp, llarp::seckey_topublic(encryption)); llarp_rc_set_pubenckey(&tmp, llarp::seckey_topublic(encryption));
// get identity public sig key // get identity public sig key
@ -206,33 +211,37 @@ main(int argc, char *argv[])
// write file // write file
llarp_rc_write(&tmp, our_rc_file_out.c_str()); llarp_rc_write(&tmp, our_rc_file_out.c_str());
} }
if (listMode) { if(listMode)
{
llarp_main_loadDatabase(ctx); llarp_main_loadDatabase(ctx);
llarp_nodedb_iter iter; llarp_nodedb_iter iter;
iter.visit = printNode; iter.visit = printNode;
llarp_main_iterateDatabase(ctx, iter); llarp_main_iterateDatabase(ctx, iter);
} }
if (importMode) { if(importMode)
{
llarp_main_loadDatabase(ctx); llarp_main_loadDatabase(ctx);
llarp::Info("Loading ", rcfname); llarp::Info("Loading ", rcfname);
llarp_rc *rc = llarp_rc_read(rcfname); llarp_rc *rc = llarp_rc_read(rcfname);
if (!rc) if(!rc)
{ {
llarp::Error("Can't load RC"); llarp::Error("Can't load RC");
return 0; return 0;
} }
llarp_main_putDatabase(ctx, rc); llarp_main_putDatabase(ctx, rc);
} }
if (exportMode) { if(exportMode)
{
llarp_main_loadDatabase(ctx); llarp_main_loadDatabase(ctx);
//llarp::Info("Looking for string: ", rcfname); // llarp::Info("Looking for string: ", rcfname);
llarp::PubKey binaryPK; llarp::PubKey binaryPK;
llarp::HexDecode(rcfname, binaryPK.data()); llarp::HexDecode(rcfname, binaryPK.data());
llarp::Info("Looking for binary: ", binaryPK); llarp::Info("Looking for binary: ", binaryPK);
struct llarp_rc *rc = llarp_main_getDatabase(ctx, binaryPK.data()); struct llarp_rc *rc = llarp_main_getDatabase(ctx, binaryPK.data());
if (!rc) { if(!rc)
{
llarp::Error("Can't load RC from database"); llarp::Error("Can't load RC from database");
} }
std::string filename(rcfname); std::string filename(rcfname);
@ -241,5 +250,5 @@ main(int argc, char *argv[])
llarp_rc_write(rc, filename.c_str()); llarp_rc_write(rc, filename.c_str());
} }
llarp_main_free(ctx); llarp_main_free(ctx);
return 1; // success return 1; // success
} }

@ -39,7 +39,6 @@ llarp_main_loadDatabase(struct llarp_main *ptr);
int int
llarp_main_iterateDatabase(struct llarp_main *ptr, struct llarp_nodedb_iter i); llarp_main_iterateDatabase(struct llarp_main *ptr, struct llarp_nodedb_iter i);
/// put RC into nodeDB /// put RC into nodeDB
bool bool
llarp_main_putDatabase(struct llarp_main *ptr, struct llarp_rc *rc); llarp_main_putDatabase(struct llarp_main *ptr, struct llarp_rc *rc);
@ -47,7 +46,6 @@ llarp_main_putDatabase(struct llarp_main *ptr, struct llarp_rc *rc);
struct llarp_rc * struct llarp_rc *
llarp_main_getDatabase(struct llarp_main *ptr, byte_t *pk); llarp_main_getDatabase(struct llarp_main *ptr, byte_t *pk);
void void
llarp_main_free(struct llarp_main *ptr); llarp_main_free(struct llarp_main *ptr);

@ -83,6 +83,14 @@ namespace llarp
b[idx] = f; b[idx] = f;
} }
bool
IsZero() const
{
AlignedBuffer< sz > b;
b.Zero();
return memcmp(l, b.l, sz) == 0;
}
void void
Zero() Zero()
{ {

@ -4,6 +4,7 @@
#include <llarp/ev.h> #include <llarp/ev.h>
#include <llarp/logic.h> #include <llarp/logic.h>
#include <llarp/threadpool.h> #include <llarp/threadpool.h>
#include <llarp/time.h>
/** /**
* crypto_async.h * crypto_async.h
@ -166,6 +167,8 @@ struct iwp_async_frame
{ {
/// true if decryption succeded /// true if decryption succeded
bool success; bool success;
/// timestamp for CoDel
llarp_time_t created;
struct llarp_async_iwp *iwp; struct llarp_async_iwp *iwp;
/// a pointer to pass ourself /// a pointer to pass ourself
void *user; void *user;
@ -179,6 +182,14 @@ struct iwp_async_frame
byte_t buf[1500]; byte_t buf[1500];
}; };
/// synchronously decrypt a frame
bool
iwp_decrypt_frame(struct iwp_async_frame *frame);
/// synchronosuly encrypt a frame
bool
iwp_encrypt_frame(struct iwp_async_frame *frame);
/// decrypt iwp frame asynchronously /// decrypt iwp frame asynchronously
void void
iwp_call_async_frame_decrypt(struct llarp_async_iwp *iwp, iwp_call_async_frame_decrypt(struct llarp_async_iwp *iwp,

@ -30,9 +30,6 @@ namespace llarp
{ {
} }
bool
IsZero() const;
Key_t Key_t
operator^(const Key_t& other) const operator^(const Key_t& other) const
{ {
@ -49,8 +46,6 @@ namespace llarp
} }
}; };
extern Key_t ZeroKey;
struct Node struct Node
{ {
llarp_rc* rc; llarp_rc* rc;

@ -1,7 +1,7 @@
#ifndef LLARP_ENCODE_HPP #ifndef LLARP_ENCODE_HPP
#define LLARP_ENCODE_HPP #define LLARP_ENCODE_HPP
#include <cstdlib>
#include <stdint.h> #include <stdint.h>
#include <cstdlib>
namespace llarp namespace llarp
{ {
@ -28,8 +28,10 @@ namespace llarp
return &stack[0]; return &stack[0];
} }
int char2int(char input); int
void HexDecode(const char* src, uint8_t* target); char2int(char input);
void
HexDecode(const char* src, uint8_t* target);
} }
#endif #endif

@ -11,7 +11,10 @@
namespace llarp namespace llarp
{ {
// forward declare // forward declare
struct PathContext; namespace path
{
struct PathContext;
}
struct LR_CommitRecord struct LR_CommitRecord
{ {
@ -67,7 +70,7 @@ namespace llarp
HandleMessage(llarp_router *router) const; HandleMessage(llarp_router *router) const;
bool bool
AsyncDecrypt(PathContext *context) const; AsyncDecrypt(llarp::path::PathContext *context) const;
}; };
} // namespace llarp } // namespace llarp

@ -4,6 +4,9 @@
#include <llarp/router_contact.h> #include <llarp/router_contact.h>
#define MAXHOPS (8) #define MAXHOPS (8)
#define DEFAULT_PATH_LIFETIME (10 * 60 * 1000)
#define PATH_BUILD_TIMEOUT (30 * 1000)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

@ -5,10 +5,12 @@
#include <llarp/time.h> #include <llarp/time.h>
#include <llarp/aligned.hpp> #include <llarp/aligned.hpp>
#include <llarp/crypto.hpp> #include <llarp/crypto.hpp>
#include <llarp/dht.hpp>
#include <llarp/endpoint.hpp> #include <llarp/endpoint.hpp>
#include <llarp/messages/relay.hpp> #include <llarp/messages/relay.hpp>
#include <llarp/messages/relay_commit.hpp> #include <llarp/messages/relay_commit.hpp>
#include <llarp/path_types.hpp> #include <llarp/path_types.hpp>
#include <llarp/pathset.hpp>
#include <llarp/router_id.hpp> #include <llarp/router_id.hpp>
#include <llarp/routing/handler.hpp> #include <llarp/routing/handler.hpp>
#include <llarp/routing/message.hpp> #include <llarp/routing/message.hpp>
@ -19,292 +21,315 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#define DEFAULT_PATH_LIFETIME (10 * 60 * 1000)
namespace llarp namespace llarp
{ {
struct TransitHopInfo namespace path
{ {
TransitHopInfo() = default; struct TransitHopInfo
TransitHopInfo(const TransitHopInfo& other); {
TransitHopInfo(const RouterID& down, const LR_CommitRecord& record); TransitHopInfo() = default;
TransitHopInfo(const TransitHopInfo& other);
TransitHopInfo(const RouterID& down, const LR_CommitRecord& record);
PathID_t txID, rxID; PathID_t txID, rxID;
RouterID upstream; RouterID upstream;
RouterID downstream; RouterID downstream;
friend std::ostream& friend std::ostream&
operator<<(std::ostream& out, const TransitHopInfo& info) operator<<(std::ostream& out, const TransitHopInfo& info)
{ {
out << "<tx=" << info.txID << " rx=" << info.rxID; out << "<tx=" << info.txID << " rx=" << info.rxID;
out << " upstream=" << info.upstream << " downstream=" << info.downstream; out << " upstream=" << info.upstream
return out << ">"; << " downstream=" << info.downstream;
} return out << ">";
}
bool bool
operator==(const TransitHopInfo& other) const operator==(const TransitHopInfo& other) const
{ {
return txID == other.txID && rxID == other.rxID return txID == other.txID && rxID == other.rxID
&& upstream == other.upstream && downstream == other.downstream; && upstream == other.upstream && downstream == other.downstream;
} }
bool bool
operator!=(const TransitHopInfo& other) const operator!=(const TransitHopInfo& other) const
{ {
return !(*this == other); return !(*this == other);
} }
bool bool
operator<(const TransitHopInfo& other) const operator<(const TransitHopInfo& other) const
{ {
return txID < other.txID || rxID < other.rxID || upstream < other.upstream return txID < other.txID || rxID < other.rxID
|| downstream < other.downstream; || upstream < other.upstream || downstream < other.downstream;
} }
struct Hash
{
std::size_t
operator()(TransitHopInfo const& a) const
{
std::size_t idx0, idx1, idx2, idx3;
memcpy(&idx0, a.upstream, sizeof(std::size_t));
memcpy(&idx1, a.downstream, sizeof(std::size_t));
memcpy(&idx2, a.txID, sizeof(std::size_t));
memcpy(&idx3, a.rxID, sizeof(std::size_t));
return idx0 ^ idx1 ^ idx2;
}
};
};
struct Hash struct PathIDHash
{ {
std::size_t std::size_t
operator()(TransitHopInfo const& a) const operator()(const PathID_t& a) const
{ {
std::size_t idx0, idx1, idx2, idx3; std::size_t idx0;
memcpy(&idx0, a.upstream, sizeof(std::size_t)); memcpy(&idx0, a, sizeof(std::size_t));
memcpy(&idx1, a.downstream, sizeof(std::size_t)); return idx0;
memcpy(&idx2, a.txID, sizeof(std::size_t));
memcpy(&idx3, a.rxID, sizeof(std::size_t));
return idx0 ^ idx1 ^ idx2;
} }
}; };
};
struct PathIDHash struct IHopHandler
{
std::size_t
operator()(const PathID_t& a) const
{ {
std::size_t idx0; virtual ~IHopHandler(){};
memcpy(&idx0, a, sizeof(std::size_t));
return idx0;
}
};
struct IHopHandler virtual bool
{ Expired(llarp_time_t now) const = 0;
virtual ~IHopHandler(){};
virtual bool
SendRoutingMessage(const llarp::routing::IMessage* msg,
llarp_router* r) = 0;
virtual bool // handle data in upstream direction
Expired(llarp_time_t now) const = 0; virtual bool
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y,
llarp_router* r) = 0;
virtual bool // handle data in downstream direction
SendRoutingMessage(const llarp::routing::IMessage* msg, virtual bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y,
llarp_router* r) = 0; llarp_router* r) = 0;
};
// handle data in upstream direction struct TransitHop : public IHopHandler
virtual bool {
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r) = 0; TransitHop() = default;
// handle data in downstream direction TransitHop(const TransitHop& other);
virtual bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y,
llarp_router* r) = 0;
};
struct TransitHop : public IHopHandler TransitHopInfo info;
{ SharedSecret pathKey;
TransitHop() = default; llarp_time_t started = 0;
// 10 minutes default
llarp_time_t lifetime = DEFAULT_PATH_LIFETIME;
llarp_proto_version_t version;
friend std::ostream&
operator<<(std::ostream& out, const TransitHop& h)
{
return out << "[TransitHop " << h.info << " started=" << h.started
<< " lifetime=" << h.lifetime << "]";
}
bool
Expired(llarp_time_t now) const;
TransitHop(const TransitHop& other); bool
SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r);
TransitHopInfo info; // handle data in upstream direction
SharedSecret pathKey; bool
llarp_time_t started = 0; HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
// 10 minutes default
llarp_time_t lifetime = DEFAULT_PATH_LIFETIME;
llarp_proto_version_t version;
friend std::ostream& // handle data in downstream direction
operator<<(std::ostream& out, const TransitHop& h) bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
};
/// configuration for a single hop when building a path
struct PathHopConfig
{ {
return out << "[TransitHop " << h.info << " started=" << h.started /// path id
<< " lifetime=" << h.lifetime << "]"; PathID_t txID, rxID;
} // router contact of router
llarp_rc router;
// temp public encryption key
SecretKey commkey;
/// shared secret at this hop
SharedSecret shared;
/// next hop's router id
RouterID upstream;
/// nonce for key exchange
TunnelNonce nonce;
// lifetime
llarp_time_t lifetime = DEFAULT_PATH_LIFETIME;
~PathHopConfig();
PathHopConfig();
};
bool /// A path we made
Expired(llarp_time_t now) const; struct Path : public IHopHandler, public llarp::routing::IMessageHandler
{
typedef std::function< void(Path*) > BuildResultHookFunc;
typedef std::vector< PathHopConfig > HopList;
HopList hops;
llarp_time_t buildStarted;
PathStatus status;
bool Path(llarp_path_hops* path);
SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r);
// handle data in upstream direction void
bool SetBuildResultHook(BuildResultHookFunc func);
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
// handle data in downstream direction bool
bool Expired(llarp_time_t now) const;
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
};
/// configuration for a single hop when building a path bool
struct PathHopConfig SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r);
{
/// path id
PathID_t txID, rxID;
// router contact of router
llarp_rc router;
// temp public encryption key
SecretKey commkey;
/// shared secret at this hop
SharedSecret shared;
/// next hop's router id
RouterID upstream;
/// nonce for key exchange
TunnelNonce nonce;
// lifetime
llarp_time_t lifetime = DEFAULT_PATH_LIFETIME;
~PathHopConfig();
PathHopConfig();
};
enum PathStatus
{
ePathBuilding,
ePathEstablished,
ePathTimeout,
ePathExpired
};
/// A path we made
struct Path : public IHopHandler, public llarp::routing::IMessageHandler
{
typedef std::vector< PathHopConfig > HopList;
HopList hops;
llarp_time_t buildStarted;
PathStatus status;
Path(llarp_path_hops* path); bool
HandlePathConfirmMessage(const llarp::routing::PathConfirmMessage* msg);
bool bool
Expired(llarp_time_t now) const; HandlePathLatencyMessage(const llarp::routing::PathLatencyMessage* msg);
bool bool
SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r); HandleDHTMessage(const llarp::dht::IMessage* msg);
bool bool
HandleRoutingMessage(llarp_buffer_t buf, llarp_router* r); HandleRoutingMessage(llarp_buffer_t buf, llarp_router* r);
bool bool
HandleHiddenServiceData(llarp_buffer_t buf); HandleHiddenServiceData(llarp_buffer_t buf);
// handle data in upstream direction // handle data in upstream direction
bool bool
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r); HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
// handle data in downstream direction // handle data in downstream direction
bool bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r); HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
// Is this deprecated? // Is this deprecated?
const PathID_t& // nope not deprecated :^DDDD
TXID() const; const PathID_t&
TXID() const;
const PathID_t& const PathID_t&
RXID() const; RXID() const;
RouterID RouterID
Upstream() const; Upstream() const;
protected: protected:
llarp::routing::InboundMessageParser m_InboundMessageParser; llarp::routing::InboundMessageParser m_InboundMessageParser;
};
enum PathBuildStatus private:
{ BuildResultHookFunc m_BuiltHook;
ePathBuildSuccess, };
ePathBuildTimeout,
ePathBuildReject
};
struct PathContext enum PathBuildStatus
{ {
PathContext(llarp_router* router); ePathBuildSuccess,
~PathContext(); ePathBuildTimeout,
ePathBuildReject
};
struct PathContext
{
PathContext(llarp_router* router);
~PathContext();
/// called from router tick function /// called from router tick function
void void
ExpirePaths(); ExpirePaths();
void /// called from router tick function
AllowTransit(); /// builds all paths we need to build at current tick
void void
RejectTransit(); BuildPaths();
bool /// track a path builder with this context
AllowingTransit() const; void
AddPathBuilder(llarp_pathbuilder_context* set);
bool void
HasTransitHop(const TransitHopInfo& info); AllowTransit();
void
RejectTransit();
bool bool
HandleRelayCommit(const LR_CommitMessage* msg); AllowingTransit() const;
void bool
PutTransitHop(TransitHop* hop); HasTransitHop(const TransitHopInfo& info);
IHopHandler* bool
GetByUpstream(const RouterID& id, const PathID_t& path); HandleRelayCommit(const LR_CommitMessage* msg);
IHopHandler* void
GetByDownstream(const RouterID& id, const PathID_t& path); PutTransitHop(TransitHop* hop);
bool IHopHandler*
ForwardLRCM(const RouterID& nextHop, std::deque< EncryptedFrame >& frames); GetByUpstream(const RouterID& id, const PathID_t& path);
bool IHopHandler*
HopIsUs(const PubKey& k) const; GetByDownstream(const RouterID& id, const PathID_t& path);
bool bool
HandleLRUM(const RelayUpstreamMessage* msg); ForwardLRCM(const RouterID& nextHop,
std::deque< EncryptedFrame >& frames);
bool bool
HandleLRDM(const RelayDownstreamMessage* msg); HopIsUs(const PubKey& k) const;
void bool
AddOwnPath(Path* p); HandleLRUM(const RelayUpstreamMessage* msg);
typedef std::multimap< PathID_t, TransitHop* > TransitHopsMap_t; bool
HandleLRDM(const RelayDownstreamMessage* msg);
typedef std::pair< std::mutex, TransitHopsMap_t > SyncTransitMap_t; void
AddOwnPath(PathSet* set, Path* p);
typedef std::map< PathID_t, Path* > OwnedPathsMap_t; typedef std::multimap< PathID_t, TransitHop* > TransitHopsMap_t;
typedef std::pair< std::mutex, OwnedPathsMap_t > SyncOwnedPathsMap_t; typedef std::pair< std::mutex, TransitHopsMap_t > SyncTransitMap_t;
llarp_threadpool* // maps path id -> pathset owner of path
Worker(); typedef std::map< PathID_t, PathSet* > OwnedPathsMap_t;
llarp_crypto* typedef std::pair< std::mutex, OwnedPathsMap_t > SyncOwnedPathsMap_t;
Crypto();
llarp_logic* llarp_threadpool*
Logic(); Worker();
llarp_router* llarp_crypto*
Router(); Crypto();
byte_t* llarp_logic*
EncryptionSecretKey(); Logic();
const byte_t* llarp_router*
OurRouterID() const; Router();
private: byte_t*
llarp_router* m_Router; EncryptionSecretKey();
SyncTransitMap_t m_TransitPaths;
SyncTransitMap_t m_Paths;
SyncOwnedPathsMap_t m_OurPaths;
bool m_AllowTransit; const byte_t*
}; OurRouterID() const;
private:
llarp_router* m_Router;
SyncTransitMap_t m_TransitPaths;
SyncTransitMap_t m_Paths;
SyncOwnedPathsMap_t m_OurPaths;
std::list< llarp_pathbuilder_context* > m_PathBuilders;
bool m_AllowTransit;
};
} // namespace path
} // namespace llarp } // namespace llarp
#endif #endif

@ -0,0 +1,63 @@
#ifndef LLARP_PATHSET_HPP
#define LLARP_PATHSET_HPP
#include <llarp/path_types.hpp>
#include <map>
#include <tuple>
namespace llarp
{
namespace path
{
enum PathStatus
{
ePathBuilding,
ePathEstablished,
ePathTimeout,
ePathExpired
};
// forward declare
struct Path;
/// a set of paths owned by an entity
struct PathSet
{
/// construct
/// @params numPaths the number of paths to maintain
PathSet(size_t numPaths);
void
RemovePath(Path* path);
void
HandlePathBuilt(Path* path);
void
AddPath(Path* path);
Path*
GetByUpstream(const RouterID& remote, const PathID_t& rxid);
void
ExpirePaths(llarp_time_t now);
size_t
NumInStatus(PathStatus st) const;
/// return true if we should build another path
bool
ShouldBuildMore() const;
private:
typedef std::map< PathID_t, Path* > PathMap_t;
// (tx,rx)
typedef std::tuple< PathMap_t, PathMap_t > PathContainer_t;
size_t m_NumPaths;
PathContainer_t m_Paths;
};
} // namespace path
} // namespace llarp
#endif

@ -2,6 +2,9 @@
#define LLARP_ROUTING_HANDLER_HPP #define LLARP_ROUTING_HANDLER_HPP
#include <llarp/buffer.h> #include <llarp/buffer.h>
#include <llarp/dht.hpp>
#include <llarp/messages/path_confirm.hpp>
#include <llarp/messages/path_latency.hpp>
namespace llarp namespace llarp
{ {
@ -12,6 +15,15 @@ namespace llarp
{ {
virtual bool virtual bool
HandleHiddenServiceData(llarp_buffer_t buf) = 0; HandleHiddenServiceData(llarp_buffer_t buf) = 0;
virtual bool
HandlePathConfirmMessage(const PathConfirmMessage* msg) = 0;
virtual bool
HandlePathLatencyMessage(const PathLatencyMessage* msg) = 0;
virtual bool
HandleDHTMessage(const llarp::dht::IMessage* msg) = 0;
}; };
} // namespace routing } // namespace routing
} // namespace llarp } // namespace llarp

@ -7,7 +7,6 @@ namespace llarp
{ {
namespace api namespace api
{ {
bool bool
CreateSessionMessage::DecodeParams(llarp_buffer_t *buf) CreateSessionMessage::DecodeParams(llarp_buffer_t *buf)
{ {

@ -0,0 +1,74 @@
#ifndef LLARP_CODEL_QUEUE_HPP
#define LLARP_CODEL_QUEUE_HPP
#include <llarp/time.h>
#include <cmath>
#include <functional>
#include <mutex>
#include <queue>
namespace llarp
{
namespace util
{
template < typename T, typename GetTime, llarp_time_t dropMs = 20,
llarp_time_t initialIntervalMs = 100 >
struct CoDelQueue
{
struct CoDelCompare
{
GetTime getTime = GetTime();
bool
operator()(const T& left, const T& right) const
{
return getTime(left) < getTime(right);
}
};
void
Put(T* item)
{
std::unique_lock< std::mutex > lock(m_QueueMutex);
m_Queue.push(*item);
}
void
Process(std::queue< T >& result)
{
llarp_time_t lowest = 0xFFFFFFFFFFFFFFFFUL;
auto start = llarp_time_now_ms();
std::unique_lock< std::mutex > lock(m_QueueMutex);
while(m_Queue.size())
{
const auto& item = m_Queue.top();
auto dlt = start - getTime(item);
lowest = std::min(dlt, lowest);
if(m_Queue.size() == 1)
{
if(lowest > dropMs)
{
// drop
nextTickInterval = initialIntervalMs / std::sqrt(++dropNum);
m_Queue.pop();
return;
}
else
{
nextTickInterval = initialIntervalMs;
dropNum = 0;
}
}
result.push(item);
m_Queue.pop();
}
}
GetTime getTime = GetTime();
size_t dropNum = 0;
llarp_time_t nextTickInterval = initialIntervalMs;
std::mutex m_QueueMutex;
std::priority_queue< T, std::vector< T >, CoDelCompare > m_Queue;
};
} // namespace util
} // namespace llarp
#endif

@ -29,7 +29,7 @@ namespace llarp
bool bool
Context::ReloadConfig() Context::ReloadConfig()
{ {
//llarp::Info("loading config at ", configfile); // llarp::Info("loading config at ", configfile);
if(llarp_load_config(config, configfile.c_str())) if(llarp_load_config(config, configfile.c_str()))
{ {
llarp_free_config(&config); llarp_free_config(&config);
@ -94,7 +94,7 @@ namespace llarp
llarp::Error("nodedb_dir is incorrect"); llarp::Error("nodedb_dir is incorrect");
return 0; return 0;
} }
//llarp::Info("nodedb_dir [", nodedb_dir, "] configured!"); // llarp::Info("nodedb_dir [", nodedb_dir, "] configured!");
ssize_t loaded = llarp_nodedb_load_dir(nodedb, nodedb_dir); ssize_t loaded = llarp_nodedb_load_dir(nodedb, nodedb_dir);
llarp::Info("nodedb_dir loaded ", loaded, " RCs from [", nodedb_dir, "]"); llarp::Info("nodedb_dir loaded ", loaded, " RCs from [", nodedb_dir, "]");
if(loaded < 0) if(loaded < 0)

@ -333,30 +333,7 @@ namespace iwp
hmac_then_decrypt(void *user) hmac_then_decrypt(void *user)
{ {
iwp_async_frame *frame = static_cast< iwp_async_frame * >(user); iwp_async_frame *frame = static_cast< iwp_async_frame * >(user);
auto crypto = frame->iwp->crypto; iwp_decrypt_frame(frame);
byte_t *hmac = frame->buf;
byte_t *nonce = frame->buf + 32;
byte_t *body = frame->buf + 64;
llarp::ShortHash digest;
llarp_buffer_t buf;
buf.base = nonce;
buf.cur = buf.base;
buf.sz = frame->sz - 32;
// h = MDS(n + x, S)
crypto->hmac(digest, buf, frame->sessionkey);
// check hmac
frame->success = memcmp(digest, hmac, 32) == 0;
// x = SE(S, p, n[0:24])
buf.base = body;
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 // inform result
llarp_logic_queue_job(frame->iwp->logic, {frame, &inform_frame_done}); llarp_logic_queue_job(frame->iwp->logic, {frame, &inform_frame_done});
} }
@ -365,25 +342,7 @@ namespace iwp
encrypt_then_hmac(void *user) encrypt_then_hmac(void *user)
{ {
iwp_async_frame *frame = static_cast< iwp_async_frame * >(user); iwp_async_frame *frame = static_cast< iwp_async_frame * >(user);
auto crypto = frame->iwp->crypto; iwp_encrypt_frame(frame);
byte_t *hmac = frame->buf;
byte_t *nonce = frame->buf + 32;
byte_t *body = frame->buf + 64;
llarp_buffer_t buf;
buf.base = body;
buf.cur = buf.base;
buf.sz = frame->sz - 64;
// randomize N
crypto->randbytes(nonce, 32);
// x = SE(S, p, n[0:24])
crypto->xchacha20(buf, frame->sessionkey, nonce);
// h = MDS(n + x, S)
buf.base = nonce;
buf.cur = buf.base;
buf.sz = frame->sz - 32;
crypto->hmac(hmac, buf, frame->sessionkey);
// call result RIGHT HERE // call result RIGHT HERE
frame->hook(frame); frame->hook(frame);
delete frame; delete frame;
@ -399,6 +358,58 @@ iwp_call_async_keygen(struct llarp_async_iwp *iwp,
llarp_threadpool_queue_job(iwp->worker, {keygen, &iwp::keygen}); llarp_threadpool_queue_job(iwp->worker, {keygen, &iwp::keygen});
} }
bool
iwp_decrypt_frame(struct iwp_async_frame *frame)
{
auto crypto = frame->iwp->crypto;
byte_t *hmac = frame->buf;
byte_t *nonce = frame->buf + 32;
byte_t *body = frame->buf + 64;
llarp::ShortHash digest;
llarp_buffer_t buf;
buf.base = nonce;
buf.cur = buf.base;
buf.sz = frame->sz - 32;
// h = MDS(n + x, S)
crypto->hmac(digest, buf, frame->sessionkey);
// check hmac
frame->success = memcmp(digest, hmac, 32) == 0;
// x = SE(S, p, n[0:24])
buf.base = body;
buf.cur = buf.base;
buf.sz = frame->sz - 64;
crypto->xchacha20(buf, frame->sessionkey, nonce);
return frame->success;
}
bool
iwp_encrypt_frame(struct iwp_async_frame *frame)
{
auto crypto = frame->iwp->crypto;
byte_t *hmac = frame->buf;
byte_t *nonce = frame->buf + 32;
byte_t *body = frame->buf + 64;
llarp_buffer_t buf;
buf.base = body;
buf.cur = buf.base;
buf.sz = frame->sz - 64;
// randomize N
crypto->randbytes(nonce, 32);
// x = SE(S, p, n[0:24])
crypto->xchacha20(buf, frame->sessionkey, nonce);
// h = MDS(n + x, S)
buf.base = nonce;
buf.cur = buf.base;
buf.sz = frame->sz - 32;
crypto->hmac(hmac, buf, frame->sessionkey);
return true;
}
void void
iwp_call_async_gen_intro(struct llarp_async_iwp *iwp, iwp_call_async_gen_intro(struct llarp_async_iwp *iwp,
struct iwp_async_intro *intro) struct iwp_async_intro *intro)

@ -81,14 +81,6 @@ namespace llarp
namespace dht namespace dht
{ {
Key_t ZeroKey;
bool
Key_t::IsZero() const
{
return memcmp(l, ZeroKey.l, 32) == 0;
}
GotRouterMessage::~GotRouterMessage() GotRouterMessage::~GotRouterMessage()
{ {
for(auto &rc : R) for(auto &rc : R)

@ -3,8 +3,8 @@
namespace llarp namespace llarp
{ {
int
int char2int(char input) char2int(char input)
{ {
if(input >= '0' && input <= '9') if(input >= '0' && input <= '9')
return input - '0'; return input - '0';
@ -15,13 +15,13 @@ namespace llarp
throw std::invalid_argument("Invalid input string"); throw std::invalid_argument("Invalid input string");
} }
void HexDecode(const char* src, uint8_t* target) void
HexDecode(const char* src, uint8_t* target)
{ {
while(*src && src[1]) while(*src && src[1])
{ {
*(target++) = char2int(*src)*16 + char2int(src[1]); *(target++) = char2int(*src) * 16 + char2int(src[1]);
src += 2; src += 2;
} }
} }
} }

@ -4,6 +4,7 @@
#include <llarp/time.h> #include <llarp/time.h>
#include <llarp/crypto.hpp> #include <llarp/crypto.hpp>
#include "address_info.hpp" #include "address_info.hpp"
#include "codel.hpp"
#include "link/encoder.hpp" #include "link/encoder.hpp"
#include <sodium/crypto_sign_ed25519.h> #include <sodium/crypto_sign_ed25519.h>
@ -657,6 +658,16 @@ namespace iwp
} }
}; };
/// get the time from a iwp_async_frame
struct FrameGetTime
{
llarp_time_t
operator()(const iwp_async_frame &frame) const
{
return frame.created;
}
};
struct session struct session
{ {
llarp_udp_io *udp; llarp_udp_io *udp;
@ -676,9 +687,22 @@ namespace iwp
llarp_link_establish_job *establish_job = nullptr; llarp_link_establish_job *establish_job = nullptr;
/// cached timestamp for frame creation
llarp_time_t now;
uint32_t establish_job_id = 0; uint32_t establish_job_id = 0;
uint32_t frames = 0; uint32_t frames = 0;
bool working = false; bool working = false;
llarp::util::CoDelQueue< iwp_async_frame, FrameGetTime > inboundFrames;
llarp::util::CoDelQueue< iwp_async_frame, FrameGetTime > outboundFrames;
std::mutex m_DecryptedFramesMutex;
std::queue< iwp_async_frame > decryptedFrames;
std::mutex m_EncryptedFramesMutex;
std::queue< iwp_async_frame > encryptedFrames;
uint32_t pump_send_timer_id = 0;
uint32_t pump_recv_timer_id = 0;
llarp::Addr addr; llarp::Addr addr;
iwp_async_intro intro; iwp_async_intro intro;
iwp_async_introack introack; iwp_async_introack introack;
@ -770,21 +794,50 @@ namespace iwp
return false; return false;
} }
static void
handle_codel_inbound_pump(void *u, uint64_t orig, uint64_t left);
static void
handle_codel_outbound_pump(void *u, uint64_t orig, uint64_t left);
void
PumpCrypto();
void
PumpCodelInbound()
{
pump_recv_timer_id = llarp_logic_call_later(
logic,
{inboundFrames.nextTickInterval, this, &handle_codel_inbound_pump});
}
void
PumpCodelOutbound()
{
pump_send_timer_id = llarp_logic_call_later(
logic,
{outboundFrames.nextTickInterval, this, &handle_codel_outbound_pump});
}
void void
pump() pump()
{ {
// TODO: in codel the timestamp may cause excssive drop when all the
// packets have a similar timestamp
now = llarp_time_now_ms();
llarp_buffer_t buf; llarp_buffer_t buf;
while(frame.next_frame(&buf)) while(frame.next_frame(&buf))
{ {
encrypt_frame_async_send(buf.base, buf.sz); encrypt_frame_async_send(buf.base, buf.sz);
frame.pop_next_frame(); frame.pop_next_frame();
} }
PumpCrypto();
} }
// this is called from net thread // this is called from net thread
void void
recv(const void *buf, size_t sz) recv(const void *buf, size_t sz)
{ {
now = llarp_time_now_ms();
switch(state) switch(state)
{ {
case eInitial: case eInitial:
@ -832,9 +885,11 @@ namespace iwp
crypto->shorthash(digest, buf); crypto->shorthash(digest, buf);
auto id = frame.txids++; auto id = frame.txids++;
auto msg = new transit_message(buf, digest, id); auto msg = new transit_message(buf, digest, id);
// enter state
EnterState(eLIMSent);
// put into outbound send queue // put into outbound send queue
add_outbound_message(id, msg); add_outbound_message(id, msg);
EnterState(eLIMSent);
} }
else else
llarp::Error("LIM Encode failed"); llarp::Error("LIM Encode failed");
@ -845,43 +900,10 @@ namespace iwp
// return true if we should be removed // return true if we should be removed
bool bool
Tick(uint64_t now) Tick(uint64_t now);
{
if(timedout(now, SESSION_TIMEOUT))
{
// we are timed out
// 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())
{
// both sides agreeed to session invalidation
// terminate our session when all of our frames from the crypto workers
// 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 static void
if(state == eEstablished) codel_timer_handler(void *user, uint64_t orig, uint64_t left);
{
frame.retransmit();
pump();
}
// TODO: determine if we are too idle
return false;
}
bool bool
IsEstablished() IsEstablished()
@ -1001,13 +1023,11 @@ namespace iwp
{ {
session *self = static_cast< session * >(frame->user); session *self = static_cast< session * >(frame->user);
llarp::Debug("rx ", frame->sz, " frames=", self->frames); llarp::Debug("rx ", frame->sz, " frames=", self->frames);
self->frames--;
if(frame->success) if(frame->success)
{ {
if(self->frame.process(frame->buf + 64, frame->sz - 64)) if(self->frame.process(frame->buf + 64, frame->sz - 64))
{ {
self->frame.alive(); self->frame.alive();
self->pump();
} }
else else
llarp::Error("invalid frame from ", self->addr); llarp::Error("invalid frame from ", self->addr);
@ -1021,14 +1041,38 @@ namespace iwp
{ {
if(sz > 64) if(sz > 64)
{ {
iwp_async_frame *frame = alloc_frame(buf, sz); alloc_frame(inboundFrames, buf, sz);
frame->hook = &handle_frame_decrypt;
iwp_call_async_frame_decrypt(iwp, frame);
} }
else else
llarp::Warn("short packet of ", sz, " bytes"); llarp::Warn("short packet of ", sz, " bytes");
} }
static void
handle_crypto_pump(void *u);
void
DecryptInboundFrames()
{
std::queue< iwp_async_frame > outq;
std::queue< iwp_async_frame > inq;
inboundFrames.Process(inq);
while(inq.size())
{
auto &front = inq.front();
if(iwp_decrypt_frame(&front))
outq.push(front);
inq.pop();
}
{
std::unique_lock< std::mutex > lock(m_DecryptedFramesMutex);
while(outq.size())
{
decryptedFrames.push(outq.front());
outq.pop();
}
}
}
static void static void
handle_frame_encrypt(iwp_async_frame *frame) handle_frame_encrypt(iwp_async_frame *frame)
{ {
@ -1037,23 +1081,26 @@ namespace iwp
if(llarp_ev_udp_sendto(self->udp, self->addr, frame->buf, frame->sz) if(llarp_ev_udp_sendto(self->udp, self->addr, frame->buf, frame->sz)
== -1) == -1)
llarp::Warn("sendto failed"); llarp::Warn("sendto failed");
self->frames--;
} }
template < typename Queue >
iwp_async_frame * iwp_async_frame *
alloc_frame(const void *buf, size_t sz) alloc_frame(Queue &q, const void *buf, size_t sz)
{ {
// TODO don't hard code 1500 // TODO don't hard code 1500
if(sz > 1500) if(sz > 1500)
return nullptr; return nullptr;
iwp_async_frame *frame = new iwp_async_frame(); iwp_async_frame *frame = new iwp_async_frame;
if(buf) if(buf)
memcpy(frame->buf, buf, sz); memcpy(frame->buf, buf, sz);
frame->iwp = iwp;
frame->sz = sz; frame->sz = sz;
frame->user = this; frame->user = this;
frame->sessionkey = sessionkey; frame->sessionkey = sessionkey;
frames++; /// TODO: this could be rather slow
frame->created = now;
q.Put(frame);
return frame; return frame;
} }
@ -1061,14 +1108,35 @@ namespace iwp
encrypt_frame_async_send(const void *buf, size_t sz) encrypt_frame_async_send(const void *buf, size_t sz)
{ {
// 64 bytes frame overhead for nonce and hmac // 64 bytes frame overhead for nonce and hmac
iwp_async_frame *frame = alloc_frame(nullptr, sz + 64); iwp_async_frame *frame = alloc_frame(outboundFrames, nullptr, sz + 64);
memcpy(frame->buf + 64, buf, sz); memcpy(frame->buf + 64, buf, sz);
auto padding = rand() % MAX_PAD; auto padding = rand() % MAX_PAD;
if(padding) if(padding)
crypto->randbytes(frame->buf + 64 + sz, padding); crypto->randbytes(frame->buf + 64 + sz, padding);
frame->sz += padding; frame->sz += padding;
frame->hook = &handle_frame_encrypt; }
iwp_call_async_frame_encrypt(iwp, frame);
void
EncryptOutboundFrames()
{
std::queue< iwp_async_frame > q;
std::queue< iwp_async_frame > outq;
outboundFrames.Process(outq);
while(outq.size())
{
auto &front = outq.front();
if(iwp_encrypt_frame(&front))
q.push(front);
outq.pop();
}
{
std::unique_lock< std::mutex > lock(m_EncryptedFramesMutex);
while(q.size())
{
encryptedFrames.push(q.front());
q.pop();
}
}
} }
static void static void
@ -1203,6 +1271,11 @@ namespace iwp
{ {
frame.alive(); frame.alive();
state = st; state = st;
if(state == eLIMSent || state == eSessionStartSent)
{
PumpCodelInbound();
PumpCodelOutbound();
}
} }
}; };
@ -1216,13 +1289,14 @@ namespace iwp
llarp_crypto *crypto; llarp_crypto *crypto;
llarp_ev_loop *netloop; llarp_ev_loop *netloop;
llarp_async_iwp *iwp; llarp_async_iwp *iwp;
llarp_threadpool *worker;
llarp_link *parent = nullptr; llarp_link *parent = nullptr;
llarp_udp_io udp; llarp_udp_io udp;
llarp::Addr addr; llarp::Addr addr;
char keyfile[255]; char keyfile[255];
uint32_t timeout_job_id; uint32_t timeout_job_id;
typedef std::unordered_map< llarp::Addr, llarp_link_session, typedef std::unordered_map< llarp::Addr, llarp_link_session *,
llarp::addrhash > llarp::addrhash >
LinkMap_t; LinkMap_t;
@ -1243,6 +1317,7 @@ namespace iwp
router = r; router = r;
crypto = c; crypto = c;
logic = l; logic = l;
worker = w;
iwp = llarp_async_iwp_new(crypto, logic, w); iwp = llarp_async_iwp_new(crypto, logic, w);
} }
@ -1277,7 +1352,7 @@ namespace iwp
std::set< llarp::Addr > remove; std::set< llarp::Addr > remove;
for(auto &itr : m_sessions) for(auto &itr : m_sessions)
{ {
session *s = static_cast< session * >(itr.second.impl); session *s = static_cast< session * >(itr.second->impl);
if(s && s->Tick(now)) if(s && s->Tick(now))
remove.insert(itr.first); remove.insert(itr.first);
} }
@ -1300,7 +1375,7 @@ namespace iwp
auto inner_itr = serv->m_sessions.find(itr->second); auto inner_itr = serv->m_sessions.find(itr->second);
if(inner_itr != serv->m_sessions.end()) if(inner_itr != serv->m_sessions.end())
{ {
llarp_link_session *link = &inner_itr->second; llarp_link_session *link = inner_itr->second;
return link->sendto(link, buf); return link->sendto(link, buf);
} }
} }
@ -1350,28 +1425,28 @@ namespace iwp
if(itr == m_sessions.end()) if(itr == m_sessions.end())
return nullptr; return nullptr;
else else
return static_cast< session * >(itr->second.impl); return static_cast< session * >(itr->second->impl);
} }
void void
put_session(const llarp::Addr &src, session *impl) put_session(const llarp::Addr &src, session *impl)
{ {
llarp_link_session s = {}; llarp_link_session *s = new llarp_link_session;
s.impl = impl; s->impl = impl;
s.sendto = &session::sendto; s->sendto = &session::sendto;
s.timeout = &session::is_timedout; s->timeout = &session::is_timedout;
s.close = &session::close; s->close = &session::close;
s.get_remote_router = &session::get_remote_router; s->get_remote_router = &session::get_remote_router;
s.established = &session::set_established; s->established = &session::set_established;
s.get_parent = &session::get_parent; s->get_parent = &session::get_parent;
{ {
lock_t lock(m_sessions_Mutex); lock_t lock(m_sessions_Mutex);
m_sessions[src] = s; m_sessions.emplace(src, s);
impl->parent = &m_sessions[src]; impl->parent = m_sessions[src];
impl->frame.router = router;
impl->frame.parent = impl->parent;
impl->our_router = &router->rc;
} }
impl->frame.router = router;
impl->frame.parent = impl->parent;
impl->our_router = &router->rc;
} }
void void
@ -1381,8 +1456,9 @@ namespace iwp
auto itr = m_sessions.begin(); auto itr = m_sessions.begin();
while(itr != m_sessions.end()) while(itr != m_sessions.end())
{ {
session *s = static_cast< session * >(itr->second.impl); session *s = static_cast< session * >(itr->second->impl);
delete s; delete s;
delete itr->second;
itr = m_sessions.erase(itr); itr = m_sessions.erase(itr);
} }
} }
@ -1395,17 +1471,11 @@ namespace iwp
{ {
llarp::Debug("removing session ", addr); llarp::Debug("removing session ", addr);
UnmapAddr(addr); UnmapAddr(addr);
session *s = static_cast< session * >(itr->second.impl); session *s = static_cast< session * >(itr->second->impl);
s->done(); s->done();
m_sessions.erase(addr); delete itr->second;
if(s->frames) m_sessions.erase(itr);
{ delete s;
llarp::Warn("session has ", s->frames,
" left but is idle, not deallocating session so we "
"leak but don't die");
}
else
delete s;
} }
} }
@ -1556,7 +1626,6 @@ namespace iwp
{ {
llarp::Error("intro verify failed from ", self->addr, " via ", llarp::Error("intro verify failed from ", self->addr, " via ",
self->serv->addr); self->serv->addr);
delete self;
return; return;
} }
self->intro_ack(); self->intro_ack();
@ -1575,11 +1644,20 @@ namespace iwp
void void
session::done() session::done()
{ {
auto logic = serv->logic;
if(establish_job_id) if(establish_job_id)
{ {
llarp_logic_remove_call(logic, establish_job_id); llarp_logic_remove_call(logic, establish_job_id);
handle_establish_timeout(this, 0, 0); handle_establish_timeout(this, 0, 0);
} }
if(pump_recv_timer_id)
{
llarp_logic_remove_call(logic, pump_recv_timer_id);
}
if(pump_send_timer_id)
{
llarp_logic_remove_call(logic, pump_send_timer_id);
}
} }
void void
@ -1624,7 +1702,8 @@ namespace iwp
frame_header hdr(tmp); frame_header hdr(tmp);
hdr.flags() = self->frame.txflags; hdr.flags() = self->frame.txflags;
// send frame after encrypting // send frame after encrypting
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp); auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
self->now = llarp_time_now_ms();
self->encrypt_frame_async_send(buf.base, buf.sz); self->encrypt_frame_async_send(buf.base, buf.sz);
} }
@ -1663,7 +1742,6 @@ namespace iwp
if(msg->completed()) if(msg->completed())
{ {
llarp::Debug("message transmitted msgid=", msgid); llarp::Debug("message transmitted msgid=", msgid);
session *impl = static_cast< session * >(parent->impl);
tx.erase(msgid); tx.erase(msgid);
delete msg; delete msg;
} }
@ -1699,6 +1777,97 @@ namespace iwp
link->session_start(); link->session_start();
} }
bool
session::Tick(llarp_time_t now)
{
if(timedout(now, SESSION_TIMEOUT))
{
// we are timed out
// 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 !working;
}
if(is_invalidated())
{
// both sides agreeed to session invalidation
// terminate our session when all of our frames from the crypto workers
// are done
llarp::Debug(addr, " invaldiated session with ", frames, " frames left");
return !working;
}
// send keepalive if we are established or a session is made
if(state == eEstablished || state == eLIMSent)
send_keepalive(this);
// pump frame state
if(state == eEstablished)
{
frame.retransmit();
pump();
}
// TODO: determine if we are too idle
return false;
}
void
session::handle_codel_outbound_pump(void *u, uint64_t orig, uint64_t left)
{
if(left)
return;
session *self = static_cast< session * >(u);
self->pump_send_timer_id = 0;
if(self->timedout(llarp_time_now_ms()))
return;
{
std::unique_lock< std::mutex > lock(self->m_EncryptedFramesMutex);
while(self->encryptedFrames.size())
{
auto &front = self->encryptedFrames.front();
handle_frame_encrypt(&front);
self->encryptedFrames.pop();
}
}
self->PumpCodelOutbound();
self->PumpCrypto();
}
void
session::handle_codel_inbound_pump(void *u, uint64_t orig, uint64_t left)
{
if(left)
return;
session *self = static_cast< session * >(u);
self->pump_recv_timer_id = 0;
if(self->timedout(llarp_time_now_ms()))
return;
{
std::unique_lock< std::mutex > lock(self->m_DecryptedFramesMutex);
while(self->decryptedFrames.size())
{
auto &front = self->decryptedFrames.front();
handle_frame_decrypt(&front);
self->decryptedFrames.pop();
}
}
self->PumpCodelInbound();
self->PumpCrypto();
}
void
session::PumpCrypto()
{
llarp_threadpool_queue_job(serv->worker, {this, &handle_crypto_pump});
}
void
session::handle_crypto_pump(void *u)
{
session *self = static_cast< session * >(u);
self->EncryptOutboundFrames();
self->DecryptInboundFrames();
}
void void
session::handle_verify_session_start(iwp_async_session_start *s) session::handle_verify_session_start(iwp_async_session_start *s)
{ {
@ -1829,7 +1998,7 @@ namespace iwp
link->timeout_job_id = 0; link->timeout_job_id = 0;
link->logic = logic; link->logic = logic;
// start cleanup timer // start cleanup timer
link->issue_cleanup_timer(2500); link->issue_cleanup_timer(1000);
return true; return true;
} }
@ -1854,8 +2023,8 @@ namespace iwp
iter.link = l; iter.link = l;
// TODO: race condition with cleanup timer // TODO: race condition with cleanup timer
for(auto &item : link->m_sessions) for(auto &item : link->m_sessions)
if(item.second.impl) if(item.second->impl)
if(!iter.visit(&iter, &item.second)) if(!iter.visit(&iter, item.second))
return; return;
} }
} }
@ -1933,6 +2102,7 @@ namespace iwp
delete link; delete link;
return; return;
} }
link->frame.alive();
link->serv->put_session(link->addr, link); link->serv->put_session(link->addr, link);
llarp::Debug("send introack to ", link->addr, " via ", link->serv->addr); llarp::Debug("send introack to ", link->addr, " via ", link->serv->addr);
if(llarp_ev_udp_sendto(link->udp, link->addr, i->buf, i->sz) == -1) if(llarp_ev_udp_sendto(link->udp, link->addr, i->buf, i->sz) == -1)

@ -47,23 +47,23 @@ struct llarp_nodedb
return entries.find(pk) != entries.end(); return entries.find(pk) != entries.end();
} }
/* /*
bool bool
Has(const byte_t *pk) Has(const byte_t *pk)
{
llarp::PubKey test(pk);
auto itr = this->entries.begin();
while(itr != this->entries.end())
{ {
llarp::Info("Has byte_t [", test.size(), "] vs [", itr->first.size(), "]"); llarp::PubKey test(pk);
if (memcmp(test.data(), itr->first.data(), 32) == 0) { auto itr = this->entries.begin();
llarp::Info("Match"); while(itr != this->entries.end())
{
llarp::Info("Has byte_t [", test.size(), "] vs [", itr->first.size(),
"]"); if (memcmp(test.data(), itr->first.data(), 32) == 0) {
llarp::Info("Match");
}
itr++;
} }
itr++; return entries.find(pk) != entries.end();
} }
return entries.find(pk) != entries.end(); */
}
*/
bool bool
pubKeyExists(llarp_rc *rc) pubKeyExists(llarp_rc *rc)
@ -185,7 +185,7 @@ struct llarp_nodedb
auto itr = i.begin(); auto itr = i.begin();
while(itr != itr.end()) while(itr != itr.end())
{ {
if (fs::is_regular_file(itr->symlink_status()) && loadfile(*itr)) if(fs::is_regular_file(itr->symlink_status()) && loadfile(*itr))
sz++; sz++;
++itr; ++itr;
@ -198,12 +198,13 @@ struct llarp_nodedb
{ {
#if __APPLE__ && __MACH__ #if __APPLE__ && __MACH__
// skip .DS_Store files // skip .DS_Store files
if (strstr(fpath.c_str(), ".DS_Store") != 0) { if(strstr(fpath.c_str(), ".DS_Store") != 0)
{
return false; return false;
} }
#endif #endif
llarp_rc *rc = llarp_rc_read(fpath.c_str()); llarp_rc *rc = llarp_rc_read(fpath.c_str());
if (!rc) if(!rc)
{ {
llarp::Error("Signature read failed", fpath); llarp::Error("Signature read failed", fpath);
return false; return false;
@ -218,8 +219,10 @@ struct llarp_nodedb
return true; return true;
} }
bool iterate(struct llarp_nodedb_iter i) { bool
i.index = 0; iterate(struct llarp_nodedb_iter i)
{
i.index = 0;
auto itr = entries.begin(); auto itr = entries.begin();
while(itr != entries.end()) while(itr != entries.end())
{ {
@ -372,12 +375,14 @@ llarp_nodedb_load_dir(struct llarp_nodedb *n, const char *dir)
} }
bool bool
llarp_nodedb_put_rc(struct llarp_nodedb *n, struct llarp_rc *rc) { llarp_nodedb_put_rc(struct llarp_nodedb *n, struct llarp_rc *rc)
{
return n->setRC(rc); return n->setRC(rc);
} }
int int
llarp_nodedb_iterate_all(struct llarp_nodedb *n, struct llarp_nodedb_iter i) { llarp_nodedb_iterate_all(struct llarp_nodedb *n, struct llarp_nodedb_iter i)
{
n->iterate(i); n->iterate(i);
return n->entries.size(); return n->entries.size();
} }
@ -401,7 +406,7 @@ llarp_nodedb_async_load_rc(struct llarp_async_load_rc *job)
struct llarp_rc * struct llarp_rc *
llarp_nodedb_get_rc(struct llarp_nodedb *n, const byte_t *pk) llarp_nodedb_get_rc(struct llarp_nodedb *n, const byte_t *pk)
{ {
//llarp::Info("llarp_nodedb_get_rc [", pk, "]"); // llarp::Info("llarp_nodedb_get_rc [", pk, "]");
if(n->Has(pk)) if(n->Has(pk))
return n->getRC(pk); return n->getRC(pk);
else else

@ -2,312 +2,403 @@
#include <llarp/encrypted_frame.hpp> #include <llarp/encrypted_frame.hpp>
#include <llarp/path.hpp> #include <llarp/path.hpp>
#include "buffer.hpp" #include "buffer.hpp"
#include "pathbuilder.hpp"
#include "router.hpp" #include "router.hpp"
namespace llarp namespace llarp
{ {
PathContext::PathContext(llarp_router* router) namespace path
: m_Router(router), m_AllowTransit(false)
{ {
} PathContext::PathContext(llarp_router* router)
: m_Router(router), m_AllowTransit(false)
{
}
PathContext::~PathContext() PathContext::~PathContext()
{ {
} }
void void
PathContext::AllowTransit() PathContext::AllowTransit()
{ {
m_AllowTransit = true; m_AllowTransit = true;
} }
bool bool
PathContext::AllowingTransit() const PathContext::AllowingTransit() const
{ {
return m_AllowTransit; return m_AllowTransit;
} }
llarp_threadpool* llarp_threadpool*
PathContext::Worker() PathContext::Worker()
{ {
return m_Router->tp; return m_Router->tp;
} }
llarp_crypto* llarp_crypto*
PathContext::Crypto() PathContext::Crypto()
{ {
return &m_Router->crypto; return &m_Router->crypto;
} }
llarp_logic* llarp_logic*
PathContext::Logic() PathContext::Logic()
{ {
return m_Router->logic; return m_Router->logic;
} }
byte_t* byte_t*
PathContext::EncryptionSecretKey() PathContext::EncryptionSecretKey()
{ {
return m_Router->encryption; return m_Router->encryption;
} }
bool bool
PathContext::HopIsUs(const PubKey& k) const PathContext::HopIsUs(const PubKey& k) const
{ {
return memcmp(k, m_Router->pubkey(), PUBKEYSIZE) == 0; return memcmp(k, m_Router->pubkey(), PUBKEYSIZE) == 0;
} }
bool bool
PathContext::ForwardLRCM(const RouterID& nextHop, PathContext::ForwardLRCM(const RouterID& nextHop,
std::deque< EncryptedFrame >& frames) std::deque< EncryptedFrame >& frames)
{ {
llarp::Info("fowarding LRCM to ", nextHop); llarp::Info("fowarding LRCM to ", nextHop);
LR_CommitMessage* msg = new LR_CommitMessage; LR_CommitMessage* msg = new LR_CommitMessage;
while(frames.size()) while(frames.size())
{ {
msg->frames.push_back(frames.front()); msg->frames.push_back(frames.front());
frames.pop_front(); frames.pop_front();
} }
return m_Router->SendToOrQueue(nextHop, msg); return m_Router->SendToOrQueue(nextHop, msg);
} }
template < typename Map_t, typename Key_t, typename CheckValue_t > template < typename Map_t, typename Key_t, typename CheckValue_t,
IHopHandler* typename GetFunc_t >
MapGet(Map_t& map, const Key_t& k, CheckValue_t check) IHopHandler*
{ MapGet(Map_t& map, const Key_t& k, CheckValue_t check, GetFunc_t get)
std::unique_lock< std::mutex > lock(map.first);
auto range = map.second.equal_range(k);
for(auto i = range.first; i != range.second; ++i)
{ {
if(check(i->second)) std::unique_lock< std::mutex > lock(map.first);
return i->second; auto range = map.second.equal_range(k);
for(auto i = range.first; i != range.second; ++i)
{
if(check(i->second))
return get(i->second);
}
return nullptr;
} }
return nullptr;
}
template < typename Map_t, typename Key_t, typename CheckValue_t > template < typename Map_t, typename Key_t, typename CheckValue_t >
bool bool
MapHas(Map_t& map, const Key_t& k, CheckValue_t check) MapHas(Map_t& map, const Key_t& k, CheckValue_t check)
{
std::unique_lock< std::mutex > lock(map.first);
auto range = map.second.equal_range(k);
for(auto i = range.first; i != range.second; ++i)
{ {
if(check(i->second)) std::unique_lock< std::mutex > lock(map.first);
return true; auto range = map.second.equal_range(k);
for(auto i = range.first; i != range.second; ++i)
{
if(check(i->second))
return true;
}
return false;
} }
return false;
}
template < typename Map_t, typename Key_t, typename Value_t > template < typename Map_t, typename Key_t, typename Value_t >
void void
MapPut(Map_t& map, const Key_t& k, const Value_t& v) MapPut(Map_t& map, const Key_t& k, const Value_t& v)
{ {
std::unique_lock< std::mutex > lock(map.first); std::unique_lock< std::mutex > lock(map.first);
map.second.emplace(k, v); map.second.emplace(k, v);
} }
template < typename Map_t, typename Visit_t > template < typename Map_t, typename Visit_t >
void void
MapIter(Map_t& map, Visit_t v) MapIter(Map_t& map, Visit_t v)
{
std::unique_lock< std::mutex > lock(map.first);
for(const auto& item : map.second)
v(item);
}
template < typename Map_t, typename Key_t, typename Check_t >
void
MapDel(Map_t& map, const Key_t& k, Check_t check)
{
std::unique_lock< std::mutex > lock(map.first);
auto range = map.second.equal_range(k);
for(auto i = range.first; i != range.second;)
{ {
if(check(i->second)) std::unique_lock< std::mutex > lock(map.first);
i = map.second.erase(i); for(const auto& item : map.second)
else v(item);
++i;
} }
}
void template < typename Map_t, typename Key_t, typename Check_t >
PathContext::AddOwnPath(Path* path) void
{ MapDel(Map_t& map, const Key_t& k, Check_t check)
MapPut(m_OurPaths, path->TXID(), path); {
MapPut(m_OurPaths, path->RXID(), path); std::unique_lock< std::mutex > lock(map.first);
} auto range = map.second.equal_range(k);
for(auto i = range.first; i != range.second;)
{
if(check(i->second))
i = map.second.erase(i);
else
++i;
}
}
bool void
PathContext::HasTransitHop(const TransitHopInfo& info) PathContext::AddOwnPath(PathSet* set, Path* path)
{ {
return MapHas(m_TransitPaths, info.txID, [info](TransitHop* hop) -> bool { set->AddPath(path);
return info == hop->info; MapPut(m_OurPaths, path->TXID(), set);
}); MapPut(m_OurPaths, path->RXID(), set);
} }
IHopHandler* bool
PathContext::GetByUpstream(const RouterID& remote, const PathID_t& id) PathContext::HasTransitHop(const TransitHopInfo& info)
{ {
auto own = MapGet(m_OurPaths, id, [remote](const Path* p) -> bool { return MapHas(m_TransitPaths, info.txID, [info](TransitHop* hop) -> bool {
return p->Upstream() == remote; return info == hop->info;
}); });
if(own) }
return own;
return MapGet(m_TransitPaths, id, [remote](const TransitHop* hop) -> bool {
return hop->info.upstream == remote;
});
}
IHopHandler*
PathContext::GetByDownstream(const RouterID& remote, const PathID_t& id)
{
return MapGet(m_TransitPaths, id, [remote](const TransitHop* hop) -> bool {
return hop->info.downstream == remote;
});
}
const byte_t* IHopHandler*
PathContext::OurRouterID() const PathContext::GetByUpstream(const RouterID& remote, const PathID_t& id)
{ {
return m_Router->pubkey(); auto own = MapGet(m_OurPaths, id,
} [](const PathSet* s) -> bool {
// TODO: is this right?
return true;
},
[remote, id](PathSet* p) -> IHopHandler* {
return p->GetByUpstream(remote, id);
});
if(own)
return own;
return MapGet(m_TransitPaths, id,
[remote](const TransitHop* hop) -> bool {
return hop->info.upstream == remote;
},
[](TransitHop* h) -> IHopHandler* { return h; });
}
llarp_router* IHopHandler*
PathContext::Router() PathContext::GetByDownstream(const RouterID& remote, const PathID_t& id)
{ {
return m_Router; return MapGet(m_TransitPaths, id,
} [remote](const TransitHop* hop) -> bool {
return hop->info.downstream == remote;
},
[](TransitHop* h) -> IHopHandler* { return h; });
}
void const byte_t*
PathContext::PutTransitHop(TransitHop* hop) PathContext::OurRouterID() const
{ {
MapPut(m_TransitPaths, hop->info.txID, hop); return m_Router->pubkey();
MapPut(m_TransitPaths, hop->info.rxID, hop); }
}
void llarp_router*
PathContext::ExpirePaths() PathContext::Router()
{ {
std::unique_lock< std::mutex > lock(m_TransitPaths.first); return m_Router;
auto now = llarp_time_now_ms(); }
auto& map = m_TransitPaths.second;
auto itr = map.begin(); void
std::set< TransitHop* > removePaths; PathContext::PutTransitHop(TransitHop* hop)
while(itr != map.end()) {
{ MapPut(m_TransitPaths, hop->info.txID, hop);
if(itr->second->Expired(now)) MapPut(m_TransitPaths, hop->info.rxID, hop);
}
void
PathContext::ExpirePaths()
{
std::unique_lock< std::mutex > lock(m_TransitPaths.first);
auto now = llarp_time_now_ms();
auto& map = m_TransitPaths.second;
auto itr = map.begin();
std::set< TransitHop* > removePaths;
while(itr != map.end())
{
if(itr->second->Expired(now))
{
TransitHop* path = itr->second;
llarp::Info("transit path expired ", path);
removePaths.insert(path);
}
++itr;
}
for(auto& p : removePaths)
{
map.erase(p->info.txID);
map.erase(p->info.rxID);
delete p;
}
for(auto& builder : m_PathBuilders)
{ {
TransitHop* path = itr->second; builder->ExpirePaths(now);
llarp::Info("transit path expired ", path);
removePaths.insert(path);
} }
++itr;
} }
for(auto& p : removePaths)
void
PathContext::BuildPaths()
{ {
map.erase(p->info.txID); for(auto& builder : m_PathBuilders)
map.erase(p->info.rxID); {
delete p; if(builder->ShouldBuildMore())
{
builder->BuildOne();
}
}
} }
}
Path::Path(llarp_path_hops* h) : hops(h->numHops) void
{ PathContext::AddPathBuilder(llarp_pathbuilder_context* ctx)
for(size_t idx = 0; idx < h->numHops; ++idx)
{ {
llarp_rc_copy(&hops[idx].router, &h->hops[idx].router); m_PathBuilders.push_back(ctx);
hops[idx].txID.Randomize();
hops[idx].rxID.Randomize();
} }
for(size_t idx = (h->numHops - 1); idx > 0; --idx)
PathHopConfig::PathHopConfig()
{ {
hops[idx].txID = hops[idx - 1].rxID; llarp_rc_clear(&router);
} }
}
const PathID_t& PathHopConfig::~PathHopConfig()
Path::TXID() const {
{ llarp_rc_free(&router);
return hops[0].txID; }
}
const PathID_t& Path::Path(llarp_path_hops* h) : hops(h->numHops)
Path::RXID() const {
{ for(size_t idx = 0; idx < h->numHops; ++idx)
return hops[0].rxID; {
} llarp_rc_copy(&hops[idx].router, &h->hops[idx].router);
hops[idx].txID.Randomize();
hops[idx].rxID.Randomize();
}
for(size_t idx = (h->numHops - 1); idx > 0; --idx)
{
hops[idx].txID = hops[idx - 1].rxID;
}
}
RouterID void
Path::Upstream() const Path::SetBuildResultHook(BuildResultHookFunc func)
{ {
return hops[0].router.pubkey; m_BuiltHook = func;
} }
bool const PathID_t&
Path::HandleUpstream(llarp_buffer_t buf, const TunnelNonce& Y, Path::TXID() const
llarp_router* r)
{
for(const auto& hop : hops)
{ {
r->crypto.xchacha20(buf, hop.shared, Y); return hops[0].txID;
} }
RelayUpstreamMessage* msg = new RelayUpstreamMessage;
msg->X = buf;
msg->Y = Y;
msg->pathid = TXID();
return r->SendToOrQueue(Upstream(), msg);
}
bool const PathID_t&
Path::Expired(llarp_time_t now) const Path::RXID() const
{ {
return now - buildStarted > hops[0].lifetime; return hops[0].rxID;
} }
bool RouterID
Path::HandleDownstream(llarp_buffer_t buf, const TunnelNonce& Y, Path::Upstream() const
{
return hops[0].router.pubkey;
}
bool
Path::HandleUpstream(llarp_buffer_t buf, const TunnelNonce& Y,
llarp_router* r) llarp_router* r)
{
for(const auto& hop : hops)
{ {
r->crypto.xchacha20(buf, hop.shared, Y); for(const auto& hop : hops)
{
r->crypto.xchacha20(buf, hop.shared, Y);
}
RelayUpstreamMessage* msg = new RelayUpstreamMessage;
msg->X = buf;
msg->Y = Y;
msg->pathid = TXID();
return r->SendToOrQueue(Upstream(), msg);
} }
return HandleRoutingMessage(buf, r);
}
bool bool
Path::HandleHiddenServiceData(llarp_buffer_t buf) Path::Expired(llarp_time_t now) const
{ {
// TODO: implement me if(status == ePathEstablished)
return false; return now - buildStarted > hops[0].lifetime;
} else if(status == ePathBuilding)
return now - buildStarted > PATH_BUILD_TIMEOUT;
else
return true;
}
bool bool
Path::HandleRoutingMessage(llarp_buffer_t buf, llarp_router* r) Path::HandleDownstream(llarp_buffer_t buf, const TunnelNonce& Y,
{ llarp_router* r)
if(!m_InboundMessageParser.ParseMessageBuffer(buf, this))
{ {
llarp::Warn("Failed to parse inbound routing message"); for(const auto& hop : hops)
{
r->crypto.xchacha20(buf, hop.shared, Y);
}
return HandleRoutingMessage(buf, r);
}
bool
Path::HandleHiddenServiceData(llarp_buffer_t buf)
{
// TODO: implement me
return false; return false;
} }
return true;
}
bool bool
Path::SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r) Path::HandleRoutingMessage(llarp_buffer_t buf, llarp_router* r)
{ {
byte_t tmp[MAX_LINK_MSG_SIZE / 2]; if(!m_InboundMessageParser.ParseMessageBuffer(buf, this))
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp); {
if(!msg->BEncode(&buf)) llarp::Warn("Failed to parse inbound routing message");
return false;
}
return true;
}
bool
Path::SendRoutingMessage(const llarp::routing::IMessage* msg,
llarp_router* r)
{
byte_t tmp[MAX_LINK_MSG_SIZE / 2];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!msg->BEncode(&buf))
return false;
// rewind
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// make nonce
TunnelNonce N;
N.Randomize();
return HandleUpstream(buf, N, r);
}
bool
Path::HandlePathConfirmMessage(
const llarp::routing::PathConfirmMessage* msg)
{
if(status == ePathBuilding)
{
// confirm that we build the path
status = ePathEstablished;
if(m_BuiltHook)
m_BuiltHook(this);
m_BuiltHook = nullptr;
return true;
}
llarp::Warn("got unwarrented path confirm message on rx=", RXID(),
" tx=", TXID());
return false; return false;
// rewind }
buf.sz = buf.cur - buf.base;
buf.cur = buf.base; bool
// make nonce Path::HandlePathLatencyMessage(
TunnelNonce N; const llarp::routing::PathLatencyMessage* msg)
N.Randomize(); {
return HandleUpstream(buf, N, r); // TODO: implement me
} return false;
}
bool
Path::HandleDHTMessage(const llarp::dht::IMessage* msg)
{
// TODO: implement me
return false;
}
} // namespace path
} // namespace llarp } // namespace llarp

@ -9,7 +9,10 @@ namespace llarp
template < typename User > template < typename User >
struct AsyncPathKeyExchangeContext struct AsyncPathKeyExchangeContext
{ {
Path* path = nullptr; typedef llarp::path::Path Path_t;
typedef llarp::path::PathSet PathSet_t;
PathSet_t* pathset = nullptr;
Path_t* path = nullptr;
typedef void (*Handler)(AsyncPathKeyExchangeContext< User >*); typedef void (*Handler)(AsyncPathKeyExchangeContext< User >*);
User* user = nullptr; User* user = nullptr;
Handler result = nullptr; Handler result = nullptr;
@ -105,8 +108,8 @@ namespace llarp
/// Generate all keys asynchronously and call hadler when done /// Generate all keys asynchronously and call hadler when done
void void
AsyncGenerateKeys(Path* p, llarp_logic* l, llarp_threadpool* pool, User* u, AsyncGenerateKeys(Path_t* p, llarp_logic* l, llarp_threadpool* pool,
Handler func) User* u, Handler func)
{ {
path = p; path = p;
logic = l; logic = l;
@ -124,16 +127,6 @@ namespace llarp
} }
}; };
PathHopConfig::PathHopConfig()
{
llarp_rc_clear(&router);
}
PathHopConfig::~PathHopConfig()
{
llarp_rc_free(&router);
}
void void
pathbuilder_generated_keys( pathbuilder_generated_keys(
AsyncPathKeyExchangeContext< llarp_pathbuild_job >* ctx) AsyncPathKeyExchangeContext< llarp_pathbuild_job >* ctx)
@ -146,8 +139,8 @@ namespace llarp
llarp::Error("failed to send LRCM"); llarp::Error("failed to send LRCM");
return; return;
} }
ctx->path->status = ePathBuilding; ctx->path->status = llarp::path::ePathBuilding;
router->paths.AddOwnPath(ctx->path); router->paths.AddOwnPath(ctx->pathset, ctx->path);
ctx->user->pathBuildStarted(ctx->user); ctx->user->pathBuildStarted(ctx->user);
} }
@ -171,16 +164,33 @@ namespace llarp
AsyncPathKeyExchangeContext< llarp_pathbuild_job >* ctx = AsyncPathKeyExchangeContext< llarp_pathbuild_job >* ctx =
new AsyncPathKeyExchangeContext< llarp_pathbuild_job >( new AsyncPathKeyExchangeContext< llarp_pathbuild_job >(
&job->router->crypto); &job->router->crypto);
ctx->pathset = job->context;
ctx->AsyncGenerateKeys(new Path(&job->hops), job->router->logic, auto path = new llarp::path::Path(&job->hops);
job->router->tp, job, &pathbuilder_generated_keys); path->SetBuildResultHook(std::bind(&llarp::path::PathSet::HandlePathBuilt,
ctx->pathset, std::placeholders::_1));
ctx->AsyncGenerateKeys(path, job->router->logic, job->router->tp, job,
&pathbuilder_generated_keys);
} }
} // namespace llarp } // namespace llarp
llarp_pathbuilder_context::llarp_pathbuilder_context( llarp_pathbuilder_context::llarp_pathbuilder_context(
llarp_router* p_router, struct llarp_dht_context* p_dht) llarp_router* p_router, struct llarp_dht_context* p_dht)
: router(p_router), dht(p_dht) // TODO: hardcoded value
: llarp::path::PathSet(4), router(p_router), dht(p_dht)
{
p_router->paths.AddPathBuilder(this);
}
void
llarp_pathbuilder_context::BuildOne()
{ {
llarp_pathbuild_job* job = new llarp_pathbuild_job;
job->context = this;
job->selectHop = nullptr;
job->hops.numHops = 4;
job->user = nullptr;
job->pathBuildStarted = [](llarp_pathbuild_job* j) { delete j; };
llarp_pathbuilder_build_path(job);
} }
extern "C" { extern "C" {
@ -200,7 +210,7 @@ llarp_pathbuilder_context_free(struct llarp_pathbuilder_context* ctx)
void void
llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job) llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job)
{ {
if (!job->context) if(!job->context)
{ {
llarp::Error("failed to build path because no context is set in job"); llarp::Error("failed to build path because no context is set in job");
return; return;
@ -211,4 +221,4 @@ llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job)
llarp_logic_queue_job(job->router->logic, llarp_logic_queue_job(job->router->logic,
{job, &llarp::pathbuilder_start_build}); {job, &llarp::pathbuilder_start_build});
} }
} // end extern c } // end extern c

@ -2,13 +2,16 @@
#define LLARP_PATHFINDER_HPP_ #define LLARP_PATHFINDER_HPP_
#include <llarp/pathbuilder.h> #include <llarp/pathbuilder.h>
struct llarp_pathbuilder_context struct llarp_pathbuilder_context : public llarp::path::PathSet
{ {
struct llarp_router* router; struct llarp_router* router;
struct llarp_dht_context* dht; struct llarp_dht_context* dht;
/// copy cstr /// construct
llarp_pathbuilder_context(llarp_router* p_router, llarp_pathbuilder_context(llarp_router* p_router,
struct llarp_dht_context* p_dht); struct llarp_dht_context* p_dht);
void
BuildOne();
}; };
#endif #endif

@ -0,0 +1,97 @@
#include <llarp/path.hpp>
#include <llarp/pathset.hpp>
namespace llarp
{
namespace path
{
PathSet::PathSet(size_t num) : m_NumPaths(num)
{
}
bool
PathSet::ShouldBuildMore() const
{
return std::get< 0 >(m_Paths).size() < m_NumPaths;
}
void
PathSet::ExpirePaths(llarp_time_t now)
{
{
auto& map = std::get< 0 >(m_Paths);
auto itr = map.begin();
while(itr != map.end())
{
if(itr->second->Expired(now))
{
itr = map.erase(itr);
}
}
}
{
auto& map = std::get< 1 >(m_Paths);
auto itr = map.begin();
while(itr != map.end())
{
if(itr->second->Expired(now))
{
// delete path on second iteration
delete itr->second;
itr = map.erase(itr);
}
}
}
}
size_t
PathSet::NumInStatus(PathStatus st) const
{
size_t count = 0;
auto& map = std::get< 0 >(m_Paths);
auto itr = map.begin();
while(itr != map.end())
{
if(itr->second->status == st)
++count;
++itr;
}
return count;
}
void
PathSet::AddPath(Path* path)
{
std::get< 0 >(m_Paths).emplace(path->TXID(), path);
std::get< 1 >(m_Paths).emplace(path->RXID(), path);
}
void
PathSet::RemovePath(Path* path)
{
std::get< 0 >(m_Paths).erase(path->TXID());
std::get< 1 >(m_Paths).erase(path->RXID());
}
Path*
PathSet::GetByUpstream(const RouterID& remote, const PathID_t& rxid)
{
auto& set = std::get< 1 >(m_Paths);
auto itr = set.begin();
while(itr != set.end())
{
if(itr->second->Upstream() == remote)
return itr->second;
++itr;
}
return nullptr;
}
void
PathSet::HandlePathBuilt(Path* path)
{
// TODO: implement me
}
} // namespace path
} // namespace llarp

@ -155,18 +155,20 @@ namespace llarp
struct LRCMFrameDecrypt struct LRCMFrameDecrypt
{ {
typedef llarp::path::PathContext Context;
typedef llarp::path::TransitHop Hop;
typedef AsyncFrameDecrypter< LRCMFrameDecrypt > Decrypter; typedef AsyncFrameDecrypter< LRCMFrameDecrypt > Decrypter;
Decrypter* decrypter; Decrypter* decrypter;
std::deque< EncryptedFrame > frames; std::deque< EncryptedFrame > frames;
PathContext* context; Context* context;
// decrypted record // decrypted record
LR_CommitRecord record; LR_CommitRecord record;
// the actual hop // the actual hop
TransitHop* hop; Hop* hop;
LRCMFrameDecrypt(PathContext* ctx, Decrypter* dec, LRCMFrameDecrypt(Context* ctx, Decrypter* dec,
const LR_CommitMessage* commit) const LR_CommitMessage* commit)
: decrypter(dec), context(ctx), hop(new TransitHop) : decrypter(dec), context(ctx), hop(new Hop)
{ {
for(const auto& f : commit->frames) for(const auto& f : commit->frames)
frames.push_back(f); frames.push_back(f);
@ -276,7 +278,7 @@ namespace llarp
}; };
bool bool
LR_CommitMessage::AsyncDecrypt(PathContext* context) const LR_CommitMessage::AsyncDecrypt(llarp::path::PathContext* context) const
{ {
LRCMFrameDecrypt::Decrypter* decrypter = new LRCMFrameDecrypt::Decrypter( LRCMFrameDecrypt::Decrypter* decrypter = new LRCMFrameDecrypt::Decrypter(
context->Crypto(), context->EncryptionSecretKey(), context->Crypto(), context->EncryptionSecretKey(),

@ -356,6 +356,7 @@ llarp_router::HandleExploritoryPathBuildStarted(llarp_pathbuild_job *job)
delete job; delete job;
} }
// TODO: do we still need this?
void void
llarp_router::BuildExploritoryPath() llarp_router::BuildExploritoryPath()
{ {
@ -379,7 +380,7 @@ llarp_router::Tick()
auto N = llarp_nodedb_num_loaded(nodedb); auto N = llarp_nodedb_num_loaded(nodedb);
if(N > 5) if(N > 5)
{ {
BuildExploritoryPath(); paths.BuildPaths();
} }
else else
{ {
@ -595,16 +596,14 @@ llarp_router::Run()
// set public encryption key // set public encryption key
llarp_rc_set_pubenckey(&rc, llarp::seckey_topublic(encryption)); llarp_rc_set_pubenckey(&rc, llarp::seckey_topublic(encryption));
char ftmp[68] = {0}; char ftmp[68] = {0};
const char *hexKey = llarp::HexEncode< llarp::PubKey, const char *hexKey = llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(
decltype(ftmp) >(llarp::seckey_topublic(encryption), llarp::seckey_topublic(encryption), ftmp);
ftmp);
llarp::Info("Your Encryption pubkey ", hexKey); llarp::Info("Your Encryption pubkey ", hexKey);
// set public signing key // set public signing key
llarp_rc_set_pubsigkey(&rc, llarp::seckey_topublic(identity)); llarp_rc_set_pubsigkey(&rc, llarp::seckey_topublic(identity));
hexKey = llarp::HexEncode< llarp::PubKey, hexKey = llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(
decltype(ftmp) >(llarp::seckey_topublic(identity), llarp::seckey_topublic(identity), ftmp);
ftmp);
llarp::Info("Your Identity pubkey ", hexKey); llarp::Info("Your Identity pubkey ", hexKey);
llarp_rc_sign(&crypto, identity, &rc); llarp_rc_sign(&crypto, identity, &rc);
@ -641,14 +640,16 @@ llarp_router::Run()
// immediate connect all for service node // immediate connect all for service node
uint64_t delay = rand() % 100; uint64_t delay = rand() % 100;
llarp_logic_call_later(logic, {delay, this, &ConnectAll}); llarp_logic_call_later(logic, {delay, this, &ConnectAll});
//llarp_logic_call_later(logic, {static_cast<uint64_t>(delay), this, &ConnectAll}); // llarp_logic_call_later(logic, {static_cast<uint64_t>(delay), this,
// &ConnectAll});
} }
else else
{ {
// delayed connect all for clients // delayed connect all for clients
uint64_t delay = ((rand() % 10) * 500) + 1000; uint64_t delay = ((rand() % 10) * 500) + 1000;
llarp_logic_call_later(logic, {delay, this, &ConnectAll}); llarp_logic_call_later(logic, {delay, this, &ConnectAll});
//llarp_logic_call_later(logic, {static_cast<uint64_t>(delay), this, &ConnectAll}); // llarp_logic_call_later(logic, {static_cast<uint64_t>(delay), this,
// &ConnectAll});
} }
llarp::PubKey ourPubkey = pubkey(); llarp::PubKey ourPubkey = pubkey();
@ -850,7 +851,7 @@ llarp_rc_read(const char *fpath)
return 0; return 0;
f.read((char *)buf.base, sz); f.read((char *)buf.base, sz);
//printf("contents[%s]\n", tmpc); // printf("contents[%s]\n", tmpc);
llarp_rc *rc = new llarp_rc; llarp_rc *rc = new llarp_rc;
llarp::Zero(rc, sizeof(llarp_rc)); llarp::Zero(rc, sizeof(llarp_rc));
if(!llarp_rc_bdecode(rc, &buf)) if(!llarp_rc_bdecode(rc, &buf))
@ -977,12 +978,12 @@ llarp_findOrCreateIdentity(llarp_crypto *crypto, const char *fpath,
return false; return false;
} }
} // end extern C } // end extern C
// C++ ... // C++ ...
bool bool
llarp_findOrCreateEncryption(llarp_crypto *crypto, const char *fpath, llarp_findOrCreateEncryption(llarp_crypto *crypto, const char *fpath,
llarp::SecretKey *encryption) llarp::SecretKey *encryption)
{ {
llarp::Debug("find or create ", fpath); llarp::Debug("find or create ", fpath);
fs::path path(fpath); fs::path path(fpath);

@ -58,7 +58,7 @@ struct llarp_router
llarp_threadpool *tp; llarp_threadpool *tp;
llarp_logic *logic; llarp_logic *logic;
llarp_crypto crypto; llarp_crypto crypto;
llarp::PathContext paths; llarp::path::PathContext paths;
llarp::SecretKey identity; llarp::SecretKey identity;
llarp::SecretKey encryption; llarp::SecretKey encryption;
llarp_threadpool *disk; llarp_threadpool *disk;

@ -44,9 +44,7 @@ namespace llarp
bool bool
PathConfirmMessage::HandleMessage(IMessageHandler* h) const PathConfirmMessage::HandleMessage(IMessageHandler* h) const
{ {
llarp::Info("got path confirm created=", pathCreated, return h && h->HandlePathConfirmMessage(this);
" lifetime=", pathLifetime);
return true;
} }
} // namespace routing } // namespace routing

@ -4,85 +4,87 @@
namespace llarp namespace llarp
{ {
bool namespace path
TransitHop::Expired(llarp_time_t now) const
{ {
return now - started > lifetime; bool
} TransitHop::Expired(llarp_time_t now) const
{
TransitHopInfo::TransitHopInfo(const TransitHopInfo& other) return now - started > lifetime;
: txID(other.txID) }
, rxID(other.rxID)
, upstream(other.upstream)
, downstream(other.downstream)
{
}
TransitHopInfo::TransitHopInfo(const RouterID& down, TransitHopInfo::TransitHopInfo(const TransitHopInfo& other)
const LR_CommitRecord& record) : txID(other.txID)
: txID(record.txid) , rxID(other.rxID)
, rxID(record.rxid) , upstream(other.upstream)
, upstream(record.nextHop) , downstream(other.downstream)
, downstream(down) {
{ }
}
TransitHop::TransitHop(const TransitHop& other) TransitHopInfo::TransitHopInfo(const RouterID& down,
: info(other.info) const LR_CommitRecord& record)
, pathKey(other.pathKey) : txID(record.txid)
, started(other.started) , rxID(record.rxid)
, lifetime(other.lifetime) , upstream(record.nextHop)
, version(other.version) , downstream(down)
{ {
} }
bool TransitHop::TransitHop(const TransitHop& other)
TransitHop::SendRoutingMessage(const llarp::routing::IMessage* msg, : info(other.info)
llarp_router* r) , pathKey(other.pathKey)
{ , started(other.started)
byte_t tmp[MAX_LINK_MSG_SIZE / 2]; , lifetime(other.lifetime)
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp); , version(other.version)
if(!msg->BEncode(&buf))
{ {
llarp::Error("failed to encode routing message");
return false;
} }
TunnelNonce N;
N.Randomize();
// rewind
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return HandleDownstream(buf, N, r);
}
bool bool
TransitHop::HandleDownstream(llarp_buffer_t buf, const TunnelNonce& Y, TransitHop::SendRoutingMessage(const llarp::routing::IMessage* msg,
llarp_router* r) llarp_router* r)
{ {
RelayDownstreamMessage* msg = new RelayDownstreamMessage; byte_t tmp[MAX_LINK_MSG_SIZE / 2];
msg->pathid = info.txID; auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
msg->Y = Y; if(!msg->BEncode(&buf))
{
llarp::Error("failed to encode routing message");
return false;
}
TunnelNonce N;
N.Randomize();
// rewind
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return HandleDownstream(buf, N, r);
}
r->crypto.xchacha20(buf, pathKey, Y); bool
msg->X = buf; TransitHop::HandleDownstream(llarp_buffer_t buf, const TunnelNonce& Y,
llarp::Info("relay ", msg->X.size(), " bytes downstream from ", llarp_router* r)
info.upstream, " to ", info.downstream); {
return r->SendToOrQueue(info.downstream, msg); RelayDownstreamMessage* msg = new RelayDownstreamMessage;
} msg->pathid = info.txID;
msg->Y = Y;
bool r->crypto.xchacha20(buf, pathKey, Y);
TransitHop::HandleUpstream(llarp_buffer_t buf, const TunnelNonce& Y, msg->X = buf;
llarp_router* r) llarp::Info("relay ", msg->X.size(), " bytes downstream from ",
{ info.upstream, " to ", info.downstream);
RelayUpstreamMessage* msg = new RelayUpstreamMessage; return r->SendToOrQueue(info.downstream, msg);
msg->pathid = info.rxID; }
msg->Y = Y;
r->crypto.xchacha20(buf, pathKey, Y); bool
msg->X = buf; TransitHop::HandleUpstream(llarp_buffer_t buf, const TunnelNonce& Y,
llarp::Info("relay ", msg->X.size(), " bytes upstream from ", llarp_router* r)
info.downstream, " to ", info.upstream); {
return r->SendToOrQueue(info.upstream, msg); RelayUpstreamMessage* msg = new RelayUpstreamMessage;
} msg->pathid = info.rxID;
msg->Y = Y;
r->crypto.xchacha20(buf, pathKey, Y);
msg->X = buf;
llarp::Info("relay ", msg->X.size(), " bytes upstream from ",
info.downstream, " to ", info.upstream);
return r->SendToOrQueue(info.upstream, msg);
}
} // namespace path
} // namespace llarp } // namespace llarp

Loading…
Cancel
Save