Copyright (C) 2003 - 2015 PowerDNS.COM BV
This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2
+ it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation
Additionally, the license of this program contains a special
#include "ws-recursor.hh"
#include <pthread.h>
#include "recpacketcache.hh"
-#include "utility.hh"
+#include "utility.hh"
#include "dns_random.hh"
#include <iostream>
#include <errno.h>
#define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10"
// Bad Nets taken from both:
-// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
+// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
// and
// http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
// where such a network may not be considered a valid destination
//! used to send information to a newborn mthread
struct DNSComboWriter {
- DNSComboWriter(const char* data, uint16_t len, const struct timeval& now) : d_mdp(data, len), d_now(now),
+ DNSComboWriter(const char* data, uint16_t len, const struct timeval& now) : d_mdp(data, len), d_now(now),
d_tcp(false), d_socket(-1)
{}
MOADNSParser d_mdp;
void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var);
// -1 is error, 0 is timeout, 1 is success
-int asendtcp(const string& data, Socket* sock)
+int asendtcp(const string& data, Socket* sock)
{
PacketID pident;
pident.sock=sock;
pident.outMSG=data;
-
+
t_fdm->addWriteFD(sock->getHandle(), handleTCPClientWritable, pident);
string packet;
return ret;
}
-vector<ComboAddress> g_localQueryAddresses4, g_localQueryAddresses6;
+vector<ComboAddress> g_localQueryAddresses4, g_localQueryAddresses6;
const ComboAddress g_local4("0.0.0.0"), g_local6("::");
//! pick a random query local address
{
ComboAddress ret;
if(family==AF_INET) {
- if(g_localQueryAddresses4.empty())
+ if(g_localQueryAddresses4.empty())
ret = g_local4;
- else
+ else
ret = g_localQueryAddresses4[dns_random(g_localQueryAddresses4.size())];
ret.sin4.sin_port = htons(port);
}
ret = g_local6;
else
ret = g_localQueryAddresses6[dns_random(g_localQueryAddresses6.size())];
-
+
ret.sin6.sin6_port = htons(port);
}
return ret;
{
uint32_t psize=0;
socklen_t len=sizeof(psize);
-
+
if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
L<<Logger::Error<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
- return;
+ return;
}
if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0 )
// we sometimes return a socket that has not yet been assigned to t_fdm
}
closesocket(*i);
-
+
d_socks.erase(i++);
--d_numsocks;
}
if(ret < 0 && errno==EMFILE) // this is not a catastrophic error
return ret;
-
- if(ret<0)
+
+ if(ret<0)
throw PDNSException("Making a socket for resolver (family = "+lexical_cast<string>(family)+"): "+stringerror());
setCloseOnExec(ret);
int tries=10;
while(--tries) {
uint16_t port;
-
+
if(tries==1) // fall back to kernel 'random'
port = 0;
else
port = 1025 + dns_random(64510);
-
+
ComboAddress sin=getQueryLocalAddress(family, port); // does htons for us
- if (::bind(ret, (struct sockaddr *)&sin, sin.getSocklen()) >= 0)
+ if (::bind(ret, (struct sockaddr *)&sin, sin.getSocklen()) >= 0)
break;
}
if(!tries)
throw PDNSException("Resolver binding to local query client socket: "+stringerror());
-
+
setNonBlocking(ret);
return ret;
}
/* these two functions are used by LWRes */
// -2 is OS error, -1 is error that depends on the remote, > 0 is success
-int asendto(const char *data, int len, int flags,
- const ComboAddress& toaddr, uint16_t id, const DNSName& domain, uint16_t qtype, int* fd)
+int asendto(const char *data, int len, int flags,
+ const ComboAddress& toaddr, uint16_t id, const DNSName& domain, uint16_t qtype, int* fd)
{
PacketID pident;
pident.fd=*fd;
pident.id=id;
-
+
t_fdm->addReadFD(*fd, handleUDPServerResponse, pident);
ret = send(*fd, data, len, 0);
}
// -1 is error, 0 is timeout, 1 is success
-int arecvfrom(char *data, int len, int flags, const ComboAddress& fromaddr, int *d_len,
+int arecvfrom(char *data, int len, int flags, const ComboAddress& fromaddr, int *d_len,
uint16_t id, const DNSName& domain, uint16_t qtype, int fd, struct timeval* now)
{
static optional<unsigned int> nearMissLimit;
- if(!nearMissLimit)
+ if(!nearMissLimit)
nearMissLimit=::arg().asNum("spoof-nearmiss-max");
PacketID pident;
if(ret > 0) {
if(packet.empty()) // means "error"
- return -1;
+ return -1;
*d_len=(int)packet.size();
memcpy(data,packet.c_str(),min(len,*d_len));
tcpClientCounts_t __thread* t_tcpClientCounts;
TCPConnection::TCPConnection(int fd, const ComboAddress& addr) : d_remote(addr), d_fd(fd)
-{
- ++s_currentConnections;
+{
+ ++s_currentConnections;
(*t_tcpClientCounts)[d_remote]++;
}
TCPConnection::~TCPConnection()
{
- if(closesocket(d_fd) < 0)
+ if(closesocket(d_fd) < 0)
unixDie("closing socket for TCPConnection");
- if(t_tcpClientCounts->count(d_remote) && !(*t_tcpClientCounts)[d_remote]--)
+ if(t_tcpClientCounts->count(d_remote) && !(*t_tcpClientCounts)[d_remote]--)
t_tcpClientCounts->erase(d_remote);
--s_currentConnections;
}
-AtomicCounter TCPConnection::s_currentConnections;
+AtomicCounter TCPConnection::s_currentConnections;
void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var);
// the idea is, only do things that depend on the *response* here. Incoming accounting is on incoming.
if(getEDNSOpts(dc->d_mdp, &edo) && !dc->d_tcp) {
maxanswersize = min(edo.d_packetsize, g_udpTruncationThreshold);
}
- ComboAddress local;
+ ComboAddress local;
listenSocketsAddresses_t::const_iterator lociter;
vector<DNSResourceRecord> ret;
vector<uint8_t> packet;
- DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
+ DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
pw.getHeader()->aa=0;
pw.getHeader()->ra=1;
sr.setLogMode(SyncRes::Store);
tracedQuery=true;
}
-
+
if(!g_quiet || tracedQuery)
L<<Logger::Warning<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote()<<endl;
getsockname(dc->d_socket, (sockaddr*)&local, &len); // if this fails, we're ok with it
}
- // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
+ // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer)) {
try {
res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
if(t_pdl->get()) {
if(res == RCode::NoError) {
vector<DNSResourceRecord>::const_iterator i;
- for(i=ret.begin(); i!=ret.end(); ++i)
+ for(i=ret.begin(); i!=ret.end(); ++i)
if(i->qtype.getCode() == dc->d_mdp.d_qtype && i->d_place == DNSResourceRecord::ANSWER)
break;
if(i == ret.end())
}
else if(res == RCode::NXDomain)
(*t_pdl)->nxdomain(dc->d_remote,local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer);
-
+
(*t_pdl)->postresolve(dc->d_remote,local, dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer);
}
}
-
+
if(res == PolicyDecision::DROP) {
g_stats.policyDrops++;
delete dc;
dc=0;
return;
- }
+ }
if(tracedQuery || res == PolicyDecision::PASS || res == RCode::ServFail || pw.getHeader()->rcode == RCode::ServFail)
{
string trace(sr.getTrace());
}
}
}
-
+
if(res == PolicyDecision::PASS) {
pw.getHeader()->rcode=RCode::ServFail;
// no commit here, because no record
else {
pw.getHeader()->rcode=res;
-
+
if(ret.size()) {
orderAndShuffle(ret);
for(vector<DNSResourceRecord>::const_iterator i=ret.begin(); i!=ret.end(); ++i) {
- pw.startRecord(i->qname, i->qtype.getCode(), i->ttl, i->qclass, (DNSPacketWriter::Place)i->d_place);
+ pw.startRecord(i->qname, i->qtype.getCode(), i->ttl, i->qclass, (DNSPacketWriter::Place)i->d_place);
minTTL = min(minTTL, i->ttl);
if(i->qtype.getCode() == QType::A) { // blast out A record w/o doing whole dnswriter thing
uint32_t ip=0;
IpToU32(i->content, &ip);
pw.xfr32BitInt(htonl(ip));
} else {
- shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(i->qtype.getCode(), i->qclass, i->content));
+ shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(i->qtype.getCode(), i->qclass, i->content));
drc->toPacket(pw);
}
if(pw.size() > maxanswersize) {
sendmsg(dc->d_socket, &msgh, 0);
if(!SyncRes::s_nopacketcache && !variableAnswer ) {
t_packetCache->insertResponsePacket(string((const char*)&*packet.begin(), packet.size()),
- g_now.tv_sec,
- min(minTTL,
+ g_now.tv_sec,
+ min(minTTL,
(pw.getHeader()->rcode == RCode::ServFail) ? SyncRes::s_packetcacheservfailttl : SyncRes::s_packetcachettl
- )
+ )
);
}
}
int ret=Utility::writev(dc->d_socket, iov, 2);
bool hadError=true;
- if(ret == 0)
+ if(ret == 0)
L<<Logger::Error<<"EOF writing TCP answer to "<<dc->getRemote()<<endl;
- else if(ret < 0 )
+ else if(ret < 0 )
L<<Logger::Error<<"Error writing TCP answer to "<<dc->getRemote()<<": "<< strerror(errno) <<endl;
else if((unsigned int)ret != 2 + packet.size())
L<<Logger::Error<<"Oops, partial answer sent to "<<dc->getRemote()<<" for "<<dc->d_mdp.d_qname<<" (size="<< (2 + packet.size()) <<", sent "<<ret<<")"<<endl;
else
hadError=false;
-
+
// update tcp connection status, either by closing or moving to 'BYTE0'
-
+
if(hadError) {
// no need to remove us from FDM, we weren't there
dc->d_socket = -1;
t_fdm->setReadTTD(dc->d_socket, g_now, g_tcpTimeout);
}
}
-
+
if(!g_quiet) {
L<<Logger::Error<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] answer to "<<(dc->d_mdp.d_header.rd?"":"non-rd ")<<"question '"<<dc->d_mdp.d_qname<<"|"<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype);
L<<"': "<<ntohs(pw.getHeader()->ancount)<<" answers, "<<ntohs(pw.getHeader()->arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<<
sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, "<<sr.d_tcpoutqueries<<" tcp connections, rcode="<<res<<endl;
}
- sr.d_outqueries ? t_RC->cacheMisses++ : t_RC->cacheHits++;
+ sr.d_outqueries ? t_RC->cacheMisses++ : t_RC->cacheHits++;
float spent=makeFloat(sr.d_now-dc->d_now);
if(spent < 0.001)
g_stats.answers0_1++;
catch(...) {
L<<Logger::Error<<"Any other exception in a resolver context "<< makeLoginfo(dc) <<endl;
}
-
+
g_stats.maxMThreadStackUsage = max(MT->getMaxStackUsage(), g_stats.maxMThreadStackUsage);
}
sockname += "."+lexical_cast<string>(processNum);
sockname+=".controlsocket";
s_rcc.listen(sockname);
-
+
int sockowner = -1;
int sockgroup = -1;
sockgroup=::arg().asGid("socket-group");
if (!::arg().isEmpty("socket-owner"))
sockowner=::arg().asUid("socket-owner");
-
+
if (sockgroup > -1 || sockowner > -1) {
if(chown(sockname.c_str(), sockowner, sockgroup) < 0) {
unixDie("Failed to chown control socket");
int bytes=recv(conn->getFD(), conn->data, 2, 0);
if(bytes==1)
conn->state=TCPConnection::BYTE1;
- if(bytes==2) {
+ if(bytes==2) {
conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
conn->bytesread=0;
conn->state=TCPConnection::GETQUESTION;
dc=new DNSComboWriter(conn->data, conn->qlen, g_now);
}
catch(MOADNSException &mde) {
- g_stats.clientParseError++;
+ g_stats.clientParseError++;
if(g_logCommonErrors)
L<<Logger::Error<<"Unable to parse packet from TCP client "<< conn->d_remote.toString() <<endl;
return;
if(t_remotes)
t_remotes->push_back(addr);
if(t_allowFrom && !t_allowFrom->match(&addr)) {
- if(!g_quiet)
+ if(!g_quiet)
L<<Logger::Error<<"["<<MT->getTid()<<"] dropping TCP query from "<<addr.toString()<<", address not matched by allow-from"<<endl;
g_stats.unauthorizedTCP++;
closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
return;
}
-
+
setNonBlocking(newsock);
shared_ptr<TCPConnection> tc(new TCPConnection(newsock, addr));
tc->state=TCPConnection::BYTE0;
-
+
t_fdm->addReadFD(tc->getFD(), handleRunningTCPQuestion, tc);
struct timeval now;
t_fdm->setReadTTD(tc->getFD(), now, g_tcpTimeout);
}
}
-
+
string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, struct timeval tv, int fd)
{
gettimeofday(&g_now, 0);
if(!g_quiet)
L<<Logger::Notice<<t_id<< " question answered from packet cache from "<<fromaddr.toString()<<endl;
// t_queryring->push_back("packetcached");
-
+
g_stats.packetCacheHits++;
SyncRes::s_queries++;
ageDNSPacket(response, age);
g_stats.avgLatencyUsec=(1-1.0/g_latencyStatSize)*g_stats.avgLatencyUsec + 0.0; // we assume 0 usec
return 0;
}
- }
+ }
catch(std::exception& e) {
L<<Logger::Error<<"Error processing or aging answer packet: "<<e.what()<<endl;
return 0;
}
-
+
if(t_pdl->get()) {
if((*t_pdl)->ipfilter(fromaddr, destaddr)) {
if(!g_quiet)
g_stats.overCapacityDrops++;
return 0;
}
-
+
DNSComboWriter* dc = new DNSComboWriter(question.c_str(), question.size(), g_now);
dc->setSocket(fd);
dc->setRemote(&fromaddr);
dc->d_tcp=false;
MT->makeThread(startDoResolve, (void*) dc); // deletes dc
return 0;
-}
-
+}
+
void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var)
{
fromaddr.sin6.sin6_family=AF_INET6; // this makes sure fromaddr is big enough
fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), data, sizeof(data), &fromaddr);
- for(;;)
+ for(;;)
if((len=recvmsg(fd, &msgh, 0)) >= 0) {
if(t_remotes)
t_remotes->push_back(fromaddr);
if(t_allowFrom && !t_allowFrom->match(&fromaddr)) {
- if(!g_quiet)
+ if(!g_quiet)
L<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toString()<<", address not matched by allow-from"<<endl;
g_stats.unauthorizedUDP++;
}
BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
if(!fromaddr.sin4.sin_port) { // also works for IPv6
- if(!g_quiet)
+ if(!g_quiet)
L<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toStringWithPort()<<", can't deal with port 0"<<endl;
g_stats.clientParseError++; // not quite the best place to put it, but needs to go somewhere
}
try {
dnsheader* dh=(dnsheader*)data;
-
+
if(dh->qr) {
if(g_logCommonErrors)
L<<Logger::Error<<"Ignoring answer from "<<fromaddr.toString()<<" on server socket!"<<endl;
}
}
catch(MOADNSException& mde) {
- g_stats.clientParseError++;
+ g_stats.clientParseError++;
if(g_logCommonErrors)
L<<Logger::Error<<"Unable to parse packet from remote UDP client "<<fromaddr.toString() <<": "<<mde.what()<<endl;
}
}
else {
// cerr<<t_id<<" had error: "<<stringerror()<<endl;
- if(errno == EAGAIN)
+ if(errno == EAGAIN)
g_stats.noPacketError++;
break;
}
if(locals.empty())
throw PDNSException("No local address specified");
-
+
for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
ServiceTuple st;
st.port=::arg().asNum("local-port");
parseService(*i, st);
-
+
ComboAddress sin;
memset((char *)&sin,0, sizeof(sin));
if(!IpToU32(st.host, (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
sin.sin6.sin6_family = AF_INET6;
if(makeIPv6sockaddr(st.host, &sin.sin6) < 0)
- throw PDNSException("Unable to resolve local address for TCP server on '"+ st.host +"'");
+ throw PDNSException("Unable to resolve local address for TCP server on '"+ st.host +"'");
}
fd=socket(sin.sin6.sin6_family, SOCK_STREAM, 0);
- if(fd<0)
+ if(fd<0)
throw PDNSException("Making a TCP server socket for resolver: "+stringerror());
setCloseOnExec(fd);
sin.sin4.sin_port = htons(st.port);
int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
- if (::bind(fd, (struct sockaddr *)&sin, socklen )<0)
+ if (::bind(fd, (struct sockaddr *)&sin, socklen )<0)
throw PDNSException("Binding TCP server socket for "+ st.host +": "+stringerror());
-
+
setNonBlocking(fd);
setSocketSendBuffer(fd, 65000);
listen(fd, 128);
g_tcpListenSockets.push_back(fd);
// we don't need to update g_listenSocketsAddresses since it doesn't work for TCP/IP:
// - fd is not that which we know here, but returned from accept()
- if(sin.sin4.sin_family == AF_INET)
+ if(sin.sin4.sin_family == AF_INET)
L<<Logger::Error<<"Listening for TCP queries on "<< sin.toString() <<":"<<st.port<<endl;
else
L<<Logger::Error<<"Listening for TCP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
if(locals.empty())
throw PDNSException("No local address specified");
-
+
for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
ServiceTuple st;
st.port=::arg().asNum("local-port");
if(!IpToU32(st.host.c_str() , (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
sin.sin6.sin6_family = AF_INET6;
if(makeIPv6sockaddr(st.host, &sin.sin6) < 0)
- throw PDNSException("Unable to resolve local address for UDP server on '"+ st.host +"'");
+ throw PDNSException("Unable to resolve local address for UDP server on '"+ st.host +"'");
}
-
+
int fd=socket(sin.sin4.sin_family, SOCK_DGRAM, 0);
if(fd < 0) {
throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
if(IsAnyAddress(sin)) {
setsockopt(fd, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
#ifdef IPV6_RECVPKTINFO
- setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+ setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
#endif
if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) {
L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
sin.sin4.sin_port = htons(st.port);
int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
- if (::bind(fd, (struct sockaddr *)&sin, socklen)<0)
+ if (::bind(fd, (struct sockaddr *)&sin, socklen)<0)
throw PDNSException("Resolver binding to server socket on port "+ lexical_cast<string>(st.port) +" for "+ st.host+": "+stringerror());
-
+
setNonBlocking(fd);
deferredAdd.push_back(make_pair(fd, handleNewUDPQuestion));
g_listenSocketsAddresses[fd]=sin; // this is written to only from the startup thread, not from the workers
- if(sin.sin4.sin_family == AF_INET)
+ if(sin.sin4.sin_family == AF_INET)
L<<Logger::Error<<"Listening for UDP queries on "<< sin.toString() <<":"<<st.port<<endl;
else
L<<Logger::Error<<"Listening for UDP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
{
if(fork())
exit(0); // bye bye
-
- setsid();
+
+ setsid();
int i=open("/dev/null",O_RDWR); /* open stdin */
- if(i < 0)
+ if(i < 0)
L<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
else {
dup2(i,0); /* stdin */
uint64_t cacheHits = broadcastAccFunction<uint64_t>(pleaseGetCacheHits);
uint64_t cacheMisses = broadcastAccFunction<uint64_t>(pleaseGetCacheMisses);
-
+
if(g_stats.qcounter && (cacheHits + cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) {
L<<Logger::Warning<<"stats: "<<g_stats.qcounter<<" questions, "<<
broadcastAccFunction<uint64_t>(pleaseGetCacheSize)<< " cache entries, "<<
broadcastAccFunction<uint64_t>(pleaseGetNegCacheSize)<<" negative entries, "<<
- (int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits"<<endl;
-
+ (int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits"<<endl;
+
L<<Logger::Warning<<"stats: throttle map: "
<< broadcastAccFunction<uint64_t>(pleaseGetThrottleSize) <<", ns speeds: "
- << broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize)<<endl;
+ << broadcastAccFunction<uint64_t>(pleaseGetNsSpeedsSize)<<endl;
L<<Logger::Warning<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
L<<Logger::Warning<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
<<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
//L<<Logger::Warning<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
//g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
-
+
L<<Logger::Warning<<"stats: " << broadcastAccFunction<uint64_t>(pleaseGetPacketCacheSize) <<
" packet cache entries, "<<(int)(100.0*broadcastAccFunction<uint64_t>(pleaseGetPacketCacheHits)/SyncRes::s_queries) << "% packet cache hits"<<endl;
-
+
time_t now = time(0);
if(lastOutputTime && lastQueryCount && now != lastOutputTime) {
L<<Logger::Warning<<"stats: "<< (SyncRes::s_queries - lastQueryCount) / (now - lastOutputTime) <<" qps (average over "<< (now - lastOutputTime) << " seconds)"<<endl;
lastOutputTime = now;
lastQueryCount = SyncRes::s_queries;
}
- else if(statsWanted)
+ else if(statsWanted)
L<<Logger::Warning<<"stats: no stats yet!"<<endl;
statsWanted=false;
if(s_running)
return;
s_running=true;
-
+
struct timeval now;
Utility::gettimeofday(&now, 0);
-
- if(now.tv_sec - last_prune > (time_t)(5 + t_id)) {
+
+ if(now.tv_sec - last_prune > (time_t)(5 + t_id)) {
DTime dt;
dt.setTimeval(now);
t_RC->doPrune(); // this function is local to a thread, so fine anyhow
t_packetCache->doPruneTo(::arg().asNum("max-packetcache-entries") / g_numWorkerThreads);
-
+
pruneCollection(t_sstorage->negcache, ::arg().asNum("max-cache-entries") / (g_numWorkerThreads * 10), 200);
-
+
if(!((cleanCounter++)%40)) { // this is a full scan!
time_t limit=now.tv_sec-300;
for(SyncRes::nsspeeds_t::iterator i = t_sstorage->nsSpeeds.begin() ; i!= t_sstorage->nsSpeeds.end(); )
}
last_prune=time(0);
}
-
+
if(now.tv_sec - last_rootupdate > 7200) {
SyncRes sr(now);
sr.setDoEDNS0(true);
vector<DNSResourceRecord> ret;
-
+
sr.setNoCache();
int res=-1;
try {
else
L<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
}
-
+
if(!t_id) {
- if(now.tv_sec - last_stat >= 1800) {
+ if(now.tv_sec - last_stat >= 1800) {
doStats();
last_stat=time(0);
}
-
+
if(now.tv_sec - last_secpoll >= 3600) {
try {
doSecPoll(&last_secpoll);
int fd[2];
if(pipe(fd) < 0)
unixDie("Creating pipe for inter-thread communications");
-
+
tps.readToThread = fd[0];
tps.writeToThread = fd[1];
-
+
if(pipe(fd) < 0)
unixDie("Creating pipe for inter-thread communications");
tps.readFromThread = fd[0];
tps.writeFromThread = fd[1];
-
+
g_pipes.push_back(tps);
}
}
void broadcastFunction(const pipefunc_t& func, bool skipSelf)
{
unsigned int n = 0;
- BOOST_FOREACH(ThreadPipeSet& tps, g_pipes)
+ BOOST_FOREACH(ThreadPipeSet& tps, g_pipes)
{
if(n++ == t_id) {
if(!skipSelf)
func(); // don't write to ourselves!
continue;
}
-
+
ThreadMSG* tmsg = new ThreadMSG();
tmsg->func = func;
tmsg->wantAnswer = true;
if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg))
unixDie("write to thread pipe returned wrong size or error");
-
+
string* resp;
if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
unixDie("read from thread pipe returned wrong size or error");
-
+
if(resp) {
// cerr <<"got response: " << *resp << endl;
delete resp;
}
uint32_t g_disthashseed;
-void distributeAsyncFunction(const std::string& question, const pipefunc_t& func)
+void distributeAsyncFunction(const DNSName& question, const pipefunc_t& func)
{
- unsigned int hash = hashQuestion(question.c_str(), question.length(), g_disthashseed);
+ string squestion = question.toString();
+ unsigned int hash = hashQuestion(squestion.c_str(), squestion.length(), g_disthashseed);
unsigned int target = 1 + (hash % (g_pipes.size()-1));
if(target == t_id) {
func();
return;
}
- ThreadPipeSet& tps = g_pipes[target];
+ ThreadPipeSet& tps = g_pipes[target];
ThreadMSG* tmsg = new ThreadMSG();
tmsg->func = func;
tmsg->wantAnswer = false;
-
+
if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg))
- unixDie("write to thread pipe returned wrong size or error");
+ unixDie("write to thread pipe returned wrong size or error");
}
void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var)
{
ThreadMSG* tmsg;
-
- if(read(fd, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // fd == readToThread
+
+ if(read(fd, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // fd == readToThread
unixDie("read from thread pipe returned wrong size or error");
}
-
+
void *resp=0;
try {
resp = tmsg->func();
if(tmsg->wantAnswer)
if(write(g_pipes[t_id].writeFromThread, &resp, sizeof(resp)) != sizeof(resp))
unixDie("write to thread pipe returned wrong size or error");
-
+
delete tmsg;
}
return a;
}
+vector<pair<DNSName, uint16_t> >& operator+=(vector<pair<DNSName, uint16_t> >&a, const vector<pair<DNSName, uint16_t> >& b)
+{
+ a.insert(a.end(), b.begin(), b.end());
+ return a;
+}
+
template<class T> T broadcastAccFunction(const boost::function<T*()>& func, bool skipSelf)
{
unsigned int n = 0;
T ret=T();
- BOOST_FOREACH(ThreadPipeSet& tps, g_pipes)
+ BOOST_FOREACH(ThreadPipeSet& tps, g_pipes)
{
if(n++ == t_id) {
if(!skipSelf) {
}
continue;
}
-
+
ThreadMSG* tmsg = new ThreadMSG();
tmsg->func = boost::bind(voider<T>, func);
tmsg->wantAnswer = true;
-
+
if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg))
unixDie("write to thread pipe returned wrong size or error");
-
-
+
+
T* resp;
if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp))
unixDie("read from thread pipe returned wrong size or error");
-
+
if(resp) {
//~ cerr <<"got response: " << *resp << endl;
ret += *resp;
template string broadcastAccFunction(const boost::function<string*()>& fun, bool skipSelf); // explicit instantiation
template uint64_t broadcastAccFunction(const boost::function<uint64_t*()>& fun, bool skipSelf); // explicit instantiation
template vector<ComboAddress> broadcastAccFunction(const boost::function<vector<ComboAddress> *()>& fun, bool skipSelf); // explicit instantiation
-template vector<pair<string,uint16_t> > broadcastAccFunction(const boost::function<vector<pair<string, uint16_t> > *()>& fun, bool skipSelf); // explicit instantiation
+template vector<pair<DNSName,uint16_t> > broadcastAccFunction(const boost::function<vector<pair<DNSName, uint16_t> > *()>& fun, bool skipSelf); // explicit instantiation
void handleRCC(int fd, FDMultiplexer::funcparam_t& var)
{
string msg=s_rcc.recv(&remote);
RecursorControlParser rcp;
RecursorControlParser::func_t* command;
-
+
string answer=rcp.getAnswer(msg, &command);
try {
s_rcc.send(answer, &remote);
// cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
PacketID pid=*pident;
string msg=pident->inMSG;
-
+
t_fdm->removeReadFD(fd);
- MT->sendEvent(pid, &msg);
+ MT->sendEvent(pid, &msg);
}
else {
// cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
if(len < 0)
; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
else {
- g_stats.serverParseError++;
+ g_stats.serverParseError++;
if(g_logCommonErrors)
L<<Logger::Error<<"Unable to parse packet from remote UDP server "<< fromaddr.toString() <<
": packet smaller than DNS header"<<endl;
string empty;
MT_t::waiters_t::iterator iter=MT->d_waiters.find(pid);
- if(iter != MT->d_waiters.end())
+ if(iter != MT->d_waiters.end())
doResends(iter, pid, empty);
-
+
MT->sendEvent(pid, &empty); // this denotes error (does lookup again.. at least L1 will be hot)
return;
- }
+ }
dnsheader dh;
memcpy(&dh, data, sizeof(dh));
-
+
PacketID pident;
pident.remote=fromaddr;
pident.id=dh.id;
}
// be a bit paranoid here since we're weakening our matching
- if(pident.domain.empty() && !mthread->key.domain.empty() && !pident.type && mthread->key.type &&
+ if(pident.domain.empty() && !mthread->key.domain.empty() && !pident.type && mthread->key.type &&
pident.id == mthread->key.id && mthread->key.remote == pident.remote) {
// cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
pident.domain = mthread->key.domain;
exit(1);
}
-
+
string* doReloadLuaScript()
{
string fname= ::arg()["lua-dns-script"];
L<<Logger::Error<<t_id<<" Retaining current script, error from '"<<fname<<"': "<< e.what() <<endl;
return new string("retaining current script, error from '"+fname+"': "+e.what()+"\n");
}
-
+
L<<Logger::Warning<<t_id<<" (Re)loaded lua script from '"<<fname<<"'"<<endl;
return new string("(re)loaded '"+fname+"'\n");
}
string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end)
{
- if(begin != end)
+ if(begin != end)
::arg().set("lua-dns-script") = *begin;
-
+
return broadcastAccFunction<string>(doReloadLuaScript);
-}
+}
string* pleaseUseNewTraceRegex(const std::string& newRegex)
try
void parseACLs()
{
static bool l_initialized;
-
+
if(l_initialized) { // only reload configuration file on second call
string configname=::arg()["config-dir"]+"/recursor.conf";
cleanSlashes(configname);
-
- if(!::arg().preParseFile(configname.c_str(), "allow-from-file"))
+
+ if(!::arg().preParseFile(configname.c_str(), "allow-from-file"))
throw runtime_error("Unable to re-parse configuration file '"+configname+"'");
::arg().preParseFile(configname.c_str(), "allow-from", LOCAL_NETS);
::arg().preParseFile(configname.c_str(), "include-dir");
}
NetmaskGroup* oldAllowFrom = t_allowFrom, *allowFrom=new NetmaskGroup;
-
+
if(!::arg()["allow-from-file"].empty()) {
string line;
ifstream ifs(::arg()["allow-from-file"].c_str());
if(!ifs) {
- delete allowFrom;
+ delete allowFrom;
throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
}
else if(!::arg()["allow-from"].empty()) {
vector<string> ips;
stringtok(ips, ::arg()["allow-from"], ", ");
-
+
L<<Logger::Warning<<"Only allowing queries from: ";
for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
allowFrom->addMask(*i);
L<<Logger::Warning<<endl;
}
else {
- if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
+ if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
L<<Logger::Error<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl;
delete allowFrom;
allowFrom = 0;
}
-
+
g_initialAllowFrom = allowFrom;
broadcastFunction(boost::bind(pleaseSupplantACLs, allowFrom));
delete oldAllowFrom;
-
+
l_initialized = true;
}
}
g_quiet=::arg().mustDo("quiet");
-
+
g_weDistributeQueries = ::arg().mustDo("pdns-distributes-queries");
if(g_weDistributeQueries) {
L<<Logger::Warning<<"PowerDNS Recursor itself will distribute queries over threads"<<endl;
}
-
+
if(::arg()["trace"]=="fail") {
SyncRes::setDefaultLogMode(SyncRes::Store);
}
::arg().set("quiet")="no";
g_quiet=false;
}
-
+
SyncRes::s_minimumTTL = ::arg().asNum("minimum-ttl-override");
checkLinuxIPv6Limits();
try {
- vector<string> addrs;
+ vector<string> addrs;
if(!::arg()["query-local-address6"].empty()) {
SyncRes::s_doIPv6=true;
L<<Logger::Warning<<"Enabling IPv6 transport for outgoing queries"<<endl;
-
+
stringtok(addrs, ::arg()["query-local-address6"], ", ;");
BOOST_FOREACH(const string& addr, addrs) {
g_localQueryAddresses6.push_back(ComboAddress(addr));
gethostname(tmp, sizeof(tmp)-1);
SyncRes::s_serverID=tmp;
}
-
+
g_networkTimeoutMsec = ::arg().asNum("network-timeout");
g_initialDomainMap = parseAuthAndForwards();
-
+
g_latencyStatSize=::arg().asNum("latency-statistic-size");
-
+
g_logCommonErrors=::arg().mustDo("log-common-errors");
g_anyToTcp = ::arg().mustDo("any-to-tcp");
if(!fork()) // we are child
break;
}
-
+
s_pidfname=::arg()["socket-dir"]+"/"+s_programname+".pid";
if(!s_pidfname.empty())
- unlink(s_pidfname.c_str()); // remove possible old pid file
-
+ unlink(s_pidfname.c_str()); // remove possible old pid file
+
if(::arg().mustDo("daemon")) {
L<<Logger::Warning<<"Calling daemonize, going to background"<<endl;
L.toConsole(Logger::Critical);
g_numThreads = ::arg().asNum("threads") + ::arg().mustDo("pdns-distributes-queries");
g_maxMThreads = ::arg().asNum("max-mthreads");
checkOrFixFDS();
-
+
int newgid=0;
if(!::arg()["setgid"].empty())
newgid=Utility::makeGidNumeric(::arg()["setgid"]);
g_numThreads = ::arg().asNum("threads") + ::arg().mustDo("pdns-distributes-queries");
g_numWorkerThreads = ::arg().asNum("threads");
makeThreadPipes();
-
+
g_tcpTimeout=::arg().asNum("client-tcp-timeout");
g_maxTCPPerClient=::arg().asNum("max-tcp-per-client");
}
void* res;
-
+
pthread_join(tid, &res);
}
return 0;
t_udpclientsocks = new UDPClientSocks();
t_tcpClientCounts = new tcpClientCounts_t();
primeHints();
-
+
t_packetCache = new RecursorPacketCache();
-
+
L<<Logger::Warning<<"Done priming cache with root hints"<<endl;
-
+
t_pdl = new shared_ptr<RecursorLua>();
-
+
try {
if(!::arg()["lua-dns-script"].empty()) {
*t_pdl = shared_ptr<RecursorLua>(new RecursorLua(::arg()["lua-dns-script"]));
L<<Logger::Error<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e.what()<<endl;
_exit(99);
}
-
+
t_traceRegex = new shared_ptr<Regex>();
unsigned int ringsize=::arg().asNum("stats-ringbuffer-entries") / g_numWorkerThreads;
if(ringsize) {
t_remotes = new addrringbuf_t();
if(g_weDistributeQueries) // if so, only 1 thread does recvfrom
- t_remotes->set_capacity(::arg().asNum("stats-ringbuffer-entries"));
+ t_remotes->set_capacity(::arg().asNum("stats-ringbuffer-entries"));
else
- t_remotes->set_capacity(ringsize);
+ t_remotes->set_capacity(ringsize);
t_servfailremotes = new addrringbuf_t();
- t_servfailremotes->set_capacity(ringsize);
+ t_servfailremotes->set_capacity(ringsize);
t_largeanswerremotes = new addrringbuf_t();
- t_largeanswerremotes->set_capacity(ringsize);
+ t_largeanswerremotes->set_capacity(ringsize);
t_queryring = new boost::circular_buffer<pair<DNSName, uint16_t> >();
- t_queryring->set_capacity(ringsize);
+ t_queryring->set_capacity(ringsize);
t_servfailqueryring = new boost::circular_buffer<pair<DNSName, uint16_t> >();
- t_servfailqueryring->set_capacity(ringsize);
+ t_servfailqueryring->set_capacity(ringsize);
}
-
+
MT=new MTasker<PacketID,string>(::arg().asNum("stack-size"));
-
+
PacketID pident;
t_fdm=getMultiplexer();
t_fdm->addReadFD(g_pipes[t_id].readToThread, handlePipeRequest);
if(!g_weDistributeQueries || !t_id) // if we distribute queries, only t_id = 0 listens
- for(deferredAdd_t::const_iterator i=deferredAdd.begin(); i!=deferredAdd.end(); ++i)
+ for(deferredAdd_t::const_iterator i=deferredAdd.begin(); i!=deferredAdd.end(); ++i)
t_fdm->addReadFD(i->first, i->second);
-
+
if(!t_id) {
t_fdm->addReadFD(s_rcc.d_fd, handleRCC); // control channel
}
unsigned int maxTcpClients=::arg().asNum("max-tcp-clients");
-
+
bool listenOnTCP(true);
time_t last_carbon=0;
counter=AtomicCounter(0); // used to periodically execute certain tasks
for(;;) {
while(MT->schedule(&g_now)); // MTasker letting the mthreads do their thing
-
+
if(!(counter%500)) {
MT->makeThread(houseKeeping, 0);
}
if(!(counter%55)) {
typedef vector<pair<int, FDMultiplexer::funcparam_t> > expired_t;
expired_t expired=t_fdm->getTimeouts(g_now);
-
+
for(expired_t::iterator i=expired.begin() ; i != expired.end(); ++i) {
shared_ptr<TCPConnection> conn=any_cast<shared_ptr<TCPConnection> >(i->second);
if(g_logCommonErrors)
t_fdm->removeReadFD(i->first);
}
}
-
+
counter++;
if(!t_id && statsWanted) {
}
-int main(int argc, char **argv)
+int main(int argc, char **argv)
{
g_argc = argc;
g_argv = argv;
::arg().set("threads", "Launch this number of threads")="2";
::arg().set("processes", "Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)")="1";
::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
- ::arg().set( "experimental-logfile", "Filename of the log file for JSON parser" )= "/var/log/pdns.log";
+ ::arg().set( "experimental-logfile", "Filename of the log file for JSON parser" )= "/var/log/pdns.log";
::arg().setSwitch("experimental-webserver", "Start a webserver for monitoring") = "no";
::arg().set("experimental-webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
::arg().set("experimental-webserver-port", "Port of webserver to listen on") = "8082";
::arg().set("socket-owner","Owner of socket")="";
::arg().set("socket-group","Group of socket")="";
::arg().set("socket-mode", "Permissions for socket")="";
-
+
::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR;
::arg().set("delegation-only","Which domains we only accept delegations from")="";
::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS;
::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
- ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY;
+ ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY;
::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="";
::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000";
-// ::arg().setSwitch( "disable-edns-ping", "Disable EDNSPing - EXPERIMENTAL, LEAVE DISABLED" )= "no";
- ::arg().setSwitch( "disable-edns", "Disable EDNS - EXPERIMENTAL, LEAVE DISABLED" )= "";
- ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
+// ::arg().setSwitch( "disable-edns-ping", "Disable EDNSPing - EXPERIMENTAL, LEAVE DISABLED" )= "no";
+ ::arg().setSwitch( "disable-edns", "Disable EDNS - EXPERIMENTAL, LEAVE DISABLED" )= "";
+ ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="";
::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="no";
::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";
exit(0);
}
- if(!::arg().file(configname.c_str()))
+ if(!::arg().file(configname.c_str()))
L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
::arg().parse(argc,argv);
L<<Logger::Error<<"any other exception in main: "<<endl;
ret=EXIT_FAILURE;
}
-
+
return ret;
}
DNSName wcarddomain(qname);
while(!pdns_iequals(wcarddomain, iter->first) && wcarddomain.chopOff()) {
LOG(prefix<<qname.toString()<<": trying '*."+wcarddomain.toString()+"' in "<<authdomain.toString()<<endl);
- range=iter->second.d_records.equal_range(boost::make_tuple(DNSName("*")+wcarddomain));
+ range=iter->second.d_records.equal_range(boost::make_tuple(DNSName("*")+wcarddomain));
if(range.first==range.second)
continue;
DNSName nsdomain(qname);
while(nsdomain.chopOff() && !pdns_iequals(nsdomain, iter->first)) {
- range=iter->second.d_records.equal_range(boost::make_tuple(nsdomain,QType(QType::NS)));
+ range=iter->second.d_records.equal_range(boost::make_tuple(nsdomain,QType(QType::NS)));
if(range.first==range.second)
continue;
ret.push_back(rr);
}
}
- if(ret.empty()) {
+ if(ret.empty()) {
LOG(prefix<<qname.toString()<<": no NS match in zone '"<<authdomain.toString()<<"' either, handing out SOA"<<endl);
ziter=iter->second.d_records.find(boost::make_tuple(authdomain, QType(QType::SOA)));
if(ziter!=iter->second.d_records.end()) {
fclose(fp);
}
-int SyncRes::asyncresolveWrapper(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, LWResult* res)
+int SyncRes::asyncresolveWrapper(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, LWResult* res)
{
/* what is your QUEST?
the goal is to get as many remotes as possible on the highest level of hipness: EDNS PING responders.
if(d_cacheonly)
return 0;
-
+
LOG(prefix<<qname.toString()<<": No cache hit for '"<<qname.toString()<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl);
DNSName subdomain(qname);
if(!(res=doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere)))
return 0;
-
+
LOG(prefix<<qname.toString()<<": failed (res="<<res<<")"<<endl);
return res<0 ? RCode::ServFail : res;
}
}
}
LOG(prefix<<qname.toString()<<": no valid/useful NS in cache for '"<<subdomain.toString()<<"'"<<endl);
- if(subdomain=="." && !brokeloop) {
- primeHints();
+ if(subdomain=="." && !brokeloop) {
+ primeHints();
LOG(prefix<<qname.toString()<<": reprimed the root"<<endl);
}
}while(subdomain.chopOff());
{
DNSName subdomain(qname);
DNSName authdomain(qname);
-
+
domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
if(iter!=t_sstorage->domainmap->end()) {
if( iter->second.d_servers.empty() )
res=RCode::ServFail;
return true;
}
-
+
LOG(prefix<<qname.toString()<<": Looking for CNAME cache hit of '"<<(qname.toString()+"|CNAME")<<"'"<<endl);
set<DNSResourceRecord> cset;
if(t_RC->get(d_now.tv_sec, qname,QType(QType::CNAME),&cset) > 0) {
for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
if(j->ttl>(unsigned int) d_now.tv_sec) {
- LOG(prefix<<qname.toString()<<": Found cache CNAME hit for '"<< (qname.toString()+"|CNAME") <<"' to '"<<j->content<<"'"<<endl);
+ LOG(prefix<<qname.toString()<<": Found cache CNAME hit for '"<< (qname.toString()+"|CNAME") <<"' to '"<<j->content<<"'"<<endl);
DNSResourceRecord rr=*j;
rr.ttl-=d_now.tv_sec;
ret.push_back(rr);
QType sqt(qtype);
uint32_t sttl=0;
// cout<<"Lookup for '"<<qname.toString()<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
-
+
pair<negcache_t::const_iterator, negcache_t::const_iterator> range;
QType qtnull(0);
(range.first=t_sstorage->negcache.find(tie(getLastLabel(qname), qtnull))) != t_sstorage->negcache.end() &&
range.first->d_qname=="." && (uint32_t)d_now.tv_sec < range.first->d_ttd ) {
sttl=range.first->d_ttd - d_now.tv_sec;
-
+
LOG(prefix<<qname.toString()<<": Entire name '"<<qname.toString()<<"', is negatively cached via '"<<range.first->d_name.toString()<<"' & '"<<range.first->d_qname.toString()<<"' for another "<<sttl<<" seconds"<<endl);
- res = RCode::NXDomain;
+ res = RCode::NXDomain;
sqname=range.first->d_qname;
sqt=QType::SOA;
moveCacheItemToBack(t_sstorage->negcache, range.first);
}
else {
LOG(prefix<<qname.toString()<<": Entire name '"<<qname.toString()<<"', is negatively cached via '"<<ni->d_qname.toString()<<"' for another "<<sttl<<" seconds"<<endl);
- res= RCode::NXDomain;
+ res= RCode::NXDomain;
}
giveNegative=true;
sqname=ni->d_qname;
struct speedOrder
{
- speedOrder(map<string,double> &speeds) : d_speeds(speeds) {}
- bool operator()(const string &a, const string &b) const
+ speedOrder(map<DNSName,double> &speeds) : d_speeds(speeds) {}
+ bool operator()(const DNSName &a, const DNSName &b) const
{
return d_speeds[a] < d_speeds[b];
}
- map<string, double>& d_speeds;
+ map<DNSName, double>& d_speeds;
};
inline vector<DNSName> SyncRes::shuffleInSpeedOrder(set<DNSName> &tnameservers, const string &prefix)
if(doLog()) {
LOG(prefix<<"Nameservers: ");
- for(const auto & i: rnameservers) {
- if(i!=rnameservers.begin()) {
+ for(vector<DNSName>::const_iterator i=rnameservers.begin();i!=rnameservers.end();++i) {
+ if(i!=rnameservers.begin()) {
LOG(", ");
if(!((i-rnameservers.begin())%3)) {
LOG(endl<<prefix<<" ");
}
}
- LOG(*i<<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)");
+ LOG(i->toString()<<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)");
}
LOG(endl);
}
struct TCacheComp
{
- bool operator()(const pair<string, QType>& a, const pair<string, QType>& b) const
+ bool operator()(const pair<DNSName, QType>& a, const pair<DNSName, QType>& b) const
{
- if(pdns_ilexicographical_compare(a.first, b.first))
- return true;
- if(pdns_ilexicographical_compare(b.first, a.first))
- return false;
-
- return a.second < b.second;
+ return tie(a.first, a.second) < tie(b.first, b.second);
}
};
}
/** returns -1 in case of no results, rcode otherwise */
-int SyncRes::doResolveAt(set<DNSName> nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype,
- vector<DNSResourceRecord>&ret,
+int SyncRes::doResolveAt(set<DNSName> nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype,
+ vector<DNSResourceRecord>&ret,
int depth, set<GetBestNSAnswer>&beenthere)
{
string prefix;
prefix=d_prefix;
prefix.append(depth, ' ');
}
-
+
LOG(prefix<<qname.toString()<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact"<<endl);
for(;;) { // we may get more specific nameservers
vector<DNSName > rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() );
-
- for(const auto &tns: rnameservers) {
+
+ for(vector<DNSName >::const_iterator tns=rnameservers.begin();;++tns) {
if(tns==rnameservers.end()) {
LOG(prefix<<qname.toString()<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth.toString()<<"'"<<endl);
if(auth!="." && flawedNSSet) {
return -1;
}
// this line needs to identify the 'self-resolving' behaviour, but we get it wrong now
- if(pdns_iequals(qname, *tns) && qtype.getCode()==QType::A && rnameservers.size() > (unsigned)(1+1*s_doIPv6)) {
+ if(pdns_iequals(qname, *tns) && qtype.getCode()==QType::A && rnameservers.size() > (unsigned)(1+1*s_doIPv6)) {
LOG(prefix<<qname.toString()<<": Not using NS to resolve itself!"<<endl);
continue;
}
lwr.d_aabit=true;
}
else {
- LOG(prefix<<qname.toString()<<": Trying to resolve NS '"<<*tns<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
+ LOG(prefix<<qname.toString()<<": Trying to resolve NS '"<<tns->toString()<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
if(!isCanonical(*tns)) {
LOG(prefix<<qname.toString()<<": Domain has hardcoded nameserver(s)"<<endl);
- string txtAddr = *tns;
+ string txtAddr = tns->toString();
if(!tns->empty()) {
sendRDQuery = txtAddr[0] == '+';
txtAddr=txtAddr.c_str()+1;
}
if(remoteIPs.empty()) {
- LOG(prefix<<qname.toString()<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl);
+ LOG(prefix<<qname.toString()<<": Failed to get IP for NS "<<tns->toString()<<", trying next if available"<<endl);
flawedNSSet=true;
continue;
}
LOG(prefix<<qname.toString()<<": using TCP with "<< remoteIP->toStringWithPort() <<endl);
s_tcpoutqueries++; d_tcpoutqueries++;
}
-
- if(s_maxtotusec && d_totUsec > s_maxtotusec)
+
+ if(s_maxtotusec && d_totUsec > s_maxtotusec)
throw ImmediateServFailException("Too much time waiting for "+qname.toString()+"|"+qtype.getName()+", timeouts: "+boost::lexical_cast<string>(d_timeouts) +", throttles: "+boost::lexical_cast<string>(d_throttledqueries) + ", queries: "+lexical_cast<string>(d_outqueries)+", "+lexical_cast<string>(d_totUsec/1000)+"msec");
if(d_pdl && d_pdl->preoutquery(*remoteIP, d_requestor, qname, qtype, lwr.d_result, resolveret)) {
// if(d_timeouts + 0.5*d_throttledqueries > 6.0 && d_timeouts > 2) throw ImmediateServFailException("Too much work resolving "+qname+"|"+qtype.getName()+", timeouts: "+boost::lexical_cast<string>(d_timeouts) +", throttles: "+boost::lexical_cast<string>(d_throttledqueries));
if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
- LOG(prefix<<qname.toString()<<": "<<*tns<<" returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
+ LOG(prefix<<qname.toString()<<": "<<tns->toString()<<" returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
t_sstorage->throttle.throttle(d_now.tv_sec,boost::make_tuple(*remoteIP, qname, qtype.getCode()),60,3); // servfail or refused
continue;
}
break; // this IP address worked!
wasLame:; // well, it didn't
- LOG(prefix<<qname.toString()<<": status=NS "<<*tns<<" ("<< remoteIP->toString() <<") is lame for '"<<auth<<"', trying sibling IP or NS"<<endl);
+ LOG(prefix<<qname.toString()<<": status=NS "<<tns->toString()<<" ("<< remoteIP->toString() <<") is lame for '"<<auth.toString()<<"', trying sibling IP or NS"<<endl);
t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // lame
}
}
LOG(prefix<<qname.toString()<<": truncated bit set, over TCP?"<<endl);
return RCode::ServFail;
}
-
- LOG(prefix<<qname.toString()<<": Got "<<(unsigned int)lwr.d_result.size()<<" answers from "<<*tns<<" ("<< remoteIP->toString() <<"), rcode="<<lwr.d_rcode<<" ("<<RCode::to_s(lwr.d_rcode)<<"), aa="<<lwr.d_aabit<<", in "<<lwr.d_usec/1000<<"ms"<<endl);
+
+ LOG(prefix<<qname.toString()<<": Got "<<(unsigned int)lwr.d_result.size()<<" answers from "<<tns->toString()<<" ("<< remoteIP->toString() <<"), rcode="<<lwr.d_rcode<<" ("<<RCode::to_s(lwr.d_rcode)<<"), aa="<<lwr.d_aabit<<", in "<<lwr.d_usec/1000<<"ms"<<endl);
/* // for you IPv6 fanatics :-)
if(remoteIP->sin4.sin_family==AF_INET6)
LOG("NO! - we don't accept 'ANY' data"<<endl);
continue;
}
-
+
if(i->qname.isPartOf(auth)) {
if(lwr.d_aabit && lwr.d_rcode==RCode::NoError && i->d_place==DNSResourceRecord::ANSWER && ::arg().contains("delegation-only",auth.toString() /* ugh */)) {
LOG("NO! Is from delegation-only zone"<<endl);
t_RC->replace(d_now.tv_sec, i->first.first, i->first.second, i->second, lwr.d_aabit);
}
- set<DNSName> nsset;
+ set<DNSName> nsset;
LOG(prefix<<qname.toString()<<": determining status after receiving this packet"<<endl);
bool done=false, realreferral=false, negindic=false;
if(i->d_place==DNSResourceRecord::AUTHORITY && i->qtype.getCode()==QType::SOA &&
lwr.d_rcode==RCode::NXDomain && dottedEndsOn(qname,i->qname) && dottedEndsOn(i->qname, auth)) {
LOG(prefix<<qname.toString()<<": got negative caching indication for name '"<<qname.toString()+"' (accept="<<dottedEndsOn(i->qname, auth)<<"), newtarget='"<<newtarget.toString()<<"'"<<endl);
-
+
i->ttl = min(i->ttl, s_maxnegttl);
if(!newtarget.length()) // only add a SOA if we're not going anywhere after this
ret.push_back(*i);
)
)
{
-
+
LOG(prefix<<qname.toString()<<": answer is in: resolved to '"<< i->content<<"|"<<i->qtype.getName()<<"'"<<endl);
done=true;
LOG(prefix<<qname.toString()<<": got NS record '"<<i->qname.toString()<<"' -> '"<<i->content<<"'"<<endl);
realreferral=true;
}
- else
+ else
LOG(prefix<<qname.toString()<<": got upwards/level NS record '"<<i->qname.toString()<<"' -> '"<<i->content<<"', had '"<<auth.toString()<<"'"<<endl);
nsset.insert(i->content);
}
else if(!done && i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA &&
lwr.d_rcode==RCode::NoError) {
LOG(prefix<<qname.toString()<<": got negative caching indication for '"<< (qname.toString()+"|"+qtype.getName()+"'") <<endl);
-
+
if(!newtarget.empty()) {
LOG(prefix<<qname.toString()<<": Hang on! Got a redirect to '"<<newtarget.toString()<<"' already"<<endl);
}
}
}
- if(done){
+ if(done){
LOG(prefix<<qname.toString()<<": status=got results, this level of recursion done"<<endl);
return 0;
}
string url = "/servers/localhost/zones/" + zoneId;
Value jurl(url.c_str(), doc.GetAllocator()); // copy
doc.AddMember("url", jurl, doc.GetAllocator());
- doc.AddMember("name", iter->first.c_str(), doc.GetAllocator());
+ doc.AddMember("name", iter->first.toString().c_str(), doc.GetAllocator());
doc.AddMember("kind", zone.d_servers.empty() ? "Native" : "Forwarded", doc.GetAllocator());
Value servers;
servers.SetArray();
BOOST_FOREACH(const SyncRes::AuthDomain::records_t::value_type& rr, zone.d_records) {
Value object;
object.SetObject();
- Value jname(rr.qname.c_str(), doc.GetAllocator()); // copy
+ Value jname(rr.qname.toString().c_str(), doc.GetAllocator()); // copy
object.AddMember("name", jname, doc.GetAllocator());
Value jtype(rr.qtype.getName().c_str(), doc.GetAllocator()); // copy
object.AddMember("type", jtype, doc.GetAllocator());
Value jdi;
jdi.SetObject();
// id is the canonical lookup key, which doesn't actually match the name (in some cases)
- string zoneId = apiZoneNameToId(val.first);
+ string zoneId = apiZoneNameToId(val.first.toString());
Value jzoneid(zoneId.c_str(), doc.GetAllocator()); // copy
jdi.AddMember("id", jzoneid, doc.GetAllocator());
string url = "/servers/localhost/zones/" + zoneId;
Value jurl(url.c_str(), doc.GetAllocator()); // copy
jdi.AddMember("url", jurl, doc.GetAllocator());
- jdi.AddMember("name", val.first.c_str(), doc.GetAllocator());
+ jdi.AddMember("name", val.first.toString().c_str(), doc.GetAllocator());
jdi.AddMember("kind", zone.d_servers.empty() ? "Native" : "Forwarded", doc.GetAllocator());
Value servers;
servers.SetArray();
doc.SetArray();
BOOST_FOREACH(const SyncRes::domainmap_t::value_type& val, *t_sstorage->domainmap) {
- string zoneId = apiZoneNameToId(val.first);
- if (pdns_ci_find(val.first, q) != string::npos) {
+ string zoneId = apiZoneNameToId(val.first.toString());
+ if (pdns_ci_find(val.first.toString(), q) != string::npos) {
Value object;
object.SetObject();
object.AddMember("type", "zone", doc.GetAllocator());
Value jzoneId(zoneId.c_str(), doc.GetAllocator()); // copy
object.AddMember("zone_id", jzoneId, doc.GetAllocator());
- Value jzoneName(val.first.c_str(), doc.GetAllocator()); // copy
+ Value jzoneName(val.first.toString().c_str(), doc.GetAllocator()); // copy
object.AddMember("name", jzoneName, doc.GetAllocator());
doc.PushBack(object, doc.GetAllocator());
}
const SyncRes::AuthDomain& zone = val.second;
BOOST_FOREACH(const SyncRes::AuthDomain::records_t::value_type& rr, zone.d_records) {
- if (pdns_ci_find(rr.qname, q) == string::npos && pdns_ci_find(rr.content, q) == string::npos)
+ if (pdns_ci_find(rr.qname.toString(), q) == string::npos && pdns_ci_find(rr.content, q) == string::npos)
continue;
Value object;
object.AddMember("type", "record", doc.GetAllocator());
Value jzoneId(zoneId.c_str(), doc.GetAllocator()); // copy
object.AddMember("zone_id", jzoneId, doc.GetAllocator());
- Value jzoneName(val.first.c_str(), doc.GetAllocator()); // copy
+ Value jzoneName(val.first.toString().c_str(), doc.GetAllocator()); // copy
object.AddMember("zone_name", jzoneName, doc.GetAllocator());
- Value jname(rr.qname.c_str(), doc.GetAllocator()); // copy
+ Value jname(rr.qname.toString().c_str(), doc.GetAllocator()); // copy
object.AddMember("name", jname, doc.GetAllocator());
Value jcontent(rr.content.c_str(), doc.GetAllocator()); // copy
object.AddMember("content", jcontent, doc.GetAllocator());
if(req->method != "PUT")
throw HttpMethodNotAllowedException();
- string canon = toCanonic("", req->getvars["domain"]);
+ DNSName canon = req->getvars["domain"];
int count = broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, canon));
count += broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, canon));
map<string, string> object;
req->getvars.erase("command");
}
- map<string, string> stats;
+ map<string, string> stats;
if(command == "get-query-ring") {
- typedef pair<string,uint16_t> query_t;
+ typedef pair<DNSName,uint16_t> query_t;
vector<query_t> queries;
bool filter=!req->getvars["public-filtered"].empty();
-
+
if(req->getvars["name"]=="servfail-queries")
queries=broadcastAccFunction<vector<query_t> >(pleaseGetServfailQueryRing);
else if(req->getvars["name"]=="queries")
queries=broadcastAccFunction<vector<query_t> >(pleaseGetQueryRing);
-
+
typedef map<query_t,unsigned int> counts_t;
counts_t counts;
unsigned int total=0;
BOOST_FOREACH(const query_t& q, queries) {
total++;
if(filter)
- counts[make_pair(getRegisteredName(toLower(q.first)), q.second)]++;
- else
- counts[make_pair(toLower(q.first), q.second)]++;
+ counts[make_pair(getRegisteredName(q.first), q.second)]++;
+ else
+ counts[make_pair(q.first, q.second)]++;
}
-
+
typedef std::multimap<int, query_t> rcounts_t;
rcounts_t rcounts;
-
+
for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
rcounts.insert(make_pair(-i->second, i->first));
unsigned int tot=0, totIncluded=0;
BOOST_FOREACH(const rcounts_t::value_type& q, rcounts) {
Value arr;
-
+
arr.SetArray();
totIncluded-=q.first;
arr.PushBack(-q.first, doc.GetAllocator());
- arr.PushBack(q.second.first.c_str(), doc.GetAllocator());
+ arr.PushBack(q.second.first.toString().c_str(), doc.GetAllocator());
arr.PushBack(DNSRecordContent::NumberToType(q.second.second).c_str(), doc.GetAllocator());
entries.PushBack(arr, doc.GetAllocator());
if(tot++>=100)
arr.PushBack("", doc.GetAllocator());
entries.PushBack(arr, doc.GetAllocator());
}
- doc.AddMember("entries", entries, doc.GetAllocator());
+ doc.AddMember("entries", entries, doc.GetAllocator());
resp->setBody(doc);
return;
}
queries=broadcastAccFunction<vector<ComboAddress> >(pleaseGetServfailRemotes);
else if(req->getvars["name"]=="large-answer-remotes")
queries=broadcastAccFunction<vector<ComboAddress> >(pleaseGetLargeAnswerRemotes);
-
+
typedef map<ComboAddress,unsigned int,ComboAddress::addressOnlyLessThan> counts_t;
counts_t counts;
unsigned int total=0;
total++;
counts[q]++;
}
-
+
typedef std::multimap<int, ComboAddress> rcounts_t;
rcounts_t rcounts;
-
+
for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i)
rcounts.insert(make_pair(-i->second, i->first));
-
+
Document doc;
doc.SetObject();
Value entries;
BOOST_FOREACH(const rcounts_t::value_type& q, rcounts) {
totIncluded-=q.first;
Value arr;
-
+
arr.SetArray();
arr.PushBack(-q.first, doc.GetAllocator());
- Value jname(q.second.toString().c_str(), doc.GetAllocator()); // copy
+ Value jname(q.second.toString().c_str(), doc.GetAllocator()); // copy
arr.PushBack(jname, doc.GetAllocator());
entries.PushBack(arr, doc.GetAllocator());
if(tot++>=100)
entries.PushBack(arr, doc.GetAllocator());
}
- doc.AddMember("entries", entries, doc.GetAllocator());
+ doc.AddMember("entries", entries, doc.GetAllocator());
resp->setBody(doc);
return;
} else {
YaHTTP::AsyncRequestLoader yarl;
yarl.initialize(&req);
client->setNonBlocking();
-
+
string data;
try {
while(!req.complete) {