25#ifndef JOIN_FABRIC_RESOLVER_HPP
26#define JOIN_FABRIC_RESOLVER_HPP
38#include <unordered_map>
43#include <arpa/nameser.h>
44#include <netinet/in.h>
53 template <
class Protocol>
57 using Socket =
typename Protocol::Socket;
82 uint16_t
port = Protocol::defaultPort,
95 ,
_buffer (
std::make_unique<char[]> (Protocol::maxMsgSize))
141 std::chrono::milliseconds timeout = std::chrono::seconds (5))
150 packet.flags = 1 << 8;
153 question.
host = host;
156 packet.questions.push_back (question);
158 if (
query (packet, timeout) == -1)
165 for (
auto const& answer : packet.answers)
167 if (!answer.addr.isWildcard () && (answer.type == question.
type))
169 addresses.push_back (answer.addr);
188 if (!addresses.empty ())
204 std::chrono::milliseconds timeout = std::chrono::seconds (5))
208 for (
auto const& family : {AF_INET, AF_INET6})
211 addresses.insert (addresses.end (), tmp.begin (), tmp.end ());
227 if (!addresses.empty ())
244 std::chrono::milliseconds timeout = std::chrono::seconds (5))
308 std::chrono::milliseconds timeout = std::chrono::seconds (5))
317 packet.flags = 1 << 8;
323 packet.questions.push_back (question);
325 if (
query (packet, timeout) == -1)
332 for (
auto const& answer : packet.answers)
336 aliases.insert (answer.name);
353 if (!aliases.empty ())
400 std::chrono::milliseconds timeout = std::chrono::seconds (5))
409 packet.flags = 1 << 8;
412 question.
host = host;
415 packet.questions.push_back (question);
417 if (
query (packet, timeout) == -1)
424 for (
auto const& answer : packet.answers)
428 servers.insert (answer.name);
445 if (!servers.empty ())
461 std::chrono::milliseconds timeout = std::chrono::seconds (5))
493 std::chrono::milliseconds timeout = std::chrono::seconds (5))
502 packet.flags = 1 << 8;
505 question.
host = host;
508 packet.questions.push_back (question);
510 if (
query (packet, timeout) == -1)
515 for (
auto const& answer : packet.answers)
536 if (!authority.empty ())
552 std::chrono::milliseconds timeout = std::chrono::seconds (5))
561 packet.flags = 1 << 8;
564 question.
host = host;
567 packet.questions.push_back (question);
569 if (
query (packet, timeout) == -1)
575 for (
auto const& answer : packet.answers)
579 exchangers.insert (answer.name);
597 if (!exchangers.empty ())
613 std::chrono::milliseconds timeout = std::chrono::seconds (5))
646 struct __res_state res;
647 if (res_ninit (&res) == 0)
649 for (
int i = 0; i < res.nscount; ++i)
651 if (res.nsaddr_list[i].sin_family == AF_INET)
653 addressList.emplace_back (&res.nsaddr_list[i].sin_addr, sizeof (
struct in_addr));
656 else if (res._u._ext.nsaddrs[i] !=
nullptr && res._u._ext.nsaddrs[i]->sin6_family == AF_INET6)
658 addressList.emplace_back (&res._u._ext.nsaddrs[i]->sin6_addr, sizeof (
struct in6_addr));
675 struct servent entry, *res;
678 int status = getservbyname_r (service.c_str (),
nullptr, &entry, buffer,
sizeof buffer, &res);
679 if ((status == 0) && (res !=
nullptr))
681 return ntohs (entry.s_port);
695 [[maybe_unused]] std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept
697 if (
_socket.connect (endpoint) == -1)
703 _server = endpoint.hostname ().empty () ? endpoint.ip ().toString () : endpoint.hostname ();
704 _port = endpoint.port ();
715 virtual int disconnect ([[maybe_unused]] std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept
717 if (this->
_socket.handle () == -1)
724 if (
_socket.disconnect () == -1)
739 return !
_socket.connected () ||
_socket.remoteEndpoint ().ip ().isWildcard ();
748 int reconnect (
const Endpoint& endpoint, std::chrono::milliseconds timeout = std::chrono::seconds (5))
751 return connect (endpoint, timeout);
760 virtual ssize_t
read (
char* data,
size_t maxSize)
noexcept
762 return _socket.read (data, maxSize);
771 virtual ssize_t
write (
const char* data,
size_t size)
noexcept
773 return _socket.write (data, size);
784 auto remote =
_socket.remoteEndpoint ();
786 if (remote.ip ().isWildcard ())
802 packet.
dest = remote.ip ();
803 packet.
port = remote.port ();
819 char buffer[Protocol::maxMsgSize];
829 auto inserted =
_pending.emplace (packet.
id, std::make_unique<PendingRequest> ());
830 if (!inserted.second)
839 if (
write (buffer,
static_cast<size_t> (size)) == -1)
848 if (!inserted.first->second->cond.timedWait (lock, timeout))
856 auto pendingReq = std::move (inserted.first->second);
861 lastError = pendingReq->ec;
866 packet = std::move (pendingReq->packet);
878 ssize_t size =
read (
_buffer.get (), Protocol::maxMsgSize);
882 std::error_code error;
889 auto local =
_socket.localEndpoint ();
890 auto remote =
_socket.remoteEndpoint ();
891 packet.
src = local.ip ();
892 packet.
dest = remote.ip ();
893 packet.
port = remote.port ();
895 if (packet.
flags & 0x8000)
902 it->second->packet = packet;
904 if ((packet.
flags & 0x0200) && it->second->ec == std::error_code{})
908 it->second->cond.signal ();
918 void onClose ([[maybe_unused]]
int fd)
override final
928 static void defaultOnSuccess (
const DnsPacket& packet)
930 std::cout << std::endl;
931 std::cout <<
"SERVER: " << packet.
dest <<
"#" << packet.
port << std::endl;
933 std::cout << std::endl;
934 std::cout <<
";; QUESTION SECTION: " << std::endl;
935 for (
auto const& question : packet.
questions)
937 std::cout << question.host;
940 std::cout << std::endl;
943 std::cout << std::endl;
944 std::cout <<
";; ANSWER SECTION: " << std::endl;
945 for (
auto const& answer : packet.
answers)
947 std::cout << answer.host;
950 std::cout <<
" " << answer.ttl;
953 std::cout <<
" " << answer.addr;
957 std::cout <<
" " << answer.name;
961 std::cout <<
" " << answer.name;
965 std::cout <<
" " << answer.name;
966 std::cout <<
" " << answer.mail;
967 std::cout <<
" " << answer.serial;
968 std::cout <<
" " << answer.refresh;
969 std::cout <<
" " << answer.retry;
970 std::cout <<
" " << answer.expire;
971 std::cout <<
" " << answer.minimum;
975 std::cout <<
" " << answer.name;
979 std::cout <<
" " << answer.mxpref;
980 std::cout <<
" " << answer.name;
984 std::cout <<
" " << answer.addr;
986 std::cout << std::endl;
994 static void defaultOnFailure (
const DnsPacket& packet)
996 std::cout << std::endl;
997 std::cout <<
"SERVER: " << packet.dest <<
"#" << packet.port << std::endl;
999 std::cout << std::endl;
1000 std::cout <<
";; QUESTION SECTION: " << std::endl;
1001 for (
auto const& question : packet.questions)
1003 std::cout << question.host;
1006 std::cout << std::endl;
1009 std::cout << std::endl;
1010 std::cout << lastError.message () << std::endl;
1057 std::unordered_map<uint16_t, std::unique_ptr<PendingRequest>>
_pending;
1066 template <
class Protocol>
1206 int connect (
const Endpoint& endpoint,
1207 std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept override final
1209 if (this->
_socket.connect (endpoint) == -1)
1217 if (!this->
_socket.waitConnected (timeout))
1224 this->
_server = endpoint.hostname ().empty () ? endpoint.ip ().toString () : endpoint.hostname ();
1225 this->
_port = endpoint.port ();
1227 if (this->
_socket.handshake () == -1)
1235 if (!this->
_socket.waitHandshake (timeout))
1251 int disconnect (std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept override final
1253 if (this->
_socket.handle () == -1)
1260 if (this->
_socket.shutdown () == -1)
1268 if (!this->
_socket.waitShutdown (timeout))
1275 if (!this->
_socket.waitDisconnected (timeout))
1287 void close () noexcept
1298 bool needReconnection () noexcept override final
1300 return !this->
_socket.encrypted () || this->
_socket.remoteEndpoint ().ip ().isWildcard ();
1309 ssize_t read (
char* data,
size_t maxSize)
noexcept override final
1311 if (_offset < _frameHeaderSize)
1313 ssize_t nread = this->
_socket.read (data + _offset, _frameHeaderSize - _offset);
1324 _offset +=
static_cast<size_t> (nread);
1326 if (_offset < _frameHeaderSize)
1332 _size = ntohs (*
reinterpret_cast<uint16_t*
> (data));
1334 if (_size > maxSize)
1344 this->
_socket.read (data + (_offset - _frameHeaderSize), _size - (_offset - _frameHeaderSize));
1355 _offset +=
static_cast<size_t> (nread);
1357 if (_offset < (_size + _frameHeaderSize))
1363 int msgLen =
static_cast<int> (_size);
1376 ssize_t write (
const char* data,
size_t size)
noexcept override final
1378 uint16_t msgLength = htons (
static_cast<uint16_t
> (size));
1379 const char* p =
reinterpret_cast<const char*
> (&msgLength);
1380 size_t remaining =
sizeof (msgLength);
1382 while (remaining > 0)
1384 ssize_t result = this->
_socket.write (p, remaining);
1389 if (this->
_socket.waitReadyWrite ())
1395 remaining -= result;
1401 while (remaining > 0)
1403 ssize_t result = this->
_socket.write (p, remaining);
1408 if (this->
_socket.waitReadyWrite ())
1414 remaining -= result;
1417 return static_cast<int> (size);
1421 static constexpr size_t _frameHeaderSize = 2;
basic DNS resolver over datagram socket.
Definition resolver.hpp:55
virtual int connect(const Endpoint &endpoint, std::chrono::milliseconds timeout=std::chrono::seconds(5)) noexcept
make a connection to the given endpoint.
Definition resolver.hpp:694
IpAddress resolveAddress(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name.
Definition resolver.hpp:276
static ExchangerList lookupAllMailExchanger(const std::string &host)
resolve all host mail exchanger.
Definition resolver.hpp:591
void notify(const DnsNotify &func, const DnsPacket &packet) const noexcept
safe way to notify DNS events.
Definition resolver.hpp:1019
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:182
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:222
int reconnect(const Endpoint &endpoint, std::chrono::milliseconds timeout=std::chrono::seconds(5))
reconnect to the remote DNS server.
Definition resolver.hpp:748
Mutex _syncMutex
protection mutex.
Definition resolver.hpp:1060
ExchangerList resolveAllMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host mail exchanger.
Definition resolver.hpp:551
std::function< void(const DnsPacket &)> DnsNotify
notification callback definition.
Definition resolver.hpp:61
static std::string lookupAuthority(const std::string &host)
resolve host start of authority name server.
Definition resolver.hpp:531
virtual bool needReconnection() noexcept
check if client must reconnect.
Definition resolver.hpp:737
static IpAddressList nameServers() noexcept
get IP address of the currently configured name servers.
Definition resolver.hpp:642
virtual ssize_t read(char *data, size_t maxSize) noexcept
read a DNS message.
Definition resolver.hpp:760
static IpAddress lookupAddress(const std::string &host, int family)
resolve host name using system name servers.
Definition resolver.hpp:260
void onReadable(int fd) override final
method called when data are ready to be read on handle.
Definition resolver.hpp:876
DnsNotify onSuccess
callback called when a lookup sequence succeed.
Definition resolver.hpp:64
BasicDatagramResolver(const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
Definition resolver.hpp:69
virtual int disconnect(std::chrono::milliseconds timeout=std::chrono::seconds(5)) noexcept
shutdown the connection.
Definition resolver.hpp:715
uint16_t _port
remote DNS server port.
Definition resolver.hpp:1040
Socket _socket
underlying socket.
Definition resolver.hpp:1034
static std::string lookupMailExchanger(const std::string &host)
resolve host mail exchanger.
Definition resolver.hpp:628
virtual ssize_t write(const char *data, size_t size) noexcept
write a DNS message.
Definition resolver.hpp:771
virtual ~BasicDatagramResolver() noexcept
destroy instance.
Definition resolver.hpp:128
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:243
typename Protocol::Endpoint Endpoint
Definition resolver.hpp:58
std::string _server
remote DNS server.
Definition resolver.hpp:1037
ServerList resolveAllNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host name server.
Definition resolver.hpp:399
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:140
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:492
BasicDatagramResolver(Socket &&socket, const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
construct the resolver instance.
Definition resolver.hpp:81
static std::string lookupNameServer(const std::string &host)
resolve host name server.
Definition resolver.hpp:476
BasicDatagramResolver & operator=(const BasicDatagramResolver &other)=delete
copy assignment operator.
static uint16_t resolveService(const std::string &service) noexcept
resolve service name.
Definition resolver.hpp:673
static IpAddress lookupAddress(const std::string &host)
resolve host name using system name servers.
Definition resolver.hpp:291
static ServerList lookupAllNameServer(const std::string &host)
resolve all host name server.
Definition resolver.hpp:440
std::string resolveName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host address.
Definition resolver.hpp:368
static std::string lookupName(const IpAddress &address)
resolve host address.
Definition resolver.hpp:383
void onClose(int fd) override final
method called when handle is closed.
Definition resolver.hpp:918
std::string resolveNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name server.
Definition resolver.hpp:460
DnsMessage _message
DNS message codec.
Definition resolver.hpp:1031
std::unique_ptr< char[]> _buffer
reception buffer.
Definition resolver.hpp:1046
AliasList resolveAllName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host address.
Definition resolver.hpp:307
static constexpr size_t _headerSize
DNS message header size.
Definition resolver.hpp:1028
int query(DnsPacket &packet, std::chrono::milliseconds timeout)
serialize and send a DNS query, waiting for a response.
Definition resolver.hpp:782
BasicDatagramResolver(BasicDatagramResolver &&other)=delete
move constructor.
typename Protocol::Socket Socket
Definition resolver.hpp:57
std::string resolveMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host mail exchanger.
Definition resolver.hpp:612
DnsNotify onFailure
callback called when a lookup sequence failed.
Definition resolver.hpp:67
static AliasList lookupAllName(const IpAddress &address)
resolve all host address.
Definition resolver.hpp:348
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:203
Reactor & _reactor
event loop reactor.
Definition resolver.hpp:1043
std::unordered_map< uint16_t, std::unique_ptr< PendingRequest > > _pending
synchronous requests indexed by sequence number.
Definition resolver.hpp:1057
basic DNS resolver over TLS socket (DNS over TLS).
Definition resolver.hpp:1068
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.
static std::string lookupAuthority(const std::string &host)=delete
resolve host start of authority name server.
BasicTlsResolver & operator=(const BasicTlsResolver &other)=delete
copy assignment operator.
static IpAddress lookupAddress(const std::string &host)=delete
resolve host name using system name servers.
virtual ~BasicTlsResolver() noexcept
destroy instance.
Definition resolver.hpp:1115
BasicTlsResolver(const BasicTlsResolver &other)=delete
copy constructor.
typename Socket::UnderlyingSocket UnderlyingSocket
Definition resolver.hpp:1071
BasicTlsResolver(TlsContext ctx, const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
construct the DoT resolver instance.
Definition resolver.hpp:1080
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:1072
static IpAddress lookupAddress(const std::string &host, int family)=delete
resolve host name using system name servers.
typename Protocol::Socket Socket
Definition resolver.hpp:1070
static ServerList lookupAllNameServer(const std::string &host)=delete
resolve all host name server.
BasicTlsResolver(BasicTlsResolver &&other)=delete
move constructor.
condition variable class.
Definition condition.hpp:42
DNS message codec.
Definition dns_message.hpp:104
int deserialize(DnsPacket &packet, const char *data, size_t size) const
deserialize a DNS packet from a buffer.
Definition dns_message.hpp:228
static std::string className(uint16_t recordClass)
get record class name.
Definition dns_message.hpp:356
@ A
Definition dns_message.hpp:111
@ PTR
Definition dns_message.hpp:115
@ SOA
Definition dns_message.hpp:114
@ NS
Definition dns_message.hpp:112
@ MX
Definition dns_message.hpp:116
@ CNAME
Definition dns_message.hpp:113
@ AAAA
Definition dns_message.hpp:118
ssize_t serialize(const DnsPacket &packet, char *data, size_t maxSize) const
serialize a DNS packet into a buffer.
Definition dns_message.hpp:174
static std::error_code decodeError(uint16_t error) noexcept
convert DNS error to system error code.
Definition dns_message.hpp:307
@ IN
Definition dns_message.hpp:128
static std::string typeName(uint16_t recordType)
get record type name.
Definition dns_message.hpp:332
Event handler interface class.
Definition reactor.hpp:51
IPv6, IPv4 address class.
Definition ip_address.hpp:52
bool isWildcard() const
check if IP address is a wildcard address.
Definition ip_address.cpp:1295
static bool isIpAddress(const std::string &address)
check if the specified string is an IP address.
Definition ip_address.cpp:1376
class used to protect shared data from being simultaneously accessed by multiple threads.
Definition mutex.hpp:37
static Reactor & reactor()
get the global Reactor instance.
Definition reactor.cpp:612
Reactor class.
Definition reactor.hpp:159
int delHandler(int fd, bool sync=true) noexcept
delete handler from reactor.
Definition reactor.cpp:156
int addHandler(int fd, EventHandler *handler, bool wantRead=true, bool wantWrite=false, bool sync=true) noexcept
add handler to reactor.
Definition reactor.cpp:101
class owning a mutex for the duration of a scoped block.
Definition mutex.hpp:249
TLS/DTLS context.
Definition tls_context.hpp:42
Definition acceptor.hpp:32
std::unordered_set< std::string > ExchangerList
list of mail exchangers.
Definition dns_message.hpp:51
std::unordered_set< std::string > ServerList
list of name servers.
Definition dns_message.hpp:48
std::unordered_set< std::string > AliasList
list of aliases.
Definition dns_message.hpp:45
Type randomize()
create a random number.
Definition utils.hpp:402
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
thread_local std::error_code lastError
last error.
Definition error.cpp:32
std::vector< IpAddress > IpAddressList
List of IP address.
Definition ip_address.hpp:46
pending synchronous request.
Definition resolver.hpp:1050
Condition cond
Definition resolver.hpp:1051
std::error_code ec
Definition resolver.hpp:1053
DnsPacket packet
Definition resolver.hpp:1052
DNS packet.
Definition dns_message.hpp:88
uint16_t id
Definition dns_message.hpp:89
uint16_t flags
Definition dns_message.hpp:90
uint16_t port
Definition dns_message.hpp:93
std::vector< QuestionRecord > questions
Definition dns_message.hpp:94
IpAddress src
Definition dns_message.hpp:91
IpAddress dest
Definition dns_message.hpp:92
std::vector< ResourceRecord > answers
Definition dns_message.hpp:95
question record.
Definition dns_message.hpp:57
std::string host
Definition dns_message.hpp:58
uint16_t type
Definition dns_message.hpp:59
uint16_t dnsclass
Definition dns_message.hpp:60
IpAddress address
Definition tcp_acceptor_test.cpp:35
uint16_t port
Definition tcp_acceptor_test.cpp:36