* implement path transfer message

* update dht docs
* update other docs
* start working on dht for hidden services
* fix up unit tests for dht
* update makefile and other build files
This commit is contained in:
Jeff Becker 2018-06-29 10:25:09 -04:00
parent 7d9bffdf9c
commit 18b50f4a74
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05
17 changed files with 420 additions and 261 deletions

View File

@ -170,9 +170,11 @@ set(LIB_SRC
llarp/api/client.cpp llarp/api/client.cpp
llarp/api/message.cpp llarp/api/message.cpp
llarp/api/parser.cpp llarp/api/parser.cpp
llarp/routing/dht_message.cpp
llarp/routing/message_parser.cpp llarp/routing/message_parser.cpp
llarp/routing/path_confirm.cpp llarp/routing/path_confirm.cpp
llarp/routing/path_latency.cpp llarp/routing/path_latency.cpp
llarp/routing/path_transfer.cpp
vendor/cppbackport-master/lib/fs/rename.cpp vendor/cppbackport-master/lib/fs/rename.cpp
vendor/cppbackport-master/lib/fs/filestatus.cpp vendor/cppbackport-master/lib/fs/filestatus.cpp
vendor/cppbackport-master/lib/fs/filetype.cpp vendor/cppbackport-master/lib/fs/filetype.cpp

View File

@ -70,7 +70,7 @@ testnet-build: testnet-configure
testnet: testnet-build testnet: testnet-build
mkdir -p $(TESTNET_ROOT) mkdir -p $(TESTNET_ROOT)
python3 contrib/testnet/genconf.py --bin=$(REPO)/llarpd --svc=10 --clients=1 --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF) python3 contrib/testnet/genconf.py --bin=$(REPO)/llarpd --svc=30 --clients=100 --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF)
supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF) supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF)
test: debug-configure test: debug-configure

View File

@ -2,13 +2,12 @@ DHT messages
these messages can be either wrapped in a LIDM message or sent anonymously over a path these messages can be either wrapped in a LIDM message or sent anonymously over a path
This document is currently out of date (probably)
find introduction message (FIM) find introduction message (FIM)
recursively find an IS. recursively find an IS by SA
variant 1, by SA
{ {
A: "F", A: "F",
@ -18,16 +17,6 @@ variant 1, by SA
V: 0 V: 0
} }
variant 2, by claimed name
{
A: "F",
N: "service.name.tld",
R: r_counter,
T: transaction_id_uin64,
V: 0
}
Transactions will persist until replied to by a GIM or 60 seconds, whichever Transactions will persist until replied to by a GIM or 60 seconds, whichever
is reached first. is reached first.
@ -80,9 +69,9 @@ got introduction message (GIM)
{ {
A: "G", A: "G",
I: [IS],
T: transaction_id_uint64, T: transaction_id_uint64,
V: 0, V: 0,
X: [ IS, IS, IS, ... ]
} }
if we have a transaction with id T: if we have a transaction with id T:
@ -95,115 +84,36 @@ when a linked transaction gets a GIM:
* set T to the current transaction id * set T to the current transaction id
* foward the GIM to the requester of T * foward the GIM to the requester of T
publish introduction message (PIM) publish introduction message (PIM)
publish one or many IM into the dht at once. publish one IS to the DHT.
each IS will be placed in the dht
version 0 uses the SA of each IS as the keyspace location. version 0 uses the SA of the IS as the keyspace location.
in the future the location will be determined by the dht kdf in the future the location will be determined by the dht kdf
which uses a shared random source to obfuscate keyspace location. which uses a shared random source to obfuscate keyspace location.
R is currently set to 3 +/- 2 by the sender. R is currently set to 0 by the sender.
{ {
A: "P", A: "I",
I: IS,
R: r_counter, R: r_counter,
V: 0, S: optional member 0 for immediate store otherwise non zero,
X: [ IS, IS, IS, ... ] V: 0
} }
The following steps happen in order: if R is greater than 0, do a random walk, otherwise if we are
closer to the SA of the IS than anyone else we know in the DHT
store the IS for later lookup.
first stage: reduction If S is provided store the IS for later lookup unconditionally,
decrement S by 1 and forward to dht peer who is next closest to
the SA of the IS. If S is greater than 3, don't store and discard
this message.
if X's length is divisble by 2:
* split X in half as J and K
* generate 2 new PIM with the same values as the parent with empty X
* put J and K into the new PIM's X values
* associate the 2 new PIM with the current PIM batch
if X's length is not divisible by 2 and greater than 1:
* pop off an IS from X as A
* generate a new PIM with the same values as the parent with an X value of A
* associate the new PIM with the current PIM batch
* associate the old PIM having A removed from X with the current PIM batch
if X's length is 1:
* associate the PIM with the current PIM batch
any other cases for X are ignored.
for each PIM in the current batch:
if R is greater than 0:
* decrement R by 1
* queue the PIM for shuffle (second stage)
if R is 0:
* queue the PIM for distribution (third stage)
if R is less than 0:
* drop the message entirely
second stage: shuffle
* The dht node waits until we have collected 10 or more PIM or for 5 seconds,
which ever comes first.
* shuffle the list of IS randomly
* re-combine the IS into new PIMs
* queue each newly shuffled PIM for distribution (third stage)
if we collected 10 or more PIM:
* X holds 5 IS at most
if we collected less than 10 but more than 1 PIM:
* X holds 2 IS at most
if we only collected 1 PIM:
* the single PIM is unmodified
third stage: distribution
if R is less than 0:
* drop message and terminate current transaction, this should never happen but
this case is left here in the event of implementation bugs.
if R is greater than 0:
* pick a random dht capable router, N
* forward the PIM to N
if R is equal to 0:
for each IS in X as A:
* find the router closest to the SA in A, N
if N is our router:
* create dht positon S from SA in A
* store A for lookup at S
if N is not our router:
* send a PIM with X value containing just A to N
In the future post random walk keyspace batching may be done here.
As of version 0, none is done.
find router contact message (FRCM) find router contact message (FRCM)
@ -254,8 +164,3 @@ sent in reply to FRCM only
* send a GRCM with R to requesters in all linked transactions * send a GRCM with R to requesters in all linked transactions
* terminate transaction with id T * terminate transaction with id T
notes:
if we get a GRCM with empty R on one Tx and then one with a filled R on another
with the same K, the request is terminated by the first message as not found.
A backtrack case is needed.

