mein gott

pull/2204/head
dr7ana 9 months ago
parent edd3534425
commit a921575c55

@ -96,7 +96,7 @@ if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
add_definitions(-DLOKINET_DEBUG)
endif()
option(WARN_DEPRECATED "show deprecation warnings" ${debug})
option(WARN_DEPRECATED "show deprecation warnings" OFF)
include(CheckCXXSourceCompiles)
include(CheckLibraryExists)

@ -110,7 +110,7 @@ namespace llarp
/// 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, IMessage* msg, bool keepalive = true) override;
DHTSendTo(const RouterID& peer, AbstractDHTMessage* msg, bool keepalive = true) override;
/// get routers closest to target excluding requester
bool
@ -118,7 +118,7 @@ namespace llarp
const Key_t& requester,
uint64_t txid,
const RouterID& target,
std::vector<std::unique_ptr<IMessage>>& reply) override;
std::vector<std::unique_ptr<AbstractDHTMessage>>& reply) override;
/// handle rc lookup from requester for target
void
@ -127,11 +127,11 @@ namespace llarp
uint64_t txid,
const Key_t& target,
bool recursive,
std::vector<std::unique_ptr<IMessage>>& replies) override;
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 IMessage& msg) override;
RelayRequestForPath(const llarp::PathID_t& localPath, const AbstractDHTMessage& msg) override;
/// send introset to peer as R/S
void
@ -374,7 +374,7 @@ namespace llarp
uint64_t txid,
const Key_t& target,
bool recursive,
std::vector<std::unique_ptr<IMessage>>& replies)
std::vector<std::unique_ptr<AbstractDHTMessage>>& replies)
{
if (target == ourKey)
{
@ -475,9 +475,9 @@ namespace llarp
}
void
Context::DHTSendTo(const RouterID& peer, IMessage* msg, bool)
Context::DHTSendTo(const RouterID& peer, AbstractDHTMessage* msg, bool)
{
llarp::DHTImmediateMessage m;
DHTImmediateMessage m;
m.msgs.emplace_back(msg);
router->SendToOrQueue(peer, m);
auto now = Now();
@ -489,10 +489,10 @@ namespace llarp
// namespace. by the time this is called, we are inside
// llarp::routing::DHTMessage::HandleMessage()
bool
Context::RelayRequestForPath(const llarp::PathID_t& id, const IMessage& msg)
Context::RelayRequestForPath(const llarp::PathID_t& id, const AbstractDHTMessage& msg)
{
llarp::routing::DHTMessage reply;
if (!msg.HandleMessage(router->dht(), reply.M))
routing::DHTMessage reply;
if (!msg.handle_message(router->dht(), reply.M))
return false;
if (not reply.M.empty())
{
@ -584,7 +584,7 @@ namespace llarp
const Key_t& requester,
uint64_t txid,
const RouterID& target,
std::vector<std::unique_ptr<IMessage>>& reply)
std::vector<std::unique_ptr<AbstractDHTMessage>>& reply)
{
std::vector<RouterID> closer;
const Key_t t(target.as_array());

@ -89,7 +89,7 @@ namespace llarp
uint64_t relayOrder) = 0;
virtual void
DHTSendTo(const RouterID& peer, IMessage* msg, bool keepalive = true) = 0;
DHTSendTo(const RouterID& peer, AbstractDHTMessage* msg, bool keepalive = true) = 0;
/// get routers closest to target excluding requester
virtual bool
@ -97,7 +97,7 @@ namespace llarp
const Key_t& requester,
uint64_t txid,
const RouterID& target,
std::vector<std::unique_ptr<IMessage>>& reply) = 0;
std::vector<std::unique_ptr<AbstractDHTMessage>>& reply) = 0;
/// handle rc lookup from requester for target
virtual void
@ -106,10 +106,10 @@ namespace llarp
uint64_t txid,
const Key_t& target,
bool recursive,
std::vector<std::unique_ptr<IMessage>>& replies) = 0;
std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) = 0;
virtual bool
RelayRequestForPath(const PathID_t& localPath, const IMessage& msg) = 0;
RelayRequestForPath(const PathID_t& localPath, const AbstractDHTMessage& msg) = 0;
/// send introset to peer from source with S counter and excluding peers
virtual void

@ -1,4 +1,5 @@
#include "context.hpp"
#include "oxenc/bt_serialize.h"
#include <memory>
#include <llarp/util/bencode.hpp>
@ -10,128 +11,124 @@
#include <llarp/dht/messages/findname.hpp>
#include <llarp/dht/messages/gotname.hpp>
namespace llarp
namespace llarp::dht
{
namespace dht
struct MessageDecoder
{
struct MessageDecoder
{
const Key_t& From;
IMessage::Ptr_t msg;
bool firstKey = true;
bool relayed = false;
const Key_t& From;
AbstractDHTMessage::Ptr_t msg;
bool firstKey = true;
bool relayed = false;
MessageDecoder(const Key_t& from, bool wasRelayed) : From(from), relayed(wasRelayed)
{}
MessageDecoder(const Key_t& from, bool wasRelayed) : From(from), relayed(wasRelayed)
{}
bool
operator()(llarp_buffer_t* buffer, llarp_buffer_t* key)
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)
{
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)
{
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);
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;
case 'M':
msg = std::make_unique<GotNameMessage>(From, 0, service::EncryptedName{});
}
else
{
msg = std::make_unique<GotIntroMessage>(From);
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;
}
default:
llarp::LogWarn("unknown dht message type: ", (char)*strbuf.base);
// bad msg type
return false;
}
return msg->DecodeKey(*key, buffer);
firstKey = false;
return msg != nullptr;
}
};
IMessage::Ptr_t
DecodeMesssage(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);
return msg->decode_key(*key, buffer);
}
};
struct ListDecoder
{
ListDecoder(bool hasRelayed, const Key_t& from, std::vector<IMessage::Ptr_t>& list)
: relayed(hasRelayed), From(from), l(list)
{}
AbstractDHTMessage::Ptr_t
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed)
{
MessageDecoder dec(from, relayed);
if (!bencode_read_dict(dec, buf))
return nullptr;
bool relayed;
const Key_t& From;
std::vector<IMessage::Ptr_t>& l;
return std::move(dec.msg);
}
bool
operator()(llarp_buffer_t* buffer, bool has)
{
if (!has)
return true;
auto msg = DecodeMesssage(From, buffer, relayed);
if (msg)
{
l.emplace_back(std::move(msg));
return true;
}
struct ListDecoder
{
ListDecoder(bool hasRelayed, const Key_t& from, std::vector<AbstractDHTMessage::Ptr_t>& list)
: relayed(hasRelayed), From(from), l(list)
{}
return false;
}
};
bool relayed;
const Key_t& From;
std::vector<AbstractDHTMessage::Ptr_t>& l;
bool
DecodeMesssageList(
Key_t from, llarp_buffer_t* buf, std::vector<IMessage::Ptr_t>& list, bool relayed)
operator()(llarp_buffer_t* buffer, bool has)
{
ListDecoder dec(relayed, from, list);
return bencode_read_list(dec, buf);
if (!has)
return true;
auto msg = DecodeMessage(From, buffer, relayed);
if (msg)
{
l.emplace_back(std::move(msg));
return true;
}
return false;
}
} // namespace dht
} // namespace llarp
};
bool
DecodeMessageList(
Key_t from, llarp_buffer_t* buf, std::vector<AbstractDHTMessage::Ptr_t>& list, bool relayed)
{
ListDecoder dec(relayed, from, list);
return bencode_read_list(dec, buf);
}
} // namespace llarp::dht

@ -2,46 +2,70 @@
#include "dht.h"
#include "key.hpp"
#include <llarp/messages/link_message.hpp>
#include <llarp/path/path_types.hpp>
#include <llarp/util/bencode.hpp>
#include <vector>
namespace llarp
namespace
{
namespace dht
static auto dht_cat = llarp::log::Cat("lokinet.dht");
} // namespace
namespace llarp::dht
{
constexpr size_t MAX_MSG_SIZE = 2048;
struct AbstractDHTMessage : private AbstractSerializable
{
constexpr size_t MAX_MSG_SIZE = 2048;
virtual ~AbstractDHTMessage() = default;
struct IMessage
{
virtual ~IMessage() = default;
/// construct
AbstractDHTMessage(const Key_t& from) : From(from)
{}
/// construct
IMessage(const Key_t& from) : From(from)
{}
using Ptr_t = std::unique_ptr<AbstractDHTMessage>;
using Ptr_t = std::unique_ptr<IMessage>;
virtual bool
handle_message(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const = 0;
virtual bool
HandleMessage(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const = 0;
void
bt_encode(oxenc::bt_dict_producer& btdp) const override = 0;
virtual bool
BEncode(llarp_buffer_t* buf) const = 0;
virtual bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) = 0;
// methods we do not want to inherit onwards from AbstractSerializable
void
bt_encode(oxenc::bt_list_producer&) const final
{
throw std::runtime_error{"Error: DHT messages should encode directly to a bt dict producer!"};
}
void
bt_encode(llarp_buffer&) const final
{
throw std::runtime_error{"Error: DHT messages should encode directly to a bt dict producer!"};
}
std::string
bt_encode() const final
{
throw std::runtime_error{"Error: DHT messages should encode directly to a bt dict producer!"};
}
virtual bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) = 0;
Key_t From;
PathID_t pathID;
uint64_t version = llarp::constants::proto_version;
};
Key_t From;
PathID_t pathID;
uint64_t version = llarp::constants::proto_version;
};
AbstractDHTMessage::Ptr_t
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed = false);
IMessage::Ptr_t
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed = false);
bool
DecodeMessageList(
Key_t from,
llarp_buffer_t* buf,
std::vector<AbstractDHTMessage::Ptr_t>& list,
bool relayed = false);
bool
DecodeMesssageList(
Key_t from, llarp_buffer_t* buf, std::vector<IMessage::Ptr_t>& dst, bool relayed = false);
} // namespace dht
} // namespace llarp
} // namespace llarp::dht

@ -2,26 +2,23 @@
#include <llarp/dht/message.hpp>
#include <llarp/router_version.hpp>
namespace llarp
namespace llarp::dht
{
namespace dht
struct ConsensusMessage
{
struct ConsensusMessage
{
/// H
ShortHash m_Hash;
/// K
std::vector<RouterID> m_Keys;
/// N
uint64_t m_NumberOfEntries;
/// O
uint64_t m_EntryOffset;
/// T
uint64_t m_TxID;
/// U
llarp_time_t m_NextUpdateRequired;
/// V
RouterVersion m_RotuerVersion;
};
} // namespace dht
} // namespace llarp
/// H
ShortHash m_Hash;
/// K
std::vector<RouterID> m_Keys;
/// N
uint64_t m_NumberOfEntries;
/// O
uint64_t m_EntryOffset;
/// T
uint64_t m_TxID;
/// U
llarp_time_t m_NextUpdateRequired;
/// V
RouterVersion m_RotuerVersion;
};
} // namespace llarp::dht

