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 std::stringstream data;
820 if (_message.serialize (packet, data) == -1)
821 {
823 notify (onFailure, packet);
824 return -1;
825 }
826
827 std::string buffer = data.str ();
828 if (buffer.size () > Protocol::maxMsgSize)
829 {
831 notify (onFailure, packet);
832 return -1;
833 }
834
836
837 auto inserted = _pending.emplace (packet.id, std::make_unique<PendingRequest> ());
838 if (!inserted.second)
839 {
840 // LCOV_EXCL_START
842 notify (onFailure, packet);
843 return -1;
844 // LCOV_EXCL_STOP
845 }
846
847 if (write (buffer.data (), buffer.size ()) == -1)
848 {
849 // LCOV_EXCL_START
850 _pending.erase (inserted.first);
851 notify (onFailure, packet);
852 return -1;
853 // LCOV_EXCL_STOP
854 }
855
856 if (!inserted.first->second->cond.timedWait (lock, timeout))
857 {
858 _pending.erase (inserted.first);
859 lastError = make_error_code (Errc::TimedOut);
860 notify (onFailure, packet);
861 return -1;
862 }
863
864 auto pendingReq = std::move (inserted.first->second);
865 _pending.erase (inserted.first);
866
867 if (pendingReq->ec)
868 {
869 lastError = pendingReq->ec;
870 notify (onFailure, packet);
871 return -1;
872 }
873
874 packet = std::move (pendingReq->packet);
875 notify (onSuccess, packet);
876
877 return 0;
878 }
879
884 void onReadable ([[maybe_unused]] int fd) override final
885 {
886 ssize_t size = read (_buffer.get (), Protocol::maxMsgSize);
887 if (size >= int (_headerSize))
888 {
889 std::stringstream data;
890 data.rdbuf ()->pubsetbuf (_buffer.get (), size);
891
892 DnsPacket packet;
893 _message.deserialize (packet, data);
894 auto local = _socket.localEndpoint ();
895 auto remote = _socket.remoteEndpoint ();
896 packet.src = local.ip ();
897 packet.dest = remote.ip ();
898 packet.port = remote.port ();
899
900 if (packet.flags & 0x8000)
901 {
903
904 auto it = _pending.find (packet.id);
905 if (it != _pending.end ())
906 {
907 it->second->packet = packet;
908 it->second->ec = DnsMessage::decodeError (packet.flags & 0x000F);
909 if ((packet.flags & 0x0200) && it->second->ec == std::error_code{})
910 {
911 it->second->ec = make_error_code (Errc::MessageTooLong);
912 }
913 it->second->cond.signal ();
914 }
915 }
916 }
917 }
918
923 void onClose ([[maybe_unused]] int fd) override final
924 {
925 disconnect ();
926 }
927
928#ifdef DEBUG
929 /*
930 * @brief default callback called when a lookup sequence succeed.
931 * @param packet DNS packet.
932 */
933 static void defaultOnSuccess (const DnsPacket& packet)
934 {
935 std::cout << std::endl;
936 std::cout << "SERVER: " << packet.dest << "#" << packet.port << std::endl;
937
938 std::cout << std::endl;
939 std::cout << ";; QUESTION SECTION: " << std::endl;
940 for (auto const& question : packet.questions)
941 {
942 std::cout << question.host;
943 std::cout << " " << DnsMessage::typeName (question.type);
944 std::cout << " " << DnsMessage::className (question.dnsclass);
945 std::cout << std::endl;
946 }
947
948 std::cout << std::endl;
949 std::cout << ";; ANSWER SECTION: " << std::endl;
950 for (auto const& answer : packet.answers)
951 {
952 std::cout << answer.host;
953 std::cout << " " << DnsMessage::typeName (answer.type);
954 std::cout << " " << DnsMessage::className (answer.dnsclass);
955 std::cout << " " << answer.ttl;
956 if (answer.type == DnsMessage::RecordType::A)
957 {
958 std::cout << " " << answer.addr;
959 }
960 else if (answer.type == DnsMessage::RecordType::NS)
961 {
962 std::cout << " " << answer.name;
963 }
964 else if (answer.type == DnsMessage::RecordType::CNAME)
965 {
966 std::cout << " " << answer.name;
967 }
968 else if (answer.type == DnsMessage::RecordType::SOA)
969 {
970 std::cout << " " << answer.name;
971 std::cout << " " << answer.mail;
972 std::cout << " " << answer.serial;
973 std::cout << " " << answer.refresh;
974 std::cout << " " << answer.retry;
975 std::cout << " " << answer.expire;
976 std::cout << " " << answer.minimum;
977 }
978 else if (answer.type == DnsMessage::RecordType::PTR)
979 {
980 std::cout << " " << answer.name;
981 }
982 else if (answer.type == DnsMessage::RecordType::MX)
983 {
984 std::cout << " " << answer.mxpref;
985 std::cout << " " << answer.name;
986 }
987 else if (answer.type == DnsMessage::RecordType::AAAA)
988 {
989 std::cout << " " << answer.addr;
990 }
991 std::cout << std::endl;
992 }
993 }
994
995 /*
996 * @brief default callback called when a lookup sequence failed.
997 * @param packet DNS packet.
998 */
999 static void defaultOnFailure (const DnsPacket& packet)
1000 {
1001 std::cout << std::endl;
1002 std::cout << "SERVER: " << packet.dest << "#" << packet.port << std::endl;
1003
1004 std::cout << std::endl;
1005 std::cout << ";; QUESTION SECTION: " << std::endl;
1006 for (auto const& question : packet.questions)
1007 {
1008 std::cout << question.host;
1009 std::cout << " " << DnsMessage::typeName (question.type);
1010 std::cout << " " << DnsMessage::className (question.dnsclass);
1011 std::cout << std::endl;
1012 }
1013
1014 std::cout << std::endl;
1015 std::cout << lastError.message () << std::endl;
1016 }
1017#endif
1018
1024 void notify (const DnsNotify& func, const DnsPacket& packet) const noexcept
1025 {
1026 if (func)
1027 {
1028 func (packet);
1029 }
1030 }
1031
1033 static constexpr size_t _headerSize = 12;
1034
1037
1040
1042 std::string _server;
1043
1045 uint16_t _port;
1046
1049
1051 std::unique_ptr<char[]> _buffer;
1052
1055 {
1058 std::error_code ec;
1059 };
1060
1062 std::unordered_map<uint16_t, std::unique_ptr<PendingRequest>> _pending;
1063
1066 };
1067
1071 template <class Protocol>
1073 {
1074 public:
1075 using Socket = typename Protocol::Socket;
1076 using UnderlyingSocket = typename Socket::UnderlyingSocket;
1077 using Endpoint = typename Protocol::Endpoint;
1078
1085 explicit BasicTlsResolver (TlsContext ctx, const std::string& server = {},
1086 uint16_t port = Protocol::defaultPort, Reactor& reactor = ReactorThread::reactor ())
1087 : BasicDatagramResolver<Protocol> (Socket (UnderlyingSocket{}, ctx), server, port, reactor)
1088 {
1089 }
1090
1095 BasicTlsResolver (const BasicTlsResolver& other) = delete;
1096
1103
1109
1116
1120 virtual ~BasicTlsResolver () noexcept
1121 {
1122 disconnect ();
1123 }
1124
1131 static IpAddressList lookupAllAddress (const std::string& host, int family) = delete;
1132
1138 static IpAddressList lookupAllAddress (const std::string& host) = delete;
1139
1146 static IpAddress lookupAddress (const std::string& host, int family) = delete;
1147
1153 static IpAddress lookupAddress (const std::string& host) = delete;
1154
1160 static AliasList lookupAllName (const IpAddress& address) = delete;
1161
1167 static std::string lookupName (const IpAddress& address) = delete;
1168
1174 static ServerList lookupAllNameServer (const std::string& host) = delete;
1175
1181 static std::string lookupNameServer (const std::string& host) = delete;
1182
1188 static std::string lookupAuthority (const std::string& host) = delete;
1189
1195 static ExchangerList lookupAllMailExchanger (const std::string& host) = delete;
1196
1202 static std::string lookupMailExchanger (const std::string& host) = delete;
1203
1204 private:
1211 int connect (const Endpoint& endpoint,
1212 std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept override final
1213 {
1214 if (this->_socket.connect (endpoint) == -1)
1215 {
1216 if (lastError != Errc::TemporaryError)
1217 {
1218 close ();
1219 return -1;
1220 }
1221
1222 if (!this->_socket.waitConnected (timeout))
1223 {
1224 close ();
1225 return -1;
1226 }
1227 }
1228
1229 this->_server = endpoint.hostname ().empty () ? endpoint.ip ().toString () : endpoint.hostname ();
1230 this->_port = endpoint.port ();
1231
1232 if (this->_socket.handshake () == -1)
1233 {
1234 if (lastError != Errc::TemporaryError)
1235 {
1236 close ();
1237 return -1;
1238 }
1239
1240 if (!this->_socket.waitHandshake (timeout))
1241 {
1242 close ();
1243 return -1;
1244 }
1245 }
1246
1247 this->_reactor.addHandler (this->_socket.handle (), this);
1248
1249 return 0;
1250 }
1251
1256 int disconnect (std::chrono::milliseconds timeout = std::chrono::seconds (5)) noexcept override final
1257 {
1258 if (this->_socket.handle () == -1)
1259 {
1260 return 0;
1261 }
1262
1263 this->_reactor.delHandler (this->_socket.handle ());
1264
1265 if (this->_socket.shutdown () == -1)
1266 {
1267 if ((lastError != Errc::TemporaryError))
1268 {
1269 close ();
1270 return -1;
1271 }
1272
1273 if (!this->_socket.waitShutdown (timeout))
1274 {
1275 close ();
1276 return -1;
1277 }
1278 }
1279
1280 if (!this->_socket.waitDisconnected (timeout))
1281 {
1282 close ();
1283 return -1;
1284 }
1285
1286 return 0;
1287 }
1288
1292 void close () noexcept
1293 {
1294 this->_socket.close ();
1295 _offset = 0;
1296 _size = 0;
1297 }
1298
1303 bool needReconnection () noexcept override final
1304 {
1305 return !this->_socket.encrypted () || this->_socket.remoteEndpoint ().ip ().isWildcard ();
1306 }
1307
1314 ssize_t read (char* data, size_t maxSize) noexcept override final
1315 {
1316 if (_offset < _frameHeaderSize)
1317 {
1318 ssize_t nread = this->_socket.read (data + _offset, _frameHeaderSize - _offset);
1319 if (nread == -1)
1320 {
1321 if (lastError != Errc::TemporaryError)
1322 {
1323 _offset = 0;
1324 _size = 0;
1325 }
1326 return -1;
1327 }
1328
1329 _offset += static_cast<size_t> (nread);
1330
1331 if (_offset < _frameHeaderSize)
1332 {
1334 return -1;
1335 }
1336
1337 _size = ntohs (*reinterpret_cast<uint16_t*> (data));
1338
1339 if (_size > maxSize)
1340 {
1342 _offset = 0;
1343 _size = 0;
1344 return -1;
1345 }
1346 }
1347
1348 ssize_t nread =
1349 this->_socket.read (data + (_offset - _frameHeaderSize), _size - (_offset - _frameHeaderSize));
1350 if (nread == -1)
1351 {
1352 if (lastError != Errc::TemporaryError)
1353 {
1354 _offset = 0;
1355 _size = 0;
1356 }
1357 return -1;
1358 }
1359
1360 _offset += static_cast<size_t> (nread);
1361
1362 if (_offset < (_size + _frameHeaderSize))
1363 {
1365 return -1;
1366 }
1367
1368 int msgLen = static_cast<int> (_size);
1369 _offset = 0;
1370 _size = 0;
1371
1372 return msgLen;
1373 }
1374
1381 ssize_t write (const char* data, size_t size) noexcept override final
1382 {
1383 uint16_t msgLength = htons (static_cast<uint16_t> (size));
1384 const char* p = reinterpret_cast<const char*> (&msgLength);
1385 size_t remaining = sizeof (msgLength);
1386
1387 while (remaining > 0)
1388 {
1389 ssize_t result = this->_socket.write (p, remaining);
1390 if (result == -1)
1391 {
1392 if (lastError == Errc::TemporaryError)
1393 {
1394 if (this->_socket.waitReadyWrite ())
1395 continue;
1396 }
1397 return -1;
1398 }
1399 p += result;
1400 remaining -= result;
1401 }
1402
1403 p = data;
1404 remaining = size;
1405
1406 while (remaining > 0)
1407 {
1408 ssize_t result = this->_socket.write (p, remaining);
1409 if (result == -1)
1410 {
1411 if (lastError == Errc::TemporaryError)
1412 {
1413 if (this->_socket.waitReadyWrite ())
1414 continue;
1415 }
1416 return -1;
1417 }
1418 p += result;
1419 remaining -= result;
1420 }
1421
1422 return static_cast<int> (size);
1423 }
1424
1426 static constexpr size_t _frameHeaderSize = 2;
1427
1429 size_t _size = 0;
1430
1432 size_t _offset = 0;
1433 };
1434}
1435
1436#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:1024
static IpAddressList lookupAllAddress(const std::string &host, int family)
resolve host name using system name servers and return all IP addresses found.
Definition resolver.hpp:182
BasicDatagramResolver(const BasicDatagramResolver &other)=delete
copy constructor.
static IpAddressList lookupAllAddress(const std::string &host)
resolve host name using system name servers and return all IP addresses found.
Definition resolver.hpp:222
int reconnect(const Endpoint &endpoint, std::chrono::milliseconds timeout=std::chrono::seconds(5))
reconnect to the remote DNS server.
Definition resolver.hpp:748
Mutex _syncMutex
protection mutex.
Definition resolver.hpp:1065
ExchangerList resolveAllMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host mail exchanger.
Definition resolver.hpp:551
std::function< void(const DnsPacket &)> DnsNotify
notification callback definition.
Definition resolver.hpp:61
static std::string lookupAuthority(const std::string &host)
resolve host start of authority name server.
Definition resolver.hpp:531
virtual bool needReconnection() noexcept
check if client must reconnect.
Definition resolver.hpp:737
static IpAddressList nameServers() noexcept
get IP address of the currently configured name servers.
Definition resolver.hpp:642
virtual ssize_t read(char *data, size_t maxSize) noexcept
read a DNS message.
Definition resolver.hpp:760
static IpAddress lookupAddress(const std::string &host, int family)
resolve host name using system name servers.
Definition resolver.hpp:260
void onReadable(int fd) override final
method called when data are ready to be read on handle.
Definition resolver.hpp:884
DnsNotify onSuccess
callback called when a lookup sequence succeed.
Definition resolver.hpp:64
BasicDatagramResolver(const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
Definition resolver.hpp:69
virtual int disconnect(std::chrono::milliseconds timeout=std::chrono::seconds(5)) noexcept
shutdown the connection.
Definition resolver.hpp:715
uint16_t _port
remote DNS server port.
Definition resolver.hpp:1045
Socket _socket
underlying socket.
Definition resolver.hpp:1039
static std::string lookupMailExchanger(const std::string &host)
resolve host mail exchanger.
Definition resolver.hpp:628
virtual ssize_t write(const char *data, size_t size) noexcept
write a DNS message.
Definition resolver.hpp:771
virtual ~BasicDatagramResolver() noexcept
destroy instance.
Definition resolver.hpp:128
IpAddress resolveAddress(const std::string &host, int family, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name using address family.
Definition resolver.hpp:243
typename Protocol::Endpoint Endpoint
Definition resolver.hpp:58
std::string _server
remote DNS server.
Definition resolver.hpp:1042
ServerList resolveAllNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host name server.
Definition resolver.hpp:399
IpAddressList resolveAllAddress(const std::string &host, int family, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name and return all IP addresses found.
Definition resolver.hpp:140
std::string resolveAuthority(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host start of authority name server.
Definition resolver.hpp:492
BasicDatagramResolver(Socket &&socket, const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
construct the resolver instance.
Definition resolver.hpp:81
static std::string lookupNameServer(const std::string &host)
resolve host name server.
Definition resolver.hpp:476
BasicDatagramResolver & operator=(const BasicDatagramResolver &other)=delete
copy assignment operator.
static uint16_t resolveService(const std::string &service) noexcept
resolve service name.
Definition resolver.hpp:673
static IpAddress lookupAddress(const std::string &host)
resolve host name using system name servers.
Definition resolver.hpp:291
static ServerList lookupAllNameServer(const std::string &host)
resolve all host name server.
Definition resolver.hpp:440
std::string resolveName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host address.
Definition resolver.hpp:368
static std::string lookupName(const IpAddress &address)
resolve host address.
Definition resolver.hpp:383
void onClose(int fd) override final
method called when handle is closed.
Definition resolver.hpp:923
std::string resolveNameServer(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name server.
Definition resolver.hpp:460
DnsMessage _message
DNS message codec.
Definition resolver.hpp:1036
std::unique_ptr< char[]> _buffer
reception buffer.
Definition resolver.hpp:1051
AliasList resolveAllName(const IpAddress &address, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve all host address.
Definition resolver.hpp:307
static constexpr size_t _headerSize
DNS message header size.
Definition resolver.hpp:1033
int query(DnsPacket &packet, std::chrono::milliseconds timeout)
serialize and send a DNS query, waiting for a response.
Definition resolver.hpp:782
BasicDatagramResolver(BasicDatagramResolver &&other)=delete
move constructor.
typename Protocol::Socket Socket
Definition resolver.hpp:57
std::string resolveMailExchanger(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host mail exchanger.
Definition resolver.hpp:612
DnsNotify onFailure
callback called when a lookup sequence failed.
Definition resolver.hpp:67
static AliasList lookupAllName(const IpAddress &address)
resolve all host address.
Definition resolver.hpp:348
IpAddressList resolveAllAddress(const std::string &host, std::chrono::milliseconds timeout=std::chrono::seconds(5))
resolve host name and return all IP addresses found.
Definition resolver.hpp:203
Reactor & _reactor
event loop reactor.
Definition resolver.hpp:1048
std::unordered_map< uint16_t, std::unique_ptr< PendingRequest > > _pending
synchronous requests indexed by sequence number.
Definition resolver.hpp:1062
basic DNS resolver over TLS socket (DNS over TLS).
Definition resolver.hpp:1073
static IpAddressList lookupAllAddress(const std::string &host)=delete
resolve host name using system name servers and return all IP addresses found.
static std::string lookupNameServer(const std::string &host)=delete
resolve host name server.
static std::string lookupMailExchanger(const std::string &host)=delete
resolve host mail exchanger.
static std::string lookupAuthority(const std::string &host)=delete
resolve host start of authority name server.
BasicTlsResolver & operator=(const BasicTlsResolver &other)=delete
copy assignment operator.
static IpAddress lookupAddress(const std::string &host)=delete
resolve host name using system name servers.
virtual ~BasicTlsResolver() noexcept
destroy instance.
Definition resolver.hpp:1120
BasicTlsResolver(const BasicTlsResolver &other)=delete
copy constructor.
typename Socket::UnderlyingSocket UnderlyingSocket
Definition resolver.hpp:1076
BasicTlsResolver(TlsContext ctx, const std::string &server={}, uint16_t port=Protocol::defaultPort, Reactor &reactor=ReactorThread::reactor())
construct the DoT resolver instance.
Definition resolver.hpp:1085
static AliasList lookupAllName(const IpAddress &address)=delete
resolve all host address.
static IpAddressList lookupAllAddress(const std::string &host, int family)=delete
resolve host name using system name servers and return all IP addresses found.
static ExchangerList lookupAllMailExchanger(const std::string &host)=delete
resolve all host mail exchanger.
static std::string lookupName(const IpAddress &address)=delete
resolve host address.
typename Protocol::Endpoint Endpoint
Definition resolver.hpp:1077
static IpAddress lookupAddress(const std::string &host, int family)=delete
resolve host name using system name servers.
typename Protocol::Socket Socket
Definition resolver.hpp:1075
static ServerList lookupAllNameServer(const std::string &host)=delete
resolve all host name server.
BasicTlsResolver(BasicTlsResolver &&other)=delete
move constructor.
condition variable class.
Definition condition.hpp:42
DNS message codec.
Definition dns_message.hpp:105
int serialize(const DnsPacket &packet, std::stringstream &data) const
serialize a DNS packet into a byte stream.
Definition dns_message.hpp:174
static std::string className(uint16_t recordClass)
get record class name.
Definition dns_message.hpp:360
@ A
Definition dns_message.hpp:112
@ PTR
Definition dns_message.hpp:116
@ SOA
Definition dns_message.hpp:115
@ NS
Definition dns_message.hpp:113
@ MX
Definition dns_message.hpp:117
@ CNAME
Definition dns_message.hpp:114
@ AAAA
Definition dns_message.hpp:119
int deserialize(DnsPacket &packet, std::stringstream &data) const
deserialize a DNS packet from a byte stream.
Definition dns_message.hpp:235
static std::error_code decodeError(uint16_t error) noexcept
convert DNS error to system error code.
Definition dns_message.hpp:311
@ IN
Definition dns_message.hpp:129
static std::string typeName(uint16_t recordType)
get record type name.
Definition dns_message.hpp:336
Event handler interface class.
Definition reactor.hpp:48
IPv6, IPv4 address class.
Definition ip_address.hpp:51
bool isWildcard() const
check if IP address is a wildcard address.
Definition ip_address.cpp:1295
static bool isIpAddress(const std::string &address)
check if the specified string is an IP address.
Definition ip_address.cpp:1376
class used to protect shared data from being simultaneously accessed by multiple threads.
Definition mutex.hpp:37
static Reactor & reactor()
get the global Reactor instance.
Definition reactor.cpp:584
Reactor class.
Definition reactor.hpp:156
int delHandler(int fd, bool sync=true) noexcept
delete handler from reactor.
Definition reactor.cpp:155
int addHandler(int fd, EventHandler *handler, bool wantRead=true, bool wantWrite=false, bool sync=true) noexcept
add handler to reactor.
Definition reactor.cpp:100
class owning a mutex for the duration of a scoped block.
Definition mutex.hpp:246
TLS/DTLS context.
Definition tls_context.hpp:42
Definition acceptor.hpp:32
std::unordered_set< std::string > ExchangerList
list of mail exchangers.
Definition dns_message.hpp:52
std::unordered_set< std::string > ServerList
list of name servers.
Definition dns_message.hpp:49
std::enable_if_t< std::numeric_limits< Type >::is_integer, Type > randomize()
create a random number.
Definition utils.hpp:434
std::unordered_set< std::string > AliasList
list of aliases.
Definition dns_message.hpp:46
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
std::vector< IpAddress > IpAddressList
List of IP address.
Definition ip_address.hpp:45
Definition error.hpp:144
pending synchronous request.
Definition resolver.hpp:1055
Condition cond
Definition resolver.hpp:1056
std::error_code ec
Definition resolver.hpp:1058
DnsPacket packet
Definition resolver.hpp:1057
DNS packet.
Definition dns_message.hpp:89
uint16_t id
Definition dns_message.hpp:90
uint16_t flags
Definition dns_message.hpp:91
uint16_t port
Definition dns_message.hpp:94
std::vector< QuestionRecord > questions
Definition dns_message.hpp:95
IpAddress src
Definition dns_message.hpp:92
IpAddress dest
Definition dns_message.hpp:93
std::vector< ResourceRecord > answers
Definition dns_message.hpp:96
question record.
Definition dns_message.hpp:58
std::string host
Definition dns_message.hpp:59
uint16_t type
Definition dns_message.hpp:60
uint16_t dnsclass
Definition dns_message.hpp:61
IpAddress address
Definition tcp_acceptor_test.cpp:35
uint16_t port
Definition tcp_acceptor_test.cpp:36