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/reactor.hpp>
32#include <join/socket.hpp>
33
34// C++.
35#include <unordered_map>
36#include <chrono>
37#include <memory>
38
39// C.
40#include <arpa/nameser.h>
41#include <netinet/in.h>
42#include <resolv.h>
43#include <netdb.h>
44
45namespace join
46{
50 template <class Protocol>
51 class BasicDatagramResolver : public Protocol::Socket, public EventHandler
52 {
53 public:
54 using Socket = typename Protocol::Socket;
55 using Endpoint = typename Protocol::Endpoint;
56 using State = typename Socket::State;
57
59 using DnsNotify = std::function<void (const DnsPacket&)>;
60
63
66
73 explicit BasicDatagramResolver (const std::string& server = {}, uint16_t port = Protocol::defaultPort,
74 Reactor& reactor = ReactorThread::reactor ())
75 : Socket ()
76#ifdef DEBUG
77 , onSuccess (defaultOnSuccess)
78 , onFailure (defaultOnFailure)
79#else
80 , onSuccess (nullptr)
81 , onFailure (nullptr)
82#endif
83 , _server (server)
84 , _port (port)
85 , _reactor (reactor)
86 , _buffer (std::make_unique<char[]> (Protocol::maxMsgSize))
87 {
88 }
89
95
102
108
115
119 virtual ~BasicDatagramResolver () noexcept = default;
120
126 virtual int connect (const Endpoint& endpoint) override
127 {
128 if (Socket::connect (endpoint) == -1)
129 {
130 return -1;
131 }
132
133 _server = endpoint.hostname ();
134 if (_server.empty ())
135 {
136 _server = endpoint.ip ().toString ();
137 }
138 _port = endpoint.port ();
139
140 this->_reactor.addHandler (this->handle (), this);
141
142 return 0;
143 }
144
149 virtual int disconnect () override
150 {
151 this->_reactor.delHandler (this->_handle);
152
153 if (Socket::disconnect () == -1)
154 {
155 return -1;
156 }
157
158 return 0;
159 }
160
168 IpAddressList resolveAllAddress (const std::string& host, int family,
169 std::chrono::milliseconds timeout = std::chrono::seconds (5))
170 {
171 if (host.empty ())
172 {
173 return {};
174 }
175
176 DnsPacket packet{};
177 packet.id = join::randomize<uint16_t> ();
178 packet.flags = 1 << 8;
179
180 QuestionRecord question;
181 question.host = host;
182 question.type = (family == AF_INET6) ? DnsMessage::RecordType::AAAA : DnsMessage::RecordType::A;
184 packet.questions.push_back (question);
185
186 if (query (packet, timeout) == -1)
187 {
188 return {};
189 }
190
191 IpAddressList addresses;
192
193 for (auto const& answer : packet.answers)
194 {
195 if (!answer.addr.isWildcard () && (answer.type == question.type))
196 {
197 addresses.push_back (answer.addr);
198 }
199 }
200
201 return addresses;
202 }
203
210 static IpAddressList lookupAllAddress (const std::string& host, int family)
211 {
212 for (auto const& server : nameServers ())
213 {
214 IpAddressList addresses =
215 BasicDatagramResolver<Protocol> (server.toString ()).resolveAllAddress (host, family);
216 if (!addresses.empty ())
217 {
218 return addresses;
219 }
220 }
221
222 return {};
223 }
224
231 IpAddressList resolveAllAddress (const std::string& host,
232 std::chrono::milliseconds timeout = std::chrono::seconds (5))
233 {
234 IpAddressList addresses;
235
236 for (auto const& family : {AF_INET, AF_INET6})
237 {
238 IpAddressList tmp = resolveAllAddress (host, family, timeout);
239 addresses.insert (addresses.end (), tmp.begin (), tmp.end ());
240 }
241
242 return addresses;
243 }
244
250 static IpAddressList lookupAllAddress (const std::string& host)
251 {
252 for (auto const& server : nameServers ())
253 {
254 IpAddressList addresses = BasicDatagramResolver<Protocol> (server.toString ()).resolveAllAddress (host);
255 if (!addresses.empty ())
256 {
257 return addresses;
258 }
259 }
260
261 return {};
262 }
263
271 IpAddress resolveAddress (const std::string& host, int family,
272 std::chrono::milliseconds timeout = std::chrono::seconds (5))
273 {
274 for (auto const& address : resolveAllAddress (host, family, timeout))
275 {
276 return address;
277 }
278
279 return IpAddress (family);
280 }
281
288 static IpAddress lookupAddress (const std::string& host, int family)
289 {
290 for (auto const& address : lookupAllAddress (host, family))
291 {
292 return address;
293 }
294
295 return IpAddress (family);
296 }
297
304 IpAddress resolveAddress (const std::string& host, std::chrono::milliseconds timeout = std::chrono::seconds (5))
305 {
306 for (auto const& address : resolveAllAddress (host, timeout))
307 {
308 return address;
309 }
310
311 return {};
312 }
313
319 static IpAddress lookupAddress (const std::string& host)
320 {
321 for (auto const& address : lookupAllAddress (host))
322 {
323 return address;
324 }
325
326 return {};
327 }
328
336 std::chrono::milliseconds timeout = std::chrono::seconds (5))
337 {
338 if (address.isWildcard ())
339 {
340 return {};
341 }
342
343 DnsPacket packet{};
344 packet.id = join::randomize<uint16_t> ();
345 packet.flags = 1 << 8;
346
347 QuestionRecord question;
348 question.host = address.toArpa ();
351 packet.questions.push_back (question);
352
353 if (query (packet, timeout) == -1)
354 {
355 return {};
356 }
357
358 AliasList aliases;
359
360 for (auto const& answer : packet.answers)
361 {
362 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::PTR))
363 {
364 aliases.insert (answer.name);
365 }
366 }
367
368 return aliases;
369 }
370
377 {
378 for (auto const& server : nameServers ())
379 {
380 AliasList aliases = BasicDatagramResolver<Protocol> (server.toString ()).resolveAllName (address);
381 if (!aliases.empty ())
382 {
383 return aliases;
384 }
385 }
386
387 return {};
388 }
389
396 std::string resolveName (const IpAddress& address, std::chrono::milliseconds timeout = std::chrono::seconds (5))
397 {
398 for (auto const& alias : resolveAllName (address, timeout))
399 {
400 return alias;
401 }
402
403 return {};
404 }
405
411 static std::string lookupName (const IpAddress& address)
412 {
413 for (auto const& alias : lookupAllName (address))
414 {
415 return alias;
416 }
417
418 return {};
419 }
420
427 ServerList resolveAllNameServer (const std::string& host,
428 std::chrono::milliseconds timeout = std::chrono::seconds (5))
429 {
430 if (host.empty ())
431 {
432 return {};
433 }
434
435 DnsPacket packet{};
436 packet.id = join::randomize<uint16_t> ();
437 packet.flags = 1 << 8;
438
439 QuestionRecord question;
440 question.host = host;
443 packet.questions.push_back (question);
444
445 if (query (packet, timeout) == -1)
446 {
447 return {};
448 }
449
450 ServerList servers;
451
452 for (auto const& answer : packet.answers)
453 {
454 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::NS))
455 {
456 servers.insert (answer.name);
457 }
458 }
459
460 return servers;
461 }
462
468 static ServerList lookupAllNameServer (const std::string& host)
469 {
470 for (auto const& server : nameServers ())
471 {
472 ServerList servers = BasicDatagramResolver<Protocol> (server.toString ()).resolveAllNameServer (host);
473 if (!servers.empty ())
474 {
475 return servers;
476 }
477 }
478
479 return {};
480 }
481
488 std::string resolveNameServer (const std::string& host,
489 std::chrono::milliseconds timeout = std::chrono::seconds (5))
490 {
491 for (auto const& server : resolveAllNameServer (host, timeout))
492 {
493 return server;
494 }
495
496 return {};
497 }
498
504 static std::string lookupNameServer (const std::string& host)
505 {
506 for (auto const& server : lookupAllNameServer (host))
507 {
508 return server;
509 }
510
511 return {};
512 }
513
520 std::string resolveAuthority (const std::string& host,
521 std::chrono::milliseconds timeout = std::chrono::seconds (5))
522 {
523 if (host.empty ())
524 {
525 return {};
526 }
527
528 DnsPacket packet{};
529 packet.id = join::randomize<uint16_t> ();
530 packet.flags = 1 << 8;
531
532 QuestionRecord question;
533 question.host = host;
536 packet.questions.push_back (question);
537
538 if (query (packet, timeout) == -1)
539 {
540 return {};
541 }
542
543 for (auto const& answer : packet.answers)
544 {
545 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::SOA))
546 {
547 return answer.name;
548 }
549 }
550
551 return {};
552 }
553
559 static std::string lookupAuthority (const std::string& host)
560 {
561 for (auto const& server : nameServers ())
562 {
563 std::string authority = BasicDatagramResolver<Protocol> (server.toString ()).resolveAuthority (host);
564 if (!authority.empty ())
565 {
566 return authority;
567 }
568 }
569
570 return {};
571 }
572
579 ExchangerList resolveAllMailExchanger (const std::string& host,
580 std::chrono::milliseconds timeout = std::chrono::seconds (5))
581 {
582 if (host.empty ())
583 {
584 return {};
585 }
586
587 DnsPacket packet{};
588 packet.id = join::randomize<uint16_t> ();
589 packet.flags = 1 << 8;
590
591 QuestionRecord question;
592 question.host = host;
595 packet.questions.push_back (question);
596
597 if (query (packet, timeout) == -1)
598 {
599 return {};
600 }
601
602 ExchangerList exchangers;
603 for (auto const& answer : packet.answers)
604 {
605 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::MX))
606 {
607 exchangers.insert (answer.name);
608 }
609 }
610
611 return exchangers;
612 }
613
619 static ExchangerList lookupAllMailExchanger (const std::string& host)
620 {
621 for (auto const& server : nameServers ())
622 {
623 ExchangerList exchangers =
624 BasicDatagramResolver<Protocol> (server.toString ()).resolveAllMailExchanger (host);
625 if (!exchangers.empty ())
626 {
627 return exchangers;
628 }
629 }
630
631 return {};
632 }
633
640 std::string resolveMailExchanger (const std::string& host,
641 std::chrono::milliseconds timeout = std::chrono::seconds (5))
642 {
643 for (auto const& exchanger : resolveAllMailExchanger (host, timeout))
644 {
645 return exchanger;
646 }
647
648 return {};
649 }
650
656 static std::string lookupMailExchanger (const std::string& host)
657 {
658 for (auto const& exchanger : lookupAllMailExchanger (host))
659 {
660 return exchanger;
661 }
662
663 return {};
664 }
665
670 static IpAddressList nameServers () noexcept
671 {
672 IpAddressList addressList;
673
674 struct __res_state res;
675 if (res_ninit (&res) == 0)
676 {
677 for (int i = 0; i < res.nscount; ++i)
678 {
679 if (res.nsaddr_list[i].sin_family == AF_INET)
680 {
681 addressList.emplace_back (&res.nsaddr_list[i].sin_addr, sizeof (struct in_addr));
682 }
683 // LCOV_EXCL_START: requires specific host IPv6 configuration.
684 else if (res._u._ext.nsaddrs[i] != nullptr && res._u._ext.nsaddrs[i]->sin6_family == AF_INET6)
685 {
686 addressList.emplace_back (&res._u._ext.nsaddrs[i]->sin6_addr, sizeof (struct in6_addr));
687 }
688 // LCOV_EXCL_STOP
689 }
690 res_nclose (&res);
691 }
692
693 return addressList;
694 }
695
701 static uint16_t resolveService (const std::string& service) noexcept
702 {
703 struct servent entry, *res;
704 char buffer[1024];
705
706 int status = getservbyname_r (service.c_str (), nullptr, &entry, buffer, sizeof buffer, &res);
707 if ((status == 0) && (res != nullptr))
708 {
709 return ntohs (entry.s_port);
710 }
711
712 return 0;
713 }
714
715 protected:
720 bool needReconnection () noexcept
721 {
722 return !this->connected ();
723 }
724
731 virtual int reconnect (const Endpoint& endpoint, [[maybe_unused]] std::chrono::milliseconds timeout)
732 {
733 if (this->disconnect () == -1)
734 {
735 // LCOV_EXCL_START
736 this->close ();
737 return -1;
738 // LCOV_EXCL_STOP
739 }
740
741 if (this->connect (endpoint) == -1)
742 {
743 this->close ();
744 return -1;
745 }
746
747 return 0;
748 }
749
756 int query (DnsPacket& packet, std::chrono::milliseconds timeout)
757 {
758 if (this->_remote.ip ().isWildcard ())
759 {
762
763 if (ip.isWildcard ())
764 {
766 notify (onFailure, packet);
767 return -1;
768 }
769
770 this->_remote.ip (ip);
771 this->_remote.port (_port);
772 }
773
774 packet.dest = this->_remote.ip ();
775 packet.port = this->_remote.port ();
776
777 if (this->needReconnection ())
778 {
779 Endpoint endpoint{packet.dest, packet.port};
780 endpoint.hostname (_server);
781
782 if (this->reconnect (endpoint, timeout) == -1)
783 {
784 notify (onFailure, packet);
785 return -1;
786 }
787 }
788
789 packet.src = this->localEndpoint ().ip ();
790
791 std::stringstream data;
792 if (_message.serialize (packet, data) == -1)
793 {
795 notify (onFailure, packet);
796 return -1;
797 }
798
799 std::string buffer = data.str ();
800 if (buffer.size () > Protocol::maxMsgSize)
801 {
803 notify (onFailure, packet);
804 return -1;
805 }
806
808
809 auto inserted = _pending.emplace (packet.id, std::make_unique<PendingRequest> ());
810 if (!inserted.second)
811 {
812 // LCOV_EXCL_START
814 notify (onFailure, packet);
815 return -1;
816 // LCOV_EXCL_STOP
817 }
818
819 if (this->write (buffer.data (), buffer.size ()) == -1)
820 {
821 // LCOV_EXCL_START
822 _pending.erase (inserted.first);
823 notify (onFailure, packet);
824 return -1;
825 // LCOV_EXCL_STOP
826 }
827
828 if (!inserted.first->second->cond.timedWait (lock, timeout))
829 {
830 _pending.erase (inserted.first);
831 lastError = make_error_code (Errc::TimedOut);
832 notify (onFailure, packet);
833 return -1;
834 }
835
836 auto pendingReq = std::move (inserted.first->second);
837 _pending.erase (inserted.first);
838
839 if (pendingReq->ec)
840 {
841 lastError = pendingReq->ec;
842 notify (onFailure, packet);
843 return -1;
844 }
845
846 packet = std::move (pendingReq->packet);
847 notify (onSuccess, packet);
848
849 return 0;
850 }
851
856 void onReadable ([[maybe_unused]] int fd) override final
857 {
858 int size = this->read (_buffer.get (), Protocol::maxMsgSize);
859 if (size >= int (_headerSize))
860 {
861 std::stringstream data;
862 data.rdbuf ()->pubsetbuf (_buffer.get (), size);
863
864 DnsPacket packet;
865 _message.deserialize (packet, data);
866 packet.src = this->localEndpoint ().ip ();
867 packet.dest = this->remoteEndpoint ().ip ();
868 packet.port = this->remoteEndpoint ().port ();
869
870 if (packet.flags & 0x8000)
871 {
873
874 auto it = _pending.find (packet.id);
875 if (it != _pending.end ())
876 {
877 it->second->packet = packet;
878 it->second->ec = DnsMessage::decodeError (packet.flags & 0x000F);
879 if ((packet.flags & 0x0200) && it->second->ec == std::error_code{})
880 {
881 it->second->ec = make_error_code (Errc::MessageTooLong);
882 }
883 it->second->cond.signal ();
884 }
885 }
886 }
887 }
888
893 void onClose ([[maybe_unused]] int fd) override final
894 {
895 this->disconnect ();
896 }
897
898#ifdef DEBUG
899 /*
900 * @brief default callback called when a lookup sequence succeed.
901 * @param packet DNS packet.
902 */
903 static void defaultOnSuccess (const DnsPacket& packet)
904 {
905 std::cout << std::endl;
906 std::cout << "SERVER: " << packet.dest << "#" << packet.port << std::endl;
907
908 std::cout << std::endl;
909 std::cout << ";; QUESTION SECTION: " << std::endl;
910 for (auto const& question : packet.questions)
911 {
912 std::cout << question.host;
913 std::cout << " " << DnsMessage::typeName (question.type);
914 std::cout << " " << DnsMessage::className (question.dnsclass);
915 std::cout << std::endl;
916 }
917
918 std::cout << std::endl;
919 std::cout << ";; ANSWER SECTION: " << std::endl;
920 for (auto const& answer : packet.answers)
921 {
922 std::cout << answer.host;
923 std::cout << " " << DnsMessage::typeName (answer.type);
924 std::cout << " " << DnsMessage::className (answer.dnsclass);
925 std::cout << " " << answer.ttl;
926 if (answer.type == DnsMessage::RecordType::A)
927 {
928 std::cout << " " << answer.addr;
929 }
930 else if (answer.type == DnsMessage::RecordType::NS)
931 {
932 std::cout << " " << answer.name;
933 }
934 else if (answer.type == DnsMessage::RecordType::CNAME)
935 {
936 std::cout << " " << answer.name;
937 }
938 else if (answer.type == DnsMessage::RecordType::SOA)
939 {
940 std::cout << " " << answer.name;
941 std::cout << " " << answer.mail;
942 std::cout << " " << answer.serial;
943 std::cout << " " << answer.refresh;
944 std::cout << " " << answer.retry;
945 std::cout << " " << answer.expire;
946 std::cout << " " << answer.minimum;
947 }
948 else if (answer.type == DnsMessage::RecordType::PTR)
949 {
950 std::cout << " " << answer.name;
951 }
952 else if (answer.type == DnsMessage::RecordType::MX)
953 {
954 std::cout << " " << answer.mxpref;
955 std::cout << " " << answer.name;
956 }
957 else if (answer.type == DnsMessage::RecordType::AAAA)
958 {
959 std::cout << " " << answer.addr;
960 }
961 std::cout << std::endl;
962 }
963 }
964
965 /*
966 * @brief default callback called when a lookup sequence failed.
967 * @param packet DNS packet.
968 */
969 static void defaultOnFailure (const DnsPacket& packet)
970 {
971 std::cout << std::endl;
972 std::cout << "SERVER: " << packet.dest << "#" << packet.port << std::endl;
973
974 std::cout << std::endl;
975 std::cout << ";; QUESTION SECTION: " << std::endl;
976 for (auto const& question : packet.questions)
977 {
978 std::cout << question.host;
979 std::cout << " " << DnsMessage::typeName (question.type);
980 std::cout << " " << DnsMessage::className (question.dnsclass);
981 std::cout << std::endl;
982 }
983
984 std::cout << std::endl;
985 std::cout << lastError.message () << std::endl;
986 }
987#endif
988
994 void notify (const DnsNotify& func, const DnsPacket& packet) const noexcept
995 {
996 if (func)
997 {
998 func (packet);
999 }
1000 }
1001
1003 static constexpr size_t _headerSize = 12;
1004
1007
1009 std::string _server;
1010
1012 uint16_t _port;
1013
1016
1018 std::unique_ptr<char[]> _buffer;
1019
1022 {
1025 std::error_code ec;
1026 };
1027
1029 std::unordered_map<uint16_t, std::unique_ptr<PendingRequest>> _pending;
1030
1033 };
1034
1038 template <class Protocol>
1040 {
1041 public:
1042 using Socket = typename Protocol::Socket;
1043 using Endpoint = typename Protocol::Endpoint;
1044 using State = typename Socket::State;
1045
1052 explicit BasicTlsResolver (const std::string& server = {}, uint16_t port = Protocol::defaultPort,
1053 Reactor& reactor = ReactorThread::reactor ())
1054 : BasicDatagramResolver<Protocol> (server, port, reactor)
1055 {
1056 }
1057
1062 BasicTlsResolver (const BasicTlsResolver& other) = delete;
1063
1070
1076
1083
1087 virtual ~BasicTlsResolver () noexcept = default;
1088
1094 virtual int connect (const Endpoint& endpoint) override
1095 {
1096 if (Socket::connect (endpoint) == -1)
1097 {
1098 return -1;
1099 }
1100
1101 this->_server = this->_remote.hostname ();
1102 if (this->_server.empty ())
1103 {
1104 this->_server = this->_remote.ip ().toString ();
1105 }
1106 this->_port = this->_remote.port ();
1107
1108 return 0;
1109 }
1110
1116 virtual int connectEncrypted (const Endpoint& endpoint) override
1117 {
1118 if (Socket::connectEncrypted (endpoint) == -1)
1119 {
1120 return -1;
1121 }
1122
1123 this->_reactor.addHandler (this->handle (), this);
1124
1125 return 0;
1126 }
1127
1133 virtual bool waitEncrypted (int timeout = 0) override
1134 {
1135 if (!Socket::waitEncrypted (timeout))
1136 {
1137 return false;
1138 }
1139
1140 this->_reactor.addHandler (this->handle (), this);
1141
1142 return true;
1143 }
1144
1150 virtual bool waitConnected (int timeout = 0) override
1151 {
1152 if (!Socket::waitConnected (timeout))
1153 {
1154 return false;
1155 }
1156
1157 this->_server = this->_remote.hostname ();
1158 if (this->_server.empty ())
1159 {
1160 this->_server = this->_remote.ip ().toString ();
1161 }
1162 this->_port = this->_remote.port ();
1163
1164 return true;
1165 }
1166
1170 virtual void close () noexcept override
1171 {
1172 Socket::close ();
1173 _size = 0;
1174 _offset = 0;
1175 }
1176
1183 virtual int read (char* data, unsigned long maxSize) noexcept override
1184 {
1185 if (_offset < _frameHeaderSize)
1186 {
1187 int nread = Socket::read (data + _offset, _frameHeaderSize - _offset);
1188 if (nread == -1)
1189 {
1190 if (lastError != Errc::TemporaryError)
1191 {
1192 _offset = 0;
1193 _size = 0;
1194 }
1195 return -1;
1196 }
1197
1198 _offset += static_cast<size_t> (nread);
1199
1200 if (_offset < _frameHeaderSize)
1201 {
1203 return -1;
1204 }
1205
1206 _size = ntohs (*reinterpret_cast<uint16_t*> (data));
1207
1208 if (_size > maxSize)
1209 {
1211 _offset = 0;
1212 _size = 0;
1213 return -1;
1214 }
1215 }
1216
1217 int nread = Socket::read (data + (_offset - _frameHeaderSize), _size - (_offset - _frameHeaderSize));
1218 if (nread == -1)
1219 {
1220 if (lastError != Errc::TemporaryError)
1221 {
1222 _offset = 0;
1223 _size = 0;
1224 }
1225 return -1;
1226 }
1227
1228 _offset += static_cast<size_t> (nread);
1229
1230 if (_offset < (_size + _frameHeaderSize))
1231 {
1233 return -1;
1234 }
1235
1236 int msgLen = static_cast<int> (_size);
1237 _offset = 0;
1238 _size = 0;
1239
1240 return msgLen;
1241 }
1242
1249 virtual int write (const char* data, unsigned long size) noexcept override
1250 {
1251 uint16_t msgLength = htons (static_cast<uint16_t> (size));
1252 const char* p = reinterpret_cast<const char*> (&msgLength);
1253 unsigned long remaining = sizeof (msgLength);
1254
1255 while (remaining > 0)
1256 {
1257 int result = Socket::write (p, remaining);
1258 if (result == -1)
1259 {
1260 if (lastError == Errc::TemporaryError)
1261 {
1262 if (this->waitReadyWrite ())
1263 continue;
1264 }
1265 return -1;
1266 }
1267 p += result;
1268 remaining -= result;
1269 }
1270
1271 p = data;
1272 remaining = size;
1273
1274 while (remaining > 0)
1275 {
1276 int result = Socket::write (p, remaining);
1277 if (result == -1)
1278 {
1279 if (lastError == Errc::TemporaryError)
1280 {
1281 if (this->waitReadyWrite ())
1282 continue;
1283 }
1284 return -1;
1285 }
1286 p += result;
1287 remaining -= result;
1288 }
1289
1290 return static_cast<int> (size);
1291 }
1292
1299 static IpAddressList lookupAllAddress (const std::string& host, int family) = delete;
1300
1306 static IpAddressList lookupAllAddress (const std::string& host) = delete;
1307
1314 static IpAddress lookupAddress (const std::string& host, int family) = delete;
1315
1321 static IpAddress lookupAddress (const std::string& host) = delete;
1322
1328 static AliasList lookupAllName (const IpAddress& address) = delete;
1329
1335 static std::string lookupName (const IpAddress& address) = delete;
1336
1342 static ServerList lookupAllNameServer (const std::string& host) = delete;
1343
1349 static std::string lookupNameServer (const std::string& host) = delete;
1350
1356 static std::string lookupAuthority (const std::string& host) = delete;
1357
1363 static ExchangerList lookupAllMailExchanger (const std::string& host) = delete;
1364
1370 static std::string lookupMailExchanger (const std::string& host) = delete;
1371
1372 private:
1379 virtual int reconnect (const Endpoint& endpoint, std::chrono::milliseconds timeout) override
1380 {
1381 if (this->disconnect () == -1)
1382 {
1383 if (lastError != Errc::TemporaryError)
1384 {
1385 // LCOV_EXCL_START
1386 this->close ();
1387 return -1;
1388 // LCOV_EXCL_STOP
1389 }
1390
1391 if (!this->waitDisconnected (timeout.count ()))
1392 {
1393 this->close ();
1394 return -1;
1395 }
1396 }
1397
1398 this->setAlpnProtocols ({"dot"});
1399
1400 if (this->connectEncrypted (endpoint) == -1)
1401 {
1402 if (lastError != Errc::TemporaryError)
1403 {
1404 this->close ();
1405 return -1;
1406 }
1407
1408 if (!this->waitEncrypted (timeout.count ()))
1409 {
1410 this->close ();
1411 return -1;
1412 }
1413 }
1414
1415 return 0;
1416 }
1417
1419 static constexpr size_t _frameHeaderSize = 2;
1420
1422 size_t _size = 0;
1423
1425 size_t _offset = 0;
1426 };
1427}
1428
1429#endif
basic DNS resolver over datagram socket.
Definition resolver.hpp:52
IpAddress resolveAddress(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name.
Definition resolver.hpp:304
static ExchangerList lookupAllMailExchanger(const std::string &host)
resolve all host mail exchanger.
Definition resolver.hpp:619
void notify(const DnsNotify &func, const DnsPacket &packet) const noexcept
safe way to notify DNS events.
Definition resolver.hpp:994
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:210
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:250
Mutex _syncMutex
protection mutex.
Definition resolver.hpp:1032
ExchangerList resolveAllMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host mail exchanger.
Definition resolver.hpp:579
virtual int connect(const Endpoint &endpoint) override
make a connection to the given endpoint.
Definition resolver.hpp:126
std::function< void(const DnsPacket &)> DnsNotify
notification callback definition.
Definition resolver.hpp:59
static std::string lookupAuthority(const std::string &host)
resolve host start of authority name server.
Definition resolver.hpp:559
bool needReconnection() noexcept
check if client must reconnect.
Definition resolver.hpp:720
static IpAddressList nameServers() noexcept
get IP address of the currently configured name servers.
Definition resolver.hpp:670
static IpAddress lookupAddress(const std::string &host, int family)
resolve host name using system name servers.
Definition resolver.hpp:288
void onReadable(int fd) override final
method called when data are ready to be read on handle.
Definition resolver.hpp:856
DnsNotify onSuccess
callback called when a lookup sequence succeed.
Definition resolver.hpp:62
BasicDatagramResolver(const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
construct the resolver instance.
Definition resolver.hpp:73
uint16_t _port
remote DNS server port.
Definition resolver.hpp:1012
static std::string lookupMailExchanger(const std::string &host)
resolve host mail exchanger.
Definition resolver.hpp:656
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:271
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:731
typename Protocol::Endpoint Endpoint
Definition resolver.hpp:55
std::string _server
remote DNS server.
Definition resolver.hpp:1009
ServerList resolveAllNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host name server.
Definition resolver.hpp:427
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:168
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:520
static std::string lookupNameServer(const std::string &host)
resolve host name server.
Definition resolver.hpp:504
BasicDatagramResolver & operator=(const BasicDatagramResolver &other)=delete
copy assignment operator.
typename Socket::State State
Definition resolver.hpp:56
static uint16_t resolveService(const std::string &service) noexcept
resolve service name.
Definition resolver.hpp:701
static IpAddress lookupAddress(const std::string &host)
resolve host name using system name servers.
Definition resolver.hpp:319
static ServerList lookupAllNameServer(const std::string &host)
resolve all host name server.
Definition resolver.hpp:468
virtual int disconnect() override
shutdown the connection.
Definition resolver.hpp:149
std::string resolveName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host address.
Definition resolver.hpp:396
static std::string lookupName(const IpAddress &address)
resolve host address.
Definition resolver.hpp:411
void onClose(int fd) override final
method called when handle is closed.
Definition resolver.hpp:893
std::string resolveNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name server.
Definition resolver.hpp:488
DnsMessage _message
DNS message codec.
Definition resolver.hpp:1006
std::unique_ptr< char[]> _buffer
reception buffer.
Definition resolver.hpp:1018
AliasList resolveAllName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host address.
Definition resolver.hpp:335
static constexpr size_t _headerSize
DNS message header size.
Definition resolver.hpp:1003
int query(DnsPacket &packet, std::chrono::milliseconds timeout)
serialize and send a DNS query, waiting for a response.
Definition resolver.hpp:756
BasicDatagramResolver(BasicDatagramResolver &&other)=delete
move constructor.
typename Protocol::Socket Socket
Definition resolver.hpp:54
std::string resolveMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host mail exchanger.
Definition resolver.hpp:640
DnsNotify onFailure
callback called when a lookup sequence failed.
Definition resolver.hpp:65
static AliasList lookupAllName(const IpAddress &address)
resolve all host address.
Definition resolver.hpp:376
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:231
Reactor & _reactor
event loop reactor.
Definition resolver.hpp:1015
std::unordered_map< uint16_t, std::unique_ptr< PendingRequest > > _pending
synchronous requests indexed by sequence number.
Definition resolver.hpp:1029
basic DNS resolver over TLS socket (DNS over TLS).
Definition resolver.hpp:1040
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.
virtual int write(const char *data, unsigned long size) noexcept override
write a framed DoT message (2-byte length prefix).
Definition resolver.hpp:1249
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:1116
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:1170
typename Socket::State State
Definition resolver.hpp:1044
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.
BasicTlsResolver(const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
construct the DoT resolver instance.
Definition resolver.hpp:1052
typename Protocol::Endpoint Endpoint
Definition resolver.hpp:1043
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:1150
typename Protocol::Socket Socket
Definition resolver.hpp:1042
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:1133
virtual ~BasicTlsResolver() noexcept=default
destroy instance.
virtual int connect(const Endpoint &endpoint) override
make a connection to the given endpoint.
Definition resolver.hpp:1094
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:1183
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
Event handler interface class.
Definition reactor.hpp:46
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
static Reactor & reactor()
get the global Reactor instance.
Definition reactor.cpp:514
Reactor class.
Definition reactor.hpp:129
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
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:1022
Condition cond
Definition resolver.hpp:1023
std::error_code ec
Definition resolver.hpp:1025
DnsPacket packet
Definition resolver.hpp:1024
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