@ -5,135 +5,120 @@
#include <llarp/router/abstractrouter.hpp>
#include <llarp/nodedb.hpp>
namespace llarp
namespace llarp::dht
{
namespace dht
{
FindIntroMessage::~FindIntroMessage() = default;
FindIntroMessage::~FindIntroMessage() = default;
bool
FindIntroMessage::DecodeKey(const llarp_buffer_t& k, llarp_buffer_t* val)
{
bool read = false;
bool
FindIntroMessage::decode_key(const llarp_buffer_t& k, llarp_buffer_t* val)
{
bool read = false;
if (!BEncodeMaybeReadDictEntry("N", tagName, read, k, val))
return false;
if (!BEncodeMaybeReadDictEntry("N", tagName, read, k, val))
return false;
if (!BEncodeMaybeReadDictInt("O", relayOrder, read, k, val))
return false;
if (!BEncodeMaybeReadDictInt("O", relayOrder, read, k, val))
return false;
if (!BEncodeMaybeReadDictEntry("S", location, read, k, val))
return false;
if (!BEncodeMaybeReadDictEntry("S", location, read, k, val))
return false;
if (!BEncodeMaybeReadDictInt("T", txID, read, k, val))
return false;
if (!BEncodeMaybeReadDictInt("T", txID, read, k, val))
return false;
if (!BEncodeMaybeVerifyVersion("V", version, llarp::constants::proto_version, read, k, val))
return false;
if (!BEncodeMaybeVerifyVersion("V", version, llarp::constants::proto_version, read, k, val))
return false;
return read;
}
return read;
}
bool
FindIntroMessage::BEncode(llarp_buffer_t* buf) const
void
FindIntroMessage::bt_encode(oxenc::bt_dict_producer& btdp) const
{
try
{
if (!bencode_start_dict(buf))
return false;
// message id
if (!BEncodeWriteDictMsgType(buf, "A", "F"))
return false;
btdp.append("A", "F");
if (tagName.Empty())
{
// relay order
if (!BEncodeWriteDictInt("O", relayOrder, buf))
return false;
// service address
if (!BEncodeWriteDictEntry("S", location, buf))
return false;
btdp.append("O", relayOrder);
btdp.append("S", location.ToView());
}
else
{
if (!BEncodeWriteDictEntry("N", tagName, buf))
return false;
// relay order
if (!BEncodeWriteDictInt("O", relayOrder, buf))
return false;
btdp.append("N", tagName.ToView());
btdp.append("O", relayOrder);
}
// txid
if (!BEncodeWriteDictInt("T", txID, buf))
return false;
// protocol version
if (!BEncodeWriteDictInt("V", llarp::constants::proto_version, buf))
return false;
return bencode_end(buf);
btdp.append("T", txID);
btdp.append("V", llarp::constants::proto_version);
}
catch (...)
{
log::critical(dht_cat, "FindIntroMessage failed to bt encode contents!");
}
}
bool
FindIntroMessage::HandleMessage(
llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const
bool
FindIntroMessage::handle_message(
llarp_dht_context* ctx, std::vector<AbstractDHTMessage::Ptr_t>& replies) const
{
auto& dht = *ctx->impl;
if (dht.pendingIntrosetLookups().HasPendingLookupFrom(TXOwner{From, txID}))
{
auto& dht = *ctx->impl;
if (dht.pendingIntrosetLookups().HasPendingLookupFrom(TXOwner{From, txID}))
{
llarp::LogWarn("duplicate FIM from ", From, " txid=", txID);
return false;
}
llarp::LogWarn("duplicate FIM from ", From, " txid=", txID);
return false;
}
if (not tagName.Empty())
if (not tagName.Empty())
{
return false;
}
// bad request (request for zero-key)
if (location.IsZero())
{
// we dont got it
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
// we are relaying this message for e.g. a client
if (relayed)
{
if (relayOrder >= IntroSetStorageRedundancy)
{
return false;
llarp::LogWarn("Invalid relayOrder received: ", relayOrder);
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
// bad request (request for zero-key)
if (location.IsZero())
auto closestRCs =
dht.GetRouter()->nodedb()->FindManyClosestTo(location, IntroSetStorageRedundancy);
if (closestRCs.size() <= relayOrder)
{
// we dont got it
llarp::LogWarn("Can't fulfill FindIntro for relayOrder: ", relayOrder);
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
// we are relaying this message for e.g. a client
if (relayed)
const auto& entry = closestRCs[relayOrder];
Key_t peer = Key_t(entry.pubkey);
dht.LookupIntroSetForPath(location, txID, pathID, peer, 0);
}
else
{
// we should have this value if introset was propagated properly
const auto maybe = dht.GetIntroSetByLocation(location);
if (maybe)
{
if (relayOrder >= IntroSetStorageRedundancy)
{
llarp::LogWarn("Invalid relayOrder received: ", relayOrder);
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
auto closestRCs =
dht.GetRouter()->nodedb()->FindManyClosestTo(location, IntroSetStorageRedundancy);
if (closestRCs.size() <= relayOrder)
{
llarp::LogWarn("Can't fulfill FindIntro for relayOrder: ", relayOrder);
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
const auto& entry = closestRCs[relayOrder];
Key_t peer = Key_t(entry.pubkey);
dht.LookupIntroSetForPath(location, txID, pathID, peer, 0);
replies.emplace_back(new GotIntroMessage({*maybe}, txID));
}
else
{
// we should have this value if introset was propagated properly
const auto maybe = dht.GetIntroSetByLocation(location);
if (maybe)
{
replies.emplace_back(new GotIntroMessage({*maybe}, txID));
}
else
{
LogWarn("Got FIM with relayed == false and we don't have entry");
replies.emplace_back(new GotIntroMessage({}, txID));
}
LogWarn("Got FIM with relayed == false and we don't have entry");
replies.emplace_back(new GotIntroMessage({}, txID));
}
return true;
}
} // namespace dht
} // namespace llarp
return true;
}
} // namespace llarp::dht

@ -5,44 +5,42 @@
#include <llarp/service/address.hpp>
#include <llarp/service/tag.hpp>
namespace llarp
namespace llarp::dht
{
namespace dht
struct FindIntroMessage final : public AbstractDHTMessage
{
struct FindIntroMessage final : public IMessage
Key_t location;
llarp::service::Tag tagName;
uint64_t txID = 0;
bool relayed = false;
uint64_t relayOrder = 0;
FindIntroMessage(const Key_t& from, bool relay, uint64_t order) : AbstractDHTMessage(from)
{
relayed = relay;
relayOrder = order;
}
FindIntroMessage(const llarp::service::Tag& tag, uint64_t txid)
: AbstractDHTMessage({}), tagName(tag), txID(txid)
{}
explicit FindIntroMessage(uint64_t txid, const Key_t& addr, uint64_t order)
: AbstractDHTMessage({}), location(addr), txID(txid), relayOrder(order)
{
Key_t location;
llarp::service::Tag tagName;
uint64_t txID = 0;
bool relayed = false;
uint64_t relayOrder = 0;
FindIntroMessage(const Key_t& from, bool relay, uint64_t order) : IMessage(from)
{
relayed = relay;
relayOrder = order;
}
FindIntroMessage(const llarp::service::Tag& tag, uint64_t txid)
: IMessage({}), tagName(tag), txID(txid)
{}
explicit FindIntroMessage(uint64_t txid, const Key_t& addr, uint64_t order)
: IMessage({}), location(addr), txID(txid), relayOrder(order)
{
tagName.Zero();
}
~FindIntroMessage() override;
bool
BEncode(llarp_buffer_t* buf) const override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
HandleMessage(llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const override;
};
} // namespace dht
} // namespace llarp
tagName.Zero();
}
~FindIntroMessage() override;
void
bt_encode(oxenc::bt_dict_producer& btdp) const override;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
handle_message(
llarp_dht_context* ctx, std::vector<AbstractDHTMessage::Ptr_t>& replies) const override;
};
} // namespace llarp::dht

@ -10,21 +10,26 @@
namespace llarp::dht
{
FindNameMessage::FindNameMessage(const Key_t& from, Key_t namehash, uint64_t txid)
: IMessage(from), NameHash(std::move(namehash)), TxID(txid)
: AbstractDHTMessage(from), NameHash(std::move(namehash)), TxID(txid)
{}
bool
FindNameMessage::BEncode(llarp_buffer_t* buf) const
void
FindNameMessage::bt_encode(oxenc::bt_dict_producer& btdp) const
{
const auto data = oxenc::bt_serialize(oxenc::bt_dict{
{"A", "N"sv},
{"H", std::string_view{(char*)NameHash.data(), NameHash.size()}},
{"T", TxID}});
return buf->write(data.begin(), data.end());
try
{
btdp.append("A", "N");
btdp.append("H", NameHash.ToView());
btdp.append("T", TxID);
}
catch (...)
{
log::error(dht_cat, "Error: FindNameMessage failed to bt encode contents!");
}
}
bool
FindNameMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
FindNameMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* val)
{
if (key.startswith("H"))
{
@ -38,7 +43,7 @@ namespace llarp::dht
}
bool
FindNameMessage::HandleMessage(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const
FindNameMessage::handle_message(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const
{
(void)replies;
auto r = dht->impl->GetRouter();

@ -4,18 +4,18 @@
namespace llarp::dht
{
struct FindNameMessage : public IMessage
struct FindNameMessage : public AbstractDHTMessage
{
explicit FindNameMessage(const Key_t& from, Key_t namehash, uint64_t txid);
bool
BEncode(llarp_buffer_t* buf) const override;
void
bt_encode(oxenc::bt_dict_producer& btdp) const override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
HandleMessage(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const override;
handle_message(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const override;
Key_t NameHash;
uint64_t TxID;

@ -9,172 +9,142 @@
#include <llarp/tooling/dht_event.hpp>
namespace llarp
namespace llarp::dht
{
namespace dht
bool
RelayedFindRouterMessage::handle_message(
llarp_dht_context* ctx, std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) const
{
bool
RelayedFindRouterMessage::HandleMessage(
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const
auto& dht = *ctx->impl;
/// lookup for us, send an immeidate reply
const Key_t us = dht.OurKey();
const Key_t k{targetKey};
if (k == us)
{
auto& dht = *ctx->impl;
/// lookup for us, send an immeidate reply
const Key_t us = dht.OurKey();
const Key_t k{targetKey};
if (k == us)
auto path = dht.GetRouter()->pathContext().GetByUpstream(targetKey, pathID);
if (path)
{
auto path = dht.GetRouter()->pathContext().GetByUpstream(targetKey, pathID);
if (path)
{
replies.emplace_back(new GotRouterMessage(k, txid, {dht.GetRouter()->rc()}, false));
return true;
}
return false;
}
Key_t peer;
// check if we know this in our nodedb first
if (not dht.GetRouter()->SessionToRouterAllowed(targetKey))
{
// explicitly disallowed by network
replies.emplace_back(new GotRouterMessage(k, txid, {}, false));
return true;
}
// check netdb
const auto rc = dht.GetRouter()->nodedb()->FindClosestTo(k);
if (rc.pubkey == targetKey)
{
replies.emplace_back(new GotRouterMessage(k, txid, {rc}, false));
replies.emplace_back(new GotRouterMessage(k, txid, {dht.GetRouter()->rc()}, false));
return true;
}
peer = Key_t(rc.pubkey);
// lookup if we don't have it in our nodedb
dht.LookupRouterForPath(targetKey, txid, pathID, peer);
return false;
}
Key_t peer;
// check if we know this in our nodedb first
if (not dht.GetRouter()->SessionToRouterAllowed(targetKey))
{
// explicitly disallowed by network
replies.emplace_back(new GotRouterMessage(k, txid, {}, false));
return true;
}
// check netdb
const auto rc = dht.GetRouter()->nodedb()->FindClosestTo(k);
if (rc.pubkey == targetKey)
{
replies.emplace_back(new GotRouterMessage(k, txid, {rc}, false));
return true;
}
peer = Key_t(rc.pubkey);
// lookup if we don't have it in our nodedb
dht.LookupRouterForPath(targetKey, txid, pathID, peer);
return true;
}
FindRouterMessage::~FindRouterMessage() = default;
FindRouterMessage::~FindRouterMessage() = default;
bool
FindRouterMessage::BEncode(llarp_buffer_t* buf) const
void
FindRouterMessage::bt_encode(oxenc::bt_dict_producer& btdp) const
{
try
{
if (!bencode_start_dict(buf))
return false;
// message type
if (!bencode_write_bytestring(buf, "A", 1))
return false;
if (!bencode_write_bytestring(buf, "R", 1))
return false;
btdp.append("A", "R");
btdp.append("T", exploratory ? 1 : 0);
btdp.append("I", iterative ? 1 : 0);
btdp.append("K", targetKey.ToView());
btdp.append("T", txid);
btdp.append("V", version);
}
catch (...)
{
log::error(dht_cat, "Error: FindRouterMessage failed to bt encode contents!");
}
}
// exploritory or not?
if (!bencode_write_bytestring(buf, "E", 1))
return false;
if (!bencode_write_uint64(buf, exploritory ? 1 : 0))
return false;
bool
FindRouterMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* val)
{
llarp_buffer_t strbuf;
// iterative or not?
if (!bencode_write_bytestring(buf, "I", 1))
return false;
if (!bencode_write_uint64(buf, iterative ? 1 : 0))
if (key.startswith("E"))
{
uint64_t result;
if (!bencode_read_integer(val, &result))
return false;
// key
if (!bencode_write_bytestring(buf, "K", 1))
return false;
if (!bencode_write_bytestring(buf, targetKey.data(), targetKey.size()))
return false;
exploratory = result != 0;
return true;
}
// txid
if (!bencode_write_bytestring(buf, "T", 1))
return false;
if (!bencode_write_uint64(buf, txid))
if (key.startswith("I"))
{
uint64_t result;
if (!bencode_read_integer(val, &result))
return false;
// version
if (!bencode_write_bytestring(buf, "V", 1))
iterative = result != 0;
return true;
}
if (key.startswith("K"))
{
if (!bencode_read_string(val, &strbuf))
return false;
if (!bencode_write_uint64(buf, version))
if (strbuf.sz != targetKey.size())
return false;
return bencode_end(buf);
std::copy(strbuf.base, strbuf.base + targetKey.SIZE, targetKey.begin());
return true;
}
bool
FindRouterMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
if (key.startswith("T"))
{
llarp_buffer_t strbuf;
if (key.startswith("E"))
{
uint64_t result;
if (!bencode_read_integer(val, &result))
return false;
return bencode_read_integer(val, &txid);
}
if (key.startswith("V"))
{
return bencode_read_integer(val, &version);
}
return false;
}
exploritory = result != 0;
return true;
}
bool
FindRouterMessage::handle_message(
llarp_dht_context* ctx, std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) const
{
auto& dht = *ctx->impl;
if (key.startswith("I"))
{
uint64_t result;
if (!bencode_read_integer(val, &result))
return false;
auto router = dht.GetRouter();
router->NotifyRouterEvent<tooling::FindRouterReceivedEvent>(router->pubkey(), *this);
iterative = result != 0;
return true;
}
if (key.startswith("K"))
{
if (!bencode_read_string(val, &strbuf))
return false;
if (strbuf.sz != targetKey.size())
return false;
std::copy(strbuf.base, strbuf.base + targetKey.SIZE, targetKey.begin());
return true;
}
if (key.startswith("T"))
{
return bencode_read_integer(val, &txid);
}
if (key.startswith("V"))
{
return bencode_read_integer(val, &version);
}
if (!dht.AllowTransit())
{
llarp::LogWarn("Got DHT lookup from ", From, " when we are not allowing dht transit");
return false;
}
bool
FindRouterMessage::HandleMessage(
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const
if (dht.pendingRouterLookups().HasPendingLookupFrom({From, txid}))
{
auto& dht = *ctx->impl;
auto router = dht.GetRouter();
router->NotifyRouterEvent<tooling::FindRouterReceivedEvent>(router->pubkey(), *this);
if (!dht.AllowTransit())
{
llarp::LogWarn("Got DHT lookup from ", From, " when we are not allowing dht transit");
return false;
}
if (dht.pendingRouterLookups().HasPendingLookupFrom({From, txid}))
{
llarp::LogWarn("Duplicate FRM from ", From, " txid=", txid);
return false;
}
RouterContact found;
if (targetKey.IsZero())
{
llarp::LogError("invalid FRM from ", From, " key is zero");
return false;
}
const Key_t k(targetKey);
if (exploritory)
return dht.HandleExploritoryRouterLookup(From, txid, targetKey, replies);
dht.LookupRouterRelayed(From, txid, k, !iterative, replies);
return true;
llarp::LogWarn("Duplicate FRM from ", From, " txid=", txid);
return false;
}
RouterContact found;
if (targetKey.IsZero())
{
llarp::LogError("invalid FRM from ", From, " key is zero");
return false;
}
} // namespace dht
} // namespace llarp
const Key_t k(targetKey);
if (exploratory)
return dht.HandleExploritoryRouterLookup(From, txid, targetKey, replies);
dht.LookupRouterRelayed(From, txid, k, !iterative, replies);
return true;
}
} // namespace llarp::dht

@ -1,57 +1,56 @@
#pragma once
#include <llarp/dht/message.hpp>
namespace llarp
namespace llarp::dht
{
namespace dht
struct FindRouterMessage : public AbstractDHTMessage
{
struct FindRouterMessage : public IMessage
{
// inbound parsing
FindRouterMessage(const Key_t& from) : IMessage(from)
{}
// find by routerid
FindRouterMessage(uint64_t id, const RouterID& target)
: IMessage({}), targetKey(target), txid(id)
{}
// exploritory
FindRouterMessage(uint64_t id) : IMessage({}), exploritory(true), txid(id)
{
targetKey.Randomize();
}
~FindRouterMessage() override;
bool
BEncode(llarp_buffer_t* buf) const override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
HandleMessage(
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const override;
RouterID targetKey;
bool iterative = false;
bool exploritory = false;
uint64_t txid = 0;
uint64_t version = 0;
};
/// variant of FindRouterMessage relayed via path
struct RelayedFindRouterMessage final : public FindRouterMessage
// inbound parsing
FindRouterMessage(const Key_t& from) : AbstractDHTMessage(from)
{}
// find by routerid
FindRouterMessage(uint64_t id, const RouterID& target)
: AbstractDHTMessage({}), targetKey(target), txid(id)
{}
// exploritory
FindRouterMessage(uint64_t id) : AbstractDHTMessage({}), exploratory(true), txid(id)
{
RelayedFindRouterMessage(const Key_t& from) : FindRouterMessage(from)
{}
/// handle a relayed FindRouterMessage, do a lookup on the dht and inform
/// the path of the result
/// TODO: smart path expiration logic needs to be implemented
bool
HandleMessage(llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const override;
};
} // namespace dht
} // namespace llarp
targetKey.Randomize();
}
~FindRouterMessage() override;
void
bt_encode(oxenc::bt_dict_producer& btdp) const override;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
handle_message(
llarp_dht_context* ctx,
std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) const override;
RouterID targetKey;
bool iterative = false;
bool exploratory = false;
uint64_t txid = 0;
uint64_t version = 0;
};
/// variant of FindRouterMessage relayed via path
struct RelayedFindRouterMessage final : public FindRouterMessage
{
RelayedFindRouterMessage(const Key_t& from) : FindRouterMessage(from)
{}
/// handle a relayed FindRouterMessage, do a lookup on the dht and inform
/// the path of the result
/// TODO: smart path expiration logic needs to be implemented
bool
handle_message(
llarp_dht_context* ctx, std::vector<AbstractDHTMessage::Ptr_t>& replies) const override;
};
} // namespace llarp::dht

@ -9,117 +9,118 @@
#include <llarp/tooling/dht_event.hpp>
#include <utility>
namespace llarp
namespace llarp::dht
{
namespace dht
{
GotIntroMessage::GotIntroMessage(std::vector<service::EncryptedIntroSet> results, uint64_t tx)
: IMessage({}), found(std::move(results)), txid(tx)
{}
GotIntroMessage::GotIntroMessage(std::vector<service::EncryptedIntroSet> results, uint64_t tx)
: AbstractDHTMessage({}), found(std::move(results)), txid(tx)
{}
bool
GotIntroMessage::HandleMessage(
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& /*replies*/) const
{
auto& dht = *ctx->impl;
auto* router = dht.GetRouter();
bool
GotIntroMessage::handle_message(
llarp_dht_context* ctx, std::vector<std::unique_ptr<AbstractDHTMessage>>& /*replies*/) const
{
auto& dht = *ctx->impl;
auto* router = dht.GetRouter();
router->NotifyRouterEvent<tooling::GotIntroReceivedEvent>(
router->pubkey(),
Key_t(From.data()),
(found.size() > 0 ? found[0] : llarp::service::EncryptedIntroSet{}),
txid);
router->NotifyRouterEvent<tooling::GotIntroReceivedEvent>(
router->pubkey(),
Key_t(From.data()),
(found.size() > 0 ? found[0] : llarp::service::EncryptedIntroSet{}),
txid);
for (const auto& introset : found)
for (const auto& introset : found)
{
if (!introset.Verify(dht.Now()))
{
if (!introset.Verify(dht.Now()))
{
LogWarn(
"Invalid introset while handling direct GotIntro "
"from ",
From);
return false;
}
LogWarn(
"Invalid introset while handling direct GotIntro "
"from ",
From);
return false;
}
TXOwner owner(From, txid);
}
TXOwner owner(From, txid);
auto serviceLookup = dht.pendingIntrosetLookups().GetPendingLookupFrom(owner);
if (serviceLookup)
auto serviceLookup = dht.pendingIntrosetLookups().GetPendingLookupFrom(owner);
if (serviceLookup)
{
if (not found.empty())
{
if (not found.empty())
{
dht.pendingIntrosetLookups().Found(owner, serviceLookup->target, found);
}
else
{
dht.pendingIntrosetLookups().NotFound(owner, nullptr);
}
return true;
dht.pendingIntrosetLookups().Found(owner, serviceLookup->target, found);
}
LogError("no pending TX for GIM from ", From, " txid=", txid);
return false;
else
{
dht.pendingIntrosetLookups().NotFound(owner, nullptr);
}
return true;
}
LogError("no pending TX for GIM from ", From, " txid=", txid);
return false;
}
bool
RelayedGotIntroMessage::HandleMessage(
llarp_dht_context* ctx,
[[maybe_unused]] std::vector<std::unique_ptr<IMessage>>& replies) const
bool
RelayedGotIntroMessage::handle_message(
llarp_dht_context* ctx,
[[maybe_unused]] std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) const
{
// TODO: implement me better?
auto pathset = ctx->impl->GetRouter()->pathContext().GetLocalPathSet(pathID);
if (pathset)
{
// TODO: implement me better?
auto pathset = ctx->impl->GetRouter()->pathContext().GetLocalPathSet(pathID);
if (pathset)
{
auto copy = std::make_shared<const RelayedGotIntroMessage>(*this);
return pathset->HandleGotIntroMessage(copy);
}
LogWarn("No path for got intro message pathid=", pathID);
return false;
auto copy = std::make_shared<const RelayedGotIntroMessage>(*this);
return pathset->HandleGotIntroMessage(copy);
}
LogWarn("No path for got intro message pathid=", pathID);
return false;
}
bool
GotIntroMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
bool
GotIntroMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
if (key.startswith("I"))
{
if (key.startswith("I"))
{
return BEncodeReadList(found, buf);
}
if (key.startswith("K"))
{
if (closer) // duplicate key?
return false;
dht::Key_t K;
if (not K.BDecode(buf))
return false;
closer = K;
return true;
}
bool read = false;
if (!BEncodeMaybeReadDictInt("T", txid, read, key, buf))
return BEncodeReadList(found, buf);
}
if (key.startswith("K"))
{
if (closer) // duplicate key?
return false;
if (!BEncodeMaybeReadDictInt("V", version, read, key, buf))
dht::Key_t K;
if (not K.BDecode(buf))
return false;
return read;
closer = K;
return true;
}
bool read = false;
if (!BEncodeMaybeReadDictInt("T", txid, read, key, buf))
return false;
if (!BEncodeMaybeReadDictInt("V", version, read, key, buf))
return false;
return read;
}
bool
GotIntroMessage::BEncode(llarp_buffer_t* buf) const
void
GotIntroMessage::bt_encode(oxenc::bt_dict_producer& btdp) const
{
try
{
if (!bencode_start_dict(buf))
return false;
if (!BEncodeWriteDictMsgType(buf, "A", "G"))
return false;
if (!BEncodeWriteDictList("I", found, buf))
return false;
if (closer)
btdp.append("A", "G");
{
if (!BEncodeWriteDictEntry("K", *closer, buf))
return false;
auto sublist = btdp.append_list("I");
for (auto f : found)
sublist.append(f.ToString());
}
if (!BEncodeWriteDictInt("T", txid, buf))
return false;
if (!BEncodeWriteDictInt("V", version, buf))
return false;
return bencode_end(buf);
if (closer)
btdp.append("K", closer->ToView());
btdp.append("T", txid);
btdp.append("V", version);
}
catch (...)
{
log::error(dht_cat, "Error: GotIntroMessage failed to bt encode contents!");
}
} // namespace dht
} // namespace llarp
}
} // namespace llarp::dht

@ -7,58 +7,57 @@
#include <vector>
#include <optional>
namespace llarp
namespace llarp::dht
{
namespace dht
/// acknowledgement to PublishIntroMessage or reply to FindIntroMessage
struct GotIntroMessage : public AbstractDHTMessage
{
/// acknowledgement to PublishIntroMessage or reply to FindIntroMessage
struct GotIntroMessage : public IMessage
/// the found introsets
std::vector<service::EncryptedIntroSet> found;
/// txid
uint64_t txid = 0;
/// the key of a router closer in keyspace if iterative lookup
std::optional<Key_t> closer;
GotIntroMessage(const Key_t& from) : AbstractDHTMessage(from)
{}
GotIntroMessage(const GotIntroMessage& other)
: AbstractDHTMessage(other.From), found(other.found), txid(other.txid), closer(other.closer)
{
/// the found introsets
std::vector<service::EncryptedIntroSet> found;
/// txid
uint64_t txid = 0;
/// the key of a router closer in keyspace if iterative lookup
std::optional<Key_t> closer;
version = other.version;
}
GotIntroMessage(const Key_t& from) : IMessage(from)
{}
/// for iterative reply
GotIntroMessage(const Key_t& from, const Key_t& _closer, uint64_t _txid)
: AbstractDHTMessage(from), txid(_txid), closer(_closer)
{}
GotIntroMessage(const GotIntroMessage& other)
: IMessage(other.From), found(other.found), txid(other.txid), closer(other.closer)
{
version = other.version;
}
/// for recursive reply
GotIntroMessage(std::vector<service::EncryptedIntroSet> results, uint64_t txid);
/// for iterative reply
GotIntroMessage(const Key_t& from, const Key_t& _closer, uint64_t _txid)
: IMessage(from), txid(_txid), closer(_closer)
{}
~GotIntroMessage() override = default;
/// for recursive reply
GotIntroMessage(std::vector<service::EncryptedIntroSet> results, uint64_t txid);
void
bt_encode(oxenc::bt_dict_producer& btdp) const override;
~GotIntroMessage() override = default;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
BEncode(llarp_buffer_t* buf) const override;
bool
handle_message(
llarp_dht_context* ctx, std::vector<AbstractDHTMessage::Ptr_t>& replies) const override;
};
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
HandleMessage(llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const override;
};
struct RelayedGotIntroMessage final : public GotIntroMessage
{
RelayedGotIntroMessage() : GotIntroMessage({})
{}
struct RelayedGotIntroMessage final : public GotIntroMessage
{
RelayedGotIntroMessage() : GotIntroMessage({})
{}
bool
HandleMessage(llarp_dht_context* ctx, std::vector<IMessage::Ptr_t>& replies) const override;
};
bool
handle_message(
llarp_dht_context* ctx, std::vector<AbstractDHTMessage::Ptr_t>& replies) const override;
};
using GotIntroMessage_constptr = std::shared_ptr<const GotIntroMessage>;
} // namespace dht
} // namespace llarp
using GotIntroMessage_constptr = std::shared_ptr<const GotIntroMessage>;
} // namespace llarp::dht

@ -9,23 +9,30 @@ namespace llarp::dht
constexpr size_t NameSizeLimit = 128;
GotNameMessage::GotNameMessage(const Key_t& from, uint64_t txid, service::EncryptedName data)
: IMessage(from), result(std::move(data)), TxID(txid)
: AbstractDHTMessage(from), result(std::move(data)), TxID(txid)
{
if (result.ciphertext.size() > NameSizeLimit)
throw std::invalid_argument("name data too big");
}
bool
GotNameMessage::BEncode(llarp_buffer_t* buf) const
void
GotNameMessage::bt_encode(oxenc::bt_dict_producer& btdp) const
{
const std::string nonce((const char*)result.nonce.data(), result.nonce.size());
const auto data = oxenc::bt_serialize(
oxenc::bt_dict{{"A", "M"sv}, {"D", result.ciphertext}, {"N", nonce}, {"T", TxID}});
return buf->write(data.begin(), data.end());
try
{
btdp.append("A", "M");
btdp.append("D", result.ciphertext);
btdp.append("N", result.nonce.ToView());
btdp.append("T", TxID);
}
catch (...)
{
log::error(dht_cat, "Error: GotNameMessage failed to bt encode contents!");
}
}
bool
GotNameMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
GotNameMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* val)
{
if (key.startswith("D"))
{
@ -50,7 +57,7 @@ namespace llarp::dht
}
bool
GotNameMessage::HandleMessage(struct llarp_dht_context* ctx, std::vector<Ptr_t>&) const
GotNameMessage::handle_message(struct llarp_dht_context* ctx, std::vector<Ptr_t>&) const
{
auto pathset = ctx->impl->GetRouter()->pathContext().GetLocalPathSet(pathID);
if (pathset == nullptr)

@ -5,21 +5,20 @@
namespace llarp::dht
{
struct GotNameMessage : public IMessage
struct GotNameMessage : public AbstractDHTMessage
{
explicit GotNameMessage(const Key_t& from, uint64_t txid, service::EncryptedName data);
bool
BEncode(llarp_buffer_t* buf) const override;
void
bt_encode(oxenc::bt_dict_producer& btdp) const override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
HandleMessage(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const override;
handle_message(struct llarp_dht_context* dht, std::vector<Ptr_t>& replies) const override;
service::EncryptedName result;
uint64_t TxID;
};
} // namespace llarp::dht

@ -7,133 +7,126 @@
#include <llarp/router/i_rc_lookup_handler.hpp>
#include <llarp/tooling/rc_event.hpp>
namespace llarp
namespace llarp::dht
{
namespace dht
{
GotRouterMessage::~GotRouterMessage() = default;
GotRouterMessage::~GotRouterMessage() = default;
bool
GotRouterMessage::BEncode(llarp_buffer_t* buf) const
void
GotRouterMessage::bt_encode(oxenc::bt_dict_producer& btdp) const
{
try
{
if (not bencode_start_dict(buf))
return false;
// message type
if (not BEncodeWriteDictMsgType(buf, "A", "S"))
return false;
btdp.append("A", "S");
if (closerTarget)
btdp.append("K", closerTarget->ToView());
{
if (not BEncodeWriteDictEntry("K", *closerTarget, buf))
return false;
auto sublist = btdp.append_list("N");
for (auto& k : nearKeys)
sublist.append(k.ToView());
}
// near
if (not nearKeys.empty())
{
if (not BEncodeWriteDictList("N", nearKeys, buf))
return false;
auto sublist = btdp.append_list("R");
for (auto& r : foundRCs)
sublist.append(r.ToString());
}
if (not BEncodeWriteDictList("R", foundRCs, buf))
return false;
btdp.append("T", txid);
btdp.append("V", version);
}
catch (...)
{
log::error(dht_cat, "Error: GotRouterMessage failed to bt encode contents!");
}
}
// txid
if (not BEncodeWriteDictInt("T", txid, buf))
bool
GotRouterMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* val)
{
if (key.startswith("K"))
{
if (closerTarget) // duplicate key?
return false;
closerTarget = std::make_unique<dht::Key_t>();
return closerTarget->BDecode(val);
}
if (key.startswith("N"))
{
return BEncodeReadList(nearKeys, val);
}
if (key.startswith("R"))
{
return BEncodeReadList(foundRCs, val);
}
if (key.startswith("T"))
{
return bencode_read_integer(val, &txid);
}
bool read = false;
if (!BEncodeMaybeVerifyVersion("V", version, llarp::constants::proto_version, read, key, val))
return false;
// version
if (not BEncodeWriteDictInt("V", version, buf))
return false;
return read;
}
return bencode_end(buf);
bool
GotRouterMessage::handle_message(
llarp_dht_context* ctx,
[[maybe_unused]] std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) const
{
auto& dht = *ctx->impl;
if (relayed)
{
auto pathset = ctx->impl->GetRouter()->pathContext().GetLocalPathSet(pathID);
auto copy = std::make_shared<const GotRouterMessage>(*this);
return pathset && pathset->HandleGotRouterMessage(copy);
}
// not relayed
const TXOwner owner(From, txid);
bool
GotRouterMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
if (dht.pendingExploreLookups().HasPendingLookupFrom(owner))
{
if (key.startswith("K"))
{
if (closerTarget) // duplicate key?
return false;
closerTarget = std::make_unique<dht::Key_t>();
return closerTarget->BDecode(val);
}
if (key.startswith("N"))
LogDebug("got ", nearKeys.size(), " results in GRM for explore");
if (nearKeys.empty())
dht.pendingExploreLookups().NotFound(owner, closerTarget);
else
{
return BEncodeReadList(nearKeys, val);
dht.pendingExploreLookups().Found(owner, From.as_array(), nearKeys);
}
if (key.startswith("R"))
{
return BEncodeReadList(foundRCs, val);
}
if (key.startswith("T"))
{
return bencode_read_integer(val, &txid);
}
bool read = false;
if (!BEncodeMaybeVerifyVersion("V", version, llarp::constants::proto_version, read, key, val))
return true;
}
// not explore lookup
if (dht.pendingRouterLookups().HasPendingLookupFrom(owner))
{
LogDebug("got ", foundRCs.size(), " results in GRM for lookup");
if (foundRCs.empty())
dht.pendingRouterLookups().NotFound(owner, closerTarget);
else if (foundRCs[0].pubkey.IsZero())
return false;
return read;
else
dht.pendingRouterLookups().Found(owner, foundRCs[0].pubkey, foundRCs);
return true;
}
bool
GotRouterMessage::HandleMessage(
llarp_dht_context* ctx,
[[maybe_unused]] std::vector<std::unique_ptr<IMessage>>& replies) const
// store if valid
for (const auto& rc : foundRCs)
{
auto& dht = *ctx->impl;
if (relayed)
{
auto pathset = ctx->impl->GetRouter()->pathContext().GetLocalPathSet(pathID);
auto copy = std::make_shared<const GotRouterMessage>(*this);
return pathset && pathset->HandleGotRouterMessage(copy);
}
// not relayed
const TXOwner owner(From, txid);
if (dht.pendingExploreLookups().HasPendingLookupFrom(owner))
{
LogDebug("got ", nearKeys.size(), " results in GRM for explore");
if (nearKeys.empty())
dht.pendingExploreLookups().NotFound(owner, closerTarget);
else
{
dht.pendingExploreLookups().Found(owner, From.as_array(), nearKeys);
}
return true;
}
// not explore lookup
if (dht.pendingRouterLookups().HasPendingLookupFrom(owner))
{
LogDebug("got ", foundRCs.size(), " results in GRM for lookup");
if (foundRCs.empty())
dht.pendingRouterLookups().NotFound(owner, closerTarget);
else if (foundRCs[0].pubkey.IsZero())
return false;
else
dht.pendingRouterLookups().Found(owner, foundRCs[0].pubkey, foundRCs);
return true;
}
// store if valid
for (const auto& rc : foundRCs)
if (not dht.GetRouter()->rcLookupHandler().CheckRC(rc))
return false;
if (txid == 0) // txid == 0 on gossip
{
if (not dht.GetRouter()->rcLookupHandler().CheckRC(rc))
return false;
if (txid == 0) // txid == 0 on gossip
{
auto* router = dht.GetRouter();
router->NotifyRouterEvent<tooling::RCGossipReceivedEvent>(router->pubkey(), rc);
router->GossipRCIfNeeded(rc);
auto* router = dht.GetRouter();
router->NotifyRouterEvent<tooling::RCGossipReceivedEvent>(router->pubkey(), rc);
router->GossipRCIfNeeded(rc);
auto peerDb = router->peerDb();
if (peerDb)
peerDb->handleGossipedRC(rc);
}
auto peerDb = router->peerDb();
if (peerDb)
peerDb->handleGossipedRC(rc);
}
return true;
}
} // namespace dht
} // namespace llarp
return true;
}
} // namespace llarp::dht

@ -6,63 +6,61 @@
#include <utility>
#include <vector>
namespace llarp
namespace llarp::dht
{
namespace dht
struct GotRouterMessage final : public AbstractDHTMessage
{
struct GotRouterMessage final : public IMessage
{
GotRouterMessage(const Key_t& from, bool tunneled) : IMessage(from), relayed(tunneled)
{}
GotRouterMessage(
const Key_t& from, uint64_t id, const std::vector<RouterContact>& results, bool tunneled)
: IMessage(from), foundRCs(results), txid(id), relayed(tunneled)
{}
GotRouterMessage(const Key_t& from, bool tunneled) : AbstractDHTMessage(from), relayed(tunneled)
{}
GotRouterMessage(
const Key_t& from, uint64_t id, const std::vector<RouterContact>& results, bool tunneled)
: AbstractDHTMessage(from), foundRCs(results), txid(id), relayed(tunneled)
{}
GotRouterMessage(const Key_t& from, const Key_t& closer, uint64_t id, bool tunneled)
: IMessage(from), closerTarget(new Key_t(closer)), txid(id), relayed(tunneled)
{}
GotRouterMessage(const Key_t& from, const Key_t& closer, uint64_t id, bool tunneled)
: AbstractDHTMessage(from), closerTarget(new Key_t(closer)), txid(id), relayed(tunneled)
{}
GotRouterMessage(uint64_t id, std::vector<RouterID> _near, bool tunneled)
: IMessage({}), nearKeys(std::move(_near)), txid(id), relayed(tunneled)
{}
GotRouterMessage(uint64_t id, std::vector<RouterID> _near, bool tunneled)
: AbstractDHTMessage({}), nearKeys(std::move(_near)), txid(id), relayed(tunneled)
{}
/// gossip message
GotRouterMessage(const RouterContact rc) : IMessage({}), foundRCs({rc}), txid(0)
{
version = llarp::constants::proto_version;
}
/// gossip message
GotRouterMessage(const RouterContact rc) : AbstractDHTMessage({}), foundRCs({rc}), txid(0)
{
version = llarp::constants::proto_version;
}
GotRouterMessage(const GotRouterMessage& other)
: IMessage(other.From)
, foundRCs(other.foundRCs)
, nearKeys(other.nearKeys)
, closerTarget(copy_or_nullptr(other.closerTarget))
, txid(other.txid)
, relayed(other.relayed)
{
version = other.version;
}
GotRouterMessage(const GotRouterMessage& other)
: AbstractDHTMessage(other.From)
, foundRCs(other.foundRCs)
, nearKeys(other.nearKeys)
, closerTarget(copy_or_nullptr(other.closerTarget))
, txid(other.txid)
, relayed(other.relayed)
{
version = other.version;
}
~GotRouterMessage() override;
~GotRouterMessage() override;
bool
BEncode(llarp_buffer_t* buf) const override;
void
bt_encode(oxenc::bt_dict_producer& btdp) const override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
HandleMessage(
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const override;
bool
handle_message(
llarp_dht_context* ctx,
std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) const override;
std::vector<RouterContact> foundRCs;
std::vector<RouterID> nearKeys;
std::unique_ptr<Key_t> closerTarget;
uint64_t txid = 0;
bool relayed = false;
};
std::vector<RouterContact> foundRCs;
std::vector<RouterID> nearKeys;
std::unique_ptr<Key_t> closerTarget;
uint64_t txid = 0;
bool relayed = false;
};
using GotRouterMessage_constptr = std::shared_ptr<const GotRouterMessage>;
} // namespace dht
} // namespace llarp
using GotRouterMessage_constptr = std::shared_ptr<const GotRouterMessage>;
} // namespace llarp::dht

@ -9,194 +9,184 @@
#include <llarp/tooling/dht_event.hpp>
namespace llarp
namespace llarp::dht
{
namespace dht
const uint64_t PublishIntroMessage::MaxPropagationDepth = 5;
PublishIntroMessage::~PublishIntroMessage() = default;
bool
PublishIntroMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* val)
{
const uint64_t PublishIntroMessage::MaxPropagationDepth = 5;
PublishIntroMessage::~PublishIntroMessage() = default;
bool read = false;
if (!BEncodeMaybeReadDictEntry("I", introset, read, key, val))
return false;
if (read)
return true;
if (!BEncodeMaybeReadDictInt("O", relayOrder, read, key, val))
return false;
if (read)
return true;
bool
PublishIntroMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
uint64_t relayedInt = (relayed ? 1 : 0);
if (!BEncodeMaybeReadDictInt("R", relayedInt, read, key, val))
return false;
if (read)
{
bool read = false;
if (!BEncodeMaybeReadDictEntry("I", introset, read, key, val))
return false;
if (read)
return true;
relayed = relayedInt;
return true;
}
if (!BEncodeMaybeReadDictInt("O", relayOrder, read, key, val))
return false;
if (read)
return true;
if (!BEncodeMaybeReadDictInt("T", txID, read, key, val))
return false;
if (read)
return true;
uint64_t relayedInt = (relayed ? 1 : 0);
if (!BEncodeMaybeReadDictInt("R", relayedInt, read, key, val))
return false;
if (read)
{
relayed = relayedInt;
return true;
}
if (!BEncodeMaybeReadDictInt("V", version, read, key, val))
return false;
if (read)
return true;
if (!BEncodeMaybeReadDictInt("T", txID, read, key, val))
return false;
if (read)
return true;
return false;
}
if (!BEncodeMaybeReadDictInt("V", version, read, key, val))
return false;
if (read)
return true;
bool
PublishIntroMessage::handle_message(
llarp_dht_context* ctx, std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) const
{
const auto now = ctx->impl->Now();
const llarp::dht::Key_t addr{introset.derivedSigningKey.data()};
return false;
auto router = ctx->impl->GetRouter();
router->NotifyRouterEvent<tooling::PubIntroReceivedEvent>(
router->pubkey(), Key_t(relayed ? router->pubkey() : From.data()), addr, txID, relayOrder);
auto& dht = *ctx->impl;
if (!introset.Verify(now))
{
llarp::LogWarn("Received PublishIntroMessage with invalid introset: ", introset);
// don't propogate or store
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
bool
PublishIntroMessage::HandleMessage(
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const
if (introset.IsExpired(now + llarp::service::MAX_INTROSET_TIME_DELTA))
{
const auto now = ctx->impl->Now();
const llarp::dht::Key_t addr{introset.derivedSigningKey.data()};
auto router = ctx->impl->GetRouter();
router->NotifyRouterEvent<tooling::PubIntroReceivedEvent>(
router->pubkey(),
Key_t(relayed ? router->pubkey() : From.data()),
addr,
txID,
relayOrder);
auto& dht = *ctx->impl;
if (!introset.Verify(now))
{
llarp::LogWarn("Received PublishIntroMessage with invalid introset: ", introset);
// don't propogate or store
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
// don't propogate or store
llarp::LogWarn("Received PublishIntroMessage with expired Introset: ", introset);
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
if (introset.IsExpired(now + llarp::service::MAX_INTROSET_TIME_DELTA))
{
// don't propogate or store
llarp::LogWarn("Received PublishIntroMessage with expired Introset: ", introset);
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
// identify closest 4 routers
auto closestRCs = dht.GetRouter()->nodedb()->FindManyClosestTo(addr, IntroSetStorageRedundancy);
if (closestRCs.size() != IntroSetStorageRedundancy)
{
llarp::LogWarn("Received PublishIntroMessage but only know ", closestRCs.size(), " nodes");
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
// identify closest 4 routers
auto closestRCs =
dht.GetRouter()->nodedb()->FindManyClosestTo(addr, IntroSetStorageRedundancy);
if (closestRCs.size() != IntroSetStorageRedundancy)
{
llarp::LogWarn("Received PublishIntroMessage but only know ", closestRCs.size(), " nodes");
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
const auto& us = dht.OurKey();
const auto& us = dht.OurKey();
// function to identify the closest 4 routers we know of for this introset
auto propagateIfNotUs = [&](size_t index) {
assert(index < IntroSetStorageRedundancy);
// function to identify the closest 4 routers we know of for this introset
auto propagateIfNotUs = [&](size_t index) {
assert(index < IntroSetStorageRedundancy);
const auto& rc = closestRCs[index];
const Key_t peer{rc.pubkey};
const auto& rc = closestRCs[index];
const Key_t peer{rc.pubkey};
if (peer == us)
{
llarp::LogInfo("we are peer ", index, " so storing instead of propagating");
if (peer == us)
dht.services()->PutNode(introset);
replies.emplace_back(new GotIntroMessage({introset}, txID));
}
else
{
llarp::LogInfo("propagating to peer ", index);
if (relayed)
{
llarp::LogInfo("we are peer ", index, " so storing instead of propagating");
dht.services()->PutNode(introset);
replies.emplace_back(new GotIntroMessage({introset}, txID));
dht.PropagateLocalIntroSet(pathID, txID, introset, peer, 0);
}
else
{
llarp::LogInfo("propagating to peer ", index);
if (relayed)
{
dht.PropagateLocalIntroSet(pathID, txID, introset, peer, 0);
}
else
{
dht.PropagateIntroSetTo(From, txID, introset, peer, 0);
}
dht.PropagateIntroSetTo(From, txID, introset, peer, 0);
}
};
}
};
if (relayed)
if (relayed)
{
if (relayOrder >= IntroSetStorageRedundancy)
{
if (relayOrder >= IntroSetStorageRedundancy)
{
llarp::LogWarn("Received PublishIntroMessage with invalid relayOrder: ", relayOrder);
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
llarp::LogWarn("Received PublishIntroMessage with invalid relayOrder: ", relayOrder);
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
llarp::LogInfo("Relaying PublishIntroMessage for ", addr, ", txid=", txID);
llarp::LogInfo("Relaying PublishIntroMessage for ", addr, ", txid=", txID);
propagateIfNotUs(relayOrder);
}
else
propagateIfNotUs(relayOrder);
}
else
{
int candidateNumber = -1;
int index = 0;
for (const auto& rc : closestRCs)
{
int candidateNumber = -1;
int index = 0;
for (const auto& rc : closestRCs)
{
if (rc.pubkey == dht.OurKey())
{
candidateNumber = index;
break;
}
++index;
}
if (candidateNumber >= 0)
if (rc.pubkey == dht.OurKey())
{
LogInfo(
"Received PubIntro for ",
addr,
", txid=",
txID,
" and we are candidate ",
candidateNumber);
dht.services()->PutNode(introset);
replies.emplace_back(new GotIntroMessage({introset}, txID));
}
else
{
LogWarn(
"!!! Received PubIntro with relayed==false but we aren't"
" candidate, intro derived key: ",
addr,
", txid=",
txID,
", message from: ",
From);
candidateNumber = index;
break;
}
++index;
}
return true;
if (candidateNumber >= 0)
{
LogInfo(
"Received PubIntro for ",
addr,
", txid=",
txID,
" and we are candidate ",
candidateNumber);
dht.services()->PutNode(introset);
replies.emplace_back(new GotIntroMessage({introset}, txID));
}
else
{
LogWarn(
"!!! Received PubIntro with relayed==false but we aren't"
" candidate, intro derived key: ",
addr,
", txid=",
txID,
", message from: ",
From);
}
}
bool
PublishIntroMessage::BEncode(llarp_buffer_t* buf) const
return true;
}
void
PublishIntroMessage::bt_encode(oxenc::bt_dict_producer& btdp) const
{
try
{
btdp.append("A", "I");
btdp.append("T", introset.ToString());
btdp.append("O", relayOrder);
btdp.append("R", relayed ? 1 : 0);
btdp.append("T", txID);
btdp.append("V", llarp::constants::proto_version);
}
catch (...)
{
if (!bencode_start_dict(buf))
return false;
if (!BEncodeWriteDictMsgType(buf, "A", "I"))
return false;
if (!BEncodeWriteDictEntry("I", introset, buf))
return false;
if (!BEncodeWriteDictInt("O", relayOrder, buf))
return false;
if (!BEncodeWriteDictInt("R", relayed, buf))
return false;
if (!BEncodeWriteDictInt("T", txID, buf))
return false;
if (!BEncodeWriteDictInt("V", llarp::constants::proto_version, buf))
return false;
return bencode_end(buf);
log::error(dht_cat, "Error: PublishIntroMessage failed to bt encode contents!");
}
} // namespace dht
} // namespace llarp
}
} // namespace llarp::dht

@ -5,39 +5,42 @@
#include <utility>
#include <vector>
namespace llarp
namespace llarp::dht
{
namespace dht
struct PublishIntroMessage final : public AbstractDHTMessage
{
struct PublishIntroMessage final : public IMessage
{
static const uint64_t MaxPropagationDepth;
llarp::service::EncryptedIntroSet introset;
bool relayed = false;
uint64_t relayOrder = 0;
uint64_t txID = 0;
PublishIntroMessage(const Key_t& from, bool relayed_) : IMessage(from), relayed(relayed_)
{}
static const uint64_t MaxPropagationDepth;
llarp::service::EncryptedIntroSet introset;
bool relayed = false;
uint64_t relayOrder = 0;
uint64_t txID = 0;
PublishIntroMessage(const Key_t& from, bool relayed_)
: AbstractDHTMessage(from), relayed(relayed_)
{}
PublishIntroMessage(
const llarp::service::EncryptedIntroSet& introset_,
uint64_t tx,
bool relayed_,
uint64_t relayOrder_)
: IMessage({}), introset(introset_), relayed(relayed_), relayOrder(relayOrder_), txID(tx)
{}
PublishIntroMessage(
const llarp::service::EncryptedIntroSet& introset_,
uint64_t tx,
bool relayed_,
uint64_t relayOrder_)
: AbstractDHTMessage({})
, introset(introset_)
, relayed(relayed_)
, relayOrder(relayOrder_)
, txID(tx)
{}
~PublishIntroMessage() override;
~PublishIntroMessage() override;
bool
BEncode(llarp_buffer_t* buf) const override;
void
bt_encode(oxenc::bt_dict_producer& btdp) const override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
decode_key(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
HandleMessage(
llarp_dht_context* ctx, std::vector<std::unique_ptr<IMessage>>& replies) const override;
};
} // namespace dht
} // namespace llarp
bool
handle_message(
llarp_dht_context* ctx,
std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) const override;
};
} // namespace llarp::dht

@ -93,7 +93,7 @@ namespace llarp
}
bool
ObtainExitMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
ObtainExitMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h->HandleObtainExitMessage(*this, r);
}
@ -163,7 +163,7 @@ namespace llarp
}
bool
GrantExitMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
GrantExitMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h->HandleGrantExitMessage(*this, r);
}
@ -241,7 +241,7 @@ namespace llarp
}
bool
RejectExitMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
RejectExitMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h->HandleRejectExitMessage(*this, r);
}
@ -311,7 +311,7 @@ namespace llarp
}
bool
UpdateExitMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
UpdateExitMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h->HandleUpdateExitMessage(*this, r);
}
@ -346,7 +346,8 @@ namespace llarp
}
bool
UpdateExitVerifyMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
UpdateExitVerifyMessage::HandleMessage(
AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h->HandleUpdateExitVerifyMessage(*this, r);
}
@ -412,7 +413,7 @@ namespace llarp
}
bool
CloseExitMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
CloseExitMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h->HandleCloseExitMessage(*this, r);
}