View File

@ -153,14 +153,14 @@ the "network address" of a hidden service, which is computed as the blake2b
HS(BE(SI)) HS(BE(SI))
introducer (I) introduction (I)
a descriptor annoucing a path to a hidden service a descriptor annoucing a path to a hidden service
k is the rc.k value of the router to contact k is the rc.k value of the router to contact
p is the path id on the router that is owned by the service p is the path id on the router that is owned by the service
v is the protocol version v is the protocol version
x is the timestamp seconds since epoch that this introducer expires at x is the timestamp seconds since epoch that this introduction expires at
{ {
k: "<32 bytes public identity key of router>", k: "<32 bytes public identity key of router>",
@ -169,12 +169,13 @@ x is the timestamp seconds since epoch that this introducer expires at
x: time_expires_seconds_since_epoch_uint64 x: time_expires_seconds_since_epoch_uint64
} }
introducer set (IS) introduction set (IS)
a signed set of introducers for a hidden service a signed set of introductions for a hidden service
a is the service info a is the service info
i is the list of introducers that this service is advertising with i is the list of introductions that this service is advertising with
v is the protocol version v is the protocol version
w is an optinal proof of work for DoS protection (slot for future)
z is the signature of the entire IS where z is set to zero signed by the hidden z is the signature of the entire IS where z is set to zero signed by the hidden
service's signing key. service's signing key.
@ -182,6 +183,7 @@ service's signing key.
a: SI, a: SI,
i: [ I, I, I, ... ], i: [ I, I, I, ... ],
v: 0, v: 0,
w: optional proof of work,
z: "<64 bytes signature using service info signing key>" z: "<64 bytes signature using service info signing key>"
} }
@ -190,10 +192,6 @@ service's signing key.
Encrypted frames: Encrypted frames:
{
v: 0,
w: "<32+32+32+N bytes payload>"
}
Encrypted frames are encrypted containers for link message records like LRCR. Encrypted frames are encrypted containers for link message records like LRCR.
@ -502,7 +500,7 @@ sent in response to an OXAM to indicate that exit traffic is not allowed or
was denied. was denied.
{ {
A: "R", A: "J",
B: backoff_milliseconds_uint64, B: backoff_milliseconds_uint64,
I: "<32 bytes signing public key of requester>", I: "<32 bytes signing public key of requester>",
R: "<optional reject metadata>", R: "<optional reject metadata>",
@ -596,3 +594,13 @@ The address used in exit MAY be reused later.
Y: "<16 bytes nounce>", Y: "<16 bytes nounce>",
Z: "<64 bytes signagure using previously provided signing key>" Z: "<64 bytes signagure using previously provided signing key>"
} }
DHT message holder message:
wrapper message for sending many dht messages down a path.
{
A: "M",
M: [many, dht, messages, here],
V: 0
}

View File

@ -6,6 +6,8 @@
#include <llarp/router_contact.h> #include <llarp/router_contact.h>
#include <llarp/time.h> #include <llarp/time.h>
#include <llarp/aligned.hpp> #include <llarp/aligned.hpp>
#include <llarp/path_types.hpp>
#include <llarp/service.hpp>
#include <array> #include <array>
#include <functional> #include <functional>
@ -46,23 +48,40 @@ namespace llarp
} }
}; };
struct Node struct RCNode
{ {
llarp_rc* rc; llarp_rc* rc;
Key_t ID; Key_t ID;
Node() : rc(nullptr) RCNode() : rc(nullptr)
{ {
ID.Zero(); ID.Zero();
} }
Node(llarp_rc* other) : rc(other) RCNode(llarp_rc* other) : rc(other)
{ {
ID = other->pubkey; 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 struct SearchJob
{ {
const static uint64_t JobTimeout = 30000; const static uint64_t JobTimeout = 30000;
@ -128,24 +147,65 @@ namespace llarp
DecodeMesssageList(const Key_t& from, llarp_buffer_t* buf, DecodeMesssageList(const Key_t& from, llarp_buffer_t* buf,
std::vector< IMessage* >& dst); std::vector< IMessage* >& dst);
template < typename Val_t >
struct Bucket struct Bucket
{ {
typedef std::map< Key_t, Node, XorMetric > BucketStorage_t; typedef std::map< Key_t, Val_t, XorMetric > BucketStorage_t;
Bucket(const Key_t& us) : nodes(XorMetric(us)){}; Bucket(const Key_t& us) : nodes(XorMetric(us)){};
bool bool
FindClosest(const Key_t& target, Key_t& result) const; 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 bool
FindCloseExcluding(const Key_t& target, Key_t& result, FindCloseExcluding(const Key_t& target, Key_t& result,
const std::set< Key_t >& exclude) const; 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 void
PutNode(const Node& val); PutNode(const Val_t& val)
{
nodes[val.ID] = val;
}
void void
DelNode(const Key_t& key); DelNode(const Key_t& key)
{
auto itr = nodes.find(key);
if(itr != nodes.end())
nodes.erase(itr);
}
BucketStorage_t nodes; BucketStorage_t nodes;
}; };
@ -177,6 +237,10 @@ namespace llarp
const Key_t& target, bool recursive, const Key_t& target, bool recursive,
std::vector< IMessage* >& replies); std::vector< IMessage* >& replies);
bool
RelayRequestForPath(const llarp::PathID_t& localPath,
const IMessage* msg);
void void
Init(const Key_t& us, llarp_router* router); Init(const Key_t& us, llarp_router* router);
@ -190,8 +254,12 @@ namespace llarp
queue_router_lookup(void* user); queue_router_lookup(void* user);
llarp_router* router = nullptr; llarp_router* router = nullptr;
Bucket* nodes = nullptr; // for router contacts
bool allowTransit = false; Bucket< RCNode >* nodes = nullptr;
// for introduction sets
Bucket< ISNode >* services = nullptr;
bool allowTransit = false;
const Key_t& const Key_t&
OurKey() const OurKey() const

View File

@ -0,0 +1,31 @@
#ifndef LLARP_MESSAGES_DHT_HPP
#define LLARP_MESSAGES_DHT_HPP
#include <llarp/dht.hpp>
#include <llarp/routing/message.hpp>
#include <vector>
namespace llarp
{
namespace routing
{
struct DHTMessage : public IMessage
{
std::vector< llarp::dht::IMessage* > M;
uint64_t V = 0;
~DHTMessage();
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
bool
BEncode(llarp_buffer_t* buf) const;
bool
HandleMessage(IMessageHandler* h, llarp_router* r) const;
};
} // namespace routing
} // namespace llarp
#endif

View File

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

View File

@ -13,7 +13,20 @@ namespace llarp
{ {
PathID_t P; PathID_t P;
Encrypted T; Encrypted T;
uint64_t V = 0;
TunnelNonce Y; TunnelNonce Y;
PathTransferMessage();
~PathTransferMessage();
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* val);
bool
BEncode(llarp_buffer_t* buf) const;
bool
HandleMessage(IMessageHandler*, llarp_router* r) const;
}; };
} // namespace routing } // namespace routing

View File

@ -23,8 +23,9 @@ namespace llarp
TunnelNonce tunnelNonce; TunnelNonce tunnelNonce;
PathID_t txid, rxid; PathID_t txid, rxid;
PoW *work = nullptr; PoW *work = nullptr;
uint64_t version = 0; uint64_t version = 0;
uint64_t lifetime = 0;
bool bool
BDecode(llarp_buffer_t *buf); BDecode(llarp_buffer_t *buf);

View File

@ -3,6 +3,9 @@
#include <llarp/aligned.hpp> #include <llarp/aligned.hpp>
#include <llarp/bencode.hpp> #include <llarp/bencode.hpp>
#include <llarp/crypto.hpp> #include <llarp/crypto.hpp>
#include <llarp/path_types.hpp>
#include <set>
namespace llarp namespace llarp
{ {
@ -22,7 +25,7 @@ namespace llarp
/// calculate our address /// calculate our address
void void
CalculateAddress(llarp_crypto* c, Address& addr) const; CalculateAddress(Address& addr) const;
bool bool
BEncode(llarp_buffer_t* buf) const; BEncode(llarp_buffer_t* buf) const;
@ -49,6 +52,33 @@ namespace llarp
// load from file // load from file
bool bool
LoadFromFile(const std::string& fpath); LoadFromFile(const std::string& fpath);
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
};
struct Introduction : public llarp::IBEncodeMessage
{
llarp::PubKey router;
llarp::PathID_t pathID;
uint64_t version = 0;
uint64_t expiresAt;
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
};
struct IntroSet : public llarp::IBEncodeMessage
{
Info A;
std::set< Introduction > I;
llarp::Signature Z;
}; };
}; // namespace service }; // namespace service

View File

@ -426,59 +426,6 @@ namespace llarp
return now - started >= JobTimeout; return now - started >= JobTimeout;
} }
bool
Bucket::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
Bucket::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
Bucket::PutNode(const Node &v)
{
nodes[v.ID] = v;
}
void
Bucket::DelNode(const Key_t &k)
{
auto itr = nodes.find(k);
if(itr != nodes.end())
nodes.erase(itr);
}
Context::Context() Context::Context()
{ {
randombytes((byte_t *)&ids, sizeof(uint64_t)); randombytes((byte_t *)&ids, sizeof(uint64_t));
@ -488,6 +435,8 @@ namespace llarp
{ {
if(nodes) if(nodes)
delete nodes; delete nodes;
if(services)
delete services;
} }
void void
@ -603,9 +552,10 @@ namespace llarp
void void
Context::Init(const Key_t &us, llarp_router *r) Context::Init(const Key_t &us, llarp_router *r)
{ {
router = r; router = r;
ourKey = us; ourKey = us;
nodes = new Bucket(ourKey); nodes = new Bucket< RCNode >(ourKey);
services = new Bucket< ISNode >(ourKey);
llarp::Debug("intialize dht with key ", ourKey); llarp::Debug("intialize dht with key ", ourKey);
} }
@ -616,6 +566,13 @@ namespace llarp
{1000, this, &handle_cleaner_timer}); {1000, this, &handle_cleaner_timer});
} }
bool
Context::RelayRequestForPath(const llarp::PathID_t &id, const IMessage *msg)
{
// TODO: implement me
return false;
}
void void
Context::LookupRouter(const Key_t &target, const Key_t &whoasked, Context::LookupRouter(const Key_t &target, const Key_t &whoasked,
uint64_t txid, const Key_t &askpeer, uint64_t txid, const Key_t &askpeer,
@ -673,60 +630,61 @@ llarp_dht_context::llarp_dht_context(llarp_router *router)
parent = router; parent = router;
} }
extern "C" { extern "C"
struct llarp_dht_context *
llarp_dht_context_new(struct llarp_router *router)
{ {
return new llarp_dht_context(router); struct llarp_dht_context *
} llarp_dht_context_new(struct llarp_router *router)
{
return new llarp_dht_context(router);
}
void void
llarp_dht_context_free(struct llarp_dht_context *ctx) llarp_dht_context_free(struct llarp_dht_context *ctx)
{ {
delete ctx; delete ctx;
} }
void void
llarp_dht_put_peer(struct llarp_dht_context *ctx, struct llarp_rc *rc) llarp_dht_put_peer(struct llarp_dht_context *ctx, struct llarp_rc *rc)
{ {
llarp::dht::Node n(rc); llarp::dht::RCNode n(rc);
ctx->impl.nodes->PutNode(n); ctx->impl.nodes->PutNode(n);
} }
void void
llarp_dht_remove_peer(struct llarp_dht_context *ctx, const byte_t *id) llarp_dht_remove_peer(struct llarp_dht_context *ctx, const byte_t *id)
{ {
llarp::dht::Key_t k = id; llarp::dht::Key_t k = id;
ctx->impl.nodes->DelNode(k); ctx->impl.nodes->DelNode(k);
} }
void void
llarp_dht_set_msg_handler(struct llarp_dht_context *ctx, llarp_dht_set_msg_handler(struct llarp_dht_context *ctx,
llarp_dht_msg_handler handler) llarp_dht_msg_handler handler)
{ {
ctx->impl.custom_handler = handler; ctx->impl.custom_handler = handler;
} }
void void
llarp_dht_allow_transit(llarp_dht_context *ctx) llarp_dht_allow_transit(llarp_dht_context *ctx)
{ {
ctx->impl.allowTransit = true; ctx->impl.allowTransit = true;
} }
void void
llarp_dht_context_start(struct llarp_dht_context *ctx, const byte_t *key) llarp_dht_context_start(struct llarp_dht_context *ctx, const byte_t *key)
{ {
ctx->impl.Init(key, ctx->parent); ctx->impl.Init(key, ctx->parent);
} }
void void
llarp_dht_lookup_router(struct llarp_dht_context *ctx, llarp_dht_lookup_router(struct llarp_dht_context *ctx,
struct llarp_router_lookup_job *job) struct llarp_router_lookup_job *job)
{ {
job->dht = ctx; job->dht = ctx;
job->found = false; job->found = false;
llarp_logic_queue_job(ctx->parent->logic, llarp_logic_queue_job(ctx->parent->logic,
{job, &llarp::dht::Context::queue_router_lookup}); {job, &llarp::dht::Context::queue_router_lookup});
} }
} }

