DoT Resolver

The Dot::Resolver class is a DNS-over-TLS resolver. It shares the full instance API of Dns::Resolver but transports queries over a persistent TLS connection with RFC 7858 framing (2-byte length prefix). System name servers are reached over plain UDP by Dns::Resolver.


Construction

// Connect to a specific DoT server, default port 853
Dot::Resolver resolver("1.1.1.1");

// Custom port and reactor
Dot::Resolver resolver("dns.google", 853, &myReactor);

// Default constructor
Dot::Resolver resolver;

Dot::Resolver is neither copyable nor movable.


Host resolution (A / AAAA)

All instance methods are identical to Dns::Resolver:

Dot::Resolver resolver("1.1.1.1");

IpAddress     ip  = resolver.resolveAddress("example.com", AF_INET);
IpAddress     ip6 = resolver.resolveAddress("example.com", AF_INET6);
IpAddress     ip  = resolver.resolveAddress("example.com");

IpAddressList v4  = resolver.resolveAllAddress("example.com", AF_INET);
IpAddressList v6  = resolver.resolveAllAddress("example.com", AF_INET6);
IpAddressList all = resolver.resolveAllAddress("example.com");

// Custom timeout
IpAddress ip = resolver.resolveAddress("example.com", AF_INET,
                                        std::chrono::milliseconds(3000));

⚠️ The first query triggers a TLS handshake. Subsequent queries reuse the same connection.


Reverse DNS (PTR)

std::string name    = resolver.resolveName("1.1.1.1");
AliasList   aliases = resolver.resolveAllName("1.1.1.1");

Name servers (NS)

std::string ns  = resolver.resolveNameServer("example.com");
ServerList  nsl = resolver.resolveAllNameServer("example.com");

Start of Authority (SOA)

std::string soa = resolver.resolveAuthority("example.com");

Mail exchangers (MX)

std::string   mx  = resolver.resolveMailExchanger("example.com");
ExchangerList mxl = resolver.resolveAllMailExchanger("example.com");

Static methods

All lookup* static methods are deleted on Dot::Resolver. Use Dns::Resolver::lookup* for system-DNS queries, then use a Dot::Resolver instance for privacy-sensitive lookups:

// Resolve server address via plain DNS first
IpAddress dotServer = Dns::Resolver::lookupAddress("dns.google", AF_INET);

// Then query over TLS
Dot::Resolver resolver(dotServer.toString());
IpAddress ip = resolver.resolveAddress("example.com");

Service name resolution

resolveService is inherited from BasicDatagramResolver and remains available as a static method (it reads /etc/services locally, no network):

uint16_t port = Dot::Resolver::resolveService("https"); // 443

Debug callbacks

Same as Dns::Resolver — pre-wired in DEBUG builds, nullptr in release:

resolver.onSuccess = [](const DnsPacket& p) { /* ... */ };
resolver.onFailure = [](const DnsPacket& p) { /* ... */ };

Error handling

Same error codes as Dns::Resolver, plus:

CodeCause
Errc::TimedOutTLS handshake or query timeout
Errc::MessageTooLongFrame payload exceeds maxMsgSize (16384 bytes)
Errc::TemporaryErrorPartial read/write — internal, triggers retry

On TLS reconnection the resolver sets ALPN to "dot" before the handshake.


Protocol details

  • Transport: TLS over TCP, default port 853, max message size 16384 bytes
  • Framing: 2-byte big-endian length prefix per message (RFC 7858)
  • ALPN: "dot"
  • Connection is established lazily on first query and reused for subsequent queries
  • Reconnection is attempted automatically if the connection is found closed

Summary

FeatureSupported
Host resolution (A/AAAA)✅
Reverse DNS (PTR)✅
Name servers (NS)✅
SOA✅
Mail exchangers (MX)✅
Static lookup* methods❌ (deleted)
resolveService✅ (local, no network)
TLS transport✅
RFC 7858 framing✅
ALPN "dot"✅
Custom timeout✅
Custom reactor✅