17#include <arpa/nameser.h>
37#define RESIPROCATE_SUBSYSTEM resip::Subsystem::DNS
42int DnsStub::mDnsTimeout = 0;
43int DnsStub::mDnsTries = 0;
44unsigned int DnsStub::mDnsFeatures = 0;
49 DebugLog(<<
"Host(A) Result: " << rr);
56 DebugLog(<<
"Host(AAAA) Result: " << rr);
58 ErrLog(<<
"Something called "
59 "DnsResultSink::onLogDnsResult(const DNSResult<DnsAAAARecord>& rr)"
60 " when ipv6 support was disabled.");
86 mInterruptorHandle(0),
87 mCommandFifo(&mSelectInterruptor),
91 mAsyncProcessHandler(asyncProcessHandler)
95 int retCode = mDnsProvider->
init(additional, socketFunc, mDnsTimeout, mDnsTries, mDnsFeatures);
101 throw DnsStubException(
"Library was not build w/ required capabilities(probably USE_IPV6 resip/ares mismatch",
106 ErrLog (<<
"Failed to initialize async dns library: " << err);
108 throw DnsStubException(
"Failed to initialize async dns library " + err, __FILE__,__LINE__);
114 for (set<Query*>::iterator it = mQueries.begin(); it != mQueries.end(); ++it)
126 if(mCommandFifo.size() > 0)
return 0;
138DnsStub::processFifo()
140 while (mCommandFifo.messageAvailable())
142 Command* command = mCommandFifo.getNext();
151 mSelectInterruptor.
process(fdset);
167 mCommandFifo.add(command);
170 if (mAsyncProcessHandler)
186 const unsigned char* abuf,
190 vector<RROverlay> overlays;
193 const unsigned char* aptr = abuf +
HFIXEDSZ;
196 for (
int i = 0; i < qdcount && aptr; ++i)
198 aptr = skipDNSQuestion(aptr, abuf, alen);
203 for (
int i = 0; i < ancount; i++)
205 aptr = createOverlay(abuf, alen, aptr, overlays);
210 for (
int i = 0; i < nscount; i++)
212 aptr = createOverlay(abuf, alen, aptr, overlays,
true);
217 for (
int i = 0; i < arcount; i++)
219 aptr = createOverlay(abuf, alen, aptr, overlays);
222 if (overlays.size() > 0)
225 sort(overlays.begin(), overlays.end());
227 vector<RROverlay>::iterator itLow = lower_bound(overlays.begin(), overlays.end(), *overlays.begin());
228 vector<RROverlay>::iterator itHigh = upper_bound(overlays.begin(), overlays.end(), *overlays.begin());
229 while (itLow != overlays.end())
231 mRRCache.
updateCache(key, (*itLow).type(), itLow, itHigh);
233 if (itHigh != overlays.end())
235 itHigh = upper_bound(itLow, overlays.end(), *itLow);
245 const unsigned char* abuf,
249 const unsigned char* aptr = abuf +
HFIXEDSZ;
252 for (
int i = 0; i < qdcount && aptr; ++i)
254 aptr = skipDNSQuestion(aptr, abuf, alen);
257 vector<RROverlay> overlays;
261 if (ancount != 0)
return;
265 if (nscount == 0)
return;
266 vector<RROverlay> soa;
267 aptr = createOverlay(abuf, alen, aptr, soa);
273 mRRCache.
cacheTTL(key, rrType, status, soa[0]);
277DnsStub::skipDNSQuestion(
const unsigned char *aptr,
278 const unsigned char *abuf,
289 throw DnsStubException(
"Failed DNS preparse", __FILE__, __LINE__);
298 throw DnsStubException(
"Failed DNS preparse", __FILE__, __LINE__);
328 return (
T_A == type);
331 return (
T_A == type ||
338 return (
T_A == type ||
347DnsStub::createOverlay(
const unsigned char* abuf,
349 const unsigned char* aptr,
350 vector<RROverlay>& overlays,
353 const unsigned char* rptr = aptr;
360 throw DnsStubException(
"Failed overlay creation", __FILE__, __LINE__);
366 throw DnsStubException(
"Failed overlay creation", __FILE__, __LINE__);
381 overlays.push_back(overlay);
387DnsStub::removeQuery(Query*
query)
389 set<Query*>::iterator it = mQueries.find(
query);
390 if (it != mQueries.end())
399 mTransform = transform;
415 mInterruptorHandle=0;
428DnsStub::Query::Query(
DnsStub& stub, ResultTransform* transform, ResultConverter* resultConv,
429 const Data& target,
int rrType,
433 mTransform(transform),
434 mResultConverter(resultConv),
439 mFollowCname(followCname)
444DnsStub::Query::~Query()
446 delete mResultConverter;
453 if (rr == RR_A::getRRType())
455 return RR_A::getRRTypeName();
458 else if(rr == RR_AAAA::getRRType())
460 return RR_AAAA::getRRTypeName();
463 else if (rr ==RR_NAPTR::getRRType())
465 return RR_NAPTR::getRRTypeName();
467 else if(rr == RR_SRV::getRRType())
469 return RR_SRV::getRRTypeName();
471 else if (rr == RR_CNAME::getRRType())
473 return RR_CNAME::getRRTypeName();
486 DnsResourceRecordsByPtr records;
489 Data targetToQuery = mTarget;
490 bool newTargetToQuery =
false;
492 cached = mStub.mRRCache.lookup(mTarget, mRRType, mProto, records, status);
497 int numRequeries = 0;
500 DnsResourceRecordsByPtr cnames;
501 if(mStub.mRRCache.lookup(targetToQuery,
T_CNAME, mProto, cnames, status) && cnames.size() > 0)
503 targetToQuery = (
dynamic_cast<DnsCnameRecord*
>(cnames[0]))->cname();
504 newTargetToQuery =
true;
511 }
while(++numRequeries < MAX_REQUERIES);
515 if (newTargetToQuery)
517 StackLog(<< mTarget <<
" mapped to CNAME " << targetToQuery);
518 cached = mStub.mRRCache.lookup(targetToQuery, mRRType, mProto, records, status);
523 if(mStub.mDnsProvider && mStub.mDnsProvider->hostFileLookupLookupOnlyMode())
526 StackLog (<< targetToQuery <<
" not cached. Doing hostfile lookup");
528 if (mStub.mDnsProvider->hostFileLookup(targetToQuery.
c_str(), address))
530 mStub.cache(mTarget, address);
531 DnsResourceRecordsByPtr result;
534 mStub.mRRCache.lookup(mTarget, mRRType, mProto, result, queryStatus);
537 mTransform->transform(mTarget, mRRType, result);
539 mResultConverter->notifyUser(mTarget, queryStatus, mStub.errorMessage(queryStatus), result, mSink);
547 mStub.removeQuery(
this);
553 StackLog (<< targetToQuery <<
" not cached. Doing external dns lookup, type=" <<
typeToData(mRRType));
554 mStub.lookupRecords(targetToQuery, mRRType,
this);
559 if (mTransform && !records.empty())
561 mTransform->transform(mTarget, mRRType, records);
563 mResultConverter->notifyUser(mTarget, status, mStub.errorMessage(status), records, mSink);
565 mStub.removeQuery(
this);
571DnsStub::Query::process(
int status,
const unsigned char* abuf,
const int alen)
586 if (mStub.mDnsProvider->hostFileLookup(mTarget.c_str(), address))
588 mStub.cache(mTarget, address);
590 DnsResourceRecordsByPtr result;
593 mStub.mRRCache.lookup(mTarget, mRRType, mProto, result, queryStatus);
596 mTransform->transform(mTarget, mRRType, result);
598 mResultConverter->notifyUser(mTarget, queryStatus, mStub.errorMessage(queryStatus), result, mSink);
599 mStub.removeQuery(
this);
606 mStub.cacheTTL(mTarget, mRRType, status, abuf, alen);
612 ErrLog(<<
"Couldn't parse failure response to lookup for " << mTarget);
619 ErrLog (<<
"Connection error " << mStub.errorMessage(status) <<
" for " << mTarget);
622 ErrLog (<<
"Server response error " << mStub.errorMessage(status) <<
" for " << mTarget);
628 ErrLog (<<
"Error " << mStub.errorMessage(status) <<
" for " << mTarget);
631 ErrLog(<<
"Garbage hostname failed to resolve: " << mStub.errorMessage(status) <<
" for " << mTarget);
634 ErrLog(<<
"Query was malformed (probably because hostname was "
635 "too long) " << mStub.errorMessage(status) <<
" for "
639 ErrLog (<<
"Bad lookup type " << mStub.errorMessage(status) <<
" for " << mTarget);
644 ErrLog (<<
"Unknown error " << mStub.errorMessage(status) <<
" for " << mTarget);
651 mResultConverter->notifyUser(mTarget, status, mStub.errorMessage(status), Empty, mSink);
653 mStub.removeQuery(
this);
658 bool bDeleteThis =
true;
661 const unsigned char* aptr = abuf +
HFIXEDSZ;
664 for (
int i = 0; i < qdcount && aptr; ++i)
668 aptr = mStub.skipDNSQuestion(aptr, abuf, alen);
672 ErrLog(<<
"Error parsing DNS record for " << mTarget <<
": " << e.
getMessage());
674 mStub.removeQuery(
this);
683 mResultConverter->notifyUser(mTarget, 0, mStub.errorMessage(0), Empty, mSink);
687 bool bGotAnswers =
true;
689 followCname(aptr, abuf, alen, bGotAnswers, bDeleteThis, targetToQuery);
694 DnsResourceRecordsByPtr result;
697 if (mTarget != targetToQuery)
DebugLog (<< mTarget <<
" mapped to " << targetToQuery <<
" and returned result");
698 mStub.mRRCache.lookup(targetToQuery, mRRType, mProto, result, queryStatus);
701 mTransform->transform(mTarget, mRRType, result);
703 mResultConverter->notifyUser(mTarget, queryStatus, mStub.errorMessage(queryStatus), result, mSink);
709 mStub.removeQuery(
this);
715DnsStub::Query::onDnsRaw(
int status,
const unsigned char* abuf,
int alen)
717 process(status, abuf, alen);
721DnsStub::Query::followCname(
const unsigned char* aptr,
const unsigned char*abuf,
const int alen,
bool& bGotAnswers,
bool& bDeleteThis,
Data& targetToQuery)
731 ErrLog(<<
"Failed DNS preparse for " << targetToQuery);
732 mResultConverter->notifyUser(mTarget,
ARES_EFORMERR,
"Failed DNS preparse", Empty, mSink);
737 targetToQuery = name;
742 mStub.cache(name, abuf, alen);
746 ErrLog(<<
"Failed to cache result for " << targetToQuery <<
": " << e.
getMessage());
757 if (mFollowCname && mReQuery < MAX_REQUERIES)
765 DnsResourceRecordsByPtr cnames;
766 if(mStub.mRRCache.lookup(targetToQuery,
T_CNAME, mProto, cnames, status) && cnames.size() > 0)
768 targetToQuery = (
dynamic_cast<DnsCnameRecord*
>(cnames[0]))->cname();
775 }
while(++mReQuery < MAX_REQUERIES);
777 DnsResourceRecordsByPtr result;
778 if (!mStub.mRRCache.lookup(targetToQuery, mRRType, mProto, result, status))
780 StackLog(<< targetToQuery <<
" not cached. Doing external dns lookup, type=" <<
typeToData(mRRType));
781 mStub.lookupRecords(targetToQuery, mRRType,
this);
789 mResultConverter->notifyUser(mTarget, 1, mStub.errorMessage(1), Empty, mSink);
799DnsStub::errorMessage(
int status)
805DnsStub::lookupRecords(
const Data& target,
unsigned short type,
DnsRawSink* sink)
807 mDnsProvider->
lookup(target.
c_str(), type,
this, sink);
820 SetEnumSuffixesCommand* command =
new SetEnumSuffixesCommand(*
this, suffixes);
824const std::vector<Data>&
827 return mEnumSuffixes;
831DnsStub::doSetEnumSuffixes(
const std::vector<Data>& suffixes)
833 mEnumSuffixes = suffixes;
839 SetEnumDomainsCommand* command =
new SetEnumDomainsCommand(*
this, domains);
843const std::map<Data,Data>&
850DnsStub::doSetEnumDomains(
const std::map<Data,Data>& domains)
852 mEnumDomains = domains;
858 ClearDnsCacheCommand* command =
new ClearDnsCacheCommand(*
this);
863DnsStub::doClearDnsCache()
871 LogDnsCacheCommand* command =
new LogDnsCacheCommand(*
this);
876DnsStub::doLogDnsCache()
884 GetDnsCacheDumpCommand* command =
new GetDnsCacheDumpCommand(*
this, key, handler);
900 ReloadDnsServersCommand* command =
new ReloadDnsServersCommand(*
this);
905DnsStub::doReloadDnsServers()
912 mDnsProvider->
init(mDnsTimeout, mDnsTries, mDnsFeatures);
static Data typeToData(int rr)
#define resip_assert(x)
This file needs to work for both C and C++ code.
Handles cross-platform sockets compatibility.
#define ARES_ECONNREFUSED
#define DNS_HEADER_QDCOUNT(h)
#define DNS_HEADER_NSCOUNT(h)
#define ARES_EDESTRUCTION
#define DNS_HEADER_ANCOUNT(h)
#define DNS_HEADER_ARCOUNT(h)
int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf, int alen, char **s, long *enclen)
virtual void handleProcessNotification()=0
The abstract base-class for all exceptions thrown by resip code.
const Data & getMessage() const noexcept
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
const char * c_str() const
Returns a null-terminated string representing.
@ Take
The Data instance takes complete ownership of the buffer.
virtual void onLogDnsResult(const DNSResult< DnsHostRecord > &)
virtual unsigned int getTimeTillNextProcessMS()
static NameserverList EmptyNameserverList
const std::map< Data, Data > & getEnumDomains() const
std::vector< GenericIPAddress > NameserverList
void removeResultTransform()
DnsStub(const NameserverList &additional=EmptyNameserverList, AfterSocketCreationFuncPtr socketFunc=0, AsyncProcessHandler *asyncProcessHandler=0, FdPollGrp *pollGrp=0)
std::vector< DnsResourceRecord * > DnsResourceRecordsByPtr
void setResultTransform(ResultTransform *)
void setEnumDomains(const std::map< Data, Data > &domains)
void cacheTTL(const Data &key, int rrType, int status, const unsigned char *abuf, int alen)
const std::vector< Data > & getEnumSuffixes() const
void setDnsCacheTTL(int ttl)
void setDnsCacheSize(int size)
virtual void queueCommand(Command *command)
void cache(const Data &key, in_addr addr)
virtual void process(FdSet &fdset)
void getDnsCacheDump(std::pair< unsigned long, unsigned long > key, GetDnsCacheDumpHandler *handler)
virtual void buildFdSet(FdSet &fdset)
void setPollGrp(FdPollGrp *pollGrp)
virtual void handleDnsRaw(ExternalDnsRawResult)
bool changeNameServers(const NameserverList &additional)
void setEnumSuffixes(const std::vector< Data > &suffixes)
virtual bool checkDnsChange()=0
virtual void lookup(const char *target, unsigned short type, ExternalDnsHandler *handler, void *userData)=0
virtual int init(const std::vector< GenericIPAddress > &additionalNameservers, AfterSocketCreationFuncPtr, int dnsTimeout=0, int dnsTries=0, unsigned int features=0)=0
virtual void freeResult(ExternalDnsRawResult res)=0
virtual bool hostFileLookupLookupOnlyMode()=0
virtual unsigned int getTimeTillNextProcessMS()=0
virtual void buildFdSet(fd_set &read, fd_set &write, int &size)=0
virtual char * errorMessage(long errorCode)=0
virtual void setPollGrp(FdPollGrp *grp)=0
virtual void process(fd_set &read, fd_set &write)=0
virtual void processTimers()=0
virtual void changeNameServers(const std::vector< GenericIPAddress > &additional)=0
virtual FdPollItemHandle addPollItem(Socket sock, FdPollEventMask newMask, FdPollItemIf *item)=0
virtual void delPollItem(FdPollItemHandle handle)=0
Object-oriented wrapper for your platform's file-descriptor set.
virtual void onDnsCacheDumpRetrieved(std::pair< unsigned long, unsigned long > key, const Data &dnsCache)=0
void updateCacheFromHostFile(const DnsHostRecord &)
void cacheTTL(const Data &target, const int rrType, const int status, RROverlay overlay)
void updateCache(const Data &target, const int rrType, Itr begin, Itr end)
void getCacheDump(Data &dnsCacheDump)
void process(FdSet &fdset)
cleanup signalled fd
Socket getReadSocket() const
void buildFdSet(FdSet &fdset)
Used to add the 'artificial' fd to the fdset that will be responsible for interrupting a subsequent s...
This file is used to handle compatibility fixes/tweaks so reSIProcate can function on multiple platfo...
dcm! – add UnusedChecking(_enum) below;
void(* AfterSocketCreationFuncPtr)(Socket s, int transportType, const char *file, int line)