View File

@ -59,7 +59,6 @@ namespace llarp
" when we are not allowing transit"); " when we are not allowing transit");
return false; return false;
} }
llarp::Info("Got LRCM from ", remote);
return AsyncDecrypt(&router->paths); return AsyncDecrypt(&router->paths);
} }
@ -73,6 +72,11 @@ namespace llarp
return false; return false;
if(!BEncodeWriteDictEntry("i", nextHop, buf)) if(!BEncodeWriteDictEntry("i", nextHop, buf))
return false; return false;
if(lifetime > 10 && lifetime < 600)
{
if(!BEncodeWriteDictInt(buf, "i", lifetime))
return false;
}
if(!BEncodeWriteDictEntry("n", tunnelNonce, buf)) if(!BEncodeWriteDictEntry("n", tunnelNonce, buf))
return false; return false;
if(!BEncodeWriteDictEntry("r", rxid, buf)) if(!BEncodeWriteDictEntry("r", rxid, buf))
@ -107,6 +111,8 @@ namespace llarp
return false; return false;
if(!BEncodeMaybeReadDictEntry("i", self->nextHop, read, *key, r->buffer)) if(!BEncodeMaybeReadDictEntry("i", self->nextHop, read, *key, r->buffer))
return false; return false;
if(!BEncodeMaybeReadDictInt("l", self->lifetime, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("n", self->tunnelNonce, read, *key, if(!BEncodeMaybeReadDictEntry("n", self->tunnelNonce, read, *key,
r->buffer)) r->buffer))
return false; return false;
@ -247,6 +253,12 @@ namespace llarp
self->record.work->extendedLifetime, " seconds for ", info); self->record.work->extendedLifetime, " seconds for ", info);
self->hop->lifetime += 1000 * self->record.work->extendedLifetime; self->hop->lifetime += 1000 * self->record.work->extendedLifetime;
} }
else if(self->record.lifetime < 600 && self->record.lifetime > 10)
{
self->hop->lifetime = self->record.lifetime;
llarp::Info("LRCM short lifespan set to ", self->hop->lifetime,
" seconds for ", info);
}
// TODO: check if we really want to accept it // TODO: check if we really want to accept it
self->hop->started = llarp_time_now_ms(); self->hop->started = llarp_time_now_ms();

