mirror of https://github.com/oxen-io/lokinet
Compare commits
31 Commits
f173186696
...
42337388f9
Author | SHA1 | Date |
---|---|---|
dr7ana | 42337388f9 | 7 months ago |
Jason Rhinelander | f7c18de0d4 | 7 months ago |
Jason Rhinelander | 4f364f5e59 | 7 months ago |
Jason Rhinelander | a7a18868c7 | 7 months ago |
Jason Rhinelander | 6ebc812cda | 7 months ago |
Jason Rhinelander | 1ca81713ab | 7 months ago |
Jason Rhinelander | e237d5ad6e | 7 months ago |
dr7ana | 8cbae70369 | 7 months ago |
Jason Rhinelander | b4a1ed9b85 | 7 months ago |
dr7ana | 7d713323f0 | 7 months ago |
dr7ana | aae677814d | 7 months ago |
Jason Rhinelander | 6f2825c922 | 7 months ago |
Jason Rhinelander | 16506b6d8b | 7 months ago |
Jason Rhinelander | d2667cfb89 | 7 months ago |
dr7ana | 7ac88616f7 | 7 months ago |
dr7ana | b7e21becf0 | 7 months ago |
dr7ana | 7314c2a22a | 7 months ago |
Jason Rhinelander | c18ad4c618 | 7 months ago |
dr7ana | 2abe2d9363 | 7 months ago |
Jason Rhinelander | 5c3467ecb0 | 7 months ago |
Jason Rhinelander | 18effaa76f | 7 months ago |
Jason Rhinelander | c3242e4092 | 7 months ago |
dr7ana | 46ad8d4058 | 7 months ago |
dr7ana | bda8b211dd | 7 months ago |
Jason Rhinelander | f4f5ab0109 | 7 months ago |
dr7ana | e710cfea47 | 7 months ago |
dr7ana | 0e451db77f | 7 months ago |
dr7ana | 3ae8fce77d | 7 months ago |
dr7ana | 41312abab0 | 7 months ago |
dr7ana | 6955f3fae0 | 7 months ago |
Thomas Winget | 4755269458 | 7 months ago |
@ -0,0 +1,4 @@
|
||||
set(GRAPHVIZ_GRAPH_NAME "graph.dot" CACHE STRING "")
|
||||
set(GRAPHVIZ_GENERATE_PER_TARGET FALSE CACHE BOOL "")
|
||||
set(GRAPHVIZ_GENERATE_DEPENDERS FALSE CACHE BOOL "")
|
||||
set(GRAPHVIZ_OBJECT_LIBS OFF CACHE BOOL "")
|
@ -1,7 +0,0 @@
|
||||
if(STATIC_LINK)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
link_libraries( -static-libstdc++ )
|
||||
else()
|
||||
link_libraries( -static-libstdc++ -static-libgcc )
|
||||
endif()
|
||||
endif()
|
@ -0,0 +1 @@
|
||||
Subproject commit a7de63756dcc5c31cb899a4b810e6434b1a7c01c
|
@ -1 +1 @@
|
||||
Subproject commit 33982d24a380268933ebea33976ad806e5c4e4bb
|
||||
Subproject commit 6ee6ed398d00043d862466a56279b5c502513bff
|
@ -1 +1 @@
|
||||
Subproject commit 68b3420bad5f0384f06d378b89ccdc06aba07465
|
||||
Subproject commit a27961d787c9065f2bf6da9d60d01dca2e125739
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "lokinet/lokinet_addr.h"
|
||||
#include "lokinet/lokinet_context.h"
|
||||
#include "lokinet/lokinet_srv.h"
|
||||
#include "lokinet/lokinet_misc.h"
|
||||
#include "lokinet/lokinet_addr.h"
|
||||
#include "lokinet/lokinet_srv.h"
|
||||
#include "lokinet/lokinet_stream.h"
|
||||
#include "lokinet/lokinet_udp.h"
|
||||
|
@ -0,0 +1,26 @@
|
||||
#include <llarp/bootstrap.hpp>
|
||||
|
||||
#include <initializer_list>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
std::unordered_map<std::string, BootstrapList>
|
||||
load_bootstrap_fallbacks()
|
||||
{
|
||||
std::unordered_map<std::string, BootstrapList> fallbacks;
|
||||
using init_list = std::initializer_list<std::pair<std::string, std::string_view>>;
|
||||
// clang-format off
|
||||
for (const auto& [network, bootstrap] : init_list{
|
||||
//
|
||||
})
|
||||
// clang-format on
|
||||
{
|
||||
llarp_buffer_t buf{bootstrap.data(), bootstrap.size()};
|
||||
auto& bsl = fallbacks[network];
|
||||
bsl.BDecode(&buf);
|
||||
}
|
||||
return fallbacks;
|
||||
}
|
||||
} // namespace llarp
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
/// default queue length for logic jobs
|
||||
constexpr std::size_t event_loop_queue_size = 1024;
|
||||
} // namespace llarp
|
@ -1,669 +0,0 @@
|
||||
#include "context.hpp"
|
||||
|
||||
#include "explorenetworkjob.hpp"
|
||||
#include "localrouterlookup.hpp"
|
||||
#include "localserviceaddresslookup.hpp"
|
||||
#include "localtaglookup.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>
|
||||
#include "node.hpp"
|
||||
#include "publishservicejob.hpp"
|
||||
#include "recursiverouterlookup.hpp"
|
||||
#include "serviceaddresslookup.hpp"
|
||||
#include "taglookup.hpp"
|
||||
#include <llarp/messages/dht_immediate.hpp>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/router/router.hpp>
|
||||
#include <llarp/routing/path_dht_message.hpp>
|
||||
#include <llarp/nodedb.hpp>
|
||||
#include <llarp/profiling.hpp>
|
||||
#include <llarp/router/rc_lookup_handler.hpp>
|
||||
#include <llarp/util/decaying_hashset.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
AbstractDHTMessageHandler::~AbstractDHTMessageHandler() = default;
|
||||
|
||||
struct DHTMessageHandler final : public AbstractDHTMessageHandler
|
||||
{
|
||||
DHTMessageHandler();
|
||||
|
||||
~DHTMessageHandler() override = default;
|
||||
|
||||
util::StatusObject
|
||||
ExtractStatus() const override;
|
||||
|
||||
void
|
||||
StoreRC(const RouterContact rc) const override
|
||||
{
|
||||
GetRouter()->rc_lookup_handler().check_rc(rc);
|
||||
}
|
||||
|
||||
// void
|
||||
// LookupIntroSetRelayed(
|
||||
// const Key_t& target,
|
||||
// const Key_t& whoasked,
|
||||
// uint64_t whoaskedTX,
|
||||
// const Key_t& askpeer,
|
||||
// uint64_t relayOrder,
|
||||
// service::EncryptedIntroSetLookupHandler result = nullptr) override;
|
||||
|
||||
// void
|
||||
// LookupIntroSetDirect(
|
||||
// const Key_t& target,
|
||||
// const Key_t& whoasked,
|
||||
// uint64_t whoaskedTX,
|
||||
// const Key_t& askpeer,
|
||||
// service::EncryptedIntroSetLookupHandler result = nullptr) override;
|
||||
|
||||
/// on behalf of whoasked request router with public key target from dht
|
||||
/// router with key askpeer
|
||||
void
|
||||
LookupRouterRecursive(
|
||||
const RouterID& target,
|
||||
const Key_t& whoasked,
|
||||
uint64_t whoaskedTX,
|
||||
const Key_t& askpeer,
|
||||
RouterLookupHandler result = nullptr) override;
|
||||
|
||||
bool
|
||||
LookupRouter(const RouterID& target, RouterLookupHandler result) override
|
||||
{
|
||||
Key_t askpeer;
|
||||
if (!_nodes->FindClosest(Key_t(target), askpeer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
LookupRouterRecursive(target, OurKey(), 0, askpeer, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HasRouterLookup(const RouterID& target) const override
|
||||
{
|
||||
return pendingRouterLookups().HasLookupFor(target);
|
||||
}
|
||||
|
||||
/// issue dht lookup for router via askpeer and send reply to local path
|
||||
void
|
||||
LookupRouterForPath(
|
||||
const RouterID& target, uint64_t txid, const PathID_t& path, const Key_t& askpeer) override;
|
||||
|
||||
/// issue dht lookup for introset for addr via askpeer and send reply to
|
||||
/// local path
|
||||
void
|
||||
LookupIntroSetForPath(
|
||||
const Key_t& addr,
|
||||
uint64_t txid,
|
||||
const llarp::PathID_t& path,
|
||||
const Key_t& askpeer,
|
||||
uint64_t relayOrder) override;
|
||||
|
||||
/// send a dht message to peer, if keepalive is true then keep the session
|
||||
/// with that peer alive for 10 seconds
|
||||
void
|
||||
DHTSendTo(const RouterID& peer, AbstractDHTMessage* msg, bool keepalive = true) override;
|
||||
|
||||
/// get routers closest to target excluding requester
|
||||
bool
|
||||
HandleExploritoryRouterLookup(
|
||||
const Key_t& requester,
|
||||
uint64_t txid,
|
||||
const RouterID& target,
|
||||
std::vector<std::unique_ptr<AbstractDHTMessage>>& reply) override;
|
||||
|
||||
/// handle rc lookup from requester for target
|
||||
void
|
||||
LookupRouterRelayed(
|
||||
const Key_t& requester,
|
||||
uint64_t txid,
|
||||
const Key_t& target,
|
||||
bool recursive,
|
||||
std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) override;
|
||||
|
||||
/// relay a dht message from a local path to the main network
|
||||
bool
|
||||
RelayRequestForPath(const llarp::PathID_t& localPath, const AbstractDHTMessage& msg) override;
|
||||
|
||||
/// send introset to peer as R/S
|
||||
void
|
||||
PropagateLocalIntroSet(
|
||||
const PathID_t& from,
|
||||
uint64_t txid,
|
||||
const service::EncryptedIntroSet& introset,
|
||||
const Key_t& tellpeer,
|
||||
uint64_t relayOrder) override;
|
||||
|
||||
/// send introset to peer from source with S counter and excluding peers
|
||||
void
|
||||
PropagateIntroSetTo(
|
||||
const Key_t& from,
|
||||
uint64_t txid,
|
||||
const service::EncryptedIntroSet& introset,
|
||||
const Key_t& tellpeer,
|
||||
uint64_t relayOrder) override;
|
||||
|
||||
/// initialize dht context and explore every exploreInterval milliseconds
|
||||
void
|
||||
Init(const Key_t& us, Router* router) override;
|
||||
|
||||
/// get localally stored introset by service address
|
||||
std::optional<llarp::service::EncryptedIntroSet>
|
||||
GetIntroSetByLocation(const Key_t& location) const override;
|
||||
|
||||
void
|
||||
handle_cleaner_timer();
|
||||
|
||||
/// explore dht for new routers
|
||||
void
|
||||
Explore(size_t N = 3);
|
||||
|
||||
llarp::Router* router{nullptr};
|
||||
// for router contacts
|
||||
std::unique_ptr<Bucket<RCNode>> _nodes;
|
||||
|
||||
// for introduction sets
|
||||
std::unique_ptr<Bucket<ISNode>> _services;
|
||||
|
||||
Bucket<ISNode>*
|
||||
services() override
|
||||
{
|
||||
return _services.get();
|
||||
}
|
||||
|
||||
bool allowTransit{false};
|
||||
|
||||
bool&
|
||||
AllowTransit() override
|
||||
{
|
||||
return allowTransit;
|
||||
}
|
||||
const bool&
|
||||
AllowTransit() const override
|
||||
{
|
||||
return allowTransit;
|
||||
}
|
||||
|
||||
Bucket<RCNode>*
|
||||
Nodes() const override
|
||||
{
|
||||
return _nodes.get();
|
||||
}
|
||||
|
||||
void
|
||||
PutRCNodeAsync(const RCNode& val) override
|
||||
{
|
||||
router->loop()->call([nodes = Nodes(), val] { nodes->PutNode(val); });
|
||||
}
|
||||
|
||||
void
|
||||
DelRCNodeAsync(const Key_t& val) override
|
||||
{
|
||||
router->loop()->call([nodes = Nodes(), val] { nodes->DelNode(val); });
|
||||
}
|
||||
|
||||
const Key_t&
|
||||
OurKey() const override
|
||||
{
|
||||
return ourKey;
|
||||
}
|
||||
|
||||
llarp::Router*
|
||||
GetRouter() const override
|
||||
{
|
||||
return router;
|
||||
}
|
||||
|
||||
bool
|
||||
GetRCFromNodeDB(const Key_t& k, llarp::RouterContact& rc) const override
|
||||
{
|
||||
if (const auto maybe = router->node_db()->Get(k.as_array()); maybe.has_value())
|
||||
{
|
||||
rc = *maybe;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PendingIntrosetLookups _pendingIntrosetLookups;
|
||||
PendingRouterLookups _pendingRouterLookups;
|
||||
PendingExploreLookups _pendingExploreLookups;
|
||||
|
||||
PendingIntrosetLookups&
|
||||
pendingIntrosetLookups() override
|
||||
{
|
||||
return _pendingIntrosetLookups;
|
||||
}
|
||||
|
||||
const PendingIntrosetLookups&
|
||||
pendingIntrosetLookups() const override
|
||||
{
|
||||
return _pendingIntrosetLookups;
|
||||
}
|
||||
|
||||
PendingRouterLookups&
|
||||
pendingRouterLookups() override
|
||||
{
|
||||
return _pendingRouterLookups;
|
||||
}
|
||||
|
||||
const PendingRouterLookups&
|
||||
pendingRouterLookups() const override
|
||||
{
|
||||
return _pendingRouterLookups;
|
||||
}
|
||||
|
||||
PendingExploreLookups&
|
||||
pendingExploreLookups() override
|
||||
{
|
||||
return _pendingExploreLookups;
|
||||
}
|
||||
|
||||
const PendingExploreLookups&
|
||||
pendingExploreLookups() const override
|
||||
{
|
||||
return _pendingExploreLookups;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
NextID()
|
||||
{
|
||||
return ++ids;
|
||||
}
|
||||
|
||||
llarp_time_t
|
||||
Now() const override;
|
||||
|
||||
void
|
||||
ExploreNetworkVia(const Key_t& peer) override;
|
||||
|
||||
bool
|
||||
handle_message(
|
||||
const AbstractDHTMessage&, std::vector<std::unique_ptr<dht::AbstractDHTMessage>>&) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<int> _timer_keepalive;
|
||||
|
||||
void
|
||||
CleanupTX();
|
||||
|
||||
uint64_t ids;
|
||||
|
||||
Key_t ourKey;
|
||||
};
|
||||
|
||||
DHTMessageHandler::DHTMessageHandler()
|
||||
{
|
||||
randombytes((byte_t*)&ids, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::Explore(size_t N)
|
||||
{
|
||||
// ask N random peers for new routers
|
||||
llarp::LogDebug("Exploring network via ", N, " peers");
|
||||
std::set<Key_t> peers;
|
||||
|
||||
if (_nodes->GetManyRandom(peers, N))
|
||||
{
|
||||
for (const auto& peer : peers)
|
||||
ExploreNetworkVia(peer);
|
||||
}
|
||||
else
|
||||
llarp::LogError("failed to select ", N, " random nodes for exploration");
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::ExploreNetworkVia(const Key_t& askpeer)
|
||||
{
|
||||
uint64_t txid = ++ids;
|
||||
const TXOwner peer(askpeer, txid);
|
||||
const TXOwner whoasked(OurKey(), txid);
|
||||
const RouterID K(askpeer.as_array());
|
||||
pendingExploreLookups().NewTX(
|
||||
peer, whoasked, K, new ExploreNetworkJob(askpeer.as_array(), this));
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::handle_cleaner_timer()
|
||||
{
|
||||
// clean up transactions
|
||||
CleanupTX();
|
||||
const llarp_time_t now = Now();
|
||||
|
||||
if (_nodes)
|
||||
{
|
||||
// expire router contacts in memory
|
||||
auto& nodes = _nodes->nodes;
|
||||
auto itr = nodes.begin();
|
||||
while (itr != nodes.end())
|
||||
{
|
||||
if (itr->second.rc.IsExpired(now))
|
||||
{
|
||||
itr = nodes.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
if (_services)
|
||||
{
|
||||
// expire intro sets
|
||||
auto& nodes = _services->nodes;
|
||||
auto itr = nodes.begin();
|
||||
while (itr != nodes.end())
|
||||
{
|
||||
if (itr->second.introset.IsExpired(now))
|
||||
{
|
||||
itr = nodes.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::LookupRouterRelayed(
|
||||
const Key_t& requester,
|
||||
uint64_t txid,
|
||||
const Key_t& target,
|
||||
bool recursive,
|
||||
std::vector<std::unique_ptr<AbstractDHTMessage>>& replies)
|
||||
{
|
||||
if (target == ourKey)
|
||||
{
|
||||
// we are the target, give them our RC
|
||||
replies.emplace_back(new GotRouterMessage(requester, txid, {router->rc()}, false));
|
||||
return;
|
||||
}
|
||||
if (not GetRouter()->SessionToRouterAllowed(target.as_array()))
|
||||
{
|
||||
// explicitly not allowed
|
||||
replies.emplace_back(new GotRouterMessage(requester, txid, {}, false));
|
||||
return;
|
||||
}
|
||||
const auto rc = GetRouter()->node_db()->FindClosestTo(target);
|
||||
const Key_t next(rc.pubkey);
|
||||
{
|
||||
if (next == target)
|
||||
{
|
||||
// we know the target
|
||||
if (rc.ExpiresSoon(llarp::time_now_ms()))
|
||||
{
|
||||
// ask target for their rc to keep it updated
|
||||
LookupRouterRecursive(target.as_array(), requester, txid, next);
|
||||
}
|
||||
else
|
||||
{
|
||||
// send reply with rc we know of
|
||||
replies.emplace_back(new GotRouterMessage(requester, txid, {rc}, false));
|
||||
}
|
||||
}
|
||||
else if (recursive) // are we doing a recursive lookup?
|
||||
{
|
||||
// is the next peer we ask closer to the target than us?
|
||||
if ((next ^ target) < (ourKey ^ target))
|
||||
{
|
||||
// yes it is closer, ask neighbour recursively
|
||||
LookupRouterRecursive(target.as_array(), requester, txid, next);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no we are closer to the target so tell requester it's not there
|
||||
// so they switch to iterative lookup
|
||||
replies.emplace_back(new GotRouterMessage(requester, txid, {}, false));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// iterative lookup and we don't have it tell them who is closer
|
||||
replies.emplace_back(new GotRouterMessage(requester, next, txid, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<llarp::service::EncryptedIntroSet>
|
||||
DHTMessageHandler::GetIntroSetByLocation(const Key_t& key) const
|
||||
{
|
||||
auto itr = _services->nodes.find(key);
|
||||
if (itr == _services->nodes.end())
|
||||
return {};
|
||||
return itr->second.introset;
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::CleanupTX()
|
||||
{
|
||||
auto now = Now();
|
||||
llarp::LogTrace("DHT tick");
|
||||
|
||||
pendingRouterLookups().Expire(now);
|
||||
_pendingIntrosetLookups.Expire(now);
|
||||
pendingExploreLookups().Expire(now);
|
||||
}
|
||||
|
||||
util::StatusObject
|
||||
DHTMessageHandler::ExtractStatus() const
|
||||
{
|
||||
util::StatusObject obj{
|
||||
{"pendingRouterLookups", pendingRouterLookups().ExtractStatus()},
|
||||
{"pendingIntrosetLookups", _pendingIntrosetLookups.ExtractStatus()},
|
||||
{"pendingExploreLookups", pendingExploreLookups().ExtractStatus()},
|
||||
{"nodes", _nodes->ExtractStatus()},
|
||||
{"services", _services->ExtractStatus()},
|
||||
{"ourKey", ourKey.ToHex()}};
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool
|
||||
DHTMessageHandler::handle_message(
|
||||
const AbstractDHTMessage& msg, std::vector<std::unique_ptr<dht::AbstractDHTMessage>>& replies)
|
||||
{
|
||||
return msg.handle_message(*this, replies);
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::Init(const Key_t& us, Router* r)
|
||||
{
|
||||
router = r;
|
||||
ourKey = us;
|
||||
_nodes = std::make_unique<Bucket<RCNode>>(ourKey, llarp::randint);
|
||||
_services = std::make_unique<Bucket<ISNode>>(ourKey, llarp::randint);
|
||||
llarp::LogDebug("initialize dht with key ", ourKey);
|
||||
// start cleanup timer
|
||||
_timer_keepalive = std::make_shared<int>(0);
|
||||
router->loop()->call_every(1s, _timer_keepalive, [this] { handle_cleaner_timer(); });
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::DHTSendTo(const RouterID& peer, AbstractDHTMessage* msg, bool)
|
||||
{
|
||||
router->SendToOrQueue(peer, msg);
|
||||
auto now = Now();
|
||||
router->PersistSessionUntil(peer, now + 1min);
|
||||
}
|
||||
|
||||
// this function handles incoming DHT messages sent down a path by a client
|
||||
// note that IMessage here is different than that found in the routing
|
||||
// namespace. by the time this is called, we are inside
|
||||
// llarp::routing::DHTMessage::HandleMessage()
|
||||
bool
|
||||
DHTMessageHandler::RelayRequestForPath(const llarp::PathID_t& id, const AbstractDHTMessage& msg)
|
||||
{
|
||||
routing::PathDHTMessage reply;
|
||||
if (not handle_message(msg, reply.dht_msgs))
|
||||
return false;
|
||||
if (not reply.dht_msgs.empty())
|
||||
{
|
||||
auto path = router->path_context().GetByUpstream(router->pubkey(), id);
|
||||
return path && path->SendRoutingMessage(reply, router);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::LookupIntroSetForPath(
|
||||
const Key_t& addr,
|
||||
uint64_t txid,
|
||||
const llarp::PathID_t& path,
|
||||
const Key_t& askpeer,
|
||||
uint64_t relayOrder)
|
||||
{
|
||||
const TXOwner asker(OurKey(), txid);
|
||||
const TXOwner peer(askpeer, ++ids);
|
||||
_pendingIntrosetLookups.NewTX(
|
||||
peer,
|
||||
asker,
|
||||
asker,
|
||||
new LocalServiceAddressLookup(path, txid, relayOrder, addr, this, askpeer));
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::PropagateIntroSetTo(
|
||||
const Key_t& from,
|
||||
uint64_t txid,
|
||||
const service::EncryptedIntroSet& introset,
|
||||
const Key_t& tellpeer,
|
||||
uint64_t relayOrder)
|
||||
{
|
||||
const TXOwner asker(from, txid);
|
||||
const TXOwner peer(tellpeer, ++ids);
|
||||
_pendingIntrosetLookups.NewTX(
|
||||
peer, asker, asker, new PublishServiceJob(asker, introset, this, relayOrder));
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::PropagateLocalIntroSet(
|
||||
const PathID_t& from,
|
||||
uint64_t txid,
|
||||
const service::EncryptedIntroSet& introset,
|
||||
const Key_t& tellpeer,
|
||||
uint64_t relayOrder)
|
||||
{
|
||||
const TXOwner asker(OurKey(), txid);
|
||||
const TXOwner peer(tellpeer, ++ids);
|
||||
_pendingIntrosetLookups.NewTX(
|
||||
peer,
|
||||
asker,
|
||||
peer,
|
||||
new LocalPublishServiceJob(peer, from, txid, introset, this, relayOrder));
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::LookupIntroSetRelayed(
|
||||
const Key_t& addr,
|
||||
const Key_t& whoasked,
|
||||
uint64_t txid,
|
||||
const Key_t& askpeer,
|
||||
uint64_t relayOrder,
|
||||
service::EncryptedIntroSetLookupHandler handler)
|
||||
{
|
||||
const TXOwner asker(whoasked, txid);
|
||||
const TXOwner peer(askpeer, ++ids);
|
||||
_pendingIntrosetLookups.NewTX(
|
||||
peer, asker, asker, new ServiceAddressLookup(asker, addr, this, relayOrder, handler));
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::LookupIntroSetDirect(
|
||||
const Key_t& addr,
|
||||
const Key_t& whoasked,
|
||||
uint64_t txid,
|
||||
const Key_t& askpeer,
|
||||
service::EncryptedIntroSetLookupHandler handler)
|
||||
{
|
||||
const TXOwner asker(whoasked, txid);
|
||||
const TXOwner peer(askpeer, ++ids);
|
||||
_pendingIntrosetLookups.NewTX(
|
||||
peer, asker, asker, new ServiceAddressLookup(asker, addr, this, 0, handler), 1s);
|
||||
}
|
||||
|
||||
bool
|
||||
DHTMessageHandler::HandleExploritoryRouterLookup(
|
||||
const Key_t& requester,
|
||||
uint64_t txid,
|
||||
const RouterID& target,
|
||||
std::vector<std::unique_ptr<AbstractDHTMessage>>& reply)
|
||||
{
|
||||
std::vector<RouterID> closer;
|
||||
const Key_t t(target.as_array());
|
||||
std::set<Key_t> foundRouters;
|
||||
if (!_nodes)
|
||||
return false;
|
||||
|
||||
const size_t nodeCount = _nodes->size();
|
||||
if (nodeCount == 0)
|
||||
{
|
||||
llarp::LogError("cannot handle exploritory router lookup, no dht peers");
|
||||
return false;
|
||||
}
|
||||
llarp::LogDebug("We have ", _nodes->size(), " connected nodes into the DHT");
|
||||
// ourKey should never be in the connected list
|
||||
// requester is likely in the connected list
|
||||
// 4 or connection nodes (minus a potential requestor), whatever is less
|
||||
if (!_nodes->GetManyNearExcluding(
|
||||
t, foundRouters, std::min(nodeCount, size_t{4}), std::set<Key_t>{ourKey, requester}))
|
||||
{
|
||||
llarp::LogError(
|
||||
"not enough dht nodes to handle exploritory router lookup, "
|
||||
"have ",
|
||||
nodeCount,
|
||||
" dht peers");
|
||||
return false;
|
||||
}
|
||||
for (const auto& f : foundRouters)
|
||||
{
|
||||
const RouterID id = f.as_array();
|
||||
// discard shit routers
|
||||
if (router->router_profiling().IsBadForConnect(id))
|
||||
continue;
|
||||
closer.emplace_back(id);
|
||||
}
|
||||
llarp::LogDebug("Gave ", closer.size(), " routers for exploration");
|
||||
reply.emplace_back(new GotRouterMessage(txid, closer, false));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::LookupRouterForPath(
|
||||
const RouterID& target, uint64_t txid, const llarp::PathID_t& path, const Key_t& askpeer)
|
||||
|
||||
{
|
||||
const TXOwner peer(askpeer, ++ids);
|
||||
const TXOwner whoasked(OurKey(), txid);
|
||||
_pendingRouterLookups.NewTX(
|
||||
peer, whoasked, target, new LocalRouterLookup(path, txid, target, this));
|
||||
}
|
||||
|
||||
void
|
||||
DHTMessageHandler::LookupRouterRecursive(
|
||||
const RouterID& target,
|
||||
const Key_t& whoasked,
|
||||
uint64_t txid,
|
||||
const Key_t& askpeer,
|
||||
RouterLookupHandler handler)
|
||||
{
|
||||
const TXOwner asker(whoasked, txid);
|
||||
const TXOwner peer(askpeer, ++ids);
|
||||
_pendingRouterLookups.NewTX(
|
||||
peer, asker, target, new RecursiveRouterLookup(asker, target, this, handler));
|
||||
}
|
||||
|
||||
llarp_time_t
|
||||
DHTMessageHandler::Now() const
|
||||
{
|
||||
return router->now();
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractDHTMessageHandler>
|
||||
make_handler()
|
||||
{
|
||||
return std::make_unique<DHTMessageHandler>();
|
||||
}
|
||||
|
||||
} // namespace llarp::dht
|
@ -1,53 +0,0 @@
|
||||
#include "context.hpp"
|
||||
#include "dht.h"
|
||||
#include <llarp/router_contact.hpp>
|
||||
|
||||
llarp_dht_context::llarp_dht_context(llarp::Router* router)
|
||||
{
|
||||
parent = router;
|
||||
impl = llarp::dht::make_handler();
|
||||
}
|
||||
|
||||
struct llarp_dht_context*
|
||||
llarp_dht_context_new(llarp::Router* router)
|
||||
{
|
||||
return new llarp_dht_context(router);
|
||||
}
|
||||
|
||||
void
|
||||
llarp_dht_context_free(struct llarp_dht_context* ctx)
|
||||
{
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
void
|
||||
__llarp_dht_remove_peer(struct llarp_dht_context* ctx, const byte_t* id)
|
||||
{
|
||||
ctx->impl->Nodes()->DelNode(llarp::dht::Key_t(id));
|
||||
}
|
||||
|
||||
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(llarp::dht::Key_t(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;
|
||||
job->result.Clear();
|
||||
// llarp_rc_clear(&job->result);
|
||||
llarp::LogError("implement me llarp_dht_lookup_router");
|
||||
/*
|
||||
ctx->parent->logic->queue_job(
|
||||
{job, &llarp::dht::Context::queue_router_lookup});
|
||||
*/
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/crypto/crypto.hpp>
|
||||
#include <llarp/router_contact.hpp>
|
||||
#include <llarp/util/buffer.hpp>
|
||||
|
||||
/**
|
||||
* dht.h
|
||||
*
|
||||
* DHT functions
|
||||
*/
|
||||
|
||||
struct llarp_dht_context;
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct Router;
|
||||
}
|
||||
|
||||
/// allocator
|
||||
struct llarp_dht_context*
|
||||
llarp_dht_context_new(llarp::Router* parent);
|
||||
|
||||
/// deallocator
|
||||
void
|
||||
llarp_dht_context_free(struct llarp_dht_context* dht);
|
||||
|
||||
/// start dht context with our location in keyspace
|
||||
void
|
||||
llarp_dht_context_start(struct llarp_dht_context* ctx, const byte_t* key);
|
||||
|
||||
// remove this? dns needs it atm
|
||||
struct llarp_router_lookup_job;
|
||||
|
||||
using llarp_router_lookup_handler = void (*)(struct llarp_router_lookup_job*);
|
||||
|
||||
struct llarp_router_lookup_job
|
||||
{
|
||||
/// can be anything but usually a class context for hook
|
||||
void* user;
|
||||
llarp_router_lookup_handler hook;
|
||||
struct llarp_dht_context* dht;
|
||||
llarp::PubKey target;
|
||||
bool found;
|
||||
// make sure you initialize addr and exits
|
||||
llarp::RouterContact result;
|
||||
bool iterative;
|
||||
};
|
||||
// end dns requirement
|
||||
|
||||
/// start allowing dht participation on a context
|
||||
void
|
||||
llarp_dht_allow_transit(struct llarp_dht_context* ctx);
|
||||
|
||||
/// remove router from tracked dht peer list
|
||||
/// internal function do not use
|
||||
void
|
||||
__llarp_dht_remove_peer(struct llarp_dht_context* ctx, const byte_t* id);
|
||||
|
||||
void
|
||||
llarp_dht_lookup_router(struct llarp_dht_context* ctx, struct llarp_router_lookup_job* job);
|
@ -1,39 +0,0 @@
|
||||
#include "explorenetworkjob.hpp"
|
||||
|
||||
#include <llarp/dht/messages/findrouter.hpp>
|
||||
#include <llarp/router/router.hpp>
|
||||
|
||||
#include <llarp/nodedb.hpp>
|
||||
|
||||
#include <llarp/tooling/dht_event.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
void
|
||||
ExploreNetworkJob::Start(const TXOwner& peer)
|
||||
{
|
||||
auto msg = new FindRouterMessage(peer.txid);
|
||||
auto router = parent->GetRouter();
|
||||
if (router)
|
||||
{
|
||||
router->notify_router_event<tooling::FindRouterSentEvent>(router->pubkey(), *msg);
|
||||
}
|
||||
parent->DHTSendTo(peer.node.as_array(), msg);
|
||||
}
|
||||
|
||||
void
|
||||
ExploreNetworkJob::SendReply()
|
||||
{
|
||||
llarp::LogDebug("got ", valuesFound.size(), " routers from exploration");
|
||||
|
||||
auto router = parent->GetRouter();
|
||||
for (const auto& pk : valuesFound)
|
||||
{
|
||||
// lookup router
|
||||
if (router and router->node_db()->Has(pk))
|
||||
continue;
|
||||
parent->LookupRouter(
|
||||
pk, [router, pk](const auto& res) { router->HandleDHTLookupForExplore(pk, res); });
|
||||
}
|
||||
}
|
||||
} // namespace llarp::dht
|
@ -1,30 +0,0 @@
|
||||
#ifndef LLARP_DHT_EXPLORENETWORKJOB
|
||||
#define LLARP_DHT_EXPLORENETWORKJOB
|
||||
|
||||
#include "tx.hpp"
|
||||
#include <llarp/router_id.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
struct ExploreNetworkJob : public TX<RouterID, RouterID>
|
||||
{
|
||||
ExploreNetworkJob(const RouterID& peer, AbstractDHTMessageHandler* ctx)
|
||||
: TX<RouterID, RouterID>(TXOwner{}, peer, ctx)
|
||||
{}
|
||||
|
||||
bool
|
||||
Validate(const RouterID&) const override
|
||||
{
|
||||
// TODO: check with lokid
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Start(const TXOwner& peer) override;
|
||||
|
||||
void
|
||||
SendReply() override;
|
||||
};
|
||||
} // namespace llarp::dht
|
||||
|
||||
#endif
|
@ -1,61 +0,0 @@
|
||||
#include "localrouterlookup.hpp"
|
||||
|
||||
#include "context.hpp"
|
||||
#include <llarp/dht/messages/gotrouter.hpp>
|
||||
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/router/router.hpp>
|
||||
#include <llarp/routing/path_dht_message.hpp>
|
||||
#include <llarp/util/logging.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
LocalRouterLookup::LocalRouterLookup(
|
||||
const PathID_t& path, uint64_t txid, const RouterID& _target, AbstractDHTMessageHandler* ctx)
|
||||
: RecursiveRouterLookup(TXOwner{ctx->OurKey(), txid}, _target, ctx, nullptr), localPath(path)
|
||||
{}
|
||||
|
||||
void
|
||||
LocalRouterLookup::SendReply()
|
||||
{
|
||||
auto path =
|
||||
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
|
||||
if (!path)
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"did not send reply for relayed dht request, no such local path "
|
||||
"for pathid=",
|
||||
localPath);
|
||||
return;
|
||||
}
|
||||
if (valuesFound.size())
|
||||
{
|
||||
RouterContact found;
|
||||
for (const auto& rc : valuesFound)
|
||||
{
|
||||
if (rc.OtherIsNewer(found))
|
||||
found = rc;
|
||||
}
|
||||
valuesFound.clear();
|
||||
if (not found.pubkey.IsZero())
|
||||
{
|
||||
valuesFound.resize(1);
|
||||
valuesFound[0] = found;
|
||||
}
|
||||
else
|
||||
{
|
||||
llarp::LogWarn("We found a null RC for dht request, dropping it");
|
||||
}
|
||||
}
|
||||
routing::PathDHTMessage msg;
|
||||
msg.dht_msgs.emplace_back(
|
||||
new GotRouterMessage(parent->OurKey(), whoasked.txid, valuesFound, true));
|
||||
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"failed to send routing message when informing result of dht "
|
||||
"request, pathid=",
|
||||
localPath);
|
||||
}
|
||||
}
|
||||
} // namespace llarp::dht
|
@ -1,27 +0,0 @@
|
||||
#ifndef LLARP_DHT_LOCALROUTERLOOKUP
|
||||
#define LLARP_DHT_LOCALROUTERLOOKUP
|
||||
|
||||
#include "recursiverouterlookup.hpp"
|
||||
|
||||
#include <llarp/path/path_types.hpp>
|
||||
#include <llarp/router_contact.hpp>
|
||||
#include <llarp/router_id.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
struct LocalRouterLookup : public RecursiveRouterLookup
|
||||
{
|
||||
PathID_t localPath;
|
||||
|
||||
LocalRouterLookup(
|
||||
const PathID_t& path,
|
||||
uint64_t txid,
|
||||
const RouterID& target,
|
||||
AbstractDHTMessageHandler* ctx);
|
||||
|
||||
void
|
||||
SendReply() override;
|
||||
};
|
||||
} // namespace llarp::dht
|
||||
|
||||
#endif
|
@ -1,58 +0,0 @@
|
||||
#include "localserviceaddresslookup.hpp"
|
||||
|
||||
#include "context.hpp"
|
||||
#include <llarp/dht/messages/gotintro.hpp>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/router/router.hpp>
|
||||
#include <llarp/routing/path_dht_message.hpp>
|
||||
#include <llarp/util/logging.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
LocalServiceAddressLookup::LocalServiceAddressLookup(
|
||||
const PathID_t& pathid,
|
||||
uint64_t txid,
|
||||
uint64_t relayOrder,
|
||||
const Key_t& addr,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
[[maybe_unused]] const Key_t& askpeer)
|
||||
: ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, relayOrder, nullptr)
|
||||
, localPath(pathid)
|
||||
{}
|
||||
|
||||
void
|
||||
LocalServiceAddressLookup::SendReply()
|
||||
{
|
||||
auto path =
|
||||
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
|
||||
if (!path)
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"did not send reply for relayed dht request, no such local path "
|
||||
"for pathid=",
|
||||
localPath);
|
||||
return;
|
||||
}
|
||||
// pick newest if we have more than 1 result
|
||||
if (valuesFound.size())
|
||||
{
|
||||
service::EncryptedIntroSet found;
|
||||
for (const auto& introset : valuesFound)
|
||||
{
|
||||
if (found.OtherIsNewer(introset))
|
||||
found = introset;
|
||||
}
|
||||
valuesFound.clear();
|
||||
valuesFound.emplace_back(found);
|
||||
}
|
||||
routing::PathDHTMessage msg;
|
||||
msg.dht_msgs.emplace_back(new GotIntroMessage(valuesFound, whoasked.txid));
|
||||
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"failed to send routing message when informing result of dht "
|
||||
"request, pathid=",
|
||||
localPath);
|
||||
}
|
||||
}
|
||||
} // namespace llarp::dht
|
@ -1,28 +0,0 @@
|
||||
#ifndef LLARP_DHT_LOCALSERVICEADDRESSLOOKUP
|
||||
#define LLARP_DHT_LOCALSERVICEADDRESSLOOKUP
|
||||
|
||||
#include "serviceaddresslookup.hpp"
|
||||
|
||||
#include <llarp/path/path_types.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
struct LocalServiceAddressLookup : public ServiceAddressLookup
|
||||
{
|
||||
PathID_t localPath;
|
||||
|
||||
LocalServiceAddressLookup(
|
||||
const PathID_t& pathid,
|
||||
uint64_t txid,
|
||||
uint64_t relayOrder,
|
||||
const Key_t& addr,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
[[maybe_unused]] const Key_t& askpeer);
|
||||
|
||||
void
|
||||
SendReply() override;
|
||||
};
|
||||
|
||||
} // namespace llarp::dht
|
||||
|
||||
#endif
|
@ -1,42 +0,0 @@
|
||||
#include "localtaglookup.hpp"
|
||||
|
||||
#include "context.hpp"
|
||||
#include <llarp/dht/messages/gotintro.hpp>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/router/router.hpp>
|
||||
#include <llarp/routing/path_dht_message.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
LocalTagLookup::LocalTagLookup(
|
||||
const PathID_t& path,
|
||||
uint64_t txid,
|
||||
const service::Tag& _target,
|
||||
AbstractDHTMessageHandler* ctx)
|
||||
: TagLookup(TXOwner{ctx->OurKey(), txid}, _target, ctx, 0), localPath(path)
|
||||
{}
|
||||
|
||||
void
|
||||
LocalTagLookup::SendReply()
|
||||
{
|
||||
auto path =
|
||||
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
|
||||
if (!path)
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"did not send reply for relayed dht request, no such local path "
|
||||
"for pathid=",
|
||||
localPath);
|
||||
return;
|
||||
}
|
||||
routing::PathDHTMessage msg;
|
||||
msg.dht_msgs.emplace_back(new GotIntroMessage(valuesFound, whoasked.txid));
|
||||
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"failed to send routing message when informing result of dht "
|
||||
"request, pathid=",
|
||||
localPath);
|
||||
}
|
||||
}
|
||||
} // namespace llarp::dht
|
@ -1,23 +0,0 @@
|
||||
#ifndef LLARP_DHT_LOOKUPTAGLOOKUP
|
||||
#define LLARP_DHT_LOOKUPTAGLOOKUP
|
||||
|
||||
#include "taglookup.hpp"
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
struct LocalTagLookup : public TagLookup
|
||||
{
|
||||
PathID_t localPath;
|
||||
|
||||
LocalTagLookup(
|
||||
const PathID_t& path,
|
||||
uint64_t txid,
|
||||
const service::Tag& target,
|
||||
AbstractDHTMessageHandler* ctx);
|
||||
|
||||
void
|
||||
SendReply() override;
|
||||
};
|
||||
} // namespace llarp::dht
|
||||
|
||||
#endif
|
@ -1,138 +0,0 @@
|
||||
#include "context.hpp"
|
||||
#include "oxenc/bt_serialize.h"
|
||||
|
||||
#include <memory>
|
||||
#include <llarp/util/bencode.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>
|
||||
#include <llarp/dht/messages/findname.hpp>
|
||||
#include <llarp/dht/messages/gotname.hpp>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
struct MessageDecoder
|
||||
{
|
||||
const Key_t& From;
|
||||
std::unique_ptr<AbstractDHTMessage> msg;
|
||||
bool firstKey = true;
|
||||
bool relayed = false;
|
||||
|
||||
MessageDecoder(const Key_t& from, bool wasRelayed) : From(from), relayed(wasRelayed)
|
||||
{}
|
||||
|
||||
bool
|
||||
operator()(llarp_buffer_t* buffer, llarp_buffer_t* key)
|
||||
{
|
||||
llarp_buffer_t strbuf;
|
||||
// check for empty dict
|
||||
if (!key)
|
||||
return !firstKey;
|
||||
// first key
|
||||
if (firstKey)
|
||||
{
|
||||
if (!(key->startswith("A")))
|
||||
return false;
|
||||
if (!bencode_read_string(buffer, &strbuf))
|
||||
return false;
|
||||
// bad msg size?
|
||||
if (strbuf.sz != 1)
|
||||
return false;
|
||||
llarp::LogDebug("Handle DHT message ", *strbuf.base, " relayed=", relayed);
|
||||
switch (*strbuf.base)
|
||||
{
|
||||
case 'N':
|
||||
msg = std::make_unique<FindNameMessage>(From, Key_t{}, 0);
|
||||
break;
|
||||
case 'M':
|
||||
msg = std::make_unique<GotNameMessage>(From, 0, service::EncryptedName{});
|
||||
break;
|
||||
case 'F':
|
||||
msg = std::make_unique<FindIntroMessage>(From, relayed, 0);
|
||||
break;
|
||||
case 'R':
|
||||
if (relayed)
|
||||
msg = std::make_unique<RelayedFindRouterMessage>(From);
|
||||
else
|
||||
msg = std::make_unique<FindRouterMessage>(From);
|
||||
break;
|
||||
case 'S':
|
||||
msg = std::make_unique<GotRouterMessage>(From, relayed);
|
||||
break;
|
||||
case 'I':
|
||||
msg = std::make_unique<PublishIntroMessage>(From, relayed);
|
||||
break;
|
||||
case 'G':
|
||||
if (relayed)
|
||||
{
|
||||
msg = std::make_unique<RelayedGotIntroMessage>();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = std::make_unique<GotIntroMessage>(From);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llarp::LogWarn("unknown dht message type: ", (char)*strbuf.base);
|
||||
// bad msg type
|
||||
return false;
|
||||
}
|
||||
firstKey = false;
|
||||
return msg != nullptr;
|
||||
}
|
||||
|
||||
return msg->decode_key(*key, buffer);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<AbstractDHTMessage>
|
||||
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed)
|
||||
{
|
||||
MessageDecoder dec(from, relayed);
|
||||
if (!bencode_read_dict(dec, buf))
|
||||
return nullptr;
|
||||
|
||||
return std::move(dec.msg);
|
||||
}
|
||||
|
||||
struct ListDecoder
|
||||
{
|
||||
ListDecoder(
|
||||
bool hasRelayed, const Key_t& from, std::vector<std::unique_ptr<AbstractDHTMessage>>& list)
|
||||
: relayed(hasRelayed), From(from), l(list)
|
||||
{}
|
||||
|
||||
bool relayed;
|
||||
const Key_t& From;
|
||||
std::vector<std::unique_ptr<AbstractDHTMessage>>& l;
|
||||
|
||||
bool
|
||||
operator()(llarp_buffer_t* buffer, bool has)
|
||||
{
|
||||
if (!has)
|
||||
return true;
|
||||
auto msg = DecodeMessage(From, buffer, relayed);
|
||||
if (msg)
|
||||
{
|
||||
l.emplace_back(std::move(msg));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
DecodeMessageList(
|
||||
Key_t from,
|
||||
llarp_buffer_t* buf,
|
||||
std::vector<std::unique_ptr<AbstractDHTMessage>>& list,
|
||||
bool relayed)
|
||||
{
|
||||
ListDecoder dec(relayed, from, list);
|
||||
return bencode_read_list(dec, buf);
|
||||
}
|
||||
} // namespace llarp::dht
|
@ -1,81 +0,0 @@
|
||||
#include "publishservicejob.hpp"
|
||||
|
||||
#include "context.hpp"
|
||||
#include <llarp/dht/messages/pubintro.hpp>
|
||||
#include <llarp/dht/messages/gotintro.hpp>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/routing/path_dht_message.hpp>
|
||||
#include <llarp/router/router.hpp>
|
||||
|
||||
#include <utility>
|
||||
namespace llarp::dht
|
||||
{
|
||||
PublishServiceJob::PublishServiceJob(
|
||||
const TXOwner& asker,
|
||||
const service::EncryptedIntroSet& introset_,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
uint64_t relayOrder_)
|
||||
: TX<TXOwner, service::EncryptedIntroSet>(asker, asker, ctx)
|
||||
, relayOrder(relayOrder_)
|
||||
, introset(introset_)
|
||||
{}
|
||||
|
||||
bool
|
||||
PublishServiceJob::Validate(const service::EncryptedIntroSet& value) const
|
||||
{
|
||||
if (value.derivedSigningKey != introset.derivedSigningKey)
|
||||
{
|
||||
llarp::LogWarn("publish introset acknowledgement acked a different service");
|
||||
return false;
|
||||
}
|
||||
const llarp_time_t now = llarp::time_now_ms();
|
||||
return value.verify(now);
|
||||
}
|
||||
|
||||
void
|
||||
PublishServiceJob::Start(const TXOwner& peer)
|
||||
{
|
||||
parent->DHTSendTo(
|
||||
peer.node.as_array(), new PublishIntroMessage(introset, peer.txid, false, relayOrder));
|
||||
}
|
||||
|
||||
void
|
||||
PublishServiceJob::SendReply()
|
||||
{
|
||||
parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage({introset}, whoasked.txid));
|
||||
}
|
||||
|
||||
LocalPublishServiceJob::LocalPublishServiceJob(
|
||||
const TXOwner& peer,
|
||||
const PathID_t& fromID,
|
||||
uint64_t _txid,
|
||||
const service::EncryptedIntroSet& introset,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
uint64_t relayOrder)
|
||||
: PublishServiceJob(peer, introset, ctx, relayOrder), localPath(fromID), txid(_txid)
|
||||
{}
|
||||
|
||||
void
|
||||
LocalPublishServiceJob::SendReply()
|
||||
{
|
||||
auto path =
|
||||
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
|
||||
if (!path)
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"did not send reply for relayed dht request, no such local path "
|
||||
"for pathid=",
|
||||
localPath);
|
||||
return;
|
||||
}
|
||||
routing::PathDHTMessage msg;
|
||||
msg.dht_msgs.emplace_back(new GotIntroMessage({introset}, txid));
|
||||
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
|
||||
{
|
||||
llarp::LogWarn(
|
||||
"failed to send routing message when informing result of dht "
|
||||
"request, pathid=",
|
||||
localPath);
|
||||
}
|
||||
}
|
||||
} // namespace llarp::dht
|
@ -1,51 +0,0 @@
|
||||
#ifndef LLARP_DHT_PUBLISHSERVICEJOB
|
||||
#define LLARP_DHT_PUBLISHSERVICEJOB
|
||||
|
||||
#include "tx.hpp"
|
||||
#include "txowner.hpp"
|
||||
#include <llarp/service/address.hpp>
|
||||
#include <llarp/service/intro_set.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
struct PublishServiceJob : public TX<TXOwner, service::EncryptedIntroSet>
|
||||
{
|
||||
uint64_t relayOrder;
|
||||
service::EncryptedIntroSet introset;
|
||||
|
||||
PublishServiceJob(
|
||||
const TXOwner& asker,
|
||||
const service::EncryptedIntroSet& introset,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
uint64_t relayOrder);
|
||||
|
||||
bool
|
||||
Validate(const service::EncryptedIntroSet& introset) const override;
|
||||
|
||||
void
|
||||
Start(const TXOwner& peer) override;
|
||||
|
||||
void
|
||||
SendReply() override;
|
||||
};
|
||||
|
||||
struct LocalPublishServiceJob : public PublishServiceJob
|
||||
{
|
||||
PathID_t localPath;
|
||||
uint64_t txid;
|
||||
LocalPublishServiceJob(
|
||||
const TXOwner& peer,
|
||||
const PathID_t& fromID,
|
||||
uint64_t txid,
|
||||
const service::EncryptedIntroSet& introset,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
uint64_t relayOrder);
|
||||
|
||||
void
|
||||
SendReply() override;
|
||||
};
|
||||
} // namespace llarp::dht
|
||||
|
||||
#endif
|
@ -1,71 +0,0 @@
|
||||
#include "recursiverouterlookup.hpp"
|
||||
|
||||
#include "context.hpp"
|
||||
#include <llarp/dht/messages/findrouter.hpp>
|
||||
#include <llarp/dht/messages/gotrouter.hpp>
|
||||
|
||||
#include <llarp/router/router.hpp>
|
||||
#include <llarp/router/rc_lookup_handler.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
RecursiveRouterLookup::RecursiveRouterLookup(
|
||||
const TXOwner& _whoasked,
|
||||
const RouterID& _target,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
RouterLookupHandler result)
|
||||
: TX<RouterID, RouterContact>(_whoasked, _target, ctx), resultHandler(std::move(result))
|
||||
|
||||
{
|
||||
peersAsked.insert(ctx->OurKey());
|
||||
}
|
||||
|
||||
bool
|
||||
RecursiveRouterLookup::Validate(const RouterContact& rc) const
|
||||
{
|
||||
if (!rc.Verify(parent->Now()))
|
||||
{
|
||||
llarp::LogWarn("rc from lookup result is invalid");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveRouterLookup::Start(const TXOwner& peer)
|
||||
{
|
||||
parent->DHTSendTo(peer.node.as_array(), new FindRouterMessage(peer.txid, target));
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveRouterLookup::SendReply()
|
||||
{
|
||||
if (valuesFound.size())
|
||||
{
|
||||
RouterContact found;
|
||||
for (const auto& rc : valuesFound)
|
||||
{
|
||||
if (found.OtherIsNewer(rc) && parent->GetRouter()->rc_lookup_handler().check_rc(rc))
|
||||
found = rc;
|
||||
}
|
||||
valuesFound.clear();
|
||||
valuesFound.emplace_back(found);
|
||||
}
|
||||
if (resultHandler)
|
||||
{
|
||||
resultHandler(valuesFound);
|
||||
}
|
||||
if (whoasked.node != parent->OurKey())
|
||||
{
|
||||
parent->DHTSendTo(
|
||||
whoasked.node.as_array(),
|
||||
new GotRouterMessage({}, whoasked.txid, valuesFound, false),
|
||||
false);
|
||||
}
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,34 +0,0 @@
|
||||
#ifndef LLARP_DHT_RECURSIVEROUTERLOOKUP
|
||||
#define LLARP_DHT_RECURSIVEROUTERLOOKUP
|
||||
|
||||
#include "tx.hpp"
|
||||
|
||||
#include <llarp/router_contact.hpp>
|
||||
#include <llarp/router_id.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct RecursiveRouterLookup : public TX<RouterID, RouterContact>
|
||||
{
|
||||
RouterLookupHandler resultHandler;
|
||||
RecursiveRouterLookup(
|
||||
const TXOwner& whoasked,
|
||||
const RouterID& target,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
RouterLookupHandler result);
|
||||
|
||||
bool
|
||||
Validate(const RouterContact& rc) const override;
|
||||
|
||||
void
|
||||
Start(const TXOwner& peer) override;
|
||||
|
||||
void
|
||||
SendReply() override;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -1,70 +0,0 @@
|
||||
#include "serviceaddresslookup.hpp"
|
||||
|
||||
#include <llarp/dht/messages/findintro.hpp>
|
||||
#include <llarp/dht/messages/gotintro.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
ServiceAddressLookup::ServiceAddressLookup(
|
||||
const TXOwner& asker,
|
||||
const Key_t& addr,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
uint32_t order,
|
||||
service::EncryptedIntroSetLookupHandler handler)
|
||||
: TX<TXOwner, service::EncryptedIntroSet>(asker, asker, ctx)
|
||||
, location(addr)
|
||||
, handleResult(std::move(handler))
|
||||
, relayOrder(order)
|
||||
{
|
||||
peersAsked.insert(ctx->OurKey());
|
||||
}
|
||||
|
||||
bool
|
||||
ServiceAddressLookup::Validate(const service::EncryptedIntroSet& value) const
|
||||
{
|
||||
if (!value.verify(parent->Now()))
|
||||
{
|
||||
llarp::LogWarn("Got invalid introset from service lookup");
|
||||
return false;
|
||||
}
|
||||
if (value.derivedSigningKey != location)
|
||||
{
|
||||
llarp::LogWarn("got introset with wrong target from service lookup");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceAddressLookup::Start(const TXOwner& peer)
|
||||
{
|
||||
parent->DHTSendTo(
|
||||
peer.node.as_array(), new FindIntroMessage(peer.txid, location, relayOrder));
|
||||
}
|
||||
|
||||
void
|
||||
ServiceAddressLookup::SendReply()
|
||||
{
|
||||
// get newest introset
|
||||
if (valuesFound.size())
|
||||
{
|
||||
llarp::service::EncryptedIntroSet found;
|
||||
for (const auto& introset : valuesFound)
|
||||
{
|
||||
if (found.OtherIsNewer(introset))
|
||||
found = introset;
|
||||
}
|
||||
valuesFound.clear();
|
||||
valuesFound.emplace_back(found);
|
||||
}
|
||||
if (handleResult)
|
||||
{
|
||||
handleResult(valuesFound);
|
||||
}
|
||||
parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage(valuesFound, whoasked.txid));
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,41 +0,0 @@
|
||||
#ifndef LLARP_DHT_SERVICEADDRESSLOOKUP
|
||||
#define LLARP_DHT_SERVICEADDRESSLOOKUP
|
||||
|
||||
#include "key.hpp"
|
||||
#include "tx.hpp"
|
||||
#include <llarp/service/address.hpp>
|
||||
#include <llarp/service/intro_set.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct TXOwner;
|
||||
|
||||
struct ServiceAddressLookup : public TX<TXOwner, service::EncryptedIntroSet>
|
||||
{
|
||||
Key_t location;
|
||||
service::EncryptedIntroSetLookupHandler handleResult;
|
||||
uint32_t relayOrder;
|
||||
|
||||
ServiceAddressLookup(
|
||||
const TXOwner& asker,
|
||||
const Key_t& addr,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
uint32_t relayOrder,
|
||||
service::EncryptedIntroSetLookupHandler handler);
|
||||
|
||||
bool
|
||||
Validate(const service::EncryptedIntroSet& value) const override;
|
||||
|
||||
void
|
||||
Start(const TXOwner& peer) override;
|
||||
|
||||
void
|
||||
SendReply() override;
|
||||
};
|
||||
} // namespace dht
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -1,40 +0,0 @@
|
||||
#include "taglookup.hpp"
|
||||
|
||||
#include "context.hpp"
|
||||
#include <llarp/dht/messages/gotintro.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
bool
|
||||
TagLookup::Validate(const service::EncryptedIntroSet& introset) const
|
||||
{
|
||||
if (!introset.verify(parent->Now()))
|
||||
{
|
||||
llarp::LogWarn("got invalid introset from tag lookup");
|
||||
return false;
|
||||
}
|
||||
if (not introset.topic)
|
||||
return false;
|
||||
if (*introset.topic != target)
|
||||
{
|
||||
llarp::LogWarn("got introset with mismatched topic in tag lookup");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TagLookup::Start(const TXOwner& peer)
|
||||
{
|
||||
parent->DHTSendTo(peer.node.as_array(), new FindIntroMessage(target, peer.txid));
|
||||
}
|
||||
|
||||
void
|
||||
TagLookup::SendReply()
|
||||
{
|
||||
parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage({}, whoasked.txid));
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
@ -1,35 +0,0 @@
|
||||
#ifndef LLARP_DHT_TAGLOOKUP
|
||||
#define LLARP_DHT_TAGLOOKUP
|
||||
|
||||
#include "tx.hpp"
|
||||
#include <llarp/service/intro_set.hpp>
|
||||
#include <llarp/service/tag.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct TagLookup : public TX<service::Tag, service::EncryptedIntroSet>
|
||||
{
|
||||
uint64_t recursionDepth;
|
||||
TagLookup(
|
||||
const TXOwner& asker,
|
||||
const service::Tag& tag,
|
||||
AbstractDHTMessageHandler* ctx,
|
||||
uint64_t recursion)
|
||||
: TX<service::Tag, service::EncryptedIntroSet>(asker, tag, ctx), recursionDepth(recursion)
|
||||
{}
|
||||
|
||||
bool
|
||||
Validate(const service::EncryptedIntroSet& introset) const override;
|
||||
|
||||
void
|
||||
Start(const TXOwner& peer) override;
|
||||
|
||||
void
|
||||
SendReply() override;
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -1,79 +0,0 @@
|
||||
#ifndef LLARP_DHT_TX
|
||||
#define LLARP_DHT_TX
|
||||
|
||||
#include "key.hpp"
|
||||
#include "txowner.hpp"
|
||||
#include <llarp/util/logging.hpp>
|
||||
#include <llarp/util/status.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp::dht
|
||||
{
|
||||
struct AbstractDHTMessageHandler;
|
||||
|
||||
template <typename K, typename V>
|
||||
struct TX
|
||||
{
|
||||
K target;
|
||||
AbstractDHTMessageHandler* parent;
|
||||
std::set<Key_t> peersAsked;
|
||||
std::vector<V> valuesFound;
|
||||
TXOwner whoasked;
|
||||
|
||||
TX(const TXOwner& asker, const K& k, AbstractDHTMessageHandler* p)
|
||||
: target(k), parent(p), whoasked(asker)
|
||||
{}
|
||||
|
||||
virtual ~TX() = default;
|
||||
|
||||
void
|
||||
OnFound(const Key_t& askedPeer, const V& value);
|
||||
|
||||
util::StatusObject
|
||||
ExtractStatus() const
|
||||
{
|
||||
util::StatusObject obj{
|
||||
{"whoasked", whoasked.ExtractStatus()}, {"target", target.ExtractStatus()}};
|
||||
std::vector<util::StatusObject> foundObjs;
|
||||
std::transform(
|
||||
valuesFound.begin(),
|
||||
valuesFound.end(),
|
||||
std::back_inserter(foundObjs),
|
||||
[](const auto& item) -> util::StatusObject { return item.ExtractStatus(); });
|
||||
|
||||
obj["found"] = foundObjs;
|
||||
std::vector<std::string> asked;
|
||||
std::transform(
|
||||
peersAsked.begin(),
|
||||
peersAsked.end(),
|
||||
std::back_inserter(asked),
|
||||
[](const auto& item) -> std::string { return item.ToString(); });
|
||||
obj["asked"] = asked;
|
||||
return obj;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
Validate(const V& value) const = 0;
|
||||
|
||||
virtual void
|
||||
Start(const TXOwner& peer) = 0;
|
||||
|
||||
virtual void
|
||||
SendReply() = 0;
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
inline void
|
||||
TX<K, V>::OnFound(const Key_t& askedPeer, const V& value)
|
||||
{
|
||||
peersAsked.insert(askedPeer);
|
||||
if (Validate(value))
|
||||
{
|
||||
valuesFound.push_back(value);
|
||||
}
|
||||
}
|
||||
} // namespace llarp::dht
|
||||
|
||||
#endif
|
@ -1,216 +0,0 @@
|
||||
#ifndef LLARP_DHT_TXHOLDER
|
||||
#define LLARP_DHT_TXHOLDER
|
||||
|
||||
#include "tx.hpp"
|
||||
#include "txowner.hpp"
|
||||
#include <llarp/util/time.hpp>
|
||||
#include <llarp/util/status.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
template <typename K, typename V>
|
||||
struct TXHolder
|
||||
{
|
||||
using TXPtr = std::unique_ptr<TX<K, V>>;
|
||||
// tx who are waiting for a reply for each key
|
||||
std::unordered_multimap<K, TXOwner> waiting;
|
||||
// tx timesouts by key
|
||||
std::unordered_map<K, llarp_time_t> timeouts;
|
||||
// maps remote peer with tx to handle reply from them
|
||||
std::unordered_map<TXOwner, TXPtr> tx;
|
||||
|
||||
const TX<K, V>*
|
||||
GetPendingLookupFrom(const TXOwner& owner) const;
|
||||
|
||||
util::StatusObject
|
||||
ExtractStatus() const
|
||||
{
|
||||
util::StatusObject obj{};
|
||||
std::vector<util::StatusObject> txObjs, timeoutsObjs, waitingObjs;
|
||||
std::transform(
|
||||
tx.begin(),
|
||||
tx.end(),
|
||||
std::back_inserter(txObjs),
|
||||
[](const auto& item) -> util::StatusObject {
|
||||
return util::StatusObject{
|
||||
{"owner", item.first.ExtractStatus()}, {"tx", item.second->ExtractStatus()}};
|
||||
});
|
||||
obj["tx"] = txObjs;
|
||||
std::transform(
|
||||
timeouts.begin(),
|
||||
timeouts.end(),
|
||||
std::back_inserter(timeoutsObjs),
|
||||
[](const auto& item) -> util::StatusObject {
|
||||
return util::StatusObject{
|
||||
{"time", to_json(item.second)}, {"target", item.first.ExtractStatus()}};
|
||||
});
|
||||
obj["timeouts"] = timeoutsObjs;
|
||||
std::transform(
|
||||
waiting.begin(),
|
||||
waiting.end(),
|
||||
std::back_inserter(waitingObjs),
|
||||
[](const auto& item) -> util::StatusObject {
|
||||
return util::StatusObject{
|
||||
{"target", item.first.ExtractStatus()},
|
||||
{"whoasked", item.second.ExtractStatus()}};
|
||||
});
|
||||
obj["waiting"] = waitingObjs;
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool
|
||||
HasLookupFor(const K& target) const
|
||||
{
|
||||
return timeouts.find(target) != timeouts.end();
|
||||
}
|
||||
|
||||
bool
|
||||
HasPendingLookupFrom(const TXOwner& owner) const
|
||||
{
|
||||
return GetPendingLookupFrom(owner) != nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
NewTX(
|
||||
const TXOwner& askpeer,
|
||||
const TXOwner& whoasked,
|
||||
const K& k,
|
||||
TX<K, V>* t,
|
||||
llarp_time_t requestTimeoutMS = 15s);
|
||||
|
||||
/// mark tx as not fond
|
||||
void
|
||||
NotFound(const TXOwner& from, const std::unique_ptr<Key_t>& next);
|
||||
|
||||
void
|
||||
Found(const TXOwner& from, const K& k, const std::vector<V>& values)
|
||||
{
|
||||
Inform(from, k, values, true);
|
||||
}
|
||||
|
||||
/// inform all watches for key of values found
|
||||
void
|
||||
Inform(
|
||||
TXOwner from,
|
||||
K key,
|
||||
std::vector<V> values,
|
||||
bool sendreply = false,
|
||||
bool removeTimeouts = true);
|
||||
|
||||
void
|
||||
Expire(llarp_time_t now);
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
const TX<K, V>*
|
||||
TXHolder<K, V>::GetPendingLookupFrom(const TXOwner& owner) const
|
||||
{
|
||||
auto itr = tx.find(owner);
|
||||
if (itr == tx.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return itr->second.get();
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void
|
||||
TXHolder<K, V>::NewTX(
|
||||
const TXOwner& askpeer,
|
||||
const TXOwner& whoasked,
|
||||
const K& k,
|
||||
TX<K, V>* t,
|
||||
llarp_time_t requestTimeoutMS)
|
||||
{
|
||||
(void)whoasked;
|
||||
tx.emplace(askpeer, std::unique_ptr<TX<K, V>>(t));
|
||||
auto count = waiting.count(k);
|
||||
waiting.emplace(k, askpeer);
|
||||
|
||||
auto itr = timeouts.find(k);
|
||||
if (itr == timeouts.end())
|
||||
{
|
||||
timeouts.emplace(k, time_now_ms() + requestTimeoutMS);
|
||||
}
|
||||
if (count == 0)
|
||||
{
|
||||
t->Start(askpeer);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void
|
||||
TXHolder<K, V>::NotFound(const TXOwner& from, const std::unique_ptr<Key_t>&)
|
||||
{
|
||||
auto txitr = tx.find(from);
|
||||
if (txitr == tx.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Inform(from, txitr->second->target, {}, true, true);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void
|
||||
TXHolder<K, V>::Inform(
|
||||
TXOwner from, K key, std::vector<V> values, bool sendreply, bool removeTimeouts)
|
||||
{
|
||||
auto range = waiting.equal_range(key);
|
||||
auto itr = range.first;
|
||||
while (itr != range.second)
|
||||
{
|
||||
auto txitr = tx.find(itr->second);
|
||||
if (txitr != tx.end())
|
||||
{
|
||||
for (const auto& value : values)
|
||||
{
|
||||
txitr->second->OnFound(from.node, value);
|
||||
}
|
||||
if (sendreply)
|
||||
{
|
||||
txitr->second->SendReply();
|
||||
tx.erase(txitr);
|
||||
}
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
|
||||
if (sendreply)
|
||||
{
|
||||
waiting.erase(key);
|
||||
}
|
||||
|
||||
if (removeTimeouts)
|
||||
{
|
||||
timeouts.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void
|
||||
TXHolder<K, V>::Expire(llarp_time_t now)
|
||||
{
|
||||
auto itr = timeouts.begin();
|
||||
while (itr != timeouts.end())
|
||||
{
|
||||
if (now >= itr->second)
|
||||
{
|
||||
Inform(TXOwner{}, itr->first, {}, true, false);
|
||||
itr = timeouts.erase(itr);
|
||||
}
|
||||
else
|
||||
{
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
@ -1,64 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "key.hpp"
|
||||
#include <llarp/util/status.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace dht
|
||||
{
|
||||
struct TXOwner
|
||||
{
|
||||
Key_t node;
|
||||
uint64_t txid = 0;
|
||||
|
||||
TXOwner() = default;
|
||||
TXOwner(const TXOwner&) = default;
|
||||
TXOwner(TXOwner&&) = default;
|
||||
|
||||
TXOwner&
|
||||
operator=(const TXOwner&) = default;
|
||||
|
||||
TXOwner(const Key_t& k, uint64_t id) : node(k), txid(id)
|
||||
{}
|
||||
|
||||
util::StatusObject
|
||||
ExtractStatus() const
|
||||
{
|
||||
util::StatusObject obj{
|
||||
{"txid", txid},
|
||||
{"node", node.ToHex()},
|
||||
};
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const TXOwner& other) const
|
||||
{
|
||||
return std::tie(txid, node) == std::tie(other.txid, other.node);
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const TXOwner& other) const
|
||||
{
|
||||
return std::tie(txid, node) < std::tie(other.txid, other.node);
|
||||
}
|
||||
};
|
||||
} // namespace dht
|
||||
} // namespace llarp
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<llarp::dht::TXOwner>
|
||||
{
|
||||
std::size_t
|
||||
operator()(const llarp::dht::TXOwner& o) const noexcept
|
||||
{
|
||||
std::size_t sz2;
|
||||
memcpy(&sz2, o.node.data(), sizeof(std::size_t));
|
||||
return o.txid ^ (sz2 << 1);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
@ -1,30 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/util/logging.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::dns
|
||||
{
|
||||
namespace dns
|
||||
{
|
||||
constexpr uint16_t qTypeSRV = 33;
|
||||
constexpr uint16_t qTypeAAAA = 28;
|
||||
constexpr uint16_t qTypeTXT = 16;
|
||||
constexpr uint16_t qTypeMX = 15;
|
||||
constexpr uint16_t qTypePTR = 12;
|
||||
constexpr uint16_t qTypeCNAME = 5;
|
||||
constexpr uint16_t qTypeNS = 2;
|
||||
constexpr uint16_t qTypeA = 1;
|
||||
constexpr uint16_t qTypeSRV = 33;
|
||||
constexpr uint16_t qTypeAAAA = 28;
|
||||
constexpr uint16_t qTypeTXT = 16;
|
||||
constexpr uint16_t qTypeMX = 15;
|
||||
constexpr uint16_t qTypePTR = 12;
|
||||
constexpr uint16_t qTypeCNAME = 5;
|
||||
constexpr uint16_t qTypeNS = 2;
|
||||
constexpr uint16_t qTypeA = 1;
|
||||
|
||||
constexpr uint16_t qClassIN = 1;
|
||||
constexpr uint16_t qClassIN = 1;
|
||||
|
||||
constexpr uint16_t flags_QR = (1 << 15);
|
||||
constexpr uint16_t flags_AA = (1 << 10);
|
||||
constexpr uint16_t flags_TC = (1 << 9);
|
||||
constexpr uint16_t flags_RD = (1 << 8);
|
||||
constexpr uint16_t flags_RA = (1 << 7);
|
||||
constexpr uint16_t flags_RCODENameError = (3);
|
||||
constexpr uint16_t flags_RCODEServFail = (2);
|
||||
constexpr uint16_t flags_RCODENoError = (0);
|
||||
constexpr uint16_t flags_QR = (1 << 15);
|
||||
constexpr uint16_t flags_AA = (1 << 10);
|
||||
constexpr uint16_t flags_TC = (1 << 9);
|
||||
constexpr uint16_t flags_RD = (1 << 8);
|
||||
constexpr uint16_t flags_RA = (1 << 7);
|
||||
constexpr uint16_t flags_RCODENameError = (3);
|
||||
constexpr uint16_t flags_RCODEServFail = (2);
|
||||
constexpr uint16_t flags_RCODENoError = (0);
|
||||
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
} // namespace llarp::dns
|
||||
|
@ -1,434 +1,432 @@
|
||||
#include "message.hpp"
|
||||
#include <oxenc/endian.h>
|
||||
|
||||
#include "dns.hpp"
|
||||
#include "srv_data.hpp"
|
||||
#include <llarp/util/buffer.hpp>
|
||||
#include <llarp/util/logging.hpp>
|
||||
|
||||
#include <llarp/net/ip.hpp>
|
||||
#include <llarp/util/buffer.hpp>
|
||||
|
||||
#include <oxenc/endian.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::dns
|
||||
{
|
||||
namespace dns
|
||||
static auto logcat = log::Cat("dns");
|
||||
|
||||
bool
|
||||
MessageHeader::Encode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if (!buf->put_uint16(id))
|
||||
return false;
|
||||
if (!buf->put_uint16(fields))
|
||||
return false;
|
||||
if (!buf->put_uint16(qd_count))
|
||||
return false;
|
||||
if (!buf->put_uint16(an_count))
|
||||
return false;
|
||||
if (!buf->put_uint16(ns_count))
|
||||
return false;
|
||||
return buf->put_uint16(ar_count);
|
||||
}
|
||||
|
||||
bool
|
||||
MessageHeader::Decode(llarp_buffer_t* buf)
|
||||
{
|
||||
static auto logcat = log::Cat("dns");
|
||||
if (!buf->read_uint16(id))
|
||||
return false;
|
||||
if (!buf->read_uint16(fields))
|
||||
return false;
|
||||
if (!buf->read_uint16(qd_count))
|
||||
return false;
|
||||
if (!buf->read_uint16(an_count))
|
||||
return false;
|
||||
if (!buf->read_uint16(ns_count))
|
||||
return false;
|
||||
if (!buf->read_uint16(ar_count))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
util::StatusObject
|
||||
MessageHeader::ToJSON() const
|
||||
{
|
||||
return util::StatusObject{};
|
||||
}
|
||||
|
||||
Message::Message(Message&& other)
|
||||
: hdr_id(std::move(other.hdr_id))
|
||||
, hdr_fields(std::move(other.hdr_fields))
|
||||
, questions(std::move(other.questions))
|
||||
, answers(std::move(other.answers))
|
||||
, authorities(std::move(other.authorities))
|
||||
, additional(std::move(other.additional))
|
||||
{}
|
||||
|
||||
Message::Message(const Message& other)
|
||||
: hdr_id(other.hdr_id)
|
||||
, hdr_fields(other.hdr_fields)
|
||||
, questions(other.questions)
|
||||
, answers(other.answers)
|
||||
, authorities(other.authorities)
|
||||
, additional(other.additional)
|
||||
{}
|
||||
|
||||
Message::Message(const MessageHeader& hdr) : hdr_id(hdr.id), hdr_fields(hdr.fields)
|
||||
{
|
||||
questions.resize(size_t(hdr.qd_count));
|
||||
answers.resize(size_t(hdr.an_count));
|
||||
authorities.resize(size_t(hdr.ns_count));
|
||||
additional.resize(size_t(hdr.ar_count));
|
||||
}
|
||||
|
||||
bool
|
||||
MessageHeader::Encode(llarp_buffer_t* buf) const
|
||||
{
|
||||
if (!buf->put_uint16(id))
|
||||
return false;
|
||||
if (!buf->put_uint16(fields))
|
||||
return false;
|
||||
if (!buf->put_uint16(qd_count))
|
||||
return false;
|
||||
if (!buf->put_uint16(an_count))
|
||||
return false;
|
||||
if (!buf->put_uint16(ns_count))
|
||||
return false;
|
||||
return buf->put_uint16(ar_count);
|
||||
}
|
||||
Message::Message(const Question& question) : hdr_id{0}, hdr_fields{}
|
||||
{
|
||||
questions.emplace_back(question);
|
||||
}
|
||||
|
||||
bool
|
||||
MessageHeader::Decode(llarp_buffer_t* buf)
|
||||
{
|
||||
if (!buf->read_uint16(id))
|
||||
return false;
|
||||
if (!buf->read_uint16(fields))
|
||||
return false;
|
||||
if (!buf->read_uint16(qd_count))
|
||||
return false;
|
||||
if (!buf->read_uint16(an_count))
|
||||
return false;
|
||||
if (!buf->read_uint16(ns_count))
|
||||
return false;
|
||||
if (!buf->read_uint16(ar_count))
|
||||
bool
|
||||
Message::Encode(llarp_buffer_t* buf) const
|
||||
{
|
||||
MessageHeader hdr;
|
||||
hdr.id = hdr_id;
|
||||
hdr.fields = hdr_fields;
|
||||
hdr.qd_count = questions.size();
|
||||
hdr.an_count = answers.size();
|
||||
hdr.ns_count = 0;
|
||||
hdr.ar_count = 0;
|
||||
|
||||
if (!hdr.Encode(buf))
|
||||
return false;
|
||||
|
||||
for (const auto& question : questions)
|
||||
if (!question.Encode(buf))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
util::StatusObject
|
||||
MessageHeader::ToJSON() const
|
||||
{
|
||||
return util::StatusObject{};
|
||||
}
|
||||
|
||||
Message::Message(Message&& other)
|
||||
: hdr_id(std::move(other.hdr_id))
|
||||
, hdr_fields(std::move(other.hdr_fields))
|
||||
, questions(std::move(other.questions))
|
||||
, answers(std::move(other.answers))
|
||||
, authorities(std::move(other.authorities))
|
||||
, additional(std::move(other.additional))
|
||||
{}
|
||||
|
||||
Message::Message(const Message& other)
|
||||
: hdr_id(other.hdr_id)
|
||||
, hdr_fields(other.hdr_fields)
|
||||
, questions(other.questions)
|
||||
, answers(other.answers)
|
||||
, authorities(other.authorities)
|
||||
, additional(other.additional)
|
||||
{}
|
||||
|
||||
Message::Message(const MessageHeader& hdr) : hdr_id(hdr.id), hdr_fields(hdr.fields)
|
||||
{
|
||||
questions.resize(size_t(hdr.qd_count));
|
||||
answers.resize(size_t(hdr.an_count));
|
||||
authorities.resize(size_t(hdr.ns_count));
|
||||
additional.resize(size_t(hdr.ar_count));
|
||||
}
|
||||
|
||||
Message::Message(const Question& question) : hdr_id{0}, hdr_fields{}
|
||||
{
|
||||
questions.emplace_back(question);
|
||||
}
|
||||
|
||||
bool
|
||||
Message::Encode(llarp_buffer_t* buf) const
|
||||
{
|
||||
MessageHeader hdr;
|
||||
hdr.id = hdr_id;
|
||||
hdr.fields = hdr_fields;
|
||||
hdr.qd_count = questions.size();
|
||||
hdr.an_count = answers.size();
|
||||
hdr.ns_count = 0;
|
||||
hdr.ar_count = 0;
|
||||
|
||||
if (!hdr.Encode(buf))
|
||||
for (const auto& answer : answers)
|
||||
if (!answer.Encode(buf))
|
||||
return false;
|
||||
|
||||
for (const auto& question : questions)
|
||||
if (!question.Encode(buf))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& answer : answers)
|
||||
if (!answer.Encode(buf))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Message::Decode(llarp_buffer_t* buf)
|
||||
bool
|
||||
Message::Decode(llarp_buffer_t* buf)
|
||||
{
|
||||
for (auto& qd : questions)
|
||||
{
|
||||
for (auto& qd : questions)
|
||||
if (!qd.Decode(buf))
|
||||
{
|
||||
if (!qd.Decode(buf))
|
||||
{
|
||||
log::error(logcat, "failed to decode question");
|
||||
return false;
|
||||
}
|
||||
log::debug(logcat, "question: {}", qd);
|
||||
}
|
||||
for (auto& an : answers)
|
||||
{
|
||||
if (not an.Decode(buf))
|
||||
{
|
||||
log::debug(logcat, "failed to decode answer");
|
||||
return false;
|
||||
}
|
||||
log::error(logcat, "failed to decode question");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
log::debug(logcat, "question: {}", qd);
|
||||
}
|
||||
|
||||
util::StatusObject
|
||||
Message::ToJSON() const
|
||||
for (auto& an : answers)
|
||||
{
|
||||
std::vector<util::StatusObject> ques;
|
||||
std::vector<util::StatusObject> ans;
|
||||
for (const auto& q : questions)
|
||||
if (not an.Decode(buf))
|
||||
{
|
||||
ques.push_back(q.ToJSON());
|
||||
}
|
||||
for (const auto& a : answers)
|
||||
{
|
||||
ans.push_back(a.ToJSON());
|
||||
log::debug(logcat, "failed to decode answer");
|
||||
return false;
|
||||
}
|
||||
return util::StatusObject{{"questions", ques}, {"answers", ans}};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
OwnedBuffer
|
||||
Message::ToBuffer() const
|
||||
util::StatusObject
|
||||
Message::ToJSON() const
|
||||
{
|
||||
std::vector<util::StatusObject> ques;
|
||||
std::vector<util::StatusObject> ans;
|
||||
for (const auto& q : questions)
|
||||
{
|
||||
std::array<byte_t, 1500> tmp;
|
||||
llarp_buffer_t buf{tmp};
|
||||
if (not Encode(&buf))
|
||||
throw std::runtime_error("cannot encode dns message");
|
||||
return OwnedBuffer::copy_used(buf);
|
||||
ques.push_back(q.ToJSON());
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddServFail(RR_TTL_t)
|
||||
for (const auto& a : answers)
|
||||
{
|
||||
if (questions.size())
|
||||
{
|
||||
hdr_fields |= flags_RCODEServFail;
|
||||
// authorative response with recursion available
|
||||
hdr_fields |= flags_QR | flags_AA | flags_RA;
|
||||
// don't allow recursion on this request
|
||||
hdr_fields &= ~flags_RD;
|
||||
}
|
||||
ans.push_back(a.ToJSON());
|
||||
}
|
||||
return util::StatusObject{{"questions", ques}, {"answers", ans}};
|
||||
}
|
||||
|
||||
static constexpr uint16_t
|
||||
reply_flags(uint16_t setbits)
|
||||
OwnedBuffer
|
||||
Message::ToBuffer() const
|
||||
{
|
||||
std::array<byte_t, 1500> tmp;
|
||||
llarp_buffer_t buf{tmp};
|
||||
if (not Encode(&buf))
|
||||
throw std::runtime_error("cannot encode dns message");
|
||||
return OwnedBuffer::copy_used(buf);
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddServFail(RR_TTL_t)
|
||||
{
|
||||
if (questions.size())
|
||||
{
|
||||
return setbits | flags_QR | flags_AA | flags_RA;
|
||||
hdr_fields |= flags_RCODEServFail;
|
||||
// authorative response with recursion available
|
||||
hdr_fields |= flags_QR | flags_AA | flags_RA;
|
||||
// don't allow recursion on this request
|
||||
hdr_fields &= ~flags_RD;
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr uint16_t
|
||||
reply_flags(uint16_t setbits)
|
||||
{
|
||||
return setbits | flags_QR | flags_AA | flags_RA;
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddINReply(llarp::huint128_t ip, bool isV6, RR_TTL_t ttl)
|
||||
void
|
||||
Message::AddINReply(llarp::huint128_t ip, bool isV6, RR_TTL_t ttl)
|
||||
{
|
||||
if (questions.size())
|
||||
{
|
||||
if (questions.size())
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
ResourceRecord rec;
|
||||
rec.rr_name = questions[0].qname;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
if (isV6)
|
||||
{
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
ResourceRecord rec;
|
||||
rec.rr_name = questions[0].qname;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
if (isV6)
|
||||
{
|
||||
rec.rr_type = qTypeAAAA;
|
||||
ip.ToV6(rec.rData);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto addr = net::TruncateV6(ip);
|
||||
rec.rr_type = qTypeA;
|
||||
rec.rData.resize(4);
|
||||
oxenc::write_host_as_big(addr.h, rec.rData.data());
|
||||
}
|
||||
answers.emplace_back(std::move(rec));
|
||||
rec.rr_type = qTypeAAAA;
|
||||
ip.ToV6(rec.rData);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddAReply(std::string name, RR_TTL_t ttl)
|
||||
{
|
||||
if (questions.size())
|
||||
else
|
||||
{
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
|
||||
const auto& question = questions[0];
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = question.qtype;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
if (EncodeNameTo(&buf, name))
|
||||
{
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
const auto addr = net::TruncateV6(ip);
|
||||
rec.rr_type = qTypeA;
|
||||
rec.rData.resize(4);
|
||||
oxenc::write_host_as_big(addr.h, rec.rData.data());
|
||||
}
|
||||
answers.emplace_back(std::move(rec));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddNSReply(std::string name, RR_TTL_t ttl)
|
||||
void
|
||||
Message::AddAReply(std::string name, RR_TTL_t ttl)
|
||||
{
|
||||
if (questions.size())
|
||||
{
|
||||
if (not questions.empty())
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
|
||||
const auto& question = questions[0];
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = question.qtype;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
if (EncodeNameTo(&buf, name))
|
||||
{
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
|
||||
const auto& question = questions[0];
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = qTypeNS;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
if (EncodeNameTo(&buf, name))
|
||||
{
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddCNAMEReply(std::string name, RR_TTL_t ttl)
|
||||
void
|
||||
Message::AddNSReply(std::string name, RR_TTL_t ttl)
|
||||
{
|
||||
if (not questions.empty())
|
||||
{
|
||||
if (questions.size())
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
|
||||
const auto& question = questions[0];
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = qTypeNS;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
if (EncodeNameTo(&buf, name))
|
||||
{
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
|
||||
const auto& question = questions[0];
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = qTypeCNAME;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
if (EncodeNameTo(&buf, name))
|
||||
{
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddMXReply(std::string name, uint16_t priority, RR_TTL_t ttl)
|
||||
void
|
||||
Message::AddCNAMEReply(std::string name, RR_TTL_t ttl)
|
||||
{
|
||||
if (questions.size())
|
||||
{
|
||||
if (questions.size())
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
|
||||
const auto& question = questions[0];
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = qTypeCNAME;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
if (EncodeNameTo(&buf, name))
|
||||
{
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
|
||||
const auto& question = questions[0];
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = qTypeMX;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
buf.put_uint16(priority);
|
||||
if (EncodeNameTo(&buf, name))
|
||||
{
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddSRVReply(std::vector<SRVData> records, RR_TTL_t ttl)
|
||||
void
|
||||
Message::AddMXReply(std::string name, uint16_t priority, RR_TTL_t ttl)
|
||||
{
|
||||
if (questions.size())
|
||||
{
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
|
||||
const auto& question = questions[0];
|
||||
|
||||
for (const auto& srv : records)
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = qTypeMX;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
buf.put_uint16(priority);
|
||||
if (EncodeNameTo(&buf, name))
|
||||
{
|
||||
if (not srv.IsValid())
|
||||
{
|
||||
AddNXReply();
|
||||
return;
|
||||
}
|
||||
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = qTypeSRV;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.ttl = ttl;
|
||||
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
|
||||
buf.put_uint16(srv.priority);
|
||||
buf.put_uint16(srv.weight);
|
||||
buf.put_uint16(srv.port);
|
||||
|
||||
std::string target;
|
||||
if (srv.target == "")
|
||||
{
|
||||
// get location of second dot (after service.proto) in qname
|
||||
size_t pos = question.qname.find(".");
|
||||
pos = question.qname.find(".", pos + 1);
|
||||
|
||||
target = question.qname.substr(pos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = srv.target;
|
||||
}
|
||||
|
||||
if (not EncodeNameTo(&buf, target))
|
||||
{
|
||||
AddNXReply();
|
||||
return;
|
||||
}
|
||||
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddTXTReply(std::string str, RR_TTL_t ttl)
|
||||
void
|
||||
Message::AddSRVReply(std::vector<SRVData> records, RR_TTL_t ttl)
|
||||
{
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
|
||||
const auto& question = questions[0];
|
||||
|
||||
for (const auto& srv : records)
|
||||
{
|
||||
auto& rec = answers.emplace_back();
|
||||
rec.rr_name = questions[0].qname;
|
||||
if (not srv.IsValid())
|
||||
{
|
||||
AddNXReply();
|
||||
return;
|
||||
}
|
||||
|
||||
answers.emplace_back();
|
||||
auto& rec = answers.back();
|
||||
rec.rr_name = question.qname;
|
||||
rec.rr_type = qTypeSRV;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.rr_type = qTypeTXT;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 1024> tmp{};
|
||||
|
||||
std::array<byte_t, 512> tmp = {{0}};
|
||||
llarp_buffer_t buf(tmp);
|
||||
while (not str.empty())
|
||||
|
||||
buf.put_uint16(srv.priority);
|
||||
buf.put_uint16(srv.weight);
|
||||
buf.put_uint16(srv.port);
|
||||
|
||||
std::string target;
|
||||
if (srv.target == "")
|
||||
{
|
||||
const auto left = std::min(str.size(), size_t{256});
|
||||
const auto sub = str.substr(0, left);
|
||||
uint8_t byte = left;
|
||||
*buf.cur = byte;
|
||||
buf.cur++;
|
||||
if (not buf.write(sub.begin(), sub.end()))
|
||||
throw std::length_error("text record too big");
|
||||
str = str.substr(left);
|
||||
// get location of second dot (after service.proto) in qname
|
||||
size_t pos = question.qname.find(".");
|
||||
pos = question.qname.find(".", pos + 1);
|
||||
|
||||
target = question.qname.substr(pos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
target = srv.target;
|
||||
}
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
std::copy_n(buf.base, buf.sz, rec.rData.data());
|
||||
}
|
||||
|
||||
void
|
||||
Message::AddNXReply(RR_TTL_t)
|
||||
{
|
||||
if (questions.size())
|
||||
if (not EncodeNameTo(&buf, target))
|
||||
{
|
||||
answers.clear();
|
||||
authorities.clear();
|
||||
additional.clear();
|
||||
|
||||
// authorative response with recursion available
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
// don't allow recursion on this request
|
||||
hdr_fields &= ~flags_RD;
|
||||
hdr_fields |= flags_RCODENameError;
|
||||
AddNXReply();
|
||||
return;
|
||||
}
|
||||
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
memcpy(rec.rData.data(), buf.base, buf.sz);
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Message::ToString() const
|
||||
void
|
||||
Message::AddTXTReply(std::string str, RR_TTL_t ttl)
|
||||
{
|
||||
auto& rec = answers.emplace_back();
|
||||
rec.rr_name = questions[0].qname;
|
||||
rec.rr_class = qClassIN;
|
||||
rec.rr_type = qTypeTXT;
|
||||
rec.ttl = ttl;
|
||||
std::array<byte_t, 1024> tmp{};
|
||||
llarp_buffer_t buf(tmp);
|
||||
while (not str.empty())
|
||||
{
|
||||
return fmt::format(
|
||||
"[DNSMessage id={:x} fields={:x} questions={{{}}} answers={{{}}} authorities={{{}}} "
|
||||
"additional={{{}}}]",
|
||||
hdr_id,
|
||||
hdr_fields,
|
||||
fmt::format("{}", fmt::join(questions, ",")),
|
||||
fmt::format("{}", fmt::join(answers, ",")),
|
||||
fmt::format("{}", fmt::join(authorities, ",")),
|
||||
fmt::format("{}", fmt::join(additional, ",")));
|
||||
const auto left = std::min(str.size(), size_t{256});
|
||||
const auto sub = str.substr(0, left);
|
||||
uint8_t byte = left;
|
||||
*buf.cur = byte;
|
||||
buf.cur++;
|
||||
if (not buf.write(sub.begin(), sub.end()))
|
||||
throw std::length_error("text record too big");
|
||||
str = str.substr(left);
|
||||
}
|
||||
buf.sz = buf.cur - buf.base;
|
||||
rec.rData.resize(buf.sz);
|
||||
std::copy_n(buf.base, buf.sz, rec.rData.data());
|
||||
}
|
||||
|
||||
std::optional<Message>
|
||||
MaybeParseDNSMessage(llarp_buffer_t buf)
|
||||
void
|
||||
Message::AddNXReply(RR_TTL_t)
|
||||
{
|
||||
if (questions.size())
|
||||
{
|
||||
MessageHeader hdr{};
|
||||
if (not hdr.Decode(&buf))
|
||||
return std::nullopt;
|
||||
|
||||
Message msg{hdr};
|
||||
if (not msg.Decode(&buf))
|
||||
return std::nullopt;
|
||||
return msg;
|
||||
answers.clear();
|
||||
authorities.clear();
|
||||
additional.clear();
|
||||
|
||||
// authorative response with recursion available
|
||||
hdr_fields = reply_flags(hdr_fields);
|
||||
// don't allow recursion on this request
|
||||
hdr_fields &= ~flags_RD;
|
||||
hdr_fields |= flags_RCODENameError;
|
||||
}
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
}
|
||||
|
||||
std::string
|
||||
Message::ToString() const
|
||||
{
|
||||
return fmt::format(
|
||||
"[DNSMessage id={:x} fields={:x} questions={{{}}} answers={{{}}} authorities={{{}}} "
|
||||
"additional={{{}}}]",
|
||||
hdr_id,
|
||||
hdr_fields,
|
||||
fmt::format("{}", fmt::join(questions, ",")),
|
||||
fmt::format("{}", fmt::join(answers, ",")),
|
||||
fmt::format("{}", fmt::join(authorities, ",")),
|
||||
fmt::format("{}", fmt::join(additional, ",")));
|
||||
}
|
||||
|
||||
std::optional<Message>
|
||||
MaybeParseDNSMessage(llarp_buffer_t buf)
|
||||
{
|
||||
MessageHeader hdr{};
|
||||
if (not hdr.Decode(&buf))
|
||||
return std::nullopt;
|
||||
|
||||
Message msg{hdr};
|
||||
if (not msg.Decode(&buf))
|
||||
return std::nullopt;
|
||||
return msg;
|
||||
}
|
||||
} // namespace llarp::dns
|
||||
|
@ -1,139 +1,138 @@
|
||||
#include "name.hpp"
|
||||
#include <llarp/net/net.hpp>
|
||||
|
||||
#include <llarp/net/ip.hpp>
|
||||
#include <llarp/net/net_bits.hpp>
|
||||
#include <llarp/util/str.hpp>
|
||||
|
||||
#include <oxenc/hex.h>
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::dns
|
||||
{
|
||||
namespace dns
|
||||
std::optional<std::string>
|
||||
DecodeName(llarp_buffer_t* buf, bool trimTrailingDot)
|
||||
{
|
||||
std::optional<std::string>
|
||||
DecodeName(llarp_buffer_t* buf, bool trimTrailingDot)
|
||||
if (buf->size_left() < 1)
|
||||
return std::nullopt;
|
||||
auto result = std::make_optional<std::string>();
|
||||
auto& name = *result;
|
||||
size_t l;
|
||||
do
|
||||
{
|
||||
if (buf->size_left() < 1)
|
||||
return std::nullopt;
|
||||
auto result = std::make_optional<std::string>();
|
||||
auto& name = *result;
|
||||
size_t l;
|
||||
do
|
||||
l = *buf->cur;
|
||||
buf->cur++;
|
||||
if (l)
|
||||
{
|
||||
l = *buf->cur;
|
||||
buf->cur++;
|
||||
if (l)
|
||||
{
|
||||
if (buf->size_left() < l)
|
||||
return std::nullopt;
|
||||
if (buf->size_left() < l)
|
||||
return std::nullopt;
|
||||
|
||||
name.append((const char*)buf->cur, l);
|
||||
name += '.';
|
||||
}
|
||||
buf->cur = buf->cur + l;
|
||||
} while (l);
|
||||
/// trim off last dot
|
||||
if (trimTrailingDot)
|
||||
name.pop_back();
|
||||
return result;
|
||||
}
|
||||
name.append((const char*)buf->cur, l);
|
||||
name += '.';
|
||||
}
|
||||
buf->cur = buf->cur + l;
|
||||
} while (l);
|
||||
/// trim off last dot
|
||||
if (trimTrailingDot)
|
||||
name.pop_back();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
EncodeNameTo(llarp_buffer_t* buf, std::string_view name)
|
||||
{
|
||||
if (name.size() && name.back() == '.')
|
||||
name.remove_suffix(1);
|
||||
bool
|
||||
EncodeNameTo(llarp_buffer_t* buf, std::string_view name)
|
||||
{
|
||||
if (name.size() && name.back() == '.')
|
||||
name.remove_suffix(1);
|
||||
|
||||
for (auto part : llarp::split(name, "."))
|
||||
for (auto part : llarp::split(name, "."))
|
||||
{
|
||||
size_t l = part.length();
|
||||
if (l > 63)
|
||||
return false;
|
||||
*(buf->cur) = l;
|
||||
buf->cur++;
|
||||
if (buf->size_left() < l)
|
||||
return false;
|
||||
if (l)
|
||||
{
|
||||
size_t l = part.length();
|
||||
if (l > 63)
|
||||
return false;
|
||||
*(buf->cur) = l;
|
||||
buf->cur++;
|
||||
if (buf->size_left() < l)
|
||||
return false;
|
||||
if (l)
|
||||
{
|
||||
std::memcpy(buf->cur, part.data(), l);
|
||||
buf->cur += l;
|
||||
}
|
||||
else
|
||||
break;
|
||||
std::memcpy(buf->cur, part.data(), l);
|
||||
buf->cur += l;
|
||||
}
|
||||
*buf->cur = 0;
|
||||
buf->cur++;
|
||||
return true;
|
||||
else
|
||||
break;
|
||||
}
|
||||
*buf->cur = 0;
|
||||
buf->cur++;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<huint128_t>
|
||||
DecodePTR(std::string_view name)
|
||||
std::optional<huint128_t>
|
||||
DecodePTR(std::string_view name)
|
||||
{
|
||||
bool isV6 = false;
|
||||
auto pos = name.find(".in-addr.arpa");
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
bool isV6 = false;
|
||||
auto pos = name.find(".in-addr.arpa");
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
pos = name.find(".ip6.arpa");
|
||||
isV6 = true;
|
||||
}
|
||||
if (pos == std::string::npos)
|
||||
return std::nullopt;
|
||||
name = name.substr(0, pos + 1);
|
||||
const auto numdots = std::count(name.begin(), name.end(), '.');
|
||||
if (numdots == 4 && !isV6)
|
||||
pos = name.find(".ip6.arpa");
|
||||
isV6 = true;
|
||||
}
|
||||
if (pos == std::string::npos)
|
||||
return std::nullopt;
|
||||
name = name.substr(0, pos + 1);
|
||||
const auto numdots = std::count(name.begin(), name.end(), '.');
|
||||
if (numdots == 4 && !isV6)
|
||||
{
|
||||
std::array<uint8_t, 4> q;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
{
|
||||
std::array<uint8_t, 4> q;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
{
|
||||
pos = name.find('.');
|
||||
if (!llarp::parse_int(name.substr(0, pos), q[i]))
|
||||
return std::nullopt;
|
||||
name.remove_prefix(pos + 1);
|
||||
}
|
||||
return net::ExpandV4(llarp::ipaddr_ipv4_bits(q[0], q[1], q[2], q[3]));
|
||||
pos = name.find('.');
|
||||
if (!llarp::parse_int(name.substr(0, pos), q[i]))
|
||||
return std::nullopt;
|
||||
name.remove_prefix(pos + 1);
|
||||
}
|
||||
if (numdots == 32 && name.size() == 64 && isV6)
|
||||
return net::ExpandV4(llarp::ipaddr_ipv4_bits(q[0], q[1], q[2], q[3]));
|
||||
}
|
||||
if (numdots == 32 && name.size() == 64 && isV6)
|
||||
{
|
||||
// We're going to convert from nybbles a.b.c.d.e.f.0.1.2.3.[...] into hex string
|
||||
// "badcfe1032...", then decode the hex string to bytes.
|
||||
std::array<char, 32> in;
|
||||
auto in_pos = in.data();
|
||||
for (size_t i = 0; i < 64; i += 4)
|
||||
{
|
||||
// We're going to convert from nybbles a.b.c.d.e.f.0.1.2.3.[...] into hex string
|
||||
// "badcfe1032...", then decode the hex string to bytes.
|
||||
std::array<char, 32> in;
|
||||
auto in_pos = in.data();
|
||||
for (size_t i = 0; i < 64; i += 4)
|
||||
{
|
||||
if (not(oxenc::is_hex_digit(name[i]) and name[i + 1] == '.'
|
||||
and oxenc::is_hex_digit(name[i + 2]) and name[i + 3] == '.'))
|
||||
return std::nullopt;
|
||||
if (not(oxenc::is_hex_digit(name[i]) and name[i + 1] == '.'
|
||||
and oxenc::is_hex_digit(name[i + 2]) and name[i + 3] == '.'))
|
||||
return std::nullopt;
|
||||
|
||||
// Flip the nybbles because the smallest one is first
|
||||
*in_pos++ = name[i + 2];
|
||||
*in_pos++ = name[i];
|
||||
}
|
||||
assert(in_pos == in.data() + in.size());
|
||||
huint128_t ip;
|
||||
static_assert(in.size() == 2 * sizeof(ip.h));
|
||||
// our string right now is the little endian representation, so load it as such on little
|
||||
// endian, or in reverse on big endian.
|
||||
if constexpr (oxenc::little_endian)
|
||||
oxenc::from_hex(in.begin(), in.end(), reinterpret_cast<uint8_t*>(&ip.h));
|
||||
else
|
||||
oxenc::from_hex(in.rbegin(), in.rend(), reinterpret_cast<uint8_t*>(&ip.h));
|
||||
|
||||
return ip;
|
||||
// Flip the nybbles because the smallest one is first
|
||||
*in_pos++ = name[i + 2];
|
||||
*in_pos++ = name[i];
|
||||
}
|
||||
return std::nullopt;
|
||||
assert(in_pos == in.data() + in.size());
|
||||
huint128_t ip;
|
||||
static_assert(in.size() == 2 * sizeof(ip.h));
|
||||
// our string right now is the little endian representation, so load it as such on little
|
||||
// endian, or in reverse on big endian.
|
||||
if constexpr (oxenc::little_endian)
|
||||
oxenc::from_hex(in.begin(), in.end(), reinterpret_cast<uint8_t*>(&ip.h));
|
||||
else
|
||||
oxenc::from_hex(in.rbegin(), in.rend(), reinterpret_cast<uint8_t*>(&ip.h));
|
||||
|
||||
return ip;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool
|
||||
NameIsReserved(std::string_view name)
|
||||
bool
|
||||
NameIsReserved(std::string_view name)
|
||||
{
|
||||
const std::vector<std::string_view> reserved_names = {
|
||||
".snode.loki"sv, ".loki.loki"sv, ".snode.loki."sv, ".loki.loki."sv};
|
||||
for (const auto& reserved : reserved_names)
|
||||
{
|
||||
const std::vector<std::string_view> reserved_names = {
|
||||
".snode.loki"sv, ".loki.loki"sv, ".snode.loki."sv, ".loki.loki."sv};
|
||||
for (const auto& reserved : reserved_names)
|
||||
{
|
||||
if (ends_with(name, reserved)) // subdomain foo.loki.loki
|
||||
return true;
|
||||
if (name == reserved.substr(1)) // loki.loki itself
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (ends_with(name, reserved)) // subdomain foo.loki.loki
|
||||
return true;
|
||||
if (name == reserved.substr(1)) // loki.loki itself
|
||||
return true;
|
||||
}
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
return false;
|
||||
}
|
||||
} // namespace llarp::dns
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue