2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2003 - 2015 PowerDNS.COM BV
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <boost/foreach.hpp>
30 #include "ws-recursor.hh"
32 #include "recpacketcache.hh"
34 #include "dns_random.hh"
37 #include <boost/static_assert.hpp>
40 #include "recursor_cache.hh"
41 #include "cachecleaner.hh"
48 #include "arguments.hh"
53 #include <boost/tuple/tuple.hpp>
54 #include <boost/tuple/tuple_comparison.hpp>
55 #include <boost/shared_array.hpp>
56 #include <boost/lexical_cast.hpp>
57 #include <boost/function.hpp>
58 #include <boost/algorithm/string.hpp>
59 #include <netinet/tcp.h>
60 #include "dnsparser.hh"
61 #include "dnswriter.hh"
62 #include "dnsrecords.hh"
63 #include "zoneparser-tng.hh"
64 #include "rec_channel.hh"
69 #include "lua-recursor.hh"
71 #include "responsestats.hh"
72 #include "secpoll-recursor.hh"
74 #include "filterpo.hh"
75 #include "rpzloader.hh"
81 __thread FDMultiplexer
* t_fdm
;
82 __thread
unsigned int t_id
;
83 unsigned int g_maxTCPPerClient
;
84 unsigned int g_networkTimeoutMsec
;
85 uint64_t g_latencyStatSize
;
86 bool g_logCommonErrors
;
88 uint16_t g_udpTruncationThreshold
;
89 __thread shared_ptr
<RecursorLua
>* t_pdl
;
91 __thread addrringbuf_t
* t_remotes
, *t_servfailremotes
, *t_largeanswerremotes
;
93 __thread
boost::circular_buffer
<pair
<DNSName
, uint16_t> >* t_queryring
, *t_servfailqueryring
;
94 __thread shared_ptr
<Regex
>* t_traceRegex
;
96 DNSFilterEngine g_dfe
;
98 RecursorControlChannel s_rcc
; // only active in thread 0
100 // for communicating with our threads
109 vector
<ThreadPipeSet
> g_pipes
; // effectively readonly after startup
111 SyncRes::domainmap_t
* g_initialDomainMap
; // new threads needs this to be setup
113 #include "namespaces.hh"
115 __thread MemRecursorCache
* t_RC
;
116 __thread RecursorPacketCache
* t_packetCache
;
117 RecursorStats g_stats
;
120 bool g_weDistributeQueries
; // if true, only 1 thread listens on the incoming query sockets
122 __thread NetmaskGroup
* t_allowFrom
;
123 static NetmaskGroup
* g_initialAllowFrom
; // new thread needs to be setup with this
125 NetmaskGroup
* g_dontQuery
;
126 string s_programname
="pdns_recursor";
128 typedef vector
<int> tcpListenSockets_t
;
129 tcpListenSockets_t g_tcpListenSockets
; // shared across threads, but this is fine, never written to from a thread. All threads listen on all sockets
131 unsigned int g_maxMThreads
;
132 __thread
struct timeval g_now
; // timestamp, updated (too) frequently
133 typedef map
<int, ComboAddress
> listenSocketsAddresses_t
; // is shared across all threads right now
134 listenSocketsAddresses_t g_listenSocketsAddresses
; // is shared across all threads right now
136 __thread MT_t
* MT
; // the big MTasker
138 unsigned int g_numThreads
, g_numWorkerThreads
;
140 #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"
141 // Bad Nets taken from both:
142 // http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
144 // http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
145 // where such a network may not be considered a valid destination
146 #define BAD_NETS "0.0.0.0/8, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96, ::ffff:0:0/96, 100::/64, 2001:db8::/32"
147 #define DONT_QUERY LOCAL_NETS ", " BAD_NETS
149 //! used to send information to a newborn mthread
150 struct DNSComboWriter
{
151 DNSComboWriter(const char* data
, uint16_t len
, const struct timeval
& now
) : d_mdp(data
, len
), d_now(now
),
152 d_tcp(false), d_socket(-1)
155 void setRemote(const ComboAddress
* sa
)
160 void setLocal(const ComboAddress
& sa
)
166 void setSocket(int sock
)
171 string
getRemote() const
173 return d_remote
.toString();
176 struct timeval d_now
;
177 ComboAddress d_remote
, d_local
;
180 shared_ptr
<TCPConnection
> d_tcpConnection
;
186 static ArgvMap theArg
;
191 void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
);
193 // -1 is error, 0 is timeout, 1 is success
194 int asendtcp(const string
& data
, Socket
* sock
)
200 t_fdm
->addWriteFD(sock
->getHandle(), handleTCPClientWritable
, pident
);
203 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
);
205 if(!ret
|| ret
==-1) { // timeout
206 t_fdm
->removeWriteFD(sock
->getHandle());
208 else if(packet
.size() !=data
.size()) { // main loop tells us what it sent out, or empty in case of an error
214 void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
);
216 // -1 is error, 0 is timeout, 1 is success
217 int arecvtcp(string
& data
, int len
, Socket
* sock
, bool incompleteOkay
)
223 pident
.inIncompleteOkay
=incompleteOkay
;
224 t_fdm
->addReadFD(sock
->getHandle(), handleTCPClientReadable
, pident
);
226 int ret
=MT
->waitEvent(pident
,&data
, g_networkTimeoutMsec
);
227 if(!ret
|| ret
==-1) { // timeout
228 t_fdm
->removeReadFD(sock
->getHandle());
230 else if(data
.empty()) {// error, EOF or other
237 vector
<ComboAddress
> g_localQueryAddresses4
, g_localQueryAddresses6
;
238 const ComboAddress
g_local4("0.0.0.0"), g_local6("::");
240 //! pick a random query local address
241 ComboAddress
getQueryLocalAddress(int family
, uint16_t port
)
244 if(family
==AF_INET
) {
245 if(g_localQueryAddresses4
.empty())
248 ret
= g_localQueryAddresses4
[dns_random(g_localQueryAddresses4
.size())];
249 ret
.sin4
.sin_port
= htons(port
);
252 if(g_localQueryAddresses6
.empty())
255 ret
= g_localQueryAddresses6
[dns_random(g_localQueryAddresses6
.size())];
257 ret
.sin6
.sin6_port
= htons(port
);
262 void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
&);
264 void setSocketBuffer(int fd
, int optname
, uint32_t size
)
267 socklen_t len
=sizeof(psize
);
269 if(!getsockopt(fd
, SOL_SOCKET
, optname
, (char*)&psize
, &len
) && psize
> size
) {
270 L
<<Logger::Error
<<"Not decreasing socket buffer size from "<<psize
<<" to "<<size
<<endl
;
274 if (setsockopt(fd
, SOL_SOCKET
, optname
, (char*)&size
, sizeof(size
)) < 0 )
275 L
<<Logger::Error
<<"Unable to raise socket buffer size to "<<size
<<": "<<strerror(errno
)<<endl
;
279 static void setSocketReceiveBuffer(int fd
, uint32_t size
)
281 setSocketBuffer(fd
, SO_RCVBUF
, size
);
284 static void setSocketSendBuffer(int fd
, uint32_t size
)
286 setSocketBuffer(fd
, SO_SNDBUF
, size
);
290 // you can ask this class for a UDP socket to send a query from
291 // this socket is not yours, don't even think about deleting it
292 // but after you call 'returnSocket' on it, don't assume anything anymore
295 unsigned int d_numsocks
;
297 UDPClientSocks() : d_numsocks(0)
301 typedef set
<int> socks_t
;
304 // returning -1 means: temporary OS error (ie, out of files), -2 means OS error
305 int getSocket(const ComboAddress
& toaddr
, int* fd
)
307 *fd
=makeClientSocket(toaddr
.sin4
.sin_family
);
308 if(*fd
< 0) // temporary error - receive exception otherwise
311 if(connect(*fd
, (struct sockaddr
*)(&toaddr
), toaddr
.getSocklen()) < 0) {
313 // returnSocket(*fd);
315 if(err
==ENETUNREACH
) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
325 void returnSocket(int fd
)
327 socks_t::iterator i
=d_socks
.find(fd
);
328 if(i
==d_socks
.end()) {
329 throw PDNSException("Trying to return a socket (fd="+lexical_cast
<string
>(fd
)+") not in the pool");
331 returnSocketLocked(i
);
334 // return a socket to the pool, or simply erase it
335 void returnSocketLocked(socks_t::iterator
& i
)
337 if(i
==d_socks
.end()) {
338 throw PDNSException("Trying to return a socket not in the pool");
341 t_fdm
->removeReadFD(*i
);
343 catch(FDMultiplexerException
& e
) {
344 // we sometimes return a socket that has not yet been assigned to t_fdm
352 // returns -1 for errors which might go away, throws for ones that won't
353 static int makeClientSocket(int family
)
355 int ret
=(int)socket(family
, SOCK_DGRAM
, 0 ); // turns out that setting CLO_EXEC and NONBLOCK from here is not a performance win on Linux (oddly enough)
357 if(ret
< 0 && errno
==EMFILE
) // this is not a catastrophic error
361 throw PDNSException("Making a socket for resolver (family = "+lexical_cast
<string
>(family
)+"): "+stringerror());
370 if(tries
==1) // fall back to kernel 'random'
373 port
= 1025 + dns_random(64510);
375 sin
=getQueryLocalAddress(family
, port
); // does htons for us
377 if (::bind(ret
, (struct sockaddr
*)&sin
, sin
.getSocklen()) >= 0)
381 throw PDNSException("Resolver binding to local query client socket on "+sin
.toString()+": "+stringerror());
388 static __thread UDPClientSocks
* t_udpclientsocks
;
390 /* these two functions are used by LWRes */
391 // -2 is OS error, -1 is error that depends on the remote, > 0 is success
392 int asendto(const char *data
, int len
, int flags
,
393 const ComboAddress
& toaddr
, uint16_t id
, const DNSName
& domain
, uint16_t qtype
, int* fd
)
397 pident
.domain
= domain
;
398 pident
.remote
= toaddr
;
401 // see if there is an existing outstanding request we can chain on to, using partial equivalence function
402 pair
<MT_t::waiters_t::iterator
, MT_t::waiters_t::iterator
> chain
=MT
->d_waiters
.equal_range(pident
, PacketIDBirthdayCompare());
404 for(; chain
.first
!= chain
.second
; chain
.first
++) {
405 if(chain
.first
->key
.fd
> -1) { // don't chain onto existing chained waiter!
407 cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
408 cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
409 <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
411 chain
.first
->key
.chain
.insert(id
); // we can chain
412 *fd
=-1; // gets used in waitEvent / sendEvent later on
417 int ret
=t_udpclientsocks
->getSocket(toaddr
, fd
);
424 t_fdm
->addReadFD(*fd
, handleUDPServerResponse
, pident
);
425 ret
= send(*fd
, data
, len
, 0);
430 t_udpclientsocks
->returnSocket(*fd
);
432 errno
= tmp
; // this is for logging purposes only
436 // -1 is error, 0 is timeout, 1 is success
437 int arecvfrom(char *data
, int len
, int flags
, const ComboAddress
& fromaddr
, int *d_len
,
438 uint16_t id
, const DNSName
& domain
, uint16_t qtype
, int fd
, struct timeval
* now
)
440 static optional
<unsigned int> nearMissLimit
;
442 nearMissLimit
=::arg().asNum("spoof-nearmiss-max");
447 pident
.domain
=domain
;
449 pident
.remote
=fromaddr
;
452 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
, now
);
455 if(packet
.empty()) // means "error"
458 *d_len
=(int)packet
.size();
459 memcpy(data
,packet
.c_str(),min(len
,*d_len
));
460 if(*nearMissLimit
&& pident
.nearMisses
> *nearMissLimit
) {
461 L
<<Logger::Error
<<"Too many ("<<pident
.nearMisses
<<" > "<<*nearMissLimit
<<") bogus answers for '"<<domain
<<"' from "<<fromaddr
.toString()<<", assuming spoof attempt."<<endl
;
462 g_stats
.spoofCount
++;
468 t_udpclientsocks
->returnSocket(fd
);
475 static void writePid(void)
477 if(!::arg().mustDo("write-pid"))
479 ofstream
of(s_pidfname
.c_str(), std::ios_base::app
);
481 of
<< Utility::getpid() <<endl
;
483 L
<<Logger::Error
<<"Writing pid for "<<Utility::getpid()<<" to "<<s_pidfname
<<" failed: "<<strerror(errno
)<<endl
;
486 typedef map
<ComboAddress
, uint32_t, ComboAddress::addressOnlyLessThan
> tcpClientCounts_t
;
487 tcpClientCounts_t __thread
* t_tcpClientCounts
;
489 TCPConnection::TCPConnection(int fd
, const ComboAddress
& addr
) : d_remote(addr
), d_fd(fd
)
491 ++s_currentConnections
;
492 (*t_tcpClientCounts
)[d_remote
]++;
495 TCPConnection::~TCPConnection()
497 if(closesocket(d_fd
) < 0)
498 unixDie("closing socket for TCPConnection");
499 if(t_tcpClientCounts
->count(d_remote
) && !(*t_tcpClientCounts
)[d_remote
]--)
500 t_tcpClientCounts
->erase(d_remote
);
501 --s_currentConnections
;
504 AtomicCounter
TCPConnection::s_currentConnections
;
505 void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
);
507 // the idea is, only do things that depend on the *response* here. Incoming accounting is on incoming.
508 void updateResponseStats(int res
, const ComboAddress
& remote
, unsigned int packetsize
, const DNSName
* query
, uint16_t qtype
)
510 if(packetsize
> 1000 && t_largeanswerremotes
)
511 t_largeanswerremotes
->push_back(remote
);
513 case RCode::ServFail
:
514 if(t_servfailremotes
) {
515 t_servfailremotes
->push_back(remote
);
516 if(query
) // packet cache
517 t_servfailqueryring
->push_back(make_pair(*query
, qtype
));
521 case RCode::NXDomain
:
530 static string
makeLoginfo(DNSComboWriter
* dc
)
533 return "("+dc
->d_mdp
.d_qname
.toString()+"/"+DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)+" from "+(dc
->d_remote
.toString())+")";
537 return "Exception making error message for exception";
540 void startDoResolve(void *p
)
542 DNSComboWriter
* dc
=(DNSComboWriter
*)p
;
544 t_queryring
->push_back(make_pair(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
));
546 uint32_t maxanswersize
= dc
->d_tcp
? 65535 : min((uint16_t) 512, g_udpTruncationThreshold
);
548 if(getEDNSOpts(dc
->d_mdp
, &edo
) && !dc
->d_tcp
) {
549 maxanswersize
= min(edo
.d_packetsize
, g_udpTruncationThreshold
);
552 listenSocketsAddresses_t::const_iterator lociter
;
553 vector
<DNSRecord
> ret
;
554 vector
<uint8_t> packet
;
556 DNSPacketWriter
pw(packet
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
);
558 pw
.getHeader()->aa
=0;
559 pw
.getHeader()->ra
=1;
560 pw
.getHeader()->qr
=1;
561 pw
.getHeader()->tc
=0;
562 pw
.getHeader()->id
=dc
->d_mdp
.d_header
.id
;
563 pw
.getHeader()->rd
=dc
->d_mdp
.d_header
.rd
;
564 pw
.getHeader()->cd
=dc
->d_mdp
.d_header
.cd
;
566 uint32_t minTTL
=std::numeric_limits
<uint32_t>::max();
568 SyncRes
sr(dc
->d_now
);
570 sr
.setLuaEngine(*t_pdl
);
571 sr
.d_requestor
=dc
->d_remote
;
574 if(pw
.getHeader()->cd
|| edo
.d_Z
& EDNSOpts::DNSSECOK
)
577 bool tracedQuery
=false; // we could consider letting Lua know about this too
578 bool variableAnswer
= false;
582 if(dc
->d_mdp
.d_qtype
==QType::ANY
&& !dc
->d_tcp
&& g_anyToTcp
) {
583 pw
.getHeader()->tc
= 1;
585 variableAnswer
= true;
589 if(t_traceRegex
->get() && (*t_traceRegex
)->match(dc
->d_mdp
.d_qname
.toString())) {
590 sr
.setLogMode(SyncRes::Store
);
594 if(!g_quiet
|| tracedQuery
)
595 L
<<Logger::Warning
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] " << (dc
->d_tcp
? "TCP " : "") << "question for '"<<dc
->d_mdp
.d_qname
<<"|"
596 <<DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)<<"' from "<<dc
->getRemote()<<endl
;
598 sr
.setId(MT
->getTid());
599 if(!dc
->d_mdp
.d_header
.rd
)
602 local
.sin4
.sin_family
= dc
->d_remote
.sin4
.sin_family
;
604 lociter
= g_listenSocketsAddresses
.find(dc
->d_socket
);
605 if(lociter
!= g_listenSocketsAddresses
.end()) {
606 local
= lociter
->second
;
609 socklen_t len
= local
.getSocklen();
610 getsockname(dc
->d_socket
, (sockaddr
*)&local
, &len
); // if this fails, we're ok with it
613 // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
615 switch(g_dfe
.getQueryPolicy(dc
->d_mdp
.d_qname
, dc
->d_remote
)) {
616 case DNSFilterEngine::Policy::NoAction
:
618 case DNSFilterEngine::Policy::Drop
:
619 g_stats
.policyDrops
++;
623 case DNSFilterEngine::Policy::NXDOMAIN
:
627 case DNSFilterEngine::Policy::NODATA
:
631 case DNSFilterEngine::Policy::Truncate
:
634 pw
.getHeader()->tc
=1;
640 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
)) {
642 res
= sr
.beginResolve(dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), dc
->d_mdp
.d_qclass
, ret
);
644 catch(ImmediateServFailException
&e
) {
645 if(g_logCommonErrors
)
646 L
<<Logger::Notice
<<"Sending SERVFAIL to "<<dc
->getRemote()<<" during resolve of '"<<dc
->d_mdp
.d_qname
<<"' because: "<<e
.reason
<<endl
;
647 res
= RCode::ServFail
;
650 switch(g_dfe
.getPostPolicy(ret
)) {
651 case DNSFilterEngine::Policy::NoAction
:
653 case DNSFilterEngine::Policy::Drop
:
654 g_stats
.policyDrops
++;
658 case DNSFilterEngine::Policy::NXDOMAIN
:
663 case DNSFilterEngine::Policy::NODATA
:
668 case DNSFilterEngine::Policy::Truncate
:
672 pw
.getHeader()->tc
=1;
679 if(res
== RCode::NoError
) {
681 for(; i
!= ret
.cend(); ++i
)
682 if(i
->d_type
== dc
->d_mdp
.d_qtype
&& i
->d_place
== DNSRecord::Answer
)
685 (*t_pdl
)->nodata(dc
->d_remote
,local
, dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), ret
, res
, &variableAnswer
);
687 else if(res
== RCode::NXDomain
)
688 (*t_pdl
)->nxdomain(dc
->d_remote
,local
, dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), ret
, res
, &variableAnswer
);
691 (*t_pdl
)->postresolve(dc
->d_remote
,local
, dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), ret
, res
, &variableAnswer
);
695 if(res
== PolicyDecision::DROP
) {
696 g_stats
.policyDrops
++;
701 if(tracedQuery
|| res
== PolicyDecision::PASS
|| res
== RCode::ServFail
|| pw
.getHeader()->rcode
== RCode::ServFail
)
703 string
trace(sr
.getTrace());
705 vector
<string
> lines
;
706 boost::split(lines
, trace
, boost::is_any_of("\n"));
707 for(const string
& line
: lines
) {
709 L
<<Logger::Warning
<< line
<< endl
;
714 if(res
== PolicyDecision::PASS
) {
715 pw
.getHeader()->rcode
=RCode::ServFail
;
716 // no commit here, because no record
720 pw
.getHeader()->rcode
=res
;
723 orderAndShuffle(ret
);
724 for(auto i
=ret
.cbegin(); i
!=ret
.cend(); ++i
) {
725 pw
.startRecord(i
->d_name
, i
->d_type
, i
->d_ttl
, i
->d_class
, (DNSPacketWriter::Place
)i
->d_place
);
726 minTTL
= min(minTTL
, i
->d_ttl
);
727 i
->d_content
->toPacket(pw
);
728 if(pw
.size() > maxanswersize
) {
730 if(i
->d_place
==DNSRecord::Answer
) // only truncate if we actually omitted parts of the answer
732 pw
.getHeader()->tc
=1;
735 goto sendit
; // need to jump over pw.commit
743 g_rs
.submitResponse(dc
->d_mdp
.d_qtype
, packet
.size(), !dc
->d_tcp
);
744 updateResponseStats(res
, dc
->d_remote
, packet
.size(), &dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
);
749 fillMSGHdr(&msgh
, &iov
, cbuf
, 0, (char*)&*packet
.begin(), packet
.size(), &dc
->d_remote
);
750 if(dc
->d_local
.sin4
.sin_family
)
751 addCMsgSrcAddr(&msgh
, cbuf
, &dc
->d_local
);
753 msgh
.msg_control
=NULL
;
754 sendmsg(dc
->d_socket
, &msgh
, 0);
755 if(!SyncRes::s_nopacketcache
&& !variableAnswer
) {
756 t_packetCache
->insertResponsePacket(string((const char*)&*packet
.begin(), packet
.size()),
759 (pw
.getHeader()->rcode
== RCode::ServFail
) ? SyncRes::s_packetcacheservfailttl
: SyncRes::s_packetcachettl
766 buf
[0]=packet
.size()/256;
767 buf
[1]=packet
.size()%256;
769 Utility::iovec iov
[2];
771 iov
[0].iov_base
=(void*)buf
; iov
[0].iov_len
=2;
772 iov
[1].iov_base
=(void*)&*packet
.begin(); iov
[1].iov_len
= packet
.size();
774 int ret
=Utility::writev(dc
->d_socket
, iov
, 2);
778 L
<<Logger::Error
<<"EOF writing TCP answer to "<<dc
->getRemote()<<endl
;
780 L
<<Logger::Error
<<"Error writing TCP answer to "<<dc
->getRemote()<<": "<< strerror(errno
) <<endl
;
781 else if((unsigned int)ret
!= 2 + packet
.size())
782 L
<<Logger::Error
<<"Oops, partial answer sent to "<<dc
->getRemote()<<" for "<<dc
->d_mdp
.d_qname
<<" (size="<< (2 + packet
.size()) <<", sent "<<ret
<<")"<<endl
;
786 // update tcp connection status, either by closing or moving to 'BYTE0'
789 // no need to remove us from FDM, we weren't there
793 dc
->d_tcpConnection
->state
=TCPConnection::BYTE0
;
794 Utility::gettimeofday(&g_now
, 0); // needs to be updated
795 t_fdm
->addReadFD(dc
->d_socket
, handleRunningTCPQuestion
, dc
->d_tcpConnection
);
796 t_fdm
->setReadTTD(dc
->d_socket
, g_now
, g_tcpTimeout
);
801 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
);
802 L
<<"': "<<ntohs(pw
.getHeader()->ancount
)<<" answers, "<<ntohs(pw
.getHeader()->arcount
)<<" additional, took "<<sr
.d_outqueries
<<" packets, "<<
803 sr
.d_totUsec
/1000.0<<" ms, "<<
804 sr
.d_throttledqueries
<<" throttled, "<<sr
.d_timeouts
<<" timeouts, "<<sr
.d_tcpoutqueries
<<" tcp connections, rcode="<<res
<<endl
;
807 sr
.d_outqueries
? t_RC
->cacheMisses
++ : t_RC
->cacheHits
++;
808 float spent
=makeFloat(sr
.d_now
-dc
->d_now
);
810 g_stats
.answers0_1
++;
811 else if(spent
< 0.010)
812 g_stats
.answers1_10
++;
814 g_stats
.answers10_100
++;
816 g_stats
.answers100_1000
++;
818 g_stats
.answersSlow
++;
820 uint64_t newLat
=(uint64_t)(spent
*1000000);
821 newLat
= min(newLat
,(uint64_t)(g_networkTimeoutMsec
*1000)); // outliers of several minutes exist..
822 g_stats
.avgLatencyUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyUsec
+ (float)newLat
/g_latencyStatSize
;
823 // no worries, we do this for packet cache hits elsewhere
824 // cout<<dc->d_mdp.d_qname<<"\t"<<MT->getUsec()<<"\t"<<sr.d_outqueries<<endl;
828 catch(PDNSException
&ae
) {
829 L
<<Logger::Error
<<"startDoResolve problem "<<makeLoginfo(dc
)<<": "<<ae
.reason
<<endl
;
832 catch(MOADNSException
& e
) {
833 L
<<Logger::Error
<<"DNS parser error "<<makeLoginfo(dc
) <<": "<<dc
->d_mdp
.d_qname
<<", "<<e
.what()<<endl
;
836 catch(std::exception
& e
) {
837 L
<<Logger::Error
<<"STL error "<< makeLoginfo(dc
)<<": "<<e
.what()<<endl
;
841 L
<<Logger::Error
<<"Any other exception in a resolver context "<< makeLoginfo(dc
) <<endl
;
844 g_stats
.maxMThreadStackUsage
= max(MT
->getMaxStackUsage(), g_stats
.maxMThreadStackUsage
);
847 void makeControlChannelSocket(int processNum
=-1)
849 string sockname
=::arg()["socket-dir"]+"/"+s_programname
;
851 sockname
+= "."+lexical_cast
<string
>(processNum
);
852 sockname
+=".controlsocket";
853 s_rcc
.listen(sockname
);
858 if (!::arg().isEmpty("socket-group"))
859 sockgroup
=::arg().asGid("socket-group");
860 if (!::arg().isEmpty("socket-owner"))
861 sockowner
=::arg().asUid("socket-owner");
863 if (sockgroup
> -1 || sockowner
> -1) {
864 if(chown(sockname
.c_str(), sockowner
, sockgroup
) < 0) {
865 unixDie("Failed to chown control socket");
869 // do mode change if socket-mode is given
870 if(!::arg().isEmpty("socket-mode")) {
871 mode_t sockmode
=::arg().asMode("socket-mode");
872 chmod(sockname
.c_str(), sockmode
);
876 void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
878 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(var
);
880 if(conn
->state
==TCPConnection::BYTE0
) {
881 int bytes
=recv(conn
->getFD(), conn
->data
, 2, 0);
883 conn
->state
=TCPConnection::BYTE1
;
885 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
887 conn
->state
=TCPConnection::GETQUESTION
;
889 if(!bytes
|| bytes
< 0) {
890 t_fdm
->removeReadFD(fd
);
894 else if(conn
->state
==TCPConnection::BYTE1
) {
895 int bytes
=recv(conn
->getFD(), conn
->data
+1, 1, 0);
897 conn
->state
=TCPConnection::GETQUESTION
;
898 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
901 if(!bytes
|| bytes
< 0) {
902 if(g_logCommonErrors
)
903 L
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toString() <<" disconnected after first byte"<<endl
;
904 t_fdm
->removeReadFD(fd
);
908 else if(conn
->state
==TCPConnection::GETQUESTION
) {
909 int bytes
=recv(conn
->getFD(), conn
->data
+ conn
->bytesread
, conn
->qlen
- conn
->bytesread
, 0);
910 if(!bytes
|| bytes
< 0) {
911 L
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toString() <<" disconnected while reading question body"<<endl
;
912 t_fdm
->removeReadFD(fd
);
915 conn
->bytesread
+=bytes
;
916 if(conn
->bytesread
==conn
->qlen
) {
917 t_fdm
->removeReadFD(fd
); // should no longer awake ourselves when there is data to read
919 DNSComboWriter
* dc
=0;
921 dc
=new DNSComboWriter(conn
->data
, conn
->qlen
, g_now
);
923 catch(MOADNSException
&mde
) {
924 g_stats
.clientParseError
++;
925 if(g_logCommonErrors
)
926 L
<<Logger::Error
<<"Unable to parse packet from TCP client "<< conn
->d_remote
.toString() <<endl
;
929 dc
->d_tcpConnection
= conn
; // carry the torch
930 dc
->setSocket(conn
->getFD()); // this is the only time a copy is made of the actual fd
932 dc
->setRemote(&conn
->d_remote
);
933 if(dc
->d_mdp
.d_header
.qr
) {
935 L
<<Logger::Error
<<"Ignoring answer on server socket!"<<endl
;
938 if(dc
->d_mdp
.d_header
.opcode
) {
940 L
<<Logger::Error
<<"Ignoring non-query opcode on server socket!"<<endl
;
945 ++g_stats
.tcpqcounter
;
946 MT
->makeThread(startDoResolve
, dc
); // deletes dc, will set state to BYTE0 again
953 //! Handle new incoming TCP connection
954 void handleNewTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& )
957 socklen_t addrlen
=sizeof(addr
);
958 int newsock
=(int)accept(fd
, (struct sockaddr
*)&addr
, &addrlen
);
960 if(MT
->numProcesses() > g_maxMThreads
) {
961 g_stats
.overCapacityDrops
++;
962 closesocket(newsock
);
967 t_remotes
->push_back(addr
);
968 if(t_allowFrom
&& !t_allowFrom
->match(&addr
)) {
970 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping TCP query from "<<addr
.toString()<<", address not matched by allow-from"<<endl
;
972 g_stats
.unauthorizedTCP
++;
973 closesocket(newsock
);
976 if(g_maxTCPPerClient
&& t_tcpClientCounts
->count(addr
) && (*t_tcpClientCounts
)[addr
] >= g_maxTCPPerClient
) {
977 g_stats
.tcpClientOverflow
++;
978 closesocket(newsock
); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
982 setNonBlocking(newsock
);
983 shared_ptr
<TCPConnection
> tc(new TCPConnection(newsock
, addr
));
984 tc
->state
=TCPConnection::BYTE0
;
986 t_fdm
->addReadFD(tc
->getFD(), handleRunningTCPQuestion
, tc
);
989 Utility::gettimeofday(&now
, 0);
990 t_fdm
->setReadTTD(tc
->getFD(), now
, g_tcpTimeout
);
994 string
* doProcessUDPQuestion(const std::string
& question
, const ComboAddress
& fromaddr
, const ComboAddress
& destaddr
, struct timeval tv
, int fd
)
996 gettimeofday(&g_now
, 0);
997 struct timeval diff
= g_now
- tv
;
998 double delta
=(diff
.tv_sec
*1000 + diff
.tv_usec
/1000.0);
1000 if(tv
.tv_sec
&& delta
> 1000.0) {
1001 g_stats
.tooOldDrops
++;
1006 if(fromaddr
.sin4
.sin_family
==AF_INET6
)
1007 g_stats
.ipv6qcounter
++;
1012 if(!SyncRes::s_nopacketcache
&& t_packetCache
->getResponsePacket(question
, g_now
.tv_sec
, &response
, &age
)) {
1014 L
<<Logger::Notice
<<t_id
<< " question answered from packet cache from "<<fromaddr
.toString()<<endl
;
1015 // t_queryring->push_back("packetcached");
1017 g_stats
.packetCacheHits
++;
1018 SyncRes::s_queries
++;
1019 ageDNSPacket(response
, age
);
1023 fillMSGHdr(&msgh
, &iov
, cbuf
, 0, (char*)response
.c_str(), response
.length(), const_cast<ComboAddress
*>(&fromaddr
));
1024 if(destaddr
.sin4
.sin_family
) {
1025 addCMsgSrcAddr(&msgh
, cbuf
, &destaddr
);
1028 msgh
.msg_control
=NULL
;
1030 sendmsg(fd
, &msgh
, 0);
1032 if(response
.length() >= sizeof(struct dnsheader
)) {
1033 struct dnsheader dh
;
1034 memcpy(&dh
, response
.c_str(), sizeof(dh
));
1035 updateResponseStats(dh
.rcode
, fromaddr
, response
.length(), 0, 0);
1037 g_stats
.avgLatencyUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyUsec
+ 0.0; // we assume 0 usec
1041 catch(std::exception
& e
) {
1042 L
<<Logger::Error
<<"Error processing or aging answer packet: "<<e
.what()<<endl
;
1047 if((*t_pdl
)->ipfilter(fromaddr
, destaddr
)) {
1049 L
<<Logger::Notice
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] DROPPED question from "<<fromaddr
.toStringWithPort()<<" based on policy"<<endl
;
1050 g_stats
.policyDrops
++;
1055 if(MT
->numProcesses() > g_maxMThreads
) {
1057 L
<<Logger::Notice
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] DROPPED question from "<<fromaddr
.toStringWithPort()<<", over capacity"<<endl
;
1059 g_stats
.overCapacityDrops
++;
1063 DNSComboWriter
* dc
= new DNSComboWriter(question
.c_str(), question
.size(), g_now
);
1065 dc
->setRemote(&fromaddr
);
1066 dc
->setLocal(destaddr
);
1069 MT
->makeThread(startDoResolve
, (void*) dc
); // deletes dc
1074 void handleNewUDPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
1078 ComboAddress fromaddr
;
1083 fromaddr
.sin6
.sin6_family
=AF_INET6
; // this makes sure fromaddr is big enough
1084 fillMSGHdr(&msgh
, &iov
, cbuf
, sizeof(cbuf
), data
, sizeof(data
), &fromaddr
);
1087 if((len
=recvmsg(fd
, &msgh
, 0)) >= 0) {
1089 t_remotes
->push_back(fromaddr
);
1091 if(t_allowFrom
&& !t_allowFrom
->match(&fromaddr
)) {
1093 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toString()<<", address not matched by allow-from"<<endl
;
1095 g_stats
.unauthorizedUDP
++;
1098 BOOST_STATIC_ASSERT(offsetof(sockaddr_in
, sin_port
) == offsetof(sockaddr_in6
, sin6_port
));
1099 if(!fromaddr
.sin4
.sin_port
) { // also works for IPv6
1101 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toStringWithPort()<<", can't deal with port 0"<<endl
;
1103 g_stats
.clientParseError
++; // not quite the best place to put it, but needs to go somewhere
1107 dnsheader
* dh
=(dnsheader
*)data
;
1110 if(g_logCommonErrors
)
1111 L
<<Logger::Error
<<"Ignoring answer from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
1113 else if(dh
->opcode
) {
1114 if(g_logCommonErrors
)
1115 L
<<Logger::Error
<<"Ignoring non-query opcode "<<dh
->opcode
<<" from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
1118 string
question(data
, len
);
1119 struct timeval tv
={0,0};
1120 HarvestTimestamp(&msgh
, &tv
);
1122 memset(&dest
, 0, sizeof(dest
)); // this makes sure we igore this address if not returned by recvmsg above
1123 HarvestDestinationAddress(&msgh
, &dest
);
1124 if(g_weDistributeQueries
)
1125 distributeAsyncFunction(question
, boost::bind(doProcessUDPQuestion
, question
, fromaddr
, dest
, tv
, fd
));
1127 doProcessUDPQuestion(question
, fromaddr
, dest
, tv
, fd
);
1130 catch(MOADNSException
& mde
) {
1131 g_stats
.clientParseError
++;
1132 if(g_logCommonErrors
)
1133 L
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<mde
.what()<<endl
;
1135 catch(std::runtime_error
& e
) {
1136 g_stats
.clientParseError
++;
1137 if(g_logCommonErrors
)
1138 L
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<e
.what()<<endl
;
1142 // cerr<<t_id<<" had error: "<<stringerror()<<endl;
1144 g_stats
.noPacketError
++;
1150 typedef vector
<pair
<int, function
< void(int, any
&) > > > deferredAdd_t
;
1151 deferredAdd_t deferredAdd
;
1153 void makeTCPServerSockets()
1156 vector
<string
>locals
;
1157 stringtok(locals
,::arg()["local-address"]," ,");
1160 throw PDNSException("No local address specified");
1162 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
1164 st
.port
=::arg().asNum("local-port");
1165 parseService(*i
, st
);
1169 memset((char *)&sin
,0, sizeof(sin
));
1170 sin
.sin4
.sin_family
= AF_INET
;
1171 if(!IpToU32(st
.host
, (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
1172 sin
.sin6
.sin6_family
= AF_INET6
;
1173 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
1174 throw PDNSException("Unable to resolve local address for TCP server on '"+ st
.host
+"'");
1177 fd
=socket(sin
.sin6
.sin6_family
, SOCK_STREAM
, 0);
1179 throw PDNSException("Making a TCP server socket for resolver: "+stringerror());
1184 if(setsockopt(fd
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
1185 L
<<Logger::Error
<<"Setsockopt failed for TCP listening socket"<<endl
;
1188 if(sin
.sin6
.sin6_family
== AF_INET6
&& setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &tmp
, sizeof(tmp
)) < 0) {
1189 L
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
1192 #ifdef TCP_DEFER_ACCEPT
1193 if(setsockopt(fd
, SOL_TCP
,TCP_DEFER_ACCEPT
,(char*)&tmp
,sizeof tmp
) >= 0) {
1194 if(i
==locals
.begin())
1195 L
<<Logger::Error
<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl
;
1199 if( ::arg().mustDo("non-local-bind") )
1200 Utility::setBindAny(AF_INET
, fd
);
1202 sin
.sin4
.sin_port
= htons(st
.port
);
1203 int socklen
=sin
.sin4
.sin_family
==AF_INET
? sizeof(sin
.sin4
) : sizeof(sin
.sin6
);
1204 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
1205 throw PDNSException("Binding TCP server socket for "+ st
.host
+": "+stringerror());
1208 setSocketSendBuffer(fd
, 65000);
1210 deferredAdd
.push_back(make_pair(fd
, handleNewTCPQuestion
));
1211 g_tcpListenSockets
.push_back(fd
);
1212 // we don't need to update g_listenSocketsAddresses since it doesn't work for TCP/IP:
1213 // - fd is not that which we know here, but returned from accept()
1214 if(sin
.sin4
.sin_family
== AF_INET
)
1215 L
<<Logger::Error
<<"Listening for TCP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
1217 L
<<Logger::Error
<<"Listening for TCP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
1221 void makeUDPServerSockets()
1224 vector
<string
>locals
;
1225 stringtok(locals
,::arg()["local-address"]," ,");
1228 throw PDNSException("No local address specified");
1230 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
1232 st
.port
=::arg().asNum("local-port");
1233 parseService(*i
, st
);
1237 memset(&sin
, 0, sizeof(sin
));
1238 sin
.sin4
.sin_family
= AF_INET
;
1239 if(!IpToU32(st
.host
.c_str() , (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
1240 sin
.sin6
.sin6_family
= AF_INET6
;
1241 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
1242 throw PDNSException("Unable to resolve local address for UDP server on '"+ st
.host
+"'");
1245 int fd
=socket(sin
.sin4
.sin_family
, SOCK_DGRAM
, 0);
1247 throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
1249 if (!setSocketTimestamps(fd
))
1250 L
<<Logger::Warning
<<"Unable to enable timestamp reporting for socket"<<endl
;
1252 if(IsAnyAddress(sin
)) {
1253 setsockopt(fd
, IPPROTO_IP
, GEN_IP_PKTINFO
, &one
, sizeof(one
)); // linux supports this, so why not - might fail on other systems
1254 #ifdef IPV6_RECVPKTINFO
1255 setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
));
1257 if(sin
.sin6
.sin6_family
== AF_INET6
&& setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
)) < 0) {
1258 L
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
1262 if( ::arg().mustDo("non-local-bind") )
1263 Utility::setBindAny(AF_INET6
, fd
);
1267 setSocketReceiveBuffer(fd
, 250000);
1268 sin
.sin4
.sin_port
= htons(st
.port
);
1270 int socklen
=sin
.sin4
.sin_family
==AF_INET
? sizeof(sin
.sin4
) : sizeof(sin
.sin6
);
1271 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
1272 throw PDNSException("Resolver binding to server socket on port "+ lexical_cast
<string
>(st
.port
) +" for "+ st
.host
+": "+stringerror());
1276 deferredAdd
.push_back(make_pair(fd
, handleNewUDPQuestion
));
1277 g_listenSocketsAddresses
[fd
]=sin
; // this is written to only from the startup thread, not from the workers
1278 if(sin
.sin4
.sin_family
== AF_INET
)
1279 L
<<Logger::Error
<<"Listening for UDP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
1281 L
<<Logger::Error
<<"Listening for UDP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
1286 void daemonize(void)
1293 int i
=open("/dev/null",O_RDWR
); /* open stdin */
1295 L
<<Logger::Critical
<<"Unable to open /dev/null: "<<stringerror()<<endl
;
1297 dup2(i
,0); /* stdin */
1298 dup2(i
,1); /* stderr */
1299 dup2(i
,2); /* stderr */
1304 AtomicCounter counter
;
1307 void usr1Handler(int)
1312 void usr2Handler(int)
1315 SyncRes::setDefaultLogMode(g_quiet
? SyncRes::LogNone
: SyncRes::Log
);
1316 ::arg().set("quiet")=g_quiet
? "" : "no";
1321 static time_t lastOutputTime
;
1322 static uint64_t lastQueryCount
;
1324 uint64_t cacheHits
= broadcastAccFunction
<uint64_t>(pleaseGetCacheHits
);
1325 uint64_t cacheMisses
= broadcastAccFunction
<uint64_t>(pleaseGetCacheMisses
);
1327 if(g_stats
.qcounter
&& (cacheHits
+ cacheMisses
) && SyncRes::s_queries
&& SyncRes::s_outqueries
) {
1328 L
<<Logger::Warning
<<"stats: "<<g_stats
.qcounter
<<" questions, "<<
1329 broadcastAccFunction
<uint64_t>(pleaseGetCacheSize
)<< " cache entries, "<<
1330 broadcastAccFunction
<uint64_t>(pleaseGetNegCacheSize
)<<" negative entries, "<<
1331 (int)((cacheHits
*100.0)/(cacheHits
+cacheMisses
))<<"% cache hits"<<endl
;
1333 L
<<Logger::Warning
<<"stats: throttle map: "
1334 << broadcastAccFunction
<uint64_t>(pleaseGetThrottleSize
) <<", ns speeds: "
1335 << broadcastAccFunction
<uint64_t>(pleaseGetNsSpeedsSize
)<<endl
;
1336 L
<<Logger::Warning
<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries
*100.0/SyncRes::s_queries
)<<"%";
1337 L
<<Logger::Warning
<<", "<<(int)(SyncRes::s_throttledqueries
*100.0/(SyncRes::s_outqueries
+SyncRes::s_throttledqueries
))<<"% throttled, "
1338 <<SyncRes::s_nodelegated
<<" no-delegation drops"<<endl
;
1339 L
<<Logger::Warning
<<"stats: "<<SyncRes::s_tcpoutqueries
<<" outgoing tcp connections, "<<
1340 broadcastAccFunction
<uint64_t>(pleaseGetConcurrentQueries
)<<" queries running, "<<SyncRes::s_outgoingtimeouts
<<" outgoing timeouts"<<endl
;
1342 //L<<Logger::Warning<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
1343 //g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
1345 L
<<Logger::Warning
<<"stats: " << broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheSize
) <<
1346 " packet cache entries, "<<(int)(100.0*broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheHits
)/SyncRes::s_queries
) << "% packet cache hits"<<endl
;
1348 time_t now
= time(0);
1349 if(lastOutputTime
&& lastQueryCount
&& now
!= lastOutputTime
) {
1350 L
<<Logger::Warning
<<"stats: "<< (SyncRes::s_queries
- lastQueryCount
) / (now
- lastOutputTime
) <<" qps (average over "<< (now
- lastOutputTime
) << " seconds)"<<endl
;
1352 lastOutputTime
= now
;
1353 lastQueryCount
= SyncRes::s_queries
;
1355 else if(statsWanted
)
1356 L
<<Logger::Warning
<<"stats: no stats yet!"<<endl
;
1361 static void houseKeeping(void *)
1363 static __thread
time_t last_stat
, last_rootupdate
, last_prune
, last_secpoll
;
1364 static __thread
int cleanCounter
=0;
1365 static __thread
bool s_running
; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
1372 Utility::gettimeofday(&now
, 0);
1374 if(now
.tv_sec
- last_prune
> (time_t)(5 + t_id
)) {
1377 t_RC
->doPrune(); // this function is local to a thread, so fine anyhow
1378 t_packetCache
->doPruneTo(::arg().asNum("max-packetcache-entries") / g_numWorkerThreads
);
1380 pruneCollection(t_sstorage
->negcache
, ::arg().asNum("max-cache-entries") / (g_numWorkerThreads
* 10), 200);
1382 if(!((cleanCounter
++)%40)) { // this is a full scan!
1383 time_t limit
=now
.tv_sec
-300;
1384 for(SyncRes::nsspeeds_t::iterator i
= t_sstorage
->nsSpeeds
.begin() ; i
!= t_sstorage
->nsSpeeds
.end(); )
1385 if(i
->second
.stale(limit
))
1386 t_sstorage
->nsSpeeds
.erase(i
++);
1393 if(now
.tv_sec
- last_rootupdate
> 7200) {
1395 sr
.setDoEDNS0(true);
1396 vector
<DNSRecord
> ret
;
1401 res
=sr
.beginResolve(DNSName(), QType(QType::NS
), 1, ret
);
1403 catch(PDNSException
& e
)
1405 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
1408 catch(std::exception
& e
)
1410 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
1415 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
1418 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
1419 last_rootupdate
=now
.tv_sec
;
1422 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;
1426 if(now
.tv_sec
- last_stat
>= 1800) {
1431 if(now
.tv_sec
- last_secpoll
>= 3600) {
1433 doSecPoll(&last_secpoll
);
1440 catch(PDNSException
& ae
)
1443 L
<<Logger::Error
<<"Fatal error in housekeeping thread: "<<ae
.reason
<<endl
;
1448 void makeThreadPipes()
1450 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
1451 struct ThreadPipeSet tps
;
1454 unixDie("Creating pipe for inter-thread communications");
1456 tps
.readToThread
= fd
[0];
1457 tps
.writeToThread
= fd
[1];
1460 unixDie("Creating pipe for inter-thread communications");
1461 tps
.readFromThread
= fd
[0];
1462 tps
.writeFromThread
= fd
[1];
1464 g_pipes
.push_back(tps
);
1474 void broadcastFunction(const pipefunc_t
& func
, bool skipSelf
)
1477 for(ThreadPipeSet
& tps
: g_pipes
)
1481 func(); // don't write to ourselves!
1485 ThreadMSG
* tmsg
= new ThreadMSG();
1487 tmsg
->wantAnswer
= true;
1488 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
))
1489 unixDie("write to thread pipe returned wrong size or error");
1492 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
1493 unixDie("read from thread pipe returned wrong size or error");
1496 // cerr <<"got response: " << *resp << endl;
1502 uint32_t g_disthashseed
;
1503 void distributeAsyncFunction(const string
& packet
, const pipefunc_t
& func
)
1505 unsigned int hash
= hashQuestion(packet
.c_str(), packet
.length(), g_disthashseed
);
1506 unsigned int target
= 1 + (hash
% (g_pipes
.size()-1));
1508 if(target
== t_id
) {
1512 ThreadPipeSet
& tps
= g_pipes
[target
];
1513 ThreadMSG
* tmsg
= new ThreadMSG();
1515 tmsg
->wantAnswer
= false;
1517 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
))
1518 unixDie("write to thread pipe returned wrong size or error");
1521 void handlePipeRequest(int fd
, FDMultiplexer::funcparam_t
& var
)
1525 if(read(fd
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) { // fd == readToThread
1526 unixDie("read from thread pipe returned wrong size or error");
1531 resp
= tmsg
->func();
1533 catch(std::exception
& e
) {
1534 L
<<Logger::Error
<<"PIPE function we executed created exception: "<<e
.what()<<endl
; // but what if they wanted an answer.. we send 0
1536 catch(PDNSException
& e
) {
1537 L
<<Logger::Error
<<"PIPE function we executed created PDNS exception: "<<e
.reason
<<endl
; // but what if they wanted an answer.. we send 0
1539 if(tmsg
->wantAnswer
)
1540 if(write(g_pipes
[t_id
].writeFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
1541 unixDie("write to thread pipe returned wrong size or error");
1546 template<class T
> void *voider(const boost::function
<T
*()>& func
)
1551 vector
<ComboAddress
>& operator+=(vector
<ComboAddress
>&a
, const vector
<ComboAddress
>& b
)
1553 a
.insert(a
.end(), b
.begin(), b
.end());
1557 vector
<pair
<string
, uint16_t> >& operator+=(vector
<pair
<string
, uint16_t> >&a
, const vector
<pair
<string
, uint16_t> >& b
)
1559 a
.insert(a
.end(), b
.begin(), b
.end());
1563 vector
<pair
<DNSName
, uint16_t> >& operator+=(vector
<pair
<DNSName
, uint16_t> >&a
, const vector
<pair
<DNSName
, uint16_t> >& b
)
1565 a
.insert(a
.end(), b
.begin(), b
.end());
1570 template<class T
> T
broadcastAccFunction(const boost::function
<T
*()>& func
, bool skipSelf
)
1574 for(ThreadPipeSet
& tps
: g_pipes
)
1578 T
* resp
= (T
*)func(); // don't write to ourselves!
1580 //~ cerr <<"got direct: " << *resp << endl;
1588 ThreadMSG
* tmsg
= new ThreadMSG();
1589 tmsg
->func
= boost::bind(voider
<T
>, func
);
1590 tmsg
->wantAnswer
= true;
1592 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
))
1593 unixDie("write to thread pipe returned wrong size or error");
1597 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
1598 unixDie("read from thread pipe returned wrong size or error");
1601 //~ cerr <<"got response: " << *resp << endl;
1609 template string
broadcastAccFunction(const boost::function
<string
*()>& fun
, bool skipSelf
); // explicit instantiation
1610 template uint64_t broadcastAccFunction(const boost::function
<uint64_t*()>& fun
, bool skipSelf
); // explicit instantiation
1611 template vector
<ComboAddress
> broadcastAccFunction(const boost::function
<vector
<ComboAddress
> *()>& fun
, bool skipSelf
); // explicit instantiation
1612 template vector
<pair
<DNSName
,uint16_t> > broadcastAccFunction(const boost::function
<vector
<pair
<DNSName
, uint16_t> > *()>& fun
, bool skipSelf
); // explicit instantiation
1614 void handleRCC(int fd
, FDMultiplexer::funcparam_t
& var
)
1617 string msg
=s_rcc
.recv(&remote
);
1618 RecursorControlParser rcp
;
1619 RecursorControlParser::func_t
* command
;
1621 string answer
=rcp
.getAnswer(msg
, &command
);
1623 s_rcc
.send(answer
, &remote
);
1626 catch(std::exception
& e
) {
1627 L
<<Logger::Error
<<"Error dealing with control socket request: "<<e
.what()<<endl
;
1629 catch(PDNSException
& ae
) {
1630 L
<<Logger::Error
<<"Error dealing with control socket request: "<<ae
.reason
<<endl
;
1634 void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
)
1636 PacketID
* pident
=any_cast
<PacketID
>(&var
);
1637 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
1639 shared_array
<char> buffer(new char[pident
->inNeeded
]);
1641 int ret
=recv(fd
, buffer
.get(), pident
->inNeeded
,0);
1643 pident
->inMSG
.append(&buffer
[0], &buffer
[ret
]);
1644 pident
->inNeeded
-=ret
;
1645 if(!pident
->inNeeded
|| pident
->inIncompleteOkay
) {
1646 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
1647 PacketID pid
=*pident
;
1648 string msg
=pident
->inMSG
;
1650 t_fdm
->removeReadFD(fd
);
1651 MT
->sendEvent(pid
, &msg
);
1654 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
1658 PacketID tmp
=*pident
;
1659 t_fdm
->removeReadFD(fd
); // pident might now be invalid (it isn't, but still)
1661 MT
->sendEvent(tmp
, &empty
); // this conveys error status
1665 void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
)
1667 PacketID
* pid
=any_cast
<PacketID
>(&var
);
1668 int ret
=send(fd
, pid
->outMSG
.c_str() + pid
->outPos
, pid
->outMSG
.size() - pid
->outPos
,0);
1671 if(pid
->outPos
==pid
->outMSG
.size()) {
1673 t_fdm
->removeWriteFD(fd
);
1674 MT
->sendEvent(tmp
, &tmp
.outMSG
); // send back what we sent to convey everything is ok
1677 else { // error or EOF
1679 t_fdm
->removeWriteFD(fd
);
1681 MT
->sendEvent(tmp
, &sent
); // we convey error status by sending empty string
1685 // resend event to everybody chained onto it
1686 void doResends(MT_t::waiters_t::iterator
& iter
, PacketID resend
, const string
& content
)
1688 if(iter
->key
.chain
.empty())
1690 // cerr<<"doResends called!\n";
1691 for(PacketID::chain_t::iterator i
=iter
->key
.chain
.begin(); i
!= iter
->key
.chain
.end() ; ++i
) {
1694 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
1696 MT
->sendEvent(resend
, &content
);
1697 g_stats
.chainResends
++;
1701 void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
1703 PacketID pid
=any_cast
<PacketID
>(var
);
1706 ComboAddress fromaddr
;
1707 socklen_t addrlen
=sizeof(fromaddr
);
1709 len
=recvfrom(fd
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
);
1711 if(len
< (int)sizeof(dnsheader
)) {
1713 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
1715 g_stats
.serverParseError
++;
1716 if(g_logCommonErrors
)
1717 L
<<Logger::Error
<<"Unable to parse packet from remote UDP server "<< fromaddr
.toString() <<
1718 ": packet smaller than DNS header"<<endl
;
1721 t_udpclientsocks
->returnSocket(fd
);
1724 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pid
);
1725 if(iter
!= MT
->d_waiters
.end())
1726 doResends(iter
, pid
, empty
);
1728 MT
->sendEvent(pid
, &empty
); // this denotes error (does lookup again.. at least L1 will be hot)
1733 memcpy(&dh
, data
, sizeof(dh
));
1736 pident
.remote
=fromaddr
;
1740 if(!dh
.qr
&& g_logCommonErrors
) {
1741 L
<<Logger::Notice
<<"Not taking data from question on outgoing socket from "<< fromaddr
.toStringWithPort() <<endl
;
1744 if(!dh
.qdcount
|| // UPC, Nominum, very old BIND on FormErr, NSD
1745 !dh
.qr
) { // one weird server
1746 pident
.domain
.clear();
1751 pident
.domain
=DNSName(data
, len
, 12, false, &pident
.type
); // don't copy this from above - we need to do the actual read
1753 catch(std::exception
& e
) {
1754 g_stats
.serverParseError
++; // won't be fed to lwres.cc, so we have to increment
1755 L
<<Logger::Warning
<<"Error in packet from "<< fromaddr
.toStringWithPort() << ": "<<e
.what() << endl
;
1760 packet
.assign(data
, len
);
1762 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pident
);
1763 if(iter
!= MT
->d_waiters
.end()) {
1764 doResends(iter
, pident
, packet
);
1769 if(!MT
->sendEvent(pident
, &packet
)) {
1770 // we do a full scan for outstanding queries on unexpected answers. not too bad since we only accept them on the right port number, which is hard enough to guess
1771 for(MT_t::waiters_t::iterator mthread
=MT
->d_waiters
.begin(); mthread
!=MT
->d_waiters
.end(); ++mthread
) {
1772 if(pident
.fd
==mthread
->key
.fd
&& mthread
->key
.remote
==pident
.remote
&& mthread
->key
.type
== pident
.type
&&
1773 pident
.domain
== mthread
->key
.domain
) {
1774 mthread
->key
.nearMisses
++;
1777 // be a bit paranoid here since we're weakening our matching
1778 if(pident
.domain
.empty() && !mthread
->key
.domain
.empty() && !pident
.type
&& mthread
->key
.type
&&
1779 pident
.id
== mthread
->key
.id
&& mthread
->key
.remote
== pident
.remote
) {
1780 // cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
1781 pident
.domain
= mthread
->key
.domain
;
1782 pident
.type
= mthread
->key
.type
;
1783 goto retryWithName
; // note that this only passes on an error, lwres will still reject the packet
1786 g_stats
.unexpectedCount
++; // if we made it here, it really is an unexpected answer
1787 if(g_logCommonErrors
) {
1788 L
<<Logger::Warning
<<"Discarding unexpected packet from "<<fromaddr
.toStringWithPort()<<": "<<pident
.domain
<<", "<<pident
.type
<<", "<<MT
->d_waiters
.size()<<" waiters"<<endl
;
1792 t_udpclientsocks
->returnSocket(fd
);
1796 FDMultiplexer
* getMultiplexer()
1799 for(FDMultiplexer::FDMultiplexermap_t::const_iterator i
= FDMultiplexer::getMultiplexerMap().begin();
1800 i
!= FDMultiplexer::getMultiplexerMap().end(); ++i
) {
1805 catch(FDMultiplexerException
&fe
) {
1806 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer ("<<fe
.what()<<"), falling back"<<endl
;
1809 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer"<<endl
;
1812 L
<<Logger::Error
<<"No working multiplexer found!"<<endl
;
1817 string
* doReloadLuaScript()
1819 string fname
= ::arg()["lua-dns-script"];
1823 L
<<Logger::Error
<<t_id
<<" Unloaded current lua script"<<endl
;
1824 return new string("unloaded\n");
1827 *t_pdl
= shared_ptr
<RecursorLua
>(new RecursorLua(fname
));
1830 catch(std::exception
& e
) {
1831 L
<<Logger::Error
<<t_id
<<" Retaining current script, error from '"<<fname
<<"': "<< e
.what() <<endl
;
1832 return new string("retaining current script, error from '"+fname
+"': "+e
.what()+"\n");
1835 L
<<Logger::Warning
<<t_id
<<" (Re)loaded lua script from '"<<fname
<<"'"<<endl
;
1836 return new string("(re)loaded '"+fname
+"'\n");
1839 string
doQueueReloadLuaScript(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
1842 ::arg().set("lua-dns-script") = *begin
;
1844 return broadcastAccFunction
<string
>(doReloadLuaScript
);
1847 string
* pleaseUseNewTraceRegex(const std::string
& newRegex
)
1850 if(newRegex
.empty()) {
1851 t_traceRegex
->reset();
1852 return new string("unset\n");
1855 (*t_traceRegex
) = shared_ptr
<Regex
>(new Regex(newRegex
));
1856 return new string("ok\n");
1859 catch(PDNSException
& ae
)
1861 return new string(ae
.reason
+"\n");
1864 string
doTraceRegex(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
1866 return broadcastAccFunction
<string
>(boost::bind(pleaseUseNewTraceRegex
, begin
!=end
? *begin
: ""));
1869 static void checkLinuxIPv6Limits()
1873 if(readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line
)) {
1874 int lim
=atoi(line
.c_str());
1876 L
<<Logger::Error
<<"If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to "<<lim
<<" which is < 16384"<<endl
;
1881 static void checkOrFixFDS()
1883 unsigned int availFDs
=getFilenumLimit()-10; // some healthy margin, thanks AJ ;-)
1884 if(g_maxMThreads
* g_numWorkerThreads
> availFDs
) {
1885 if(getFilenumLimit(true) >= g_maxMThreads
* g_numWorkerThreads
) {
1886 setFilenumLimit(g_maxMThreads
* g_numWorkerThreads
);
1887 L
<<Logger::Warning
<<"Raised soft limit on number of filedescriptors to "<<g_maxMThreads
* g_numWorkerThreads
<<" to match max-mthreads and threads settings"<<endl
;
1890 int newval
= getFilenumLimit(true) / g_numWorkerThreads
;
1891 L
<<Logger::Warning
<<"Insufficient number of filedescriptors available for max-mthreads*threads setting! ("<<availFDs
<<" < "<<g_maxMThreads
*g_numWorkerThreads
<<"), reducing max-mthreads to "<<newval
<<endl
;
1892 g_maxMThreads
= newval
;
1893 setFilenumLimit(g_maxMThreads
* g_numWorkerThreads
);
1898 void* recursorThread(void*);
1900 void* pleaseSupplantACLs(NetmaskGroup
*ng
)
1911 static bool l_initialized
;
1913 if(l_initialized
) { // only reload configuration file on second call
1914 string configname
=::arg()["config-dir"]+"/recursor.conf";
1915 cleanSlashes(configname
);
1917 if(!::arg().preParseFile(configname
.c_str(), "allow-from-file"))
1918 throw runtime_error("Unable to re-parse configuration file '"+configname
+"'");
1919 ::arg().preParseFile(configname
.c_str(), "allow-from", LOCAL_NETS
);
1920 ::arg().preParseFile(configname
.c_str(), "include-dir");
1921 ::arg().preParse(g_argc
, g_argv
, "include-dir");
1923 // then process includes
1924 std::vector
<std::string
> extraConfigs
;
1925 ::arg().gatherIncludes(extraConfigs
);
1927 for(const std::string
& fn
: extraConfigs
) {
1928 if(!::arg().preParseFile(fn
.c_str(), "allow-from-file", ::arg()["allow-from-file"]))
1929 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
1930 if(!::arg().preParseFile(fn
.c_str(), "allow-from", ::arg()["allow-from"]))
1931 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
1934 ::arg().preParse(g_argc
, g_argv
, "allow-from-file");
1935 ::arg().preParse(g_argc
, g_argv
, "allow-from");
1938 NetmaskGroup
* oldAllowFrom
= t_allowFrom
, *allowFrom
=new NetmaskGroup
;
1940 if(!::arg()["allow-from-file"].empty()) {
1942 ifstream
ifs(::arg()["allow-from-file"].c_str());
1945 throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
1948 string::size_type pos
;
1949 while(getline(ifs
,line
)) {
1951 if(pos
!=string::npos
)
1957 allowFrom
->addMask(line
);
1959 L
<<Logger::Warning
<<"Done parsing " << allowFrom
->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl
;
1961 else if(!::arg()["allow-from"].empty()) {
1963 stringtok(ips
, ::arg()["allow-from"], ", ");
1965 L
<<Logger::Warning
<<"Only allowing queries from: ";
1966 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
1967 allowFrom
->addMask(*i
);
1969 L
<<Logger::Warning
<<", ";
1970 L
<<Logger::Warning
<<*i
;
1972 L
<<Logger::Warning
<<endl
;
1975 if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
1976 L
<<Logger::Error
<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl
;
1981 g_initialAllowFrom
= allowFrom
;
1982 broadcastFunction(boost::bind(pleaseSupplantACLs
, allowFrom
));
1983 delete oldAllowFrom
;
1985 l_initialized
= true;
1988 int serviceMain(int argc
, char*argv
[])
1991 L
.setName(s_programname
);
1992 L
.setLoglevel((Logger::Urgency
)(6)); // info and up
1994 if(!::arg()["logging-facility"].empty()) {
1995 int val
=logFacilityToLOG(::arg().asNum("logging-facility") );
1997 theL().setFacility(val
);
1999 L
<<Logger::Error
<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl
;
2002 showProductVersion();
2003 seedRandom(::arg()["entropy-source"]);
2004 g_disthashseed
=dns_random(0xffffffff);
2007 sortPublicSuffixList();
2009 if(!::arg()["dont-query"].empty()) {
2010 g_dontQuery
=new NetmaskGroup
;
2012 stringtok(ips
, ::arg()["dont-query"], ", ");
2013 ips
.push_back("0.0.0.0");
2014 ips
.push_back("::");
2016 L
<<Logger::Warning
<<"Will not send queries to: ";
2017 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
2018 g_dontQuery
->addMask(*i
);
2020 L
<<Logger::Warning
<<", ";
2021 L
<<Logger::Warning
<<*i
;
2023 L
<<Logger::Warning
<<endl
;
2026 g_quiet
=::arg().mustDo("quiet");
2028 g_weDistributeQueries
= ::arg().mustDo("pdns-distributes-queries");
2029 if(g_weDistributeQueries
) {
2030 L
<<Logger::Warning
<<"PowerDNS Recursor itself will distribute queries over threads"<<endl
;
2033 if(::arg()["trace"]=="fail") {
2034 SyncRes::setDefaultLogMode(SyncRes::Store
);
2036 else if(::arg().mustDo("trace")) {
2037 SyncRes::setDefaultLogMode(SyncRes::Log
);
2038 ::arg().set("quiet")="no";
2042 SyncRes::s_minimumTTL
= ::arg().asNum("minimum-ttl-override");
2044 checkLinuxIPv6Limits();
2046 vector
<string
> addrs
;
2047 if(!::arg()["query-local-address6"].empty()) {
2048 SyncRes::s_doIPv6
=true;
2049 L
<<Logger::Warning
<<"Enabling IPv6 transport for outgoing queries"<<endl
;
2051 stringtok(addrs
, ::arg()["query-local-address6"], ", ;");
2052 for(const string
& addr
: addrs
) {
2053 g_localQueryAddresses6
.push_back(ComboAddress(addr
));
2057 L
<<Logger::Warning
<<"NOT using IPv6 for outgoing queries - set 'query-local-address6=::' to enable"<<endl
;
2060 stringtok(addrs
, ::arg()["query-local-address"], ", ;");
2061 for(const string
& addr
: addrs
) {
2062 g_localQueryAddresses4
.push_back(ComboAddress(addr
));
2065 catch(std::exception
& e
) {
2066 L
<<Logger::Error
<<"Assigning local query addresses: "<<e
.what();
2070 SyncRes::s_nopacketcache
= ::arg().mustDo("disable-packetcache");
2072 SyncRes::s_maxnegttl
=::arg().asNum("max-negative-ttl");
2073 SyncRes::s_maxcachettl
=::arg().asNum("max-cache-ttl");
2074 SyncRes::s_packetcachettl
=::arg().asNum("packetcache-ttl");
2075 SyncRes::s_packetcacheservfailttl
=::arg().asNum("packetcache-servfail-ttl");
2076 SyncRes::s_serverdownmaxfails
=::arg().asNum("server-down-max-fails");
2077 SyncRes::s_serverdownthrottletime
=::arg().asNum("server-down-throttle-time");
2078 SyncRes::s_serverID
=::arg()["server-id"];
2079 SyncRes::s_maxqperq
=::arg().asNum("max-qperq");
2080 SyncRes::s_maxtotusec
=1000*::arg().asNum("max-total-msec");
2081 SyncRes::s_rootNXTrust
= ::arg().mustDo( "root-nx-trust");
2082 if(SyncRes::s_serverID
.empty()) {
2084 gethostname(tmp
, sizeof(tmp
)-1);
2085 SyncRes::s_serverID
=tmp
;
2088 g_networkTimeoutMsec
= ::arg().asNum("network-timeout");
2090 g_initialDomainMap
= parseAuthAndForwards();
2092 g_latencyStatSize
=::arg().asNum("latency-statistic-size");
2094 g_logCommonErrors
=::arg().mustDo("log-common-errors");
2096 g_anyToTcp
= ::arg().mustDo("any-to-tcp");
2097 g_udpTruncationThreshold
= ::arg().asNum("udp-truncation-threshold");
2099 makeUDPServerSockets();
2100 makeTCPServerSockets();
2103 for(forks
= 0; forks
< ::arg().asNum("processes") - 1; ++forks
) {
2104 if(!fork()) // we are child
2108 s_pidfname
=::arg()["socket-dir"]+"/"+s_programname
+".pid";
2109 if(!s_pidfname
.empty())
2110 unlink(s_pidfname
.c_str()); // remove possible old pid file
2114 if(::arg().mustDo("daemon")) {
2115 L
<<Logger::Warning
<<"Calling daemonize, going to background"<<endl
;
2116 L
.toConsole(Logger::Critical
);
2119 signal(SIGUSR1
,usr1Handler
);
2120 signal(SIGUSR2
,usr2Handler
);
2121 signal(SIGPIPE
,SIG_IGN
);
2123 makeControlChannelSocket( ::arg().asNum("processes") > 1 ? forks
: -1);
2124 g_numThreads
= ::arg().asNum("threads") + ::arg().mustDo("pdns-distributes-queries");
2125 g_maxMThreads
= ::arg().asNum("max-mthreads");
2131 if(!::arg()["setgid"].empty())
2132 newgid
=Utility::makeGidNumeric(::arg()["setgid"]);
2134 if(!::arg()["setuid"].empty())
2135 newuid
=Utility::makeUidNumeric(::arg()["setuid"]);
2137 Utility::dropGroupPrivs(newuid
, newgid
);
2139 if (!::arg()["chroot"].empty()) {
2140 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
2141 L
<<Logger::Error
<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno
)<<", exiting"<<endl
;
2146 Utility::dropUserPrivs(newuid
);
2147 g_numThreads
= ::arg().asNum("threads") + ::arg().mustDo("pdns-distributes-queries");
2148 g_numWorkerThreads
= ::arg().asNum("threads");
2151 g_tcpTimeout
=::arg().asNum("client-tcp-timeout");
2152 g_maxTCPPerClient
=::arg().asNum("max-tcp-per-client");
2154 if(g_numThreads
== 1) {
2155 L
<<Logger::Warning
<<"Operating unthreaded"<<endl
;
2160 L
<<Logger::Warning
<<"Launching "<< g_numThreads
<<" threads"<<endl
;
2161 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
2162 pthread_create(&tid
, 0, recursorThread
, (void*)(long)n
);
2167 pthread_join(tid
, &res
);
2172 void* recursorThread(void* ptr
)
2175 t_id
=(int) (long) ptr
;
2176 SyncRes
tmp(g_now
); // make sure it allocates tsstorage before we do anything, like primeHints or so..
2177 t_sstorage
->domainmap
= g_initialDomainMap
;
2178 t_allowFrom
= g_initialAllowFrom
;
2179 t_udpclientsocks
= new UDPClientSocks();
2180 t_tcpClientCounts
= new tcpClientCounts_t();
2183 t_packetCache
= new RecursorPacketCache();
2185 L
<<Logger::Warning
<<"Done priming cache with root hints"<<endl
;
2187 t_pdl
= new shared_ptr
<RecursorLua
>();
2190 if(!::arg()["lua-dns-script"].empty()) {
2191 *t_pdl
= shared_ptr
<RecursorLua
>(new RecursorLua(::arg()["lua-dns-script"]));
2192 L
<<Logger::Warning
<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl
;
2195 catch(std::exception
&e
) {
2196 L
<<Logger::Error
<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e
.what()<<endl
;
2200 t_traceRegex
= new shared_ptr
<Regex
>();
2201 unsigned int ringsize
=::arg().asNum("stats-ringbuffer-entries") / g_numWorkerThreads
;
2203 t_remotes
= new addrringbuf_t();
2204 if(g_weDistributeQueries
) // if so, only 1 thread does recvfrom
2205 t_remotes
->set_capacity(::arg().asNum("stats-ringbuffer-entries"));
2207 t_remotes
->set_capacity(ringsize
);
2208 t_servfailremotes
= new addrringbuf_t();
2209 t_servfailremotes
->set_capacity(ringsize
);
2210 t_largeanswerremotes
= new addrringbuf_t();
2211 t_largeanswerremotes
->set_capacity(ringsize
);
2213 t_queryring
= new boost::circular_buffer
<pair
<DNSName
, uint16_t> >();
2214 t_queryring
->set_capacity(ringsize
);
2215 t_servfailqueryring
= new boost::circular_buffer
<pair
<DNSName
, uint16_t> >();
2216 t_servfailqueryring
->set_capacity(ringsize
);
2219 MT
=new MTasker
<PacketID
,string
>(::arg().asNum("stack-size"));
2223 t_fdm
=getMultiplexer();
2225 if(::arg().mustDo("experimental-webserver")) {
2226 L
<<Logger::Warning
<< "Enabling web server" << endl
;
2228 new RecursorWebServer(t_fdm
);
2230 catch(PDNSException
&e
) {
2231 L
<<Logger::Error
<<"Exception: "<<e
.reason
<<endl
;
2235 L
<<Logger::Error
<<"Enabled '"<< t_fdm
->getName() << "' multiplexer"<<endl
;
2238 t_fdm
->addReadFD(g_pipes
[t_id
].readToThread
, handlePipeRequest
);
2240 if(!g_weDistributeQueries
|| !t_id
) // if we distribute queries, only t_id = 0 listens
2241 for(deferredAdd_t::const_iterator i
=deferredAdd
.begin(); i
!=deferredAdd
.end(); ++i
)
2242 t_fdm
->addReadFD(i
->first
, i
->second
);
2245 t_fdm
->addReadFD(s_rcc
.d_fd
, handleRCC
); // control channel
2248 unsigned int maxTcpClients
=::arg().asNum("max-tcp-clients");
2250 bool listenOnTCP(true);
2252 time_t last_carbon
=0;
2253 time_t carbonInterval
=::arg().asNum("carbon-interval");
2254 counter
=AtomicCounter(0); // used to periodically execute certain tasks
2256 while(MT
->schedule(&g_now
)); // MTasker letting the mthreads do their thing
2258 if(!(counter
%500)) {
2259 MT
->makeThread(houseKeeping
, 0);
2263 typedef vector
<pair
<int, FDMultiplexer::funcparam_t
> > expired_t
;
2264 expired_t expired
=t_fdm
->getTimeouts(g_now
);
2266 for(expired_t::iterator i
=expired
.begin() ; i
!= expired
.end(); ++i
) {
2267 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(i
->second
);
2268 if(g_logCommonErrors
)
2269 L
<<Logger::Warning
<<"Timeout from remote TCP client "<< conn
->d_remote
.toString() <<endl
;
2270 t_fdm
->removeReadFD(i
->first
);
2276 if(!t_id
&& statsWanted
) {
2280 Utility::gettimeofday(&g_now
, 0);
2282 if(!t_id
&& (g_now
.tv_sec
- last_carbon
>= carbonInterval
)) {
2283 MT
->makeThread(doCarbonDump
, 0);
2284 last_carbon
= g_now
.tv_sec
;
2288 // 'run' updates g_now for us
2290 if(!g_weDistributeQueries
|| !t_id
) { // if pdns distributes queries, only tid 0 should do this
2292 if(TCPConnection::getCurrentConnections() > maxTcpClients
) { // shutdown, too many connections
2293 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
2294 t_fdm
->removeReadFD(*i
);
2299 if(TCPConnection::getCurrentConnections() <= maxTcpClients
) { // reenable
2300 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
2301 t_fdm
->addReadFD(*i
, handleNewTCPQuestion
);
2308 catch(PDNSException
&ae
) {
2309 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
2312 catch(std::exception
&e
) {
2313 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
2317 L
<<Logger::Error
<<"any other exception in main: "<<endl
;
2322 int main(int argc
, char **argv
)
2326 g_stats
.startupTime
=time(0);
2327 versionSetProduct(ProductRecursor
);
2331 int ret
= EXIT_SUCCESS
;
2334 ::arg().set("stack-size","stack size per mthread")="200000";
2335 ::arg().set("soa-minimum-ttl","Don't change")="0";
2336 ::arg().set("no-shuffle","Don't change")="off";
2337 ::arg().set("local-port","port to listen on")="53";
2338 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
2339 ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
2340 ::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
2341 ::arg().set("daemon","Operate as a daemon")="yes";
2342 ::arg().setSwitch("write-pid","Write a PID file")="yes";
2343 ::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="4";
2344 ::arg().set("log-common-errors","If we should log rather common errors")="yes";
2345 ::arg().set("chroot","switch to chroot jail")="";
2346 ::arg().set("setgid","If set, change group id to this gid for more security")="";
2347 ::arg().set("setuid","If set, change user id to this uid for more security")="";
2348 ::arg().set("network-timeout", "Wait this nummer of milliseconds for network i/o")="1500";
2349 ::arg().set("threads", "Launch this number of threads")="2";
2350 ::arg().set("processes", "Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)")="1";
2351 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
2352 ::arg().set( "experimental-logfile", "Filename of the log file for JSON parser" )= "/var/log/pdns.log";
2353 ::arg().setSwitch("experimental-webserver", "Start a webserver for monitoring") = "no";
2354 ::arg().set("experimental-webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
2355 ::arg().set("experimental-webserver-port", "Port of webserver to listen on") = "8082";
2356 ::arg().set("experimental-webserver-password", "Password required for accessing the webserver") = "";
2357 ::arg().set("webserver-allow-from","Webserver access is only allowed from these subnets")="0.0.0.0/0,::/0";
2358 ::arg().set("experimental-api-config-dir", "Directory where REST API stores config and zones") = "";
2359 ::arg().set("experimental-api-key", "REST API Static authentication key (required for API use)") = "";
2360 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats")="";
2361 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server")="";
2362 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates")="30";
2363 ::arg().set("experimental-api-readonly", "If the JSON API should disallow data modification") = "no";
2364 ::arg().set("quiet","Suppress logging of questions and answers")="";
2365 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
2366 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR
;
2367 ::arg().set("socket-owner","Owner of socket")="";
2368 ::arg().set("socket-group","Group of socket")="";
2369 ::arg().set("socket-mode", "Permissions for socket")="";
2371 ::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR
;
2372 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
2373 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
2374 ::arg().set("query-local-address6","Source IPv6 address for sending queries. IF UNSET, IPv6 WILL NOT BE USED FOR OUTGOING QUERIES")="";
2375 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
2376 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
2377 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
2378 ::arg().set("server-down-max-fails","Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )")="64";
2379 ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60";
2380 ::arg().set("hint-file", "If set, load root hints from this file")="";
2381 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
2382 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
2383 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
2384 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
2385 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000";
2386 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
2387 ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")="";
2388 ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for")="10000";
2389 ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString();
2390 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS
;
2391 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
2392 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
2393 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY
;
2394 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
2395 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
2396 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
2397 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
2398 ::arg().set("rpz-files", "RPZ files to load in order, domain or domain=policy pairs separated by commas")="";
2400 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
2401 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
2402 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")="";
2403 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
2404 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")="";
2405 ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
2406 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="";
2407 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
2408 ::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000";
2409 // ::arg().setSwitch( "disable-edns-ping", "Disable EDNSPing - EXPERIMENTAL, LEAVE DISABLED" )= "no";
2410 ::arg().setSwitch( "disable-edns", "Disable EDNS - EXPERIMENTAL, LEAVE DISABLED" )= "";
2411 ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
2412 ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="";
2413 ::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="no";
2414 ::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";
2415 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1680";
2416 ::arg().set("minimum-ttl-override", "Set under adverse conditions, a minimum TTL")="0";
2417 ::arg().set("max-qperq", "Maximum outgoing queries per query")="50";
2418 ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited")="7000";
2420 ::arg().set("include-dir","Include *.conf files from this directory")="";
2421 ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
2423 ::arg().setCmd("help","Provide a helpful message");
2424 ::arg().setCmd("version","Print version string");
2425 ::arg().setCmd("config","Output blank configuration");
2426 L
.toConsole(Logger::Info
);
2427 ::arg().laxParse(argc
,argv
); // do a lax parse
2429 string configname
=::arg()["config-dir"]+"/recursor.conf";
2430 if(::arg()["config-name"]!="") {
2431 configname
=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
2432 s_programname
+="-"+::arg()["config-name"];
2434 cleanSlashes(configname
);
2436 if(::arg().mustDo("config")) {
2437 cout
<<::arg().configstring()<<endl
;
2441 if(!::arg().file(configname
.c_str()))
2442 L
<<Logger::Warning
<<"Unable to parse configuration file '"<<configname
<<"'"<<endl
;
2444 ::arg().parse(argc
,argv
);
2446 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
2448 if(::arg().asNum("threads")==1)
2449 ::arg().set("pdns-distributes-queries")="no";
2451 if(::arg().mustDo("help")) {
2452 cout
<<"syntax:"<<endl
<<endl
;
2453 cout
<<::arg().helpstring(::arg()["help"])<<endl
;
2456 if(::arg().mustDo("version")) {
2457 showProductVersion();
2458 showBuildConfiguration();
2462 Logger::Urgency logUrgency
= (Logger::Urgency
)::arg().asNum("loglevel");
2464 if (logUrgency
< Logger::Error
)
2465 logUrgency
= Logger::Error
;
2466 if(!g_quiet
&& logUrgency
< Logger::Info
) { // Logger::Info=6, Logger::Debug=7
2467 logUrgency
= Logger::Info
; // if you do --quiet=no, you need Info to also see the query log
2469 L
.setLoglevel(logUrgency
);
2470 L
.toConsole(logUrgency
);
2472 serviceMain(argc
, argv
);
2474 catch(PDNSException
&ae
) {
2475 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
2478 catch(std::exception
&e
) {
2479 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
2483 L
<<Logger::Error
<<"any other exception in main: "<<endl
;