mirror of https://github.com/oxen-io/lokinet
srv records
* add srv records in RCs if we have any * add mechanism to add SRV records for plainquic exposed ports * resign and republish rc or introset on srv record changes
This commit is contained in:
parent
a2285730b8
commit
25e338d621
|
@ -128,6 +128,9 @@ add_library(liblokinet
|
|||
dht/recursiverouterlookup.cpp
|
||||
dht/serviceaddresslookup.cpp
|
||||
dht/taglookup.cpp
|
||||
|
||||
endpoint_base.cpp
|
||||
|
||||
exit/context.cpp
|
||||
exit/endpoint.cpp
|
||||
exit/exit_messages.cpp
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#include <limits>
|
||||
|
||||
#include <oxenmq/bt_serialize.h>
|
||||
#include "llarp/util/bencode.h"
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
bool
|
||||
|
@ -99,4 +102,42 @@ namespace llarp::dns
|
|||
return IsValid();
|
||||
}
|
||||
|
||||
bool
|
||||
SRVData::BEncode(llarp_buffer_t* buf) const
|
||||
{
|
||||
const std::string data = oxenmq::bt_serialize(toTuple());
|
||||
return buf->write(data.begin(), data.end());
|
||||
}
|
||||
|
||||
bool
|
||||
SRVData::BDecode(llarp_buffer_t* buf)
|
||||
{
|
||||
byte_t* begin = buf->cur;
|
||||
if (not bencode_discard(buf))
|
||||
return false;
|
||||
byte_t* end = buf->cur;
|
||||
std::string_view srvString{reinterpret_cast<char*>(begin), end - begin};
|
||||
try
|
||||
{
|
||||
SRVTuple tuple{};
|
||||
oxenmq::bt_deserialize(srvString, tuple);
|
||||
*this = fromTuple(std::move(tuple));
|
||||
return true;
|
||||
}
|
||||
catch (const oxenmq::bt_deserialize_invalid&)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
util::StatusObject
|
||||
SRVData::ExtractStatus() const
|
||||
{
|
||||
return util::StatusObject{
|
||||
{"proto", service_proto},
|
||||
{"priority", priority},
|
||||
{"weight", weight},
|
||||
{"port", port},
|
||||
{"target", target}};
|
||||
}
|
||||
} // namespace llarp::dns
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <tuple>
|
||||
#include <string_view>
|
||||
|
||||
#include "llarp/util/status.hpp"
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
typedef std::tuple<std::string, uint16_t, uint16_t, uint16_t, std::string> SRVTuple;
|
||||
|
@ -36,6 +38,30 @@ namespace llarp::dns
|
|||
SRVTuple
|
||||
toTuple() const;
|
||||
|
||||
/// so we can put SRVData in a std::set
|
||||
bool
|
||||
operator<(const SRVData& other) const
|
||||
{
|
||||
return service_proto < other.service_proto or priority < other.priority
|
||||
or weight < other.weight or port < other.port or target < other.target;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const SRVData& other) const
|
||||
{
|
||||
return service_proto == other.service_proto and priority == other.priority
|
||||
and weight == other.weight and port == other.port and target == other.target;
|
||||
}
|
||||
|
||||
bool
|
||||
BEncode(llarp_buffer_t*) const;
|
||||
|
||||
bool
|
||||
BDecode(llarp_buffer_t*);
|
||||
|
||||
util::StatusObject
|
||||
ExtractStatus() const;
|
||||
|
||||
static SRVData
|
||||
fromTuple(SRVTuple tuple);
|
||||
|
||||
|
@ -60,3 +86,19 @@ namespace llarp::dns
|
|||
};
|
||||
|
||||
} // namespace llarp::dns
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<llarp::dns::SRVData>
|
||||
{
|
||||
size_t
|
||||
operator()(const llarp::dns::SRVData& data) const
|
||||
{
|
||||
const std::hash<std::string> h_str{};
|
||||
const std::hash<uint16_t> h_port{};
|
||||
return h_str(data.service_proto) ^ (h_str(data.target) << 3) ^ (h_port(data.priority) << 5)
|
||||
^ (h_port(data.weight) << 7) ^ (h_port(data.port) << 9);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
|
|
@ -4,13 +4,16 @@
|
|||
#include "llarp/service/convotag.hpp"
|
||||
#include "llarp/service/protocol_type.hpp"
|
||||
#include "router_id.hpp"
|
||||
#include "ev/ev.hpp"
|
||||
#include "llarp/ev/ev.hpp"
|
||||
#include "llarp/dns/srv_data.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <optional>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
#include "oxenmq/variant.h"
|
||||
|
||||
namespace llarp
|
||||
|
@ -22,6 +25,8 @@ namespace llarp
|
|||
|
||||
class EndpointBase
|
||||
{
|
||||
std::unordered_set<dns::SRVData> m_SRVRecords;
|
||||
|
||||
public:
|
||||
virtual ~EndpointBase() = default;
|
||||
|
||||
|
@ -43,10 +48,51 @@ namespace llarp
|
|||
Duration_t lastRecvAt;
|
||||
};
|
||||
|
||||
/// get statistics about how much traffic we sent and recv'd via remote endpoints we are talking
|
||||
/// to
|
||||
virtual std::unordered_map<AddressVariant_t, SendStat>
|
||||
GetStatistics() const = 0;
|
||||
/// info about a quic mapping
|
||||
struct QUICMappingInfo
|
||||
{
|
||||
/// srv data if it was provided
|
||||
std::optional<dns::SRVData> srv;
|
||||
/// address we are bound on
|
||||
SockAddr localAddr;
|
||||
/// the remote's lns name if we have one
|
||||
std::optional<std::string> remoteName;
|
||||
/// the remote's address
|
||||
AddressVariant_t remoteAddr;
|
||||
/// the remote's port we are connecting to
|
||||
uint16_t remotePort;
|
||||
};
|
||||
|
||||
/// maybe get quic mapping info given its stream id
|
||||
/// returns std::nullopt if we have no stream given that id
|
||||
std::optional<QUICMappingInfo>
|
||||
GetQUICMappingInfoByID(int stream_id) const;
|
||||
|
||||
/// add an srv record to this endpoint's descriptor
|
||||
void
|
||||
PutSRVRecord(dns::SRVData srv);
|
||||
|
||||
/// called when srv data changes in some way
|
||||
virtual void
|
||||
SRVRecordsChanged() = 0;
|
||||
|
||||
/// remove srv records from this endpoint that match a filter
|
||||
/// for each srv record call it with filter, remove if filter returns true
|
||||
/// return if we removed any srv records
|
||||
bool
|
||||
DelSRVRecordIf(std::function<bool(const dns::SRVData&)> filter);
|
||||
|
||||
/// get copy of all srv records
|
||||
std::set<dns::SRVData>
|
||||
SRVRecords() const;
|
||||
|
||||
/// get statistics about how much traffic we sent and recv'd to a remote endpoint
|
||||
virtual std::optional<SendStat>
|
||||
GetStatFor(AddressVariant_t remote) const = 0;
|
||||
|
||||
/// list all remote endpoint addresses we have that are mapped
|
||||
virtual std::unordered_set<AddressVariant_t>
|
||||
AllRemoteEndpoints() const = 0;
|
||||
|
||||
/// get our local address
|
||||
virtual AddressVariant_t
|
||||
|
|
|
@ -563,10 +563,49 @@ namespace llarp
|
|||
return RouterID{m_Router->pubkey()};
|
||||
}
|
||||
|
||||
std::unordered_map<EndpointBase::AddressVariant_t, EndpointBase::SendStat>
|
||||
ExitEndpoint::GetStatistics() const
|
||||
void
|
||||
ExitEndpoint::SRVRecordsChanged()
|
||||
{
|
||||
return {};
|
||||
m_Router->ModifyOurRC(
|
||||
[srvRecords = SRVRecords()](RouterContact rc) -> std::optional<RouterContact> {
|
||||
// check if there are any new srv records
|
||||
bool shouldUpdate = false;
|
||||
|
||||
for (const auto& rcSrv : rc.srvRecords)
|
||||
{
|
||||
if (srvRecords.count(rcSrv) == 0)
|
||||
shouldUpdate = true;
|
||||
}
|
||||
|
||||
// no new records so don't modify
|
||||
if (not shouldUpdate)
|
||||
return std::nullopt;
|
||||
|
||||
// we got new entries so we clear the whole vector on the rc and recreate it
|
||||
rc.srvRecords.clear();
|
||||
for (auto& record : srvRecords)
|
||||
rc.srvRecords.emplace_back(record);
|
||||
// set the version to 1 because we have srv records
|
||||
rc.version = 1;
|
||||
return rc;
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<EndpointBase::SendStat> ExitEndpoint::GetStatFor(AddressVariant_t) const
|
||||
{
|
||||
/// TODO: implement me
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::unordered_set<EndpointBase::AddressVariant_t>
|
||||
ExitEndpoint::AllRemoteEndpoints() const
|
||||
{
|
||||
std::unordered_set<AddressVariant_t> remote;
|
||||
for (auto itr = m_Paths.begin(); itr != m_Paths.end(); ++itr)
|
||||
{
|
||||
remote.insert(RouterID{itr->second});
|
||||
}
|
||||
return remote;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -35,6 +35,12 @@ namespace llarp
|
|||
const EventLoop_ptr&
|
||||
Loop() override;
|
||||
|
||||
std::unordered_set<EndpointBase::AddressVariant_t>
|
||||
AllRemoteEndpoints() const override;
|
||||
|
||||
void
|
||||
SRVRecordsChanged() override;
|
||||
|
||||
bool
|
||||
SendToOrQueue(
|
||||
service::ConvoTag tag, const llarp_buffer_t& payload, service::ProtocolType t) override;
|
||||
|
@ -112,8 +118,8 @@ namespace llarp
|
|||
AddressVariant_t
|
||||
LocalAddress() const override;
|
||||
|
||||
std::unordered_map<AddressVariant_t, SendStat>
|
||||
GetStatistics() const override;
|
||||
std::optional<SendStat>
|
||||
GetStatFor(AddressVariant_t remote) const override;
|
||||
|
||||
/// sets up networking and starts traffic
|
||||
bool
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <llarp/tooling/router_event.hpp>
|
||||
#include <llarp/peerstats/peer_db.hpp>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#ifdef LOKINET_HIVE
|
||||
#include <llarp/tooling/router_event.hpp>
|
||||
#endif
|
||||
|
@ -114,6 +116,12 @@ namespace llarp
|
|||
virtual const RouterContact&
|
||||
rc() const = 0;
|
||||
|
||||
/// modify our rc
|
||||
/// modify returns nullopt if unmodified otherwise it returns the new rc to be sigend and
|
||||
/// published out
|
||||
virtual void
|
||||
ModifyOurRC(std::function<std::optional<RouterContact>(RouterContact)> modify) = 0;
|
||||
|
||||
virtual exit::Context&
|
||||
exitContext() = 0;
|
||||
|
||||
|
|
|
@ -946,6 +946,17 @@ namespace llarp
|
|||
_outboundSessionMaker.OnConnectTimeout(session);
|
||||
}
|
||||
|
||||
void
|
||||
Router::ModifyOurRC(std::function<std::optional<RouterContact>(RouterContact)> modify)
|
||||
{
|
||||
if (auto maybe = modify(rc()))
|
||||
{
|
||||
_rc = *maybe;
|
||||
UpdateOurRC();
|
||||
_rcGossiper.GossipRC(rc());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Router::ConnectionEstablished(ILinkSession* session, bool inbound)
|
||||
{
|
||||
|
|
|
@ -119,6 +119,9 @@ namespace llarp
|
|||
return _rc;
|
||||
}
|
||||
|
||||
void
|
||||
ModifyOurRC(std::function<std::optional<RouterContact>(RouterContact)> modify) override;
|
||||
|
||||
void
|
||||
SetRouterWhitelist(const std::vector<RouterID> routers) override;
|
||||
|
||||
|
|
|
@ -163,12 +163,20 @@ namespace llarp
|
|||
return false;
|
||||
if (!enckey.BEncode(buf))
|
||||
return false;
|
||||
|
||||
// write router version if present
|
||||
if (routerVersion)
|
||||
{
|
||||
if (not BEncodeWriteDictEntry("r", *routerVersion, buf))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (version > 0)
|
||||
{
|
||||
// srv records if present
|
||||
if (not BEncodeWriteDictList("s", srvRecords, buf))
|
||||
return false;
|
||||
}
|
||||
/* write last updated */
|
||||
if (!bencode_write_bytestring(buf, "u", 1))
|
||||
return false;
|
||||
|
@ -212,6 +220,8 @@ namespace llarp
|
|||
pubkey.Zero();
|
||||
routerVersion = std::optional<RouterVersion>{};
|
||||
last_updated = 0s;
|
||||
srvRecords.clear();
|
||||
version = LLARP_PROTO_VERSION;
|
||||
}
|
||||
|
||||
util::StatusObject
|
||||
|
@ -231,6 +241,12 @@ namespace llarp
|
|||
{
|
||||
obj["routerVersion"] = routerVersion->ToString();
|
||||
}
|
||||
std::vector<util::StatusObject> srv;
|
||||
for (const auto& record : srvRecords)
|
||||
{
|
||||
srv.emplace_back(record.ExtractStatus());
|
||||
}
|
||||
obj["srvRecords"] = srv;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -345,6 +361,9 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
if (not BEncodeMaybeReadDictList("s", srvRecords, read, key, buf))
|
||||
return false;
|
||||
|
||||
if (!BEncodeMaybeReadDictEntry("p", enckey, read, key, buf))
|
||||
return false;
|
||||
|
||||
|
@ -362,7 +381,7 @@ namespace llarp
|
|||
if (!BEncodeMaybeReadDictEntry("z", signature, read, key, buf))
|
||||
return false;
|
||||
|
||||
return read;
|
||||
return read or bencode_discard(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -503,7 +522,7 @@ namespace llarp
|
|||
/* else */
|
||||
if (version == 1)
|
||||
{
|
||||
llarp_buffer_t buf(signed_bt_dict);
|
||||
llarp_buffer_t buf{signed_bt_dict};
|
||||
return CryptoManager::instance()->verify(pubkey, buf, signature);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "constants/version.hpp"
|
||||
#include "crypto/types.hpp"
|
||||
#include "net/address_info.hpp"
|
||||
#include "net/exit_info.hpp"
|
||||
#include "util/aligned.hpp"
|
||||
#include "util/bencode.hpp"
|
||||
#include "util/status.hpp"
|
||||
#include "llarp/constants/version.hpp"
|
||||
#include "llarp/crypto/types.hpp"
|
||||
#include "llarp/net/address_info.hpp"
|
||||
#include "llarp/net/exit_info.hpp"
|
||||
#include "llarp/util/aligned.hpp"
|
||||
#include "llarp/util/bencode.hpp"
|
||||
#include "llarp/util/status.hpp"
|
||||
#include "router_version.hpp"
|
||||
|
||||
#include "llarp/dns/srv_data.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <vector>
|
||||
|
@ -104,6 +106,8 @@ namespace llarp
|
|||
|
||||
std::string signed_bt_dict;
|
||||
|
||||
std::vector<dns::SRVData> srvRecords;
|
||||
|
||||
util::StatusObject
|
||||
ExtractStatus() const;
|
||||
|
||||
|
|
|
@ -226,12 +226,16 @@ namespace llarp::rpc
|
|||
if (auto itr = obj.find("close"); itr != obj.end())
|
||||
closeID = itr->get<int>();
|
||||
|
||||
std::string srvProto;
|
||||
if (auto itr = obj.find("srv-proto"); itr != obj.end())
|
||||
srvProto = itr->get<std::string>();
|
||||
|
||||
if (port == 0 and closeID == 0)
|
||||
{
|
||||
reply(CreateJSONError("invalid arguments"));
|
||||
return;
|
||||
}
|
||||
r->loop()->call([reply, endpoint, remote, port, r, closeID]() {
|
||||
r->loop()->call([reply, endpoint, remote, port, r, closeID, srvProto]() {
|
||||
auto ep = GetEndpointByName(r, endpoint);
|
||||
if (not ep)
|
||||
{
|
||||
|
@ -263,6 +267,12 @@ namespace llarp::rpc
|
|||
var::visit(
|
||||
[&](auto&& addr) { localAddress = addr.ToString(); }, ep->LocalAddress());
|
||||
result["addr"] = localAddress + ":" + std::to_string(port);
|
||||
if (not srvProto.empty())
|
||||
{
|
||||
auto srvData =
|
||||
dns::SRVData::fromTuple(std::make_tuple(srvProto, 1, 1, port, ""));
|
||||
ep->PutSRVRecord(std::move(srvData));
|
||||
}
|
||||
reply(CreateJSONResponse(result));
|
||||
}
|
||||
else if (closeID)
|
||||
|
|
|
@ -1030,20 +1030,25 @@ namespace llarp
|
|||
const std::shared_ptr<exit::BaseSession>& session, EndpointBase::SendStat& stats)
|
||||
{}
|
||||
|
||||
std::unordered_map<EndpointBase::AddressVariant_t, EndpointBase::SendStat>
|
||||
Endpoint::GetStatistics() const
|
||||
std::optional<EndpointBase::SendStat> Endpoint::GetStatFor(AddressVariant_t) const
|
||||
{
|
||||
std::unordered_map<AddressVariant_t, SendStat> stats;
|
||||
// TODO: implement me
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::unordered_set<EndpointBase::AddressVariant_t>
|
||||
Endpoint::AllRemoteEndpoints() const
|
||||
{
|
||||
std::unordered_set<AddressVariant_t> remote;
|
||||
for (const auto& item : Sessions())
|
||||
{
|
||||
Address addr = item.second.remote.Addr();
|
||||
AccumulateStats(item.second, stats[addr]);
|
||||
remote.insert(item.second.remote.Addr());
|
||||
}
|
||||
for (const auto& item : m_state->m_SNodeSessions)
|
||||
{
|
||||
AccumulateStats(item.second.first, stats[item.first]);
|
||||
remote.insert(item.first);
|
||||
}
|
||||
return stats;
|
||||
return remote;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1329,6 +1334,17 @@ namespace llarp
|
|||
return hookAdded;
|
||||
}
|
||||
|
||||
void
|
||||
Endpoint::SRVRecordsChanged()
|
||||
{
|
||||
auto& introset = introSet();
|
||||
introset.SRVs.clear();
|
||||
for (const auto& srv : SRVRecords())
|
||||
introset.SRVs.emplace_back(srv.toTuple());
|
||||
|
||||
RegenAndPublishIntroSet();
|
||||
}
|
||||
|
||||
bool
|
||||
Endpoint::EnsurePathToSNode(const RouterID snode, SNodeEnsureHook h)
|
||||
{
|
||||
|
|
|
@ -139,12 +139,18 @@ namespace llarp
|
|||
AddressVariant_t
|
||||
LocalAddress() const override;
|
||||
|
||||
std::unordered_map<AddressVariant_t, SendStat>
|
||||
GetStatistics() const override;
|
||||
std::optional<SendStat>
|
||||
GetStatFor(AddressVariant_t remote) const override;
|
||||
|
||||
std::unordered_set<AddressVariant_t>
|
||||
AllRemoteEndpoints() const override;
|
||||
|
||||
bool
|
||||
ShouldPublishDescriptors(llarp_time_t now) const override;
|
||||
|
||||
void
|
||||
SRVRecordsChanged() override;
|
||||
|
||||
void
|
||||
HandlePathDied(path::Path_ptr p) override;
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ namespace llarp::service
|
|||
|
||||
byte_t* end = buf->cur;
|
||||
|
||||
std::string_view srvString(reinterpret_cast<char*>(begin), end - begin);
|
||||
std::string_view srvString{reinterpret_cast<char*>(begin), end - begin};
|
||||
|
||||
try
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue