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.
30#include <join/dns_protocol.hpp>
31#include <join/dot_protocol.hpp>
32#include <join/tls_wrapper.hpp>
33#include <join/dns_message.hpp>
34#include <join/condition.hpp>
35#include <join/reactor.hpp>
36
37// C++.
38#include <unordered_map>
39#include <chrono>
40#include <memory>
41
42// C.
43#include <arpa/nameser.h>
44#include <netinet/in.h>
45#include <resolv.h>
46#include <netdb.h>
47
48namespace join
49{
53 template <class Protocol>
55 {
56 public:
57 using Socket = typename Protocol::Socket;
58 using Endpoint = typename Protocol::Endpoint;
59
61 using DnsNotify = std::function<void (const DnsPacket&)>;
62
65
68
69 explicit BasicDatagramResolver (const std::string& server = {}, uint16_t port = Protocol::defaultPort,
70 Reactor& reactor = ReactorThread::reactor ())
71 : BasicDatagramResolver (Socket{}, server, port, reactor)
72 {
73 }
74
81 explicit BasicDatagramResolver (Socket&& socket, const std::string& server = {},
82 uint16_t port = Protocol::defaultPort,
83 Reactor& reactor = ReactorThread::reactor ())
84#ifdef DEBUG
85 : onSuccess (defaultOnSuccess)
86 , onFailure (defaultOnFailure)
87#else
88 : onSuccess (nullptr)
89 , onFailure (nullptr)
90#endif
91 , _socket (std::move (socket))
92 , _server (server)
93 , _port (port)
94 , _reactor (reactor)
95 , _buffer (std::make_unique<char[]> (Protocol::maxMsgSize))
96 {
97 }
98
104
111
117
124
128 virtual ~BasicDatagramResolver () noexcept
129 {
130 disconnect ();
131 }
132
140 IpAddressList resolveAllAddress (const std::string& host, int family,
141 std::chrono::milliseconds timeout = std::chrono::seconds (5))
142 {
143 if (host.empty ())
144 {
145 return {};
146 }
147
148 DnsPacket packet{};
149 packet.id = join::randomize<uint16_t> ();
150 packet.flags = 1 << 8;
151
152 QuestionRecord question;
153 question.host = host;
154 question.type = (family == AF_INET6) ? DnsMessage::RecordType::AAAA : DnsMessage::RecordType::A;
156 packet.questions.push_back (question);
157
158 if (query (packet, timeout) == -1)
159 {
160 return {};
161 }
162
163 IpAddressList addresses;
164
165 for (auto const& answer : packet.answers)
166 {
167 if (!answer.addr.isWildcard () && (answer.type == question.type))
168 {
169 addresses.push_back (answer.addr);
170 }
171 }
172
173 return addresses;
174 }
175
182 static IpAddressList lookupAllAddress (const std::string& host, int family)
183 {
184 for (auto const& server : nameServers ())
185 {
186 IpAddressList addresses =
187 BasicDatagramResolver<Protocol> (server.toString ()).resolveAllAddress (host, family);
188 if (!addresses.empty ())
189 {
190 return addresses;
191 }
192 }
193
194 return {};
195 }
196
203 IpAddressList resolveAllAddress (const std::string& host,
204 std::chrono::milliseconds timeout = std::chrono::seconds (5))
205 {
206 IpAddressList addresses;
207
208 for (auto const& family : {AF_INET, AF_INET6})
209 {
210 IpAddressList tmp = resolveAllAddress (host, family, timeout);
211 addresses.insert (addresses.end (), tmp.begin (), tmp.end ());
212 }
213
214 return addresses;
215 }
216
222 static IpAddressList lookupAllAddress (const std::string& host)
223 {
224 for (auto const& server : nameServers ())
225 {
226 IpAddressList addresses = BasicDatagramResolver<Protocol> (server.toString ()).resolveAllAddress (host);
227 if (!addresses.empty ())
228 {
229 return addresses;
230 }
231 }
232
233 return {};
234 }
235
243 IpAddress resolveAddress (const std::string& host, int family,
244 std::chrono::milliseconds timeout = std::chrono::seconds (5))
245 {
246 for (auto const& address : resolveAllAddress (host, family, timeout))
247 {
248 return address;
249 }
250
251 return IpAddress (family);
252 }
253
260 static IpAddress lookupAddress (const std::string& host, int family)
261 {
262 for (auto const& address : lookupAllAddress (host, family))
263 {
264 return address;
265 }
266
267 return IpAddress (family);
268 }
269
276 IpAddress resolveAddress (const std::string& host, std::chrono::milliseconds timeout = std::chrono::seconds (5))
277 {
278 for (auto const& address : resolveAllAddress (host, timeout))
279 {
280 return address;
281 }
282
283 return {};
284 }
285
291 static IpAddress lookupAddress (const std::string& host)
292 {
293 for (auto const& address : lookupAllAddress (host))
294 {
295 return address;
296 }
297
298 return {};
299 }
300
308 std::chrono::milliseconds timeout = std::chrono::seconds (5))
309 {
310 if (address.isWildcard ())
311 {
312 return {};
313 }
314
315 DnsPacket packet{};
316 packet.id = join::randomize<uint16_t> ();
317 packet.flags = 1 << 8;
318
319 QuestionRecord question;
320 question.host = address.toArpa ();
323 packet.questions.push_back (question);
324
325 if (query (packet, timeout) == -1)
326 {
327 return {};
328 }
329
330 AliasList aliases;
331
332 for (auto const& answer : packet.answers)
333 {
334 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::PTR))
335 {
336 aliases.insert (answer.name);
337 }
338 }
339
340 return aliases;
341 }
342
349 {
350 for (auto const& server : nameServers ())
351 {
352 AliasList aliases = BasicDatagramResolver<Protocol> (server.toString ()).resolveAllName (address);
353 if (!aliases.empty ())
354 {
355 return aliases;
356 }
357 }
358
359 return {};
360 }
361
368 std::string resolveName (const IpAddress& address, std::chrono::milliseconds timeout = std::chrono::seconds (5))
369 {
370 for (auto const& alias : resolveAllName (address, timeout))
371 {
372 return alias;
373 }
374
375 return {};
376 }
377
383 static std::string lookupName (const IpAddress& address)
384 {
385 for (auto const& alias : lookupAllName (address))
386 {
387 return alias;
388 }
389
390 return {};
391 }
392
399 ServerList resolveAllNameServer (const std::string& host,
400 std::chrono::milliseconds timeout = std::chrono::seconds (5))
401 {
402 if (host.empty ())
403 {
404 return {};
405 }
406
407 DnsPacket packet{};
408 packet.id = join::randomize<uint16_t> ();
409 packet.flags = 1 << 8;
410
411 QuestionRecord question;
412 question.host = host;
415 packet.questions.push_back (question);
416
417 if (query (packet, timeout) == -1)
418 {
419 return {};
420 }
421
422 ServerList servers;
423
424 for (auto const& answer : packet.answers)
425 {
426 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::NS))
427 {
428 servers.insert (answer.name);
429 }
430 }
431
432 return servers;
433 }
434
440 static ServerList lookupAllNameServer (const std::string& host)
441 {
442 for (auto const& server : nameServers ())
443 {
444 ServerList servers = BasicDatagramResolver<Protocol> (server.toString ()).resolveAllNameServer (host);
445 if (!servers.empty ())
446 {
447 return servers;
448 }
449 }
450
451 return {};
452 }
453
460 std::string resolveNameServer (const std::string& host,
461 std::chrono::milliseconds timeout = std::chrono::seconds (5))
462 {
463 for (auto const& server : resolveAllNameServer (host, timeout))
464 {
465 return server;
466 }
467
468 return {};
469 }
470
476 static std::string lookupNameServer (const std::string& host)
477 {
478 for (auto const& server : lookupAllNameServer (host))
479 {
480 return server;
481 }
482
483 return {};
484 }
485
492 std::string resolveAuthority (const std::string& host,
493 std::chrono::milliseconds timeout = std::chrono::seconds (5))
494 {
495 if (host.empty ())
496 {
497 return {};
498 }
499
500 DnsPacket packet{};
501 packet.id = join::randomize<uint16_t> ();
502 packet.flags = 1 << 8;
503
504 QuestionRecord question;
505 question.host = host;
508 packet.questions.push_back (question);
509
510 if (query (packet, timeout) == -1)
511 {
512 return {};
513 }
514
515 for (auto const& answer : packet.answers)
516 {
517 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::SOA))
518 {
519 return answer.name;
520 }
521 }
522
523 return {};
524 }
525
531 static std::string lookupAuthority (const std::string& host)
532 {
533 for (auto const& server : nameServers ())
534 {
535 std::string authority = BasicDatagramResolver<Protocol> (server.toString ()).resolveAuthority (host);
536 if (!authority.empty ())
537 {
538 return authority;
539 }
540 }
541
542 return {};
543 }
544
551 ExchangerList resolveAllMailExchanger (const std::string& host,
552 std::chrono::milliseconds timeout = std::chrono::seconds (5))
553 {
554 if (host.empty ())
555 {
556 return {};
557 }
558
559 DnsPacket packet{};
560 packet.id = join::randomize<uint16_t> ();
561 packet.flags = 1 << 8;
562
563 QuestionRecord question;
564 question.host = host;
567 packet.questions.push_back (question);
568
569 if (query (packet, timeout) == -1)
570 {
571 return {};
572 }
573
574 ExchangerList exchangers;
575 for (auto const& answer : packet.answers)
576 {
577 if (!answer.name.empty () && (answer.type == DnsMessage::RecordType::MX))
578 {
579 exchangers.insert (answer.name);
580 }
581 }
582
583 return exchangers;
584 }
585
591 static ExchangerList lookupAllMailExchanger (const std::string& host)
592 {
593 for (auto const& server : nameServers ())
594 {
595 ExchangerList exchangers =
596 BasicDatagramResolver<Protocol> (server.toString ()).resolveAllMailExchanger (host);
597 if (!exchangers.empty ())
598 {
599 return exchangers;
600 }
601 }
602
603 return {};
604 }
605
612 std::string resolveMailExchanger (const std::string& host,
613 std::chrono::milliseconds timeout = std::chrono::seconds (5))
614 {
615 for (auto const& exchanger : resolveAllMailExchanger (host, timeout))
616 {
617 return exchanger;
618 }
619
620 return {};
621 }
622
628 static std::string lookupMailExchanger (const std::string& host)
629 {
630 for (auto const& exchanger : lookupAllMailExchanger (host))
631 {
632 return exchanger;
633 }
634
635 return {};
636 }
637
642 static IpAddressList nameServers () noexcept
643 {
644 IpAddressList addressList;
645
646 struct __res_state res;
647 if (res_ninit (&res) == 0)
648 {
649 for (int i = 0; i < res.nscount; ++i)
650 {
651 if (res.nsaddr_list[i].sin_family == AF_INET)
652 {
653 addressList.emplace_back (&res.nsaddr_list[i].sin_addr, sizeof (struct in_addr));
654 }
655 // LCOV_EXCL_START: requires specific host IPv6 configuration.
656 else if (res._u._ext.nsaddrs[i] != nullptr && res._u._ext.nsaddrs[i]->sin6_family == AF_INET6)
657 {
658 addressList.emplace_back (&res._u._ext.nsaddrs[i]->sin6_addr, sizeof (struct in6_addr));
659 }
660 // LCOV_EXCL_STOP
661 }
662 res_nclose (&res);
663 }
664
665 return addressList;
666 }
667
673 static uint16_t resolveService (const std::string& service) noexcept
674 {
675 struct servent entry, *res;
676 char buffer[1024];
677
678 int status = getservbyname_r (service.c_str (), nullptr, &entry, buffer, sizeof buffer, &res);
679 if ((status == 0) && (res != nullptr))
680 {
681 return ntohs (entry.s_port);
682 }
683
684 return 0;
685 }
686
687 protected:
694 virtual int connect (const Endpoint& endpoint,
695 [[maybe_unused]] std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept
696 {
697 if (_socket.connect (endpoint) == -1)
698 {
699 _socket.close ();
700 return -1;
701 }
702
703 _server = endpoint.hostname ().empty () ? endpoint.ip ().toString () : endpoint.hostname ();
704 _port = endpoint.port ();
705
706 _reactor.addHandler (_socket.handle (), this);
707
708 return 0;
709 }
710
715 virtual int disconnect ([[maybe_unused]] std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept
716 {
717 if (this->_socket.handle () == -1)
718 {
719 return 0;
720 }
721
722 _reactor.delHandler (_socket.handle ());
723
724 if (_socket.disconnect () == -1)
725 {
726 _socket.close ();
727 return -1;
728 }
729
730 return 0;
731 }
732
737 virtual bool needReconnection () noexcept
738 {
739 return !_socket.connected () || _socket.remoteEndpoint ().ip ().isWildcard ();
740 }
741
748 int reconnect (const Endpoint& endpoint, std::chrono::milliseconds timeout = std::chrono::seconds (5))
749 {
750 disconnect (timeout);
751 return connect (endpoint, timeout);
752 }
753
760 virtual ssize_t read (char* data, size_t maxSize) noexcept
761 {
762 return _socket.read (data, maxSize);
763 }
764
771 virtual ssize_t write (const char* data, size_t size) noexcept
772 {
773 return _socket.write (data, size);
774 }
775
782 int query (DnsPacket& packet, std::chrono::milliseconds timeout)
783 {
784 auto remote = _socket.remoteEndpoint ();
785
786 if (remote.ip ().isWildcard ())
787 {
790
791 if (ip.isWildcard ())
792 {
794 notify (onFailure, packet);
795 return -1;
796 }
797
798 remote.ip (ip);
799 remote.port (_port);
800 }
801
802 packet.dest = remote.ip ();
803 packet.port = remote.port ();
804
805 if (needReconnection ())
806 {
807 Endpoint endpoint{packet.dest, packet.port};
808 endpoint.hostname (_server);
809
810 if (reconnect (endpoint, timeout) == -1)
811 {
812 notify (onFailure, packet);
813 return -1;
814 }
815 }
816
817 packet.src = _socket.localEndpoint ().ip ();
818
819 char buffer[Protocol::maxMsgSize];
820 ssize_t size = _message.serialize (packet, buffer, sizeof (buffer));
821 if (size == -1)
822 {
823 notify (onFailure, packet);
824 return -1;
825 }
826
828
829 auto inserted = _pending.emplace (packet.id, std::make_unique<PendingRequest> ());
830 if (!inserted.second)
831 {
832 // LCOV_EXCL_START
834 notify (onFailure, packet);
835 return -1;
836 // LCOV_EXCL_STOP
837 }
838
839 if (write (buffer, static_cast<size_t> (size)) == -1)
840 {
841 // LCOV_EXCL_START
842 _pending.erase (inserted.first);
843 notify (onFailure, packet);
844 return -1;
845 // LCOV_EXCL_STOP
846 }
847
848 if (!inserted.first->second->cond.timedWait (lock, timeout))
849 {
850 _pending.erase (inserted.first);
851 lastError = make_error_code (Errc::TimedOut);
852 notify (onFailure, packet);
853 return -1;
854 }
855
856 auto pendingReq = std::move (inserted.first->second);
857 _pending.erase (inserted.first);
858
859 if (pendingReq->ec)
860 {
861 lastError = pendingReq->ec;
862 notify (onFailure, packet);
863 return -1;
864 }
865
866 packet = std::move (pendingReq->packet);
867 notify (onSuccess, packet);
868
869 return 0;
870 }
871
876 void onReadable ([[maybe_unused]] int fd) override final
877 {
878 ssize_t size = read (_buffer.get (), Protocol::maxMsgSize);
879 if (size >= int (_headerSize))
880 {
881 DnsPacket packet;
882 std::error_code error;
883
884 if (_message.deserialize (packet, _buffer.get (), static_cast<size_t> (size)) == -1)
885 {
886 error = lastError;
887 }
888
889 auto local = _socket.localEndpoint ();
890 auto remote = _socket.remoteEndpoint ();
891 packet.src = local.ip ();
892 packet.dest = remote.ip ();
893 packet.port = remote.port ();
894
895 if (packet.flags & 0x8000)
896 {
898
899 auto it = _pending.find (packet.id);
900 if (it != _pending.end ())
901 {
902 it->second->packet = packet;
903 it->second->ec = error ? error : DnsMessage::decodeError (packet.flags & 0x000F);
904 if ((packet.flags & 0x0200) && it->second->ec == std::error_code{})
905 {
906 it->second->ec = make_error_code (Errc::MessageTooLong);
907 }
908 it->second->cond.signal ();
909 }
910 }
911 }
912 }
913
918 void onClose ([[maybe_unused]] int fd) override final
919 {
920 disconnect ();
921 }
922
923#ifdef DEBUG
924 /*
925 * @brief default callback called when a lookup sequence succeed.
926 * @param packet DNS packet.
927 */
928 static void defaultOnSuccess (const DnsPacket& packet)
929 {
930 std::cout << std::endl;
931 std::cout << "SERVER: " << packet.dest << "#" << packet.port << std::endl;
932
933 std::cout << std::endl;
934 std::cout << ";; QUESTION SECTION: " << std::endl;
935 for (auto const& question : packet.questions)
936 {
937 std::cout << question.host;
938 std::cout << " " << DnsMessage::typeName (question.type);
939 std::cout << " " << DnsMessage::className (question.dnsclass);
940 std::cout << std::endl;
941 }
942
943 std::cout << std::endl;
944 std::cout << ";; ANSWER SECTION: " << std::endl;
945 for (auto const& answer : packet.answers)
946 {
947 std::cout << answer.host;
948 std::cout << " " << DnsMessage::typeName (answer.type);
949 std::cout << " " << DnsMessage::className (answer.dnsclass);
950 std::cout << " " << answer.ttl;
951 if (answer.type == DnsMessage::RecordType::A)
952 {
953 std::cout << " " << answer.addr;
954 }
955 else if (answer.type == DnsMessage::RecordType::NS)
956 {
957 std::cout << " " << answer.name;
958 }
959 else if (answer.type == DnsMessage::RecordType::CNAME)
960 {
961 std::cout << " " << answer.name;
962 }
963 else if (answer.type == DnsMessage::RecordType::SOA)
964 {
965 std::cout << " " << answer.name;
966 std::cout << " " << answer.mail;
967 std::cout << " " << answer.serial;
968 std::cout << " " << answer.refresh;
969 std::cout << " " << answer.retry;
970 std::cout << " " << answer.expire;
971 std::cout << " " << answer.minimum;
972 }
973 else if (answer.type == DnsMessage::RecordType::PTR)
974 {
975 std::cout << " " << answer.name;
976 }
977 else if (answer.type == DnsMessage::RecordType::MX)
978 {
979 std::cout << " " << answer.mxpref;
980 std::cout << " " << answer.name;
981 }
982 else if (answer.type == DnsMessage::RecordType::AAAA)
983 {
984 std::cout << " " << answer.addr;
985 }
986 std::cout << std::endl;
987 }
988 }
989
990 /*
991 * @brief default callback called when a lookup sequence failed.
992 * @param packet DNS packet.
993 */
994 static void defaultOnFailure (const DnsPacket& packet)
995 {
996 std::cout << std::endl;
997 std::cout << "SERVER: " << packet.dest << "#" << packet.port << std::endl;
998
999 std::cout << std::endl;
1000 std::cout << ";; QUESTION SECTION: " << std::endl;
1001 for (auto const& question : packet.questions)
1002 {
1003 std::cout << question.host;
1004 std::cout << " " << DnsMessage::typeName (question.type);
1005 std::cout << " " << DnsMessage::className (question.dnsclass);
1006 std::cout << std::endl;
1007 }
1008
1009 std::cout << std::endl;
1010 std::cout << lastError.message () << std::endl;
1011 }
1012#endif
1013
1019 void notify (const DnsNotify& func, const DnsPacket& packet) const noexcept
1020 {
1021 if (func)
1022 {
1023 func (packet);
1024 }
1025 }
1026
1028 static constexpr size_t _headerSize = 12;
1029
1032
1035
1037 std::string _server;
1038
1040 uint16_t _port;
1041
1044
1046 std::unique_ptr<char[]> _buffer;
1047
1050 {
1053 std::error_code ec;
1054 };
1055
1057 std::unordered_map<uint16_t, std::unique_ptr<PendingRequest>> _pending;
1058
1061 };
1062
1066 template <class Protocol>
1068 {
1069 public:
1070 using Socket = typename Protocol::Socket;
1071 using UnderlyingSocket = typename Socket::UnderlyingSocket;
1072 using Endpoint = typename Protocol::Endpoint;
1073
1080 explicit BasicTlsResolver (TlsContext ctx, const std::string& server = {},
1081 uint16_t port = Protocol::defaultPort, Reactor& reactor = ReactorThread::reactor ())
1082 : BasicDatagramResolver<Protocol> (Socket (UnderlyingSocket{}, ctx), server, port, reactor)
1083 {
1084 }
1085
1090 BasicTlsResolver (const BasicTlsResolver& other) = delete;
1091
1098
1104
1111
1115 virtual ~BasicTlsResolver () noexcept
1116 {
1117 disconnect ();
1118 }
1119
1126 static IpAddressList lookupAllAddress (const std::string& host, int family) = delete;
1127
1133 static IpAddressList lookupAllAddress (const std::string& host) = delete;
1134
1141 static IpAddress lookupAddress (const std::string& host, int family) = delete;
1142
1148 static IpAddress lookupAddress (const std::string& host) = delete;
1149
1155 static AliasList lookupAllName (const IpAddress& address) = delete;
1156
1162 static std::string lookupName (const IpAddress& address) = delete;
1163
1169 static ServerList lookupAllNameServer (const std::string& host) = delete;
1170
1176 static std::string lookupNameServer (const std::string& host) = delete;
1177
1183 static std::string lookupAuthority (const std::string& host) = delete;
1184
1190 static ExchangerList lookupAllMailExchanger (const std::string& host) = delete;
1191
1197 static std::string lookupMailExchanger (const std::string& host) = delete;
1198
1199 private:
1206 int connect (const Endpoint& endpoint,
1207 std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept override final
1208 {
1209 if (this->_socket.connect (endpoint) == -1)
1210 {
1211 if (lastError != Errc::TemporaryError)
1212 {
1213 close ();
1214 return -1;
1215 }
1216
1217 if (!this->_socket.waitConnected (timeout))
1218 {
1219 close ();
1220 return -1;
1221 }
1222 }
1223
1224 this->_server = endpoint.hostname ().empty () ? endpoint.ip ().toString () : endpoint.hostname ();
1225 this->_port = endpoint.port ();
1226
1227 if (this->_socket.handshake () == -1)
1228 {
1229 if (lastError != Errc::TemporaryError)
1230 {
1231 close ();
1232 return -1;
1233 }
1234
1235 if (!this->_socket.waitHandshake (timeout))
1236 {
1237 close ();
1238 return -1;
1239 }
1240 }
1241
1242 this->_reactor.addHandler (this->_socket.handle (), this);
1243
1244 return 0;
1245 }
1246
1251 int disconnect (std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept override final
1252 {
1253 if (this->_socket.handle () == -1)
1254 {
1255 return 0;
1256 }
1257
1258 this->_reactor.delHandler (this->_socket.handle ());
1259
1260 if (this->_socket.shutdown () == -1)
1261 {
1262 if ((lastError != Errc::TemporaryError))
1263 {
1264 close ();
1265 return -1;
1266 }
1267
1268 if (!this->_socket.waitShutdown (timeout))
1269 {
1270 close ();
1271 return -1;
1272 }
1273 }
1274
1275 if (!this->_socket.waitDisconnected (timeout))
1276 {
1277 close ();
1278 return -1;
1279 }
1280
1281 return 0;
1282 }
1283
1287 void close () noexcept
1288 {
1289 this->_socket.close ();
1290 _offset = 0;
1291 _size = 0;
1292 }
1293
1298 bool needReconnection () noexcept override final
1299 {
1300 return !this->_socket.encrypted () || this->_socket.remoteEndpoint ().ip ().isWildcard ();
1301 }
1302
1309 ssize_t read (char* data, size_t maxSize) noexcept override final
1310 {
1311 if (_offset < _frameHeaderSize)
1312 {
1313 ssize_t nread = this->_socket.read (data + _offset, _frameHeaderSize - _offset);
1314 if (nread == -1)
1315 {
1316 if (lastError != Errc::TemporaryError)
1317 {
1318 _offset = 0;
1319 _size = 0;
1320 }
1321 return -1;
1322 }
1323
1324 _offset += static_cast<size_t> (nread);
1325
1326 if (_offset < _frameHeaderSize)
1327 {
1329 return -1;
1330 }
1331
1332 _size = ntohs (*reinterpret_cast<uint16_t*> (data));
1333
1334 if (_size > maxSize)
1335 {
1337 _offset = 0;
1338 _size = 0;
1339 return -1;
1340 }
1341 }
1342
1343 ssize_t nread =
1344 this->_socket.read (data + (_offset - _frameHeaderSize), _size - (_offset - _frameHeaderSize));
1345 if (nread == -1)
1346 {
1347 if (lastError != Errc::TemporaryError)
1348 {
1349 _offset = 0;
1350 _size = 0;
1351 }
1352 return -1;
1353 }
1354
1355 _offset += static_cast<size_t> (nread);
1356
1357 if (_offset < (_size + _frameHeaderSize))
1358 {
1360 return -1;
1361 }
1362
1363 int msgLen = static_cast<int> (_size);
1364 _offset = 0;
1365 _size = 0;
1366
1367 return msgLen;
1368 }
1369
1376 ssize_t write (const char* data, size_t size) noexcept override final
1377 {
1378 uint16_t msgLength = htons (static_cast<uint16_t> (size));
1379 const char* p = reinterpret_cast<const char*> (&msgLength);
1380 size_t remaining = sizeof (msgLength);
1381
1382 while (remaining > 0)
1383 {
1384 ssize_t result = this->_socket.write (p, remaining);
1385 if (result == -1)
1386 {
1387 if (lastError == Errc::TemporaryError)
1388 {
1389 if (this->_socket.waitReadyWrite ())
1390 continue;
1391 }
1392 return -1;
1393 }
1394 p += result;
1395 remaining -= result;
1396 }
1397
1398 p = data;
1399 remaining = size;
1400
1401 while (remaining > 0)
1402 {
1403 ssize_t result = this->_socket.write (p, remaining);
1404 if (result == -1)
1405 {
1406 if (lastError == Errc::TemporaryError)
1407 {
1408 if (this->_socket.waitReadyWrite ())
1409 continue;
1410 }
1411 return -1;
1412 }
1413 p += result;
1414 remaining -= result;
1415 }
1416
1417 return static_cast<int> (size);
1418 }
1419
1421 static constexpr size_t _frameHeaderSize = 2;
1422
1424 size_t _size = 0;
1425
1427 size_t _offset = 0;
1428 };
1429}
1430
1431#endif
basic DNS resolver over datagram socket.
Definition resolver.hpp:55
virtual int connect(const Endpoint &endpoint, std::chrono::milliseconds timeout=std::chrono::seconds(5)) noexcept
make a connection to the given endpoint.
Definition resolver.hpp:694
IpAddress resolveAddress(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name.
Definition resolver.hpp:276
static ExchangerList lookupAllMailExchanger(const std::string &host)
resolve all host mail exchanger.
Definition resolver.hpp:591
void notify(const DnsNotify &func, const DnsPacket &packet) const noexcept
safe way to notify DNS events.
Definition resolver.hpp:1019
static IpAddressList lookupAllAddress(const std::string &host, int family)
resolve host name using system name servers and return all IP addresses found.
Definition resolver.hpp:182
BasicDatagramResolver(const BasicDatagramResolver &other)=delete
copy constructor.
static IpAddressList lookupAllAddress(const std::string &host)
resolve host name using system name servers and return all IP addresses found.
Definition resolver.hpp:222
int reconnect(const Endpoint &endpoint, std::chrono::milliseconds timeout=std::chrono::seconds(5))
reconnect to the remote DNS server.
Definition resolver.hpp:748
Mutex _syncMutex
protection mutex.
Definition resolver.hpp:1060
ExchangerList resolveAllMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host mail exchanger.
Definition resolver.hpp:551
std::function< void(const DnsPacket &)> DnsNotify
notification callback definition.
Definition resolver.hpp:61
static std::string lookupAuthority(const std::string &host)
resolve host start of authority name server.
Definition resolver.hpp:531
virtual bool needReconnection() noexcept
check if client must reconnect.
Definition resolver.hpp:737
static IpAddressList nameServers() noexcept
get IP address of the currently configured name servers.
Definition resolver.hpp:642
virtual ssize_t read(char *data, size_t maxSize) noexcept
read a DNS message.
Definition resolver.hpp:760
static IpAddress lookupAddress(const std::string &host, int family)
resolve host name using system name servers.
Definition resolver.hpp:260
void onReadable(int fd) override final
method called when data are ready to be read on handle.
Definition resolver.hpp:876
DnsNotify onSuccess
callback called when a lookup sequence succeed.
Definition resolver.hpp:64
BasicDatagramResolver(const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
Definition resolver.hpp:69
virtual int disconnect(std::chrono::milliseconds timeout=std::chrono::seconds(5)) noexcept
shutdown the connection.
Definition resolver.hpp:715
uint16_t _port
remote DNS server port.
Definition resolver.hpp:1040
Socket _socket
underlying socket.
Definition resolver.hpp:1034
static std::string lookupMailExchanger(const std::string &host)
resolve host mail exchanger.
Definition resolver.hpp:628
virtual ssize_t write(const char *data, size_t size) noexcept
write a DNS message.
Definition resolver.hpp:771
virtual ~BasicDatagramResolver() noexcept
destroy instance.
Definition resolver.hpp:128
IpAddress resolveAddress(const std::string &host, int family, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name using address family.
Definition resolver.hpp:243
typename Protocol::Endpoint Endpoint
Definition resolver.hpp:58
std::string _server
remote DNS server.
Definition resolver.hpp:1037
ServerList resolveAllNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host name server.
Definition resolver.hpp:399
IpAddressList resolveAllAddress(const std::string &host, int family, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name and return all IP addresses found.
Definition resolver.hpp:140
std::string resolveAuthority(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host start of authority name server.
Definition resolver.hpp:492
BasicDatagramResolver(Socket &&socket, const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
construct the resolver instance.
Definition resolver.hpp:81
static std::string lookupNameServer(const std::string &host)
resolve host name server.
Definition resolver.hpp:476
BasicDatagramResolver & operator=(const BasicDatagramResolver &other)=delete
copy assignment operator.
static uint16_t resolveService(const std::string &service) noexcept
resolve service name.
Definition resolver.hpp:673
static IpAddress lookupAddress(const std::string &host)
resolve host name using system name servers.
Definition resolver.hpp:291
static ServerList lookupAllNameServer(const std::string &host)
resolve all host name server.
Definition resolver.hpp:440
std::string resolveName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host address.
Definition resolver.hpp:368
static std::string lookupName(const IpAddress &address)
resolve host address.
Definition resolver.hpp:383
void onClose(int fd) override final
method called when handle is closed.
Definition resolver.hpp:918
std::string resolveNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name server.
Definition resolver.hpp:460
DnsMessage _message
DNS message codec.
Definition resolver.hpp:1031
std::unique_ptr< char[]> _buffer
reception buffer.
Definition resolver.hpp:1046
AliasList resolveAllName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host address.
Definition resolver.hpp:307
static constexpr size_t _headerSize
DNS message header size.
Definition resolver.hpp:1028
int query(DnsPacket &packet, std::chrono::milliseconds timeout)
serialize and send a DNS query, waiting for a response.
Definition resolver.hpp:782
BasicDatagramResolver(BasicDatagramResolver &&other)=delete
move constructor.
typename Protocol::Socket Socket
Definition resolver.hpp:57
std::string resolveMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host mail exchanger.
Definition resolver.hpp:612
DnsNotify onFailure
callback called when a lookup sequence failed.
Definition resolver.hpp:67
static AliasList lookupAllName(const IpAddress &address)
resolve all host address.
Definition resolver.hpp:348
IpAddressList resolveAllAddress(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name and return all IP addresses found.
Definition resolver.hpp:203
Reactor & _reactor
event loop reactor.
Definition resolver.hpp:1043
std::unordered_map< uint16_t, std::unique_ptr< PendingRequest > > _pending
synchronous requests indexed by sequence number.
Definition resolver.hpp:1057
basic DNS resolver over TLS socket (DNS over TLS).
Definition resolver.hpp:1068
static IpAddressList lookupAllAddress(const std::string &host)=delete
resolve host name using system name servers and return all IP addresses found.
static std::string lookupNameServer(const std::string &host)=delete
resolve host name server.
static std::string lookupMailExchanger(const std::string &host)=delete
resolve host mail exchanger.
static std::string lookupAuthority(const std::string &host)=delete
resolve host start of authority name server.
BasicTlsResolver & operator=(const BasicTlsResolver &other)=delete
copy assignment operator.
static IpAddress lookupAddress(const std::string &host)=delete
resolve host name using system name servers.
virtual ~BasicTlsResolver() noexcept
destroy instance.
Definition resolver.hpp:1115
BasicTlsResolver(const BasicTlsResolver &other)=delete
copy constructor.
typename Socket::UnderlyingSocket UnderlyingSocket
Definition resolver.hpp:1071
BasicTlsResolver(TlsContext ctx, const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
construct the DoT resolver instance.
Definition resolver.hpp:1080
static AliasList lookupAllName(const IpAddress &address)=delete
resolve all host address.
static IpAddressList lookupAllAddress(const std::string &host, int family)=delete
resolve host name using system name servers and return all IP addresses found.
static ExchangerList lookupAllMailExchanger(const std::string &host)=delete
resolve all host mail exchanger.
static std::string lookupName(const IpAddress &address)=delete
resolve host address.
typename Protocol::Endpoint Endpoint
Definition resolver.hpp:1072
static IpAddress lookupAddress(const std::string &host, int family)=delete
resolve host name using system name servers.
typename Protocol::Socket Socket
Definition resolver.hpp:1070
static ServerList lookupAllNameServer(const std::string &host)=delete
resolve all host name server.
BasicTlsResolver(BasicTlsResolver &&other)=delete
move constructor.
condition variable class.
Definition condition.hpp:42
DNS message codec.
Definition dns_message.hpp:104
int deserialize(DnsPacket &packet, const char *data, size_t size) const
deserialize a DNS packet from a buffer.
Definition dns_message.hpp:228
static std::string className(uint16_t recordClass)
get record class name.
Definition dns_message.hpp:356
@ A
Definition dns_message.hpp:111
@ PTR
Definition dns_message.hpp:115
@ SOA
Definition dns_message.hpp:114
@ NS
Definition dns_message.hpp:112
@ MX
Definition dns_message.hpp:116
@ CNAME
Definition dns_message.hpp:113
@ AAAA
Definition dns_message.hpp:118
ssize_t serialize(const DnsPacket &packet, char *data, size_t maxSize) const
serialize a DNS packet into a buffer.
Definition dns_message.hpp:174
static std::error_code decodeError(uint16_t error) noexcept
convert DNS error to system error code.
Definition dns_message.hpp:307
@ IN
Definition dns_message.hpp:128
static std::string typeName(uint16_t recordType)
get record type name.
Definition dns_message.hpp:332
Event handler interface class.
Definition reactor.hpp:51
IPv6, IPv4 address class.
Definition ip_address.hpp:52
bool isWildcard() const
check if IP address is a wildcard address.
Definition ip_address.cpp:1295
static bool isIpAddress(const std::string &address)
check if the specified string is an IP address.
Definition ip_address.cpp:1376
class used to protect shared data from being simultaneously accessed by multiple threads.
Definition mutex.hpp:37
static Reactor & reactor()
get the global Reactor instance.
Definition reactor.cpp:612
Reactor class.
Definition reactor.hpp:159
int delHandler(int fd, bool sync=true) noexcept
delete handler from reactor.
Definition reactor.cpp:156
int addHandler(int fd, EventHandler *handler, bool wantRead=true, bool wantWrite=false, bool sync=true) noexcept
add handler to reactor.
Definition reactor.cpp:101
class owning a mutex for the duration of a scoped block.
Definition mutex.hpp:249
TLS/DTLS context.
Definition tls_context.hpp:42
Definition acceptor.hpp:32
std::unordered_set< std::string > ExchangerList
list of mail exchangers.
Definition dns_message.hpp:51
std::unordered_set< std::string > ServerList
list of name servers.
Definition dns_message.hpp:48
std::unordered_set< std::string > AliasList
list of aliases.
Definition dns_message.hpp:45
Type randomize()
create a random number.
Definition utils.hpp:402
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
thread_local std::error_code lastError
last error.
Definition error.cpp:32
std::vector< IpAddress > IpAddressList
List of IP address.
Definition ip_address.hpp:46
Definition error.hpp:144
pending synchronous request.
Definition resolver.hpp:1050
Condition cond
Definition resolver.hpp:1051
std::error_code ec
Definition resolver.hpp:1053
DnsPacket packet
Definition resolver.hpp:1052
DNS packet.
Definition dns_message.hpp:88
uint16_t id
Definition dns_message.hpp:89
uint16_t flags
Definition dns_message.hpp:90
uint16_t port
Definition dns_message.hpp:93
std::vector< QuestionRecord > questions
Definition dns_message.hpp:94
IpAddress src
Definition dns_message.hpp:91
IpAddress dest
Definition dns_message.hpp:92
std::vector< ResourceRecord > answers
Definition dns_message.hpp:95
question record.
Definition dns_message.hpp:57
std::string host
Definition dns_message.hpp:58
uint16_t type
Definition dns_message.hpp:59
uint16_t dnsclass
Definition dns_message.hpp:60
IpAddress address
Definition tcp_acceptor_test.cpp:35
uint16_t port
Definition tcp_acceptor_test.cpp:36