mirror of https://github.com/oxen-io/lokinet
refactor dns subsystem
we want to be able to have multiple locally bound dns sockets in lokinet so i restructured most of the dns subsystem in order to make this easier. specifically, we have a new structure to dns subsystem: * dns::QueryJob_Base base type for holding a dns query and response with virtual methods in charge of sending a reply to whoever requested. * dns::PacketSource_Base base type for reading and writing dns messages to and from wherever they came from * dns::Resolver_Base base type for filtering and handling of dns messages asynchronously. * dns::Server contextualized per endpoint dns object, responsible for all dns related isms. this change hides all impelementation details of all of the dns components. adds some more helper functions for parsing dns and dealing with OwnedBuffer. overall dns becomes less of a pain with this new structure. probably.pull/1969/head
parent
bf2488d9e8
commit
74362149eb
@ -1,99 +1,226 @@
|
||||
#pragma once
|
||||
|
||||
#include "message.hpp"
|
||||
#include <llarp/config/config.hpp>
|
||||
#include <llarp/ev/ev.hpp>
|
||||
#include <llarp/net/net.hpp>
|
||||
#include "unbound_resolver.hpp"
|
||||
#include <llarp/util/fs.hpp>
|
||||
#include <set>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::dns
|
||||
{
|
||||
namespace dns
|
||||
/// a job handling 1 dns query
|
||||
class QueryJob_Base
|
||||
{
|
||||
/// handler of dns query hooking
|
||||
class IQueryHandler
|
||||
{
|
||||
public:
|
||||
virtual ~IQueryHandler() = default;
|
||||
protected:
|
||||
/// the original dns query
|
||||
Message m_Query;
|
||||
|
||||
/// return true if we should hook this message
|
||||
virtual bool
|
||||
ShouldHookDNSMessage(const Message& msg) const = 0;
|
||||
public:
|
||||
explicit QueryJob_Base(Message query) : m_Query{std::move(query)}
|
||||
{}
|
||||
|
||||
/// handle a hooked message
|
||||
virtual bool
|
||||
HandleHookedDNSMessage(Message query, std::function<void(Message)> sendReply) = 0;
|
||||
};
|
||||
virtual ~QueryJob_Base() = default;
|
||||
|
||||
// Base class for DNS lookups
|
||||
class PacketHandler : public std::enable_shared_from_this<PacketHandler>
|
||||
Message&
|
||||
Underlying()
|
||||
{
|
||||
public:
|
||||
explicit PacketHandler(EventLoop_ptr loop, IQueryHandler* handler);
|
||||
|
||||
virtual ~PacketHandler() = default;
|
||||
|
||||
virtual bool
|
||||
Start(
|
||||
SockAddr localaddr,
|
||||
std::vector<SockAddr> upstreamResolvers,
|
||||
std::vector<fs::path> hostfiles);
|
||||
|
||||
void
|
||||
Stop();
|
||||
|
||||
void
|
||||
Restart();
|
||||
|
||||
void
|
||||
HandlePacket(const SockAddr& resolver, const SockAddr& from, llarp_buffer_t buf);
|
||||
|
||||
bool
|
||||
ShouldHandlePacket(const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) const;
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
SendServerMessageBufferTo(const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) = 0;
|
||||
return m_Query;
|
||||
}
|
||||
|
||||
// Returns true if this packet is something that looks like it's going to an upstream
|
||||
// resolver, i.e. matches a configured resolver.
|
||||
virtual bool
|
||||
IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const;
|
||||
const Message&
|
||||
Underlying() const
|
||||
{
|
||||
return m_Query;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
HandleUpstreamFailure(const SockAddr& from, const SockAddr& to, Message msg);
|
||||
/// cancel this operation and inform anyone who cares
|
||||
void
|
||||
Cancel() const;
|
||||
|
||||
bool
|
||||
SetupUnboundResolver(std::vector<SockAddr> resolvers, std::vector<fs::path> hostfiles);
|
||||
/// send a raw buffer back to the querier
|
||||
virtual void
|
||||
SendReply(llarp::OwnedBuffer replyBuf) const = 0;
|
||||
};
|
||||
|
||||
IQueryHandler* const m_QueryHandler;
|
||||
std::set<SockAddr> m_Resolvers;
|
||||
std::shared_ptr<UnboundResolver> m_UnboundResolver;
|
||||
EventLoop_ptr m_Loop;
|
||||
};
|
||||
class PacketSource_Base
|
||||
{
|
||||
public:
|
||||
virtual ~PacketSource_Base() = default;
|
||||
|
||||
/// return true if traffic with source and dest addresses would cause a
|
||||
/// loop in resolution and thus should not be sent to query handlers
|
||||
virtual bool
|
||||
WouldLoop(const SockAddr& to, const SockAddr& from) const = 0;
|
||||
|
||||
/// send packet with src and dst address containing buf on this packet source
|
||||
virtual void
|
||||
SendTo(const SockAddr& to, const SockAddr& from, OwnedBuffer buf) const = 0;
|
||||
|
||||
/// stop reading packets and end operation
|
||||
virtual void
|
||||
Stop() = 0;
|
||||
|
||||
/// returns the sockaddr we are bound on if applicable
|
||||
virtual std::optional<SockAddr>
|
||||
BoundOn() const = 0;
|
||||
};
|
||||
|
||||
/// non complex implementation of QueryJob_Base for use in things that
|
||||
/// only ever called on the mainloop thread
|
||||
class QueryJob : public QueryJob_Base, std::enable_shared_from_this<QueryJob>
|
||||
{
|
||||
std::weak_ptr<PacketSource_Base> src;
|
||||
const SockAddr resolver;
|
||||
const SockAddr asker;
|
||||
|
||||
public:
|
||||
explicit QueryJob(
|
||||
std::weak_ptr<PacketSource_Base> source,
|
||||
const Message& query,
|
||||
const SockAddr& to_,
|
||||
const SockAddr& from_)
|
||||
: QueryJob_Base{query}, src{source}, resolver{to_}, asker{from_}
|
||||
{}
|
||||
|
||||
void
|
||||
SendReply(llarp::OwnedBuffer replyBuf) const override
|
||||
{
|
||||
if (auto ptr = src.lock())
|
||||
ptr->SendTo(asker, resolver, std::move(replyBuf));
|
||||
}
|
||||
};
|
||||
|
||||
/// handler of dns query hooking
|
||||
/// intercepts dns for internal processing
|
||||
class Resolver_Base
|
||||
{
|
||||
protected:
|
||||
/// return the sorting order for this resolver
|
||||
/// lower means it will be tried first
|
||||
virtual int
|
||||
Rank() const = 0;
|
||||
|
||||
public:
|
||||
virtual ~Resolver_Base() = default;
|
||||
|
||||
/// less than via rank
|
||||
bool
|
||||
operator<(const Resolver_Base& other) const
|
||||
{
|
||||
return Rank() < other.Rank();
|
||||
}
|
||||
|
||||
// Proxying DNS handler that listens on a UDP port for proper DNS requests.
|
||||
class Proxy : public PacketHandler
|
||||
/// greater than via rank
|
||||
bool
|
||||
operator>(const Resolver_Base& other) const
|
||||
{
|
||||
return Rank() > other.Rank();
|
||||
}
|
||||
|
||||
/// get printable name
|
||||
virtual std::string_view
|
||||
ResolverName() const = 0;
|
||||
|
||||
/// reset state
|
||||
virtual void
|
||||
ResetInternalState(){};
|
||||
|
||||
/// cancel all pending requests and ceace further operation
|
||||
virtual void
|
||||
CancelPendingQueries(){};
|
||||
/// attempt to handle a dns message
|
||||
/// returns true if we consumed this query and it should not be processed again
|
||||
virtual bool
|
||||
MaybeHookDNS(
|
||||
std::weak_ptr<PacketSource_Base> source,
|
||||
const Message& query,
|
||||
const SockAddr& to,
|
||||
const SockAddr& from) = 0;
|
||||
|
||||
/// Returns true if a packet with to and from addresses is something that would cause a
|
||||
/// resolution loop and thus should not be used on this resolver
|
||||
virtual bool
|
||||
WouldLoop(const SockAddr& to, const SockAddr& from) const
|
||||
{
|
||||
public:
|
||||
explicit Proxy(EventLoop_ptr loop, IQueryHandler* handler);
|
||||
|
||||
bool
|
||||
Start(
|
||||
SockAddr localaddr,
|
||||
std::vector<SockAddr> upstreamResolvers,
|
||||
std::vector<fs::path> hostfiles) override;
|
||||
|
||||
protected:
|
||||
void
|
||||
SendServerMessageBufferTo(
|
||||
const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<UDPHandle> m_Server;
|
||||
EventLoop_ptr m_Loop;
|
||||
(void)to;
|
||||
(void)from;
|
||||
return false;
|
||||
};
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
};
|
||||
|
||||
// Base class for DNS proxy
|
||||
class Server : public std::enable_shared_from_this<Server>
|
||||
{
|
||||
protected:
|
||||
/// add a packet source to this server, does share ownership
|
||||
void
|
||||
AddPacketSource(std::shared_ptr<PacketSource_Base> resolver);
|
||||
/// add a resolver to this packet handler, does share ownership
|
||||
void
|
||||
AddResolver(std::shared_ptr<Resolver_Base> resolver);
|
||||
|
||||
public:
|
||||
virtual ~Server() = default;
|
||||
explicit Server(EventLoop_ptr loop, llarp::DnsConfig conf);
|
||||
|
||||
/// returns all sockaddr we have from all of our PacketSources
|
||||
std::vector<SockAddr>
|
||||
BoundPacketSourceAddrs() const;
|
||||
|
||||
/// returns the first sockaddr we have on our packet sources if we have one
|
||||
std::optional<SockAddr>
|
||||
FirstBoundPacketSourceAddr() const;
|
||||
|
||||
/// add a resolver to this packet handler, does not share ownership
|
||||
void
|
||||
AddResolver(std::weak_ptr<Resolver_Base> resolver);
|
||||
|
||||
/// add a packet source to this server, does not share ownership
|
||||
void
|
||||
AddPacketSource(std::weak_ptr<PacketSource_Base> resolver);
|
||||
|
||||
/// create a packet source bound on bindaddr but does not add it
|
||||
virtual std::shared_ptr<PacketSource_Base>
|
||||
MakePacketSourceOn(const SockAddr& bindaddr, const llarp::DnsConfig& conf);
|
||||
|
||||
/// sets up all internal binds and such and begins operation
|
||||
virtual void
|
||||
Start();
|
||||
|
||||
/// stops all operation
|
||||
virtual void
|
||||
Stop();
|
||||
|
||||
/// reset the internal state
|
||||
virtual void
|
||||
Reset();
|
||||
|
||||
/// create the default resolver for out config
|
||||
virtual std::shared_ptr<Resolver_Base>
|
||||
MakeDefaultResolver();
|
||||
|
||||
/// feed a packet buffer from a packet source
|
||||
/// returns true if we decided to process the packet and consumed it
|
||||
/// returns false if we dont want to process the packet
|
||||
bool
|
||||
MaybeHandlePacket(
|
||||
std::weak_ptr<PacketSource_Base> pktsource,
|
||||
const SockAddr& resolver,
|
||||
const SockAddr& from,
|
||||
llarp::OwnedBuffer buf);
|
||||
|
||||
protected:
|
||||
EventLoop_ptr m_Loop;
|
||||
llarp::DnsConfig m_Config;
|
||||
|
||||
private:
|
||||
std::set<std::shared_ptr<Resolver_Base>, ComparePtr<std::shared_ptr<Resolver_Base>>>
|
||||
m_OwnedResolvers;
|
||||
std::set<std::weak_ptr<Resolver_Base>, CompareWeakPtr<Resolver_Base>> m_Resolvers;
|
||||
|
||||
std::vector<std::weak_ptr<PacketSource_Base>> m_PacketSources;
|
||||
std::vector<std::shared_ptr<PacketSource_Base>> m_OwnedPacketSources;
|
||||
};
|
||||
|
||||
} // namespace llarp::dns
|
||||
|
Loading…
Reference in New Issue