@ -10,7 +10,7 @@ namespace llarp
{
namespace routing
{
struct ObtainExitMessage final : public IMessage
struct ObtainExitMessage final : public AbstractRoutingMessage
{
std::vector<llarp::exit::Policy> B;
uint64_t E{0};
@ -20,7 +20,7 @@ namespace llarp
uint64_t X{0};
llarp::Signature Z;
ObtainExitMessage() : IMessage()
ObtainExitMessage() : AbstractRoutingMessage()
{}
~ObtainExitMessage() override = default;
@ -51,10 +51,10 @@ namespace llarp
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
};
struct GrantExitMessage final : public IMessage
struct GrantExitMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
@ -75,7 +75,7 @@ namespace llarp
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
void
Clear() override
@ -86,7 +86,7 @@ namespace llarp
}
};
struct RejectExitMessage final : public IMessage
struct RejectExitMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
uint64_t B;
@ -118,10 +118,10 @@ namespace llarp
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
};
struct UpdateExitVerifyMessage final : public IMessage
struct UpdateExitVerifyMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
uint64_t T;
@ -145,10 +145,10 @@ namespace llarp
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
};
struct UpdateExitMessage final : public IMessage
struct UpdateExitMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
llarp::PathID_t P;
@ -169,7 +169,7 @@ namespace llarp
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
void
Clear() override
@ -181,7 +181,7 @@ namespace llarp
}
};
struct CloseExitMessage final : public IMessage
struct CloseExitMessage final : public AbstractRoutingMessage
{
using Nonce_t = llarp::AlignedBuffer<16>;
@ -195,7 +195,7 @@ namespace llarp
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
bool
Sign(const llarp::SecretKey& sk);

@ -48,9 +48,9 @@ namespace llarp::iwp
}
void
LinkLayer::RecvFrom(const SockAddr& from, ILinkSession::Packet_t pkt)
LinkLayer::RecvFrom(const SockAddr& from, AbstractLinkSession::Packet_t pkt)
{
std::shared_ptr<ILinkSession> session;
std::shared_ptr<AbstractLinkSession> session;
auto itr = m_AuthedAddrs.find(from);
bool isNewSession = false;
if (itr == m_AuthedAddrs.end())
@ -83,7 +83,7 @@ namespace llarp::iwp
}
}
std::shared_ptr<ILinkSession>
std::shared_ptr<AbstractLinkSession>
LinkLayer::NewOutboundSession(const RouterContact& rc, const AddressInfo& ai)
{
if (m_Inbound)

@ -32,7 +32,7 @@ namespace llarp::iwp
WorkerFunc_t dowork,
bool permitInbound);
std::shared_ptr<ILinkSession>
std::shared_ptr<AbstractLinkSession>
NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) override;
std::string_view
@ -42,7 +42,7 @@ namespace llarp::iwp
Rank() const override;
void
RecvFrom(const SockAddr& from, ILinkSession::Packet_t pkt) override;
RecvFrom(const SockAddr& from, AbstractLinkSession::Packet_t pkt) override;
void
WakeupPlaintext();
@ -55,7 +55,7 @@ namespace llarp::iwp
HandleWakeupPlaintext();
const std::shared_ptr<EventLoopWakeup> m_Wakeup;
std::vector<ILinkSession*> m_WakingUp;
std::vector<AbstractLinkSession*> m_WakingUp;
const bool m_Inbound;
};

@ -8,9 +8,9 @@ namespace llarp
{
OutboundMessage::OutboundMessage(
uint64_t msgid,
ILinkSession::Message_t msg,
AbstractLinkSession::Message_t msg,
llarp_time_t now,
ILinkSession::CompletionHandler handler,
AbstractLinkSession::CompletionHandler handler,
uint16_t priority)
: m_Data{std::move(msg)}
, m_MsgID{msgid}
@ -24,7 +24,7 @@ namespace llarp
m_Acks.set(0);
}
ILinkSession::Packet_t
AbstractLinkSession::Packet_t
OutboundMessage::XMIT() const
{
size_t extra = std::min(m_Data.size(), FragmentSize);
@ -43,7 +43,7 @@ namespace llarp
{
if (m_Completed)
{
m_Completed(ILinkSession::DeliveryStatus::eDeliverySuccess);
m_Completed(AbstractLinkSession::DeliveryStatus::eDeliverySuccess);
}
m_Completed = nullptr;
}
@ -62,7 +62,7 @@ namespace llarp
void
OutboundMessage::FlushUnAcked(
std::function<void(ILinkSession::Packet_t)> sendpkt, llarp_time_t now)
std::function<void(AbstractLinkSession::Packet_t)> sendpkt, llarp_time_t now)
{
/// overhead for a data packet in plaintext
static constexpr size_t Overhead = 10;
@ -111,7 +111,7 @@ namespace llarp
{
if (m_Completed)
{
m_Completed(ILinkSession::DeliveryStatus::eDeliveryDropped);
m_Completed(AbstractLinkSession::DeliveryStatus::eDeliveryDropped);
}
m_Completed = nullptr;
}
@ -135,7 +135,7 @@ namespace llarp
m_LastActiveAt = now;
}
ILinkSession::Packet_t
AbstractLinkSession::Packet_t
InboundMessage::ACKS() const
{
auto acks = CreatePacket(Command::eACKS, 9);
@ -175,7 +175,8 @@ namespace llarp
}
void
InboundMessage::SendACKS(std::function<void(ILinkSession::Packet_t)> sendpkt, llarp_time_t now)
InboundMessage::SendACKS(
std::function<void(AbstractLinkSession::Packet_t)> sendpkt, llarp_time_t now)
{
sendpkt(ACKS());
m_LastACKSent = now;

@ -38,15 +38,15 @@ namespace llarp
OutboundMessage() = default;
OutboundMessage(
uint64_t msgid,
ILinkSession::Message_t data,
AbstractLinkSession::Message_t data,
llarp_time_t now,
ILinkSession::CompletionHandler handler,
AbstractLinkSession::CompletionHandler handler,
uint16_t priority);
ILinkSession::Message_t m_Data;
AbstractLinkSession::Message_t m_Data;
uint64_t m_MsgID = 0;
std::bitset<MAX_LINK_MSG_SIZE / FragmentSize> m_Acks;
ILinkSession::CompletionHandler m_Completed;
AbstractLinkSession::CompletionHandler m_Completed;
llarp_time_t m_LastFlush = 0s;
ShortHash m_Digest;
llarp_time_t m_StartedAt = 0s;
@ -61,14 +61,14 @@ namespace llarp
return std::tie(prioA, m_MsgID) < std::tie(prioB, other.m_MsgID);
}
ILinkSession::Packet_t
AbstractLinkSession::Packet_t
XMIT() const;
void
Ack(byte_t bitmask);
void
FlushUnAcked(std::function<void(ILinkSession::Packet_t)> sendpkt, llarp_time_t now);
FlushUnAcked(std::function<void(AbstractLinkSession::Packet_t)> sendpkt, llarp_time_t now);
bool
ShouldFlush(llarp_time_t now) const;
@ -91,7 +91,7 @@ namespace llarp
InboundMessage() = default;
InboundMessage(uint64_t msgid, uint16_t sz, ShortHash h, llarp_time_t now);
ILinkSession::Message_t m_Data;
AbstractLinkSession::Message_t m_Data;
ShortHash m_Digset;
uint64_t m_MsgID = 0;
llarp_time_t m_LastACKSent = 0s;
@ -117,9 +117,9 @@ namespace llarp
ShouldSendACKS(llarp_time_t now) const;
void
SendACKS(std::function<void(ILinkSession::Packet_t)> sendpkt, llarp_time_t now);
SendACKS(std::function<void(AbstractLinkSession::Packet_t)> sendpkt, llarp_time_t now);
ILinkSession::Packet_t
AbstractLinkSession::Packet_t
ACKS() const;
};