View File

@ -0,0 +1,61 @@
#include <llarp/messages/dht.hpp>
#include "../router.hpp"
namespace llarp
{
namespace routing
{
DHTMessage::~DHTMessage()
{
for(auto& msg : M)
delete msg;
}
bool
DHTMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t* val)
{
llarp::dht::Key_t from;
from.Zero();
if(llarp_buffer_eq(key, "M"))
{
return llarp::dht::DecodeMesssageList(from, val, M);
}
else if(llarp_buffer_eq(key, "V"))
{
return bencode_read_integer(val, &V);
}
return false;
}
bool
DHTMessage::BEncode(llarp_buffer_t* buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "M"))
return false;
if(!BEncodeWriteDictBEncodeList("M", M, buf))
return false;
if(!BEncodeWriteDictInt(buf, "V", LLARP_PROTO_VERSION))
return false;
return bencode_end(buf);
}
bool
DHTMessage::HandleMessage(IMessageHandler* h, llarp_router* r) const
{
// set source as us
llarp::dht::Key_t us = r->pubkey();
for(auto& msg : M)
{
msg->From = us;
if(!r->dht->impl.RelayRequestForPath(from, msg))
return false;
}
return true;
}
} // namespace routing
} // namespace llarp

View File

@ -1,5 +1,7 @@
#include <llarp/messages/dht.hpp>
#include <llarp/messages/path_confirm.hpp> #include <llarp/messages/path_confirm.hpp>
#include <llarp/messages/path_latency.hpp> #include <llarp/messages/path_latency.hpp>
#include <llarp/messages/path_transfer.hpp>
#include <llarp/routing/message.hpp> #include <llarp/routing/message.hpp>
namespace llarp namespace llarp
@ -40,9 +42,15 @@ namespace llarp
case 'L': case 'L':
self->msg = new PathLatencyMessage; self->msg = new PathLatencyMessage;
break; break;
case 'M':
self->msg = new DHTMessage;
break;
case 'P': case 'P':
self->msg = new PathConfirmMessage; self->msg = new PathConfirmMessage;
break; break;
case 'T':
self->msg = new PathTransferMessage;
break;
default: default:
llarp::Error("invalid routing message id: ", *strbuf.cur); llarp::Error("invalid routing message id: ", *strbuf.cur);
} }

View File

@ -0,0 +1,65 @@
#include <llarp/messages/path_transfer.hpp>
#include "../router.hpp"
namespace llarp
{
namespace routing
{
PathTransferMessage::PathTransferMessage() : IMessage()
{
}
PathTransferMessage::~PathTransferMessage()
{
}
bool
PathTransferMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t* val)
{
bool read = false;
if(!BEncodeMaybeReadDictEntry("P", P, read, key, val))
return false;
if(!BEncodeMaybeReadDictEntry("T", T, read, key, val))
return false;
if(!BEncodeMaybeReadDictInt("V", V, read, key, val))
return false;
if(!BEncodeMaybeReadDictEntry("Y", Y, read, key, val))
return false;
return false;
}
bool
PathTransferMessage::BEncode(llarp_buffer_t* buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "T"))
return false;
if(!BEncodeWriteDictEntry("P", P, buf))
return false;
if(!BEncodeWriteDictEntry("T", T, buf))
return false;
if(!BEncodeWriteDictInt(buf, "V", LLARP_PROTO_VERSION))
return false;
if(!BEncodeWriteDictEntry("Y", Y, buf))
return false;
return bencode_end(buf);
}
bool
PathTransferMessage::HandleMessage(IMessageHandler* h,
llarp_router* r) const
{
auto path = r->paths.GetByUpstream(r->pubkey(), P);
if(path)
{
return path->HandleDownstream(T.Buffer(), Y, r);
}
llarp::Warn("No such local path for path transfer src=", from,
" dst=", P);
return false;
}
} // namespace routing
} // namespace llarp

View File

@ -72,8 +72,8 @@ namespace llarp
r->crypto.xchacha20(buf, pathKey, Y); r->crypto.xchacha20(buf, pathKey, Y);
msg->X = buf; msg->X = buf;
llarp::Info("relay ", msg->X.size(), " bytes downstream from ", llarp::Debug("relay ", msg->X.size(), " bytes downstream from ",
info.upstream, " to ", info.downstream); info.upstream, " to ", info.downstream);
return r->SendToOrQueue(info.downstream, msg); return r->SendToOrQueue(info.downstream, msg);
} }
@ -93,8 +93,8 @@ namespace llarp
msg->Y = Y; msg->Y = Y;
msg->X = buf; msg->X = buf;
llarp::Info("relay ", msg->X.size(), " bytes upstream from ", llarp::Debug("relay ", msg->X.size(), " bytes upstream from ",
info.downstream, " to ", info.upstream); info.downstream, " to ", info.upstream);
return r->SendToOrQueue(info.upstream, msg); return r->SendToOrQueue(info.upstream, msg);
} }
} }
@ -113,7 +113,6 @@ namespace llarp
{ {
llarp::routing::PathLatencyMessage reply; llarp::routing::PathLatencyMessage reply;
reply.L = msg->T; reply.L = msg->T;
llarp::Info("got latency message ", msg->T);
return SendRoutingMessage(&reply, r); return SendRoutingMessage(&reply, r);
} }

View File

@ -1,9 +1,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <llarp/dht.hpp> #include <llarp/dht.hpp>
using Node = llarp::dht::Node; using Key_t = llarp::dht::Key_t;
using Key_t = llarp::dht::Key_t;
using Bucket = llarp::dht::Bucket;
class KademliaDHTTest : public ::testing::Test class KademliaDHTTest : public ::testing::Test
{ {
@ -19,12 +17,12 @@ class KademliaDHTTest : public ::testing::Test
SetUp() SetUp()
{ {
us.Fill(16); us.Fill(16);
nodes = new Bucket(us); nodes = new llarp::dht::Bucket< llarp::dht::RCNode >(us);
size_t numNodes = 10; size_t numNodes = 10;
byte_t fill = 1; byte_t fill = 1;
while(numNodes) while(numNodes)
{ {
Node n; llarp::dht::RCNode n;
n.ID.Fill(fill); n.ID.Fill(fill);
nodes->PutNode(n); nodes->PutNode(n);
--numNodes; --numNodes;
@ -38,15 +36,15 @@ class KademliaDHTTest : public ::testing::Test
delete nodes; delete nodes;
} }
Bucket* nodes = nullptr; llarp::dht::Bucket< llarp::dht::RCNode >* nodes = nullptr;
Key_t us; llarp::dht::Key_t us;
}; };
TEST_F(KademliaDHTTest, TestBucketFindClosest) TEST_F(KademliaDHTTest, TestBucketFindClosest)
{ {
Key_t result; llarp::dht::Key_t result;
Key_t target; llarp::dht::Key_t target;
Key_t oldResult; llarp::dht::Key_t oldResult;
target.Fill(5); target.Fill(5);
ASSERT_TRUE(nodes->FindClosest(target, result)); ASSERT_TRUE(nodes->FindClosest(target, result));
ASSERT_TRUE(target == result); ASSERT_TRUE(target == result);
@ -61,13 +59,13 @@ TEST_F(KademliaDHTTest, TestBucketRandomzied)
size_t moreNodes = 100; size_t moreNodes = 100;
while(moreNodes--) while(moreNodes--)
{ {
Node n; llarp::dht::RCNode n;
n.ID.Randomize(); n.ID.Randomize();
nodes->PutNode(n); nodes->PutNode(n);
} }
Key_t result; llarp::dht::Key_t result;
Key_t target; llarp::dht::Key_t target;
Key_t oldResult; llarp::dht::Key_t oldResult;
target.Randomize(); target.Randomize();
ASSERT_TRUE(nodes->FindClosest(target, result)); ASSERT_TRUE(nodes->FindClosest(target, result));
}; };