pull/1/head
Ryan Tharp 6 years ago
commit 7d2aa9b036

@ -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)

@ -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:

@ -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)

@ -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()

@ -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)

@ -4,6 +4,7 @@
#include <llarp/bencode.h>
#include <llarp/buffer.h>
#include <sodium.h>
#include <vector>
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

@ -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)
{

@ -0,0 +1,18 @@
#ifndef LLARP_ENDPOINT_HANDLER_HPP
#define LLARP_ENDPOINT_HANDLER_HPP
#include <llarp/buffer.h>
namespace llarp
{
// hidden service endpoint handler
struct IEndpointHandler
{
~IEndpointHandler(){};
virtual void
HandleMessage(llarp_buffer_t buf) = 0;
};
} // namespace llarp
#endif

@ -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__)

@ -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

@ -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

@ -5,11 +5,14 @@
#include <llarp/time.h>
#include <llarp/aligned.hpp>
#include <llarp/crypto.hpp>
#include <llarp/endpoint.hpp>
#include <llarp/messages/relay_ack.hpp>
#include <llarp/messages/relay_commit.hpp>
#include <llarp/path_types.hpp>
#include <llarp/router_id.hpp>
#include <list>
#include <map>
#include <mutex>
#include <unordered_map>
#include <vector>
@ -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;
};

@ -1,11 +1,12 @@
#ifndef LLARP_PATH_TYPES_HPP
#define LLARP_PATH_TYPES_HPP
#include <llarp/crypto.h>
#include <llarp/aligned.hpp>
namespace llarp
{
typedef AlignedBuffer< 16 > PathID_t;
typedef AlignedBuffer< PATHIDSIZE > PathID_t;
}
#endif

@ -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;
};

@ -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});
}

@ -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;

@ -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>
// <N bytes encrypted payload>
//
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>
// <N bytes encrypted payload>
//
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))
{

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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});
}

@ -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

@ -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

@ -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

@ -0,0 +1,57 @@
#include <gtest/gtest.h>
#include <llarp/crypto.hpp>
#include <llarp/encrypted_frame.hpp>
#include <llarp/messages/relay_commit.hpp>
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));
};
Loading…
Cancel
Save