@ -11,11 +11,11 @@ namespace llarp
{
namespace iwp
{
ILinkSession::Packet_t
AbstractLinkSession::Packet_t
CreatePacket(Command cmd, size_t plainsize, size_t minpad, size_t variance)
{
const size_t pad = minpad > 0 ? minpad + (variance > 0 ? randint() % variance : 0) : 0;
ILinkSession::Packet_t pkt(PacketOverhead + plainsize + pad + CommandOverhead);
AbstractLinkSession::Packet_t pkt(PacketOverhead + plainsize + pad + CommandOverhead);
// randomize pad
if (pad)
{
@ -100,8 +100,8 @@ namespace llarp
m_RemoteRC = msg->rc;
GotLIM = util::memFn(&Session::GotRenegLIM, this);
assert(shared_from_this().use_count() > 1);
SendOurLIM([self = shared_from_this()](ILinkSession::DeliveryStatus st) {
if (st == ILinkSession::DeliveryStatus::eDeliverySuccess)
SendOurLIM([self = shared_from_this()](AbstractLinkSession::DeliveryStatus st) {
if (st == AbstractLinkSession::DeliveryStatus::eDeliverySuccess)
{
self->m_State = State::Ready;
self->m_Parent->MapAddr(self->m_RemoteRC.pubkey, self.get());
@ -112,24 +112,30 @@ namespace llarp
}
void
Session::SendOurLIM(ILinkSession::CompletionHandler h)
Session::SendOurLIM(AbstractLinkSession::CompletionHandler h)
{
LinkIntroMessage msg;
msg.rc = m_Parent->GetOurRC();
msg.N.Randomize();
msg.P = 60000;
if (not msg.Sign(m_Parent->Sign))
msg.nonce.Randomize();
msg.session_period = 60000;
if (not msg.sign(m_Parent->Sign))
{
LogError("failed to sign our RC for ", m_RemoteAddr);
return;
}
ILinkSession::Message_t data(LinkIntroMessage::MaxSize + PacketOverhead);
AbstractLinkSession::Message_t data(LinkIntroMessage::MAX_MSG_SIZE + PacketOverhead);
llarp_buffer_t buf(data);
if (not msg.BEncode(&buf))
if (auto str = msg.bt_encode(); not str.empty())
{
LogError("failed to encode LIM for ", m_RemoteAddr);
buf.write(str.begin(), str.end());
}
else
{
log::critical(link_cat, "Error: Failed to encode LIM for {}", m_RemoteAddr);
return;
}
if (not SendMessageBuffer(std::move(data), h))
{
LogError("failed to send LIM to ", m_RemoteAddr);
@ -139,7 +145,7 @@ namespace llarp
}
void
Session::EncryptAndSend(ILinkSession::Packet_t data)
Session::EncryptAndSend(AbstractLinkSession::Packet_t data)
{
m_EncryptNext.emplace_back(std::move(data));
TriggerPump();
@ -186,12 +192,14 @@ namespace llarp
bool
Session::SendMessageBuffer(
ILinkSession::Message_t buf, ILinkSession::CompletionHandler completed, uint16_t priority)
AbstractLinkSession::Message_t buf,
AbstractLinkSession::CompletionHandler completed,
uint16_t priority)
{
if (m_TXMsgs.size() >= MaxSendQueueSize)
{
if (completed)
completed(ILinkSession::DeliveryStatus::eDeliveryDropped);
completed(AbstractLinkSession::DeliveryStatus::eDeliveryDropped);
return false;
}
const auto now = m_Parent->Now();
@ -441,7 +449,7 @@ namespace llarp
TunnelNonce N;
N.Randomize();
{
ILinkSession::Packet_t req(Introduction::SIZE + PacketOverhead);
AbstractLinkSession::Packet_t req(Introduction::SIZE + PacketOverhead);
const auto pk = m_Parent->GetOurRC().pubkey;
const auto e_pk = m_Parent->RouterEncryptionSecret().toPublic();
auto itr = req.data() + PacketOverhead;
@ -955,7 +963,7 @@ namespace llarp
}
bool
Session::Recv_LL(ILinkSession::Packet_t data)
Session::Recv_LL(AbstractLinkSession::Packet_t data)
{
m_RXRate += data.size();

@ -19,7 +19,7 @@ namespace llarp
/// packet crypto overhead size
static constexpr size_t PacketOverhead = HMACSIZE + TUNNONCESIZE;
/// creates a packet with plaintext size + wire overhead + random pad
ILinkSession::Packet_t
AbstractLinkSession::Packet_t
CreatePacket(Command cmd, size_t plainsize, size_t min_pad = 16, size_t pad_variance = 16);
/// Time how long we try delivery for
static constexpr std::chrono::milliseconds DeliveryTimeout = 500ms;
@ -36,7 +36,7 @@ namespace llarp
/// How long we wait for a session to die with no tx from them
static constexpr auto SessionAliveTimeout = PingInterval * 5;
struct Session : public ILinkSession, public std::enable_shared_from_this<Session>
struct Session : public AbstractLinkSession, public std::enable_shared_from_this<Session>
{
using Time_t = std::chrono::milliseconds;
@ -61,14 +61,14 @@ namespace llarp
bool
SendMessageBuffer(
ILinkSession::Message_t msg,
AbstractLinkSession::Message_t msg,
CompletionHandler resultHandler,
uint16_t priority = 0) override;
void
Send_LL(const byte_t* buf, size_t sz);
void EncryptAndSend(ILinkSession::Packet_t);
void EncryptAndSend(AbstractLinkSession::Packet_t);
void
Start() override;
@ -76,7 +76,7 @@ namespace llarp
void
Close() override;
bool Recv_LL(ILinkSession::Packet_t) override;
bool Recv_LL(AbstractLinkSession::Packet_t) override;
bool
SendKeepAlive() override;
@ -251,7 +251,7 @@ namespace llarp
GotRenegLIM(const LinkIntroMessage* msg);
void
SendOurLIM(ILinkSession::CompletionHandler h = nullptr);
SendOurLIM(AbstractLinkSession::CompletionHandler h = nullptr);
void
HandleXMIT(Packet_t msg);

@ -15,7 +15,7 @@ namespace llarp::link
RouterContact remote_rc;
bool inbound; // one side of a connection will be responsible for some things, e.g. heartbeat
bool inbound; // one side of a connection will be responsible for some things, e.g. heartbeat
bool remote_is_relay;
};
} // namespace llarp::link

@ -12,13 +12,12 @@ namespace llarp::link
struct Endpoint
{
std::shared_ptr<oxen::quic::Endpoint> endpoint;
bool inbound {false};
bool inbound{false};
// for outgoing packets, we route via RouterID; map RouterID->Connection
// for incoming packets, we get a ConnectionID; map ConnectionID->RouterID
std::unordered_map<RouterID, link::Connection> connections;
std::unordered_map<oxen::quic::ConnectionID, RouterID> connid_map;
};
} // namespace llarp::link

@ -14,7 +14,7 @@ struct llarp_buffer_t;
namespace llarp
{
//TODO: do we still want this?
// TODO: do we still want this?
enum class SessionResult
{
Establish,
@ -39,15 +39,11 @@ namespace llarp
template <>
constexpr inline bool IsToStringFormattable<SessionResult> = true;
struct RouterContact;
struct ILinkSession;
struct AbstractLinkSession;
struct IOutboundSessionMaker;
struct RouterID;
using bstring = std::basic_string<std::byte>;
using bstring_view = std::basic_string_view<std::byte>;
struct ILinkManager
{
virtual ~ILinkManager() = default;
@ -56,7 +52,7 @@ namespace llarp
SendTo(
const RouterID& remote,
const llarp_buffer_t& buf,
ILinkSession::CompletionHandler completed,
AbstractLinkSession::CompletionHandler completed,
uint16_t priority = 0) = 0;
virtual bool

@ -17,22 +17,22 @@ namespace llarp
for (auto& ep : endpoints)
{
//TODO: need some notion of "is this link compatible with that address".
// iwp just checks that the link dialect ("iwp") matches the address info dialect,
// but that feels insufficient. For now, just return the first endpoint we have;
// we should probably only have 1 for now anyway until we make ipv6 work.
// TODO: need some notion of "is this link compatible with that address".
// iwp just checks that the link dialect ("iwp") matches the address info dialect,
// but that feels insufficient. For now, just return the first endpoint we have;
// we should probably only have 1 for now anyway until we make ipv6 work.
return &ep;
}
return nullptr;
}
//TODO: replace with control/data message sending with libquic
// TODO: replace with control/data message sending with libquic
bool
LinkManager::SendTo(
const RouterID& remote,
const llarp_buffer_t& buf,
ILinkSession::CompletionHandler completed,
AbstractLinkSession::CompletionHandler completed,
uint16_t priority)
{
if (stopping)
@ -42,13 +42,13 @@ namespace llarp
{
if (completed)
{
completed(ILinkSession::DeliveryStatus::eDeliveryDropped);
completed(AbstractLinkSession::DeliveryStatus::eDeliveryDropped);
}
return false;
}
//TODO: send the message
//TODO: if we keep bool return type, change this accordingly
// TODO: send the message
// TODO: if we keep bool return type, change this accordingly
return false;
}
@ -59,7 +59,7 @@ namespace llarp
{
if (auto itr = ep.connections.find(remote); itr != ep.connections.end())
{
if (not (itr->second.remote_is_relay and client_only))
if (not(itr->second.remote_is_relay and client_only))
return true;
return false;
}
@ -93,10 +93,16 @@ namespace llarp
void
LinkManager::AddLink(const oxen::quic::opt::local_addr& bind, bool inbound)
{
//TODO: libquic callbacks: new_conn_alpn_notify, new_conn_pubkey_ok, new_conn_established/ready
// stream_opened, stream_data, stream_closed, conn_closed
oxen::quic::dgram_data_callback dgram_cb = [this](oxen::quic::dgram_interface& dgi, bstring dgram){ HandleIncomingDataMessage(dgi, dgram); };
auto ep = quic->endpoint(bind, std::move(dgram_cb), oxen::quic::opt::enable_datagrams{oxen::quic::Splitting::ACTIVE});
// TODO: libquic callbacks: new_conn_alpn_notify, new_conn_pubkey_ok, new_conn_established/ready
// stream_opened, stream_data, stream_closed, conn_closed
oxen::quic::dgram_data_callback dgram_cb =
[this](oxen::quic::dgram_interface& dgi, bstring dgram) {
HandleIncomingDataMessage(dgi, dgram);
};
auto ep = quic->endpoint(
bind,
std::move(dgram_cb),
oxen::quic::opt::enable_datagrams{oxen::quic::Splitting::ACTIVE});
endpoints.emplace_back();
auto& endp = endpoints.back();
endp.endpoint = std::move(ep);
@ -147,7 +153,7 @@ namespace llarp
{
for (const auto& conn : ep.connections)
{
if (not (conn.second.remote_is_relay and clients_only))
if (not(conn.second.remote_is_relay and clients_only))
count++;
}
}
@ -191,7 +197,7 @@ namespace llarp
return false;
}
//TODO: this? perhaps no longer necessary in the same way?
// TODO: this? perhaps no longer necessary in the same way?
void
LinkManager::CheckPersistingSessions(llarp_time_t now)
{
@ -199,13 +205,12 @@ namespace llarp
return;
}
//TODO: do we still need this concept?
// TODO: do we still need this concept?
void
LinkManager::updatePeerDb(std::shared_ptr<PeerDb> peerDb)
{
}
{}
//TODO: this
// TODO: this
util::StatusObject
LinkManager::ExtractStatus() const
{
@ -223,13 +228,13 @@ namespace llarp
void
LinkManager::Connect(RouterID router)
{
auto fn = [this](const RouterID& r, const RouterContact* const rc, const RCRequestResult res){
if (res == RCRequestResult::Success)
Connect(*rc);
/* TODO:
else
RC lookup failure callback here
*/
auto fn = [this](const RouterID& r, const RouterContact* const rc, const RCRequestResult res) {
if (res == RCRequestResult::Success)
Connect(*rc);
/* TODO:
else
RC lookup failure callback here
*/
};
_rcLookup->GetRC(router, fn);
@ -239,31 +244,35 @@ namespace llarp
void
LinkManager::Connect(RouterContact rc)
{
//TODO: connection failed callback
// TODO: connection failed callback
if (HaveConnection(rc.pubkey))
return;
// RC shouldn't be valid if this is the case, but may as well sanity check...
//TODO: connection failed callback
// TODO: connection failed callback
if (rc.addrs.empty())
return;
//TODO: connection failed callback
// TODO: connection failed callback
auto* ep = GetCompatibleLink(rc);
if (ep == nullptr)
return;
//TODO: connection established/failed callbacks
oxen::quic::stream_data_callback stream_cb = [this](oxen::quic::Stream& stream, bstring_view packet){ HandleIncomingControlMessage(stream, packet); };
// TODO: connection established/failed callbacks
oxen::quic::stream_data_callback stream_cb =
[this](oxen::quic::Stream& stream, bstring_view packet) {
HandleIncomingControlMessage(stream, packet);
};
//TODO: once "compatible link" cares about address, actually choose addr to connect to
// based on which one is compatible with the link we chose. For now, just use
// the first one.
// TODO: once "compatible link" cares about address, actually choose addr to connect to
// based on which one is compatible with the link we chose. For now, just use
// the first one.
auto& selected = rc.addrs[0];
oxen::quic::opt::remote_addr remote{selected.IPString(), selected.port};
//TODO: confirm remote end is using the expected pubkey (RouterID).
//TODO: ALPN for "client" vs "relay" (could just be set on endpoint creation)
//TODO: does connect() inherit the endpoint's datagram data callback, and do we want it to if so?
// TODO: confirm remote end is using the expected pubkey (RouterID).
// TODO: ALPN for "client" vs "relay" (could just be set on endpoint creation)
// TODO: does connect() inherit the endpoint's datagram data callback, and do we want it to if
// so?
auto conn_interface = ep->endpoint->connect(remote, stream_cb, tls_creds);
std::shared_ptr<oxen::quic::Stream> stream = conn_interface->get_new_stream();
@ -308,13 +317,13 @@ namespace llarp
void
LinkManager::HandleIncomingDataMessage(oxen::quic::dgram_interface& dgi, bstring dgram)
{
//TODO: this
// TODO: this
}
void
LinkManager::HandleIncomingControlMessage(oxen::quic::Stream& stream, bstring_view packet)
{
//TODO: this
// TODO: this
}
} // namespace llarp

@ -19,14 +19,14 @@ namespace llarp
struct LinkManager final : public ILinkManager
{
public:
explicit LinkManager(AbstractRouter* r) : router{r} {}
explicit LinkManager(AbstractRouter* r) : router{r}
{}
bool
SendTo(
const RouterID& remote,
const llarp_buffer_t& buf,
ILinkSession::CompletionHandler completed,
AbstractLinkSession::CompletionHandler completed,
uint16_t priority) override;
bool
@ -82,14 +82,13 @@ namespace llarp
void
ConnectToRandomRouters(int numDesired);
//TODO: tune these (maybe even remove max?) now that we're switching to quic
// TODO: tune these (maybe even remove max?) now that we're switching to quic
/// always maintain this many connections to other routers
size_t minConnectedRouters = 4;
/// hard upperbound limit on the number of router to router connections
size_t maxConnectedRouters = 6;
private:
link::Endpoint*
GetCompatibleLink(const RouterContact& rc);
@ -111,16 +110,17 @@ namespace llarp
// FIXME: Lokinet currently expects to be able to kill all network functionality before
// finishing other shutdown things, including destroying this class, and that is all in
// Network's destructor, so we need to be able to destroy it before this class.
std::unique_ptr<oxen::quic::Network> quic { std::make_unique<oxen::quic::Network>() };
std::unique_ptr<oxen::quic::Network> quic{std::make_unique<oxen::quic::Network>()};
std::vector<link::Endpoint> endpoints;
//TODO: initialize creds
// TODO: initialize creds
std::shared_ptr<oxen::quic::GNUTLSCreds> tls_creds;
void HandleIncomingDataMessage(oxen::quic::dgram_interface& dgi, bstring dgram);
void HandleIncomingControlMessage(oxen::quic::Stream& stream, bstring_view packet);
void
HandleIncomingDataMessage(oxen::quic::dgram_interface& dgi, bstring dgram);
void
HandleIncomingControlMessage(oxen::quic::Stream& stream, bstring_view packet);
};
} // namespace llarp

@ -53,7 +53,7 @@ namespace llarp
return m_AuthedLinks.find(id) != m_AuthedLinks.end();
}
std::shared_ptr<ILinkSession>
std::shared_ptr<AbstractLinkSession>
ILinkLayer::FindSessionByPubkey(RouterID id)
{
Lock_t l(m_AuthedLinksMutex);
@ -64,9 +64,10 @@ namespace llarp
}
void
ILinkLayer::ForEachSession(std::function<void(const ILinkSession*)> visit, bool randomize) const
ILinkLayer::ForEachSession(
std::function<void(const AbstractLinkSession*)> visit, bool randomize) const
{
std::vector<std::shared_ptr<ILinkSession>> sessions;
std::vector<std::shared_ptr<AbstractLinkSession>> sessions;
{
Lock_t l(m_AuthedLinksMutex);
if (m_AuthedLinks.size() == 0)
@ -99,9 +100,10 @@ namespace llarp
}
bool
ILinkLayer::VisitSessionByPubkey(const RouterID& pk, std::function<bool(ILinkSession*)> visit)
ILinkLayer::VisitSessionByPubkey(
const RouterID& pk, std::function<bool(AbstractLinkSession*)> visit)
{
std::shared_ptr<ILinkSession> session;
std::shared_ptr<AbstractLinkSession> session;
{
Lock_t l(m_AuthedLinksMutex);
auto itr = m_AuthedLinks.find(pk);
@ -113,9 +115,9 @@ namespace llarp
}
void
ILinkLayer::ForEachSession(std::function<void(ILinkSession*)> visit)
ILinkLayer::ForEachSession(std::function<void(AbstractLinkSession*)> visit)
{
std::vector<std::shared_ptr<ILinkSession>> sessions;
std::vector<std::shared_ptr<AbstractLinkSession>> sessions;
{
Lock_t l(m_AuthedLinksMutex);
auto itr = m_AuthedLinks.begin();
@ -138,7 +140,7 @@ namespace llarp
m_Router = router;
m_udp = m_Router->loop()->make_udp(
[this]([[maybe_unused]] UDPHandle& udp, const SockAddr& from, llarp_buffer_t buf) {
ILinkSession::Packet_t pkt;
AbstractLinkSession::Packet_t pkt;
pkt.resize(buf.sz);
std::copy_n(buf.base, buf.sz, pkt.data());
RecvFrom(from, std::move(pkt));
@ -155,7 +157,7 @@ namespace llarp
ILinkLayer::Pump()
{
std::unordered_set<RouterID> closedSessions;
std::vector<std::shared_ptr<ILinkSession>> closedPending;
std::vector<std::shared_ptr<AbstractLinkSession>> closedPending;
auto _now = Now();
{
Lock_t l(m_AuthedLinksMutex);
@ -223,7 +225,7 @@ namespace llarp
}
bool
ILinkLayer::MapAddr(const RouterID& pk, ILinkSession* s)
ILinkLayer::MapAddr(const RouterID& pk, AbstractLinkSession* s)
{
Lock_t l_authed(m_AuthedLinksMutex);
Lock_t l_pending(m_PendingMutex);
@ -321,7 +323,7 @@ namespace llarp
return false;
}
}
std::shared_ptr<ILinkSession> s = NewOutboundSession(rc, to);
std::shared_ptr<AbstractLinkSession> s = NewOutboundSession(rc, to);
if (BeforeConnect)
{
BeforeConnect(std::move(rc));
@ -432,10 +434,10 @@ namespace llarp
ILinkLayer::SendTo(
const RouterID& remote,
const llarp_buffer_t& buf,
ILinkSession::CompletionHandler completed,
AbstractLinkSession::CompletionHandler completed,
uint16_t priority)
{
std::shared_ptr<ILinkSession> s;
std::shared_ptr<AbstractLinkSession> s;
{
Lock_t l(m_AuthedLinksMutex);
// pick lowest backlog session
@ -450,7 +452,7 @@ namespace llarp
}
}
}
ILinkSession::Message_t pkt(buf.sz);
AbstractLinkSession::Message_t pkt(buf.sz);
std::copy_n(buf.base, buf.sz, pkt.begin());
return s && s->SendMessageBuffer(std::move(pkt), completed, priority);
}
@ -478,7 +480,7 @@ namespace llarp
}
bool
ILinkLayer::PutSession(const std::shared_ptr<ILinkSession>& s)
ILinkLayer::PutSession(const std::shared_ptr<AbstractLinkSession>& s)
{
Lock_t lock(m_PendingMutex);
const auto address = s->GetRemoteEndpoint();

@ -18,7 +18,7 @@ namespace llarp
/// handle a link layer message. this allows for the message to be handled by "upper layers"
///
/// currently called from iwp::Session when messages are sent or received.
using LinkMessageHandler = std::function<bool(ILinkSession*, const llarp_buffer_t&)>;
using LinkMessageHandler = std::function<bool(AbstractLinkSession*, const llarp_buffer_t&)>;
/// sign a buffer with identity key. this function should take the given `llarp_buffer_t` and
/// sign it, prividing the signature in the out variable `Signature&`.
@ -29,7 +29,7 @@ namespace llarp
/// handle connection timeout
///
/// currently called from ILinkLayer::Pump() when an unestablished session times out
using TimeoutHandler = std::function<void(ILinkSession*)>;
using TimeoutHandler = std::function<void(AbstractLinkSession*)>;
/// get our RC
///
@ -41,7 +41,7 @@ namespace llarp
/// return true to accept
///
/// currently called in iwp::Session when a valid LIM is received.
using SessionEstablishedHandler = std::function<bool(ILinkSession*, bool)>;
using SessionEstablishedHandler = std::function<bool(AbstractLinkSession*, bool)>;
/// f(new, old)
/// handler of session renegotiation
@ -95,11 +95,11 @@ namespace llarp
HasSessionTo(const RouterID& pk);
void
ForEachSession(std::function<void(const ILinkSession*)> visit, bool randomize = false) const
EXCLUDES(m_AuthedLinksMutex);
ForEachSession(std::function<void(const AbstractLinkSession*)> visit, bool randomize = false)
const EXCLUDES(m_AuthedLinksMutex);
void
ForEachSession(std::function<void(ILinkSession*)> visit) EXCLUDES(m_AuthedLinksMutex);
ForEachSession(std::function<void(AbstractLinkSession*)> visit) EXCLUDES(m_AuthedLinksMutex);
void
UnmapAddr(const SockAddr& addr);
@ -110,18 +110,18 @@ namespace llarp
void
Bind(AbstractRouter* router, SockAddr addr);
virtual std::shared_ptr<ILinkSession>
virtual std::shared_ptr<AbstractLinkSession>
NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) = 0;
/// fetch a session by the identity pubkey it claims
std::shared_ptr<ILinkSession>
std::shared_ptr<AbstractLinkSession>
FindSessionByPubkey(RouterID pk);
virtual void
Pump();
virtual void
RecvFrom(const SockAddr& from, ILinkSession::Packet_t pkt) = 0;
RecvFrom(const SockAddr& from, AbstractLinkSession::Packet_t pkt) = 0;
bool
PickAddress(const RouterContact& rc, AddressInfo& picked) const;
@ -151,14 +151,14 @@ namespace llarp
SendTo(
const RouterID& remote,
const llarp_buffer_t& buf,
ILinkSession::CompletionHandler completed,
AbstractLinkSession::CompletionHandler completed,
uint16_t priority);
virtual bool
GetOurAddressInfo(AddressInfo& addr) const;
bool
VisitSessionByPubkey(const RouterID& pk, std::function<bool(ILinkSession*)> visit)
VisitSessionByPubkey(const RouterID& pk, std::function<bool(AbstractLinkSession*)> visit)
EXCLUDES(m_AuthedLinksMutex);
virtual uint16_t
@ -187,7 +187,7 @@ namespace llarp
}
bool
MapAddr(const RouterID& pk, ILinkSession* s);
MapAddr(const RouterID& pk, AbstractLinkSession* s);
void
Tick(llarp_time_t now);
@ -254,15 +254,15 @@ namespace llarp
using Mutex_t = util::NullMutex;
#endif
bool
PutSession(const std::shared_ptr<ILinkSession>& s);
PutSession(const std::shared_ptr<AbstractLinkSession>& s);
AbstractRouter* m_Router;
SockAddr m_ourAddr;
std::shared_ptr<llarp::UDPHandle> m_udp;
SecretKey m_SecretKey;
using AuthedLinks = std::unordered_multimap<RouterID, std::shared_ptr<ILinkSession>>;
using Pending = std::unordered_map<SockAddr, std::shared_ptr<ILinkSession>>;
using AuthedLinks = std::unordered_multimap<RouterID, std::shared_ptr<AbstractLinkSession>>;
using Pending = std::unordered_map<SockAddr, std::shared_ptr<AbstractLinkSession>>;
mutable DECLARE_LOCK(Mutex_t, m_AuthedLinksMutex, ACQUIRED_BEFORE(m_PendingMutex));
AuthedLinks m_AuthedLinks GUARDED_BY(m_AuthedLinksMutex);
mutable DECLARE_LOCK(Mutex_t, m_PendingMutex, ACQUIRED_AFTER(m_AuthedLinksMutex));

@ -3,7 +3,7 @@
namespace llarp
{
bool
ILinkSession::IsRelay() const
AbstractLinkSession::IsRelay() const
{
return GetRemoteRC().IsPublicRouter();
}

@ -11,7 +11,7 @@
namespace llarp
{
struct LinkIntroMessage;
struct ILinkMessage;
struct AbstractLinkMessage;
struct ILinkLayer;
struct SessionStats
@ -27,9 +27,9 @@ namespace llarp
uint64_t totalInFlightTX = 0;
};
struct ILinkSession
struct AbstractLinkSession
{
virtual ~ILinkSession() = default;
virtual ~AbstractLinkSession() = default;
/// delivery status of a message
enum class DeliveryStatus

@ -0,0 +1,21 @@
#pragma once
#include <llarp/util/buffer.hpp>
#include <oxenc/bt.h>
namespace llarp
{
/// abstract base class for serialized messages
struct AbstractSerializable
{
virtual std::string
bt_encode() const = 0;
virtual void
bt_encode(llarp_buffer& b) const = 0;
virtual void
bt_encode(oxenc::bt_dict_producer& btdp) const = 0;
virtual void
bt_encode(oxenc::bt_list_producer& btlp) const = 0;
};
} // namespace llarp

@ -5,17 +5,41 @@
namespace llarp
{
void
DHTImmediateMessage::Clear()
DHTImmediateMessage::clear()
{
msgs.clear();
version = 0;
}
std::string
DHTImmediateMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("a", "");
{
auto subdict = btdp.append_dict("m");
for (auto& m : msgs)
m->bt_encode(subdict);
}
btdp.append("v", llarp::constants::proto_version);
}
catch (...)
{
log::critical(link_cat, "Error: DHTImmediateMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
DHTImmediateMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
DHTImmediateMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
if (key.startswith("m"))
return llarp::dht::DecodeMesssageList(dht::Key_t(session->GetPubKey()), buf, msgs);
return llarp::dht::DecodeMessageList(dht::Key_t(session->GetPubKey()), buf, msgs);
if (key.startswith("v"))
{
if (!bencode_read_integer(buf, &version))
@ -27,48 +51,14 @@ namespace llarp
}
bool
DHTImmediateMessage::BEncode(llarp_buffer_t* buf) const
{
if (!bencode_start_dict(buf))
return false;
// message type
if (!bencode_write_bytestring(buf, "a", 1))
return false;
if (!bencode_write_bytestring(buf, "m", 1))
return false;
// dht messages
if (!bencode_write_bytestring(buf, "m", 1))
return false;
// begin list
if (!bencode_start_list(buf))
return false;
for (const auto& msg : msgs)
{
if (!msg->BEncode(buf))
return false;
}
// end list
if (!bencode_end(buf))
return false;
// protocol version
if (!bencode_write_uint64_entry(buf, "v", 1, llarp::constants::proto_version))
return false;
return bencode_end(buf);
}
bool
DHTImmediateMessage::HandleMessage(AbstractRouter* router) const
DHTImmediateMessage::handle_message(AbstractRouter* router) const
{
DHTImmediateMessage reply;
reply.session = session;
bool result = true;
for (auto& msg : msgs)
{
result &= msg->HandleMessage(router->dht(), reply.msgs);
result &= msg->handle_message(router->dht(), reply.msgs);
}
if (reply.msgs.size())
{

@ -7,27 +7,27 @@
namespace llarp
{
struct DHTImmediateMessage final : public ILinkMessage
struct DHTImmediateMessage final : public AbstractLinkMessage
{
DHTImmediateMessage() = default;
~DHTImmediateMessage() override = default;
std::vector<std::unique_ptr<dht::IMessage>> msgs;
std::vector<std::unique_ptr<dht::AbstractDHTMessage>> msgs;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
std::string
bt_encode() const override;
bool
BEncode(llarp_buffer_t* buf) const override;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
HandleMessage(AbstractRouter* router) const override;
handle_message(AbstractRouter* router) const override;
void
Clear() override;
clear() override;
const char*
Name() const override
name() const override
{
return "DHTImmediate";
}

@ -7,37 +7,42 @@
namespace llarp
{
struct DiscardMessage final : public ILinkMessage
struct DiscardMessage final : public AbstractLinkMessage
{
DiscardMessage() : ILinkMessage()
DiscardMessage() : AbstractLinkMessage()
{}
bool
BEncode(llarp_buffer_t* buf) const override
std::string
bt_encode() const override
{
if (!bencode_start_dict(buf))
return false;
if (!bencode_write_bytestring(buf, "a", 1))
return false;
if (!bencode_write_bytestring(buf, "x", 1))
return false;
return bencode_end(buf);
oxenc::bt_dict_producer btdp;
try
{
btdp.append("a", "x");
}
catch (...)
{
log::critical(link_cat, "Error: RelayDownstreamMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
void
Clear() override
clear() override
{
version = 0;
}
const char*
Name() const override
name() const override
{
return "Discard";
}
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override
{
if (key.startswith("a"))
{
@ -52,7 +57,7 @@ namespace llarp
}
bool
HandleMessage(AbstractRouter* /*router*/) const override
handle_message(AbstractRouter* /*router*/) const override
{
return true;
}
@ -60,7 +65,7 @@ namespace llarp
namespace routing
{
struct DataDiscardMessage final : public IMessage
struct DataDiscardMessage final : public AbstractRoutingMessage
{
PathID_t P;
@ -73,19 +78,19 @@ namespace llarp
}
void
Clear() override
clear() override
{
version = 0;
}
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override
handle_message(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override
{
return h->HandleDataDiscardMessage(*this, r);
}
bool
DecodeKey(const llarp_buffer_t& k, llarp_buffer_t* buf) override
decode_key(const llarp_buffer_t& k, llarp_buffer_t* buf) override
{
bool read = false;
if (!BEncodeMaybeReadDictEntry("P", P, read, k, buf))
@ -97,22 +102,24 @@ namespace llarp
return read;
}
bool
BEncode(llarp_buffer_t* buf) const override
std::string
bt_encode() const override
{
if (!bencode_start_dict(buf))
return false;
if (!BEncodeWriteDictMsgType(buf, "A", "D"))
return false;
if (!BEncodeWriteDictEntry("P", P, buf))
return false;
if (!BEncodeWriteDictInt("S", S, buf))
return false;
if (!BEncodeWriteDictInt("V", version, buf))
return false;
return bencode_end(buf);
oxenc::bt_dict_producer btdp;
try
{
btdp.append("A", "D");
btdp.append("P", P.ToView());
btdp.append("S", S);
btdp.append("V", version);
}
catch (...)
{
log::critical(route_cat, "Error: DataDiscardMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
};
} // namespace routing

@ -6,10 +6,12 @@
#include <llarp/util/bencode.h>
#include <llarp/util/logging.hpp>
#include <oxenc/bt_producer.h>
namespace llarp
{
bool
LinkIntroMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
LinkIntroMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
if (key.startswith("a"))
{
@ -22,14 +24,14 @@ namespace llarp
}
if (key.startswith("n"))
{
if (N.BDecode(buf))
if (nonce.BDecode(buf))
return true;
llarp::LogWarn("failed to decode nonce in LIM");
return false;
}
if (key.startswith("p"))
{
return bencode_read_integer(buf, &P);
return bencode_read_integer(buf, &session_period);
}
if (key.startswith("r"))
{
@ -54,103 +56,104 @@ namespace llarp
}
if (key.startswith("z"))
{
return Z.BDecode(buf);
return sig.BDecode(buf);
}
llarp::LogWarn("invalid LIM key: ", *key.cur);
return false;
}
bool
LinkIntroMessage::BEncode(llarp_buffer_t* buf) const
std::string
LinkIntroMessage::bt_encode() const
{
if (!bencode_start_dict(buf))
return false;
if (!bencode_write_bytestring(buf, "a", 1))
return false;
if (!bencode_write_bytestring(buf, "i", 1))
return false;
if (!bencode_write_bytestring(buf, "n", 1))
return false;
if (!N.BEncode(buf))
return false;
if (!bencode_write_bytestring(buf, "p", 1))
return false;
if (!bencode_write_uint64(buf, P))
return false;
oxenc::bt_dict_producer btdp;
if (!bencode_write_bytestring(buf, "r", 1))
return false;
if (!rc.BEncode(buf))
return false;
try
{
btdp.append("a", "i");
btdp.append("n", nonce.ToView());
btdp.append("p", session_period);
if (!bencode_write_uint64_entry(buf, "v", 1, llarp::constants::proto_version))
return false;
{
auto subdict = btdp.append_list("r");
rc.bt_encode_subdict(subdict);
}
if (!bencode_write_bytestring(buf, "z", 1))
return false;
if (!Z.BEncode(buf))
return false;
btdp.append("v", llarp::constants::proto_version);
btdp.append("z", sig.ToView());
}
catch (...)
{
log::critical(link_cat, "Error: LinkIntroMessage failed to bt encode contents!");
}
return bencode_end(buf);
return std::move(btdp).str();
}
bool
LinkIntroMessage::HandleMessage(AbstractRouter* /*router*/) const
LinkIntroMessage::handle_message(AbstractRouter* /*router*/) const
{
if (!Verify())
if (!verify())
return false;
return session->GotLIM(this);
}
void
LinkIntroMessage::Clear()
LinkIntroMessage::clear()
{
P = 0;
N.Zero();
session_period = 0;
nonce.Zero();
rc.Clear();
Z.Zero();
sig.Zero();
version = 0;
}
bool
LinkIntroMessage::Sign(std::function<bool(Signature&, const llarp_buffer_t&)> signer)
LinkIntroMessage::sign(std::function<bool(Signature&, const llarp_buffer_t&)> signer)
{
Z.Zero();
std::array<byte_t, MaxSize> tmp;
sig.Zero();
// need to keep this as a llarp_buffer_t for now, as all the crypto code expects
// byte_t types -- fix this later
std::array<byte_t, MAX_MSG_SIZE> tmp;
llarp_buffer_t buf(tmp);
if (!BEncode(&buf))
return false;
auto bte = bt_encode();
buf.write(bte.begin(), bte.end());
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return signer(Z, buf);
return signer(sig, buf);
}
bool
LinkIntroMessage::Verify() const
LinkIntroMessage::verify() const
{
LinkIntroMessage copy;
copy = *this;
copy.Z.Zero();
std::array<byte_t, MaxSize> tmp;
copy.sig.Zero();
// need to keep this as a llarp_buffer_t for now, as all the crypto code expects
// byte_t types -- fix this later
std::array<byte_t, MAX_MSG_SIZE> tmp;
llarp_buffer_t buf(tmp);
if (!copy.BEncode(&buf))
return false;
auto bte = copy.bt_encode();
buf.write(bte.begin(), bte.end());
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// outer signature
if (!CryptoManager::instance()->verify(rc.pubkey, buf, Z))
if (!CryptoManager::instance()->verify(rc.pubkey, buf, sig))
{
llarp::LogError("outer signature failure");
log::error(link_cat, "Error: outer signature failed!");
return false;
}
// verify RC
if (!rc.Verify(llarp::time_now_ms()))
{
llarp::LogError("invalid RC in link intro");
log::error(link_cat, "Error: invalid RC in link intro!");
return false;
}
return true;

@ -6,47 +6,47 @@
namespace llarp
{
struct ILinkSession;
struct AbstractLinkSession;
struct LinkIntroMessage : public ILinkMessage
struct LinkIntroMessage final : public AbstractLinkMessage
{
static constexpr size_t MaxSize = MAX_RC_SIZE + 256;
static constexpr size_t MAX_MSG_SIZE = MAX_RC_SIZE + 256;
LinkIntroMessage() : ILinkMessage()
LinkIntroMessage() : AbstractLinkMessage()
{}
RouterContact rc;
KeyExchangeNonce N;
Signature Z;
uint64_t P;
KeyExchangeNonce nonce;
Signature sig;
uint64_t session_period;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
std::string
bt_encode() const override;
bool
BEncode(llarp_buffer_t* buf) const override;
handle_message(AbstractRouter* router) const override;
bool
HandleMessage(AbstractRouter* router) const override;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
Sign(std::function<bool(Signature&, const llarp_buffer_t&)> signer);
sign(std::function<bool(Signature&, const llarp_buffer_t&)> signer);
bool
Verify() const;
verify() const;
void
Clear() override;
clear() override;
const char*
Name() const override
name() const override
{
return "LinkIntro";
}
// always first
uint16_t
Priority() const override
priority() const override
{
return std::numeric_limits<uint16_t>::max();
}

@ -1,5 +1,7 @@
#pragma once
#include "common.hpp"
#include <llarp/link/session.hpp>
#include <llarp/router_id.hpp>
#include <llarp/util/bencode.hpp>
@ -7,60 +9,70 @@
#include <vector>
namespace
{
static auto link_cat = llarp::log::Cat("lokinet.link");
} // namespace
namespace llarp
{
struct ILinkSession;
struct AbstractLinkSession;
struct AbstractRouter;
/// parsed link layer message
struct ILinkMessage
struct AbstractLinkMessage : private AbstractSerializable
{
/// who did this message come from or is going to
ILinkSession* session = nullptr;
AbstractLinkSession* session = nullptr;
uint64_t version = llarp::constants::proto_version;
PathID_t pathid;
ILinkMessage() = default;
AbstractLinkMessage() = default;
virtual ~ILinkMessage() = default;
virtual ~AbstractLinkMessage() = default;
virtual bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) = 0;
bool
BDecode(llarp_buffer_t* buf)
{
// default version if not specified is 0
uint64_t v = 0;
// seek for version and set it if we got it
if (BEncodeSeekDictVersion(v, buf, 'v'))
{
version = v;
}
// when we hit the code path version is set and we can tell how to decode
return bencode_decode_dict(*this, buf);
}
std::string
bt_encode() const override = 0;
virtual bool
BEncode(llarp_buffer_t* buf) const = 0;
handle_message(AbstractRouter* router) const = 0;
virtual bool
HandleMessage(AbstractRouter* router) const = 0;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) = 0;
virtual void
Clear() = 0;
clear() = 0;
// the name of this kind of message
virtual const char*
Name() const = 0;
name() const = 0;
/// get message prority, higher value means more important
virtual uint16_t
Priority() const
priority() const
{
return 1;
}
// methods we do not want to inherit onwards from AbstractSerializable
void
bt_encode(llarp_buffer&) const final
{
throw std::runtime_error{"Error: Link messages should not encode directly to a buffer!"};
}
void
bt_encode(oxenc::bt_dict_producer&) const final
{
throw std::runtime_error{
"Error: Link messages should not encode directly to a bt list producer!"};
}
void
bt_encode(oxenc::bt_list_producer&) const final
{
throw std::runtime_error{
"Error: Link messages should not encode directly to a bt list producer!"};
}
};
} // namespace llarp

@ -99,7 +99,7 @@ namespace llarp
if (!key)
return MessageDone();
return msg->DecodeKey(*key, buffer);
return msg->decode_key(*key, buffer);
}
bool
@ -108,14 +108,14 @@ namespace llarp
bool result = false;
if (msg)
{
result = msg->HandleMessage(router);
result = msg->handle_message(router);
}
Reset();
return result;
}
bool
LinkMessageParser::ProcessFrom(ILinkSession* src, const llarp_buffer_t& buf)
LinkMessageParser::ProcessFrom(AbstractLinkSession* src, const llarp_buffer_t& buf)
{
if (!src)
{
@ -133,7 +133,7 @@ namespace llarp
LinkMessageParser::Reset()
{
if (msg)
msg->Clear();
msg->clear();
msg = nullptr;
}
} // namespace llarp

@ -8,8 +8,8 @@
namespace llarp
{
struct AbstractRouter;
struct ILinkMessage;
struct ILinkSession;
struct AbstractLinkMessage;
struct AbstractLinkSession;
struct LinkMessageParser
{
@ -21,7 +21,7 @@ namespace llarp
/// start processig message from a link session
bool
ProcessFrom(ILinkSession* from, const llarp_buffer_t& buf);
ProcessFrom(AbstractLinkSession* from, const llarp_buffer_t& buf);
/// called when the message is fully read
/// return true when the message was accepted otherwise returns false
@ -39,8 +39,8 @@ namespace llarp
private:
bool firstkey;
AbstractRouter* router;
ILinkSession* from;
ILinkMessage* msg;
AbstractLinkSession* from;
AbstractLinkMessage* msg;
struct msg_holder_t;

@ -7,109 +7,113 @@
namespace llarp
{
void
RelayUpstreamMessage::Clear()
RelayUpstreamMessage::clear()
{
pathid.Zero();
X.Clear();
Y.Zero();
enc.Clear();
nonce.Zero();
version = 0;
}
bool
RelayUpstreamMessage::BEncode(llarp_buffer_t* buf) const
std::string
RelayUpstreamMessage::bt_encode() const
{
if (!bencode_start_dict(buf))
return false;
if (!BEncodeWriteDictMsgType(buf, "a", "u"))
return false;
oxenc::bt_dict_producer btdp;
if (!BEncodeWriteDictEntry("p", pathid, buf))
return false;
if (!BEncodeWriteDictInt("v", llarp::constants::proto_version, buf))
return false;
if (!BEncodeWriteDictEntry("x", X, buf))
return false;
if (!BEncodeWriteDictEntry("y", Y, buf))
return false;
return bencode_end(buf);
try
{
btdp.append("a", "u");
btdp.append("p", pathid.ToView());
btdp.append("v", llarp::constants::proto_version);
btdp.append("x", std::string_view{reinterpret_cast<const char*>(enc.data()), enc.size()});
btdp.append("y", std::string_view{reinterpret_cast<const char*>(nonce.data()), nonce.size()});
}
catch (...)
{
log::critical(link_cat, "Error: RelayUpstreamMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
RelayUpstreamMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
RelayUpstreamMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictEntry("p", pathid, read, key, buf))
return false;
if (!BEncodeMaybeVerifyVersion("v", version, llarp::constants::proto_version, read, key, buf))
return false;
if (!BEncodeMaybeReadDictEntry("x", X, read, key, buf))
if (!BEncodeMaybeReadDictEntry("x", enc, read, key, buf))
return false;
if (!BEncodeMaybeReadDictEntry("y", Y, read, key, buf))
if (!BEncodeMaybeReadDictEntry("y", nonce, read, key, buf))
return false;
return read;
}
bool
RelayUpstreamMessage::HandleMessage(AbstractRouter* r) const
RelayUpstreamMessage::handle_message(AbstractRouter* r) const
{
auto path = r->pathContext().GetByDownstream(session->GetPubKey(), pathid);
if (path)
{
return path->HandleUpstream(llarp_buffer_t(X), Y, r);
return path->HandleUpstream(llarp_buffer_t(enc), nonce, r);
}
return false;
}
void
RelayDownstreamMessage::Clear()
RelayDownstreamMessage::clear()
{
pathid.Zero();
X.Clear();
Y.Zero();
enc.Clear();
nonce.Zero();
version = 0;
}
bool
RelayDownstreamMessage::BEncode(llarp_buffer_t* buf) const
std::string
RelayDownstreamMessage::bt_encode() const
{
if (!bencode_start_dict(buf))
return false;
if (!BEncodeWriteDictMsgType(buf, "a", "d"))
return false;
oxenc::bt_dict_producer btdp;
if (!BEncodeWriteDictEntry("p", pathid, buf))
return false;
if (!BEncodeWriteDictInt("v", llarp::constants::proto_version, buf))
return false;
if (!BEncodeWriteDictEntry("x", X, buf))
return false;
if (!BEncodeWriteDictEntry("y", Y, buf))
return false;
return bencode_end(buf);
try
{
btdp.append("a", "d");
btdp.append("p", pathid.ToView());
btdp.append("v", llarp::constants::proto_version);
btdp.append("x", std::string_view{reinterpret_cast<const char*>(enc.data()), enc.size()});
btdp.append("y", std::string_view{reinterpret_cast<const char*>(nonce.data()), nonce.size()});
}
catch (...)
{
log::critical(link_cat, "Error: RelayDownstreamMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
RelayDownstreamMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
RelayDownstreamMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictEntry("p", pathid, read, key, buf))
return false;
if (!BEncodeMaybeVerifyVersion("v", version, llarp::constants::proto_version, read, key, buf))
return false;
if (!BEncodeMaybeReadDictEntry("x", X, read, key, buf))
if (!BEncodeMaybeReadDictEntry("x", enc, read, key, buf))
return false;
if (!BEncodeMaybeReadDictEntry("y", Y, read, key, buf))
if (!BEncodeMaybeReadDictEntry("y", nonce, read, key, buf))
return false;
return read;
}
bool
RelayDownstreamMessage::HandleMessage(AbstractRouter* r) const
RelayDownstreamMessage::handle_message(AbstractRouter* r) const
{
auto path = r->pathContext().GetByUpstream(session->GetPubKey(), pathid);
if (path)
{
return path->HandleDownstream(llarp_buffer_t(X), Y, r);
return path->HandleDownstream(llarp_buffer_t(enc), nonce, r);
}
llarp::LogWarn("no path for downstream message id=", pathid);
return false;

@ -9,60 +9,60 @@
namespace llarp
{
struct RelayUpstreamMessage : public ILinkMessage
struct RelayUpstreamMessage final : public AbstractLinkMessage
{
Encrypted<MAX_LINK_MSG_SIZE - 128> X;
TunnelNonce Y;
Encrypted<MAX_LINK_MSG_SIZE - 128> enc;
TunnelNonce nonce;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
BEncode(llarp_buffer_t* buf) const override;
std::string
bt_encode() const override;
bool
HandleMessage(AbstractRouter* router) const override;
handle_message(AbstractRouter* router) const override;
void
Clear() override;
const char*
clear() override;
Name() const override
const char*
name() const override
{
return "RelayUpstream";
}
uint16_t
Priority() const override
priority() const override
{
return 0;
}
};
struct RelayDownstreamMessage : public ILinkMessage
struct RelayDownstreamMessage final : public AbstractLinkMessage
{
Encrypted<MAX_LINK_MSG_SIZE - 128> X;
TunnelNonce Y;
Encrypted<MAX_LINK_MSG_SIZE - 128> enc;
TunnelNonce nonce;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
BEncode(llarp_buffer_t* buf) const override;
std::string
bt_encode() const override;
bool
HandleMessage(AbstractRouter* router) const override;
handle_message(AbstractRouter* router) const override;
void
Clear() override;
clear() override;
const char*
Name() const override
name() const override
{
return "RelayDownstream";
}
uint16_t
Priority() const override
priority() const override
{
return 0;
}

@ -20,7 +20,7 @@
namespace llarp
{
bool
LR_CommitMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
LR_CommitMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
if (key.startswith("c"))
{
@ -36,32 +36,39 @@ namespace llarp
}
void
LR_CommitMessage::Clear()
LR_CommitMessage::clear()
{
std::for_each(frames.begin(), frames.end(), [](auto& f) { f.Clear(); });
version = 0;
}
bool
LR_CommitMessage::BEncode(llarp_buffer_t* buf) const
std::string
LR_CommitMessage::bt_encode() const
{
if (!bencode_start_dict(buf))
return false;
// msg type
if (!BEncodeWriteDictMsgType(buf, "a", "c"))
return false;
// frames
if (!BEncodeWriteDictArray("c", frames, buf))
return false;
// version
if (!bencode_write_uint64_entry(buf, "v", 1, llarp::constants::proto_version))
return false;
oxenc::bt_dict_producer btdp;
return bencode_end(buf);
try
{
btdp.append("a", "c");
{
auto sublist = btdp.append_list("c");
for (auto& f : frames)
sublist.append({reinterpret_cast<const char*>(f.data()), f.size()});
}
btdp.append("v", llarp::constants::proto_version);
}
catch (...)
{
log::critical(link_cat, "Error: LR_CommitMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
LR_CommitMessage::HandleMessage(AbstractRouter* router) const
LR_CommitMessage::handle_message(AbstractRouter* router) const
{
if (frames.size() != path::max_len)
{

@ -45,12 +45,12 @@ namespace llarp
OnKey(llarp_buffer_t* buffer, llarp_buffer_t* key);
};
struct LR_CommitMessage : public ILinkMessage
struct LR_CommitMessage final : public AbstractLinkMessage
{
std::array<EncryptedFrame, 8> frames;
LR_CommitMessage(std::array<EncryptedFrame, 8> _frames)
: ILinkMessage(), frames(std::move(_frames))
: AbstractLinkMessage(), frames(std::move(_frames))
{}
LR_CommitMessage() = default;
@ -58,28 +58,28 @@ namespace llarp
~LR_CommitMessage() override = default;
void
Clear() override;
clear() override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
BEncode(llarp_buffer_t* buf) const override;
std::string
bt_encode() const override;
bool
HandleMessage(AbstractRouter* router) const override;
handle_message(AbstractRouter* router) const override;
bool
AsyncDecrypt(llarp::path::PathContext* context) const;
const char*
Name() const override
name() const override
{
return "RelayCommit";
}
virtual uint16_t
Priority() const override
uint16_t
priority() const override
{
return 5;
}

@ -57,7 +57,7 @@ namespace llarp
};
bool
LR_StatusMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
LR_StatusMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
bool read = false;
if (key.startswith("c"))
@ -90,39 +90,43 @@ namespace llarp
}
void
LR_StatusMessage::Clear()
LR_StatusMessage::clear()
{
std::for_each(frames.begin(), frames.end(), [](auto& f) { f.Clear(); });
version = 0;
status = 0;
}
bool
LR_StatusMessage::BEncode(llarp_buffer_t* buf) const
std::string
LR_StatusMessage::bt_encode() const
{
if (!bencode_start_dict(buf))
return false;
// msg type
if (!BEncodeWriteDictMsgType(buf, "a", "s"))
return false;
// frames
if (!BEncodeWriteDictArray("c", frames, buf))
return false;
// path id
if (!BEncodeWriteDictEntry("p", pathid, buf))
return false;
// status (for now, only success bit is relevant)
if (!BEncodeWriteDictInt("s", status, buf))
return false;
// version
if (!bencode_write_uint64_entry(buf, "v", 1, llarp::constants::proto_version))
return false;
oxenc::bt_dict_producer btdp;
try
{
btdp.append("a", "s");
{
auto sublist = btdp.append_list("c");
for (auto& f : frames)
sublist.append({reinterpret_cast<const char*>(f.data()), f.size()});
}
btdp.append("p", pathid.ToView());
btdp.append("s", status);
btdp.append("v", llarp::constants::proto_version);
}
catch (...)
{
log::critical(link_cat, "Error: LR_StatusMessage failed to bt encode contents!");
}
return bencode_end(buf);
return std::move(btdp).str();
}
bool
LR_StatusMessage::HandleMessage(AbstractRouter* router) const
LR_StatusMessage::handle_message(AbstractRouter* router) const
{
llarp::LogDebug("Received LR_Status message from (", session->GetPubKey(), ")");
if (frames.size() != path::max_len)
@ -198,14 +202,14 @@ namespace llarp
if (!record.BEncode(&buf))
{
// failed to encode?
LogError(Name(), " Failed to generate Status Record");
LogError(name(), " Failed to generate Status Record");
DumpBuffer(buf);
return false;
}
// use ephemeral keypair for frame
if (!frame.DoEncrypt(pathKey, true))
{
LogError(Name(), " Failed to encrypt LRSR");
LogError(name(), " Failed to encrypt LRSR");
DumpBuffer(buf);
return false;
}

@ -53,7 +53,7 @@ namespace llarp
std::string
LRStatusCodeToString(uint64_t status);
struct LR_StatusMessage : public ILinkMessage
struct LR_StatusMessage final : public AbstractLinkMessage
{
std::array<EncryptedFrame, 8> frames;
@ -62,7 +62,7 @@ namespace llarp
uint64_t status = 0;
LR_StatusMessage(std::array<EncryptedFrame, 8> _frames)
: ILinkMessage(), frames(std::move(_frames))
: AbstractLinkMessage(), frames(std::move(_frames))
{}
LR_StatusMessage() = default;
@ -70,16 +70,16 @@ namespace llarp
~LR_StatusMessage() override = default;
void
Clear() override;
clear() override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) override;
bool
BEncode(llarp_buffer_t* buf) const override;
std::string
bt_encode() const override;
bool
HandleMessage(AbstractRouter* router) const override;
handle_message(AbstractRouter* router) const override;
void
SetDummyFrames();
@ -111,12 +111,12 @@ namespace llarp
std::shared_ptr<path::TransitHop> hop);
const char*
Name() const override
name() const override
{
return "RelayStatus";
}
virtual uint16_t
Priority() const override
uint16_t
priority() const override
{
return 6;
}

@ -24,7 +24,7 @@ namespace llarp
/// Empty constructor.
IpAddress() = default;
/// move construtor
IpAddress(IpAddress &&) = default;
IpAddress(IpAddress&&) = default;
/// copy construct
IpAddress(const IpAddress&);
@ -54,64 +54,80 @@ namespace llarp
/// @param addr is an SockAddr to initialize from.
IpAddress(const SockAddr& addr);
IpAddress& operator=(const sockaddr& other);
IpAddress&
operator=(const sockaddr& other);
/// move assignment
IpAddress& operator=(IpAddress&& other);
IpAddress&
operator=(IpAddress&& other);
/// copy assignment
IpAddress& operator=(const IpAddress& other);
IpAddress&
operator=(const IpAddress& other);
/// Return the port. Returns -1 if no port has been provided.
///
/// @return the port, if present
std::optional<uint16_t> getPort() const;
std::optional<uint16_t>
getPort() const;
/// Return true if we have a port set otherwise return false
bool hasPort() const;
bool
hasPort() const;
/// Set the port.
///
/// @param port
void setPort(std::optional<uint16_t> port);
void
setPort(std::optional<uint16_t> port);
/// Set the IP address. Follows the same logic as the constructor with the same signature, but
/// doesn't overwrite the port if the port isn't present in the string.
void setAddress(std::string_view str);
void setAddress(std::string_view str, std::optional<uint16_t> port);
void
setAddress(std::string_view str);
void
setAddress(std::string_view str, std::optional<uint16_t> port);
/// Returns true if this is an IPv4 address (or an IPv6 address representing an IPv4 address)
///
/// TODO: could return an int (e.g. 4 or 6) or an enum
///
/// @return true if this is an IPv4 address, false otherwise
bool isIPv4();
bool
isIPv4();
/// Returns true if this represents a valid IpAddress, false otherwise.
///
/// @return whether or not this IpAddress is empty
bool isEmpty() const;
bool
isEmpty() const;
/// Creates an instance of SockAddr representing this IpAddress.
///
/// @return an instance of a SockAddr created from this IpAddress
SockAddr createSockAddr() const;
SockAddr
createSockAddr() const;
/// Returns true if this IpAddress is a bogon, false otherwise
///
/// @return whether or not this IpAddress is a bogon
bool isBogon() const;
bool
isBogon() const;
/// Returns a string representing this IpAddress
///
/// @return string representation of this IpAddress
std::string ToString() const;
std::string
ToString() const;
std::string toHost() const;
std::string
toHost() const;
huint32_t toIP() const;
huint32_t
toIP() const;
huint128_t toIP6() const;
huint128_t
toIP6() const;
// TODO: other utility functions left over from Addr which may be useful
// IsBogon() const;
@ -119,9 +135,11 @@ namespace llarp
// std::hash
// to string / stream / etc
bool operator<(const IpAddress& other) const;
bool
operator<(const IpAddress& other) const;
bool operator==(const IpAddress& other) const;
bool
operator==(const IpAddress& other) const;
private:
bool m_empty = true;

@ -257,24 +257,26 @@ namespace llarp
inline constexpr bool IsToStringFormattable<net::port_t> = true;
using nuint16_t /* [[deprecated("use llarp::net::port_t instead")]] */ = llarp::net::port_t;
using nuint32_t /* [[deprecated("use llarp::net::ipv4addr_t instead")]] */ = llarp::net::ipv4addr_t;
using nuint128_t /* [[deprecated("use llarp::net::ipv6addr_t instead")]] */ = llarp::net::ipv6addr_t;
using nuint32_t /* [[deprecated("use llarp::net::ipv4addr_t instead")]] */ =
llarp::net::ipv4addr_t;
using nuint128_t /* [[deprecated("use llarp::net::ipv6addr_t instead")]] */ =
llarp::net::ipv6addr_t;
template <typename UInt_t>
/* [[deprecated("use llarp::net::ToNet instead")]] */ inline llarp::nuint_t<UInt_t>
/* [[deprecated("use llarp::net::ToNet instead")]] */ inline llarp::nuint_t<UInt_t>
ToNet(llarp::huint_t<UInt_t> x)
{
return llarp::net::ToNet(x);
}
template <typename UInt_t>
/* [[deprecated("use llarp::net::ToHost instead")]] */ inline llarp::huint_t<UInt_t>
/* [[deprecated("use llarp::net::ToHost instead")]] */ inline llarp::huint_t<UInt_t>
ToHost(llarp::nuint_t<UInt_t> x)
{
return llarp::net::ToHost(x);
}
/* [[deprecated("use llarp::net::ToHost instead")]] */ inline net::ipv4addr_t
/* [[deprecated("use llarp::net::ToHost instead")]] */ inline net::ipv4addr_t
xhtonl(huint32_t x)
{
return ToNet(x);

@ -17,7 +17,7 @@ namespace llarp
namespace routing
{
struct IMessage;
struct AbstractRoutingMessage;
}
namespace path
@ -43,7 +43,7 @@ namespace llarp
/// send routing message and increment sequence number
virtual bool
SendRoutingMessage(const routing::IMessage& msg, AbstractRouter* r) = 0;
SendRoutingMessage(const routing::AbstractRoutingMessage& msg, AbstractRouter* r) = 0;
// handle data in upstream direction
virtual bool

File diff suppressed because it is too large Load Diff

@ -70,7 +70,7 @@ namespace llarp
/// A path we made
struct Path final : public IHopHandler,
public routing::IMessageHandler,
public routing::AbstractRoutingMessageHandler,
public std::enable_shared_from_this<Path>
{
using BuildResultHookFunc = std::function<void(Path_ptr)>;
@ -291,7 +291,7 @@ namespace llarp
Tick(llarp_time_t now, AbstractRouter* r);
bool
SendRoutingMessage(const routing::IMessage& msg, AbstractRouter* r) override;
SendRoutingMessage(const routing::AbstractRoutingMessage& msg, AbstractRouter* r) override;
bool
HandleObtainExitMessage(const routing::ObtainExitMessage& msg, AbstractRouter* r) override;
@ -337,7 +337,7 @@ namespace llarp
HandleGotIntroMessage(const dht::GotIntroMessage& msg);
bool
HandleDHTMessage(const dht::IMessage& msg, AbstractRouter* r) override;
HandleDHTMessage(const dht::AbstractDHTMessage& msg, AbstractRouter* r) override;
bool
HandleRoutingMessage(const llarp_buffer_t& buf, AbstractRouter* r);

@ -238,7 +238,7 @@ namespace llarp
{
std::optional<RouterContact> found = std::nullopt;
m_router->ForEachPeer(
[&](const ILinkSession* s, bool isOutbound) {
[&](const AbstractLinkSession* s, bool isOutbound) {
if (s && s->IsEstablished() && isOutbound && not found.has_value())
{
const RouterContact rc = s->GetRemoteRC();

@ -230,7 +230,7 @@ namespace llarp
return false;
}
virtual routing::IMessageHandler*
virtual routing::AbstractRoutingMessageHandler*
GetDHTHandler()
{
return nullptr;

@ -17,444 +17,434 @@
#include <oxenc/endian.h>
namespace llarp
namespace llarp::path
{
namespace path
std::string
TransitHopInfo::ToString() const
{
std::string
TransitHopInfo::ToString() const
{
return fmt::format(
"[TransitHopInfo tx={} rx={} upstream={} downstream={}]",
txID,
rxID,
upstream,
downstream);
}
TransitHop::TransitHop()
: IHopHandler{}
, m_UpstreamGather{transit_hop_queue_size}
, m_DownstreamGather{transit_hop_queue_size}
{
m_UpstreamGather.enable();
m_DownstreamGather.enable();
m_UpstreamWorkCounter = 0;
m_DownstreamWorkCounter = 0;
}
return fmt::format(
"[TransitHopInfo tx={} rx={} upstream={} downstream={}]", txID, rxID, upstream, downstream);
}
TransitHop::TransitHop()
: IHopHandler{}
, m_UpstreamGather{transit_hop_queue_size}
, m_DownstreamGather{transit_hop_queue_size}
{
m_UpstreamGather.enable();
m_DownstreamGather.enable();
m_UpstreamWorkCounter = 0;
m_DownstreamWorkCounter = 0;
}
bool
TransitHop::Expired(llarp_time_t now) const
{
return destroy || (now >= ExpireTime());
}
bool
TransitHop::Expired(llarp_time_t now) const
{
return destroy || (now >= ExpireTime());
}
llarp_time_t
TransitHop::ExpireTime() const
{
return started + lifetime;
}
llarp_time_t
TransitHop::ExpireTime() const
{
return started + lifetime;
}
bool
TransitHop::HandleLRSM(uint64_t status, std::array<EncryptedFrame, 8>& frames, AbstractRouter* r)
{
auto msg = std::make_shared<LR_StatusMessage>(frames);
msg->status = status;
msg->pathid = info.rxID;
bool
TransitHop::HandleLRSM(
uint64_t status, std::array<EncryptedFrame, 8>& frames, AbstractRouter* r)
{
auto msg = std::make_shared<LR_StatusMessage>(frames);
msg->status = status;
msg->pathid = info.rxID;
// TODO: add to IHopHandler some notion of "path status"
// TODO: add to IHopHandler some notion of "path status"
const uint64_t ourStatus = LR_StatusRecord::SUCCESS;
const uint64_t ourStatus = LR_StatusRecord::SUCCESS;
msg->AddFrame(pathKey, ourStatus);
LR_StatusMessage::QueueSendMessage(r, info.downstream, msg, shared_from_this());
return true;
}
msg->AddFrame(pathKey, ourStatus);
LR_StatusMessage::QueueSendMessage(r, info.downstream, msg, shared_from_this());
return true;
}
TransitHopInfo::TransitHopInfo(const RouterID& down, const LR_CommitRecord& record)
: txID(record.txid), rxID(record.rxid), upstream(record.nextHop), downstream(down)
{}
TransitHopInfo::TransitHopInfo(const RouterID& down, const LR_CommitRecord& record)
: txID(record.txid), rxID(record.rxid), upstream(record.nextHop), downstream(down)
{}
bool
TransitHop::SendRoutingMessage(const routing::AbstractRoutingMessage& msg, AbstractRouter* r)
{
if (!IsEndpoint(r->pubkey()))
return false;
bool
TransitHop::SendRoutingMessage(const routing::IMessage& msg, AbstractRouter* r)
std::array<byte_t, MAX_LINK_MSG_SIZE - 128> tmp;
llarp_buffer_t buf(tmp);
if (!msg.BEncode(&buf))
{
if (!IsEndpoint(r->pubkey()))
return false;
llarp::LogError("failed to encode routing message");
return false;
}
TunnelNonce N;
N.Randomize();
buf.sz = buf.cur - buf.base;
// pad to nearest MESSAGE_PAD_SIZE bytes
auto dlt = buf.sz % pad_size;
if (dlt)
{
dlt = pad_size - dlt;
// randomize padding
CryptoManager::instance()->randbytes(buf.cur, dlt);
buf.sz += dlt;
}
buf.cur = buf.base;
return HandleDownstream(buf, N, r);
}
std::array<byte_t, MAX_LINK_MSG_SIZE - 128> tmp;
llarp_buffer_t buf(tmp);
if (!msg.BEncode(&buf))
void
TransitHop::DownstreamWork(TrafficQueue_t msgs, AbstractRouter* r)
{
auto flushIt = [self = shared_from_this(), r]() {
std::vector<RelayDownstreamMessage> msgs;
while (auto maybe = self->m_DownstreamGather.tryPopFront())
{
llarp::LogError("failed to encode routing message");
return false;
msgs.push_back(*maybe);
}
TunnelNonce N;
N.Randomize();
buf.sz = buf.cur - buf.base;
// pad to nearest MESSAGE_PAD_SIZE bytes
auto dlt = buf.sz % pad_size;
if (dlt)
self->HandleAllDownstream(std::move(msgs), r);
};
for (auto& ev : msgs)
{
RelayDownstreamMessage msg;
const llarp_buffer_t buf(ev.first);
msg.pathid = info.rxID;
msg.nonce = ev.second ^ nonceXOR;
CryptoManager::instance()->xchacha20(buf, pathKey, ev.second);
msg.enc = buf;
llarp::LogDebug(
"relay ",
msg.enc.size(),
" bytes downstream from ",
info.upstream,
" to ",
info.downstream);
if (m_DownstreamGather.full())
{
dlt = pad_size - dlt;
// randomize padding
CryptoManager::instance()->randbytes(buf.cur, dlt);
buf.sz += dlt;
r->loop()->call(flushIt);
}
buf.cur = buf.base;
return HandleDownstream(buf, N, r);
if (m_DownstreamGather.enabled())
m_DownstreamGather.pushBack(msg);
}
r->loop()->call(flushIt);
}
void
TransitHop::DownstreamWork(TrafficQueue_t msgs, AbstractRouter* r)
void
TransitHop::UpstreamWork(TrafficQueue_t msgs, AbstractRouter* r)
{
for (auto& ev : msgs)
{
auto flushIt = [self = shared_from_this(), r]() {
std::vector<RelayDownstreamMessage> msgs;
while (auto maybe = self->m_DownstreamGather.tryPopFront())
{
msgs.push_back(*maybe);
}
self->HandleAllDownstream(std::move(msgs), r);
};
for (auto& ev : msgs)
{
RelayDownstreamMessage msg;
const llarp_buffer_t buf(ev.first);
msg.pathid = info.rxID;
msg.Y = ev.second ^ nonceXOR;
CryptoManager::instance()->xchacha20(buf, pathKey, ev.second);
msg.X = buf;
llarp::LogDebug(
"relay ",
msg.X.size(),
" bytes downstream from ",
info.upstream,
" to ",
info.downstream);
if (m_DownstreamGather.full())
{
r->loop()->call(flushIt);
}
if (m_DownstreamGather.enabled())
m_DownstreamGather.pushBack(msg);
}
r->loop()->call(flushIt);
const llarp_buffer_t buf(ev.first);
RelayUpstreamMessage msg;
CryptoManager::instance()->xchacha20(buf, pathKey, ev.second);
msg.pathid = info.txID;
msg.nonce = ev.second ^ nonceXOR;
msg.enc = buf;
if (m_UpstreamGather.tryPushBack(msg) != thread::QueueReturn::Success)
break;
}
void
TransitHop::UpstreamWork(TrafficQueue_t msgs, AbstractRouter* r)
{
for (auto& ev : msgs)
// Flush it:
r->loop()->call([self = shared_from_this(), r] {
std::vector<RelayUpstreamMessage> msgs;
while (auto maybe = self->m_UpstreamGather.tryPopFront())
{
const llarp_buffer_t buf(ev.first);
RelayUpstreamMessage msg;
CryptoManager::instance()->xchacha20(buf, pathKey, ev.second);
msg.pathid = info.txID;
msg.Y = ev.second ^ nonceXOR;
msg.X = buf;
if (m_UpstreamGather.tryPushBack(msg) != thread::QueueReturn::Success)
break;
msgs.push_back(*maybe);
}
self->HandleAllUpstream(std::move(msgs), r);
});
}
// Flush it:
r->loop()->call([self = shared_from_this(), r] {
std::vector<RelayUpstreamMessage> msgs;
while (auto maybe = self->m_UpstreamGather.tryPopFront())
{
msgs.push_back(*maybe);
}
self->HandleAllUpstream(std::move(msgs), r);
});
}
void
TransitHop::HandleAllUpstream(std::vector<RelayUpstreamMessage> msgs, AbstractRouter* r)
void
TransitHop::HandleAllUpstream(std::vector<RelayUpstreamMessage> msgs, AbstractRouter* r)
{
if (IsEndpoint(r->pubkey()))
{
if (IsEndpoint(r->pubkey()))
for (const auto& msg : msgs)
{
for (const auto& msg : msgs)
{
const llarp_buffer_t buf(msg.X);
if (!r->ParseRoutingMessageBuffer(buf, this, info.rxID))
{
LogWarn("invalid upstream data on endpoint ", info);
}
m_LastActivity = r->Now();
}
FlushDownstream(r);
for (const auto& other : m_FlushOthers)
const llarp_buffer_t buf(msg.enc);
if (!r->ParseRoutingMessageBuffer(buf, this, info.rxID))
{
other->FlushDownstream(r);
LogWarn("invalid upstream data on endpoint ", info);
}
m_FlushOthers.clear();
m_LastActivity = r->Now();
}
else
FlushDownstream(r);
for (const auto& other : m_FlushOthers)
{
for (const auto& msg : msgs)
{
llarp::LogDebug(
"relay ",
msg.X.size(),
" bytes upstream from ",
info.downstream,
" to ",
info.upstream);
r->SendToOrQueue(info.upstream, msg);
}
other->FlushDownstream(r);
}
r->TriggerPump();
m_FlushOthers.clear();
}
void
TransitHop::HandleAllDownstream(std::vector<RelayDownstreamMessage> msgs, AbstractRouter* r)
else
{
for (const auto& msg : msgs)
{
llarp::LogDebug(
"relay ",
msg.X.size(),
" bytes downstream from ",
info.upstream,
msg.enc.size(),
" bytes upstream from ",
info.downstream,
" to ",
info.downstream);
r->SendToOrQueue(info.downstream, msg);
}
r->TriggerPump();
}
void
TransitHop::FlushUpstream(AbstractRouter* r)
{
if (not m_UpstreamQueue.empty())
{
r->QueueWork([self = shared_from_this(),
data = std::exchange(m_UpstreamQueue, {}),
r]() mutable { self->UpstreamWork(std::move(data), r); });
info.upstream);
r->SendToOrQueue(info.upstream, msg);
}
}
r->TriggerPump();
}
void
TransitHop::FlushDownstream(AbstractRouter* r)
void
TransitHop::HandleAllDownstream(std::vector<RelayDownstreamMessage> msgs, AbstractRouter* r)
{
for (const auto& msg : msgs)
{
if (not m_DownstreamQueue.empty())
{
r->QueueWork([self = shared_from_this(),
data = std::exchange(m_DownstreamQueue, {}),
r]() mutable { self->DownstreamWork(std::move(data), r); });
}
llarp::LogDebug(
"relay ",
msg.enc.size(),
" bytes downstream from ",
info.upstream,
" to ",
info.downstream);
r->SendToOrQueue(info.downstream, msg);
}
r->TriggerPump();
}
/// this is where a DHT message is handled at the end of a path, that is,
/// where a SNode receives a DHT message from a client along a path.
bool
TransitHop::HandleDHTMessage(const llarp::dht::IMessage& msg, AbstractRouter* r)
void
TransitHop::FlushUpstream(AbstractRouter* r)
{
if (not m_UpstreamQueue.empty())
{
return r->dht()->impl->RelayRequestForPath(info.rxID, msg);
r->QueueWork([self = shared_from_this(),
data = std::exchange(m_UpstreamQueue, {}),
r]() mutable { self->UpstreamWork(std::move(data), r); });
}
}
bool
TransitHop::HandlePathLatencyMessage(
const llarp::routing::PathLatencyMessage& msg, AbstractRouter* r)
void
TransitHop::FlushDownstream(AbstractRouter* r)
{
if (not m_DownstreamQueue.empty())
{
llarp::routing::PathLatencyMessage reply;
reply.L = msg.T;
reply.S = msg.S;
return SendRoutingMessage(reply, r);
r->QueueWork([self = shared_from_this(),
data = std::exchange(m_DownstreamQueue, {}),
r]() mutable { self->DownstreamWork(std::move(data), r); });
}
}
bool
TransitHop::HandlePathConfirmMessage(
[[maybe_unused]] const llarp::routing::PathConfirmMessage& msg,
[[maybe_unused]] AbstractRouter* r)
{
llarp::LogWarn("unwarranted path confirm message on ", info);
return false;
}
/// this is where a DHT message is handled at the end of a path, that is,
/// where a SNode receives a DHT message from a client along a path.
bool
TransitHop::HandleDHTMessage(const llarp::dht::AbstractDHTMessage& msg, AbstractRouter* r)
{
return r->dht()->impl->RelayRequestForPath(info.rxID, msg);
}
bool
TransitHop::HandleDataDiscardMessage(
[[maybe_unused]] const llarp::routing::DataDiscardMessage& msg,
[[maybe_unused]] AbstractRouter* r)
{
llarp::LogWarn("unwarranted path data discard message on ", info);
return false;
}
bool
TransitHop::HandlePathLatencyMessage(
const llarp::routing::PathLatencyMessage& msg, AbstractRouter* r)
{
llarp::routing::PathLatencyMessage reply;
reply.L = msg.T;
reply.S = msg.S;
return SendRoutingMessage(reply, r);
}
bool
TransitHop::HandlePathConfirmMessage(
[[maybe_unused]] const llarp::routing::PathConfirmMessage& msg,
[[maybe_unused]] AbstractRouter* r)
{
llarp::LogWarn("unwarranted path confirm message on ", info);
return false;
}
bool
TransitHop::HandleDataDiscardMessage(
[[maybe_unused]] const llarp::routing::DataDiscardMessage& msg,
[[maybe_unused]] AbstractRouter* r)
{
llarp::LogWarn("unwarranted path data discard message on ", info);
return false;
}
bool
TransitHop::HandleObtainExitMessage(
const llarp::routing::ObtainExitMessage& msg, AbstractRouter* r)
bool
TransitHop::HandleObtainExitMessage(
const llarp::routing::ObtainExitMessage& msg, AbstractRouter* r)
{
if (msg.Verify() && r->exitContext().ObtainNewExit(msg.I, info.rxID, msg.E != 0))
{
if (msg.Verify() && r->exitContext().ObtainNewExit(msg.I, info.rxID, msg.E != 0))
llarp::routing::GrantExitMessage grant;
grant.S = NextSeqNo();
grant.T = msg.T;
if (!grant.Sign(r->identity()))
{
llarp::routing::GrantExitMessage grant;
grant.S = NextSeqNo();
grant.T = msg.T;
if (!grant.Sign(r->identity()))
{
llarp::LogError("Failed to sign grant exit message");
return false;
}
return SendRoutingMessage(grant, r);
}
// TODO: exponential backoff
// TODO: rejected policies
llarp::routing::RejectExitMessage reject;
reject.S = NextSeqNo();
reject.T = msg.T;
if (!reject.Sign(r->identity()))
{
llarp::LogError("Failed to sign reject exit message");
llarp::LogError("Failed to sign grant exit message");
return false;
}
return SendRoutingMessage(reject, r);
}
bool
TransitHop::HandleCloseExitMessage(
const llarp::routing::CloseExitMessage& msg, AbstractRouter* r)
{
const llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
auto ep = r->exitContext().FindEndpointForPath(info.rxID);
if (ep && msg.Verify(ep->PubKey()))
{
llarp::routing::CloseExitMessage reply;
reply.Y = msg.Y;
reply.S = NextSeqNo();
if (reply.Sign(r->identity()))
{
if (SendRoutingMessage(reply, r))
{
ep->Close();
return true;
}
}
}
return SendRoutingMessage(discard, r);
return SendRoutingMessage(grant, r);
}
bool
TransitHop::HandleUpdateExitVerifyMessage(
const llarp::routing::UpdateExitVerifyMessage& msg, AbstractRouter* r)
// TODO: exponential backoff
// TODO: rejected policies
llarp::routing::RejectExitMessage reject;
reject.S = NextSeqNo();
reject.T = msg.T;
if (!reject.Sign(r->identity()))
{
(void)msg;
(void)r;
llarp::LogError("unwarranted exit verify on ", info);
llarp::LogError("Failed to sign reject exit message");
return false;
}
return SendRoutingMessage(reject, r);
}
bool
TransitHop::HandleUpdateExitMessage(
const llarp::routing::UpdateExitMessage& msg, AbstractRouter* r)
bool
TransitHop::HandleCloseExitMessage(const llarp::routing::CloseExitMessage& msg, AbstractRouter* r)
{
const llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
auto ep = r->exitContext().FindEndpointForPath(info.rxID);
if (ep && msg.Verify(ep->PubKey()))
{
auto ep = r->exitContext().FindEndpointForPath(msg.P);
if (ep)
llarp::routing::CloseExitMessage reply;
reply.Y = msg.Y;
reply.S = NextSeqNo();
if (reply.Sign(r->identity()))
{
if (!msg.Verify(ep->PubKey()))
return false;
if (ep->UpdateLocalPath(info.rxID))
if (SendRoutingMessage(reply, r))
{
llarp::routing::UpdateExitVerifyMessage reply;
reply.T = msg.T;
reply.S = NextSeqNo();
return SendRoutingMessage(reply, r);
ep->Close();
return true;
}
}
// on fail tell message was discarded
llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
return SendRoutingMessage(discard, r);
}
return SendRoutingMessage(discard, r);
}
bool
TransitHop::HandleRejectExitMessage(
const llarp::routing::RejectExitMessage& msg, AbstractRouter* r)
{
(void)msg;
(void)r;
llarp::LogError(info, " got unwarranted RXM");
return false;
}
bool
TransitHop::HandleGrantExitMessage(
const llarp::routing::GrantExitMessage& msg, AbstractRouter* r)
bool
TransitHop::HandleUpdateExitVerifyMessage(
const llarp::routing::UpdateExitVerifyMessage& msg, AbstractRouter* r)
{
(void)msg;
(void)r;
llarp::LogError("unwarranted exit verify on ", info);
return false;
}
bool
TransitHop::HandleUpdateExitMessage(
const llarp::routing::UpdateExitMessage& msg, AbstractRouter* r)
{
auto ep = r->exitContext().FindEndpointForPath(msg.P);
if (ep)
{
(void)msg;
(void)r;
llarp::LogError(info, " got unwarranted GXM");
return false;
}
if (!msg.Verify(ep->PubKey()))
return false;
bool
TransitHop::HandleTransferTrafficMessage(
const llarp::routing::TransferTrafficMessage& msg, AbstractRouter* r)
{
auto endpoint = r->exitContext().FindEndpointForPath(info.rxID);
if (endpoint)
if (ep->UpdateLocalPath(info.rxID))
{
bool sent = true;
for (const auto& pkt : msg.X)
{
// check short packet buffer
if (pkt.size() <= 8)
continue;
auto counter = oxenc::load_big_to_host<uint64_t>(pkt.data());
llarp_buffer_t buf{pkt.data() + 8, pkt.size() - 8};
sent =
endpoint->QueueOutboundTraffic(info.rxID, buf.copy(), counter, msg.protocol) and sent;
}
return sent;
llarp::routing::UpdateExitVerifyMessage reply;
reply.T = msg.T;
reply.S = NextSeqNo();
return SendRoutingMessage(reply, r);
}
llarp::LogError("No exit endpoint on ", info);
// discarded
llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
return SendRoutingMessage(discard, r);
}
bool
TransitHop::HandlePathTransferMessage(
const llarp::routing::PathTransferMessage& msg, AbstractRouter* r)
// on fail tell message was discarded
llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
return SendRoutingMessage(discard, r);
}
bool
TransitHop::HandleRejectExitMessage(
const llarp::routing::RejectExitMessage& msg, AbstractRouter* r)
{
(void)msg;
(void)r;
llarp::LogError(info, " got unwarranted RXM");
return false;
}
bool
TransitHop::HandleGrantExitMessage(const llarp::routing::GrantExitMessage& msg, AbstractRouter* r)
{
(void)msg;
(void)r;
llarp::LogError(info, " got unwarranted GXM");
return false;
}
bool
TransitHop::HandleTransferTrafficMessage(
const llarp::routing::TransferTrafficMessage& msg, AbstractRouter* r)
{
auto endpoint = r->exitContext().FindEndpointForPath(info.rxID);
if (endpoint)
{
auto path = r->pathContext().GetPathForTransfer(msg.P);
llarp::routing::DataDiscardMessage discarded{msg.P, msg.S};
if (path == nullptr || msg.T.F != info.txID)
bool sent = true;
for (const auto& pkt : msg.X)
{
return SendRoutingMessage(discarded, r);
// check short packet buffer
if (pkt.size() <= 8)
continue;
auto counter = oxenc::load_big_to_host<uint64_t>(pkt.data());
llarp_buffer_t buf{pkt.data() + 8, pkt.size() - 8};
sent =
endpoint->QueueOutboundTraffic(info.rxID, buf.copy(), counter, msg.protocol) and sent;
}
// send routing message
if (path->SendRoutingMessage(msg.T, r))
{
m_FlushOthers.emplace(path);
return true;
}
return SendRoutingMessage(discarded, r);
return sent;
}
std::string
TransitHop::ToString() const
{
return fmt::format(
"[TransitHop {} started={} lifetime={}", info, started.count(), lifetime.count());
}
llarp::LogError("No exit endpoint on ", info);
// discarded
llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
return SendRoutingMessage(discard, r);
}
void
TransitHop::Stop()
bool
TransitHop::HandlePathTransferMessage(
const llarp::routing::PathTransferMessage& msg, AbstractRouter* r)
{
auto path = r->pathContext().GetPathForTransfer(msg.P);
llarp::routing::DataDiscardMessage discarded{msg.P, msg.S};
if (path == nullptr || msg.T.F != info.txID)
{
m_UpstreamGather.disable();
m_DownstreamGather.disable();
return SendRoutingMessage(discarded, r);
}
void
TransitHop::SetSelfDestruct()
// send routing message
if (path->SendRoutingMessage(msg.T, r))
{
destroy = true;
m_FlushOthers.emplace(path);
return true;
}
return SendRoutingMessage(discarded, r);
}
void
TransitHop::QueueDestroySelf(AbstractRouter* r)
{
r->loop()->call([self = shared_from_this()] { self->SetSelfDestruct(); });
}
} // namespace path
} // namespace llarp
std::string
TransitHop::ToString() const
{
return fmt::format(
"[TransitHop {} started={} lifetime={}", info, started.count(), lifetime.count());
}
void
TransitHop::Stop()
{
m_UpstreamGather.disable();
m_DownstreamGather.disable();
}
void
TransitHop::SetSelfDestruct()
{
destroy = true;
}
void
TransitHop::QueueDestroySelf(AbstractRouter* r)
{
r->loop()->call([self = shared_from_this()] { self->SetSelfDestruct(); });
}
} // namespace llarp::path

@ -53,7 +53,7 @@ namespace llarp
}
struct TransitHop : public IHopHandler,
public routing::IMessageHandler,
public routing::AbstractRoutingMessageHandler,
std::enable_shared_from_this<TransitHop>
{
TransitHop();
@ -117,11 +117,11 @@ namespace llarp
// send routing message when end of path
bool
SendRoutingMessage(const routing::IMessage& msg, AbstractRouter* r) override;
SendRoutingMessage(const routing::AbstractRoutingMessage& msg, AbstractRouter* r) override;
// handle routing message when end of path
bool
HandleRoutingMessage(const routing::IMessage& msg, AbstractRouter* r);
HandleRoutingMessage(const routing::AbstractRoutingMessage& msg, AbstractRouter* r);
bool
HandleDataDiscardMessage(const routing::DataDiscardMessage& msg, AbstractRouter* r) override;
@ -171,7 +171,7 @@ namespace llarp
HandleGotIntroMessage(const dht::GotIntroMessage& msg);
bool
HandleDHTMessage(const dht::IMessage& msg, AbstractRouter* r) override;
HandleDHTMessage(const dht::AbstractDHTMessage& msg, AbstractRouter* r) override;
void
FlushUpstream(AbstractRouter* r) override;

@ -105,7 +105,10 @@ namespace llarp::quic
Address local_, remote_;
public:
ngtcp2_path path{{local_, local_.sockaddr_size()}, {remote_, remote_.sockaddr_size()}, nullptr};
ngtcp2_path path{
{local_, static_cast<ngtcp2_socklen>(local_.sockaddr_size())},
{remote_, static_cast<ngtcp2_socklen>(remote_.sockaddr_size())},
nullptr};
// Public accessors are const:
const Address& local = local_;

@ -95,10 +95,10 @@ namespace llarp::quic
auto& conn = *static_cast<Connection*>(user_data);
switch (crypto_level)
{
// case NGTCP2_CRYPTO_LEVEL_EARLY:
// // We don't currently use or support 0rtt
// LogWarn("Invalid EARLY crypto level");
// return FAIL;
// case NGTCP2_CRYPTO_LEVEL_EARLY:
// // We don't currently use or support 0rtt
// LogWarn("Invalid EARLY crypto level");
// return FAIL;
case NGTCP2_ENCRYPTION_LEVEL_INITIAL:
log::trace(log_cat, "Receiving initial crypto...");
@ -1197,7 +1197,8 @@ namespace llarp::quic
// auto exttype = is_server ? NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS
// : NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO;
if (ngtcp2_ssize nwrite = ngtcp2_conn_encode_local_transport_params(*this, buf, bufend-buf); nwrite >= 0)
if (ngtcp2_ssize nwrite = ngtcp2_conn_encode_local_transport_params(*this, buf, bufend - buf);
nwrite >= 0)
{
assert(nwrite > 0);
conn_buffer.resize(buf - u8data(conn_buffer) + nwrite);

@ -99,11 +99,7 @@ namespace llarp::quic
Endpoint::handle_packet_init(const Packet& p)
{
ngtcp2_version_cid vid;
auto rv = ngtcp2_pkt_decode_version_cid(
&vid,
u8data(p.data),
p.data.size(),
NGTCP2_MAX_CIDLEN);
auto rv = ngtcp2_pkt_decode_version_cid(&vid, u8data(p.data), p.data.size(), NGTCP2_MAX_CIDLEN);
if (rv == 1)
{ // 1 means Version Negotiation should be sent and otherwise the packet should be ignored
send_version_negotiation(vid, p.path.remote);
@ -234,7 +230,11 @@ namespace llarp::quic
ngtcp2_pkt_info pi;
ngtcp2_ccerr err;
ngtcp2_ccerr_set_liberr(&err, code, reinterpret_cast<uint8_t*>(const_cast<char*>(close_reason.data())), close_reason.size());
ngtcp2_ccerr_set_liberr(
&err,
code,
reinterpret_cast<uint8_t*>(const_cast<char*>(close_reason.data())),
close_reason.size());
auto written = ngtcp2_conn_write_connection_close(
conn,

@ -31,7 +31,8 @@ namespace llarp::quic
{ // Invalid/unexpected version, send a version negotiation
LogDebug("Invalid/unsupported version; sending version negotiation");
send_version_negotiation(
ngtcp2_version_cid{hd.version, hd.dcid.data, hd.dcid.datalen, hd.scid.data, hd.scid.datalen},
ngtcp2_version_cid{
hd.version, hd.dcid.data, hd.dcid.datalen, hd.scid.data, hd.scid.datalen},
p.path.remote);
return nullptr;
}

@ -33,8 +33,8 @@ namespace llarp
class NodeDB;
struct Config;
struct RouterID;
struct ILinkMessage;
struct ILinkSession;
struct AbstractLinkMessage;
struct AbstractLinkSession;
struct PathID_t;
struct Profiling;
struct SecretKey;
@ -71,7 +71,7 @@ namespace llarp
namespace routing
{
struct IMessageHandler;
struct AbstractRoutingMessageHandler;
}
namespace service
@ -100,7 +100,7 @@ namespace llarp
virtual ~AbstractRouter() = default;
virtual bool
HandleRecvLinkMessageBuffer(ILinkSession* from, const llarp_buffer_t& msg) = 0;
HandleRecvLinkMessageBuffer(AbstractLinkSession* from, const llarp_buffer_t& msg) = 0;
virtual const net::Platform&
Net() const = 0;
@ -268,14 +268,18 @@ namespace llarp
virtual bool
SendToOrQueue(
const RouterID& remote, const ILinkMessage& msg, SendStatusHandler handler = nullptr) = 0;
const RouterID& remote,
const AbstractLinkMessage& msg,
SendStatusHandler handler = nullptr) = 0;
virtual void
PersistSessionUntil(const RouterID& remote, llarp_time_t until) = 0;
virtual bool
ParseRoutingMessageBuffer(
const llarp_buffer_t& buf, routing::IMessageHandler* h, const PathID_t& rxid) = 0;
const llarp_buffer_t& buf,
routing::AbstractRoutingMessageHandler* h,
const PathID_t& rxid) = 0;
/// count the number of service nodes we are connected to
virtual size_t
@ -318,7 +322,8 @@ namespace llarp
/// visit each connected link session
virtual void
ForEachPeer(std::function<void(const ILinkSession*, bool)> visit, bool randomize) const = 0;
ForEachPeer(
std::function<void(const AbstractLinkSession*, bool)> visit, bool randomize) const = 0;
virtual bool
SessionToRouterAllowed(const RouterID& router) const = 0;

@ -17,7 +17,7 @@ namespace llarp
Congestion
};
struct ILinkMessage;
struct AbstractLinkMessage;
struct RouterID;
struct PathID_t;
@ -32,7 +32,8 @@ namespace llarp
virtual ~IOutboundMessageHandler() = default;
virtual bool
QueueMessage(const RouterID& remote, const ILinkMessage& msg, SendStatusHandler callback) = 0;
QueueMessage(
const RouterID& remote, const AbstractLinkMessage& msg, SendStatusHandler callback) = 0;
virtual void
Pump() = 0;

@ -10,7 +10,7 @@
namespace llarp
{
struct ILinkSession;
struct AbstractLinkSession;
struct RouterID;
struct RouterContact;
@ -45,10 +45,10 @@ namespace llarp
virtual ~IOutboundSessionMaker() = default;
virtual bool
OnSessionEstablished(ILinkSession* session) = 0;
OnSessionEstablished(AbstractLinkSession* session) = 0;
virtual void
OnConnectTimeout(ILinkSession* session) = 0;
OnConnectTimeout(AbstractLinkSession* session) = 0;
virtual void
CreateSessionTo(const RouterID& router, RouterCallback on_result) = 0;

@ -21,7 +21,7 @@ namespace llarp
bool
OutboundMessageHandler::QueueMessage(
const RouterID& remote, const ILinkMessage& msg, SendStatusHandler callback)
const RouterID& remote, const AbstractLinkMessage& msg, SendStatusHandler callback)
{
// if the destination is invalid, callback with failure and return
if (not _router->linkManager().HaveClientConnection(remote)
@ -34,19 +34,21 @@ namespace llarp
ent.router = remote;
ent.inform = std::move(callback);
ent.pathid = msg.pathid;
ent.priority = msg.Priority();
ent.priority = msg.priority();
std::array<byte_t, MAX_LINK_MSG_SIZE> linkmsg_buffer;
llarp_buffer_t buf{linkmsg_buffer};
// std::array<byte_t, MAX_LINK_MSG_SIZE> linkmsg_buffer;
// llarp_buffer_t buf{linkmsg_buffer};
if (!EncodeBuffer(msg, buf))
llarp_buffer _buf{MAX_LINK_MSG_SIZE};
if (!EncodeBuffer(msg, _buf))
{
return false;
}
ent.message.resize(buf.sz);
ent.message.resize(_buf.size());
std::copy_n(buf.base, buf.sz, ent.message.data());
std::copy_n(_buf.data(), _buf.size(), ent.message.data());
// if we have a session to the destination, queue the message and return
if (_router->linkManager().HaveConnection(remote))
@ -168,7 +170,7 @@ namespace llarp
_router->loop()->call([f = std::move(callback), status] { f(status); });
}
//TODO: still necessary/desired?
// TODO: still necessary/desired?
void
OutboundMessageHandler::QueueSessionCreation(const RouterID& remote)
{
@ -176,18 +178,16 @@ namespace llarp
}
bool
OutboundMessageHandler::EncodeBuffer(const ILinkMessage& msg, llarp_buffer_t& buf)
OutboundMessageHandler::EncodeBuffer(const AbstractLinkMessage& msg, llarp_buffer& buf)
{
if (!msg.BEncode(&buf))
if (auto str = msg.bt_encode(); not str.empty())
{
LogWarn("failed to encode outbound message, buffer size left: ", buf.size_left());
return false;
buf = llarp_buffer{std::move(str)};
return true;
}
// set size of message
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return true;
log::error(link_cat, "Error: OutboundMessageHandler failed to encode outbound message!");
return false;
}
bool
@ -199,8 +199,8 @@ namespace llarp
return _router->linkManager().SendTo(
ent.router,
buf,
[this, callback](ILinkSession::DeliveryStatus status) {
if (status == ILinkSession::DeliveryStatus::eDeliverySuccess)
[this, callback](AbstractLinkSession::DeliveryStatus status) {
if (status == AbstractLinkSession::DeliveryStatus::eDeliverySuccess)
DoCallback(callback, SendStatus::Success);
else
{

@ -44,7 +44,7 @@ namespace llarp
* so for example an invalid destination still yields a true return.
*/
bool
QueueMessage(const RouterID& remote, const ILinkMessage& msg, SendStatusHandler callback)
QueueMessage(const RouterID& remote, const AbstractLinkMessage& msg, SendStatusHandler callback)
override EXCLUDES(_mutex);
/* Called when pumping output queues, typically scheduled via a call to Router::TriggerPump().
@ -123,7 +123,7 @@ namespace llarp
QueueSessionCreation(const RouterID& remote);
bool
EncodeBuffer(const ILinkMessage& msg, llarp_buffer_t& buf);
EncodeBuffer(const AbstractLinkMessage& msg, llarp_buffer& buf);
/* sends the message along to the link layer, and hopefully out to the network
*

@ -19,7 +19,7 @@ namespace llarp
{
bool
OutboundSessionMaker::OnSessionEstablished(ILinkSession* session)
OutboundSessionMaker::OnSessionEstablished(AbstractLinkSession* session)
{
// TODO: do we want to keep it
const RouterContact rc = session->GetRemoteRC();
@ -44,7 +44,7 @@ namespace llarp
}
void
OutboundSessionMaker::OnConnectTimeout(ILinkSession* session)
OutboundSessionMaker::OnConnectTimeout(AbstractLinkSession* session)
{
const auto router = RouterID(session->GetPubKey());
LogWarn("Session establish attempt to ", router, " timed out.", session->GetRemoteEndpoint());
@ -272,7 +272,7 @@ namespace llarp
FinalizeRequest(rc.pubkey, SessionResult::Establish);
}
//TODO: rename this, if we even want to keep it
// TODO: rename this, if we even want to keep it
void
OutboundSessionMaker::CreatePendingSession(const RouterID& router)
{

@ -29,10 +29,10 @@ namespace llarp
~OutboundSessionMaker() override = default;
bool
OnSessionEstablished(ILinkSession* session) override;
OnSessionEstablished(AbstractLinkSession* session) override;
void
OnConnectTimeout(ILinkSession* session) override;
OnConnectTimeout(AbstractLinkSession* session) override;
void
CreateSessionTo(const RouterID& router, RouterCallback on_result) override EXCLUDES(_mutex);

@ -105,7 +105,7 @@ namespace llarp
*
// select peers to gossip to
m_LinkManager->ForEachPeer(
[&](const ILinkSession* peerSession, bool) {
[&](const AbstractLinkSession* peerSession, bool) {
// ensure connected session
if (not(peerSession && peerSession->IsEstablished()))
return;
@ -122,7 +122,7 @@ namespace llarp
std::sample(
gossipTo.begin(), gossipTo.end(), std::inserter(keys, keys.end()), MaxGossipPeers, CSRNG{});
m_LinkManager->ForEachPeer([&](ILinkSession* peerSession) {
m_LinkManager->ForEachPeer([&](AbstractLinkSession* peerSession) {
if (not(peerSession && peerSession->IsEstablished()))
return;
@ -131,7 +131,7 @@ namespace llarp
return;
// encode message
ILinkSession::Message_t msg{};
AbstractLinkSession::Message_t msg{};
msg.resize(MAX_LINK_MSG_SIZE / 2);
llarp_buffer_t buf(msg);
if (not gossip.BEncode(&buf))

@ -79,8 +79,8 @@ namespace llarp
llarp_dht_context_free(_dht);
}
//TODO: investigate changes needed for libquic integration
// still needed at all?
// TODO: investigate changes needed for libquic integration
// still needed at all?
void
Router::PumpLL()
{
@ -110,7 +110,7 @@ namespace llarp
{"outboundMessages", _outboundMessageHandler.ExtractStatus()}};
}
//TODO: investigate changes needed for libquic integration
// TODO: investigate changes needed for libquic integration
util::StatusObject
Router::ExtractSummaryStatus() const
{
@ -208,9 +208,9 @@ namespace llarp
return stats;
}
//TODO: libquic change
// TODO: libquic change
bool
Router::HandleRecvLinkMessageBuffer(ILinkSession* session, const llarp_buffer_t& buf)
Router::HandleRecvLinkMessageBuffer(AbstractLinkSession* session, const llarp_buffer_t& buf)
{
if (_stopping)
return true;
@ -314,21 +314,23 @@ namespace llarp
}
bool
Router::SendToOrQueue(const RouterID& remote, const ILinkMessage& msg, SendStatusHandler handler)
Router::SendToOrQueue(
const RouterID& remote, const AbstractLinkMessage& msg, SendStatusHandler handler)
{
return _outboundMessageHandler.QueueMessage(remote, msg, handler);
}
//TODO: if still needed/useful, replace this in line with libquic impl
// TODO: if still needed/useful, replace this in line with libquic impl
void
Router::ForEachPeer(std::function<void(const ILinkSession*, bool)> visit, bool randomize) const
Router::ForEachPeer(
std::function<void(const AbstractLinkSession*, bool)> visit, bool randomize) const
{
//_linkManager.ForEachPeer(visit, randomize);
}
//TODO: if still needed/useful, replace this in line with libquic impl
// TODO: if still needed/useful, replace this in line with libquic impl
void
Router::ForEachPeer(std::function<void(ILinkSession*)> visit)
Router::ForEachPeer(std::function<void(AbstractLinkSession*)> visit)
{
//_linkManager.ForEachPeer(visit);
}
@ -540,7 +542,7 @@ namespace llarp
bool
Router::ParseRoutingMessageBuffer(
const llarp_buffer_t& buf, routing::IMessageHandler* h, const PathID_t& rxid)
const llarp_buffer_t& buf, routing::AbstractRoutingMessageHandler* h, const PathID_t& rxid)
{
return inbound_routing_msg_parser.ParseMessageBuffer(buf, h, rxid, this);
}
@ -630,8 +632,8 @@ namespace llarp
_rc = std::move(nextRC);
if (rotateKeys)
{
//TODO: libquic change
// propagate RC by renegotiating sessions
// TODO: libquic change
// propagate RC by renegotiating sessions
/*
ForEachPeer([](ILinkSession* s) {
if (s->RenegotiateSession())
@ -803,7 +805,7 @@ namespace llarp
whitelistRouters,
m_isServiceNode);
//FIXME: kludge for now, will be part of larger cleanup effort.
// FIXME: kludge for now, will be part of larger cleanup effort.
if (m_isServiceNode)
InitInboundLinks();
else
@ -1176,7 +1178,7 @@ namespace llarp
return CryptoManager::instance()->sign(sig, identity(), buf);
}
//TODO: replace this in line with libquic impl
// TODO: replace this in line with libquic impl
void
Router::SessionClosed(RouterID remote)
{
@ -1193,9 +1195,9 @@ namespace llarp
}
}
//TODO: replace this in line with libquic impl
// TODO: replace this in line with libquic impl
void
Router::ConnectionTimedOut(ILinkSession* session)
Router::ConnectionTimedOut(AbstractLinkSession* session)
{
if (m_peerDb)
{
@ -1216,9 +1218,9 @@ namespace llarp
}
}
//TODO: replace this in line with libquic impl
// TODO: replace this in line with libquic impl
bool
Router::ConnectionEstablished(ILinkSession* session, bool inbound)
Router::ConnectionEstablished(AbstractLinkSession* session, bool inbound)
{
RouterID id{session->GetPubKey()};
if (m_peerDb)
@ -1670,7 +1672,7 @@ namespace llarp
if ((not Net().IsBogonIP(ai_ip)) and (not Net().IsBogonIP(override_ip))
and ai_ip != override_ip)
throw std::runtime_error{
"Lokinet is bound to public IP '{}', but public-ip is set to '{}'. Either fix the "
"Lokinet is bound to public IP '{}', but public-ip is set to '{}'. Either fix the "
"[router]:public-ip setting or set a bind address in the [bind] section of the "
"config."_format(ai_ip_str, override_ip_str)};
ai.fromSockAddr(*_ourAddress);
@ -1678,8 +1680,8 @@ namespace llarp
if (RouterContact::BlockBogons && Net().IsBogon(ai.ip))
throw std::runtime_error{var::visit(
[](auto&& ip) {
return "cannot use " + ip.ToString()
+ " as a public ip as it is in a non routable ip range";
return "cannot use " + ip.ToString()
+ " as a public ip as it is in a non routable ip range";
},
ai.IP())};
LogInfo("adding address: ", ai);
@ -1729,8 +1731,8 @@ namespace llarp
_linkManager.AddLink({ai.IPString(), ai.port}, true);
ai.pubkey = llarp::seckey_topublic(_identity);
ai.dialect = "quicinet"; // FIXME: constant, also better name?
ai.rank = 2; // FIXME: hardcoded from the beginning...keep?
ai.dialect = "quicinet"; // FIXME: constant, also better name?
ai.rank = 2; // FIXME: hardcoded from the beginning...keep?
AddAddressToRC(ai);
}
}

@ -310,7 +310,7 @@ namespace llarp
Profiling _routerProfiling;
fs::path _profilesFile;
OutboundMessageHandler _outboundMessageHandler;
LinkManager _linkManager { this };
LinkManager _linkManager{this};
RCLookupHandler _rcLookupHandler;
RCGossiper _rcGossiper;
@ -360,7 +360,7 @@ namespace llarp
~Router() override;
bool
HandleRecvLinkMessageBuffer(ILinkSession* from, const llarp_buffer_t& msg) override;
HandleRecvLinkMessageBuffer(AbstractLinkSession* from, const llarp_buffer_t& msg) override;
void
InitInboundLinks();
@ -459,14 +459,14 @@ namespace llarp
/// MUST be called in the logic thread
bool
SendToOrQueue(
const RouterID& remote, const ILinkMessage& msg, SendStatusHandler handler) override;
const RouterID& remote, const AbstractLinkMessage& msg, SendStatusHandler handler) override;
void
ForEachPeer(std::function<void(const ILinkSession*, bool)> visit, bool randomize = false)
ForEachPeer(std::function<void(const AbstractLinkSession*, bool)> visit, bool randomize = false)
const override;
void
ForEachPeer(std::function<void(ILinkSession*)> visit);
ForEachPeer(std::function<void(AbstractLinkSession*)> visit);
bool IsBootstrapNode(RouterID) const override;
@ -483,11 +483,11 @@ namespace llarp
/// called by link when an unestablished connection times out
void
ConnectionTimedOut(ILinkSession* session);
ConnectionTimedOut(AbstractLinkSession* session);
/// called by link when session is fully established
bool
ConnectionEstablished(ILinkSession* session, bool inbound);
ConnectionEstablished(AbstractLinkSession* session, bool inbound);
/// call internal router ticker
void
@ -504,7 +504,9 @@ namespace llarp
/// return false
bool
ParseRoutingMessageBuffer(
const llarp_buffer_t& buf, routing::IMessageHandler* h, const PathID_t& rxid) override;
const llarp_buffer_t& buf,
routing::AbstractRoutingMessageHandler* h,
const PathID_t& rxid) override;
void
ConnectToRandomRouters(int N) override;

@ -110,6 +110,14 @@ namespace llarp
return false;
}
void
RouterContact::bt_encode_subdict(oxenc::bt_list_producer& btlp) const
{
btlp.append("1");
btlp.append(signature.ToView());
btlp.append(signed_bt_dict);
}
std::string
RouterContact::ToTXTRecord() const
{
@ -196,6 +204,7 @@ namespace llarp
if (!bencode_write_uint64_entry(buf, "v", 1, version))
return false;
// D We can delete this?
if (serializeExit)
{
/* write xi if they exist */

@ -11,8 +11,9 @@
#include "llarp/dns/srv_data.hpp"
#include <functional>
#include <oxenc/bt_producer.h>
#include <nlohmann/json.hpp>
#include <functional>
#include <vector>
#define MAX_RC_SIZE (1024)
@ -111,6 +112,10 @@ namespace llarp
bool
BEncode(llarp_buffer_t* buf) const;
// tofix: drop version 0 case, change parameter to take btlp reference
void
bt_encode_subdict(oxenc::bt_list_producer& btlp) const;
bool
BEncodeSignedSection(llarp_buffer_t* buf) const;

@ -14,7 +14,7 @@ namespace llarp
{
llarp::dht::Key_t fromKey;
fromKey.Zero();
return llarp::dht::DecodeMesssageList(fromKey, val, M, true);
return llarp::dht::DecodeMessageList(fromKey, val, M, true);
}
if (key.startswith("S"))
{
@ -51,7 +51,7 @@ namespace llarp
/// (e.g. dht::IMessage::HandleMessage()) in-place and is the case where a
/// client receives a DHT message
bool
DHTMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
DHTMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
// set source as us
const llarp::dht::Key_t us(r->pubkey());

@ -5,32 +5,29 @@
#include <vector>
namespace llarp
namespace llarp::routing
{
namespace routing
struct DHTMessage final : public AbstractRoutingMessage
{
struct DHTMessage final : public IMessage
{
std::vector<llarp::dht::IMessage::Ptr_t> M;
uint64_t V = 0;
std::vector<llarp::dht::AbstractDHTMessage::Ptr_t> M;
uint64_t V = 0;
~DHTMessage() override = default;
~DHTMessage() override = default;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
BEncode(llarp_buffer_t* buf) const override;
bool
BEncode(llarp_buffer_t* buf) const override;
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
bool
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
void
Clear() override
{
M.clear();
V = 0;
}
};
} // namespace routing
} // namespace llarp
void
Clear() override
{
M.clear();
V = 0;
}
};
} // namespace llarp::routing

@ -8,7 +8,7 @@ namespace llarp
namespace dht
{
struct IMessage;
struct AbstractDHTMessage;
}
namespace service
@ -31,7 +31,7 @@ namespace llarp
struct PathLatencyMessage;
// handles messages on the routing level
struct IMessageHandler
struct AbstractRoutingMessageHandler
{
virtual bool
HandleObtainExitMessage(const ObtainExitMessage& msg, AbstractRouter* r) = 0;
@ -69,10 +69,10 @@ namespace llarp
virtual bool
HandlePathLatencyMessage(const PathLatencyMessage& msg, AbstractRouter* r) = 0;
virtual bool
HandleDHTMessage(const dht::IMessage& msg, AbstractRouter* r) = 0;
HandleDHTMessage(const dht::AbstractDHTMessage& msg, AbstractRouter* r) = 0;
};
using MessageHandler_ptr = std::shared_ptr<IMessageHandler>;
using MessageHandler_ptr = std::shared_ptr<AbstractRoutingMessageHandler>;
} // namespace routing
} // namespace llarp

@ -1,41 +1,66 @@
#pragma once
#include <llarp/messages/common.hpp>
#include <llarp/constants/proto.hpp>
#include <llarp/path/path_types.hpp>
#include <llarp/util/bencode.hpp>
#include <llarp/util/buffer.hpp>
namespace
{
static auto route_cat = llarp::log::Cat("lokinet.routing");
} // namespace
namespace llarp
{
struct AbstractRouter;
namespace routing
{
struct IMessageHandler;
struct AbstractRoutingMessageHandler;
struct IMessage
struct AbstractRoutingMessage : private AbstractSerializable
{
PathID_t from;
uint64_t S{0};
uint64_t version = llarp::constants::proto_version;
IMessage() = default;
AbstractRoutingMessage() = default;
virtual ~IMessage() = default;
virtual ~AbstractRoutingMessage() = default;
virtual bool
BEncode(llarp_buffer_t* buf) const = 0;
decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf) = 0;
virtual bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) = 0;
std::string
bt_encode() const override = 0;
virtual bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const = 0;
handle_message(AbstractRoutingMessageHandler* h, AbstractRouter* r) const = 0;
virtual void
Clear() = 0;
clear() = 0;
// methods we do not want to inherit onwards from AbstractSerializable
void
bt_encode(oxenc::bt_list_producer&) const final
{
throw std::runtime_error{
"Error: Routing messages should not encode directly to a bt list producer!"};
}
void
bt_encode(llarp_buffer&) const final
{
throw std::runtime_error{"Error: Routing messages should not encode directly to a buffer!"};
}
void
bt_encode(oxenc::bt_dict_producer&) const final
{
throw std::runtime_error{
"Error: Routing messages should not encode directly to a bt dict producer!"};
}
bool
operator<(const IMessage& other) const
operator<(const AbstractRoutingMessage& other) const
{
return other.S < S;
}

@ -10,136 +10,136 @@
#include "transfer_traffic_message.hpp"
#include <llarp/util/mem.hpp>
namespace llarp
namespace llarp::routing
{
namespace routing
struct InboundMessageParser::MessageHolder
{
struct InboundMessageParser::MessageHolder
{
DataDiscardMessage D;
PathLatencyMessage L;
DHTMessage M;
PathConfirmMessage P;
PathTransferMessage T;
service::ProtocolFrame H;
TransferTrafficMessage I;
GrantExitMessage G;
RejectExitMessage J;
ObtainExitMessage O;
UpdateExitMessage U;
CloseExitMessage C;
};
DataDiscardMessage D;
PathLatencyMessage L;
DHTMessage M;
PathConfirmMessage P;
PathTransferMessage T;
service::ProtocolFrame H;
TransferTrafficMessage I;
GrantExitMessage G;
RejectExitMessage J;
ObtainExitMessage O;
UpdateExitMessage U;
CloseExitMessage C;
};
InboundMessageParser::InboundMessageParser() : m_Holder(std::make_unique<MessageHolder>())
{}
InboundMessageParser::InboundMessageParser() : m_Holder(std::make_unique<MessageHolder>())
{}
InboundMessageParser::~InboundMessageParser() = default;
InboundMessageParser::~InboundMessageParser() = default;
bool
InboundMessageParser::operator()(llarp_buffer_t* buffer, llarp_buffer_t* key)
bool
InboundMessageParser::operator()(llarp_buffer_t* buffer, llarp_buffer_t* key)
{
if (key == nullptr && firstKey)
{
if (key == nullptr && firstKey)
{
// empty dict
// empty dict
return false;
}
if (!key)
return true;
if (firstKey)
{
llarp_buffer_t strbuf;
if (!(key->startswith("A")))
return false;
}
if (!key)
return true;
if (firstKey)
if (!bencode_read_string(buffer, &strbuf))
return false;
if (strbuf.sz != 1)
return false;
ourKey = *strbuf.cur;
LogDebug("routing message '", std::string{ourKey, 1}, "'");
switch (ourKey)
{
llarp_buffer_t strbuf;
if (!(key->startswith("A")))
return false;
if (!bencode_read_string(buffer, &strbuf))
return false;
if (strbuf.sz != 1)
return false;
ourKey = *strbuf.cur;
LogDebug("routing message '", std::string{ourKey, 1}, "'");
switch (ourKey)
{
case 'D':
msg = &m_Holder->D;
break;
case 'L':
msg = &m_Holder->L;
break;
case 'M':
msg = &m_Holder->M;
break;
case 'P':
msg = &m_Holder->P;
break;
case 'T':
msg = &m_Holder->T;
break;
case 'H':
msg = &m_Holder->H;
break;
case 'I':
msg = &m_Holder->I;
break;
case 'G':
msg = &m_Holder->G;
break;
case 'J':
msg = &m_Holder->J;
break;
case 'O':
msg = &m_Holder->O;
break;
case 'U':
msg = &m_Holder->U;
break;
case 'C':
msg = &m_Holder->C;
break;
default:
llarp::LogError("invalid routing message id: ", *strbuf.cur);
}
if (msg)
msg->version = version;
firstKey = false;
return msg != nullptr;
case 'D':
msg = &m_Holder->D;
break;
case 'L':
msg = &m_Holder->L;
break;
case 'M':
msg = &m_Holder->M;
break;
case 'P':
msg = &m_Holder->P;
break;
case 'T':
msg = &m_Holder->T;
break;
case 'H':
msg = &m_Holder->H;
break;
case 'I':
msg = &m_Holder->I;
break;
case 'G':
msg = &m_Holder->G;
break;
case 'J':
msg = &m_Holder->J;
break;
case 'O':
msg = &m_Holder->O;
break;
case 'U':
msg = &m_Holder->U;
break;
case 'C':
msg = &m_Holder->C;
break;
default:
llarp::LogError("invalid routing message id: ", *strbuf.cur);
}
return msg->DecodeKey(*key, buffer);
if (msg)
msg->version = version;
firstKey = false;
return msg != nullptr;
}
bool
InboundMessageParser::ParseMessageBuffer(
const llarp_buffer_t& buf, IMessageHandler* h, const PathID_t& from, AbstractRouter* r)
return msg->DecodeKey(*key, buffer);
}
bool
InboundMessageParser::ParseMessageBuffer(
const llarp_buffer_t& buf,
AbstractRoutingMessageHandler* h,
const PathID_t& from,
AbstractRouter* r)
{
bool result = false;
msg = nullptr;
firstKey = true;
ManagedBuffer copiedBuf(buf);
auto& copy = copiedBuf.underlying;
uint64_t v = 0;
if (BEncodeSeekDictVersion(v, &copy, 'V'))
{
bool result = false;
msg = nullptr;
firstKey = true;
ManagedBuffer copiedBuf(buf);
auto& copy = copiedBuf.underlying;
uint64_t v = 0;
if (BEncodeSeekDictVersion(v, &copy, 'V'))
{
version = v;
}
if (bencode_read_dict(*this, &copy))
{
msg->from = from;
LogDebug("handle routing message ", msg->S, " from ", from);
result = msg->HandleMessage(h, r);
if (!result)
{
llarp::LogWarn("Failed to handle inbound routing message ", ourKey);
}
}
else
version = v;
}
if (bencode_read_dict(*this, &copy))
{
msg->from = from;
LogDebug("handle routing message ", msg->S, " from ", from);
result = msg->HandleMessage(h, r);
if (!result)
{
llarp::LogError("read dict failed in routing layer");
llarp::DumpBuffer<llarp_buffer_t, 128>(buf);
llarp::LogWarn("Failed to handle inbound routing message ", ourKey);
}
if (msg)
msg->Clear();
msg = nullptr;
version = 0;
return result;
}
} // namespace routing
} // namespace llarp
else
{
llarp::LogError("read dict failed in routing layer");
llarp::DumpBuffer<llarp_buffer_t, 128>(buf);
}
if (msg)
msg->Clear();
msg = nullptr;
version = 0;
return result;
}
} // namespace llarp::routing

@ -12,8 +12,8 @@ namespace llarp
namespace routing
{
struct IMessage;
struct IMessageHandler;
struct AbstractRoutingMessage;
struct AbstractRoutingMessageHandler;
struct InboundMessageParser
{
@ -23,7 +23,7 @@ namespace llarp
bool
ParseMessageBuffer(
const llarp_buffer_t& buf,
IMessageHandler* handler,
AbstractRoutingMessageHandler* handler,
const PathID_t& from,
AbstractRouter* r);
@ -36,7 +36,7 @@ namespace llarp
char ourKey{'\0'};
struct MessageHolder;
IMessage* msg{nullptr};
AbstractRoutingMessage* msg{nullptr};
std::unique_ptr<MessageHolder> m_Holder;
};
} // namespace routing

@ -46,7 +46,7 @@ namespace llarp
}
bool
PathConfirmMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
PathConfirmMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h && h->HandlePathConfirmMessage(*this, r);
}

@ -2,35 +2,32 @@
#include "message.hpp"
namespace llarp
namespace llarp::routing
{
namespace routing
struct PathConfirmMessage final : public AbstractRoutingMessage
{
struct PathConfirmMessage final : public IMessage
{
llarp_time_t pathLifetime = 0s;
llarp_time_t pathCreated = 0s;
llarp_time_t pathLifetime = 0s;
llarp_time_t pathCreated = 0s;
PathConfirmMessage() = default;
PathConfirmMessage(llarp_time_t lifetime);
~PathConfirmMessage() override = default;
PathConfirmMessage() = default;
PathConfirmMessage(llarp_time_t lifetime);
~PathConfirmMessage() override = default;
bool
BEncode(llarp_buffer_t* buf) const override;
bool
BEncode(llarp_buffer_t* buf) const override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) override;
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
bool
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
void
Clear() override
{
pathLifetime = 0s;
pathCreated = 0s;
version = 0;
}
};
} // namespace routing
} // namespace llarp
void
Clear() override
{
pathLifetime = 0s;
pathCreated = 0s;
version = 0;
}
};
} // namespace llarp::routing

@ -45,7 +45,7 @@ namespace llarp
}
bool
PathLatencyMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
PathLatencyMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h && h->HandlePathLatencyMessage(*this, r);
}

@ -6,7 +6,7 @@ namespace llarp
{
namespace routing
{
struct PathLatencyMessage final : public IMessage
struct PathLatencyMessage final : public AbstractRoutingMessage
{
uint64_t T = 0;
uint64_t L = 0;
@ -27,7 +27,7 @@ namespace llarp
}
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
};
} // namespace routing
} // namespace llarp

@ -49,7 +49,7 @@ namespace llarp
}
bool
PathTransferMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
PathTransferMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h->HandlePathTransferMessage(*this, r);
}

@ -9,7 +9,7 @@ namespace llarp
{
namespace routing
{
struct PathTransferMessage final : public IMessage
struct PathTransferMessage final : public AbstractRoutingMessage
{
PathID_t P;
service::ProtocolFrame T;
@ -29,7 +29,7 @@ namespace llarp
BEncode(llarp_buffer_t* buf) const override;
bool
HandleMessage(IMessageHandler*, AbstractRouter* r) const override;
HandleMessage(AbstractRoutingMessageHandler*, AbstractRouter* r) const override;
void
Clear() override

@ -58,7 +58,7 @@ namespace llarp
}
bool
TransferTrafficMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
TransferTrafficMessage::HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const
{
return h->HandleTransferTrafficMessage(*this, r);
}

@ -13,7 +13,7 @@ namespace llarp
constexpr size_t ExitPadSize = 512 - 48;
constexpr size_t MaxExitMTU = 1500;
constexpr size_t ExitOverhead = sizeof(uint64_t);
struct TransferTrafficMessage final : public IMessage
struct TransferTrafficMessage final : public AbstractRoutingMessage
{
std::vector<llarp::Encrypted<MaxExitMTU + ExitOverhead>> X;
service::ProtocolType protocol;
@ -45,7 +45,7 @@ namespace llarp
DecodeKey(const llarp_buffer_t& k, llarp_buffer_t* val) override;
bool
HandleMessage(IMessageHandler* h, AbstractRouter* r) const override;
HandleMessage(AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
};
} // namespace routing
} // namespace llarp

@ -769,7 +769,7 @@ namespace llarp
, m_relayOrder(relayOrder)
{}
std::shared_ptr<routing::IMessage>
std::shared_ptr<routing::AbstractRoutingMessage>
BuildRequestMessage() override
{
auto msg = std::make_shared<routing::DHTMessage>();
@ -988,7 +988,7 @@ namespace llarp
namehash, llarp_buffer_t(lnsName.c_str(), lnsName.size()));
}
std::shared_ptr<routing::IMessage>
std::shared_ptr<routing::AbstractRoutingMessage>
BuildRequestMessage() override
{
auto msg = std::make_shared<routing::DHTMessage>();

@ -49,7 +49,7 @@ namespace llarp
return handle(remote, found, endpoint, TimeLeft(time_now_ms()), relayOrder);
}
std::shared_ptr<routing::IMessage>
std::shared_ptr<routing::AbstractRoutingMessage>
HiddenServiceAddressLookup::BuildRequestMessage()
{
auto msg = std::make_shared<routing::DHTMessage>();

@ -46,7 +46,7 @@ namespace llarp
bool
HandleIntrosetResponse(const std::set<EncryptedIntroSet>& results) override;
std::shared_ptr<routing::IMessage>
std::shared_ptr<routing::AbstractRoutingMessage>
BuildRequestMessage() override;
};
} // namespace service

@ -64,7 +64,7 @@ namespace llarp
}
/// build request message for service lookup
virtual std::shared_ptr<routing::IMessage>
virtual std::shared_ptr<routing::AbstractRoutingMessage>
BuildRequestMessage() = 0;
/// build a new request message and send it via a path

@ -523,7 +523,8 @@ namespace llarp
}
bool
ProtocolFrame::HandleMessage(routing::IMessageHandler* h, AbstractRouter* /*r*/) const
ProtocolFrame::HandleMessage(
routing::AbstractRoutingMessageHandler* h, AbstractRouter* /*r*/) const
{
return h->HandleHiddenServiceFrame(*this);
}

@ -71,7 +71,7 @@ namespace llarp
};
/// outer message
struct ProtocolFrame final : public routing::IMessage
struct ProtocolFrame final : public routing::AbstractRoutingMessage
{
using Encrypted_t = Encrypted<2048>;
PQCipherBlock C;
@ -83,7 +83,7 @@ namespace llarp
service::ConvoTag T;
ProtocolFrame(const ProtocolFrame& other)
: routing::IMessage()
: routing::AbstractRoutingMessage()
, C(other.C)
, D(other.D)
, R(other.R)
@ -96,7 +96,7 @@ namespace llarp
version = other.version;
}
ProtocolFrame() : routing::IMessage{}
ProtocolFrame() : routing::AbstractRoutingMessage{}
{
Clear();
}
@ -162,7 +162,7 @@ namespace llarp
Verify(const ServiceInfo& from) const;
bool
HandleMessage(routing::IMessageHandler* h, AbstractRouter* r) const override;
HandleMessage(routing::AbstractRoutingMessageHandler* h, AbstractRouter* r) const override;
};
} // namespace service
} // namespace llarp

@ -102,7 +102,7 @@ namespace tooling
, from(msg.From)
, targetKey(msg.targetKey)
, iterative(msg.iterative)
, exploritory(msg.exploritory)
, exploritory(msg.exploratory)
, txid(msg.txid)
, version(msg.version)
{}

@ -20,7 +20,84 @@
namespace llarp
{
using byte_view_t = std::basic_string_view<byte_t>;
}
using bstring = std::basic_string<std::byte>;
using bstring_view = std::basic_string_view<std::byte>;
struct llarp_buffer
{
private:
std::string _buf;
std::string_view _bview;
size_t _size;
public:
llarp_buffer() = default;
llarp_buffer(size_t s) : _size{s}
{
_buf.reserve(_size);
_bview = {_buf};
}
llarp_buffer(std::string& b) : _buf{std::move(b)}, _bview{_buf}, _size{_buf.size()}
{}
llarp_buffer(std::string_view bv) : _buf{bv}, _bview{_buf}, _size{_buf.size()}
{}
template <
typename CharT,
std::enable_if_t<
std::is_convertible_v<CharT, char> || std::is_constructible_v<std::string, CharT>,
int> = 0>
llarp_buffer(CharT* c) : _buf{c}, _bview{_buf}, _size{_buf.size()}
{}
std::string_view
view() const
{
return _bview;
}
size_t
size() const
{
return _size;
}
bool
is_empty() const
{
return _buf.empty();
}
char*
data()
{
return _buf.data();
}
char*
data_at(size_t pos)
{
return _buf.data() + pos;
}
const char*
vdata()
{
return _bview.data();
}
const char*
vdata_at(size_t pos)
{
return _bview.data() + pos;
}
char
operator[](size_t pos)
{
return *(data() + pos);
}
};
} // namespace llarp
struct ManagedBuffer;
@ -36,18 +113,19 @@ struct /* [[deprecated("this type is stupid, use something else")]] */ llarp_buf
/// max size of buffer
size_t sz{0};
byte_t operator[](size_t x)
byte_t
operator[](size_t x)
{
return *(this->base + x);
}
llarp_buffer_t() = default;
llarp_buffer_t(byte_t * b, byte_t * c, size_t s) : base(b), cur(c), sz(s)
llarp_buffer_t(byte_t* b, byte_t* c, size_t s) : base(b), cur(c), sz(s)
{}
llarp_buffer_t(const ManagedBuffer&) = delete;
llarp_buffer_t(ManagedBuffer &&) = delete;
llarp_buffer_t(ManagedBuffer&&) = delete;
template <typename Byte>
static constexpr bool is_basic_byte = sizeof(Byte) == 1 and std::is_trivially_copyable_v<Byte>;
@ -57,21 +135,21 @@ struct /* [[deprecated("this type is stupid, use something else")]] */ llarp_buf
template <
typename Byte,
typename = std::enable_if_t<not std::is_const_v<Byte> && is_basic_byte<Byte>>>
llarp_buffer_t(Byte * buf, size_t sz) : base{reinterpret_cast<byte_t*>(buf)}, cur{base}, sz{sz}
llarp_buffer_t(Byte* buf, size_t sz) : base{reinterpret_cast<byte_t*>(buf)}, cur{base}, sz{sz}
{}
/// initialize llarp_buffer_t from vector or array of byte-like values
template <
typename Byte,
typename = std::enable_if_t<not std::is_const_v<Byte> && is_basic_byte<Byte>>>
llarp_buffer_t(std::vector<Byte> & b) : llarp_buffer_t{b.data(), b.size()}
llarp_buffer_t(std::vector<Byte>& b) : llarp_buffer_t{b.data(), b.size()}
{}
template <
typename Byte,
size_t N,
typename = std::enable_if_t<not std::is_const_v<Byte> && is_basic_byte<Byte>>>
llarp_buffer_t(std::array<Byte, N> & b) : llarp_buffer_t{b.data(), b.size()}
llarp_buffer_t(std::array<Byte, N>& b) : llarp_buffer_t{b.data(), b.size()}
{}
// These overloads, const_casting away the const, are not just gross but downright dangerous:
@ -97,27 +175,32 @@ struct /* [[deprecated("this type is stupid, use something else")]] */ llarp_buf
template <
typename T,
typename = std::void_t<decltype(std::declval<T>().data() + std::declval<T>().size())>>
explicit llarp_buffer_t(T && t) : llarp_buffer_t{t.data(), t.size()}
explicit llarp_buffer_t(T&& t) : llarp_buffer_t{t.data(), t.size()}
{}
byte_t* begin()
byte_t*
begin()
{
return base;
}
const byte_t* begin() const
const byte_t*
begin() const
{
return base;
}
byte_t* end()
byte_t*
end()
{
return base + sz;
}
const byte_t* end() const
const byte_t*
end() const
{
return base + sz;
}
size_t size_left() const
size_t
size_left() const
{
size_t diff = cur - base;
assert(diff <= sz);
@ -127,50 +210,66 @@ struct /* [[deprecated("this type is stupid, use something else")]] */ llarp_buf
}
template <typename OutputIt>
bool read_into(OutputIt begin, OutputIt end);
bool
read_into(OutputIt begin, OutputIt end);
template <typename InputIt>
bool write(InputIt begin, InputIt end);
bool
write(InputIt begin, InputIt end);
#ifndef _WIN32
bool writef(const char* fmt, ...) __attribute__((format(printf, 2, 3)));
bool
writef(const char* fmt, ...) __attribute__((format(printf, 2, 3)));
#elif defined(__MINGW64__) || defined(__MINGW32__)
bool writef(const char* fmt, ...) __attribute__((__format__(__MINGW_PRINTF_FORMAT, 2, 3)));
bool
writef(const char* fmt, ...) __attribute__((__format__(__MINGW_PRINTF_FORMAT, 2, 3)));
#else
bool writef(const char* fmt, ...);
bool
writef(const char* fmt, ...);
#endif
bool put_uint16(uint16_t i);
bool put_uint32(uint32_t i);
bool
put_uint16(uint16_t i);
bool
put_uint32(uint32_t i);
bool put_uint64(uint64_t i);
bool
put_uint64(uint64_t i);
bool read_uint16(uint16_t & i);
bool read_uint32(uint32_t & i);
bool
read_uint16(uint16_t& i);
bool
read_uint32(uint32_t& i);
bool read_uint64(uint64_t & i);
bool
read_uint64(uint64_t& i);
size_t read_until(char delim, byte_t* result, size_t resultlen);
size_t
read_until(char delim, byte_t* result, size_t resultlen);
/// make a copy of this buffer
std::vector<byte_t> copy() const;
std::vector<byte_t>
copy() const;
/// get a read-only view over the entire region
llarp::byte_view_t view_all() const
llarp::byte_view_t
view_all() const
{
return {base, sz};
}
/// get a read-only view over the remaining/unused region
llarp::byte_view_t view_remaining() const
llarp::byte_view_t
view_remaining() const
{
return {cur, size_left()};
}
/// Part of the curse. Returns true if the remaining buffer space starts with the given string
/// view.
bool startswith(std::string_view prefix_str) const
bool
startswith(std::string_view prefix_str) const
{
llarp::byte_view_t prefix{
reinterpret_cast<const byte_t*>(prefix_str.data()), prefix_str.size()};
@ -180,7 +279,7 @@ struct /* [[deprecated("this type is stupid, use something else")]] */ llarp_buf
private:
friend struct ManagedBuffer;
llarp_buffer_t(const llarp_buffer_t&) = default;
llarp_buffer_t(llarp_buffer_t &&) = default;
llarp_buffer_t(llarp_buffer_t&&) = default;
};
template <typename OutputIt>
@ -233,8 +332,6 @@ struct [[deprecated("deprecated along with llarp_buffer_t")]] ManagedBuffer
namespace llarp
{
using byte_view_t = std::basic_string_view<byte_t>;
// Wrapper around a std::unique_ptr<byte_t[]> that owns its own memory and is also implicitly
// convertible to a llarp_buffer_t.
struct OwnedBuffer

Loading…
Cancel
Save