join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
resolver.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_FABRIC_RESOLVER_HPP
26#define JOIN_FABRIC_RESOLVER_HPP
27
28// libjoin.
29#include <join/dnsmessage.hpp>
30#include <join/condition.hpp>
31#include <join/socket.hpp>
32
33// C++.
34#include <unordered_map>
35#include <chrono>
36#include <memory>
37
38// C.
39#include <arpa/nameser.h>
40#include <netinet/in.h>
41#include <resolv.h>
42#include <netdb.h>
43
44namespace join
45{
49 template <class Protocol>
50 class BasicDatagramResolver : public Protocol::Socket
51 {
52 public:
53 using Socket = typename Protocol::Socket;
54 using Endpoint = typename Protocol::Endpoint;
55 using State = typename Socket::State;
56
63 explicit BasicDatagramResolver (const std::string& server = {}, uint16_t port = Protocol::defaultPort,
64 Reactor* reactor = nullptr)
65 : Socket ()
66#ifdef DEBUG
67 , _onSuccess (defaultOnSuccess)
68 , _onFailure (defaultOnFailure)
69#else
70 , _onSuccess (nullptr)
71 , _onFailure (nullptr)
72#endif
73 , _server (server)
74 , _port (port)
75 , _reactor (reactor ? reactor : ReactorThread::reactor ())
76 , _buffer (std::make_unique<char[]> (Protocol::maxMsgSize))
77 {
78 }
79
85
92
98
105
109 virtual ~BasicDatagramResolver () noexcept = default;
110
116 virtual int connect (const Endpoint& endpoint) override
117 {
118 if (Socket::connect (endpoint) == -1)
119 {
120 return -1;
121 }
122
123 _server = endpoint.hostname ();
124 if (_server.empty ())
125 {
126 _server = endpoint.ip ().toString ();
127 }
128 _port = endpoint.port ();
129
130 this->_reactor->addHandler (this->handle (), this);
131
132 return 0;
133 }
134
139 virtual int disconnect () override
140 {
141 this->_reactor->delHandler (this->_handle);
142
143 if (Socket::disconnect () == -1)
144 {
145 return -1;
146 }
147
148 return 0;
149 }
150
158 IpAddressList resolveAllAddress (const std::string& host, int family,
159 std::chrono::milliseconds timeout = std::chrono::seconds (5))
160 {
161 if (host.empty ())
162 {
163 return {};
164 }
165
166 DnsPacket packet{};
167 packet.id = join::randomize<uint16_t> ();
168 packet.flags = 1 << 8;
169
170 QuestionRecord question;
171 question.host = host;
172 question.type = (family == AF_INET6) ? DnsMessage::RecordType::AAAA : DnsMessage::RecordType::A;
174 packet.questions.push_back (question);
175
176 if (query (packet, timeout) == -1)
177 {
178 return {};
179 }
180
181 IpAddressList addresses;
182
183 for (auto const& answer : packet.answers)
184 {
185 if (!answer.addr.isWildcard () && (answer.type == question.type))
186 {
187 addresses.push_back (answer.addr);
188 }
189 }
190
191 return addresses;
192 }
193
200 static IpAddressList lookupAllAddress (const std::string& host, int family)
201 {
202 for (auto const& server : nameServers ())
203 {
204 IpAddressList addresses =
205 BasicDatagramResolver<Protocol> (server.toString ()).resolveAllAddress (host, family);
206 if (!addresses.empty ())
207 {
208 return addresses;
209 }
210 }
211
212 return {};
213 }
214
221 IpAddressList resolveAllAddress (const std::string& host,
222 std::chrono::milliseconds timeout = std::chrono::seconds (5))
223 {
224 IpAddressList addresses;
225
226 for (auto const& family : {AF_INET, AF_INET6})
227 {
228 IpAddressList tmp = resolveAllAddress (host, family, timeout);
229 addresses.insert (addresses.end (), tmp.begin (), tmp.end ());
230 }
231
232 return addresses;
233 }
234
240 static IpAddressList lookupAllAddress (const std::string& host)
241 {
242 for (auto const& server : nameServers ())
243 {
244 IpAddressList addresses = BasicDatagramResolver<Protocol> (server.toString ()).resolveAllAddress (host);
245 if (!addresses.empty ())
246 {
247 return addresses;
248 }
249 }
250
251 return {};
252 }
253
261 IpAddress resolveAddress (const std::string& host, int family,
262 std::chrono::milliseconds timeout = std::chrono::seconds (5))
263 {
264 for (auto const& address : resolveAllAddress (host, family, timeout))
265 {
266 return address;
267 }
268
269 return IpAddress (family);
270 }
271
278 static IpAddress lookupAddress (const std::string& host, int family)
279 {
280 for (auto const& address : lookupAllAddress (host, family))
281 {
282 return address;
283 }
284
285 return IpAddress (family);
286 }
287
294 IpAddress resolveAddress (const std::string& host, std::chrono::milliseconds timeout = std::chrono::seconds (5))
295 {
296 for (auto const& address : resolveAllAddress (host, timeout))
297 {
298 return address;
299 }
300
301 return {};
302 }
303
309 static IpAddress lookupAddress (const std::string& host)
310 {
311 for (auto const& address : lookupAllAddress (host))
312 {
313 return address;
314 }
315
316 return {};
317 }
318
326 std::chrono::milliseconds timeout = std::chrono::seconds (5))
327 {
328 if (address.isWildcard ())
329 {
330 return {};
331 }
332
333 DnsPacket packet{};
334 packet.id = join::randomize<uint16_t> ();
335 packet.flags = 1 << 8;
336
337 QuestionRecord question;
338 question.host = address.toArpa ();
341 packet.questions.push_back (question);
342
343 if (query (packet, timeout) == -1)
344 {
345 return {};
346 }
347
348 AliasList aliases;
349
350 for (auto const& answer : packet.answers)
351 {
352 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::PTR))
353 {
354 aliases.insert (answer.name);
355 }
356 }
357
358 return aliases;
359 }
360
367 {
368 for (auto const& server : nameServers ())
369 {
370 AliasList aliases = BasicDatagramResolver<Protocol> (server.toString ()).resolveAllName (address);
371 if (!aliases.empty ())
372 {
373 return aliases;
374 }
375 }
376
377 return {};
378 }
379
386 std::string resolveName (const IpAddress& address, std::chrono::milliseconds timeout = std::chrono::seconds (5))
387 {
388 for (auto const& alias : resolveAllName (address, timeout))
389 {
390 return alias;
391 }
392
393 return {};
394 }
395
401 static std::string lookupName (const IpAddress& address)
402 {
403 for (auto const& alias : lookupAllName (address))
404 {
405 return alias;
406 }
407
408 return {};
409 }
410
417 ServerList resolveAllNameServer (const std::string& host,
418 std::chrono::milliseconds timeout = std::chrono::seconds (5))
419 {
420 if (host.empty ())
421 {
422 return {};
423 }
424
425 DnsPacket packet{};
426 packet.id = join::randomize<uint16_t> ();
427 packet.flags = 1 << 8;
428
429 QuestionRecord question;
430 question.host = host;
433 packet.questions.push_back (question);
434
435 if (query (packet, timeout) == -1)
436 {
437 return {};
438 }
439
440 ServerList servers;
441
442 for (auto const& answer : packet.answers)
443 {
444 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::NS))
445 {
446 servers.insert (answer.name);
447 }
448 }
449
450 return servers;
451 }
452
458 static ServerList lookupAllNameServer (const std::string& host)
459 {
460 for (auto const& server : nameServers ())
461 {
462 ServerList servers = BasicDatagramResolver<Protocol> (server.toString ()).resolveAllNameServer (host);
463 if (!servers.empty ())
464 {
465 return servers;
466 }
467 }
468
469 return {};
470 }
471
478 std::string resolveNameServer (const std::string& host,
479 std::chrono::milliseconds timeout = std::chrono::seconds (5))
480 {
481 for (auto const& server : resolveAllNameServer (host, timeout))
482 {
483 return server;
484 }
485
486 return {};
487 }
488
494 static std::string lookupNameServer (const std::string& host)
495 {
496 for (auto const& server : lookupAllNameServer (host))
497 {
498 return server;
499 }
500
501 return {};
502 }
503
510 std::string resolveAuthority (const std::string& host,
511 std::chrono::milliseconds timeout = std::chrono::seconds (5))
512 {
513 if (host.empty ())
514 {
515 return {};
516 }
517
518 DnsPacket packet{};
519 packet.id = join::randomize<uint16_t> ();
520 packet.flags = 1 << 8;
521
522 QuestionRecord question;
523 question.host = host;
526 packet.questions.push_back (question);
527
528 if (query (packet, timeout) == -1)
529 {
530 return {};
531 }
532
533 for (auto const& answer : packet.answers)
534 {
535 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::SOA))
536 {
537 return answer.name;
538 }
539 }
540
541 return {};
542 }
543
549 static std::string lookupAuthority (const std::string& host)
550 {
551 for (auto const& server : nameServers ())
552 {
553 std::string authority = BasicDatagramResolver<Protocol> (server.toString ()).resolveAuthority (host);
554 if (!authority.empty ())
555 {
556 return authority;
557 }
558 }
559
560 return {};
561 }
562
569 ExchangerList resolveAllMailExchanger (const std::string& host,
570 std::chrono::milliseconds timeout = std::chrono::seconds (5))
571 {
572 if (host.empty ())
573 {
574 return {};
575 }
576
577 DnsPacket packet{};
578 packet.id = join::randomize<uint16_t> ();
579 packet.flags = 1 << 8;
580
581 QuestionRecord question;
582 question.host = host;
585 packet.questions.push_back (question);
586
587 if (query (packet, timeout) == -1)
588 {
589 return {};
590 }
591
592 ExchangerList exchangers;
593 for (auto const& answer : packet.answers)
594 {
595 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::MX))
596 {
597 exchangers.insert (answer.name);
598 }
599 }
600
601 return exchangers;
602 }
603
609 static ExchangerList lookupAllMailExchanger (const std::string& host)
610 {
611 for (auto const& server : nameServers ())
612 {
613 ExchangerList exchangers =
614 BasicDatagramResolver<Protocol> (server.toString ()).resolveAllMailExchanger (host);
615 if (!exchangers.empty ())
616 {
617 return exchangers;
618 }
619 }
620
621 return {};
622 }
623
630 std::string resolveMailExchanger (const std::string& host,
631 std::chrono::milliseconds timeout = std::chrono::seconds (5))
632 {
633 for (auto const& exchanger : resolveAllMailExchanger (host, timeout))
634 {
635 return exchanger;
636 }
637
638 return {};
639 }
640
646 static std::string lookupMailExchanger (const std::string& host)
647 {
648 for (auto const& exchanger : lookupAllMailExchanger (host))
649 {
650 return exchanger;
651 }
652
653 return {};
654 }
655
660 static IpAddressList nameServers () noexcept
661 {
662 IpAddressList addressList;
663
664 struct __res_state res;
665 if (res_ninit (&res) == 0)
666 {
667 for (int i = 0; i < res.nscount; ++i)
668 {
669 if (res.nsaddr_list[i].sin_family == AF_INET)
670 {
671 addressList.emplace_back (&res.nsaddr_list[i].sin_addr, sizeof (struct in_addr));
672 }
673 // LCOV_EXCL_START: requires specific host IPv6 configuration.
674 else if (res._u._ext.nsaddrs[i] != nullptr && res._u._ext.nsaddrs[i]->sin6_family == AF_INET6)
675 {
676 addressList.emplace_back (&res._u._ext.nsaddrs[i]->sin6_addr, sizeof (struct in6_addr));
677 }
678 // LCOV_EXCL_STOP
679 }
680 res_nclose (&res);
681 }
682
683 return addressList;
684 }
685
691 static uint16_t resolveService (const std::string& service) noexcept
692 {
693 struct servent entry, *res;
694 char buffer[1024];
695
696 int status = getservbyname_r (service.c_str (), nullptr, &entry, buffer, sizeof buffer, &res);
697 if ((status == 0) && (res != nullptr))
698 {
699 return ntohs (entry.s_port);
700 }
701
702 return 0;
703 }
704
706 using DnsNotify = std::function<void (const DnsPacket&)>;
707
710
713
714 protected:
719 bool needReconnection () noexcept
720 {
721 return !this->connected ();
722 }
723
730 virtual int reconnect (const Endpoint& endpoint, [[maybe_unused]] std::chrono::milliseconds timeout)
731 {
732 if (this->disconnect () == -1)
733 {
734 this->close ();
735 return -1;
736 }
737
738 if (this->connect (endpoint) == -1)
739 {
740 this->close ();
741 return -1;
742 }
743
744 return 0;
745 }
746
753 int query (DnsPacket& packet, std::chrono::milliseconds timeout)
754 {
755 if (this->_remote.ip ().isWildcard ())
756 {
759
760 if (ip.isWildcard ())
761 {
763 notify (_onFailure, packet);
764 return -1;
765 }
766
767 this->_remote.ip (ip);
768 this->_remote.port (_port);
769 }
770
771 packet.dest = this->_remote.ip ();
772 packet.port = this->_remote.port ();
773
774 if (this->needReconnection ())
775 {
776 Endpoint endpoint{packet.dest, packet.port};
777 endpoint.hostname (_server);
778
779 if (this->reconnect (endpoint, timeout) == -1)
780 {
781 notify (_onFailure, packet);
782 return -1;
783 }
784 }
785
786 packet.src = this->localEndpoint ().ip ();
787
788 std::stringstream data;
789 if (_message.serialize (packet, data) == -1)
790 {
792 notify (_onFailure, packet);
793 return -1;
794 }
795
796 std::string buffer = data.str ();
797 if (buffer.size () > Protocol::maxMsgSize)
798 {
800 notify (_onFailure, packet);
801 return -1;
802 }
803
805
806 auto inserted = _pending.emplace (packet.id, std::make_unique<PendingRequest> ());
807 if (!inserted.second)
808 {
810 notify (_onFailure, packet);
811 return -1;
812 }
813
814 if (this->write (buffer.data (), buffer.size ()) == -1)
815 {
816 _pending.erase (inserted.first);
817 notify (_onFailure, packet);
818 return -1;
819 }
820
821 if (!inserted.first->second->cond.timedWait (lock, timeout))
822 {
823 _pending.erase (inserted.first);
824 lastError = make_error_code (Errc::TimedOut);
825 notify (_onFailure, packet);
826 return -1;
827 }
828
829 auto pendingReq = std::move (inserted.first->second);
830 _pending.erase (inserted.first);
831
832 if (pendingReq->ec)
833 {
834 lastError = pendingReq->ec;
835 notify (_onFailure, packet);
836 return -1;
837 }
838
839 packet = std::move (pendingReq->packet);
840 notify (_onSuccess, packet);
841
842 return 0;
843 }
844
849 void onReceive ([[maybe_unused]] int fd) override final
850 {
851 int size = this->read (_buffer.get (), Protocol::maxMsgSize);
852 if (size >= int (_headerSize))
853 {
854 std::stringstream data;
855 data.rdbuf ()->pubsetbuf (_buffer.get (), size);
856
857 DnsPacket packet;
858 _message.deserialize (packet, data);
859 packet.src = this->localEndpoint ().ip ();
860 packet.dest = this->remoteEndpoint ().ip ();
861 packet.port = this->remoteEndpoint ().port ();
862
863 if (packet.flags & 0x8000)
864 {
866
867 auto it = _pending.find (packet.id);
868 if (it != _pending.end ())
869 {
870 it->second->packet = packet;
871 it->second->ec = DnsMessage::decodeError (packet.flags & 0x000F);
872 if ((packet.flags & 0x0200) && it->second->ec == std::error_code{})
873 {
874 it->second->ec = make_error_code (Errc::MessageTooLong);
875 }
876 it->second->cond.signal ();
877 }
878 }
879 }
880 }
881
886 void onClose ([[maybe_unused]] int fd) override final
887 {
888 this->disconnect ();
889 }
890
891#ifdef DEBUG
892 /*
893 * @brief default callback called when a lookup sequence succeed.
894 * @param packet DNS packet.
895 */
896 static void defaultOnSuccess (const DnsPacket& packet)
897 {
898 std::cout << std::endl;
899 std::cout << "SERVER: " << packet.dest << "#" << packet.port << std::endl;
900
901 std::cout << std::endl;
902 std::cout << ";; QUESTION SECTION: " << std::endl;
903 for (auto const& question : packet.questions)
904 {
905 std::cout << question.host;
906 std::cout << " " << DnsMessage::typeName (question.type);
907 std::cout << " " << DnsMessage::className (question.dnsclass);
908 std::cout << std::endl;
909 }
910
911 std::cout << std::endl;
912 std::cout << ";; ANSWER SECTION: " << std::endl;
913 for (auto const& answer : packet.answers)
914 {
915 std::cout << answer.host;
916 std::cout << " " << DnsMessage::typeName (answer.type);
917 std::cout << " " << DnsMessage::className (answer.dnsclass);
918 std::cout << " " << answer.ttl;
919 if (answer.type == DnsMessage::RecordType::A)
920 {
921 std::cout << " " << answer.addr;
922 }
923 else if (answer.type == DnsMessage::RecordType::NS)
924 {
925 std::cout << " " << answer.name;
926 }
927 else if (answer.type == DnsMessage::RecordType::CNAME)
928 {
929 std::cout << " " << answer.name;
930 }
931 else if (answer.type == DnsMessage::RecordType::SOA)
932 {
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;
940 }
941 else if (answer.type == DnsMessage::RecordType::PTR)
942 {
943 std::cout << " " << answer.name;
944 }
945 else if (answer.type == DnsMessage::RecordType::MX)
946 {
947 std::cout << " " << answer.mxpref;
948 std::cout << " " << answer.name;
949 }
950 else if (answer.type == DnsMessage::RecordType::AAAA)
951 {
952 std::cout << " " << answer.addr;
953 }
954 std::cout << std::endl;
955 }
956 }
957
958 /*
959 * @brief default callback called when a lookup sequence failed.
960 * @param packet DNS packet.
961 */
962 static void defaultOnFailure (const DnsPacket& packet)
963 {
964 std::cout << std::endl;
965 std::cout << "SERVER: " << packet.dest << "#" << packet.port << std::endl;
966
967 std::cout << std::endl;
968 std::cout << ";; QUESTION SECTION: " << std::endl;
969 for (auto const& question : packet.questions)
970 {
971 std::cout << question.host;
972 std::cout << " " << DnsMessage::typeName (question.type);
973 std::cout << " " << DnsMessage::className (question.dnsclass);
974 std::cout << std::endl;
975 }
976
977 std::cout << std::endl;
978 std::cout << lastError.message () << std::endl;
979 }
980#endif
981
987 void notify (const DnsNotify& func, const DnsPacket& packet) const noexcept
988 {
989 if (func)
990 {
991 func (packet);
992 }
993 }
994
996 static constexpr size_t _headerSize = 12;
997
1000
1002 std::string _server;
1003
1005 uint16_t _port;
1006
1009
1011 std::unique_ptr<char[]> _buffer;
1012
1015 {
1018 std::error_code ec;
1019 };
1020
1022 std::unordered_map<uint16_t, std::unique_ptr<PendingRequest>> _pending;
1023
1026 };
1027
1031 template <class Protocol>
1033 {
1034 public:
1035 using Socket = typename Protocol::Socket;
1036 using Endpoint = typename Protocol::Endpoint;
1037 using State = typename Socket::State;
1038
1045 explicit BasicTlsResolver (const std::string& server = {}, uint16_t port = Protocol::defaultPort,
1046 Reactor* reactor = nullptr)
1047 : BasicDatagramResolver<Protocol> (server, port, reactor)
1048 {
1049 }
1050
1055 BasicTlsResolver (const BasicTlsResolver& other) = delete;
1056
1063
1069
1076
1080 virtual ~BasicTlsResolver () noexcept = default;
1081
1087 virtual int connect (const Endpoint& endpoint) override
1088 {
1089 if (Socket::connect (endpoint) == -1)
1090 {
1091 return -1;
1092 }
1093
1094 this->_server = this->_remote.hostname ();
1095 if (this->_server.empty ())
1096 {
1097 this->_server = this->_remote.ip ().toString ();
1098 }
1099 this->_port = this->_remote.port ();
1100
1101 return 0;
1102 }
1103
1109 virtual int connectEncrypted (const Endpoint& endpoint) override
1110 {
1111 if (Socket::connectEncrypted (endpoint) == -1)
1112 {
1113 return -1;
1114 }
1115
1116 this->_reactor->addHandler (this->handle (), this);
1117
1118 return 0;
1119 }
1120
1126 virtual bool waitEncrypted (int timeout = 0) override
1127 {
1128 if (!Socket::waitEncrypted (timeout))
1129 {
1130 return false;
1131 }
1132
1133 this->_reactor->addHandler (this->handle (), this);
1134
1135 return true;
1136 }
1137
1143 virtual bool waitConnected (int timeout = 0) override
1144 {
1145 if (!Socket::waitConnected (timeout))
1146 {
1147 return false;
1148 }
1149
1150 this->_server = this->_remote.hostname ();
1151 if (this->_server.empty ())
1152 {
1153 this->_server = this->_remote.ip ().toString ();
1154 }
1155 this->_port = this->_remote.port ();
1156
1157 return true;
1158 }
1159
1163 virtual void close () noexcept override
1164 {
1165 Socket::close ();
1166 _size = 0;
1167 _offset = 0;
1168 }
1169
1176 virtual int read (char* data, unsigned long maxSize) noexcept override
1177 {
1178 if (_offset < _frameHeaderSize)
1179 {
1180 int nread = Socket::read (data + _offset, _frameHeaderSize - _offset);
1181 if (nread == -1)
1182 {
1183 if (lastError != Errc::TemporaryError)
1184 {
1185 _offset = 0;
1186 _size = 0;
1187 }
1188 return -1;
1189 }
1190
1191 _offset += static_cast<size_t> (nread);
1192
1193 if (_offset < _frameHeaderSize)
1194 {
1196 return -1;
1197 }
1198
1199 _size = ntohs (*reinterpret_cast<uint16_t*> (data));
1200
1201 if (_size > maxSize)
1202 {
1204 _offset = 0;
1205 _size = 0;
1206 return -1;
1207 }
1208 }
1209
1210 int nread = Socket::read (data + (_offset - _frameHeaderSize), _size - (_offset - _frameHeaderSize));
1211 if (nread == -1)
1212 {
1213 if (lastError != Errc::TemporaryError)
1214 {
1215 _offset = 0;
1216 _size = 0;
1217 }
1218 return -1;
1219 }
1220
1221 _offset += static_cast<size_t> (nread);
1222
1223 if (_offset < (_size + _frameHeaderSize))
1224 {
1226 return -1;
1227 }
1228
1229 int msgLen = static_cast<int> (_size);
1230 _offset = 0;
1231 _size = 0;
1232
1233 return msgLen;
1234 }
1235
1242 virtual int write (const char* data, unsigned long size) noexcept override
1243 {
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);
1247
1248 while (remaining > 0)
1249 {
1250 int result = Socket::write (p, remaining);
1251 if (result == -1)
1252 {
1253 if (lastError == Errc::TemporaryError)
1254 {
1255 if (this->waitReadyWrite ())
1256 continue;
1257 }
1258 return -1;
1259 }
1260 p += result;
1261 remaining -= result;
1262 }
1263
1264 p = data;
1265 remaining = size;
1266
1267 while (remaining > 0)
1268 {
1269 int result = Socket::write (p, remaining);
1270 if (result == -1)
1271 {
1272 if (lastError == Errc::TemporaryError)
1273 {
1274 if (this->waitReadyWrite ())
1275 continue;
1276 }
1277 return -1;
1278 }
1279 p += result;
1280 remaining -= result;
1281 }
1282
1283 return static_cast<int> (size);
1284 }
1285
1292 static IpAddressList lookupAllAddress (const std::string& host, int family) = delete;
1293
1299 static IpAddressList lookupAllAddress (const std::string& host) = delete;
1300
1307 static IpAddress lookupAddress (const std::string& host, int family) = delete;
1308
1314 static IpAddress lookupAddress (const std::string& host) = delete;
1315
1321 static AliasList lookupAllName (const IpAddress& address) = delete;
1322
1328 static std::string lookupName (const IpAddress& address) = delete;
1329
1335 static ServerList lookupAllNameServer (const std::string& host) = delete;
1336
1342 static std::string lookupNameServer (const std::string& host) = delete;
1343
1349 static std::string lookupAuthority (const std::string& host) = delete;
1350
1356 static ExchangerList lookupAllMailExchanger (const std::string& host) = delete;
1357
1363 static std::string lookupMailExchanger (const std::string& host) = delete;
1364
1365 private:
1372 virtual int reconnect (const Endpoint& endpoint, std::chrono::milliseconds timeout) override
1373 {
1374 if (this->disconnect () == -1)
1375 {
1376 if (lastError != Errc::TemporaryError)
1377 {
1378 this->close ();
1379 return -1;
1380 }
1381
1382 if (!this->waitDisconnected (timeout.count ()))
1383 {
1384 this->close ();
1385 return -1;
1386 }
1387 }
1388
1389 this->setAlpnProtocols ({"dot"});
1390
1391 if (this->connectEncrypted (endpoint) == -1)
1392 {
1393 if (lastError != Errc::TemporaryError)
1394 {
1395 this->close ();
1396 return -1;
1397 }
1398
1399 if (!this->waitEncrypted (timeout.count ()))
1400 {
1401 this->close ();
1402 return -1;
1403 }
1404 }
1405
1406 return 0;
1407 }
1408
1410 static constexpr size_t _frameHeaderSize = 2;
1411
1413 size_t _size = 0;
1414
1416 size_t _offset = 0;
1417 };
1418}
1419
1420#endif
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
Definition error.hpp:137
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