Merge branch 'hidden-service-dht' of https://github.com/majestrate/llarp

pull/5/head
Ryan Tharp 6 years ago
commit e1a4c2f32c

@ -13,6 +13,7 @@
},
"includePath": [
"${workspaceFolder}/include",
"${workspaceFolder}/llarp",
"${workspaceFolder}/vendor/cppbackport-master/lib"
],
"defines": [],

@ -82,7 +82,7 @@ if(RELEASE_MOTTO)
endif()
set(EXE llarpd)
set(EXE_SRC daemon/main.c)
set(EXE_SRC daemon/main.cpp)
if(SODIUM_INCLUDE_DIR)
include_directories(${SODIUM_INCLUDE_DIR})
@ -134,7 +134,7 @@ endif()
set(LIB_SRC
llarp/address_info.cpp
llarp/bencode.c
llarp/bencode.cpp
llarp/buffer.cpp
llarp/config.cpp
llarp/context.cpp
@ -145,10 +145,8 @@ set(LIB_SRC
llarp/encrypted_frame.cpp
llarp/ev.cpp
llarp/exit_info.cpp
llarp/exit_route.c
llarp/iwp_link.cpp
llarp/exit_route.cpp
llarp/logger.cpp
llarp/link.c
llarp/link_intro.cpp
llarp/link_message.cpp
llarp/logic.cpp
@ -174,11 +172,28 @@ set(LIB_SRC
llarp/api/client.cpp
llarp/api/message.cpp
llarp/api/parser.cpp
llarp/dht/context.cpp
llarp/dht/decode.cpp
llarp/dht/dht_immediate.cpp
llarp/dht/find_intro.cpp
llarp/dht/find_router.cpp
llarp/dht/got_intro.cpp
llarp/dht/got_router.cpp
llarp/dht/search_job.cpp
llarp/dht/publish_intro.cpp
llarp/iwp/frame_header.cpp
llarp/iwp/frame_state.cpp
llarp/iwp/session.cpp
llarp/iwp/transit_message.cpp
llarp/iwp/xmit.cpp
llarp/link/encoder.cpp
llarp/routing/dht_message.cpp
llarp/routing/message_parser.cpp
llarp/routing/path_confirm.cpp
llarp/routing/path_latency.cpp
llarp/routing/path_transfer.cpp
llarp/service/context.cpp
llarp/service/endpoint.cpp
vendor/cppbackport-master/lib/fs/rename.cpp
vendor/cppbackport-master/lib/fs/filestatus.cpp
vendor/cppbackport-master/lib/fs/filetype.cpp

@ -21,6 +21,10 @@ TESTNET_ROOT=$(REPO)/testnet_tmp
TESTNET_CONF=$(TESTNET_ROOT)/supervisor.conf
TESTNET_LOG=$(TESTNET_ROOT)/testnet.log
TESTNET_CLIENTS ?= 50
TESTNET_SERVERS ?= 50
TESTNET_DEBUG ?= 0
clean:
rm -f build.ninja rules.ninja cmake_install.cmake CMakeCache.txt
rm -rf CMakeFiles
@ -70,8 +74,8 @@ testnet-build: testnet-configure
testnet: testnet-build
mkdir -p $(TESTNET_ROOT)
python3 contrib/testnet/genconf.py --bin=$(REPO)/llarpd --svc=30 --clients=1 --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF)
supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF)
python3 contrib/testnet/genconf.py --bin=$(REPO)/llarpd --svc=$(TESTNET_SERVERS) --clients=$(TESTNET_CLIENTS) --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF)
LLARP_DEBUG=$(TESTNET_DEBUG) supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF)
test: debug-configure
ninja

