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
pull/1576/head
Jeff Becker 3 years ago
parent a2285730b8
commit 25e338d621
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -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…
Cancel
Save