📄 dnsresult.cxx
字号:
#if defined(HAVE_CONFIG_H)
#include "resip/stack/config.hxx"
#endif
#include <algorithm>
#include <stack>
#ifndef WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#ifndef __CYGWIN__
# include <netinet/in.h>
# include <arpa/nameser.h>
# include <resolv.h>
#endif
#include <netdb.h>
#include <netinet/in.h>
#else
#include <Winsock2.h>
#include <svcguid.h>
#ifdef USE_IPV6
#include <ws2tcpip.h>
#endif
#endif
#if defined(USE_ARES)
#include "ares.h"
#include "ares_dns.h"
#endif
#include "rutil/DnsUtil.hxx"
#include "rutil/Inserter.hxx"
#include "rutil/Logger.hxx"
#include "rutil/ParseBuffer.hxx"
#include "rutil/Random.hxx"
#include "rutil/compat.hxx"
#include "rutil/WinLeakCheck.hxx"
#include "rutil/dns/DnsHandler.hxx"
#include "rutil/dns/QueryTypes.hxx"
#include "rutil/dns/DnsStub.hxx"
#include "rutil/dns/DnsNaptrRecord.hxx"
#include "resip/stack/DnsResult.hxx"
#include "resip/stack/DnsInterface.hxx"
#include "resip/stack/Tuple.hxx"
#include "resip/stack/Uri.hxx"
#include "rutil/WinLeakCheck.hxx"
#if !defined(USE_ARES)
#warning "ARES is required"
#endif
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM resip::Subsystem::DNS
DnsResult::DnsResult(DnsInterface& interfaceObj, DnsStub& dns, RRVip& vip, DnsHandler* handler)
: mInterface(interfaceObj),
mDns(dns),
mVip(vip),
mHandler(handler),
mSRVCount(0),
mDoingEnum(false),
mSips(false),
mTransport(UNKNOWN_TRANSPORT),
mPort(-1),
mType(Pending),
mBlacklistLastReturnedResult(false)
{
}
DnsResult::~DnsResult()
{
//DebugLog (<< "DnsResult::~DnsResult() " << *this);
assert(mType != Pending);
}
void
DnsResult::transition(Type t)
{
if ((t == Finished || t == Destroyed || t == Available) &&
(mType == Pending))
{
mInterface.mActiveQueryCount--;
assert(mInterface.mActiveQueryCount >= 0);
}
mType = t;
}
void
DnsResult::destroy()
{
assert(this);
//DebugLog (<< "DnsResult::destroy() " << *this);
if (mType == Pending)
{
transition(Destroyed);
}
else
{
delete this;
}
}
DnsResult::Type
DnsResult::available()
{
assert(mType != Destroyed);
if (mType == Available)
{
if (!mResults.empty())
{
return Available;
}
else
{
if (mBlacklistLastReturnedResult)
{
blacklistLastReturnedResult();
mBlacklistLastReturnedResult = false;
}
primeResults();
return available(); // recurse
}
}
else
{
return mType;
}
}
Tuple
DnsResult::next()
{
assert(available() == Available);
Tuple next = mResults.front();
mResults.pop_front();
StackLog (<< "Returning next dns entry: " << next);
if (mBlacklistLastReturnedResult)
{
blacklistLastReturnedResult();
}
else if (!mCurrResultPath.empty())
{
mBlacklistLastReturnedResult = true;
}
mLastReturnedResult = next;
assert(mCurrSuccessPath.size()<=3);
Item top;
if (!mCurrSuccessPath.empty())
{
top = mCurrSuccessPath.top();
if (top.rrType == T_A || top.rrType == T_AAAA)
{
mCurrSuccessPath.pop();
}
}
top.domain = next.getTargetDomain();
top.rrType = next.isV4()? T_A : T_AAAA;
top.value = Tuple::inet_ntop(next);
mCurrSuccessPath.push(top);
return next;
}
void DnsResult::success()
{
while (!mCurrSuccessPath.empty())
{
Item top = mCurrSuccessPath.top();
DebugLog( << "Whitelisting " << top.domain << "(" << top.rrType << "): " << top.value);
mVip.vip(top.domain, top.rrType, top.value);
mCurrSuccessPath.pop();
}
}
void
DnsResult::lookup(const Uri& uri, const std::vector<Data> &enumSuffixes)
{
DebugLog (<< "DnsResult::lookup " << uri);
//int type = this->mType;
if (!enumSuffixes.empty() && uri.isEnumSearchable())
{
mInputUri = uri;
mDoingEnum = true;
std::vector<Data> enums = uri.getEnumLookups(enumSuffixes);
assert(enums.size() <= 1);
if (!enums.empty())
{
InfoLog (<< "Doing ENUM lookup on " << *enums.begin());
mDns.lookup<RR_NAPTR>(*enums.begin(), Protocol::Enum, this);
return;
}
}
mDoingEnum = false;
lookupInternal(uri);
}
void
DnsResult::lookupInternal(const Uri& uri)
{
//assert(uri.scheme() == Symbols::Sips || uri.scheme() == Symbols::Sip);
mSips = (uri.scheme() == Symbols::Sips);
mTarget = (!mSips && uri.exists(p_maddr)) ? uri.param(p_maddr) : uri.host();
mSrvKey = Symbols::UNDERSCORE + uri.scheme().substr(0, uri.scheme().size()) + Symbols::DOT;
bool isNumeric = DnsUtil::isIpAddress(mTarget);
if (uri.exists(p_transport))
{
mTransport = Tuple::toTransport(uri.param(p_transport));
if (isNumeric) // IP address specified
{
mPort = getDefaultPort(mTransport, uri.port());
Tuple tuple(mTarget, mPort, mTransport, mTarget);
DebugLog (<< "Found immediate result: " << tuple);
mResults.push_back(tuple);
transition(Available);
if (mHandler) mHandler->handle(this);
}
else if (uri.port() != 0)
{
mPort = uri.port();
lookupHost(mTarget); // for current target and port
}
else
{
if (mSips)
{
if (mTransport == UDP)
{
mTransport = DTLS;
if (!mInterface.isSupportedProtocol(mTransport))
{
transition(Finished);
if (mHandler) mHandler->handle(this);
return;
}
mSRVCount++;
mDns.lookup<RR_SRV>("_sips._udp." + mTarget, Protocol::Sip, this);
StackLog (<< "Doing SRV lookup of _sips._udp." << mTarget);
}
else
{
mTransport = TLS;
if (!mInterface.isSupportedProtocol(mTransport))
{
transition(Finished);
if (mHandler) mHandler->handle(this);
return;
}
mSRVCount++;
mDns.lookup<RR_SRV>("_sips._tcp." + mTarget, Protocol::Sip, this);
StackLog (<< "Doing SRV lookup of _sips._tcp." << mTarget);
}
}
else
{
if (!mInterface.isSupportedProtocol(mTransport))
{
transition(Finished);
if (mHandler) mHandler->handle(this);
return;
}
switch(mTransport)
{
case TLS: //deprecated, mean TLS over TCP
mSRVCount++;
mDns.lookup<RR_SRV>("_sips._tcp." + mTarget, Protocol::Sip, this);
StackLog (<< "Doing SRV lookup of _sips._tcp." << mTarget);
break;
case DTLS: //deprecated, mean TLS over TCP
mSRVCount++;
mDns.lookup<RR_SRV>("_sip._dtls." + mTarget, Protocol::Sip, this);
StackLog (<< "Doing SRV lookup of _sip._dtls." << mTarget);
break;
case TCP:
mSRVCount++;
mDns.lookup<RR_SRV>("_sip._tcp." + mTarget, Protocol::Sip, this);
StackLog (<< "Doing SRV lookup of _sip._tcp." << mTarget);
break;
case SCTP:
case DCCP:
case UDP:
default: //fall through to UDP for unimplemented & unknown
mSRVCount++;
mDns.lookup<RR_SRV>("_sip._udp." + mTarget, Protocol::Sip, this);
StackLog (<< "Doing SRV lookup of _sip._udp." << mTarget);
}
}
}
}
else
{
if (isNumeric || uri.port() != 0)
{
if (mSips || mTransport == TLS)
{
mTransport = TLS;
}
else
{
mTransport = UDP;
}
if (isNumeric) // IP address specified
{
mPort = getDefaultPort(mTransport, uri.port());
Tuple tuple(mTarget, mPort, mTransport, mTarget);
mResults.push_back(tuple);
transition(Available);
DebugLog (<< "Numeric result so return immediately: " << tuple);
if (mHandler) mHandler->handle(this);
}
else // port specified so we know the transport
{
mPort = uri.port();
if (mInterface.isSupported(mTransport, V6) || mInterface.isSupported(mTransport, V4))
{
lookupHost(mTarget);
}
else
{
assert(0);
if (mHandler) mHandler->handle(this);
}
}
}
else // do NAPTR
{
mDns.lookup<RR_NAPTR>(mTarget, Protocol::Sip, this); // for current target
}
}
}
void DnsResult::lookupHost(const Data& target)
{
if (mInterface.isSupported(mTransport, V6))
{
#ifdef USE_IPV6
DebugLog(<< "Doing host (AAAA) lookup: " << target);
mPassHostFromAAAAtoA = target;
mDns.lookup<RR_AAAA>(target, Protocol::Sip, this);
#else
assert(0);
mDns.lookup<RR_A>(target, Protocol::Sip, this);
#endif
}
else if (mInterface.isSupported(mTransport, V4))
{
mDns.lookup<RR_A>(target, Protocol::Sip, this);
}
else
{
assert(0);
}
}
int
DnsResult::getDefaultPort(TransportType transport, int port)
{
if (port == 0)
{
switch (transport)
{
case UDP:
return Symbols::DefaultSipPort;
case TCP:
return mSips ? Symbols::DefaultSipsPort : Symbols::DefaultSipPort;
case TLS:
case DTLS:
return Symbols::DefaultSipsPort;
default:
ErrLog( << "Should not get this - unknown transport" );
return Symbols::DefaultSipPort; // !cj! todo - remove
assert(0);
}
}
else
{
return port;
}
assert(0);
return 0;
}
void
DnsResult::primeResults()
{
StackLog(<< "Priming " << Inserter(mSRVResults));
//assert(mType != Pending);
//assert(mType != Finished);
assert(mResults.empty());
if (!mSRVResults.empty())
{
SRV next = retrieveSRV();
StackLog (<< "Primed with SRV=" << next);
transition(Pending);
mPort = next.port;
mTransport = next.transport;
StackLog (<< "No A or AAAA record for " << next.target << " in additional records");
if (mInterface.isSupported(mTransport, V6) || mInterface.isSupported(mTransport, V4))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -