llarp/dns/server.hpp

Namespaces

Name
llarp
[crypto.hpp]
llarp::dns

Classes

Name
class llarp::dns::QueryJob_Base
a job handling 1 dns query
class llarp::dns::PacketSource_Base
class llarp::dns::PacketSource_Wrapper
a packet source which will override the sendto function of an wrapped packet source to construct a raw ip packet as a reply
class llarp::dns::QueryJob
non complex implementation of QueryJob_Base for use in things that only ever called on the mainloop thread
class llarp::dns::Resolver_Base
handler of dns query hooking intercepts dns for internal processing
class llarp::dns::Server

Source code

#pragma once

#include "message.hpp"
#include "platform.hpp"
#include <llarp/config/config.hpp>
#include <llarp/ev/ev.hpp>
#include <llarp/net/net.hpp>
#include <llarp/util/fs.hpp>
#include <set>

namespace llarp::dns
{
  class QueryJob_Base
  {
   protected:
    Message m_Query;

    std::atomic_flag m_Done = ATOMIC_FLAG_INIT;

   public:
    explicit QueryJob_Base(Message query) : m_Query{std::move(query)}
    {}

    virtual ~QueryJob_Base() = default;

    Message&
    Underlying()
    {
      return m_Query;
    }

    const Message&
    Underlying() const
    {
      return m_Query;
    }

    void
    Cancel();

    virtual void
    SendReply(llarp::OwnedBuffer replyBuf) = 0;
  };

  class PacketSource_Base
  {
   public:
    virtual ~PacketSource_Base() = default;

    virtual bool
    WouldLoop(const SockAddr& to, const SockAddr& from) const = 0;

    virtual void
    SendTo(const SockAddr& to, const SockAddr& from, OwnedBuffer buf) const = 0;

    virtual void
    Stop() = 0;

    virtual std::optional<SockAddr>
    BoundOn() const = 0;
  };

  class PacketSource_Wrapper : public PacketSource_Base
  {
    std::weak_ptr<PacketSource_Base> m_Wrapped;
    std::function<void(net::IPPacket)> m_WritePacket;

   public:
    explicit PacketSource_Wrapper(
        std::weak_ptr<PacketSource_Base> wrapped, std::function<void(net::IPPacket)> write_packet)
        : m_Wrapped{wrapped}, m_WritePacket{write_packet}
    {}

    bool
    WouldLoop(const SockAddr& to, const SockAddr& from) const override
    {
      if (auto ptr = m_Wrapped.lock())
        return ptr->WouldLoop(to, from);
      return true;
    }

    void
    SendTo(const SockAddr& to, const SockAddr& from, OwnedBuffer buf) const override
    {
      m_WritePacket(net::IPPacket::make_udp(from, to, std::move(buf)));
    }

    void
    Stop() override
    {
      if (auto ptr = m_Wrapped.lock())
        ptr->Stop();
    }

    std::optional<SockAddr>
    BoundOn() const override
    {
      if (auto ptr = m_Wrapped.lock())
        return ptr->BoundOn();
      return std::nullopt;
    }
  };

  class QueryJob : public QueryJob_Base, std::enable_shared_from_this<QueryJob>
  {
    std::shared_ptr<PacketSource_Base> src;
    const SockAddr resolver;
    const SockAddr asker;

   public:
    explicit QueryJob(
        std::shared_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) override
    {
      src->SendTo(asker, resolver, std::move(replyBuf));
    }
  };

  class Resolver_Base
  {
   protected:
    virtual int
    Rank() const = 0;

   public:
    virtual ~Resolver_Base() = default;

    bool
    operator<(const Resolver_Base& other) const
    {
      return Rank() < other.Rank();
    }

    bool
    operator>(const Resolver_Base& other) const
    {
      return Rank() > other.Rank();
    }

    virtual std::optional<SockAddr>
    GetLocalAddr() const
    {
      return std::nullopt;
    }

    virtual std::string_view
    ResolverName() const = 0;

    virtual void
    ResetResolver(
        [[maybe_unused]] std::optional<std::vector<SockAddr>> replace_upstream = std::nullopt)
    {}

    virtual void
    Down()
    {}

    virtual bool
    MaybeHookDNS(
        std::shared_ptr<PacketSource_Base> source,
        const Message& query,
        const SockAddr& to,
        const SockAddr& from) = 0;
  };

  // Base class for DNS proxy
  class Server : public std::enable_shared_from_this<Server>
  {
   protected:
    void
    AddPacketSource(std::shared_ptr<PacketSource_Base> resolver);
    void
    AddResolver(std::shared_ptr<Resolver_Base> resolver);

    virtual std::shared_ptr<I_Platform>
    CreatePlatform() const;

   public:
    virtual ~Server() = default;

    explicit Server(EventLoop_ptr loop, llarp::DnsConfig conf, unsigned int netif_index);

    std::vector<SockAddr>
    BoundPacketSourceAddrs() const;

    std::optional<SockAddr>
    FirstBoundPacketSourceAddr() const;

    void
    AddResolver(std::weak_ptr<Resolver_Base> resolver);

    void
    AddPacketSource(std::weak_ptr<PacketSource_Base> resolver);

    virtual std::shared_ptr<PacketSource_Base>
    MakePacketSourceOn(const SockAddr& bindaddr, const llarp::DnsConfig& conf);

    virtual void
    Start();

    virtual void
    Stop();

    virtual void
    Reset();

    virtual std::shared_ptr<Resolver_Base>
    MakeDefaultResolver();

    std::vector<std::weak_ptr<Resolver_Base>>
    GetAllResolvers() const;

    bool
    MaybeHandlePacket(
        std::shared_ptr<PacketSource_Base> pktsource,
        const SockAddr& resolver,
        const SockAddr& from,
        llarp::OwnedBuffer buf);
    void
    SetDNSMode(bool all_queries);

   protected:
    EventLoop_ptr m_Loop;
    llarp::DnsConfig m_Config;
    std::shared_ptr<I_Platform> m_Platform;

   private:
    const unsigned int m_NetIfIndex;
    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

Updated on 2026-01-10 at 22:49:45 +0000