@ -27,6 +27,7 @@ def main():
ap.add_argument('--bin', type=str, required=True)
ap.add_argument('--out', type=str, required=True)
ap.add_argument('--connect', type=int, default=10)
ap.add_argument('--ifname', type=str, default='lo')
args = ap.parse_args()
@ -39,7 +40,7 @@ def main():
'worker-threads': '4'
}
config['bind'] = {
'lo': str(args.baseport + nodeid)
args.ifname: str(args.baseport + nodeid)
}
config['netdb'] = {
'dir': 'netdb'
@ -60,6 +61,7 @@ def main():
for nodeid in range(args.clients):
config = CP()
config['router'] = {
'net-threads': '1',
'worker-threads': '2'
@ -77,9 +79,19 @@ def main():
d = os.path.join(args.dir, clientNodeName(nodeid))
if not os.path.exists(d):
os.mkdir(d)
hiddenservice = os.path.join(d, 'service.ini')
config['services'] = {
'testnet': hiddenservice
}
fp = os.path.join(d, 'daemon.ini')
with open(fp, 'w') as f:
config.write(f)
config = CP()
config['test-service'] = {
}
with open(hiddenservice, 'w') as f:
config.write(f)
with open(args.out, 'w') as f:
f.write('''[program:svc-node]

@ -11,6 +11,7 @@ recursively find an IS by SA
{
A: "F",
I: 0 or 1 if iterative request,
R: r_counter,
S: "<32 bytes SA>",
T: transaction_id_uint64,
@ -102,6 +103,7 @@ R is currently set to 0 by the sender.
I: IS,
R: r_counter,
S: optional member 0 for immediate store otherwise non zero,
T: transaction_id_uint64,
V: 0
}
@ -122,33 +124,13 @@ find a router by long term RC.k public key
{
A: "R",
I: 0 or 1 if iterative lookup
K: "<32 byte public key of router>",
T: transaction_id_uint64,
V: 0
}
find RC who's RC.k is closest to K:
if A.k is equal to K:
* reply with a GRCM with an R value of just A
if A.k is not equal to K and we are closesr to A.k than anyone we know:
* reply with a GRCM with an empty R value
find a pending transaction id for K, P
if P exists:
* link transaction T to P
if P does not exist:
* generate a new transaction id, U
* start transaction U for A.k
* link transaction U to transaction T
* send FRCM to A.k requesting K
TODO: document me
got router contact message (GRCM)

@ -1,8 +1,5 @@
invisible wire protocol:
as of version 0 dtls is used, future versions will use this encrypted udp
transport protocol.
invisible wire protocol version 0:
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this

@ -166,6 +166,7 @@ x is the timestamp seconds since epoch that this introduction expires at
{
k: "<32 bytes public identity key of router>",
l: advertised_path_latency_ms_uint64, (optional)
p: "<16 bytes path id>",
v: 0,
x: time_expires_seconds_since_epoch_uint64
@ -515,20 +516,43 @@ B is set to a backoff value.
R contains additional metadata text describing why the exit was rejected.
hidden service frame (HSF)
hidden service data message (HSDM)
TODO: document this better
signed data sent anonymously over the network to a recipiant from a sender.
sent inside a TDFM encrypted to the hidden service's public encryption key.
intro message (variant 1)
{
A: "H",
H: "<payload bytes>",
I: Introducer for reply,
R: SA of recipiant,
S: SI of sender,
D: "<N bytes encrypted HSD>",
H: "<32 bytes ephemeral public encryption key>",
N: "<32 bytes nonce for key exchange>",
S: 0,
V: 0,
Z: "<64 bytes signature of entire message using sender's signing key>"
}
ordered data message (variant 2)
{
A: "H",
D: "<N bytes encrypted HSD>",
N: "<32 bytes nonce for symettric cipher>",
S: sequence_number_uint64,
V: 0,
Z: "<64 bytes signature from sender of the entire message>"
Z: "<64 bytes signature using sender's signing key>"
}
hidden service data (HSD)
data sent anonymously over the network to a recipiant from a sender.
sent inside a HSFM encrypted with a shared secret.
{
D: "<N bytes payload>",
I: Introduction for reply,
S: SI of sender,
V: 0
}
transfer data fragment message (TDFM)
@ -538,12 +562,11 @@ transfer data between paths.
{
A: "T",
P: "<16 bytes path id>",
T: "<N bytes data>",
V: 0,
Y: "<32 bytes nounce>"
T: message_transfered_between_paths,
V: 0
}
transfer data to another path with id P on the local router place Y and T values
transfer data to another path with id P on the local router place a random 32 byte and T values
into y and z values into a LRDM message (respectively) and send it in the
downstream direction.

@ -23,10 +23,6 @@ llarp_main_init(const char *fname, bool multiProcess);
void
llarp_main_signal(struct llarp_main *ptr, int sig);
/// set custom dht message handler function
void
llarp_main_set_dht_handler(struct llarp_main *ptr, llarp_dht_msg_handler h);
/// setup main context
int
llarp_main_setup(struct llarp_main *ptr);

@ -18,15 +18,14 @@ namespace llarp
bool singleThreaded = false;
std::vector< std::thread > netio_threads;
llarp_crypto crypto;
llarp_router *router = nullptr;
llarp_threadpool *worker = nullptr;
llarp_logic *logic = nullptr;
llarp_config *config = nullptr;
llarp_nodedb *nodedb = nullptr;
llarp_ev_loop *mainloop = nullptr;
llarp_dht_msg_handler custom_dht_func = nullptr;
char nodedb_dir[256] = {0};
char conatctFile[256] = "router.signed";
llarp_router *router = nullptr;
llarp_threadpool *worker = nullptr;
llarp_logic *logic = nullptr;
llarp_config *config = nullptr;
llarp_nodedb *nodedb = nullptr;
llarp_ev_loop *mainloop = nullptr;
char nodedb_dir[256] = {0};
char conatctFile[256] = "router.signed";
bool
LoadConfig(const std::string &fname);
@ -73,6 +72,6 @@ namespace llarp
std::ostream &out;
};
}
} // namespace llarp
#endif

@ -11,10 +11,6 @@
* utilities for handling addresses on the llarp network
*/
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_AI_DIALECT_SIZE 5
/// address information model
@ -92,8 +88,4 @@ struct llarp_ai_list_iter
void
llarp_ai_list_iterate(struct llarp_ai_list *l, struct llarp_ai_list_iter *iter);
#ifdef __cplusplus
}
#endif
#endif

@ -14,10 +14,6 @@
* we utilize llarp_buffer which provides memory management
*/
#ifdef __cplusplus
extern "C" {
#endif
bool
bencode_write_bytestring(llarp_buffer_t* buff, const void* data, size_t sz);
@ -88,7 +84,4 @@ struct list_reader
bool
bencode_read_list(llarp_buffer_t* buff, struct list_reader* r);
#ifdef __cplusplus
}
#endif
#endif

@ -34,10 +34,6 @@ namespace llarp
return bencode_write_bytestring(buf, k, 1) && bencode_write_uint64(buf, i);
}
template < typename Item_t >
bool
BEncodeRead(Item_t& item, llarp_buffer_t* buf);
template < typename Item_t >
bool
BEncodeMaybeReadDictEntry(const char* k, Item_t& item, bool& read,
@ -153,6 +149,27 @@ namespace llarp
virtual bool
BEncode(llarp_buffer_t* buf) const = 0;
bool
BDecode(llarp_buffer_t* buf)
{
dict_reader r;
r.user = this;
r.on_key = &OnKey;
return bencode_read_dict(buf, &r);
}
// TODO: check for shadowed values elsewhere
uint64_t version = 0;
static bool
OnKey(dict_reader* r, llarp_buffer_t* k)
{
if(k)
return static_cast< IBEncodeMessage* >(r->user)->DecodeKey(*k,
r->buffer);
return true;
}
};
} // namespace llarp

@ -13,10 +13,6 @@
* generic memory buffer
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef uint8_t byte_t;
/**
@ -86,8 +82,4 @@ llarp_buffer_read_until(llarp_buffer_t *buff, char delim, byte_t *result,
bool
llarp_buffer_eq(llarp_buffer_t buff, const char *data);
#ifdef __cplusplus
}
#endif
#endif

@ -7,10 +7,6 @@
* library configuration utilties
*/
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_config;
/// allocate config
@ -42,7 +38,4 @@ void
llarp_config_iter(struct llarp_config *conf,
struct llarp_config_iterator *iter);
#ifdef __cplusplus
}
#endif
#endif

@ -12,10 +12,6 @@
* potentially allow libssl support in the future
*/
#ifdef __cplusplus
extern "C" {
#endif
#define PUBKEYSIZE 32
#define SECKEYSIZE 64
#define NONCESIZE 24
@ -110,8 +106,4 @@ llarp_crypto_libsodium_init(struct llarp_crypto *c);
bool
llarp_crypto_initialized(struct llarp_crypto *c);
#ifdef __cplusplus
}
#endif
#endif

@ -41,6 +41,6 @@ namespace llarp
typedef AlignedBuffer< 24 > SymmNonce;
typedef AlignedBuffer< 32 > SymmKey;
}
} // namespace llarp
#endif

@ -12,10 +12,6 @@
* asynchronous crypto functions
*/
#ifdef __cplusplus
extern "C" {
#endif
/// context for doing asynchronous cryptography for iwp
/// with a worker threadpool
/// defined in crypto_async.cpp
@ -182,6 +178,24 @@ struct iwp_async_frame
byte_t buf[1500];
};
// TODO: remove
struct FramePutTime
{
void
operator()(iwp_async_frame *frame) const
{
frame->created = llarp_time_now_ms();
}
};
struct FrameGetTime
{
llarp_time_t
operator()(const iwp_async_frame *frame) const
{
return frame->created;
}
};
/// synchronously decrypt a frame
bool
iwp_decrypt_frame(struct iwp_async_frame *frame);
@ -200,7 +214,4 @@ void
iwp_call_async_frame_encrypt(struct llarp_async_iwp *iwp,
struct iwp_async_frame *frame);
#ifdef __cplusplus
}
#endif
#endif

@ -10,10 +10,6 @@
* DHT functions
*/
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_dht_context;
/// allocator
@ -24,23 +20,10 @@ llarp_dht_context_new(struct llarp_router* parent);
void
llarp_dht_context_free(struct llarp_dht_context* dht);
struct llarp_dht_msg;
/// handler function
/// f(outmsg, inmsg)
/// returns true if outmsg has been filled otherwise returns false
typedef bool (*llarp_dht_msg_handler)(struct llarp_dht_msg*,
struct llarp_dht_msg*);
/// start dht context with our location in keyspace
void
llarp_dht_context_start(struct llarp_dht_context* ctx, const byte_t* key);
// override dht message handler with custom handler
void
llarp_dht_set_msg_handler(struct llarp_dht_context* ctx,
llarp_dht_msg_handler func);
struct llarp_router_lookup_job;
typedef void (*llarp_router_lookup_handler)(struct llarp_router_lookup_job*);
@ -72,7 +55,4 @@ void
llarp_dht_lookup_router(struct llarp_dht_context* ctx,
struct llarp_router_lookup_job* job);
#ifdef __cplusplus
}
#endif
#endif

@ -1,408 +1,5 @@
#ifndef LLARP_DHT_HPP_
#define LLARP_DHT_HPP_
#include <llarp/buffer.h>
#include <llarp/dht.h>
#include <llarp/router.h>
#include <llarp/router_contact.h>
#include <llarp/time.h>
#include <llarp/aligned.hpp>
#include <llarp/path_types.hpp>
#include <llarp/service.hpp>
#include <array>
#include <functional>
#include <map>
#include <set>
#include <unordered_map>
#include <vector>
namespace llarp
{
namespace dht
{
const size_t MAX_MSG_SIZE = 2048;
struct Key_t : public llarp::AlignedBuffer< 32 >
{
Key_t(const byte_t* val) : llarp::AlignedBuffer< 32 >(val)
{
}
Key_t() : llarp::AlignedBuffer< 32 >()
{
}
Key_t
operator^(const Key_t& other) const
{
Key_t dist;
for(size_t idx = 0; idx < 4; ++idx)
dist.l[idx] = l[idx] ^ other.l[idx];
return dist;
}
bool
operator<(const Key_t& other) const
{
return memcmp(data_l(), other.data_l(), 32) < 0;
}
};
struct RCNode
{
llarp_rc* rc;
Key_t ID;
RCNode() : rc(nullptr)
{
ID.Zero();
}
RCNode(llarp_rc* other) : rc(other)
{
ID = other->pubkey;
}
};
struct ISNode
{
llarp::service::IntroSet* introset;
Key_t ID;
ISNode() : introset(nullptr)
{
ID.Zero();
}
ISNode(llarp::service::IntroSet* other) : introset(other)
{
other->A.CalculateAddress(ID);
}
};
struct SearchJob
{
const static uint64_t JobTimeout = 30000;
SearchJob();
SearchJob(const Key_t& requester, uint64_t requesterTX,
const Key_t& target, llarp_router_lookup_job* job,
const std::set< Key_t >& excludes);
void
Completed(const llarp_rc* router, bool timeout = false) const;
bool
IsExpired(llarp_time_t now) const;
llarp_router_lookup_job* job = nullptr;
llarp_time_t started;
Key_t requester;
uint64_t requesterTX;
Key_t target;
std::set< Key_t > exclude;
};
struct XorMetric
{
const Key_t& us;
XorMetric(const Key_t& ourKey) : us(ourKey){};
bool
operator()(const Key_t& left, const Key_t& right) const
{
return (us ^ left) < (us ^ right);
};
};
struct IMessage
{
virtual ~IMessage(){};
/// construct
IMessage(const Key_t& from) : From(from)
{
}
virtual bool
BEncode(llarp_buffer_t* buf) const = 0;
virtual bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val) = 0;
virtual bool
HandleMessage(llarp_dht_context* dht,
std::vector< IMessage* >& replies) const = 0;
Key_t From;
PathID_t pathID;
};
IMessage*
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed = false);
bool
DecodeMesssageList(const Key_t& from, llarp_buffer_t* buf,
std::vector< IMessage* >& dst, bool relayed = false);
template < typename Val_t >
struct Bucket
{
typedef std::map< Key_t, Val_t, XorMetric > BucketStorage_t;
Bucket(const Key_t& us) : nodes(XorMetric(us)){};
bool
FindClosest(const Key_t& target, Key_t& result) const
{
Key_t mindist;
mindist.Fill(0xff);
for(const auto& item : nodes)
{
auto curDist = item.first ^ target;
if(curDist < mindist)
{
mindist = curDist;
result = item.first;
}
}
return nodes.size() > 0;
}
bool
FindCloseExcluding(const Key_t& target, Key_t& result,
const std::set< Key_t >& exclude) const
{
Key_t maxdist;
maxdist.Fill(0xff);
Key_t mindist;
mindist.Fill(0xff);
for(const auto& item : nodes)
{
if(exclude.find(item.first) != exclude.end())
continue;
auto curDist = item.first ^ target;
if(curDist < mindist)
{
mindist = curDist;
result = item.first;
}
}
return mindist < maxdist;
}
void
PutNode(const Val_t& val)
{
nodes[val.ID] = val;
}
void
DelNode(const Key_t& key)
{
auto itr = nodes.find(key);
if(itr != nodes.end())
nodes.erase(itr);
}
BucketStorage_t nodes;
};
struct Context
{
Context();
~Context();
llarp_dht_msg_handler custom_handler = nullptr;
SearchJob*
FindPendingTX(const Key_t& owner, uint64_t txid);
void
RemovePendingLookup(const Key_t& owner, uint64_t txid);
void
LookupRouter(const Key_t& target, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
llarp_router_lookup_job* job = nullptr,
bool iterative = false, std::set< Key_t > excludes = {});
void
LookupRouterViaJob(llarp_router_lookup_job* job);
void
LookupRouterRelayed(const Key_t& requester, uint64_t txid,
const Key_t& target, bool recursive,
std::vector< IMessage* >& replies);
bool
RelayRequestForPath(const llarp::PathID_t& localPath,
const IMessage* msg);
void
Init(const Key_t& us, llarp_router* router);
void
QueueRouterLookup(llarp_router_lookup_job* job);
static void
handle_cleaner_timer(void* user, uint64_t orig, uint64_t left);
static void
queue_router_lookup(void* user);
llarp_router* router = nullptr;
// for router contacts
Bucket< RCNode >* nodes = nullptr;
// for introduction sets
Bucket< ISNode >* services = nullptr;
bool allowTransit = false;
const Key_t&
OurKey() const
{
return ourKey;
}
private:
void
ScheduleCleanupTimer();
void
CleanupTX();
uint64_t ids;
struct TXOwner
{
Key_t node;
uint64_t txid = 0;
bool
operator==(const TXOwner& other) const
{
return txid == other.txid && node == other.node;
}
bool
operator<(const TXOwner& other) const
{
return txid < other.txid || node < other.node;
}
};
struct TXOwnerHash
{
std::size_t
operator()(TXOwner const& o) const noexcept
{
std::size_t sz2;
memcpy(&sz2, &o.node[0], sizeof(std::size_t));
return o.txid ^ (sz2 << 1);
}
};
std::unordered_map< TXOwner, SearchJob, TXOwnerHash > pendingTX;
Key_t ourKey;
};
struct PublishIntroMessage : public IMessage
{
llarp::service::IntroSet I;
uint64_t R;
uint64_t S;
bool hasS = false;
uint64_t V;
PublishIntroMessage() : IMessage({})
{
}
~PublishIntroMessage();
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
};
struct GotRouterMessage : public IMessage
{
GotRouterMessage(const Key_t& from) : IMessage(from)
{
}
GotRouterMessage(const Key_t& from, uint64_t id, const llarp_rc* result)
: IMessage(from), txid(id)
{
if(result)
{
R.emplace_back();
llarp_rc_clear(&R.back());
llarp_rc_copy(&R.back(), result);
}
}
~GotRouterMessage();
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
std::vector< llarp_rc > R;
uint64_t txid = 0;
uint64_t version = 0;
};
struct FindRouterMessage : public IMessage
{
FindRouterMessage(const Key_t& from) : IMessage(from)
{
}
FindRouterMessage(const Key_t& from, const Key_t& target, uint64_t id)
: IMessage(from), K(target), txid(id)
{
}
~FindRouterMessage();
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
Key_t K;
bool iterative = false;
uint64_t txid = 0;
uint64_t version = 0;
};
} // namespace dht
} // namespace llarp
struct llarp_dht_context
{
llarp::dht::Context impl;
llarp_router* parent;
llarp_dht_context(llarp_router* router);
};
#endif
#include <llarp/dht/context.hpp>
#include <llarp/dht/key.hpp>
#include <llarp/dht/message.hpp>
#include <llarp/dht/messages/all.hpp>
#include <llarp/dht/node.hpp>

@ -0,0 +1,77 @@
#ifndef LLARP_DHT_BUCKET_HPP
#define LLARP_DHT_BUCKET_HPP
#include <llarp/dht/kademlia.hpp>
#include <llarp/dht/key.hpp>
#include <map>
#include <set>
namespace llarp
{
namespace dht
{
template < typename Val_t >
struct Bucket
{
typedef std::map< Key_t, Val_t, XorMetric > BucketStorage_t;
Bucket(const Key_t& us) : nodes(XorMetric(us)){};
bool
FindClosest(const Key_t& target, Key_t& result) const
{
Key_t mindist;
mindist.Fill(0xff);
for(const auto& item : nodes)
{
auto curDist = item.first ^ target;
if(curDist < mindist)
{
mindist = curDist;
result = item.first;
}
}
return nodes.size() > 0;
}
bool
FindCloseExcluding(const Key_t& target, Key_t& result,
const std::set< Key_t >& exclude) const
{
Key_t maxdist;
maxdist.Fill(0xff);
Key_t mindist;
mindist.Fill(0xff);
for(const auto& item : nodes)
{
if(exclude.find(item.first) != exclude.end())
continue;
auto curDist = item.first ^ target;
if(curDist < mindist)
{
mindist = curDist;
result = item.first;
}
}
return mindist < maxdist;
}
void
PutNode(const Val_t& val)
{
nodes[val.ID] = val;
}
void
DelNode(const Key_t& key)
{
auto itr = nodes.find(key);
if(itr != nodes.end())
nodes.erase(itr);
}
BucketStorage_t nodes;
};
}
}
#endif

@ -0,0 +1,130 @@
#ifndef LLARP_DHT_CONTEXT_HPP
#define LLARP_DHT_CONTEXT_HPP
#include <llarp/dht.h>
#include <llarp/router.h>
#include <llarp/dht/bucket.hpp>
#include <llarp/dht/key.hpp>
#include <llarp/dht/message.hpp>
#include <llarp/dht/node.hpp>
#include <llarp/dht/search_job.hpp>
#include <set>
namespace llarp
{
namespace dht
{
struct Context
{
Context();
~Context();
SearchJob*
FindPendingTX(const Key_t& owner, uint64_t txid);
void
RemovePendingLookup(const Key_t& owner, uint64_t txid);
void
LookupServiceDirect(const Key_t& target, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
SearchJob::IntroSetHookFunc handler,
bool iterateive = false,
std::set< Key_t > excludes = {});
void
LookupRouter(const Key_t& target, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
llarp_router_lookup_job* job = nullptr,
bool iterative = false, std::set< Key_t > excludes = {});
void
LookupRouterViaJob(llarp_router_lookup_job* job);
void
LookupRouterRelayed(const Key_t& requester, uint64_t txid,
const Key_t& target, bool recursive,
std::vector< IMessage* >& replies);
bool
RelayRequestForPath(const llarp::PathID_t& localPath,
const IMessage* msg);
void
Init(const Key_t& us, llarp_router* router);
void
QueueRouterLookup(llarp_router_lookup_job* job);
static void
handle_cleaner_timer(void* user, uint64_t orig, uint64_t left);
static void
queue_router_lookup(void* user);
llarp_router* router = nullptr;
// for router contacts
Bucket< RCNode >* nodes = nullptr;
// for introduction sets
Bucket< ISNode >* services = nullptr;
bool allowTransit = false;
const Key_t&
OurKey() const
{
return ourKey;
}
private:
void
ScheduleCleanupTimer();
void
CleanupTX();
uint64_t ids;
struct TXOwner
{
Key_t node;
uint64_t txid = 0;
bool
operator==(const TXOwner& other) const
{
return txid == other.txid && node == other.node;
}
bool
operator<(const TXOwner& other) const
{
return txid < other.txid || node < other.node;
}
};
struct TXOwnerHash
{
std::size_t
operator()(TXOwner const& o) const noexcept
{
std::size_t sz2;
memcpy(&sz2, &o.node[0], sizeof(std::size_t));
return o.txid ^ (sz2 << 1);
}
};
std::unordered_map< TXOwner, SearchJob, TXOwnerHash > pendingTX;
Key_t ourKey;
};
} // namespace dht
} // namespace llarp
struct llarp_dht_context
{
llarp::dht::Context impl;
llarp_router* parent;
llarp_dht_context(llarp_router* router);
};
#endif

@ -0,0 +1,24 @@
#ifndef LLARP_DHT_KADEMLIA_HPP
#define LLARP_DHT_KADEMLIA_HPP
#include <llarp/dht/key.hpp>
namespace llarp
{
namespace dht
{
struct XorMetric
{
const Key_t& us;
XorMetric(const Key_t& ourKey) : us(ourKey){};
bool
operator()(const Key_t& left, const Key_t& right) const
{
return (us ^ left) < (us ^ right);
};
};
}
}
#endif

@ -0,0 +1,37 @@
#ifndef LLARP_DHT_KEY_HPP
#define LLARP_DHT_KEY_HPP
#include <llarp/aligned.hpp>
namespace llarp
{
namespace dht
{
struct Key_t : public llarp::AlignedBuffer< 32 >
{
Key_t(const byte_t* val) : llarp::AlignedBuffer< 32 >(val)
{
}
Key_t() : llarp::AlignedBuffer< 32 >()
{
}
Key_t
operator^(const Key_t& other) const
{
Key_t dist;
for(size_t idx = 0; idx < 4; ++idx)
dist.l[idx] = l[idx] ^ other.l[idx];
return dist;
}
bool
operator<(const Key_t& other) const
{
return memcmp(data_l(), other.data_l(), 32) < 0;
}
};
}
}
#endif

@ -0,0 +1,41 @@
#ifndef LLARP_DHT_MESSAGE_HPP
#define LLARP_DHT_MESSAGE_HPP
#include <llarp/dht.h>
#include <llarp/bencode.hpp>
#include <llarp/dht/key.hpp>
#include <llarp/path_types.hpp>
#include <vector>
namespace llarp
{
namespace dht
{
constexpr size_t MAX_MSG_SIZE = 2048;
struct IMessage : public llarp::IBEncodeMessage
{
virtual ~IMessage(){};
/// construct
IMessage(const Key_t& from) : From(from)
{
}
virtual bool
HandleMessage(llarp_dht_context* dht,
std::vector< IMessage* >& replies) const = 0;
Key_t From;
PathID_t pathID;
};
IMessage*
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed = false);
bool
DecodeMesssageList(const Key_t& from, llarp_buffer_t* buf,
std::vector< IMessage* >& dst, bool relayed = false);
}
}
#endif

@ -0,0 +1,8 @@
#ifndef LLARP_DHT_MESSAGES_ALL_HPP
#define LLARP_DHT_MESSAGES_ALL_HPP
#include <llarp/dht/messages/findintro.hpp>
#include <llarp/dht/messages/findrouter.hpp>
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/dht/messages/pubintro.hpp>
#endif

@ -0,0 +1,31 @@
#ifndef LLARP_DHT_MESSAGES_FIND_INTRO_HPP
#define LLARP_DHT_MESSAGES_FIND_INTRO_HPP
#include <llarp/dht/message.hpp>
#include <llarp/service/address.hpp>
namespace llarp
{
namespace dht
{
struct FindIntroMessage : public IMessage
{
uint64_t R = 0;
bool iterative = false;
llarp::service::Address S;
uint64_t T = 0;
~FindIntroMessage();
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
};
} // namespace dht
} // namespace llarp
#endif

@ -0,0 +1,54 @@
#ifndef LLARP_DHT_MESSAGES_FIND_ROUTER_HPP
#define LLARP_DHT_MESSAGES_FIND_ROUTER_HPP
#include <llarp/dht/message.hpp>
namespace llarp
{
namespace dht
{
struct FindRouterMessage : public IMessage
{
FindRouterMessage(const Key_t& from) : IMessage(from)
{
}
FindRouterMessage(const Key_t& from, const Key_t& target, uint64_t id)
: IMessage(from), K(target), txid(id)
{
}
~FindRouterMessage();
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
Key_t K;
bool iterative = false;
uint64_t txid = 0;
uint64_t version = 0;
};
/// variant of FindRouterMessage relayed via path
struct RelayedFindRouterMessage : public FindRouterMessage
{
RelayedFindRouterMessage(const Key_t& from) : FindRouterMessage(from)
{
}
/// handle a relayed FindRouterMessage, do a lookup on the dht and inform
/// the path of the result
/// TODO: smart path expiration logic needs to be implemented
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
};
}
}
#endif

@ -0,0 +1,47 @@
#ifndef LLARP_DHT_MESSAGES_GOT_INTRO_HPP
#define LLARP_DHT_MESSAGES_GOT_INTRO_HPP
#include <llarp/dht/message.hpp>
#include <llarp/service/IntroSet.hpp>
namespace llarp
{
namespace dht
{
/// acknologement to PublishIntroMessage or reply to FinIntroMessage
struct GotIntroMessage : public IMessage
{
std::list< llarp::service::IntroSet > I;
uint64_t T = 0;
GotIntroMessage(const Key_t& from) : IMessage(from)
{
}
GotIntroMessage(uint64_t tx, const llarp::service::IntroSet* i = nullptr);
~GotIntroMessage();
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
};
struct RelayedGotIntroMessage : public GotIntroMessage
{
RelayedGotIntroMessage() : GotIntroMessage({})
{
}
bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
};
} // namespace dht
} // namespace llarp
#endif

@ -0,0 +1,43 @@
#ifndef LLARP_DHT_MESSAGES_GOT_ROUTER_HPP
#define LLARP_DHT_MESSAGES_GOT_ROUTER_HPP
#include <llarp/dht/message.hpp>
namespace llarp
{
namespace dht
{
struct GotRouterMessage : public IMessage
{
GotRouterMessage(const Key_t& from) : IMessage(from)
{
}
GotRouterMessage(const Key_t& from, uint64_t id, const llarp_rc* result)
: IMessage(from), txid(id)
{
if(result)
{
R.emplace_back();
llarp_rc_clear(&R.back());
llarp_rc_copy(&R.back(), result);
}
}
~GotRouterMessage();
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
std::vector< llarp_rc > R;
uint64_t txid = 0;
uint64_t version = 0;
};
}
}
#endif

@ -0,0 +1,40 @@
#ifndef LLARP_DHT_MESSAGES_PUB_INTRO_HPP
#define LLARP_DHT_MESSAGES_PUB_INTRO_HPP
#include <llarp/dht/message.hpp>
#include <llarp/service/IntroSet.hpp>
namespace llarp
{
namespace dht
{
struct PublishIntroMessage : public IMessage
{
llarp::service::IntroSet I;
uint64_t R = 0;
uint64_t S = 0;
uint64_t txID = 0;
bool hasS = false;
PublishIntroMessage() : IMessage({})
{
}
PublishIntroMessage(const llarp::service::IntroSet& i, uint64_t tx)
: IMessage({}), txID(tx)
{
I = i;
}
~PublishIntroMessage();
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
};
}
}
#endif

@ -0,0 +1,49 @@
#ifndef LLARP_DHT_NODE_HPP
#define LLARP_DHT_NODE_HPP
#include <llarp/router_contact.h>
#include <llarp/dht/key.hpp>
#include <llarp/service/IntroSet.hpp>
namespace llarp
{
namespace dht
{
struct RCNode
{
llarp_rc* rc;
Key_t ID;
RCNode() : rc(nullptr)
{
ID.Zero();
}
RCNode(llarp_rc* other) : rc(other)
{
ID = other->pubkey;
}
};
struct ISNode
{
llarp::service::IntroSet introset;
Key_t ID;
ISNode()
{
ID.Zero();
}
ISNode(const llarp::service::IntroSet& other)
{
introset = other;
other.A.CalculateAddress(ID);
}
};
}
}
#endif

@ -0,0 +1,53 @@
#ifndef LLARP_DHT_SEARCH_JOB_HPP
#define LLARP_DHT_SEARCH_JOB_HPP
#include <llarp/dht.h>
#include <llarp/time.h>
#include <functional>
#include <llarp/dht/key.hpp>
#include <llarp/service/IntroSet.hpp>
#include <set>
namespace llarp
{
namespace dht
{
struct SearchJob
{
const static uint64_t JobTimeout = 30000;
typedef std::function< void(const llarp::service::IntroSet*) >
IntroSetHookFunc;
SearchJob();
/// for routers
SearchJob(const Key_t& requester, uint64_t requesterTX,
const Key_t& target, const std::set< Key_t >& excludes,
llarp_router_lookup_job* job);
/// for introsets
SearchJob(const Key_t& requester, uint64_t requesterTX,
const Key_t& target, const std::set< Key_t >& excludes,
IntroSetHookFunc found);
void
FoundRouter(const llarp_rc* router) const;
void
FoundIntro(const llarp::service::IntroSet* introset) const;
void
Timeout() const;
bool
IsExpired(llarp_time_t now) const;
// only set if looking up router
llarp_router_lookup_job* job = nullptr;
IntroSetHookFunc foundIntroHook;
llarp_time_t started;
Key_t requester;
uint64_t requesterTX;
Key_t target;
std::set< Key_t > exclude;
};
} // namespace dht
} // namespace llarp
#endif

@ -1,7 +1,6 @@
#ifndef LLARP_DTLS_H_
#define LLARP_DTLS_H_
#include <llarp/link.h>
#include <llarp/mem.h>
/**
@ -12,10 +11,6 @@
* on DTLS
*/
#ifdef __cplusplus
extern "C" {
#endif
/// DTLS configuration
struct llarp_dtls_args
{
@ -29,7 +24,4 @@ void
dtls_link_init(struct llarp_link* link, struct llarp_dtls_args args,
struct llarp_msg_muxer* muxer);
#ifdef __cplusplus
}
#endif
#endif

@ -9,6 +9,6 @@ namespace llarp
DecryptInPlace(const byte_t* symkey, const byte_t* nonce,
llarp_crypto* crypto);
};
}
} // namespace llarp
#endif

@ -13,10 +13,6 @@
* event handler (cross platform high performance event system for IO)
*/
#ifdef __cplusplus
extern "C" {
#endif
// forward declare
struct llarp_threadpool;
struct llarp_logic;
@ -70,7 +66,4 @@ llarp_ev_udp_sendto(struct llarp_udp_io *udp, const struct sockaddr *to,
int
llarp_ev_close_udp(struct llarp_udp_io *udp);
#ifdef __cplusplus
}
#endif
#endif

@ -10,10 +10,6 @@
* utilities for handling exits on the llarp network
*/
#ifdef __cplusplus
extern "C" {
#endif
/// Exit info model
struct llarp_xi
{
@ -60,7 +56,4 @@ struct llarp_xi_list_iter
void
llarp_xi_list_iterate(struct llarp_xi_list *l, struct llarp_xi_list_iter *iter);
#ifdef __cplusplus
}
#endif
#endif

@ -3,9 +3,6 @@
#include <llarp/buffer.h>
#include <llarp/net.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_xr
{
@ -20,7 +17,4 @@ llarp_xr_bencode(struct llarp_xr* xr, llarp_buffer_t* buff);
bool
llarp_xr_bdecode(struct llarp_xr* xr, llarp_buffer_t* buff);
#ifdef __cplusplus
}
#endif
#endif

@ -1,11 +1,7 @@
#ifndef LLARP_IWP_H_
#define LLARP_IWP_H_
#include <llarp/crypto.h>
#include <llarp/link.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "router.hpp"
struct llarp_iwp_args
{
@ -16,10 +12,4 @@ struct llarp_iwp_args
const char* keyfile;
};
void
iwp_link_init(struct llarp_link* link, struct llarp_iwp_args args);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,21 @@
#pragma once
#include "llarp/address_info.h"
struct llarp_link;
struct llarp_link_session;
struct llarp_link_establish_job
{
void *user;
void (*result)(struct llarp_link_establish_job *);
struct llarp_ai ai;
uint64_t timeout;
uint16_t retries;
byte_t pubkey[PUBKEYSIZE];
/** set on success by try_establish */
struct llarp_link *link;
/** set on success by try_establish */
struct llarp_link_session *session;
};

@ -0,0 +1,39 @@
#pragma once
#include "llarp/buffer.h"
enum header_flag
{
eSessionInvalidated = (1 << 0),
eHighPacketDrop = (1 << 1),
eHighMTUDetected = (1 << 2),
eProtoUpgrade = (1 << 3)
};
struct frame_header
{
byte_t *ptr;
frame_header(byte_t *buf);
byte_t *
data();
uint8_t &
version();
uint8_t &
msgtype();
uint16_t
size() const;
void
setsize(uint16_t sz);
uint8_t &
flags();
void
setflag(header_flag f);
};

@ -0,0 +1,112 @@
#pragma once
#include "codel.hpp"
#include "frame_header.hpp"
#include "inbound_message.hpp"
#include "llarp/logger.hpp"
#include "llarp/time.h"
#include "llarp/types.h"
#include "sendbuf.hpp"
#include "transit_message.hpp"
#include <queue>
#include <unordered_map>
enum msgtype
{
eALIV = 0x00,
eXMIT = 0x01,
eACKS = 0x02,
eFRAG = 0x03
};
static inline byte_t *
init_sendbuf(sendbuf_t *buf, msgtype t, uint16_t sz, uint8_t flags)
{
frame_header hdr(buf->data());
hdr.version() = 0;
hdr.msgtype() = t;
hdr.setsize(sz);
buf->data()[4] = 0;
buf->data()[5] = flags;
return hdr.data();
}
struct llarp_router;
struct llarp_link_session;
struct frame_state
{
byte_t rxflags = 0;
byte_t txflags = 0;
uint64_t rxids = 0;
uint64_t txids = 0;
llarp_time_t lastEvent = 0;
std::unordered_map< uint64_t, transit_message * > rx;
std::unordered_map< uint64_t, transit_message * > tx;
typedef std::queue< sendbuf_t * > sendqueue_t;
typedef llarp::util::CoDelQueue<
InboundMessage *, InboundMessage::GetTime, InboundMessage::PutTime,
llarp::util::DummyMutex, llarp::util::DummyLock >
recvqueue_t;
llarp_link_session *parent = nullptr;
sendqueue_t sendqueue;
recvqueue_t recvqueue;
uint64_t nextMsgID = 0;
frame_state(llarp_link_session *session)
: parent(session), recvqueue("iwp_inbound_message")
{
}
/// return true if both sides have the same state flags
bool
flags_agree(byte_t flags) const;
bool
process_inbound_queue();
llarp_router *
Router();
void
clear();
bool
inbound_frame_complete(uint64_t id);
void
push_ackfor(uint64_t id, uint32_t bitmask);
bool
got_xmit(frame_header hdr, size_t sz);
void
alive();
bool
got_frag(frame_header hdr, size_t sz);
bool
got_acks(frame_header hdr, size_t sz);
// queue new outbound message
void
queue_tx(uint64_t id, transit_message *msg);
void
retransmit(llarp_time_t now);
// get next frame to encrypt and transmit
bool
next_frame(llarp_buffer_t *buf);
void
pop_next_frame();
bool
process(byte_t *buf, size_t sz);
};

@ -0,0 +1,59 @@
#pragma once
#include "buffer.hpp"
#include "llarp/time.h"
#include "llarp/types.h"
#include <vector>
struct InboundMessage
{
uint64_t msgid;
std::vector< byte_t > msg;
llarp_time_t queued = 0;
InboundMessage(uint64_t id, const std::vector< byte_t > &m)
: msgid(id), msg(m)
{
}
bool
operator>(const InboundMessage &other) const
{
// order in ascending order for codel queue
return msgid > other.msgid;
}
llarp_buffer_t
Buffer()
{
return llarp::Buffer< decltype(msg) >(msg);
}
struct GetTime
{
llarp_time_t
operator()(const InboundMessage *msg)
{
return msg->queued;
}
};
struct OrderCompare
{
bool
operator()(const InboundMessage *left, const InboundMessage *right)
{
return left->msgid < right->msgid;
}
};
struct PutTime
{
void
operator()(InboundMessage *msg)
{
msg->queued = llarp_time_now_ms();
}
};
};

@ -0,0 +1,38 @@
#pragma once
#include "llarp/buffer.h"
#include <queue>
struct sendbuf_t
{
sendbuf_t(size_t s) : sz(s)
{
_buf = new byte_t[s];
}
~sendbuf_t()
{
if(_buf)
delete[] _buf;
}
size_t sz;
size_t
size() const
{
return sz;
}
byte_t *
data()
{
return _buf;
}
private:
byte_t *_buf = nullptr;
};
typedef std::queue< sendbuf_t * > sendqueue_t;

@ -0,0 +1,480 @@
#pragma once
#include "llarp/iwp.h"
#include "llarp/iwp/establish_job.hpp"
#include "router.hpp"
#include "session.hpp"
#include "str.hpp"
#include <algorithm>
#include <fstream>
#include <mutex>
struct llarp_link
{
typedef std::mutex mtx_t;
typedef std::lock_guard< mtx_t > lock_t;
llarp_router *router;
llarp_crypto *crypto;
llarp_logic *logic;
llarp_ev_loop *netloop;
llarp_async_iwp *iwp;
llarp_threadpool *worker;
llarp_link *parent = nullptr;
llarp_udp_io udp;
llarp::Addr addr;
char keyfile[255];
uint32_t timeout_job_id;
const char *
name() const
{
return m_name;
}
const char *m_name;
typedef std::unordered_map< llarp::Addr, llarp_link_session *,
llarp::addrhash >
LinkMap_t;
LinkMap_t m_sessions;
mtx_t m_sessions_Mutex;
typedef std::unordered_map< llarp::PubKey, llarp::Addr, llarp::PubKeyHash >
SessionMap_t;
SessionMap_t m_Connected;
mtx_t m_Connected_Mutex;
typedef std::unordered_map< llarp::Addr, llarp_link_session *,
llarp::addrhash >
PendingSessionMap_t;
PendingSessionMap_t m_PendingSessions;
mtx_t m_PendingSessions_Mutex;
llarp::SecretKey seckey;
llarp_link(const llarp_iwp_args &args)
: router(args.router)
, crypto(args.crypto)
, logic(args.logic)
, worker(args.cryptoworker)
, m_name("IWP")
{
strncpy(keyfile, args.keyfile, sizeof(keyfile));
iwp = llarp_async_iwp_new(crypto, logic, worker);
}
~llarp_link()
{
llarp_async_iwp_free(iwp);
}
bool
has_intro_from(const llarp::Addr &from)
{
std::unique_lock< std::mutex > lock(m_PendingSessions_Mutex);
return m_PendingSessions.find(from) != m_PendingSessions.end();
}
void
put_intro_from(llarp_link_session *s)
{
std::unique_lock< std::mutex > lock(m_PendingSessions_Mutex);
m_PendingSessions[s->addr] = s;
}
void
remove_intro_from(const llarp::Addr &from)
{
std::unique_lock< std::mutex > lock(m_PendingSessions_Mutex);
m_PendingSessions.erase(from);
}
// set that src address has identity pubkey
void
MapAddr(const llarp::Addr &src, const llarp::PubKey &identity)
{
lock_t lock(m_Connected_Mutex);
m_Connected[identity] = src;
}
static bool
has_session_to(llarp_link *serv, const byte_t *pubkey)
{
llarp::PubKey pk(pubkey);
lock_t lock(serv->m_Connected_Mutex);
return serv->m_Connected.find(pk) != serv->m_Connected.end();
}
void
TickSessions()
{
auto now = llarp_time_now_ms();
{
lock_t lock(m_sessions_Mutex);
std::set< llarp::Addr > remove;
for(auto &itr : m_sessions)
{
llarp_link_session *s = itr.second;
if(s && s->Tick(now))
remove.insert(itr.first);
}
for(const auto &addr : remove)
RemoveSessionByAddr(addr);
}
}
static bool
sendto(llarp_link *serv, const byte_t *pubkey, llarp_buffer_t buf)
{
// lock_t lock(serv->m_Connected_Mutex);
auto itr = serv->m_Connected.find(pubkey);
if(itr != serv->m_Connected.end())
{
// lock_t innerlock(serv->m_sessions_Mutex);
auto inner_itr = serv->m_sessions.find(itr->second);
if(inner_itr != serv->m_sessions.end())
{
llarp_link_session *link = inner_itr->second;
return link->sendto(buf);
}
}
return false;
}
void
UnmapAddr(const llarp::Addr &src)
{
lock_t lock(m_Connected_Mutex);
// std::unordered_map< llarp::pubkey, llarp::Addr, llarp::pubkeyhash >
auto itr = std::find_if(
m_Connected.begin(), m_Connected.end(),
[src](const std::pair< llarp::PubKey, llarp::Addr > &item) -> bool {
return src == item.second;
});
if(itr == std::end(m_Connected))
return;
// tell router we are done with this session
router->SessionClosed(itr->first);
m_Connected.erase(itr);
}
llarp_link_session *
create_session(llarp::Addr src)
{
return new llarp_link_session(this, seckey, src);
}
bool
has_session_to(const llarp::Addr &dst)
{
lock_t lock(m_sessions_Mutex);
return m_sessions.find(dst) != m_sessions.end();
}
llarp_link_session *
find_session(const llarp::Addr &addr)
{
lock_t lock(m_sessions_Mutex);
auto itr = m_sessions.find(addr);
if(itr == m_sessions.end())
return nullptr;
else
return itr->second;
}
void
put_session(const llarp::Addr &src, llarp_link_session *impl)
{
lock_t lock(m_sessions_Mutex);
m_sessions.emplace(src, impl);
impl->our_router = &router->rc;
}
void
clear_sessions()
{
lock_t lock(m_sessions_Mutex);
auto itr = m_sessions.begin();
while(itr != m_sessions.end())
{
delete itr->second;
itr = m_sessions.erase(itr);
}
}
static void
handle_logic_pump(void *user)
{
llarp_link *self = static_cast< llarp_link * >(user);
lock_t lock(self->m_sessions_Mutex);
auto itr = self->m_sessions.begin();
while(itr != self->m_sessions.end())
{
itr->second->TickLogic();
++itr;
}
}
void
PumpLogic()
{
llarp_logic_queue_job(logic, {this, &handle_logic_pump});
}
void
RemoveSessionByAddr(const llarp::Addr &addr)
{
auto itr = m_sessions.find(addr);
if(itr != m_sessions.end())
{
llarp::LogDebug("removing session ", addr);
UnmapAddr(addr);
llarp_link_session *s = itr->second;
s->done();
m_sessions.erase(itr);
delete s;
}
}
uint8_t *
pubkey()
{
return llarp::seckey_topublic(seckey);
}
bool
ensure_privkey()
{
llarp::LogDebug("ensure transport private key at ", keyfile);
std::error_code ec;
if(!fs::exists(keyfile, ec))
{
if(!keygen(keyfile))
return false;
}
std::ifstream f(keyfile);
if(f.is_open())
{
f.read((char *)seckey.data(), seckey.size());
return true;
}
return false;
}
bool
keygen(const char *fname)
{
crypto->encryption_keygen(seckey);
llarp::LogInfo("new transport key generated");
std::ofstream f(fname);
if(f.is_open())
{
f.write((char *)seckey.data(), seckey.size());
return true;
}
return false;
}
static void
handle_cleanup_timer(void *l, uint64_t orig, uint64_t left)
{
if(left)
return;
llarp_link *link = static_cast< llarp_link * >(l);
link->timeout_job_id = 0;
link->TickSessions();
link->issue_cleanup_timer(orig);
}
// this is called in net threadpool
static void
handle_recvfrom(struct llarp_udp_io *udp, const struct sockaddr *saddr,
const void *buf, ssize_t sz)
{
llarp_link *link = static_cast< llarp_link * >(udp->user);
llarp_link_session *s = link->find_session(*saddr);
if(s == nullptr)
{
// new inbound session
s = link->create_session(*saddr);
}
s->recv(buf, sz);
}
void
cancel_timer()
{
if(timeout_job_id)
{
llarp_logic_cancel_call(logic, timeout_job_id);
}
timeout_job_id = 0;
}
void
issue_cleanup_timer(uint64_t timeout)
{
timeout_job_id = llarp_logic_call_later(
logic, {timeout, this, &llarp_link::handle_cleanup_timer});
}
void
get_our_address(struct llarp_ai *addr)
{
addr->rank = 1;
strncpy(addr->dialect, "IWP", sizeof(addr->dialect));
memcpy(addr->enc_key, pubkey(), 32);
memcpy(addr->ip.s6_addr, this->addr.addr6(), 16);
addr->port = this->addr.port();
}
static void
after_recv(llarp_udp_io *udp)
{
llarp_link *self = static_cast< llarp_link * >(udp->user);
self->PumpLogic();
}
bool
configure(struct llarp_ev_loop *netloop, const char *ifname, int af,
uint16_t port)
{
if(!ensure_privkey())
{
llarp::LogError("failed to ensure private key");
return false;
}
llarp::LogDebug("configure link ifname=", ifname, " af=", af,
" port=", port);
// bind
sockaddr_in ip4addr;
sockaddr_in6 ip6addr;
sockaddr *addr = nullptr;
switch(af)
{
case AF_INET:
addr = (sockaddr *)&ip4addr;
llarp::Zero(addr, sizeof(ip4addr));
break;
case AF_INET6:
addr = (sockaddr *)&ip6addr;
llarp::Zero(addr, sizeof(ip6addr));
break;
// TODO: AF_PACKET
default:
llarp::LogError(__FILE__, "unsupported address family", af);
return false;
}
addr->sa_family = af;
if(!llarp::StrEq(ifname, "*"))
{
if(!llarp_getifaddr(ifname, af, addr))
{
llarp::LogError("failed to get address of network interface ", ifname);
return false;
}
}
else
m_name = "OWP"; // outboundLink_name;
switch(af)
{
case AF_INET:
ip4addr.sin_port = htons(port);
break;
case AF_INET6:
ip6addr.sin6_port = htons(port);
break;
// TODO: AF_PACKET
default:
return false;
}
this->addr = *addr;
this->netloop = netloop;
udp.recvfrom = &llarp_link::handle_recvfrom;
udp.user = this;
udp.tick = &llarp_link::after_recv;
llarp::LogDebug("bind IWP link to ", addr);
if(llarp_ev_add_udp(netloop, &udp, addr) == -1)
{
llarp::LogError("failed to bind to ", addr);
return false;
}
return true;
}
bool
start_link(struct llarp_logic *logic)
{
// give link implementations
// link->parent = l;
timeout_job_id = 0;
logic = logic;
// start cleanup timer
issue_cleanup_timer(500);
return true;
}
bool
stop_link()
{
cancel_timer();
llarp_ev_close_udp(&udp);
clear_sessions();
return true;
}
void
iter_sessions(llarp_link_session_iter iter)
{
auto sz = m_sessions.size();
if(sz)
{
llarp::LogDebug("we have ", sz, "sessions");
iter.link = this;
// TODO: race condition with cleanup timer
for(auto &item : m_sessions)
if(item.second)
if(!iter.visit(&iter, item.second))
return;
}
}
bool
try_establish(struct llarp_link_establish_job *job)
{
llarp::Addr dst(job->ai);
llarp::LogDebug("establish session to ", dst);
llarp_link_session *s = find_session(dst);
if(s == nullptr)
{
s = create_session(dst);
put_session(dst, s);
}
else
return false;
s->establish_job = job;
s->frame.alive(); // mark it alive
s->introduce(job->ai.enc_key);
return true;
}
void
mark_session_active(llarp_link_session *s)
{
s->frame.alive();
}
};

@ -0,0 +1,178 @@
#pragma once
#include "codel.hpp"
#include "frame_state.hpp"
#include "llarp/buffer.h"
#include "llarp/crypto.hpp"
#include "llarp/crypto_async.h"
#include "llarp/router_contact.h"
#include "llarp/time.h"
#include "llarp/types.h"
#include "net.hpp"
struct llarp_udp_io;
struct llarp_async_iwp;
struct llarp_logic;
struct llarp_link;
struct transit_message;
struct llarp_link_establish_job;
struct llarp_link_session
{
static constexpr llarp_time_t SESSION_TIMEOUT = 10000;
static constexpr llarp_time_t KEEP_ALIVE_INTERVAL = SESSION_TIMEOUT / 4;
static constexpr size_t MAX_PAD = 128;
llarp_link_session(llarp_link *l, const byte_t *seckey, const llarp::Addr &a);
~llarp_link_session();
void
session_start();
bool sendto(llarp_buffer_t);
bool
has_timed_out();
bool
timedout(llarp_time_t now, llarp_time_t timeout = SESSION_TIMEOUT);
void
close();
void
session_established();
llarp_link *
get_parent();
llarp_rc *
get_remote_router();
bool
CheckRCValid();
bool
IsEstablished();
void
send_LIM();
bool
is_invalidated() const;
void
done();
void
pump();
void
introduce(uint8_t *pub);
void
intro_ack();
void
on_intro_ack(const void *buf, size_t sz);
void
on_intro(const void *buf, size_t sz);
void
on_session_start(const void *buf, size_t sz);
void
encrypt_frame_async_send(const void *buf, size_t sz);
// void send_keepalive(void *user);
bool
Tick(llarp_time_t now);
void
PumpCryptoOutbound();
// process inbound and outbound queues (logic thread)
void
TickLogic();
// this is called from net thread
void
recv(const void *buf, size_t sz);
llarp_router *
Router();
llarp_udp_io *udp;
llarp_crypto *crypto;
llarp_async_iwp *iwp;
llarp_logic *logic;
llarp_link *serv = nullptr;
llarp_rc *our_router = nullptr;
llarp_rc remote_router;
llarp::SecretKey eph_seckey;
llarp::PubKey remote;
llarp::SharedSecret sessionkey;
llarp_link_establish_job *establish_job = nullptr;
/// cached timestamp for frame creation
llarp_time_t now;
llarp_time_t lastKeepalive = 0;
uint32_t establish_job_id = 0;
uint32_t frames = 0;
bool working = false;
llarp::util::CoDelQueue< iwp_async_frame *, FrameGetTime, FramePutTime >
outboundFrames;
/*
std::mutex m_EncryptedFramesMutex;
std::queue< iwp_async_frame > encryptedFrames;
*/
llarp::util::CoDelQueue< iwp_async_frame *, FrameGetTime, FramePutTime >
decryptedFrames;
uint32_t pump_send_timer_id = 0;
uint32_t pump_recv_timer_id = 0;
llarp::Addr addr;
iwp_async_intro intro;
iwp_async_introack introack;
iwp_async_session_start start;
// frame_state frame;
bool started_inbound_codel = false;
byte_t token[32];
byte_t workbuf[MAX_PAD + 128];
enum State
{
eInitial,
eIntroRecv,
eIntroSent,
eIntroAckSent,
eIntroAckRecv,
eSessionStartSent,
eLIMSent,
eEstablished,
eTimeout
};
State state;
void
EnterState(State st);
void
add_outbound_message(uint64_t id, transit_message *msg);
void
EncryptOutboundFrames();
iwp_async_frame *
alloc_frame(const void *buf, size_t sz);
void
decrypt_frame(const void *buf, size_t sz);
static void
handle_frame_decrypt(iwp_async_frame *f);
frame_state frame;
};
struct llarp_link_session_iter
{
void *user;
struct llarp_link *link;
bool (*visit)(struct llarp_link_session_iter *, struct llarp_link_session *);
};

@ -0,0 +1,72 @@
#pragma once
#include "llarp/types.h"
#include "sendbuf.hpp"
#include "xmit.hpp"
#include <bitset>
#include <unordered_map>
#include <vector>
struct transit_message
{
xmit msginfo;
std::bitset< 32 > status = {};
typedef std::vector< byte_t > fragment_t;
std::unordered_map< byte_t, fragment_t > frags;
fragment_t lastfrag;
llarp_time_t lastAck = 0;
llarp_time_t started;
void
clear();
// calculate acked bitmask
uint32_t
get_bitmask() const;
// outbound
transit_message(llarp_buffer_t buf, const byte_t *hash, uint64_t id,
uint16_t mtu = 1024);
// inbound
transit_message(const xmit &x);
/// ack packets based off a bitmask
void
ack(uint32_t bitmask);
bool
should_send_ack(llarp_time_t now) const;
bool
should_resend_frags(llarp_time_t now) const;
bool
should_resend_xmit(llarp_time_t now) const;
bool
completed() const;
// template < typename T >
void
generate_xmit(sendqueue_t &queue, byte_t flags = 0);
// template < typename T >
void
retransmit_frags(sendqueue_t &queue, byte_t flags = 0);
bool
reassemble(std::vector< byte_t > &buffer);
void
put_message(llarp_buffer_t buf, const byte_t *hash, uint64_t id,
uint16_t mtu = 1024);
void
put_lastfrag(byte_t *buf, size_t sz);
bool
put_frag(byte_t fragno, byte_t *buf);
};

@ -0,0 +1,43 @@
#pragma once
#include "llarp/buffer.h"
struct xmit
{
byte_t buffer[48];
xmit() = default;
xmit(byte_t *ptr);
xmit(const xmit &other);
void
set_info(const byte_t *hash, uint64_t id, uint16_t fragsz, uint16_t lastsz,
uint8_t numfrags, uint8_t flags = 0x01);
const byte_t *
hash() const;
uint64_t
msgid() const;
// size of each full fragment
uint16_t
fragsize() const;
// number of full fragments
uint8_t
numfrags() const;
// size of the entire message
size_t
totalsize() const;
// size of the last fragment
uint16_t
lastfrag() const;
uint8_t
flags();
};

@ -1,127 +0,0 @@
#ifndef LLARP_LINK_H_
#define LLARP_LINK_H_
#include <llarp/address_info.h>
#include <llarp/crypto.h>
#include <llarp/ev.h>
#include <llarp/logic.h>
#include <llarp/mem.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** 2^15 bytes */
#define MAX_LINK_MSG_SIZE (32768)
/**
* wire layer transport interface
*/
struct llarp_link;
/**
* wire layer transport session for point to point communication between us
* and another
*/
struct llarp_link_session;
/** outbound session establish job */
struct llarp_link_establish_job
{
void *user;
void (*result)(struct llarp_link_establish_job *);
struct llarp_ai ai;
uint64_t timeout;
uint16_t retries;
byte_t pubkey[PUBKEYSIZE];
/** set on success by try_establish */
struct llarp_link *link;
/** set on success by try_establish */
struct llarp_link_session *session;
};
struct llarp_link_session_iter
{
void *user;
struct llarp_link *link;
bool (*visit)(struct llarp_link_session_iter *, struct llarp_link_session *);
};
struct llarp_link_ev_listener
{
void *user;
void (*established)(struct llarp_link_ev_listener *,
struct llarp_link_session *, bool);
void (*timeout)(struct llarp_link_ev_listener *, struct llarp_link_session *,
bool);
void (*tx)(struct llarp_link_ev_listener *, struct llarp_link_session *,
size_t);
void (*rx)(struct llarp_link_ev_listener *, struct llarp_link_session *,
size_t);
void (*error)(struct llarp_link_ev_listener *, struct llarp_link_session *,
const char *);
};
// forward declare
struct llarp_router;
struct llarp_link
{
void *impl;
struct llarp_router *router;
const char *(*name)(void);
void (*get_our_address)(struct llarp_link *, struct llarp_ai *);
/*
int (*register_listener)(struct llarp_link *, struct
llarp_link_ev_listener); void (*deregister_listener)(struct llarp_link *,
int);
*/
bool (*configure)(struct llarp_link *, struct llarp_ev_loop *, const char *,
int, uint16_t);
bool (*start_link)(struct llarp_link *, struct llarp_logic *);
bool (*stop_link)(struct llarp_link *);
void (*iter_sessions)(struct llarp_link *, struct llarp_link_session_iter);
bool (*try_establish)(struct llarp_link *, struct llarp_link_establish_job *);
/// send to already established session given its public identity key
/// returns false if we don't have this session
/// returns true if the messages were queued
bool (*sendto)(struct llarp_link *, const byte_t *, llarp_buffer_t);
/// return true if we have a session to router given public identity key
bool (*has_session_to)(struct llarp_link *, const byte_t *);
void (*mark_session_active)(struct llarp_link *, struct llarp_link_session *);
void (*free_impl)(struct llarp_link *);
};
/** checks if all members are initialized */
bool
llarp_link_initialized(struct llarp_link *link);
struct llarp_link_session
{
void *impl;
/** send an entire message, splits up into smaller pieces and does
* encryption
*/
bool (*sendto)(struct llarp_link_session *, llarp_buffer_t);
/** return true if this session is timed out */
bool (*timeout)(struct llarp_link_session *);
/** explicit close session */
void (*close)(struct llarp_link_session *);
/** set session established */
void (*established)(struct llarp_link_session *);
/** get parent link */
struct llarp_link *(*get_parent)(struct llarp_link_session *);
/** get router contact of remote router */
struct llarp_rc *(*get_remote_router)(struct llarp_link_session *);
};
bool
llarp_link_session_initialized(struct llarp_link_session *s);
#ifdef __cplusplus
}
#endif
#endif

@ -1,13 +1,16 @@
#ifndef LLARP_LINK_MESSAGE_HPP
#define LLARP_LINK_MESSAGE_HPP
#include <llarp/link.h>
#include <llarp/bencode.hpp>
#include <llarp/router_id.hpp>
#include <queue>
#include <vector>
struct llarp_router;
struct llarp_link_session;
struct llarp_link_session_iter;
namespace llarp
{
struct ILinkMessage;

@ -1,10 +1,6 @@
#ifndef LLARP_LOGGER_H
#define LLARP_LOGGER_H
#ifdef __cplusplus
extern "C" {
#endif
enum LogLevel
{
eLogDebug,
@ -16,8 +12,4 @@ enum LogLevel
void
cSetLogLevel(enum LogLevel lvl);
#ifdef __cplusplus
}
#endif
#endif

@ -3,11 +3,12 @@
#include <llarp/mem.h>
#include <llarp/threadpool.h>
#include <llarp/timer.h>
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_logic;
struct llarp_logic
{
struct llarp_threadpool* thread;
struct llarp_timer_context* timer;
};
struct llarp_logic*
llarp_init_logic();
@ -43,7 +44,4 @@ llarp_logic_stop(struct llarp_logic* logic);
void
llarp_logic_mainloop(struct llarp_logic* logic);
#ifdef __cplusplus
}
#endif
#endif

@ -4,16 +4,8 @@
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/** constant time memcmp */
bool
llarp_eq(const void *a, const void *b, size_t sz);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,16 @@
#ifndef LLARP_MESSAGES_HIDDEN_SERIVCE_HPP
#define LLARP_MESSAGES_HIDDEN_SERIVCE_HPP
#include <llarp/routing/message.hpp>
namespace llarp
{
namespace routing
{
struct HiddenServiceFrame : public IMessage
{
};
} // namespace routing
} // namespace llarp
#endif

@ -22,6 +22,6 @@ namespace llarp
bool
HandleMessage(llarp_router* router) const;
};
}
} // namespace llarp
#endif

@ -7,14 +7,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
bool
llarp_getifaddr(const char* ifname, int af, struct sockaddr* addr);
#ifdef __cplusplus
}
#endif
#endif

@ -10,10 +10,6 @@
* persistent storage API for router contacts
*/
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_nodedb;
/// create an empty nodedb
@ -139,7 +135,4 @@ struct llarp_async_load_rc
void
llarp_nodedb_async_load_rc(struct llarp_async_load_rc *job);
#ifdef __cplusplus
}
#endif
#endif

@ -7,10 +7,6 @@
#define DEFAULT_PATH_LIFETIME (10 * 60 * 1000)
#define PATH_BUILD_TIMEOUT (30 * 1000)
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_path_hop
{
struct llarp_rc router;
@ -28,7 +24,4 @@ struct llarp_path_hops
void
llarp_path_hops_free(struct llarp_path_hops* hops);
#ifdef __cplusplus
}
#endif
#endif

@ -14,7 +14,9 @@
#include <llarp/router_id.hpp>
#include <llarp/routing/handler.hpp>
#include <llarp/routing/message.hpp>
#include <llarp/service/Intro.hpp>
#include <functional>
#include <list>
#include <map>
#include <mutex>
@ -158,10 +160,10 @@ namespace llarp
llarp_router* r);
bool
HandleDHTMessage(const llarp::dht::IMessage* msg, llarp_router* r);
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg);
bool
HandleHiddenServiceData(llarp_buffer_t buf, llarp_router* r);
HandleDHTMessage(const llarp::dht::IMessage* msg, llarp_router* r);
// handle data in upstream direction
bool
@ -200,6 +202,9 @@ namespace llarp
typedef std::function< void(Path*) > BuildResultHookFunc;
typedef std::vector< PathHopConfig > HopList;
HopList hops;
llarp::service::Introduction intro;
llarp_time_t buildStarted;
PathStatus status;
@ -230,13 +235,13 @@ namespace llarp
llarp_router* r);
bool
HandleDHTMessage(const llarp::dht::IMessage* msg, llarp_router* r);
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg);
bool
HandleRoutingMessage(llarp_buffer_t buf, llarp_router* r);
HandleDHTMessage(const llarp::dht::IMessage* msg, llarp_router* r);
bool
HandleHiddenServiceData(llarp_buffer_t buf, llarp_router* r);
HandleRoutingMessage(llarp_buffer_t buf, llarp_router* r);
// handle data in upstream direction
bool
@ -246,6 +251,9 @@ namespace llarp
bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
bool
IsReady() const;
// Is this deprecated?
// nope not deprecated :^DDDD
const PathID_t&
@ -257,8 +265,6 @@ namespace llarp
RouterID
Upstream() const;
llarp_time_t Latency = 0;
protected:
llarp::routing::InboundMessageParser m_InboundMessageParser;
@ -320,6 +326,9 @@ namespace llarp
IHopHandler*
GetByDownstream(const RouterID& id, const PathID_t& path);
PathSet*
GetLocalPathSet(const PathID_t& id);
bool
ForwardLRCM(const RouterID& nextHop,
std::deque< EncryptedFrame >& frames);

@ -10,10 +10,6 @@
* path api functions
*/
#ifdef __cplusplus
extern "C" {
#endif
/// forard declare
struct llarp_router;
struct llarp_dht_context;
@ -24,7 +20,7 @@ struct llarp_pathbuilder_context;
/// alloc
struct llarp_pathbuilder_context*
llarp_pathbuilder_context_new(struct llarp_router* router,
struct llarp_dht_context* dht);
struct llarp_dht_context* dht, size_t numpaths);
/// dealloc
void
llarp_pathbuilder_context_free(struct llarp_pathbuilder_context* ctx);
@ -62,7 +58,4 @@ struct llarp_pathbuild_job
void
llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job);
#ifdef __cplusplus
}
#endif
#endif

@ -1,6 +1,8 @@
#ifndef LLARP_PATHFINDER_HPP_
#define LLARP_PATHFINDER_HPP_
#ifndef LLARP_PATHBUILDER_HPP_
#define LLARP_PATHBUILDER_HPP_
#include <llarp/pathbuilder.h>
#include <llarp/router.h>
#include <llarp/pathset.hpp>
struct llarp_pathbuilder_context : public llarp::path::PathSet
{
@ -8,7 +10,9 @@ struct llarp_pathbuilder_context : public llarp::path::PathSet
struct llarp_dht_context* dht;
/// construct
llarp_pathbuilder_context(llarp_router* p_router,
struct llarp_dht_context* p_dht);
struct llarp_dht_context* p_dht, size_t numPaths);
virtual ~llarp_pathbuilder_context(){};
void
BuildOne();

@ -1,12 +1,21 @@
#ifndef LLARP_PATHSET_HPP
#define LLARP_PATHSET_HPP
#include <llarp/time.h>
#include <functional>
#include <list>
#include <llarp/path_types.hpp>
#include <llarp/router_id.hpp>
#include <llarp/service/IntroSet.hpp>
#include <map>
#include <tuple>
namespace llarp
{
namespace dht
{
struct GotIntroMessage;
}
namespace path
{
enum PathStatus
@ -52,12 +61,49 @@ namespace llarp
bool
ShouldBuildMore() const;
/// return true if we should publish a new hidden service descriptor
bool
ShouldPublishDescriptors() const;
virtual bool
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg)
{
return false;
}
Path*
PickRandomEstablishedPath();
bool
GetCurrentIntroductions(
std::list< llarp::service::Introduction >& intros) const;
bool
PublishIntroSet(const llarp::service::IntroSet& introset,
llarp_router* r);
typedef std::function< void(const llarp::service::IntroSet*) >
ServiceLookupHandler;
/// return false if we are already pending a lookup for this address
bool
LookupService(const llarp::service::Address& addr,
ServiceLookupHandler handler);
protected:
void
IssueServiceLookup(const llarp::service::Address& addr);
private:
typedef std::pair< RouterID, PathID_t > PathInfo_t;
typedef std::map< PathInfo_t, Path* > PathMap_t;
size_t m_NumPaths;
PathMap_t m_Paths;
uint64_t m_CurrentPublishTX = 0;
std::unordered_map< llarp::service::Address, ServiceLookupHandler,
llarp::service::Address::Hash >
m_ServiceLookups;
};
} // namespace path

@ -1,34 +1,37 @@
#ifndef LLARP_POW_HPP
#define LLARP_POW_HPP
#include <llarp/buffer.h>
#include <llarp/crypto.h>
#include <llarp/bencode.hpp>
#include <llarp/router_id.hpp>
namespace llarp
{
/// proof of work
struct PoW
struct PoW : public IBEncodeMessage
{
static constexpr size_t MaxSize = 128;
RouterID router;
uint64_t version = 0;
uint32_t extendedLifetime = 0;
uint64_t timestamp = 0;
uint32_t extendedLifetime = 0;
AlignedBuffer< 32 > nonce;
~PoW();
bool
BEncode(llarp_buffer_t* buf) const;
IsValid(llarp_shorthash_func hashfunc) const;
bool
BDecode(llarp_buffer_t* buf);
bool
IsValid(llarp_shorthash_func hashfunc, const RouterID& us) const;
DecodeKey(llarp_buffer_t k, llarp_buffer_t* val);
bool
BEncode(llarp_buffer_t* buf) const;
bool
operator==(const PoW& other) const
{
return router == other.router && version == other.version
return timestamp == other.timestamp && version == other.version
&& extendedLifetime == other.extendedLifetime && nonce == other.nonce;
}

@ -1,21 +0,0 @@
#ifndef LLARP_QUIC_H_
#define LLARP_QUIC_H_
#include <llarp/link.h>
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_quic_args
{
};
bool
quic_link_init(struct llarp_link* link, struct llarp_quic_args args,
struct llarp_msg_muxer* muxer);
#ifdef __cplusplus
}
#endif
#endif

@ -2,17 +2,12 @@
#define LLARP_ROUTER_H_
#include <llarp/config.h>
#include <llarp/ev.h>
#include <llarp/link.h>
#include <llarp/logic.h>
#include <llarp/nodedb.h>
#include <llarp/pathbuilder.h>
#include <llarp/router_contact.h>
#include <llarp/threadpool.h>
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_router;
bool
@ -54,8 +49,4 @@ void
llarp_router_iterate_links(struct llarp_router *router,
struct llarp_router_link_iter iter);
#ifdef __cplusplus
}
#endif
#endif

@ -3,9 +3,6 @@
#include <llarp/address_info.h>
#include <llarp/crypto.h>
#include <llarp/exit_info.h>
#ifdef __cplusplus
extern "C" {
#endif
// forward declare
struct llarp_alloc;
@ -29,7 +26,6 @@ struct llarp_rc
byte_t signature[SIGSIZE];
uint64_t last_updated;
#ifdef __cplusplus
bool
BEncode(llarp_buffer_t *buf) const
{
@ -41,7 +37,6 @@ struct llarp_rc
{
return llarp_rc_bdecode(this, buf);
}
#endif
};
void
@ -87,7 +82,4 @@ llarp_rc_read(const char *fpath);
bool
llarp_rc_write(struct llarp_rc *rc, const char *our_rc_file);
#ifdef __cplusplus
}
#endif
#endif

@ -4,6 +4,7 @@
#include <llarp/buffer.h>
#include <llarp/router.h>
#include <llarp/dht.hpp>
#include <llarp/messages/hidden_service.hpp>
#include <llarp/messages/path_confirm.hpp>
#include <llarp/messages/path_latency.hpp>
#include <llarp/messages/path_transfer.hpp>
@ -16,23 +17,24 @@ namespace llarp
struct IMessageHandler
{
virtual bool
HandlePathTransferMessage(const PathTransferMessage* msg,
llarp_router* r) = 0;
HandlePathTransferMessage(const PathTransferMessage *msg,
llarp_router *r) = 0;
virtual bool
HandleHiddenServiceData(llarp_buffer_t buf, llarp_router* r) = 0;
HandleHiddenServiceFrame(const HiddenServiceFrame *msg)
{
return false;
}
virtual bool
HandlePathConfirmMessage(const PathConfirmMessage* msg,
llarp_router* r) = 0;
HandlePathConfirmMessage(const PathConfirmMessage *msg,
llarp_router *r) = 0;
virtual bool
HandlePathLatencyMessage(const PathLatencyMessage* msg,
llarp_router* r) = 0;
HandlePathLatencyMessage(const PathLatencyMessage *msg,
llarp_router *r) = 0;
virtual bool
HandleDHTMessage(const llarp::dht::IMessage* msg, llarp_router* r) = 0;
HandleDHTMessage(const llarp::dht::IMessage *msg, llarp_router *r) = 0;
};
} // namespace routing
} // namespace llarp

@ -22,6 +22,7 @@ namespace llarp
struct InboundMessageParser
{
llarp::PathID_t from;
InboundMessageParser();
bool
ParseMessageBuffer(llarp_buffer_t buf, IMessageHandler* handler,

@ -13,6 +13,6 @@ namespace llarp
{
virtual ~IRoutingEndpoint(){};
};
}
} // namespace llarp
#endif

@ -1,179 +1,12 @@
#ifndef LLARP_SERVICE_HPP
#define LLARP_SERVICE_HPP
#include <llarp/aligned.hpp>
#include <llarp/bencode.hpp>
#include <llarp/crypto.hpp>
#include <llarp/path_types.hpp>
#include <llarp/pow.hpp>
#include <iostream>
#include <set>
#include <string>
namespace llarp
{
namespace service
{
constexpr std::size_t MAX_INTROSET_SIZE = 1024;
// forward declare
struct IntroSet;
/// hidden service address
typedef llarp::AlignedBuffer< 32 > Address;
std::string
AddressToString(const Address& addr);
typedef llarp::AlignedBuffer< 16 > VanityNonce;
struct ServiceInfo : public llarp::IBEncodeMessage
{
llarp::PubKey enckey;
llarp::PubKey signkey;
uint64_t version = 0;
VanityNonce vanity;
ServiceInfo();
~ServiceInfo();
ServiceInfo&
operator=(const ServiceInfo& other)
{
enckey = other.enckey;
signkey = other.signkey;
version = other.version;
vanity = other.vanity;
return *this;
};
friend std::ostream&
operator<<(std::ostream& out, const ServiceInfo& i)
{
return out << "[e=" << i.enckey << " s=" << i.signkey
<< " v=" << i.version << " x=" << i.vanity << "]";
}
/// calculate our address
bool
CalculateAddress(Address& addr) const;
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
};
// private keys
struct Identity : public llarp::IBEncodeMessage
{
llarp::SecretKey enckey;
llarp::SecretKey signkey;
uint64_t version = 0;
VanityNonce vanity;
// public service info
ServiceInfo pub;
~Identity();
// regenerate secret keys
void
RegenerateKeys(llarp_crypto* c);
// load from file
bool
LoadFromFile(const std::string& fpath);
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
SignIntroSet(IntroSet& i, llarp_crypto* c) const;
};
struct Introduction : public llarp::IBEncodeMessage
{
llarp::PubKey router;
llarp::PathID_t pathID;
uint64_t version = 0;
uint64_t expiresAt;
~Introduction();
friend std::ostream&
operator<<(std::ostream& out, const Introduction& i)
{
return out << "k=" << i.router << " p=" << i.pathID
<< " v=" << i.version << " x=" << i.expiresAt;
}
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
operator<(const Introduction& other) const
{
return expiresAt < other.expiresAt || pathID < other.pathID;
}
};
struct IntroSet : public llarp::IBEncodeMessage
{
ServiceInfo A;
std::set< Introduction > I;
uint64_t V = 0;
llarp::PoW* W = nullptr;
llarp::Signature Z;
~IntroSet();
IntroSet&
operator=(const IntroSet& other)
{
A = other.A;
I = other.I;
V = other.V;
if(W)
delete W;
W = other.W;
Z = other.Z;
return *this;
}
friend std::ostream&
operator<<(std::ostream& out, const IntroSet& i)
{
out << "A=[" << i.A << "] I=[";
for(const auto& intro : i.I)
{
out << intro << ",";
}
return out << "] V=" << i.V << " Z=" << i.Z;
}
bool
BDecode(llarp_buffer_t* buf);
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
VerifySignature(llarp_crypto* crypto) const;
};
}; // namespace service
} // namespace llarp
#include <llarp/service/Identity.hpp>
#include <llarp/service/Intro.hpp>
#include <llarp/service/IntroSet.hpp>
#include <llarp/service/config.hpp>
#include <llarp/service/context.hpp>
#include <llarp/service/endpoint.hpp>
#include <llarp/service/types.hpp>
#endif

@ -0,0 +1,49 @@
#ifndef LLARP_SERVICE_IDENTITY_HPP
#define LLARP_SERVICE_IDENTITY_HPP
#include <llarp/bencode.hpp>
#include <llarp/crypto.hpp>
#include <llarp/service/Info.hpp>
#include <llarp/service/IntroSet.hpp>
#include <llarp/service/types.hpp>
namespace llarp
{
namespace service
{
// private keys
struct Identity : public llarp::IBEncodeMessage
{
llarp::SecretKey enckey;
llarp::SecretKey signkey;
uint64_t version = 0;
VanityNonce vanity;
// public service info
ServiceInfo pub;
~Identity();
// regenerate secret keys
void
RegenerateKeys(llarp_crypto* c);
// load from file
bool
LoadFromFile(const std::string& fpath);
bool
BEncode(llarp_buffer_t* buf) const;
bool
EnsureKeys(const std::string& fpath, llarp_crypto* c);
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
SignIntroSet(IntroSet& i, llarp_crypto* c) const;
};
} // namespace service
} // namespace llarp
#endif

@ -0,0 +1,59 @@
#ifndef LLARP_SERVICE_INFO_HPP
#define LLARP_SERVICE_INFO_HPP
#include <llarp/bencode.hpp>
#include <llarp/crypto.hpp>
#include <llarp/service/types.hpp>
namespace llarp
{
namespace service
{
struct ServiceInfo : public llarp::IBEncodeMessage
{
llarp::PubKey enckey;
llarp::PubKey signkey;
uint64_t version = 0;
VanityNonce vanity;
ServiceInfo();
~ServiceInfo();
bool
operator==(const ServiceInfo& other) const
{
return enckey == other.enckey && signkey == other.signkey
&& version == other.version && vanity == other.vanity;
}
ServiceInfo&
operator=(const ServiceInfo& other)
{
enckey = other.enckey;
signkey = other.signkey;
version = other.version;
vanity = other.vanity;
return *this;
};
friend std::ostream&
operator<<(std::ostream& out, const ServiceInfo& i)
{
return out << "[e=" << i.enckey << " s=" << i.signkey
<< " v=" << i.version << " x=" << i.vanity << "]";
}
/// calculate our address
bool
CalculateAddress(byte_t* buf) const;
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
};
} // namespace service
} // namespace llarp
#endif

@ -0,0 +1,55 @@
#ifndef LLARP_SERVICE_INTRO_HPP
#define LLARP_SERVICE_INTRO_HPP
#include <llarp/bencode.hpp>
#include <llarp/crypto.hpp>
#include <llarp/path_types.hpp>
#include <iostream>
namespace llarp
{
namespace service
{
struct Introduction : public llarp::IBEncodeMessage
{
llarp::PubKey router;
llarp::PathID_t pathID;
uint64_t latency = 0;
uint64_t version = 0;
uint64_t expiresAt = 0;
Introduction() = default;
Introduction(const Introduction& other)
{
router = other.router;
pathID = other.pathID;
latency = other.latency;
version = other.version;
expiresAt = other.expiresAt;
}
~Introduction();
friend std::ostream&
operator<<(std::ostream& out, const Introduction& i)
{
return out << "k=" << i.router << " p=" << i.pathID
<< " v=" << i.version << " x=" << i.expiresAt;
}
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
operator<(const Introduction& other) const
{
return expiresAt < other.expiresAt || pathID < other.pathID;
}
};
} // namespace service
} // namespace llarp
#endif

@ -0,0 +1,63 @@
#ifndef LLARP_SERVICE_INTROSET_HPP
#define LLARP_SERVICE_INTROSET_HPP
#include <iostream>
#include <llarp/bencode.hpp>
#include <llarp/crypto.hpp>
#include <llarp/pow.hpp>
#include <llarp/service/Info.hpp>
#include <llarp/service/Intro.hpp>
#include <list>
namespace llarp
{
namespace service
{
constexpr std::size_t MAX_INTROSET_SIZE = 1024;
struct IntroSet : public llarp::IBEncodeMessage
{
ServiceInfo A;
std::list< Introduction > I;
llarp::PoW* W = nullptr;
llarp::Signature Z;
~IntroSet();
IntroSet&
operator=(const IntroSet& other)
{
A = other.A;
I = other.I;
version = other.version;
if(W)
delete W;
W = other.W;
Z = other.Z;
return *this;
}
friend std::ostream&
operator<<(std::ostream& out, const IntroSet& i)
{
out << "A=[" << i.A << "] I=[";
for(const auto& intro : i.I)
{
out << intro << ",";
}
return out << "] V=" << i.version << " Z=" << i.Z;
}
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
VerifySignature(llarp_crypto* crypto) const;
};
} // namespace service
} // namespace llarp
#endif

@ -0,0 +1,38 @@
#ifndef LLARP_SERVICE_ADDRESS_HPP
#define LLARP_SERVICE_ADDRESS_HPP
#include <llarp/aligned.hpp>
#include <llarp/dht/key.hpp>
#include <string>
namespace llarp
{
namespace service
{
struct Address : public llarp::AlignedBuffer< 32 >
{
std::string
ToString() const;
Address() : llarp::AlignedBuffer< 32 >()
{
}
Address(const byte_t* data) : llarp::AlignedBuffer< 32 >(data)
{
}
struct Hash
{
size_t
operator()(const Address& addr) const
{
size_t idx = 0;
memcpy(&idx, addr, sizeof(idx));
return idx;
}
};
};
} // namespace service
} // namespace llarp
#endif

@ -0,0 +1,23 @@
#ifndef LLARP_SERVICE_CONFIG_HPP
#define LLARP_SERVICE_CONFIG_HPP
#include <list>
#include <string>
namespace llarp
{
namespace service
{
struct Config
{
typedef std::list< std::pair< std::string, std::string > >
section_values_t;
typedef std::pair< std::string, section_values_t > section_t;
std::list< section_t > services;
bool
Load(const std::string& fname);
};
}
}
#endif

@ -0,0 +1,30 @@
#ifndef LLARP_SERVICE_CONTEXT_HPP
#define LLARP_SERVICE_CONTEXT_HPP
#include <llarp/router.h>
#include <llarp/service/config.hpp>
#include <llarp/service/endpoint.hpp>
#include <unordered_map>
namespace llarp
{
namespace service
{
/// holds all the hidden service endpoints we own
struct Context
{
Context(llarp_router *r);
~Context();
void
Tick();
bool
AddEndpoint(const Config::section_t &conf);
private:
llarp_router *m_Router;
std::unordered_map< std::string, Endpoint * > m_Endpoints;
};
}
}
#endif

@ -0,0 +1,96 @@
#ifndef LLARP_SERVICE_ENDPOINT_HPP
#define LLARP_SERVICE_ENDPOINT_HPP
#include <llarp/messages/hidden_service.hpp>
#include <llarp/pathbuilder.hpp>
#include <llarp/service/Identity.hpp>
namespace llarp
{
namespace service
{
struct Endpoint : public llarp_pathbuilder_context
{
Endpoint(const std::string& nickname, llarp_router* r);
~Endpoint();
bool
SetOption(const std::string& k, const std::string& v);
void
Tick();
bool
Start();
bool
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg);
bool
HandleHiddenServiceFrame(const llarp::routing::HiddenServiceFrame* msg);
/// return true if we have an established path to a hidden service
bool
HasPathToService(const Address& remote) const;
/// return false if we don't have a path to the service
/// return true if we did and we removed it
bool
ForgetPathToService(const Address& remote);
/// context needed to initiate an outbound hidden service session
struct OutboundContext : public llarp_pathbuilder_context
{
OutboundContext(Endpoint* parent);
~OutboundContext();
/// the remote hidden service's curren intro set
IntroSet currentIntroSet;
uint64_t sequenceNo = 0;
/// encrypt asynchronously and send to remote endpoint from us
/// returns false if we cannot send yet otherwise returns true
bool
AsyncEncryptAndSendTo(llarp_buffer_t D);
/// issues a lookup to find the current intro set of the remote service
void
UpdateIntroSet();
bool
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg);
private:
llarp::SharedSecret sharedKey;
Endpoint* m_Parent;
};
// passed a sendto context when we have a path established otherwise
// nullptr if the path was not made before the timeout
typedef std::function< void(OutboundContext*) > PathEnsureHook;
/// return false if we have already called this function before for this
/// address
bool
EnsurePathToService(const Address& remote, PathEnsureHook h,
uint64_t timeoutMS);
virtual bool
HandleAuthenticatedDataFrom(const Address& remote, llarp_buffer_t data)
{
/// TODO: imlement me
return true;
}
private:
llarp_router* m_Router;
std::string m_Keyfile;
std::string m_Name;
Identity m_Identity;
std::unordered_map< Address, OutboundContext*, Address::Hash >
m_RemoteSessions;
};
} // namespace service
} // namespace llarp
#endif

@ -0,0 +1,6 @@
#ifndef LLARP_SERVICE_TYPES_HPP
#define LLARP_SERVICE_TYPES_HPP
#include <llarp/service/address.hpp>
#include <llarp/service/vanity.hpp>
#endif

@ -0,0 +1,14 @@
#ifndef LLARP_SERVICE_VANITY_HPP
#define LLARP_SERVICE_VANITY_HPP
#include <llarp/aligned.hpp>
namespace llarp
{
namespace service
{
/// hidden service address
typedef llarp::AlignedBuffer< 16 > VanityNonce;
}
}
#endif

@ -1,9 +1,6 @@
#ifndef LLARP_STRING_H
#define LLARP_STRING_H
#include <llarp/common.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __FreeBSD__
#if !(__APPLE__ && __MACH__)
@ -18,7 +15,4 @@ strnlen(const char* str, size_t sz)
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

@ -1,8 +1,5 @@
#ifndef LLARP_THREADPOOL_H
#define LLARP_THREADPOOL_H
#ifdef __cplusplus
extern "C" {
#endif
struct llarp_threadpool;
@ -26,8 +23,6 @@ struct llarp_thread_job
/** called in threadpool worker thread */
llarp_thread_work_func work;
#ifdef __cplusplus
llarp_thread_job(void *u, llarp_thread_work_func w) : user(u), work(w)
{
}
@ -35,8 +30,6 @@ struct llarp_thread_job
llarp_thread_job() : user(nullptr), work(nullptr)
{
}
#endif
};
/// for single process mode
@ -55,8 +48,4 @@ llarp_threadpool_join(struct llarp_threadpool *tp);
void
llarp_threadpool_wait(struct llarp_threadpool *tp);
#ifdef __cplusplus
}
#endif
#endif

@ -1,16 +1,10 @@
#ifndef LLARP_TIME_H
#define LLARP_TIME_H
#include <llarp/types.h>
#ifdef __cplusplus
extern "C" {
#endif
llarp_time_t
llarp_time_now_ms();
llarp_seconds_t
llarp_time_now_sec();
#ifdef __cplusplus
}
#endif
#endif

@ -2,9 +2,6 @@
#define LLARP_TIMER_H
#include <llarp/common.h>
#include <llarp/threadpool.h>
#ifdef __cplusplus
extern "C" {
#endif
/** called with userptr, original timeout, left */
typedef void (*llarp_timer_handler_func)(void *, uint64_t, uint64_t);
@ -47,7 +44,4 @@ llarp_timer_tick_all(struct llarp_timer_context *t,
void
llarp_free_timer(struct llarp_timer_context **t);
#ifdef __cplusplus
}
#endif
#endif

@ -2,15 +2,8 @@
#define LLARP_TYPES_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint8_t llarp_proto_version_t;
typedef uint64_t llarp_time_t;
typedef uint64_t llarp_seconds_t;
#ifdef __cplusplus
}
#endif
#endif

@ -117,8 +117,6 @@ llarp_ai_list_iter_bencode(struct llarp_ai_list_iter *iter, struct llarp_ai *ai)
return llarp_ai_bencode(ai, static_cast< llarp_buffer_t * >(iter->user));
}
extern "C" {
bool
llarp_ai_bdecode(struct llarp_ai *ai, llarp_buffer_t *buff)
{
@ -261,4 +259,3 @@ llarp_ai_list_bdecode(struct llarp_ai_list *l, llarp_buffer_t *buff)
.buffer = nullptr, .user = l, .on_item = &llarp_ai_list_bdecode_item};
return bencode_read_list(buff, &r);
}
}

@ -81,8 +81,11 @@ bencode_read_integer(struct llarp_buffer_t* buffer, uint64_t* result)
buffer->cur++;
numbuf[len] = 0;
*result = atol(numbuf);
return *result != -1;
auto num = atol(numbuf);
if(num == -1)
return false;
*result = num;
return true;
}
bool

@ -2,8 +2,6 @@
#include <stdarg.h>
#include <stdio.h>
extern "C" {
size_t
llarp_buffer_size_left(llarp_buffer_t buff)
{
@ -78,4 +76,3 @@ llarp_buffer_eq(llarp_buffer_t buf, const char* str)
}
return *str == 0;
}
}

@ -37,6 +37,6 @@ namespace llarp
buff.sz = t.size();
return buff;
}
}
} // namespace llarp
#endif

@ -1,6 +1,8 @@
#ifndef LLARP_CODEL_QUEUE_HPP
#define LLARP_CODEL_QUEUE_HPP
#include <llarp/time.h>
#include "llarp/logger.hpp"
#include <cmath>
#include <functional>
#include <mutex>

@ -28,6 +28,7 @@ namespace llarp
connect = find_section(top, "connect", section_t{});
netdb = find_section(top, "netdb", section_t{});
iwp_links = find_section(top, "bind", section_t{});
services = find_section(top, "services", section_t{});
return true;
}
return false;
@ -35,8 +36,6 @@ namespace llarp
} // namespace llarp
extern "C" {
void
llarp_new_config(struct llarp_config **conf)
{
@ -68,7 +67,8 @@ llarp_config_iter(struct llarp_config *conf, struct llarp_config_iterator *iter)
{"network", conf->impl.network},
{"connect", conf->impl.connect},
{"bind", conf->impl.iwp_links},
{"netdb", conf->impl.netdb}};
{"netdb", conf->impl.netdb},
{"services", conf->impl.services}};
for(const auto item : conf->impl.router)
iter->visit(iter, "router", item.first.c_str(), item.second.c_str());
@ -78,4 +78,3 @@ llarp_config_iter(struct llarp_config *conf, struct llarp_config_iterator *iter)
iter->visit(iter, section.first.c_str(), item.first.c_str(),
item.second.c_str());
}
}

@ -16,17 +16,17 @@ namespace llarp
section_t netdb;
section_t iwp_links;
section_t connect;
section_t services;
bool
Load(const char *fname);
};
} // namespace llarp
extern "C" {
struct llarp_config
{
llarp::Config impl;
};
}
#endif

@ -1,4 +1,5 @@
#include <llarp.h>
#include <llarp/logger.h>
#include <signal.h>
#include <llarp.hpp>
#include "logger.hpp"
@ -160,11 +161,6 @@ namespace llarp
llarp::LogError("Failed to configure router");
return 1;
}
if(custom_dht_func)
{
llarp::LogInfo("using custom dht function");
llarp_dht_set_msg_handler(router->dht, custom_dht_func);
}
// set nodedb, load our RC, establish DHT
llarp_run_router(router, nodedb);
@ -298,7 +294,6 @@ namespace llarp
}
} // namespace llarp
extern "C" {
struct llarp_main
{
std::unique_ptr< llarp::Context > ctx;
@ -309,7 +304,11 @@ llarp_main_init(const char *fname, bool multiProcess)
{
if(!fname)
fname = "daemon.ini";
char *var = getenv("LLARP_DEBUG");
if(var && *var == '1')
{
cSetLogLevel(eLogDebug);
}
llarp_main *m = new llarp_main;
m->ctx.reset(new llarp::Context(std::cout, !multiProcess));
if(!m->ctx->LoadConfig(fname))
@ -321,12 +320,6 @@ llarp_main_init(const char *fname, bool multiProcess)
return m;
}
void
llarp_main_set_dht_handler(struct llarp_main *ptr, llarp_dht_msg_handler func)
{
ptr->ctx->custom_dht_func = func;
}
void
llarp_main_signal(struct llarp_main *ptr, int sig)
{
@ -442,4 +435,3 @@ llarp_main_free(struct llarp_main *ptr)
{
delete ptr;
}
}

@ -208,6 +208,7 @@ namespace iwp
iwp_async_session_start *session =
static_cast< iwp_async_session_start * >(user);
auto crypto = session->iwp->crypto;
auto logic = session->iwp->logic;
auto dh = crypto->transport_dh_client;
auto shorthash = crypto->shorthash;
@ -248,8 +249,8 @@ namespace iwp
buf.base = (session->buf + 32);
buf.sz = session->sz - 32;
hmac(session->buf, buf, e_K);
session->hook(session);
// llarp_logic_queue_job(logic, {user, &inform_session_start});
// session->hook(session);
llarp_logic_queue_job(logic, {user, &inform_session_start});
}
void
@ -258,6 +259,7 @@ namespace iwp
iwp_async_session_start *session =
static_cast< iwp_async_session_start * >(user);
auto crypto = session->iwp->crypto;
auto logic = session->iwp->logic;
auto dh = crypto->transport_dh_server;
auto shorthash = crypto->shorthash;
@ -313,8 +315,8 @@ namespace iwp
}
else // hmac fail
session->buf = nullptr;
session->hook(session);
// llarp_logic_queue_job(logic, {user, &inform_session_start});
// session->hook(session);
llarp_logic_queue_job(logic, {user, &inform_session_start});
}
void
@ -345,7 +347,6 @@ namespace iwp
}
} // namespace iwp
extern "C" {
void
iwp_call_async_keygen(struct llarp_async_iwp *iwp,
struct iwp_async_keygen *keygen)
@ -490,4 +491,3 @@ llarp_async_iwp_free(struct llarp_async_iwp *iwp)
{
delete iwp;
}
}

@ -131,7 +131,6 @@ namespace llarp
} // namespace llarp
extern "C" {
const byte_t *
llarp_seckey_topublic(const byte_t *secret)
{
@ -160,4 +159,3 @@ llarp_crypto_libsodium_init(struct llarp_crypto *c)
c->randbytes(&seed, sizeof(seed));
srand(seed);
}
}

@ -1,865 +1,57 @@
#include <llarp/bencode.hpp>
#include <llarp/dht.hpp>
#include <llarp/messages/dht.hpp>
#include <llarp/messages/dht_immediate.hpp>
#include <llarp/dht.h>
#include "router.hpp"
#include "router_contact.hpp"
#include <sodium.h>
#include <algorithm> // std::find
#include <set>
namespace llarp
{
DHTImmeidateMessage::~DHTImmeidateMessage()
{
for(auto &msg : msgs)
delete msg;
msgs.clear();
}
bool
DHTImmeidateMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
{
if(llarp_buffer_eq(key, "m"))
return llarp::dht::DecodeMesssageList(remote.data(), buf, msgs);
if(llarp_buffer_eq(key, "v"))
{
if(!bencode_read_integer(buf, &version))
return false;
return version == LLARP_PROTO_VERSION;
}
// bad key
return false;
}
bool
DHTImmeidateMessage::BEncode(llarp_buffer_t *buf) const
{
if(!bencode_start_dict(buf))
return false;
// message type
if(!bencode_write_bytestring(buf, "a", 1))
return false;
if(!bencode_write_bytestring(buf, "m", 1))
return false;
// dht messages
if(!bencode_write_bytestring(buf, "m", 1))
return false;
// begin list
if(!bencode_start_list(buf))
return false;
for(const auto &msg : msgs)
{
if(!msg->BEncode(buf))
return false;
}
// end list
if(!bencode_end(buf))
return false;
// protocol version
if(!bencode_write_version_entry(buf))
return false;
return bencode_end(buf);
}
bool
DHTImmeidateMessage::HandleMessage(llarp_router *router) const
{
DHTImmeidateMessage *reply = new DHTImmeidateMessage(remote);
bool result = true;
for(auto &msg : msgs)
{
result &= msg->HandleMessage(router->dht, reply->msgs);
}
return result && router->SendToOrQueue(remote.data(), reply);
}
namespace dht
{
struct PathLookupInformer
{
llarp_router *router;
PathID_t pathID;
uint64_t txid;
PathLookupInformer(llarp_router *r, const PathID_t &id, uint64_t tx)
: router(r), pathID(id), txid(tx)
{
}
void
SendReply(const llarp::routing::IMessage *msg)
{
auto path = router->paths.GetByUpstream(router->pubkey(), pathID);
if(path == nullptr)
{
llarp::LogWarn("Path not found for relayed DHT message txid=", txid,
" pathid=", pathID);
return;
}
if(!path->SendRoutingMessage(msg, router))
llarp::LogWarn("Failed to send reply for relayed DHT message txid=",
txid, "pathid=", pathID);
}
static void
InformReply(llarp_router_lookup_job *job)
{
PathLookupInformer *self =
static_cast< PathLookupInformer * >(job->user);
llarp::routing::DHTMessage reply;
if(job->found)
{
if(llarp_rc_verify_sig(&self->router->crypto, &job->result))
{
reply.M.push_back(
new GotRouterMessage(job->target, self->txid, &job->result));
}
llarp_rc_free(&job->result);
llarp_rc_clear(&job->result);
}
else
{
reply.M.push_back(
new GotRouterMessage(job->target, self->txid, nullptr));
}
self->SendReply(&reply);
// TODO: is this okay?
delete self;
delete job;
}
};
/// variant of FindRouterMessage relayed via path
struct RelayedFindRouterMessage : public FindRouterMessage
{
RelayedFindRouterMessage(const Key_t &from) : FindRouterMessage(from)
{
}
/// handle a relayed FindRouterMessage, do a lookup on the dht and inform
/// the path of the result
/// TODO: smart path expiration logic needs to be implemented
virtual bool
HandleMessage(llarp_dht_context *ctx, std::vector< IMessage * > &replies)
{
auto &dht = ctx->impl;
/// lookup for us, send an immeidate reply
if(K == dht.OurKey())
{
auto path = dht.router->paths.GetByUpstream(K, pathID);
if(path)
{
llarp::routing::DHTMessage reply;
reply.M.push_back(new GotRouterMessage(K, txid, &dht.router->rc));
return path->SendRoutingMessage(&reply, dht.router);
}
return false;
}
llarp_router_lookup_job *job = new llarp_router_lookup_job;
PathLookupInformer *informer =
new PathLookupInformer(dht.router, pathID, txid);
job->user = informer;
job->hook = &PathLookupInformer::InformReply;
job->found = false;
job->dht = ctx;
memcpy(job->target, K, sizeof(job->target));
Key_t peer;
if(dht.nodes->FindClosest(K, peer))
dht.LookupRouter(K, dht.OurKey(), txid, peer, job);
return false;
}
};
PublishIntroMessage::~PublishIntroMessage()
{
}
bool
PublishIntroMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
{
bool read = false;
if(!BEncodeMaybeReadDictEntry("I", I, read, key, val))
return false;
if(!BEncodeMaybeReadDictInt("R", R, read, key, val))
return false;
if(llarp_buffer_eq(key, "S"))
{
read = true;
hasS = true;
if(!bencode_read_integer(val, &S))
return false;
}
if(!BEncodeMaybeReadDictInt("V", V, read, key, val))
return false;
return read;
}
bool
PublishIntroMessage::HandleMessage(llarp_dht_context *ctx,
std::vector< IMessage * > &replies) const
{
auto &dht = ctx->impl;
if(!I.VerifySignature(&dht.router->crypto))
{
llarp::LogWarn("invalid introset signature");
return false;
}
return false;
}
bool
PublishIntroMessage::BEncode(llarp_buffer_t *buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "I"))
return false;
if(!BEncodeWriteDictEntry("I", I, buf))
return false;
if(!BEncodeWriteDictInt(buf, "R", R))
return false;
if(hasS)
{
if(!BEncodeWriteDictInt(buf, "S", S))
return false;
}
if(!BEncodeWriteDictInt(buf, "V", LLARP_PROTO_VERSION))
return false;
return bencode_end(buf);
}
GotRouterMessage::~GotRouterMessage()
{
for(auto &rc : R)
llarp_rc_free(&rc);
R.clear();
}
bool
GotRouterMessage::BEncode(llarp_buffer_t *buf) const
{
if(!bencode_start_dict(buf))
return false;
// message type
if(!BEncodeWriteDictMsgType(buf, "A", "S"))
return false;
if(!BEncodeWriteDictList("R", R, buf))
return false;
// txid
if(!BEncodeWriteDictInt(buf, "T", txid))
return false;
// version
if(!BEncodeWriteDictInt(buf, "V", version))
return false;
return bencode_end(buf);
}
bool
GotRouterMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
{
if(llarp_buffer_eq(key, "R"))
{
return BEncodeReadList(R, val);
}
if(llarp_buffer_eq(key, "T"))
{
return bencode_read_integer(val, &txid);
}
bool read = false;
if(!BEncodeMaybeReadVersion("V", version, LLARP_PROTO_VERSION, read, key,
val))
return false;
return read;
}
bool
GotRouterMessage::HandleMessage(llarp_dht_context *ctx,
std::vector< IMessage * > &replies) const
{
auto &dht = ctx->impl;
auto pending = dht.FindPendingTX(From, txid);
if(pending)
{
if(R.size())
{
pending->Completed(&R[0]);
if(pending->requester != dht.OurKey())
{
replies.push_back(new GotRouterMessage(
pending->target, pending->requesterTX, &R[0]));
}
}
else
{
// iterate to next closest peer
Key_t nextPeer;
pending->exclude.insert(From);
if(pending->exclude.size() < 3
&& dht.nodes->FindCloseExcluding(pending->target, nextPeer,
pending->exclude))
{
llarp::LogInfo(pending->target, " was not found via ", From,
" iterating to next peer ", nextPeer,
" already asked ", pending->exclude.size(),
" other peers");
dht.LookupRouter(pending->target, pending->requester,
pending->requesterTX, nextPeer, nullptr, true,
pending->exclude);
}
else
{
llarp::LogInfo(pending->target, " was not found via ", From,
" and we won't look it up");
pending->Completed(nullptr);
if(pending->requester != dht.OurKey())
{
replies.push_back(new GotRouterMessage(
pending->target, pending->requesterTX, nullptr));
}
}
}
dht.RemovePendingLookup(From, txid);
return true;
}
llarp::LogWarn(
"Got response for DHT transaction we are not tracking, txid=", txid);
return false;
}
FindRouterMessage::~FindRouterMessage()
{
}
bool
FindRouterMessage::BEncode(llarp_buffer_t *buf) const
{
if(!bencode_start_dict(buf))
return false;
// message type
if(!bencode_write_bytestring(buf, "A", 1))
return false;
if(!bencode_write_bytestring(buf, "R", 1))
return false;
// iterative or not?
if(!bencode_write_bytestring(buf, "I", 1))
return false;
if(!bencode_write_int(buf, iterative ? 1 : 0))
return false;
// key
if(!bencode_write_bytestring(buf, "K", 1))
return false;
if(!bencode_write_bytestring(buf, K.data(), K.size()))
return false;
// txid
if(!bencode_write_bytestring(buf, "T", 1))
return false;
if(!bencode_write_uint64(buf, txid))
return false;
// version
if(!bencode_write_bytestring(buf, "V", 1))
return false;
if(!bencode_write_uint64(buf, version))
return false;
return bencode_end(buf);
}
bool
FindRouterMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *val)
{
llarp_buffer_t strbuf;
if(llarp_buffer_eq(key, "I"))
{
uint64_t result;
if(!bencode_read_integer(val, &result))
return false;
iterative = result != 0;
return true;
}
if(llarp_buffer_eq(key, "K"))
{
if(!bencode_read_string(val, &strbuf))
return false;
if(strbuf.sz != K.size())
return false;
memcpy(K.data(), strbuf.base, K.size());
return true;
}
if(llarp_buffer_eq(key, "T"))
{
return bencode_read_integer(val, &txid);
}
if(llarp_buffer_eq(key, "V"))
{
return bencode_read_integer(val, &version);
}
return false;
}
bool
FindRouterMessage::HandleMessage(llarp_dht_context *ctx,
std::vector< IMessage * > &replies) const
{
auto &dht = ctx->impl;
if(!dht.allowTransit)
{
llarp::LogWarn("Got DHT lookup from ", From,
" when we are not allowing dht transit");
return false;
}
auto pending = dht.FindPendingTX(From, txid);
if(pending)
{
llarp::LogWarn("Got duplicate DHT lookup from ", From, " txid=", txid);
return false;
}
dht.LookupRouterRelayed(From, txid, K, !iterative, replies);
return true;
}
struct MessageDecoder
{
const Key_t &From;
bool firstKey = true;
IMessage *msg = nullptr;
bool relayed = false;
MessageDecoder(const Key_t &from) : From(from)
{
}
static bool
on_key(dict_reader *r, llarp_buffer_t *key)
{
llarp_buffer_t strbuf;
MessageDecoder *dec = static_cast< MessageDecoder * >(r->user);
// check for empty dict
if(!key)
return !dec->firstKey;
// first key
if(dec->firstKey)
{
if(!llarp_buffer_eq(*key, "A"))
return false;
if(!bencode_read_string(r->buffer, &strbuf))
return false;
// bad msg size?
if(strbuf.sz != 1)
return false;
switch(*strbuf.base)
{
case 'R':
if(dec->relayed)
dec->msg = new RelayedFindRouterMessage(dec->From);
else
dec->msg = new FindRouterMessage(dec->From);
break;
case 'S':
if(dec->relayed)
{
llarp::LogWarn(
"GotRouterMessage found when parsing relayed DHT "
"message");
return false;
}
else
dec->msg = new GotRouterMessage(dec->From);
break;
case 'I':
dec->msg = new PublishIntroMessage();
break;
default:
llarp::LogWarn("unknown dht message type: ", (char)*strbuf.base);
// bad msg type
return false;
}
dec->firstKey = false;
return dec->msg != nullptr;
}
else
return dec->msg->DecodeKey(*key, r->buffer);
}
};
IMessage *
DecodeMesssage(const Key_t &from, llarp_buffer_t *buf, bool relayed)
{
MessageDecoder dec(from);
dec.relayed = relayed;
dict_reader r;
r.user = &dec;
r.on_key = &MessageDecoder::on_key;
if(bencode_read_dict(buf, &r))
return dec.msg;
else
{
if(dec.msg)
delete dec.msg;
return nullptr;
}
}
struct ListDecoder
{
ListDecoder(const Key_t &from, std::vector< IMessage * > &list)
: From(from), l(list){};
bool relayed = false;
const Key_t &From;
std::vector< IMessage * > &l;
static bool
on_item(list_reader *r, bool has)
{
ListDecoder *dec = static_cast< ListDecoder * >(r->user);
if(!has)
return true;
auto msg = DecodeMesssage(dec->From, r->buffer, dec->relayed);
if(msg)
{
dec->l.push_back(msg);
return true;
}
else
return false;
}
};
bool
DecodeMesssageList(const Key_t &from, llarp_buffer_t *buf,
std::vector< IMessage * > &list, bool relayed)
{
ListDecoder dec(from, list);
dec.relayed = relayed;
list_reader r;
r.user = &dec;
r.on_item = &ListDecoder::on_item;
return bencode_read_list(buf, &r);
}
SearchJob::SearchJob()
{
started = 0;
requester.Zero();
target.Zero();
}
SearchJob::SearchJob(const Key_t &asker, uint64_t tx, const Key_t &key,
llarp_router_lookup_job *j,
const std::set< Key_t > &excludes)
: job(j)
, started(llarp_time_now_ms())
, requester(asker)
, requesterTX(tx)
, target(key)
, exclude(excludes)
{
}
void
SearchJob::Completed(const llarp_rc *router, bool timeout) const
{
if(job && job->hook)
{
if(router)
{
job->found = true;
llarp_rc_copy(&job->result, router);
}
job->hook(job);
}
}
bool
SearchJob::IsExpired(llarp_time_t now) const
{
return now - started >= JobTimeout;
}
Context::Context()
{
randombytes((byte_t *)&ids, sizeof(uint64_t));
}
Context::~Context()
{
if(nodes)
delete nodes;
if(services)
delete services;
}
void
Context::handle_cleaner_timer(void *u, uint64_t orig, uint64_t left)
{
if(left)
return;
Context *ctx = static_cast< Context * >(u);
ctx->CleanupTX();
ctx->ScheduleCleanupTimer();
}
void
Context::LookupRouterRelayed(const Key_t &requester, uint64_t txid,
const Key_t &target, bool recursive,
std::vector< IMessage * > &replies)
{
if(target == ourKey)
{
// we are the target, give them our RC
replies.push_back(new GotRouterMessage(requester, txid, &router->rc));
return;
}
Key_t next;
std::set< Key_t > excluding = {requester, ourKey};
if(nodes->FindCloseExcluding(target, next, excluding))
{
if(next == target)
{
// we know it
replies.push_back(
new GotRouterMessage(requester, txid, nodes->nodes[target].rc));
}
else if(recursive) // are we doing a recursive lookup?
{
if((requester ^ target) < (ourKey ^ target))
{
// we aren't closer to the target than next hop
// so we won't ask neighboor recursively, tell them we don't have it
llarp::LogInfo("we aren't closer to ", target, " than ", next,
" so we end it here");
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
}
else
{
// yeah, ask neighboor recursively
LookupRouter(target, requester, txid, next);
}
}
else // otherwise tell them we don't have it
{
llarp::LogInfo("we don't have ", target,
" and this was an iterative request so telling ",
requester, " that we don't have it");
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
}
}
else
{
// we don't know it and have no closer peers
llarp::LogInfo("we don't have ", target,
" and have no closer peers so telling ", requester,
" that we don't have it");
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
}
}
void
Context::RemovePendingLookup(const Key_t &owner, uint64_t id)
{
TXOwner search;
search.node = owner;
search.txid = id;
auto itr = pendingTX.find(search);
if(itr == pendingTX.end())
return;
pendingTX.erase(itr);
}
SearchJob *
Context::FindPendingTX(const Key_t &owner, uint64_t id)
{
TXOwner search;
search.node = owner;
search.txid = id;
auto itr = pendingTX.find(search);
if(itr == pendingTX.end())
return nullptr;
else
return &itr->second;
}
void
Context::CleanupTX()
{
auto now = llarp_time_now_ms();
llarp::LogDebug("DHT tick");
auto itr = pendingTX.begin();
while(itr != pendingTX.end())
{
if(itr->second.IsExpired(now))
{
itr->second.Completed(nullptr, true);
itr = pendingTX.erase(itr);
}
else
++itr;
}
}
void
Context::Init(const Key_t &us, llarp_router *r)
{
router = r;
ourKey = us;
nodes = new Bucket< RCNode >(ourKey);
services = new Bucket< ISNode >(ourKey);
llarp::LogDebug("intialize dht with key ", ourKey);
}
void
Context::ScheduleCleanupTimer()
{
llarp_logic_call_later(router->logic,
{1000, this, &handle_cleaner_timer});
}
bool
Context::RelayRequestForPath(const llarp::PathID_t &id, const IMessage *msg)
{
llarp::routing::DHTMessage reply;
if(!msg->HandleMessage(router->dht, reply.M))
return false;
auto path = router->paths.GetByUpstream(router->pubkey(), id);
return path && path->SendRoutingMessage(&reply, router);
}
void
Context::LookupRouter(const Key_t &target, const Key_t &whoasked,
uint64_t txid, const Key_t &askpeer,
llarp_router_lookup_job *job, bool iterative,
std::set< Key_t > excludes)
{
if(target.IsZero() || whoasked.IsZero() || askpeer.IsZero())
{
return;
}
auto id = ++ids;
TXOwner ownerKey;
ownerKey.node = askpeer;
ownerKey.txid = id;
if(txid == 0)
txid = id;
pendingTX[ownerKey] = SearchJob(whoasked, txid, target, job, excludes);
llarp::LogInfo("Asking ", askpeer, " for router ", target, " for ",
whoasked);
auto msg = new llarp::DHTImmeidateMessage(askpeer);
auto dhtmsg = new FindRouterMessage(askpeer, target, id);
dhtmsg->iterative = iterative;
msg->msgs.push_back(dhtmsg);
router->SendToOrQueue(askpeer, msg);
}
void
Context::LookupRouterViaJob(llarp_router_lookup_job *job)
{
Key_t peer;
if(nodes->FindClosest(job->target, peer))
LookupRouter(job->target, ourKey, 0, peer, job);
else if(job->hook)
{
job->found = false;
job->hook(job);
}
}
void
Context::queue_router_lookup(void *user)
{
llarp_router_lookup_job *job =
static_cast< llarp_router_lookup_job * >(user);
job->dht->impl.LookupRouterViaJob(job);
}
} // namespace dht
} // namespace llarp
llarp_dht_context::llarp_dht_context(llarp_router *router)
{
parent = router;
}
extern "C"
struct llarp_dht_context *
llarp_dht_context_new(struct llarp_router *router)
{
struct llarp_dht_context *
llarp_dht_context_new(struct llarp_router *router)
{
return new llarp_dht_context(router);
}
void
llarp_dht_context_free(struct llarp_dht_context *ctx)
{
delete ctx;
}
return new llarp_dht_context(router);
}
void
llarp_dht_put_peer(struct llarp_dht_context *ctx, struct llarp_rc *rc)
void
llarp_dht_context_free(struct llarp_dht_context *ctx)
{
delete ctx;
}
{
llarp::dht::RCNode n(rc);
ctx->impl.nodes->PutNode(n);
}
void
llarp_dht_put_peer(struct llarp_dht_context *ctx, struct llarp_rc *rc)
void
llarp_dht_remove_peer(struct llarp_dht_context *ctx, const byte_t *id)
{
llarp::dht::Key_t k = id;
ctx->impl.nodes->DelNode(k);
}
{
llarp::dht::RCNode n(rc);
ctx->impl.nodes->PutNode(n);
}
void
llarp_dht_set_msg_handler(struct llarp_dht_context *ctx,
llarp_dht_msg_handler handler)
{
ctx->impl.custom_handler = handler;
}
void
llarp_dht_remove_peer(struct llarp_dht_context *ctx, const byte_t *id)
{
llarp::dht::Key_t k = id;
ctx->impl.nodes->DelNode(k);
}
void
llarp_dht_allow_transit(llarp_dht_context *ctx)
{
ctx->impl.allowTransit = true;
}
void
llarp_dht_allow_transit(llarp_dht_context *ctx)
{
ctx->impl.allowTransit = true;
}
void
llarp_dht_context_start(struct llarp_dht_context *ctx, const byte_t *key)
{
ctx->impl.Init(key, ctx->parent);
}
void
llarp_dht_context_start(struct llarp_dht_context *ctx, const byte_t *key)
{
ctx->impl.Init(key, ctx->parent);
}
void
llarp_dht_lookup_router(struct llarp_dht_context *ctx,
struct llarp_router_lookup_job *job)
{
job->dht = ctx;
job->found = false;
llarp_logic_queue_job(ctx->parent->logic,
{job, &llarp::dht::Context::queue_router_lookup});
}
void
llarp_dht_lookup_router(struct llarp_dht_context *ctx,
struct llarp_router_lookup_job *job)
{
job->dht = ctx;
job->found = false;
llarp_logic_queue_job(ctx->parent->logic,
{job, &llarp::dht::Context::queue_router_lookup});
}

@ -0,0 +1,210 @@
#include <llarp/dht/context.hpp>
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/messages/dht.hpp>
#include <llarp/messages/dht_immediate.hpp>
#include "router.hpp"
namespace llarp
{
namespace dht
{
Context::Context()
{
randombytes((byte_t *)&ids, sizeof(uint64_t));
}
Context::~Context()
{
if(nodes)
delete nodes;
if(services)
delete services;
}
void
Context::handle_cleaner_timer(void *u, uint64_t orig, uint64_t left)
{
if(left)
return;
Context *ctx = static_cast< Context * >(u);
ctx->CleanupTX();
ctx->ScheduleCleanupTimer();
}
void
Context::LookupRouterRelayed(const Key_t &requester, uint64_t txid,
const Key_t &target, bool recursive,
std::vector< IMessage * > &replies)
{
if(target == ourKey)
{
// we are the target, give them our RC
replies.push_back(new GotRouterMessage(requester, txid, &router->rc));
return;
}
Key_t next;
std::set< Key_t > excluding = {requester, ourKey};
if(nodes->FindCloseExcluding(target, next, excluding))
{
if(next == target)
{
// we know it
replies.push_back(
new GotRouterMessage(requester, txid, nodes->nodes[target].rc));
}
else if(recursive) // are we doing a recursive lookup?
{
if((requester ^ target) < (ourKey ^ target))
{
// we aren't closer to the target than next hop
// so we won't ask neighboor recursively, tell them we don't have it
llarp::LogInfo("we aren't closer to ", target, " than ", next,
" so we end it here");
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
}
else
{
// yeah, ask neighboor recursively
LookupRouter(target, requester, txid, next);
}
}
else // otherwise tell them we don't have it
{
llarp::LogInfo("we don't have ", target,
" and this was an iterative request so telling ",
requester, " that we don't have it");
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
}
}
else
{
// we don't know it and have no closer peers
llarp::LogInfo("we don't have ", target,
" and have no closer peers so telling ", requester,
" that we don't have it");
replies.push_back(new GotRouterMessage(requester, txid, nullptr));
}
}
void
Context::RemovePendingLookup(const Key_t &owner, uint64_t id)
{
TXOwner search;
search.node = owner;
search.txid = id;
auto itr = pendingTX.find(search);
if(itr == pendingTX.end())
return;
pendingTX.erase(itr);
}
SearchJob *
Context::FindPendingTX(const Key_t &owner, uint64_t id)
{
TXOwner search;
search.node = owner;
search.txid = id;
auto itr = pendingTX.find(search);
if(itr == pendingTX.end())
return nullptr;
else
return &itr->second;
}
void
Context::CleanupTX()
{
auto now = llarp_time_now_ms();
llarp::LogDebug("DHT tick");
auto itr = pendingTX.begin();
while(itr != pendingTX.end())
{
if(itr->second.IsExpired(now))
{
itr->second.Timeout();
itr = pendingTX.erase(itr);
}
else
++itr;
}
}
void
Context::Init(const Key_t &us, llarp_router *r)
{
router = r;
ourKey = us;
nodes = new Bucket< RCNode >(ourKey);
services = new Bucket< ISNode >(ourKey);
llarp::LogDebug("intialize dht with key ", ourKey);
}
void
Context::ScheduleCleanupTimer()
{
llarp_logic_call_later(router->logic,
{1000, this, &handle_cleaner_timer});
}
bool
Context::RelayRequestForPath(const llarp::PathID_t &id, const IMessage *msg)
{
llarp::routing::DHTMessage reply;
if(!msg->HandleMessage(router->dht, reply.M))
return false;
auto path = router->paths.GetByUpstream(router->pubkey(), id);
return path && path->SendRoutingMessage(&reply, router);
}
void
Context::LookupRouter(const Key_t &target, const Key_t &whoasked,
uint64_t txid, const Key_t &askpeer,
llarp_router_lookup_job *job, bool iterative,
std::set< Key_t > excludes)
{
if(target.IsZero() || whoasked.IsZero() || askpeer.IsZero())
{
return;
}
auto id = ++ids;
TXOwner ownerKey;
ownerKey.node = askpeer;
ownerKey.txid = id;
if(txid == 0)
txid = id;
SearchJob j(whoasked, txid, target, excludes, job);
pendingTX[ownerKey] = j;
llarp::LogInfo("Asking ", askpeer, " for router ", target, " for ",
whoasked);
auto msg = new llarp::DHTImmeidateMessage(askpeer);
auto dhtmsg = new FindRouterMessage(askpeer, target, id);
dhtmsg->iterative = iterative;
msg->msgs.push_back(dhtmsg);
router->SendToOrQueue(askpeer, msg);
}
void
Context::LookupRouterViaJob(llarp_router_lookup_job *job)
{
Key_t peer;
if(nodes->FindClosest(job->target, peer))
LookupRouter(job->target, ourKey, 0, peer, job);
else if(job->hook)
{
job->found = false;
job->hook(job);
}
}
void
Context::queue_router_lookup(void *user)
{
llarp_router_lookup_job *job =
static_cast< llarp_router_lookup_job * >(user);
job->dht->impl.LookupRouterViaJob(job);
}
} // namespace dht
} // namespace llarp

@ -0,0 +1,142 @@
#include <llarp/dht/context.hpp>
#include <llarp/dht/messages/all.hpp>
namespace llarp
{
namespace dht
{
struct MessageDecoder
{
const Key_t &From;
bool firstKey = true;
IMessage *msg = nullptr;
bool relayed = false;
MessageDecoder(const Key_t &from) : From(from)
{
}
static bool
on_key(dict_reader *r, llarp_buffer_t *key)
{
llarp_buffer_t strbuf;
MessageDecoder *dec = static_cast< MessageDecoder * >(r->user);
// check for empty dict
if(!key)
return !dec->firstKey;
// first key
if(dec->firstKey)
{
if(!llarp_buffer_eq(*key, "A"))
return false;
if(!bencode_read_string(r->buffer, &strbuf))
return false;
// bad msg size?
if(strbuf.sz != 1)
return false;
switch(*strbuf.base)
{
case 'R':
if(dec->relayed)
dec->msg = new RelayedFindRouterMessage(dec->From);
else
dec->msg = new FindRouterMessage(dec->From);
break;
case 'S':
if(dec->relayed)
{
llarp::LogWarn(
"GotRouterMessage found when parsing relayed DHT "
"message");
return false;
}
else
dec->msg = new GotRouterMessage(dec->From);
break;
case 'I':
dec->msg = new PublishIntroMessage();
break;
case 'G':
if(dec->relayed)
{
dec->msg = new RelayedGotIntroMessage();
break;
}
else
{
dec->msg = new GotIntroMessage(dec->From);
break;
}
default:
llarp::LogWarn("unknown dht message type: ", (char)*strbuf.base);
// bad msg type
return false;
}
dec->firstKey = false;
return dec->msg != nullptr;
}
else
return dec->msg->DecodeKey(*key, r->buffer);
}
};
IMessage *
DecodeMesssage(const Key_t &from, llarp_buffer_t *buf, bool relayed)
{
MessageDecoder dec(from);
dec.relayed = relayed;
dict_reader r;
r.user = &dec;
r.on_key = &MessageDecoder::on_key;
if(bencode_read_dict(buf, &r))
{
return dec.msg;
}
else
{
if(dec.msg)
delete dec.msg;
return nullptr;
}
}
struct ListDecoder
{
ListDecoder(const Key_t &from, std::vector< IMessage * > &list)
: From(from), l(list){};
bool relayed = false;
const Key_t &From;
std::vector< IMessage * > &l;
static bool
on_item(list_reader *r, bool has)
{
ListDecoder *dec = static_cast< ListDecoder * >(r->user);
if(!has)
return true;
auto msg = DecodeMesssage(dec->From, r->buffer, dec->relayed);
if(msg)
{
dec->l.push_back(msg);
return true;
}
else
return false;
}
};
bool
DecodeMesssageList(const Key_t &from, llarp_buffer_t *buf,
std::vector< IMessage * > &list, bool relayed)
{
ListDecoder dec(from, list);
dec.relayed = relayed;
list_reader r;
r.user = &dec;
r.on_item = &ListDecoder::on_item;
return bencode_read_list(buf, &r);
}
} // namespace dht
} // namespace llarp

@ -0,0 +1,81 @@
#include <llarp/messages/dht_immediate.hpp>
#include "router.hpp"
namespace llarp
{
DHTImmeidateMessage::~DHTImmeidateMessage()
{
for(auto &msg : msgs)
delete msg;
msgs.clear();
}
bool
DHTImmeidateMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
{
if(llarp_buffer_eq(key, "m"))
return llarp::dht::DecodeMesssageList(remote.data(), buf, msgs);
if(llarp_buffer_eq(key, "v"))
{
if(!bencode_read_integer(buf, &version))
return false;
return version == LLARP_PROTO_VERSION;
}
// bad key
return false;
}
bool
DHTImmeidateMessage::BEncode(llarp_buffer_t *buf) const
{
if(!bencode_start_dict(buf))
return false;
// message type
if(!bencode_write_bytestring(buf, "a", 1))
return false;
if(!bencode_write_bytestring(buf, "m", 1))
return false;
// dht messages
if(!bencode_write_bytestring(buf, "m", 1))
return false;
// begin list
if(!bencode_start_list(buf))
return false;
for(const auto &msg : msgs)
{
if(!msg->BEncode(buf))
return false;
}
// end list
if(!bencode_end(buf))
return false;
// protocol version
if(!bencode_write_version_entry(buf))
return false;
return bencode_end(buf);
}
bool
DHTImmeidateMessage::HandleMessage(llarp_router *router) const
{
DHTImmeidateMessage *reply = new DHTImmeidateMessage(remote);
bool result = true;
for(auto &msg : msgs)
{
result &= msg->HandleMessage(router->dht, reply->msgs);
}
if(reply->msgs.size())
{
return result && router->SendToOrQueue(remote.data(), reply);
}
else
{
delete reply;
return result;
}
}
}

@ -0,0 +1,11 @@
#include <llarp/dht/messages/findintro.hpp>
namespace llarp
{
namespace dht
{
FindIntroMessage::~FindIntroMessage()
{
}
} // namespace dht
} // namespace llarp

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save