25#ifndef JOIN_FABRIC_RESOLVER_HPP
26#define JOIN_FABRIC_RESOLVER_HPP
34#include <unordered_map>
39#include <arpa/nameser.h>
40#include <netinet/in.h>
49 template <
class Protocol>
53 using Socket =
typename Protocol::Socket;
55 using State =
typename Socket::State;
76 ,
_buffer (
std::make_unique<char[]> (Protocol::maxMsgSize))
118 if (Socket::connect (endpoint) == -1)
123 _server = endpoint.hostname ();
126 _server = endpoint.ip ().toString ();
128 _port = endpoint.port ();
130 this->_reactor->addHandler (this->handle (),
this);
143 if (Socket::disconnect () == -1)
159 std::chrono::milliseconds timeout = std::chrono::seconds (5))
168 packet.flags = 1 << 8;
171 question.
host = host;
174 packet.questions.push_back (question);
176 if (
query (packet, timeout) == -1)
183 for (
auto const& answer : packet.answers)
185 if (!answer.addr.isWildcard () && (answer.type == question.
type))
187 addresses.push_back (answer.addr);
206 if (!addresses.empty ())
222 std::chrono::milliseconds timeout = std::chrono::seconds (5))
226 for (
auto const& family : {AF_INET, AF_INET6})
229 addresses.insert (addresses.end (), tmp.begin (), tmp.end ());
245 if (!addresses.empty ())
262 std::chrono::milliseconds timeout = std::chrono::seconds (5))
326 std::chrono::milliseconds timeout = std::chrono::seconds (5))
335 packet.flags = 1 << 8;
341 packet.questions.push_back (question);
343 if (
query (packet, timeout) == -1)
350 for (
auto const& answer : packet.answers)
354 aliases.insert (answer.name);
371 if (!aliases.empty ())
418 std::chrono::milliseconds timeout = std::chrono::seconds (5))
427 packet.flags = 1 << 8;
430 question.
host = host;
433 packet.questions.push_back (question);
435 if (
query (packet, timeout) == -1)
442 for (
auto const& answer : packet.answers)
446 servers.insert (answer.name);
463 if (!servers.empty ())
479 std::chrono::milliseconds timeout = std::chrono::seconds (5))
511 std::chrono::milliseconds timeout = std::chrono::seconds (5))
520 packet.flags = 1 << 8;
523 question.
host = host;
526 packet.questions.push_back (question);
528 if (
query (packet, timeout) == -1)
533 for (
auto const& answer : packet.answers)
554 if (!authority.empty ())
570 std::chrono::milliseconds timeout = std::chrono::seconds (5))
579 packet.flags = 1 << 8;
582 question.
host = host;
585 packet.questions.push_back (question);
587 if (
query (packet, timeout) == -1)
593 for (
auto const& answer : packet.answers)
597 exchangers.insert (answer.name);
615 if (!exchangers.empty ())
631 std::chrono::milliseconds timeout = std::chrono::seconds (5))
664 struct __res_state res;
665 if (res_ninit (&res) == 0)
667 for (
int i = 0; i < res.nscount; ++i)
669 if (res.nsaddr_list[i].sin_family == AF_INET)
671 addressList.emplace_back (&res.nsaddr_list[i].sin_addr, sizeof (
struct in_addr));
674 else if (res._u._ext.nsaddrs[i] !=
nullptr && res._u._ext.nsaddrs[i]->sin6_family == AF_INET6)
676 addressList.emplace_back (&res._u._ext.nsaddrs[i]->sin6_addr, sizeof (
struct in6_addr));
693 struct servent entry, *res;
696 int status = getservbyname_r (service.c_str (),
nullptr, &entry, buffer,
sizeof buffer, &res);
697 if ((status == 0) && (res !=
nullptr))
699 return ntohs (entry.s_port);
721 return !this->connected ();
730 virtual int reconnect (
const Endpoint& endpoint, [[maybe_unused]] std::chrono::milliseconds timeout)
738 if (this->
connect (endpoint) == -1)
755 if (this->_remote.ip ().isWildcard ())
767 this->_remote.ip (ip);
768 this->_remote.port (
_port);
771 packet.
dest = this->_remote.ip ();
772 packet.
port = this->_remote.port ();
779 if (this->
reconnect (endpoint, timeout) == -1)
786 packet.
src = this->localEndpoint ().ip ();
788 std::stringstream data;
796 std::string buffer = data.str ();
797 if (buffer.size () > Protocol::maxMsgSize)
806 auto inserted =
_pending.emplace (packet.
id, std::make_unique<PendingRequest> ());
807 if (!inserted.second)
814 if (this->write (buffer.data (), buffer.size ()) == -1)
821 if (!inserted.first->second->cond.timedWait (lock, timeout))
829 auto pendingReq = std::move (inserted.first->second);
834 lastError = pendingReq->ec;
839 packet = std::move (pendingReq->packet);
851 int size = this->read (
_buffer.get (), Protocol::maxMsgSize);
854 std::stringstream data;
855 data.rdbuf ()->pubsetbuf (
_buffer.get (), size);
859 packet.
src = this->localEndpoint ().ip ();
860 packet.
dest = this->remoteEndpoint ().ip ();
861 packet.
port = this->remoteEndpoint ().port ();
863 if (packet.
flags & 0x8000)
870 it->second->packet = packet;
872 if ((packet.
flags & 0x0200) && it->second->ec == std::error_code{})
876 it->second->cond.signal ();
886 void onClose ([[maybe_unused]]
int fd)
override final
896 static void defaultOnSuccess (
const DnsPacket& packet)
898 std::cout << std::endl;
899 std::cout <<
"SERVER: " << packet.
dest <<
"#" << packet.
port << std::endl;
901 std::cout << std::endl;
902 std::cout <<
";; QUESTION SECTION: " << std::endl;
903 for (
auto const& question : packet.
questions)
905 std::cout << question.host;
908 std::cout << std::endl;
911 std::cout << std::endl;
912 std::cout <<
";; ANSWER SECTION: " << std::endl;
913 for (
auto const& answer : packet.
answers)
915 std::cout << answer.host;
918 std::cout <<
" " << answer.ttl;
921 std::cout <<
" " << answer.addr;
925 std::cout <<
" " << answer.name;
929 std::cout <<
" " << answer.name;
933 std::cout <<
" " << answer.name;
934 std::cout <<
" " << answer.mail;
935 std::cout <<
" " << answer.serial;
936 std::cout <<
" " << answer.refresh;
937 std::cout <<
" " << answer.retry;
938 std::cout <<
" " << answer.expire;
939 std::cout <<
" " << answer.minimum;
943 std::cout <<
" " << answer.name;
947 std::cout <<
" " << answer.mxpref;
948 std::cout <<
" " << answer.name;
952 std::cout <<
" " << answer.addr;
954 std::cout << std::endl;
962 static void defaultOnFailure (
const DnsPacket& packet)
964 std::cout << std::endl;
965 std::cout <<
"SERVER: " << packet.dest <<
"#" << packet.port << std::endl;
967 std::cout << std::endl;
968 std::cout <<
";; QUESTION SECTION: " << std::endl;
969 for (
auto const& question : packet.questions)
971 std::cout << question.host;
974 std::cout << std::endl;
977 std::cout << std::endl;
978 std::cout << lastError.message () << std::endl;
1022 std::unordered_map<uint16_t, std::unique_ptr<PendingRequest>>
_pending;
1031 template <
class Protocol>
1089 if (Socket::connect (endpoint) == -1)
1094 this->
_server = this->_remote.hostname ();
1097 this->_server = this->_remote.ip ().toString ();
1099 this->_port = this->_remote.port ();
1111 if (Socket::connectEncrypted (endpoint) == -1)
1128 if (!Socket::waitEncrypted (timeout))
1145 if (!Socket::waitConnected (timeout))
1150 this->
_server = this->_remote.hostname ();
1153 this->
_server = this->_remote.ip ().toString ();
1155 this->
_port = this->_remote.port ();
1176 virtual int read (
char* data,
unsigned long maxSize)
noexcept override
1178 if (_offset < _frameHeaderSize)
1180 int nread = Socket::read (data + _offset, _frameHeaderSize - _offset);
1191 _offset +=
static_cast<size_t> (nread);
1193 if (_offset < _frameHeaderSize)
1199 _size = ntohs (*
reinterpret_cast<uint16_t*
> (data));
1201 if (_size > maxSize)
1210 int nread = Socket::read (data + (_offset - _frameHeaderSize), _size - (_offset - _frameHeaderSize));
1221 _offset +=
static_cast<size_t> (nread);
1223 if (_offset < (_size + _frameHeaderSize))
1229 int msgLen =
static_cast<int> (_size);
1242 virtual int write (
const char* data,
unsigned long size)
noexcept override
1244 uint16_t msgLength = htons (
static_cast<uint16_t
> (size));
1245 const char* p =
reinterpret_cast<const char*
> (&msgLength);
1246 unsigned long remaining =
sizeof (msgLength);
1248 while (remaining > 0)
1250 int result = Socket::write (p, remaining);
1255 if (this->waitReadyWrite ())
1261 remaining -= result;
1267 while (remaining > 0)
1269 int result = Socket::write (p, remaining);
1274 if (this->waitReadyWrite ())
1280 remaining -= result;
1283 return static_cast<int> (size);
1372 virtual int reconnect (
const Endpoint& endpoint, std::chrono::milliseconds timeout)
override
1382 if (!this->waitDisconnected (timeout.count ()))
1389 this->setAlpnProtocols ({
"dot"});
1410 static constexpr size_t _frameHeaderSize = 2;
basic DNS resolver over datagram socket.
Definition resolver.hpp:51
IpAddress resolveAddress(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name.
Definition resolver.hpp:294
static ExchangerList lookupAllMailExchanger(const std::string &host)
resolve all host mail exchanger.
Definition resolver.hpp:609
void notify(const DnsNotify &func, const DnsPacket &packet) const noexcept
safe way to notify DNS events.
Definition resolver.hpp:987
static IpAddressList lookupAllAddress(const std::string &host, int family)
resolve host name using system name servers and return all IP addresses found.
Definition resolver.hpp:200
BasicDatagramResolver(const BasicDatagramResolver &other)=delete
copy constructor.
static IpAddressList lookupAllAddress(const std::string &host)
resolve host name using system name servers and return all IP addresses found.
Definition resolver.hpp:240
Mutex _syncMutex
protection mutex.
Definition resolver.hpp:1025
ExchangerList resolveAllMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host mail exchanger.
Definition resolver.hpp:569
virtual int connect(const Endpoint &endpoint) override
make a connection to the given endpoint.
Definition resolver.hpp:116
std::function< void(const DnsPacket &)> DnsNotify
notification callback definition.
Definition resolver.hpp:706
static std::string lookupAuthority(const std::string &host)
resolve host start of authority name server.
Definition resolver.hpp:549
bool needReconnection() noexcept
check if client must reconnect.
Definition resolver.hpp:719
void onReceive(int fd) override final
method called when data are ready to be read on handle.
Definition resolver.hpp:849
static IpAddressList nameServers() noexcept
get IP address of the currently configured name servers.
Definition resolver.hpp:660
static IpAddress lookupAddress(const std::string &host, int family)
resolve host name using system name servers.
Definition resolver.hpp:278
Reactor * _reactor
event loop reactor.
Definition resolver.hpp:1008
DnsNotify _onSuccess
callback called when a lookup sequence succeed.
Definition resolver.hpp:709
uint16_t _port
remote DNS server port.
Definition resolver.hpp:1005
static std::string lookupMailExchanger(const std::string &host)
resolve host mail exchanger.
Definition resolver.hpp:646
IpAddress resolveAddress(const std::string &host, int family, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name using address family.
Definition resolver.hpp:261
virtual ~BasicDatagramResolver() noexcept=default
destroy instance.
virtual int reconnect(const Endpoint &endpoint, std::chrono::milliseconds timeout)
reconnect to the remote DNS server.
Definition resolver.hpp:730
typename Protocol::Endpoint Endpoint
Definition resolver.hpp:54
std::string _server
remote DNS server.
Definition resolver.hpp:1002
ServerList resolveAllNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host name server.
Definition resolver.hpp:417
IpAddressList resolveAllAddress(const std::string &host, int family, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name and return all IP addresses found.
Definition resolver.hpp:158
std::string resolveAuthority(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host start of authority name server.
Definition resolver.hpp:510
static std::string lookupNameServer(const std::string &host)
resolve host name server.
Definition resolver.hpp:494
BasicDatagramResolver & operator=(const BasicDatagramResolver &other)=delete
copy assignment operator.
typename Socket::State State
Definition resolver.hpp:55
static uint16_t resolveService(const std::string &service) noexcept
resolve service name.
Definition resolver.hpp:691
static IpAddress lookupAddress(const std::string &host)
resolve host name using system name servers.
Definition resolver.hpp:309
BasicDatagramResolver(const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor *reactor=nullptr)
construct the resolver instance.
Definition resolver.hpp:63
DnsNotify _onFailure
callback called when a lookup sequence failed.
Definition resolver.hpp:712
static ServerList lookupAllNameServer(const std::string &host)
resolve all host name server.
Definition resolver.hpp:458
virtual int disconnect() override
shutdown the connection.
Definition resolver.hpp:139
std::string resolveName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host address.
Definition resolver.hpp:386
static std::string lookupName(const IpAddress &address)
resolve host address.
Definition resolver.hpp:401
void onClose(int fd) override final
method called when handle is closed.
Definition resolver.hpp:886
std::string resolveNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name server.
Definition resolver.hpp:478
DnsMessage _message
DNS message codec.
Definition resolver.hpp:999
std::unique_ptr< char[]> _buffer
reception buffer.
Definition resolver.hpp:1011
AliasList resolveAllName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host address.
Definition resolver.hpp:325
static constexpr size_t _headerSize
DNS message header size.
Definition resolver.hpp:996
int query(DnsPacket &packet, std::chrono::milliseconds timeout)
serialize and send a DNS query, waiting for a response.
Definition resolver.hpp:753
BasicDatagramResolver(BasicDatagramResolver &&other)=delete
move constructor.
typename Protocol::Socket Socket
Definition resolver.hpp:53
std::string resolveMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host mail exchanger.
Definition resolver.hpp:630
static AliasList lookupAllName(const IpAddress &address)
resolve all host address.
Definition resolver.hpp:366
IpAddressList resolveAllAddress(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name and return all IP addresses found.
Definition resolver.hpp:221
std::unordered_map< uint16_t, std::unique_ptr< PendingRequest > > _pending
synchronous requests indexed by sequence number.
Definition resolver.hpp:1022
basic DNS resolver over TLS socket (DNS over TLS).
Definition resolver.hpp:1033
static IpAddressList lookupAllAddress(const std::string &host)=delete
resolve host name using system name servers and return all IP addresses found.
static std::string lookupNameServer(const std::string &host)=delete
resolve host name server.
static std::string lookupMailExchanger(const std::string &host)=delete
resolve host mail exchanger.
BasicTlsResolver(const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor *reactor=nullptr)
construct the DoT resolver instance.
Definition resolver.hpp:1045
static std::string lookupAuthority(const std::string &host)=delete
resolve host start of authority name server.
virtual int write(const char *data, unsigned long size) noexcept override
write a framed DoT message (2-byte length prefix).
Definition resolver.hpp:1242
BasicTlsResolver & operator=(const BasicTlsResolver &other)=delete
copy assignment operator.
virtual int connectEncrypted(const Endpoint &endpoint) override
make an encrypted connection to the given endpoint.
Definition resolver.hpp:1109
static IpAddress lookupAddress(const std::string &host)=delete
resolve host name using system name servers.
BasicTlsResolver(const BasicTlsResolver &other)=delete
copy constructor.
virtual void close() noexcept override
close the TLS connection and reset framing state.
Definition resolver.hpp:1163
typename Socket::State State
Definition resolver.hpp:1037
static AliasList lookupAllName(const IpAddress &address)=delete
resolve all host address.
static IpAddressList lookupAllAddress(const std::string &host, int family)=delete
resolve host name using system name servers and return all IP addresses found.
static ExchangerList lookupAllMailExchanger(const std::string &host)=delete
resolve all host mail exchanger.
static std::string lookupName(const IpAddress &address)=delete
resolve host address.
typename Protocol::Endpoint Endpoint
Definition resolver.hpp:1036
static IpAddress lookupAddress(const std::string &host, int family)=delete
resolve host name using system name servers.
virtual bool waitConnected(int timeout=0) override
block until connected.
Definition resolver.hpp:1143
typename Protocol::Socket Socket
Definition resolver.hpp:1035
static ServerList lookupAllNameServer(const std::string &host)=delete
resolve all host name server.
virtual bool waitEncrypted(int timeout=0) override
wait until TLS handshake is performed or timeout occur (non blocking socket).
Definition resolver.hpp:1126
virtual ~BasicTlsResolver() noexcept=default
destroy instance.
virtual int connect(const Endpoint &endpoint) override
make a connection to the given endpoint.
Definition resolver.hpp:1087
BasicTlsResolver(BasicTlsResolver &&other)=delete
move constructor.
virtual int read(char *data, unsigned long maxSize) noexcept override
read a framed DoT message (2-byte length prefix).
Definition resolver.hpp:1176
condition variable class.
Definition condition.hpp:42
DNS message codec.
Definition dnsmessage.hpp:105
int serialize(const DnsPacket &packet, std::stringstream &data) const
serialize a DNS packet into a byte stream.
Definition dnsmessage.hpp:174
static std::string className(uint16_t recordClass)
get record class name.
Definition dnsmessage.hpp:360
@ A
Definition dnsmessage.hpp:112
@ PTR
Definition dnsmessage.hpp:116
@ SOA
Definition dnsmessage.hpp:115
@ NS
Definition dnsmessage.hpp:113
@ MX
Definition dnsmessage.hpp:117
@ CNAME
Definition dnsmessage.hpp:114
@ AAAA
Definition dnsmessage.hpp:119
int deserialize(DnsPacket &packet, std::stringstream &data) const
deserialize a DNS packet from a byte stream.
Definition dnsmessage.hpp:235
static std::error_code decodeError(uint16_t error) noexcept
convert DNS error to system error code.
Definition dnsmessage.hpp:311
@ IN
Definition dnsmessage.hpp:129
static std::string typeName(uint16_t recordType)
get record type name.
Definition dnsmessage.hpp:336
IPv6, IPv4 address class.
Definition ipaddress.hpp:51
bool isWildcard() const
check if IP address is a wildcard address.
Definition ipaddress.cpp:1295
static bool isIpAddress(const std::string &address)
check if the specified string is an IP address.
Definition ipaddress.cpp:1376
class used to protect shared data from being simultaneously accessed by multiple threads.
Definition mutex.hpp:37
Convenience class that owns a Reactor running on a dedicated background thread.
Definition reactor.hpp:316
Reactor class.
Definition reactor.hpp:120
int delHandler(int fd, bool sync=true) noexcept
delete handler from reactor.
Definition reactor.cpp:150
int addHandler(int fd, EventHandler *handler, bool sync=true) noexcept
add handler to reactor.
Definition reactor.cpp:94
class owning a mutex for the duration of a scoped block.
Definition mutex.hpp:246
Definition acceptor.hpp:32
std::unordered_set< std::string > ExchangerList
list of mail exchangers.
Definition dnsmessage.hpp:52
std::unordered_set< std::string > ServerList
list of name servers.
Definition dnsmessage.hpp:49
std::enable_if_t< std::numeric_limits< Type >::is_integer, Type > randomize()
create a random number.
Definition utils.hpp:403
std::unordered_set< std::string > AliasList
list of aliases.
Definition dnsmessage.hpp:46
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:150
std::vector< IpAddress > IpAddressList
List of IP address.
Definition ipaddress.hpp:45
pending synchronous request.
Definition resolver.hpp:1015
Condition cond
Definition resolver.hpp:1016
std::error_code ec
Definition resolver.hpp:1018
DnsPacket packet
Definition resolver.hpp:1017
DNS packet.
Definition dnsmessage.hpp:89
uint16_t id
Definition dnsmessage.hpp:90
uint16_t flags
Definition dnsmessage.hpp:91
uint16_t port
Definition dnsmessage.hpp:94
std::vector< QuestionRecord > questions
Definition dnsmessage.hpp:95
IpAddress src
Definition dnsmessage.hpp:92
IpAddress dest
Definition dnsmessage.hpp:93
std::vector< ResourceRecord > answers
Definition dnsmessage.hpp:96
question record.
Definition dnsmessage.hpp:58
std::string host
Definition dnsmessage.hpp:59
uint16_t type
Definition dnsmessage.hpp:60
uint16_t dnsclass
Definition dnsmessage.hpp:61
IpAddress address
Definition tcpacceptor_test.cpp:35
uint16_t port
Definition tcpacceptor_test.cpp:36