reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
AresDns.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#if !defined(WIN32)
6#include <sys/types.h>
7#endif
8#include <time.h>
9
10#include "rutil/dns/AresDns.hxx"
12#include "rutil/Timer.hxx"
13
14#include "AresCompat.hxx"
15#if !defined(USE_CARES)
16#include "ares_private.h"
17#endif
18
19#include "rutil/Logger.hxx"
20#include "rutil/DnsUtil.hxx"
22#include "rutil/FdPoll.hxx"
24
25#if !defined(WIN32)
26#if !defined(__CYGWIN__)
27#include <arpa/nameser.h>
28#endif
29#endif
30
31#ifndef WIN32
32#pragma GCC diagnostic push
33#pragma GCC diagnostic warning "-Wdeprecated-declarations"
34#else
35#pragma warning(push)
36#pragma warning(3 : 4996)
37#endif
38
39using namespace resip;
40
41#define RESIPROCATE_SUBSYSTEM resip::Subsystem::DNS
42
43/**********************************************************************
44 *
45 * class AresDnsPollItem
46 *
47 * This is callback class used for epoll-based systems.
48 *
49 **********************************************************************/
50
51#if defined(USE_ARES)
52namespace resip
53{
54
55class AresDnsPollItem : public FdPollItemBase
56{
57 public:
58 AresDnsPollItem(FdPollGrp *grp, int fd, int using_tcp, AresDns& aresObj,
59 ares_channel chan, int server_idx)
60 : FdPollItemBase(grp, fd, FPEM_Read), mAres(aresObj),
61 mChannel(chan), mFd(fd), mUsingTcp(using_tcp), mServerIdx(server_idx),
62 mMask(FPEM_Read)
63 {
64 }
65
66 virtual void processPollEvent(FdPollEventMask mask);
67 void resetPollGrp(FdPollGrp *grp)
68 {
69 if(mPollGrp)
70 {
71 mPollGrp->delPollItem(mPollHandle);
72 }
73 mPollHandle = 0;
74 mPollGrp = grp;
75 if(mPollGrp)
76 {
77 mPollHandle = mPollGrp->addPollItem(mFd, mMask, this);
78 }
79 }
80 void updateMask(FdPollEventMask mask)
81 {
82 mMask = mask;
83 if(mPollGrp)
84 {
85 mPollGrp->modPollItem(mPollHandle, mMask);
86 }
87 }
88
89 AresDns& mAres;
90 ares_channel mChannel;
91 int mFd;
92 int mUsingTcp;
93 int mServerIdx;
94 FdPollEventMask mMask;
95
96 static void socket_poll_cb(void *cb_data,
97 ares_channel channel, int server_idx,
98 int fd, int using_tcp, ares_poll_action_t act);
99};
100
101};
102
103void
104AresDnsPollItem::processPollEvent(FdPollEventMask mask)
105{
106 resip_assert( (mask&(FPEM_Read|FPEM_Write))!= 0 );
107
108 time_t nowSecs;
109 time(&nowSecs);
110
111 ares_process_poll(mChannel, mServerIdx,
112 (mask&FPEM_Read)?(int)mPollSocket:-1, (mask&FPEM_Write)?(int)mPollSocket:-1,
113 nowSecs);
114}
115
121void
122AresDnsPollItem::socket_poll_cb(void *cb_data,
123 ares_channel channel, int server_idx,
124 int fd, int using_tcp, ares_poll_action_t act)
125{
126 AresDns *ares = static_cast<AresDns*>(cb_data);
127 //assert( ares );
128 FdPollGrp *grp = ares->mPollGrp;
129 //assert( grp );
130 AresDns::PollItemsMap::iterator it = ares->mPollItems.find(fd);
131 AresDnsPollItem* olditem(NULL);
132 if ( it != ares->mPollItems.end() )
133 {
134 resip_assert( it->second->mChannel==channel );
135 resip_assert( it->second->mServerIdx==server_idx );
136 resip_assert( it->second->mUsingTcp==using_tcp );
137 olditem = it->second;
138 }
139 switch ( act )
140 {
142 resip_assert( !olditem );
143 resip_assert( it == ares->mPollItems.end() );
145 ares->mPollItems[fd] = new AresDnsPollItem(grp, fd, using_tcp, *ares, channel, server_idx);
146 break;
148 resip_assert( olditem );
149 resip_assert( it != ares->mPollItems.end() );
150 ares->mPollItems.erase(it);
151 delete olditem; // destructor removes from poll
152 break;
154 resip_assert( olditem );
155 resip_assert( it != ares->mPollItems.end() );
156 olditem->updateMask(FPEM_Read|FPEM_Write);
157 break;
159 resip_assert( olditem );
160 resip_assert( it != ares->mPollItems.end() );
161 olditem->updateMask(FPEM_Read);
162 break;
163 default:
164 resip_assert( 0 );
165 }
166}
167
168#elif defined(USE_CARES)
169namespace resip
170{
171
172class AresDnsPollItem : public FdPollItemBase
173{
174 public:
175 AresDnsPollItem(FdPollGrp *grp, Socket fd, FdPollEventMask mask,
176 ares_channel channel)
177 : FdPollItemBase(grp, fd, mask), mChannel(channel), mMask(mask)
178 {
179 }
180
181 virtual void processPollEvent(FdPollEventMask mask);
182 void resetPollGrp(FdPollGrp *grp)
183 {
184 if(mPollGrp)
185 {
186 mPollGrp->delPollItem(mPollHandle);
187 }
188 mPollHandle = 0;
189 mPollGrp = grp;
190 if(mPollGrp)
191 {
192 mPollHandle = mPollGrp->addPollItem(mPollSocket, mMask, this);
193 }
194 }
195 void updateMask(FdPollEventMask mask)
196 {
197 if (mMask != mask)
198 {
199 mMask = mask;
200 if(mPollGrp)
201 {
202 mPollGrp->modPollItem(mPollHandle, mMask);
203 }
204 }
205 }
206
207 ares_channel mChannel;
208 FdPollEventMask mMask;
209
210 static void sockstate_cb(void* data, ares_socket_t sock, int read, int write);
211};
212
213}
214
215void
216AresDnsPollItem::processPollEvent(FdPollEventMask mask)
217{
219
220 if (mask & FPEM_Error)
221 {
222 /* An error happened. Just pretend that the socket is both readable and */
223 /* writable. */
224 ares_process_fd(mChannel, mPollSocket, mPollSocket);
225 return;
226 }
227
228 ares_process_fd(mChannel,
229 (mask & FPEM_Read) ? mPollSocket : ARES_SOCKET_BAD,
230 (mask & FPEM_Write) ? mPollSocket : ARES_SOCKET_BAD);
231}
232
233void
234AresDnsPollItem::sockstate_cb(void* data, ares_socket_t sock, int read, int write)
235{
236 AresDns *ares = static_cast<AresDns*>(data);
237 AresDns::PollItemsMap::iterator it = ares->mPollItems.find(sock);
238 if (read || write)
239 {
240 FdPollEventMask mask(
241 (read ? FPEM_Read : 0) | (write ? FPEM_Write : 0) | FPEM_Error);
242 if (it == ares->mPollItems.end()) // new socket
243 {
244 ares->mPollItems[sock] =
245 new AresDnsPollItem( ares->mPollGrp, sock, mask, ares->mChannel);
246 }
247 else
248 {
249 resip_assert( it->second->mChannel == ares->mChannel);
250 it->second->updateMask(mask);
251 }
252 }
253 else
254 {
255 /* read == 0 and write == 0 this is c-ares's way of notifying us that */
256 /* the socket is now closed */
257 resip_assert( it != ares->mPollItems.end());
258 resip_assert( it->second->mChannel == ares->mChannel);
259 AresDnsPollItem* item = it->second;
260 ares->mPollItems.erase(it);
261 delete item;
262 }
263}
264
265// The name servers a channel uses, IPv4 and IPv6 with their ports, as a
266// comma separated list. Empty if they cannot be read.
267static Data
268caresServers(ares_channel channel)
269{
270#if ARES_VERSION >= 0x011800
271 // ares_get_servers_csv() was added in c-ares 1.24, which deprecated
272 // ares_get_servers_ports()
273 char* csv = ares_get_servers_csv(channel);
274 if (!csv)
275 {
276 return Data::Empty;
277 }
278 Data servers(csv);
279 ares_free_string(csv);
280 return servers;
281#else
282 Data servers;
283 struct ares_addr_port_node* head = 0;
284 if (ares_get_servers_ports(channel, &head) != ARES_SUCCESS)
285 {
286 return servers;
287 }
288 for (struct ares_addr_port_node* node = head; node; node = node->next)
289 {
290 if (!servers.empty())
291 {
292 servers += ",";
293 }
294 if (node->family == AF_INET6)
295 {
296#if defined(USE_IPV6)
297 in6_addr addr6;
298 memcpy(&addr6, &node->addr.addr6, sizeof(addr6));
299 servers += "[" + DnsUtil::inet_ntop(addr6) + "]";
300#else
301 // DnsUtil formats no IPv6 here; dropIpv6Servers() only needs to
302 // see that this one is IPv6
303 servers += "[IPv6]";
304#endif
305 }
306 else
307 {
308 servers += DnsUtil::inet_ntop(node->addr.addr4);
309 }
310 servers += ":" + Data(node->udp_port);
311 }
312 ares_free_data(head);
313 return servers;
314#endif
315}
316
317// Replaces the channel's name servers. A port of 0 keeps the default, 53.
318// Without USE_IPV6, IPv6 name servers are ignored, as the bundled ares does;
319// if that leaves none, the channel keeps the ones c-ares found.
320static int
321setCaresServers(ares_channel channel, const std::vector<GenericIPAddress>& nameservers)
322{
323 // host[:port], with an IPv6 address in brackets when it has a port
324 Data csv;
325 for (size_t i = 0; i < nameservers.size(); ++i)
326 {
327 const bool v4 = nameservers[i].isVersion4();
328#if defined(USE_IPV6)
329 const Data address = v4 ? DnsUtil::inet_ntop(nameservers[i].v4Address.sin_addr)
330 : DnsUtil::inet_ntop(nameservers[i].v6Address.sin6_addr);
331#else
332 if (!v4)
333 {
334 WarningLog (<< "Ignoring non-IPv4 additional name server (IPv6 support was not enabled)");
335 continue;
336 }
337 const Data address = DnsUtil::inet_ntop(nameservers[i].v4Address.sin_addr);
338#endif
339 const unsigned short port = ntohs(v4 ? nameservers[i].v4Address.sin_port
340 : nameservers[i].v6Address.sin6_port);
341 if (!csv.empty())
342 {
343 csv += ",";
344 }
345 if (port == 0)
346 {
347 csv += address;
348 }
349 else
350 {
351 csv += (v4 ? address : "[" + address + "]") + ":" + Data(port);
352 }
353 }
354 if (csv.empty())
355 {
356 return ARES_SUCCESS;
357 }
358 return ares_set_servers_ports_csv(channel, csv.c_str());
359}
360
361#if !defined(USE_IPV6)
362// This build does no IPv6, so the resolver uses IPv4 name servers only, as the
363// bundled ares does: drop any IPv6 ones c-ares found in the system
364// configuration. If none are left, use 127.0.0.1, c-ares's own default.
365static int
366dropIpv6Servers(ares_channel channel)
367{
368 const std::string servers(caresServers(channel).c_str());
369 std::string ipv4;
370 bool dropped = false;
371 for (size_t start = 0; start < servers.size(); )
372 {
373 size_t end = servers.find(',', start);
374 if (end == std::string::npos)
375 {
376 end = servers.size();
377 }
378 const std::string server = servers.substr(start, end - start);
379 start = end + 1;
380 // "[addr]:port", or a bare address with more than one ':', is IPv6
381 const size_t firstColon = server.find(':');
382 if (server.empty() || server[0] == '[' ||
383 (firstColon != std::string::npos && server.find(':', firstColon + 1) != std::string::npos))
384 {
385 dropped = dropped || !server.empty();
386 continue;
387 }
388 ipv4 += (ipv4.empty() ? "" : ",") + server;
389 }
390 if (!dropped)
391 {
392 return ARES_SUCCESS;
393 }
394 InfoLog(<< "DNS initialization: ignoring IPv6 name servers (IPv6 support was not enabled)");
395 return ares_set_servers_ports_csv(channel, ipv4.empty() ? "127.0.0.1" : ipv4.c_str());
396}
397#endif
398
399// The socket function is called as for SIP TCP connections: before the
400// socket connects, and again once it is connected if
401// ExternalDns::setEnablePostConnectSocketFuncCall() is on.
402int
403AresDns::caresSocketConfigure(Socket s, int type, void* data)
404{
405 AresDns* ares = static_cast<AresDns*>(data);
406 if (ares->mSocketFunc)
407 {
408 ares->mSocketFunc(s, type == SOCK_STREAM ? TCP : UDP, __FILE__, __LINE__);
409 }
410 return ARES_SUCCESS;
411}
412
413int
414AresDns::caresSocketConnected(Socket s, int type, void* data)
415{
416 AresDns* ares = static_cast<AresDns*>(data);
417 if (ares->mSocketFunc && getEnablePostConnectSocketFuncCall())
418 {
419 ares->mSocketFunc(s, type == SOCK_STREAM ? TCP : UDP, __FILE__, __LINE__);
420 }
421 return ARES_SUCCESS;
422}
423
424#endif
425
426/**********************************************************************
427 *
428 * class AresDns
429 *
430 **********************************************************************/
431
432volatile bool AresDns::mHostFileLookupOnlyMode = false;
433
434void
436{
437 for(PollItemsMap::iterator i=mPollItems.begin();
438 i!=mPollItems.end(); ++i)
439 {
440 i->second->resetPollGrp(grp);
441 }
442 mPollGrp = grp;
443}
444
445void
446AresDns::clearPollItems()
447{
448 PollItemsMap items;
449 items.swap(mPollItems);
450 for(PollItemsMap::iterator i=items.begin();
451 i!=items.end(); ++i)
452 {
453 delete i->second;
454 }
455}
456
457int
458AresDns::init(const std::vector<GenericIPAddress>& additionalNameservers,
460 int timeout,
461 int tries,
462 unsigned int features)
463{
464 mAdditionalNameservers = additionalNameservers;
465 mSocketFunc = socketfunc;
466
467 return init(timeout, tries, features);
468}
469
470int
471AresDns::init(int dnsTimeout, int dnsTries, unsigned int features)
472{
473 mFeatures = features;
474
475 int ret = internalInit(mAdditionalNameservers,
476 mSocketFunc,
477 features,
478 &mChannel,
479 dnsTimeout,
480 dnsTries,
481 true /* useStateFunc */);
482
483 if (ret != Success)
484 return ret;
485
486 // Ensure map starts empty, since init may be called more than once
487 clearPollItems();
488
489#if defined(WIN32) && defined(USE_ARES)
490 // For windows OSs it is uncommon to run a local DNS server. Therefor if there
491 // are no defined DNS servers in windows networking and ARES just returned the
492 // loopback address (ie. default localhost server / named)
493 // then put resip DNS resolution into hostfile lookup only mode
494 if (mChannel->nservers == 1 &&
496 {
497 // enable hostfile only lookup mode
498 mHostFileLookupOnlyMode = true;
499 }
500 else
501 {
502 // disable hostfile only lookup mode
503 mHostFileLookupOnlyMode = false;
504 }
505#endif
506
507 return Success;
508}
509
510int
511AresDns::internalInit(const std::vector<GenericIPAddress>& additionalNameservers,
513 unsigned int features,
514 ares_channeldata** channel,
515 int timeout,
516 int tries,
517 bool useStateFunc)
518{
519 if(*channel)
520 {
521 // Fails all requests in progress with ARES_EDESTRUCTION, which their
522 // handlers are told about (see resip_AresDns_aresCallback)
523 ares_destroy(*channel);
524 *channel = 0;
525 }
526
527#if defined(USE_ARES)
528
529#ifdef USE_IPV6
530 int requiredCap = ARES_CAP_IPV6;
531#else
532 int requiredCap = 0;
533#endif
534
535 // Only the contrib/ares has this function
536 int cap = ares_capabilities(requiredCap);
537 if (cap != requiredCap)
538 {
539 ErrLog (<< "Build mismatch (ipv4/ipv6) problem in ares library"); // !dcm!
540 return BuildMismatch;
541 }
542#endif
543
544 int status;
545 ares_options opt;
546 int optmask = 0;
547
548 memset(&opt, '\0', sizeof(opt));
549
550#if defined(USE_ARES)
551 // TODO: What is this and how does it map to c-ares?
553 {
554 optmask |= ARES_OPT_FLAGS;
556 }
557#endif
558
559 if ((features & ExternalDns::ReturnAllResults))
560 {
561 optmask |= ARES_OPT_FLAGS;
563 }
564
565#if defined(USE_CARES)
566 // In c-ares, we can actually set the timeout and retries via the API
567 if (timeout > 0)
568 {
569 opt.timeout = timeout;
570 optmask |= ARES_OPT_TIMEOUT;
571 }
572
573 if (tries > 0)
574 {
575 opt.tries = tries;
576 optmask |= ARES_OPT_TRIES;
577 }
578
579 if ( useStateFunc )
580 {
581 // Always track c-ares sockets, so that a FdPollGrp set after init()
582 // (see setPollGrp) still picks them up.
583 opt.sock_state_cb = AresDnsPollItem::sockstate_cb;
584 opt.sock_state_cb_data = this;
585 optmask |= ARES_OPT_SOCK_STATE_CB;
586 }
587#endif
588
589#if defined(USE_ARES)
590#if !defined(USE_IPV6)
591 // This build does no IPv6: use only the IPv4 name servers, and if none are
592 // left, the ones ares finds itself
593 std::vector<in_addr> ipv4Nameservers;
594 for (size_t i = 0; i < additionalNameservers.size(); i++)
595 {
596 if (additionalNameservers[i].isVersion4())
597 {
598 ipv4Nameservers.push_back(additionalNameservers[i].v4Address.sin_addr);
599 }
600 else
601 {
602 WarningLog (<< "Ignoring non-IPv4 additional name server (IPv6 support was not enabled)");
603 }
604 }
605 if (ipv4Nameservers.empty())
606#else
607 if (additionalNameservers.empty())
608#endif
609 {
610 status = ares_init_options_with_socket_function(channel, &opt, optmask, socketfunc);
611 }
612 else
613 {
614 optmask |= ARES_OPT_SERVERS;
615
616#if defined(USE_IPV6)
617 opt.nservers = (int)additionalNameservers.size();
618 // With contrib/ares, you can configure IPv6 addresses for the
619 // nameservers themselves.
620 opt.servers = new multiFamilyAddr[additionalNameservers.size()];
621 for (size_t i =0; i < additionalNameservers.size(); i++)
622 {
623 if (additionalNameservers[i].isVersion4())
624 {
625 opt.servers[i].family = AF_INET;
626 opt.servers[i].addr = additionalNameservers[i].v4Address.sin_addr;
627 }
628 else
629 {
630 opt.servers[i].family = AF_INET6;
631 opt.servers[i].addr6 = additionalNameservers[i].v6Address.sin6_addr;
632 }
633 }
634#else
635 opt.nservers = (int)ipv4Nameservers.size();
636 opt.servers = new in_addr[ipv4Nameservers.size()];
637 for (size_t i = 0; i < ipv4Nameservers.size(); i++)
638 {
639 opt.servers[i] = ipv4Nameservers[i];
640 }
641#endif
642
643 status = ares_init_options_with_socket_function(channel, &opt, optmask, socketfunc);
644
645 delete [] opt.servers;
646 opt.servers = 0;
647 }
648#elif defined(USE_CARES)
649 status = ares_init_options(channel, &opt, optmask);
650 if (status == ARES_SUCCESS && !additionalNameservers.empty())
651 {
652 status = setCaresServers(*channel, additionalNameservers);
653 }
654#if !defined(USE_IPV6)
655 if (status == ARES_SUCCESS)
656 {
657 status = dropIpv6Servers(*channel);
658 }
659#endif
660 if (status == ARES_SUCCESS && socketfunc)
661 {
662 ares_set_socket_configure_callback(*channel, &AresDns::caresSocketConfigure, this);
663 ares_set_socket_callback(*channel, &AresDns::caresSocketConnected, this);
664 }
665#endif
666 if (status != ARES_SUCCESS)
667 {
668 ErrLog (<< "Failed to initialize DNS library (status=" << status << ")");
669 return status;
670 }
671 else
672 {
673
674#if defined(USE_ARES)
675
676 InfoLog(<< "DNS initialization: found " << (*channel)->nservers << " name servers");
677 for (int i = 0; i < (*channel)->nservers; ++i)
678 {
679#ifdef USE_IPV6
680 if((*channel)->servers[i].family == AF_INET6)
681 {
682 InfoLog(<< " name server: " << DnsUtil::inet_ntop((*channel)->servers[i].addr6));
683 }
684 else
685#endif
686 {
687 InfoLog(<< " name server: " << DnsUtil::inet_ntop((*channel)->servers[i].addr));
688 }
689 }
690
691 // In ares, we must manipulate these directly
692 if (timeout > 0)
693 {
694 (*channel)->timeout = timeout;
695 }
696
697 if (tries > 0)
698 {
699 (*channel)->tries = tries;
700 }
701
702 if ( useStateFunc )
703 {
704 // tell ares to let us know when things change; installed even
705 // without a group, so that a FdPollGrp set after init() (see
706 // setPollGrp) still picks up the sockets
707 ares_process_set_poll_cb(*channel, AresDnsPollItem::socket_poll_cb, this);
708 }
709
710#elif defined(USE_CARES)
711 {
712 // Log which version of c-ares we're using
713 InfoLog(<< "DNS initialization: using c-ares v"
714 << ::ares_version(NULL));
715
716 InfoLog(<< "DNS initialization: name servers " << caresServers(*channel));
717 }
718#endif
719
720 return Success;
721 }
722}
723
724void
725AresDns::changeNameServers(const std::vector<GenericIPAddress>& additional)
726{
727 mAdditionalNameservers = additional;
728}
729
731{
732 // We must return 'true' if there are changes in the list of DNS servers
733 struct ares_channeldata* channel = 0;
734 bool bRet = false;
735 int result = internalInit(mAdditionalNameservers, 0, mFeatures, &channel);
736 if(result != Success || channel == 0)
737 {
738 // It has changed because it failed, I suppose
739 InfoLog(<< " DNS server list changed");
740 return true;
741 }
742
743#if defined(USE_ARES)
744 {
745 // Compare the two lists. Are they different sizes?
746 if(mChannel->nservers != channel->nservers)
747 {
748 // Yes, so they're different
749 bRet = true;
750 }
751 else
752 {
753 // Compare them one-by-one
754 for (int i = 0; i < mChannel->nservers; ++i)
755 {
756#ifdef USE_IPV6
757 if(channel->servers[i].family == AF_INET6)
758 {
759 if(memcmp(&mChannel->servers[i].addr6, &channel->servers[i].addr6, sizeof(mChannel->servers[i].addr6)) != 0)
760 {
761 bRet = true;
762 break;
763 }
764 }
765 else
766#endif
767 {
768 if (mChannel->servers[i].addr.s_addr != channel->servers[i].addr.s_addr)
769 {
770 bRet = true;
771 break;
772 }
773 }
774 }
775 }
776
777 // Destroy the secondary configuration we read
779 }
780#elif defined(USE_CARES)
781 {
782 // Compare the server lists, IPv4 and IPv6 with their ports, of the old
783 // and the current (i.e. just read) configuration. If either cannot be
784 // read, call it different.
785 const Data old = caresServers(mChannel);
786 const Data updated = caresServers(channel);
787 bRet = old.empty() || updated.empty() || old != updated;
788
789 // Destroy the secondary configuration we read
790 ares_destroy(channel);
791 }
792#endif
793
794 // Report on the results
795 if(!bRet)
796 {
797 InfoLog(<< " No changes in DNS server list");
798 }
799 else
800 {
801 InfoLog(<< " DNS server list changed");
802 }
803
804 return bRet;
805}
806
808{
809 // Fails the queries in flight with ARES_EDESTRUCTION; with mDestroying set
810 // the callback frees their payloads without reporting them (see
811 // resip_AresDns_aresCallback)
812 mDestroying = true;
813 ares_destroy(mChannel);
814 clearPollItems();
815}
816
817bool AresDns::hostFileLookup(const char* target, in_addr &addr)
818{
819 resip_assert(target);
820
821 hostent *hostdata = 0;
822
823 // Look this up
824 int status =
825#if defined(USE_ARES)
826 hostfile_lookup(target, &hostdata)
827#elif defined(USE_CARES)
828 ares_gethostbyname_file(mChannel, target, AF_INET, &hostdata)
829#endif
830 ;
831
832 if (status != ARES_SUCCESS)
833 {
834 DebugLog(<< "hostFileLookup failed for " << target);
835 return false;
836 }
837 sockaddr_in saddr;
838 memset(&saddr,0,sizeof(saddr)); /* Initialize sockaddr fields. */
839 saddr.sin_family = AF_INET;
840 memcpy((char *)&(saddr.sin_addr.s_addr),(char *)hostdata->h_addr_list[0], (size_t)hostdata->h_length);
841 addr = saddr.sin_addr;
842#if defined(USE_ARES)
843 // for resip-ares, the hostdata (and its contents) is dynamically allocated
844 ares_free_hostent(hostdata);
845#endif
846
847 DebugLog(<< "hostFileLookup succeeded for " << target);
848 return true;
849}
850
852AresDns::getHandler(void* arg)
853{
854 return reinterpret_cast<Payload*>(arg)->handler;
855}
856
858AresDns::makeRawResult(void *arg, int status, unsigned char *abuf, int alen)
859{
860 void* userArg = reinterpret_cast<Payload*>(arg)->userData;
861
862 if (status != ARES_SUCCESS)
863 {
864 return ExternalDnsRawResult(status, abuf, alen, userArg);
865 }
866 else
867 {
868 return ExternalDnsRawResult(abuf, alen, userArg);
869 }
870}
871
872unsigned int
874{
875 struct timeval tv;
876 unsigned maxSystemTime = resip::Timer::getMaxSystemTimeWaitMs();
877 tv.tv_sec = maxSystemTime / 1000;
878 tv.tv_usec = 1000 * (maxSystemTime % 1000);
879 ares_timeout(mChannel, NULL, &tv);
880 return tv.tv_sec*1000 + tv.tv_usec / 1000;
881}
882
883void
884AresDns::buildFdSet(fd_set& read, fd_set& write, int& size)
885{
886#if defined(USE_CARES)
887 // ares_fds() is deprecated. c-ares reports every socket it opens, and
888 // what it waits for, through sock_state_cb (see AresDnsPollItem), which
889 // is installed with or without a FdPollGrp.
890 for (PollItemsMap::const_iterator i = mPollItems.begin(); i != mPollItems.end(); ++i)
891 {
892 const Socket fd = i->first;
893 if (i->second->mMask & FPEM_Read)
894 {
895 FD_SET(fd, &read);
896 }
897 if (i->second->mMask & FPEM_Write)
898 {
899 FD_SET(fd, &write);
900 }
901 if ((int)fd + 1 > size)
902 {
903 size = (int)fd + 1;
904 }
905 }
906#else
907 int newsize = ares_fds(mChannel, &read, &write);
908 if ( newsize > size )
909 {
910 size = newsize;
911 }
912#endif
913}
914
915void
917{
918#ifdef USE_CARES
919 // Process timeouts only; socket events arrive via AresDnsPollItem
920 ares_process_fd(mChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
921#else
922 resip_assert( mPollGrp!=0 );
923 time_t timeSecs;
924 time(&timeSecs);
925 ares_process_poll(mChannel, /*server*/-1, /*rd*/-1, /*wr*/-1, timeSecs);
926#endif
927}
928
929void
931{
932 process(fdset.read, fdset.write);
933}
934
935void
937{
938 buildFdSet(fdset.read, fdset.write, fdset.size);
939}
940
941void
942AresDns::process(fd_set& read, fd_set& write)
943{
944#if defined(USE_CARES)
945 // ares_process() is deprecated: hand each ready socket to
946 // ares_process_fd(), then let it handle timeouts. Collect the sockets
947 // first, since processing one can close others and change mPollItems.
948 std::vector<std::pair<Socket, FdPollEventMask> > ready;
949 for (PollItemsMap::const_iterator i = mPollItems.begin(); i != mPollItems.end(); ++i)
950 {
951 FdPollEventMask mask = 0;
952 if (FD_ISSET(i->first, &read))
953 {
954 mask |= FPEM_Read;
955 }
956 if (FD_ISSET(i->first, &write))
957 {
958 mask |= FPEM_Write;
959 }
960 if (mask)
961 {
962 ready.push_back(std::make_pair(i->first, mask));
963 }
964 }
965 for (size_t i = 0; i < ready.size(); ++i)
966 {
967 ares_process_fd(mChannel,
968 (ready[i].second & FPEM_Read) ? ready[i].first : ARES_SOCKET_BAD,
969 (ready[i].second & FPEM_Write) ? ready[i].first : ARES_SOCKET_BAD);
970 }
971 ares_process_fd(mChannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
972#else
973 ares_process(mChannel, &read, &write);
974#endif
975}
976
977char*
979{
980 const char* aresMsg = ares_strerror(errorCode);
981
982 size_t len = strlen(aresMsg);
983 char* errorString = new char[len+1];
984
985 snprintf(errorString, len+1, "%s", aresMsg);
986 errorString[len] = '\0';
987 return errorString;
988}
989
990#if defined(USE_CARES) && ARES_VERSION >= 0x011c00
991// ares_query_dnsrec() gives the reply parsed; DnsStub parses the raw reply
992// itself, so write it back out, as c-ares's own ares_query() does. The
993// callback runs for every query, failures included.
994static void
995resip_AresDns_caresDnsrecCallback(void* arg, ares_status_t status, size_t timeouts,
996 const ares_dns_record_t* dnsrec)
997{
998 unsigned char* abuf = 0;
999 size_t alen = 0;
1000 if (dnsrec)
1001 {
1002 ares_status_t writeStatus = ares_dns_write(dnsrec, &abuf, &alen);
1003 if (writeStatus != ARES_SUCCESS)
1004 {
1005 status = writeStatus;
1006 }
1007 }
1008 resip_AresDns_caresCallback(arg, (int)status, (int)timeouts, abuf, (int)alen);
1009 ares_free_string(abuf);
1010}
1011#endif
1012
1013void
1014AresDns::lookup(const char* target, unsigned short type, ExternalDnsHandler* handler, void* userData)
1015{
1016#if defined(USE_CARES) && ARES_VERSION >= 0x011c00
1017 // ares_query() was deprecated in c-ares 1.28, which added ares_query_dnsrec()
1018 ares_query_dnsrec(mChannel, target, ARES_CLASS_IN, (ares_dns_rec_type_t)type,
1019 resip_AresDns_caresDnsrecCallback, new Payload(handler, userData, this), 0);
1020#else
1021 ares_query(mChannel, target, C_IN, type,
1022#if defined(USE_ARES)
1024#elif defined(USE_CARES)
1026#endif
1027 new Payload(handler, userData, this));
1028#endif
1029}
1030
1031void
1032resip_AresDns_aresCallback(void *arg, int status, unsigned char *abuf, int alen)
1033{
1034 resip::AresDns::Payload* p = reinterpret_cast<resip::AresDns::Payload*>(arg);
1035
1036 // A destroyed channel fails its queries with ARES_EDESTRUCTION. When the
1037 // AresDns itself is being destroyed, its user (DnsStub) has already let go
1038 // of them, so only the payload is freed. When init() replaces the channel
1039 // (the DNS servers were reloaded), they are still wanted, so the failure
1040 // is reported like any other, as the bundled ares does.
1041 if (status == ARES_EDESTRUCTION && p->owner->mDestroying)
1042 {
1043 delete p;
1044 return;
1045 }
1046
1047 p->handler->handleDnsRaw(resip::AresDns::makeRawResult(arg, status, abuf, alen));
1048 delete p;
1049}
1050
1051void
1052resip_AresDns_caresCallback(void *arg, int status, int timeouts,
1053 unsigned char *abuf, int alen)
1054{
1055 // Simply ignore the timeouts argument
1056 return ::resip_AresDns_aresCallback(arg, status, abuf, alen);
1057}
1058
1059const char*
1061{
1062 if (rrtype == T_A)
1063 {
1064 return "A";
1065 }
1066#if defined(USE_IPV6)
1067 else if (rrtype == T_AAAA)
1068 {
1069 return "AAAA";
1070 }
1071#endif
1072 else if (rrtype == T_NAPTR)
1073 {
1074 return "NAPTR";
1075 }
1076 else if (rrtype == T_SRV)
1077 {
1078 return "SRV";
1079 }
1080 else if (rrtype == T_CNAME)
1081 {
1082 return "CNAME";
1083 }
1084 else
1085 {
1086 return "Unknown";
1087 }
1088}
1089
1090
1091/* ====================================================================
1092 * The Vovida Software License, Version 1.0
1093 *
1094 * Copyright (c) 2026 SIP Spectrum, Inc. http://www.sipspectrum.com
1095 * Copyright (c) 2000-2005 Vovida Networks, Inc. All rights reserved.
1096 *
1097 * Redistribution and use in source and binary forms, with or without
1098 * modification, are permitted provided that the following conditions
1099 * are met:
1100 *
1101 * 1. Redistributions of source code must retain the above copyright
1102 * notice, this list of conditions and the following disclaimer.
1103 *
1104 * 2. Redistributions in binary form must reproduce the above copyright
1105 * notice, this list of conditions and the following disclaimer in
1106 * the documentation and/or other materials provided with the
1107 * distribution.
1108 *
1109 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1110 * and "Vovida Open Communication Application Library (VOCAL)" must
1111 * not be used to endorse or promote products derived from this
1112 * software without prior written permission. For written
1113 * permission, please contact vocal@vovida.org.
1114 *
1115 * 4. Products derived from this software may not be called "VOCAL", nor
1116 * may "VOCAL" appear in their name, without prior written
1117 * permission of Vovida Networks, Inc.
1118 *
1119 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1120 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1121 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1122 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1123 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1124 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1125 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1126 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1127 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1128 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1129 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1130 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1131 * DAMAGE.
1132 *
1133 * ====================================================================
1134 *
1135 * This software consists of voluntary contributions made by Vovida
1136 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1137 * Inc. For more information on Vovida Networks, Inc., please see
1138 * <http://www.vovida.org/>.
1139 *
1140 * vi: shiftwidth=3 expandtab:
1141 */
void resip_AresDns_caresCallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
Definition AresDns.cxx:1052
void resip_AresDns_aresCallback(void *arg, int status, unsigned char *abuf, int alen)
Definition AresDns.cxx:1032
#define FPEM_Write
Definition FdPoll.hxx:30
#define FPEM_Read
Definition FdPoll.hxx:29
#define FPEM_Error
Definition FdPoll.hxx:31
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
#define INVALID_SOCKET
Definition Socket.hxx:95
#define ARES_SUCCESS
Definition ares.h:79
int ares_capabilities(int capmask)
Definition ares_init.c:94
@ ARES_POLLACTION_WRITEOFF
Definition ares.h:132
@ ARES_POLLACTION_WRITEON
Definition ares.h:131
@ ARES_POLLACTION_CLOSE
Definition ares.h:130
@ ARES_POLLACTION_OPEN
Definition ares.h:129
void ares_free_string(char *str)
int ares_init_options_with_socket_function(ares_channel *channelptr, struct ares_options *options, int optmask, socket_function_ptr)
Definition ares_init.c:120
#define ARES_CAP_IPV6
Definition ares.h:125
struct timeval * ares_timeout(ares_channel channel, struct timeval *maxtv, struct timeval *tv)
#define ARES_OPT_TIMEOUT
Definition ares.h:114
void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
const char * ares_strerror(int code)
#define ARES_OPT_SERVERS
Definition ares.h:119
void ares_destroy(ares_channel channel)
#define ARES_EDESTRUCTION
Definition ares.h:99
#define ARES_FLAG_NOCHECKRESP
Definition ares.h:109
void ares_process_poll(ares_channel channel, int server_idx, int rdFd, int wrFd, time_t now)
int ares_fds(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
Definition ares_fds.c:22
int hostfile_lookup(const char *name, struct hostent **host)
void ares_free_hostent(struct hostent *host)
#define ARES_OPT_FLAGS
Definition ares.h:113
void ares_query(ares_channel channel, const char *name, int dnsclass, int type, ares_callback callback, void *arg)
Definition ares_query.c:38
#define ARES_FLAG_TRY_NEXT_SERVER_ON_RCODE3
Definition ares.h:110
int ares_init_options(ares_channel *channelptr, struct ares_options *options, int optmask)
Definition ares_init.c:114
enum ares_poll_action ares_poll_action_t
void ares_destroy_suppress_callbacks(ares_channel channel)
void ares_process_set_poll_cb(ares_channel channel, ares_poll_cb_func *cb_func, void *cb_data)
#define ARES_OPT_TRIES
Definition ares.h:115
#define C_IN
#define T_CNAME
int Socket
virtual void setPollGrp(FdPollGrp *pollGrp)
Definition AresDns.cxx:435
virtual void processTimers()
Definition AresDns.cxx:916
virtual bool checkDnsChange()
Definition AresDns.cxx:730
static const char * dnsRRTypeToString(int rrtype)
Definition AresDns.cxx:1060
int internalInit(const std::vector< GenericIPAddress > &additionalNameservers, AfterSocketCreationFuncPtr socketfunc, unsigned int features=0, ares_channeldata **channel=0, int timeout=0, int tries=0, bool useStateFunc=false)
Definition AresDns.cxx:511
virtual char * errorMessage(long errorCode)
Definition AresDns.cxx:978
virtual ~AresDns()
Definition AresDns.cxx:807
virtual int init(const std::vector< GenericIPAddress > &additionalNameservers, AfterSocketCreationFuncPtr socketfunc, int timeout=0, int tries=0, unsigned int features=0)
Definition AresDns.cxx:458
virtual unsigned int getTimeTillNextProcessMS()
Definition AresDns.cxx:873
void lookup(const char *target, unsigned short type, ExternalDnsHandler *handler, void *userData)
Definition AresDns.cxx:1014
virtual bool hostFileLookup(const char *target, in_addr &addr)
Definition AresDns.cxx:817
virtual void process(FdSet &fdset)
Definition AresDns.cxx:930
friend void::resip_AresDns_caresCallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen)
friend void::resip_AresDns_aresCallback(void *arg, int status, unsigned char *abuf, int alen)
virtual void changeNameServers(const std::vector< GenericIPAddress > &additional)
Definition AresDns.cxx:725
virtual void buildFdSet(FdSet &fdset)
Definition AresDns.cxx:936
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
Data substr(size_type first, size_type count=Data::npos) const
Copies a portion of this Data into a new Data.
Definition Data.cxx:1932
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
Definition Data.cxx:1947
Provides a collection of utility functions for manipulating DNS names and IP addresses and discoverin...
Definition DnsUtil.hxx:29
static Data inet_ntop(const struct in_addr &addr)
Converts from the network format to presentation format.
Definition DnsUtil.cxx:240
static bool getEnablePostConnectSocketFuncCall()
virtual FdPollItemHandle addPollItem(Socket sock, FdPollEventMask newMask, FdPollItemIf *item)=0
Object-oriented wrapper for your platform's file-descriptor set.
Definition Socket.hxx:162
fd_set read
Definition Socket.hxx:256
fd_set write
Definition Socket.hxx:257
static unsigned getMaxSystemTimeWaitMs(void)
On windows, change getSystemTime() to not use the actual clock time returned by ::GetSystemTime().
Definition Timer.hxx:104
#define T_NAPTR
Definition compat.hxx:140
#define T_A
Definition compat.hxx:152
#define T_AAAA
Definition compat.hxx:148
#define T_SRV
Definition compat.hxx:144
dcm! – add UnusedChecking(_enum) below;
void(* AfterSocketCreationFuncPtr)(Socket s, int transportType, const char *file, int line)
Definition Socket.hxx:107
unsigned short FdPollEventMask
Definition FdPoll.hxx:28
int Socket
Definition Socket.hxx:94
struct server_state * servers
int tries
Definition ares.h:153
int flags
Definition ares.h:151
int nservers
Definition ares.h:162
int timeout
Definition ares.h:152
struct multiFamilyAddr * servers
Definition ares.h:158
struct in_addr addr
Definition ares.h:146
u_int8_t family
Definition ares.h:144
struct in6_addr addr6
Definition ares.h:145
u_int8_t family
struct in6_addr addr6
int default_localhost_server
struct in_addr addr