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 std::stringstream data;
827 std::string buffer = data.str ();
828 if (buffer.size () > Protocol::maxMsgSize)
837 auto inserted =
_pending.emplace (packet.
id, std::make_unique<PendingRequest> ());
838 if (!inserted.second)
847 if (
write (buffer.data (), buffer.size ()) == -1)
856 if (!inserted.first->second->cond.timedWait (lock, timeout))
864 auto pendingReq = std::move (inserted.first->second);
869 lastError = pendingReq->ec;
874 packet = std::move (pendingReq->packet);
886 ssize_t size =
read (
_buffer.get (), Protocol::maxMsgSize);
889 std::stringstream data;
890 data.rdbuf ()->pubsetbuf (
_buffer.get (), size);
894 auto local =
_socket.localEndpoint ();
895 auto remote =
_socket.remoteEndpoint ();
896 packet.
src = local.ip ();
897 packet.
dest = remote.ip ();
898 packet.
port = remote.port ();
900 if (packet.
flags & 0x8000)
907 it->second->packet = packet;
909 if ((packet.
flags & 0x0200) && it->second->ec == std::error_code{})
913 it->second->cond.signal ();
923 void onClose ([[maybe_unused]]
int fd)
override final
933 static void defaultOnSuccess (
const DnsPacket& packet)
935 std::cout << std::endl;
936 std::cout <<
"SERVER: " << packet.
dest <<
"#" << packet.
port << std::endl;
938 std::cout << std::endl;
939 std::cout <<
";; QUESTION SECTION: " << std::endl;
940 for (
auto const& question : packet.
questions)
942 std::cout << question.host;
945 std::cout << std::endl;
948 std::cout << std::endl;
949 std::cout <<
";; ANSWER SECTION: " << std::endl;
950 for (
auto const& answer : packet.
answers)
952 std::cout << answer.host;
955 std::cout <<
" " << answer.ttl;
958 std::cout <<
" " << answer.addr;
962 std::cout <<
" " << answer.name;
966 std::cout <<
" " << answer.name;
970 std::cout <<
" " << answer.name;
971 std::cout <<
" " << answer.mail;
972 std::cout <<
" " << answer.serial;
973 std::cout <<
" " << answer.refresh;
974 std::cout <<
" " << answer.retry;
975 std::cout <<
" " << answer.expire;
976 std::cout <<
" " << answer.minimum;
980 std::cout <<
" " << answer.name;
984 std::cout <<
" " << answer.mxpref;
985 std::cout <<
" " << answer.name;
989 std::cout <<
" " << answer.addr;
991 std::cout << std::endl;
999 static void defaultOnFailure (
const DnsPacket& packet)
1001 std::cout << std::endl;
1002 std::cout <<
"SERVER: " << packet.dest <<
"#" << packet.port << std::endl;
1004 std::cout << std::endl;
1005 std::cout <<
";; QUESTION SECTION: " << std::endl;
1006 for (
auto const& question : packet.questions)
1008 std::cout << question.host;
1011 std::cout << std::endl;
1014 std::cout << std::endl;
1015 std::cout << lastError.message () << std::endl;
1062 std::unordered_map<uint16_t, std::unique_ptr<PendingRequest>>
_pending;
1071 template <
class Protocol>
1211 int connect (
const Endpoint& endpoint,
1212 std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept override final
1214 if (this->
_socket.connect (endpoint) == -1)
1222 if (!this->
_socket.waitConnected (timeout))
1229 this->
_server = endpoint.hostname ().empty () ? endpoint.ip ().toString () : endpoint.hostname ();
1230 this->
_port = endpoint.port ();
1232 if (this->
_socket.handshake () == -1)
1240 if (!this->
_socket.waitHandshake (timeout))
1256 int disconnect (std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept override final
1258 if (this->
_socket.handle () == -1)
1265 if (this->
_socket.shutdown () == -1)
1273 if (!this->
_socket.waitShutdown (timeout))
1280 if (!this->
_socket.waitDisconnected (timeout))
1292 void close () noexcept
1303 bool needReconnection () noexcept override final
1305 return !this->
_socket.encrypted () || this->
_socket.remoteEndpoint ().ip ().isWildcard ();
1314 ssize_t read (
char* data,
size_t maxSize)
noexcept override final
1316 if (_offset < _frameHeaderSize)
1318 ssize_t nread = this->
_socket.read (data + _offset, _frameHeaderSize - _offset);
1329 _offset +=
static_cast<size_t> (nread);
1331 if (_offset < _frameHeaderSize)
1337 _size = ntohs (*
reinterpret_cast<uint16_t*
> (data));
1339 if (_size > maxSize)
1349 this->
_socket.read (data + (_offset - _frameHeaderSize), _size - (_offset - _frameHeaderSize));
1360 _offset +=
static_cast<size_t> (nread);
1362 if (_offset < (_size + _frameHeaderSize))
1368 int msgLen =
static_cast<int> (_size);
1381 ssize_t write (
const char* data,
size_t size)
noexcept override final
1383 uint16_t msgLength = htons (
static_cast<uint16_t
> (size));
1384 const char* p =
reinterpret_cast<const char*
> (&msgLength);
1385 size_t remaining =
sizeof (msgLength);
1387 while (remaining > 0)
1389 ssize_t result = this->
_socket.write (p, remaining);
1394 if (this->
_socket.waitReadyWrite ())
1400 remaining -= result;
1406 while (remaining > 0)
1408 ssize_t result = this->
_socket.write (p, remaining);
1413 if (this->
_socket.waitReadyWrite ())
1419 remaining -= result;
1422 return static_cast<int> (size);
1426 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:1024
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:1065
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:884
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:1045
Socket _socket
underlying socket.
Definition resolver.hpp:1039
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:1042
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:923
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:1036
std::unique_ptr< char[]> _buffer
reception buffer.
Definition resolver.hpp:1051
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:1033
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:1048
std::unordered_map< uint16_t, std::unique_ptr< PendingRequest > > _pending
synchronous requests indexed by sequence number.
Definition resolver.hpp:1062
basic DNS resolver over TLS socket (DNS over TLS).
Definition resolver.hpp:1073
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:1120
BasicTlsResolver(const BasicTlsResolver &other)=delete
copy constructor.
typename Socket::UnderlyingSocket UnderlyingSocket
Definition resolver.hpp:1076
BasicTlsResolver(TlsContext ctx, const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
construct the DoT resolver instance.
Definition resolver.hpp:1085
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:1077
static IpAddress lookupAddress(const std::string &host, int family)=delete
resolve host name using system name servers.
typename Protocol::Socket Socket
Definition resolver.hpp:1075
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:105
int serialize(const DnsPacket &packet, std::stringstream &data) const
serialize a DNS packet into a byte stream.
Definition dns_message.hpp:174
static std::string className(uint16_t recordClass)
get record class name.
Definition dns_message.hpp:360
@ A
Definition dns_message.hpp:112
@ PTR
Definition dns_message.hpp:116
@ SOA
Definition dns_message.hpp:115
@ NS
Definition dns_message.hpp:113
@ MX
Definition dns_message.hpp:117
@ CNAME
Definition dns_message.hpp:114
@ AAAA
Definition dns_message.hpp:119
int deserialize(DnsPacket &packet, std::stringstream &data) const
deserialize a DNS packet from a byte stream.
Definition dns_message.hpp:235
static std::error_code decodeError(uint16_t error) noexcept
convert DNS error to system error code.
Definition dns_message.hpp:311
@ IN
Definition dns_message.hpp:129
static std::string typeName(uint16_t recordType)
get record type name.
Definition dns_message.hpp:336
Event handler interface class.
Definition reactor.hpp:48
IPv6, IPv4 address class.
Definition ip_address.hpp:51
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:584
Reactor class.
Definition reactor.hpp:156
int delHandler(int fd, bool sync=true) noexcept
delete handler from reactor.
Definition reactor.cpp:155
int addHandler(int fd, EventHandler *handler, bool wantRead=true, bool wantWrite=false, bool sync=true) noexcept
add handler to reactor.
Definition reactor.cpp:100
class owning a mutex for the duration of a scoped block.
Definition mutex.hpp:246
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:52
std::unordered_set< std::string > ServerList
list of name servers.
Definition dns_message.hpp:49
std::enable_if_t< std::numeric_limits< Type >::is_integer, Type > randomize()
create a random number.
Definition utils.hpp:434
std::unordered_set< std::string > AliasList
list of aliases.
Definition dns_message.hpp:46
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
std::vector< IpAddress > IpAddressList
List of IP address.
Definition ip_address.hpp:45
pending synchronous request.
Definition resolver.hpp:1055
Condition cond
Definition resolver.hpp:1056
std::error_code ec
Definition resolver.hpp:1058
DnsPacket packet
Definition resolver.hpp:1057
DNS packet.
Definition dns_message.hpp:89
uint16_t id
Definition dns_message.hpp:90
uint16_t flags
Definition dns_message.hpp:91
uint16_t port
Definition dns_message.hpp:94
std::vector< QuestionRecord > questions
Definition dns_message.hpp:95
IpAddress src
Definition dns_message.hpp:92
IpAddress dest
Definition dns_message.hpp:93
std::vector< ResourceRecord > answers
Definition dns_message.hpp:96
question record.
Definition dns_message.hpp:58
std::string host
Definition dns_message.hpp:59
uint16_t type
Definition dns_message.hpp:60
uint16_t dnsclass
Definition dns_message.hpp:61
IpAddress address
Definition tcp_acceptor_test.cpp:35
uint16_t port
Definition tcp_acceptor_test.cpp:36