2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2003 - 2013 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 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <boost/foreach.hpp>
25 #include "recpacketcache.hh"
27 #include "dns_random.hh"
32 #include "recursor_cache.hh"
33 #include "cachecleaner.hh"
40 #include "arguments.hh"
45 #include <boost/tuple/tuple.hpp>
46 #include <boost/tuple/tuple_comparison.hpp>
47 #include <boost/shared_array.hpp>
48 #include <boost/lexical_cast.hpp>
49 #include <boost/function.hpp>
50 #include <boost/algorithm/string.hpp>
51 #include <netinet/tcp.h>
52 #include "dnsparser.hh"
53 #include "dnswriter.hh"
54 #include "dnsrecords.hh"
55 #include "zoneparser-tng.hh"
56 #include "rec_channel.hh"
61 #include "lua-recursor.hh"
69 __thread FDMultiplexer
* t_fdm
;
70 __thread
unsigned int t_id
;
71 unsigned int g_maxTCPPerClient
;
72 unsigned int g_networkTimeoutMsec
;
73 bool g_logCommonErrors
;
74 __thread shared_ptr
<RecursorLua
>* t_pdl
;
75 __thread RemoteKeeper
* t_remotes
;
76 __thread shared_ptr
<Regex
>* t_traceRegex
;
78 RecursorControlChannel s_rcc
; // only active in thread 0
80 // for communicating with our threads
89 vector
<ThreadPipeSet
> g_pipes
; // effectively readonly after startup
91 SyncRes::domainmap_t
* g_initialDomainMap
; // new threads needs this to be setup
93 #include "namespaces.hh"
95 __thread MemRecursorCache
* t_RC
;
96 __thread RecursorPacketCache
* t_packetCache
;
97 RecursorStats g_stats
;
100 bool g_weDistributeQueries
; // if true, only 1 thread listens on the incoming query sockets
102 static __thread NetmaskGroup
* t_allowFrom
;
103 static NetmaskGroup
* g_initialAllowFrom
; // new thread needs to be setup with this
105 NetmaskGroup
* g_dontQuery
;
106 string s_programname
="recursor";
108 typedef vector
<int> tcpListenSockets_t
;
109 tcpListenSockets_t g_tcpListenSockets
; // shared across threads, but this is fine, never written to from a thread. All threads listen on all sockets
111 unsigned int g_maxMThreads
;
112 struct timeval g_now
; // timestamp, updated (too) frequently
113 map
<int, ComboAddress
> g_listenSocketsAddresses
; // is shared across all threads right now
115 __thread MT_t
* MT
; // the big MTasker
117 unsigned int g_numThreads
;
119 #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, fe80::/10"
121 //! used to send information to a newborn mthread
122 struct DNSComboWriter
{
123 DNSComboWriter(const char* data
, uint16_t len
, const struct timeval
& now
) : d_mdp(data
, len
), d_now(now
),
124 d_tcp(false), d_socket(-1)
127 void setRemote(const ComboAddress
* sa
)
132 void setSocket(int sock
)
137 string
getRemote() const
139 return d_remote
.toString();
142 struct timeval d_now
;
143 ComboAddress d_remote
;
146 shared_ptr
<TCPConnection
> d_tcpConnection
;
152 static ArgvMap theArg
;
157 void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
);
159 // -1 is error, 0 is timeout, 1 is success
160 int asendtcp(const string
& data
, Socket
* sock
)
166 t_fdm
->addWriteFD(sock
->getHandle(), handleTCPClientWritable
, pident
);
169 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
);
171 if(!ret
|| ret
==-1) { // timeout
172 t_fdm
->removeWriteFD(sock
->getHandle());
174 else if(packet
.size() !=data
.size()) { // main loop tells us what it sent out, or empty in case of an error
180 void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
);
182 // -1 is error, 0 is timeout, 1 is success
183 int arecvtcp(string
& data
, int len
, Socket
* sock
)
189 t_fdm
->addReadFD(sock
->getHandle(), handleTCPClientReadable
, pident
);
191 int ret
=MT
->waitEvent(pident
,&data
, g_networkTimeoutMsec
);
192 if(!ret
|| ret
==-1) { // timeout
193 t_fdm
->removeReadFD(sock
->getHandle());
195 else if(data
.empty()) {// error, EOF or other
202 vector
<ComboAddress
> g_localQueryAddresses4
, g_localQueryAddresses6
;
203 const ComboAddress
g_local4("0.0.0.0"), g_local6("::");
205 //! pick a random query local address
206 ComboAddress
getQueryLocalAddress(int family
, uint16_t port
)
209 if(family
==AF_INET
) {
210 if(g_localQueryAddresses4
.empty())
213 ret
= g_localQueryAddresses4
[dns_random(g_localQueryAddresses4
.size())];
214 ret
.sin4
.sin_port
= htons(port
);
217 if(g_localQueryAddresses6
.empty())
220 ret
= g_localQueryAddresses6
[dns_random(g_localQueryAddresses6
.size())];
222 ret
.sin6
.sin6_port
= htons(port
);
227 void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
&);
229 void setSocketBuffer(int fd
, int optname
, uint32_t size
)
232 socklen_t len
=sizeof(psize
);
234 if(!getsockopt(fd
, SOL_SOCKET
, optname
, (char*)&psize
, &len
) && psize
> size
) {
235 L
<<Logger::Error
<<"Not decreasing socket buffer size from "<<psize
<<" to "<<size
<<endl
;
239 if (setsockopt(fd
, SOL_SOCKET
, optname
, (char*)&size
, sizeof(size
)) < 0 )
240 L
<<Logger::Error
<<"Warning: unable to raise socket buffer size to "<<size
<<": "<<strerror(errno
)<<endl
;
244 static void setSocketReceiveBuffer(int fd
, uint32_t size
)
246 setSocketBuffer(fd
, SO_RCVBUF
, size
);
249 static void setSocketSendBuffer(int fd
, uint32_t size
)
251 setSocketBuffer(fd
, SO_SNDBUF
, size
);
255 // you can ask this class for a UDP socket to send a query from
256 // this socket is not yours, don't even think about deleting it
257 // but after you call 'returnSocket' on it, don't assume anything anymore
260 unsigned int d_numsocks
;
261 unsigned int d_maxsocks
;
263 UDPClientSocks() : d_numsocks(0), d_maxsocks(5000)
267 typedef set
<int> socks_t
;
270 // returning -1 means: temporary OS error (ie, out of files), -2 means OS error
271 int getSocket(const ComboAddress
& toaddr
, int* fd
)
273 *fd
=makeClientSocket(toaddr
.sin4
.sin_family
);
274 if(*fd
< 0) // temporary error - receive exception otherwise
277 if(connect(*fd
, (struct sockaddr
*)(&toaddr
), toaddr
.getSocklen()) < 0) {
279 // returnSocket(*fd);
280 Utility::closesocket(*fd
);
281 if(err
==ENETUNREACH
) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
291 void returnSocket(int fd
)
293 socks_t::iterator i
=d_socks
.find(fd
);
294 if(i
==d_socks
.end()) {
295 throw PDNSException("Trying to return a socket (fd="+lexical_cast
<string
>(fd
)+") not in the pool");
297 returnSocketLocked(i
);
300 // return a socket to the pool, or simply erase it
301 void returnSocketLocked(socks_t::iterator
& i
)
303 if(i
==d_socks
.end()) {
304 throw PDNSException("Trying to return a socket not in the pool");
307 t_fdm
->removeReadFD(*i
);
309 catch(FDMultiplexerException
& e
) {
310 // we sometimes return a socket that has not yet been assigned to t_fdm
312 Utility::closesocket(*i
);
318 // returns -1 for errors which might go away, throws for ones that won't
319 static int makeClientSocket(int family
)
321 int ret
=(int)socket(family
, SOCK_DGRAM
, 0);
323 if(ret
< 0 && errno
==EMFILE
) // this is not a catastrophic error
327 throw PDNSException("Making a socket for resolver (family = "+lexical_cast
<string
>(family
)+"): "+stringerror());
329 Utility::setCloseOnExec(ret
);
335 if(tries
==1) // fall back to kernel 'random'
338 port
= 1025 + dns_random(64510);
340 ComboAddress sin
=getQueryLocalAddress(family
, port
); // does htons for us
342 if (::bind(ret
, (struct sockaddr
*)&sin
, sin
.getSocklen()) >= 0)
346 throw PDNSException("Resolver binding to local query client socket: "+stringerror());
348 Utility::setNonBlocking(ret
);
353 static __thread UDPClientSocks
* t_udpclientsocks
;
355 /* these two functions are used by LWRes */
356 // -2 is OS error, -1 is error that depends on the remote, > 0 is success
357 int asendto(const char *data
, int len
, int flags
,
358 const ComboAddress
& toaddr
, uint16_t id
, const string
& domain
, uint16_t qtype
, int* fd
)
362 pident
.domain
= domain
;
363 pident
.remote
= toaddr
;
366 // see if there is an existing outstanding request we can chain on to, using partial equivalence function
367 pair
<MT_t::waiters_t::iterator
, MT_t::waiters_t::iterator
> chain
=MT
->d_waiters
.equal_range(pident
, PacketIDBirthdayCompare());
369 for(; chain
.first
!= chain
.second
; chain
.first
++) {
370 if(chain
.first
->key
.fd
> -1) { // don't chain onto existing chained waiter!
372 cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
373 cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
374 <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
376 chain
.first
->key
.chain
.insert(id
); // we can chain
377 *fd
=-1; // gets used in waitEvent / sendEvent later on
382 int ret
=t_udpclientsocks
->getSocket(toaddr
, fd
);
389 t_fdm
->addReadFD(*fd
, handleUDPServerResponse
, pident
);
390 ret
= send(*fd
, data
, len
, 0);
395 t_udpclientsocks
->returnSocket(*fd
);
397 errno
= tmp
; // this is for logging purposes only
401 // -1 is error, 0 is timeout, 1 is success
402 int arecvfrom(char *data
, int len
, int flags
, const ComboAddress
& fromaddr
, int *d_len
,
403 uint16_t id
, const string
& domain
, uint16_t qtype
, int fd
, struct timeval
* now
)
405 static optional
<unsigned int> nearMissLimit
;
407 nearMissLimit
=::arg().asNum("spoof-nearmiss-max");
412 pident
.domain
=domain
;
414 pident
.remote
=fromaddr
;
417 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
, now
);
420 if(packet
.empty()) // means "error"
423 *d_len
=(int)packet
.size();
424 memcpy(data
,packet
.c_str(),min(len
,*d_len
));
425 if(*nearMissLimit
&& pident
.nearMisses
> *nearMissLimit
) {
426 L
<<Logger::Error
<<"Too many ("<<pident
.nearMisses
<<" > "<<*nearMissLimit
<<") bogus answers for '"<<domain
<<"' from "<<fromaddr
.toString()<<", assuming spoof attempt."<<endl
;
427 g_stats
.spoofCount
++;
433 t_udpclientsocks
->returnSocket(fd
);
440 static void writePid(void)
442 ofstream
of(s_pidfname
.c_str(), std::ios_base::app
);
444 of
<< Utility::getpid() <<endl
;
446 L
<<Logger::Error
<<"Requested to write pid for "<<Utility::getpid()<<" to "<<s_pidfname
<<" failed: "<<strerror(errno
)<<endl
;
449 typedef map
<ComboAddress
, uint32_t, ComboAddress::addressOnlyLessThan
> tcpClientCounts_t
;
450 tcpClientCounts_t __thread
* t_tcpClientCounts
;
452 TCPConnection::TCPConnection(int fd
, const ComboAddress
& addr
) : d_remote(addr
), d_fd(fd
)
454 ++s_currentConnections
;
455 (*t_tcpClientCounts
)[d_remote
]++;
458 TCPConnection::~TCPConnection()
460 if(Utility::closesocket(d_fd
) < 0)
461 unixDie("closing socket for TCPConnection");
462 if(t_tcpClientCounts
->count(d_remote
) && !(*t_tcpClientCounts
)[d_remote
]--)
463 t_tcpClientCounts
->erase(d_remote
);
464 --s_currentConnections
;
467 AtomicCounter
TCPConnection::s_currentConnections
;
468 void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
);
470 void updateRcodeStats(int res
)
473 case RCode::ServFail
:
476 case RCode::NXDomain
:
485 void startDoResolve(void *p
)
487 DNSComboWriter
* dc
=(DNSComboWriter
*)p
;
491 loginfo
=" (while setting loginfo)";
492 loginfo
=" ("+dc
->d_mdp
.d_qname
+"/"+lexical_cast
<string
>(dc
->d_mdp
.d_qtype
)+" from "+(dc
->d_remote
.toString())+")";
493 uint32_t maxanswersize
= dc
->d_tcp
? 65535 : 512;
495 if(getEDNSOpts(dc
->d_mdp
, &edo
)) {
496 maxanswersize
= min(edo
.d_packetsize
, (uint16_t) (dc
->d_tcp
? 65535 : 1680));
499 vector
<DNSResourceRecord
> ret
;
500 vector
<uint8_t> packet
;
502 DNSPacketWriter
pw(packet
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
);
504 pw
.getHeader()->aa
=0;
505 pw
.getHeader()->ra
=1;
506 pw
.getHeader()->qr
=1;
507 pw
.getHeader()->tc
=0;
508 pw
.getHeader()->id
=dc
->d_mdp
.d_header
.id
;
509 pw
.getHeader()->rd
=dc
->d_mdp
.d_header
.rd
;
511 SyncRes
sr(dc
->d_now
);
512 bool tracedQuery
=false; // we could consider letting Lua know about this too
513 if(t_traceRegex
->get() && (*t_traceRegex
)->match(dc
->d_mdp
.d_qname
)) {
514 sr
.setLogMode(SyncRes::Store
);
518 if(!g_quiet
|| tracedQuery
)
519 L
<<Logger::Warning
<<t_id
<<" ["<<MT
->getTid()<<"] " << (dc
->d_tcp
? "TCP " : "") << "question for '"<<dc
->d_mdp
.d_qname
<<"|"
520 <<DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)<<"' from "<<dc
->getRemote()<<endl
;
522 sr
.setId(MT
->getTid());
523 if(!dc
->d_mdp
.d_header
.rd
)
528 bool variableAnswer
= false;
529 // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
530 if(!t_pdl
->get() || !(*t_pdl
)->preresolve(dc
->d_remote
, g_listenSocketsAddresses
[dc
->d_socket
], dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), ret
, res
, &variableAnswer
)) {
531 res
= sr
.beginResolve(dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), dc
->d_mdp
.d_qclass
, ret
);
534 if(res
== RCode::NoError
) {
535 vector
<DNSResourceRecord
>::const_iterator i
;
536 for(i
=ret
.begin(); i
!=ret
.end(); ++i
)
537 if(i
->qtype
.getCode() == dc
->d_mdp
.d_qtype
&& i
->d_place
== DNSResourceRecord::ANSWER
)
540 (*t_pdl
)->nodata(dc
->d_remote
, g_listenSocketsAddresses
[dc
->d_socket
], dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), ret
, res
, &variableAnswer
);
542 else if(res
== RCode::NXDomain
)
543 (*t_pdl
)->nxdomain(dc
->d_remote
, g_listenSocketsAddresses
[dc
->d_socket
], dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), ret
, res
, &variableAnswer
);
545 (*t_pdl
)->postresolve(dc
->d_remote
, g_listenSocketsAddresses
[dc
->d_socket
], dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), ret
, res
, &variableAnswer
);
549 uint32_t minTTL
=std::numeric_limits
<uint32_t>::max();
551 if(tracedQuery
|| res
< 0 || res
== RCode::ServFail
|| pw
.getHeader()->rcode
== RCode::ServFail
)
553 string
trace(sr
.getTrace());
555 vector
<string
> lines
;
556 boost::split(lines
, trace
, boost::is_any_of("\n"));
557 BOOST_FOREACH(const string
& line
, lines
) {
559 L
<<Logger::Warning
<< line
<< endl
;
565 pw
.getHeader()->rcode
=RCode::ServFail
;
566 // no commit here, because no record
570 pw
.getHeader()->rcode
=res
;
571 updateRcodeStats(res
);
574 orderAndShuffle(ret
);
576 for(vector
<DNSResourceRecord
>::const_iterator i
=ret
.begin(); i
!=ret
.end(); ++i
) {
577 pw
.startRecord(i
->qname
, i
->qtype
.getCode(), i
->ttl
, i
->qclass
, (DNSPacketWriter::Place
)i
->d_place
);
578 minTTL
= min(minTTL
, i
->ttl
);
579 if(i
->qtype
.getCode() == QType::A
) { // blast out A record w/o doing whole dnswriter thing
581 IpToU32(i
->content
, &ip
);
582 pw
.xfr32BitInt(htonl(ip
));
584 shared_ptr
<DNSRecordContent
> drc(DNSRecordContent::mastermake(i
->qtype
.getCode(), i
->qclass
, i
->content
));
587 if(pw
.size() > maxanswersize
) {
589 if(i
->d_place
==DNSResourceRecord::ANSWER
) // only truncate if we actually omitted parts of the answer
590 pw
.getHeader()->tc
=1;
591 goto sendit
; // need to jump over pw.commit
600 sendto(dc
->d_socket
, (const char*)&*packet
.begin(), packet
.size(), 0, (struct sockaddr
*)(&dc
->d_remote
), dc
->d_remote
.getSocklen());
601 if(!SyncRes::s_nopacketcache
&& !variableAnswer
) {
602 t_packetCache
->insertResponsePacket(string((const char*)&*packet
.begin(), packet
.size()), g_now
.tv_sec
,
604 (pw
.getHeader()->rcode
== RCode::ServFail
) ? SyncRes::s_packetcacheservfailttl
: SyncRes::s_packetcachettl
611 buf
[0]=packet
.size()/256;
612 buf
[1]=packet
.size()%256;
614 Utility::iovec iov
[2];
616 iov
[0].iov_base
=(void*)buf
; iov
[0].iov_len
=2;
617 iov
[1].iov_base
=(void*)&*packet
.begin(); iov
[1].iov_len
= packet
.size();
619 int ret
=Utility::writev(dc
->d_socket
, iov
, 2);
623 L
<<Logger::Error
<<"EOF writing TCP answer to "<<dc
->getRemote()<<endl
;
625 L
<<Logger::Error
<<"Error writing TCP answer to "<<dc
->getRemote()<<": "<< strerror(errno
) <<endl
;
626 else if((unsigned int)ret
!= 2 + packet
.size())
627 L
<<Logger::Error
<<"Oops, partial answer sent to "<<dc
->getRemote()<<" for "<<dc
->d_mdp
.d_qname
<<" (size="<< (2 + packet
.size()) <<", sent "<<ret
<<")"<<endl
;
631 // update tcp connection status, either by closing or moving to 'BYTE0'
634 // no need to remove us from FDM, we weren't there
638 dc
->d_tcpConnection
->state
=TCPConnection::BYTE0
;
639 Utility::gettimeofday(&g_now
, 0); // needs to be updated
640 t_fdm
->addReadFD(dc
->d_socket
, handleRunningTCPQuestion
, dc
->d_tcpConnection
);
641 t_fdm
->setReadTTD(dc
->d_socket
, g_now
, g_tcpTimeout
);
646 L
<<Logger::Error
<<t_id
<<" ["<<MT
->getTid()<<"] answer to "<<(dc
->d_mdp
.d_header
.rd
?"":"non-rd ")<<"question '"<<dc
->d_mdp
.d_qname
<<"|"<<DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
);
647 L
<<"': "<<ntohs(pw
.getHeader()->ancount
)<<" answers, "<<ntohs(pw
.getHeader()->arcount
)<<" additional, took "<<sr
.d_outqueries
<<" packets, "<<
648 sr
.d_throttledqueries
<<" throttled, "<<sr
.d_timeouts
<<" timeouts, "<<sr
.d_tcpoutqueries
<<" tcp connections, rcode="<<res
<<endl
;
651 sr
.d_outqueries
? t_RC
->cacheMisses
++ : t_RC
->cacheHits
++;
652 float spent
=makeFloat(sr
.d_now
-dc
->d_now
);
654 g_stats
.answers0_1
++;
655 else if(spent
< 0.010)
656 g_stats
.answers1_10
++;
658 g_stats
.answers10_100
++;
660 g_stats
.answers100_1000
++;
662 g_stats
.answersSlow
++;
664 uint64_t newLat
=(uint64_t)(spent
*1000000);
665 if(newLat
< 1000000) // outliers of several minutes exist..
666 g_stats
.avgLatencyUsec
=(uint64_t)((1-0.0001)*g_stats
.avgLatencyUsec
+ 0.0001*newLat
);
671 catch(PDNSException
&ae
) {
672 L
<<Logger::Error
<<"startDoResolve problem"<<loginfo
<<": "<<ae
.reason
<<endl
;
675 catch(MOADNSException
& e
) {
676 L
<<Logger::Error
<<"DNS parser error"<<loginfo
<<": "<<dc
->d_mdp
.d_qname
<<", "<<e
.what()<<endl
;
679 catch(std::exception
& e
) {
680 L
<<Logger::Error
<<"STL error"<<loginfo
<<": "<<e
.what()<<endl
;
684 L
<<Logger::Error
<<"Any other exception in a resolver context"<<loginfo
<<endl
;
687 g_stats
.maxMThreadStackUsage
= max(MT
->getMaxStackUsage(), g_stats
.maxMThreadStackUsage
);
690 void makeControlChannelSocket(int processNum
=-1)
692 string sockname
=::arg()["socket-dir"]+"/pdns_"+s_programname
;
694 sockname
+= "."+lexical_cast
<string
>(processNum
);
695 sockname
+=".controlsocket";
696 s_rcc
.listen(sockname
);
701 if (!::arg().isEmpty("socket-group"))
702 sockgroup
=::arg().asGid("socket-group");
703 if (!::arg().isEmpty("socket-owner"))
704 sockowner
=::arg().asUid("socket-owner");
706 if (sockgroup
> -1 || sockowner
> -1) {
707 if(chown(sockname
.c_str(), sockowner
, sockgroup
) < 0) {
708 unixDie("Failed to chown control socket");
712 // do mode change if socket-mode is given
713 if(!::arg().isEmpty("socket-mode")) {
714 mode_t sockmode
=::arg().asMode("socket-mode");
715 chmod(sockname
.c_str(), sockmode
);
719 void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
721 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(var
);
723 if(conn
->state
==TCPConnection::BYTE0
) {
724 int bytes
=recv(conn
->getFD(), conn
->data
, 2, 0);
726 conn
->state
=TCPConnection::BYTE1
;
728 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
730 conn
->state
=TCPConnection::GETQUESTION
;
732 if(!bytes
|| bytes
< 0) {
733 t_fdm
->removeReadFD(fd
);
737 else if(conn
->state
==TCPConnection::BYTE1
) {
738 int bytes
=recv(conn
->getFD(), conn
->data
+1, 1, 0);
740 conn
->state
=TCPConnection::GETQUESTION
;
741 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
744 if(!bytes
|| bytes
< 0) {
745 if(g_logCommonErrors
)
746 L
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toString() <<" disconnected after first byte"<<endl
;
747 t_fdm
->removeReadFD(fd
);
751 else if(conn
->state
==TCPConnection::GETQUESTION
) {
752 int bytes
=recv(conn
->getFD(), conn
->data
+ conn
->bytesread
, conn
->qlen
- conn
->bytesread
, 0);
753 if(!bytes
|| bytes
< 0) {
754 L
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toString() <<" disconnected while reading question body"<<endl
;
755 t_fdm
->removeReadFD(fd
);
758 conn
->bytesread
+=bytes
;
759 if(conn
->bytesread
==conn
->qlen
) {
760 t_fdm
->removeReadFD(fd
); // should no longer awake ourselves when there is data to read
762 DNSComboWriter
* dc
=0;
764 dc
=new DNSComboWriter(conn
->data
, conn
->qlen
, g_now
);
766 catch(MOADNSException
&mde
) {
767 g_stats
.clientParseError
++;
768 if(g_logCommonErrors
)
769 L
<<Logger::Error
<<"Unable to parse packet from TCP client "<< conn
->d_remote
.toString() <<endl
;
772 dc
->d_tcpConnection
= conn
; // carry the torch
773 dc
->setSocket(conn
->getFD()); // this is the only time a copy is made of the actual fd
775 dc
->setRemote(&conn
->d_remote
);
776 if(dc
->d_mdp
.d_header
.qr
) {
778 L
<<Logger::Error
<<"Ignoring answer on server socket!"<<endl
;
781 if(dc
->d_mdp
.d_header
.opcode
) {
783 L
<<Logger::Error
<<"Ignoring non-query opcode on server socket!"<<endl
;
788 ++g_stats
.tcpqcounter
;
789 MT
->makeThread(startDoResolve
, dc
); // deletes dc, will set state to BYTE0 again
796 //! Handle new incoming TCP connection
797 void handleNewTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& )
800 socklen_t addrlen
=sizeof(addr
);
801 int newsock
=(int)accept(fd
, (struct sockaddr
*)&addr
, &addrlen
);
803 if(MT
->numProcesses() > g_maxMThreads
) {
804 g_stats
.overCapacityDrops
++;
805 Utility::closesocket(newsock
);
809 t_remotes
->addRemote(addr
);
810 if(t_allowFrom
&& !t_allowFrom
->match(&addr
)) {
812 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping TCP query from "<<addr
.toString()<<", address not matched by allow-from"<<endl
;
814 g_stats
.unauthorizedTCP
++;
815 Utility::closesocket(newsock
);
818 if(g_maxTCPPerClient
&& t_tcpClientCounts
->count(addr
) && (*t_tcpClientCounts
)[addr
] >= g_maxTCPPerClient
) {
819 g_stats
.tcpClientOverflow
++;
820 Utility::closesocket(newsock
); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
824 Utility::setNonBlocking(newsock
);
825 shared_ptr
<TCPConnection
> tc(new TCPConnection(newsock
, addr
));
826 tc
->state
=TCPConnection::BYTE0
;
828 t_fdm
->addReadFD(tc
->getFD(), handleRunningTCPQuestion
, tc
);
831 Utility::gettimeofday(&now
, 0);
832 t_fdm
->setReadTTD(tc
->getFD(), now
, g_tcpTimeout
);
836 string
* doProcessUDPQuestion(const std::string
& question
, const ComboAddress
& fromaddr
, int fd
)
839 if(fromaddr
.sin4
.sin_family
==AF_INET6
)
840 g_stats
.ipv6qcounter
++;
845 if(!SyncRes::s_nopacketcache
&& t_packetCache
->getResponsePacket(question
, g_now
.tv_sec
, &response
, &age
)) {
847 L
<<Logger::Error
<<t_id
<< " question answered from packet cache from "<<fromaddr
.toString()<<endl
;
849 g_stats
.packetCacheHits
++;
850 SyncRes::s_queries
++;
851 ageDNSPacket(response
, age
);
852 sendto(fd
, response
.c_str(), response
.length(), 0, (struct sockaddr
*) &fromaddr
, fromaddr
.getSocklen());
853 if(response
.length() >= sizeof(struct dnsheader
)) {
855 memcpy(&dh
, response
.c_str(), sizeof(dh
));
856 updateRcodeStats(dh
.rcode
);
858 g_stats
.avgLatencyUsec
=(uint64_t)((1-0.0001)*g_stats
.avgLatencyUsec
+ 0); // we assume 0 usec
862 catch(std::exception
& e
) {
863 L
<<Logger::Error
<<"Error processing or aging answer packet: "<<e
.what()<<endl
;
868 if(MT
->numProcesses() > g_maxMThreads
) {
869 g_stats
.overCapacityDrops
++;
873 DNSComboWriter
* dc
= new DNSComboWriter(question
.c_str(), question
.size(), g_now
);
875 dc
->setRemote(&fromaddr
);
878 MT
->makeThread(startDoResolve
, (void*) dc
); // deletes dc
882 void handleNewUDPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
886 ComboAddress fromaddr
;
887 socklen_t addrlen
=sizeof(fromaddr
);
889 if((len
=recvfrom(fd
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
)) >= 0) {
890 t_remotes
->addRemote(fromaddr
);
892 if(t_allowFrom
&& !t_allowFrom
->match(&fromaddr
)) {
894 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toString()<<", address not matched by allow-from"<<endl
;
896 g_stats
.unauthorizedUDP
++;
900 dnsheader
* dh
=(dnsheader
*)data
;
903 if(g_logCommonErrors
)
904 L
<<Logger::Error
<<"Ignoring answer from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
906 else if(dh
->opcode
) {
907 if(g_logCommonErrors
)
908 L
<<Logger::Error
<<"Ignoring non-query opcode "<<dh
->opcode
<<" from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
911 string
question(data
, len
);
912 if(g_weDistributeQueries
)
913 distributeAsyncFunction(boost::bind(doProcessUDPQuestion
, question
, fromaddr
, fd
));
915 doProcessUDPQuestion(question
, fromaddr
, fd
);
918 catch(MOADNSException
& mde
) {
919 g_stats
.clientParseError
++;
920 if(g_logCommonErrors
)
921 L
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<mde
.what()<<endl
;
925 // cerr<<t_id<<" had error: "<<stringerror()<<endl;
927 g_stats
.noPacketError
++;
932 typedef vector
<pair
<int, function
< void(int, any
&) > > > deferredAdd_t
;
933 deferredAdd_t deferredAdd
;
935 void makeTCPServerSockets()
938 vector
<string
>locals
;
939 stringtok(locals
,::arg()["local-address"]," ,");
942 throw PDNSException("No local address specified");
944 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
946 st
.port
=::arg().asNum("local-port");
947 parseService(*i
, st
);
951 memset((char *)&sin
,0, sizeof(sin
));
952 sin
.sin4
.sin_family
= AF_INET
;
953 if(!IpToU32(st
.host
, (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
954 sin
.sin6
.sin6_family
= AF_INET6
;
955 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
956 throw PDNSException("Unable to resolve local address for TCP server on '"+ st
.host
+"'");
959 fd
=socket(sin
.sin6
.sin6_family
, SOCK_STREAM
, 0);
960 Utility::setCloseOnExec(fd
);
963 throw PDNSException("Making a TCP server socket for resolver: "+stringerror());
966 if(setsockopt(fd
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
967 L
<<Logger::Error
<<"Setsockopt failed for TCP listening socket"<<endl
;
971 #ifdef TCP_DEFER_ACCEPT
972 if(setsockopt(fd
, SOL_TCP
,TCP_DEFER_ACCEPT
,(char*)&tmp
,sizeof tmp
) >= 0) {
973 if(i
==locals
.begin())
974 L
<<Logger::Error
<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl
;
978 sin
.sin4
.sin_port
= htons(st
.port
);
979 int socklen
=sin
.sin4
.sin_family
==AF_INET
? sizeof(sin
.sin4
) : sizeof(sin
.sin6
);
980 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
981 throw PDNSException("Binding TCP server socket for "+ st
.host
+": "+stringerror());
983 Utility::setNonBlocking(fd
);
984 setSocketSendBuffer(fd
, 65000);
986 deferredAdd
.push_back(make_pair(fd
, handleNewTCPQuestion
));
987 g_tcpListenSockets
.push_back(fd
);
989 if(sin
.sin4
.sin_family
== AF_INET
)
990 L
<<Logger::Error
<<"Listening for TCP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
992 L
<<Logger::Error
<<"Listening for TCP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
998 void makeUDPServerSockets()
1000 vector
<string
>locals
;
1001 stringtok(locals
,::arg()["local-address"]," ,");
1004 throw PDNSException("No local address specified");
1006 if(::arg()["local-address"]=="0.0.0.0") {
1007 L
<<Logger::Warning
<<"It is advised to bind to explicit addresses with the --local-address option"<<endl
;
1010 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
1012 st
.port
=::arg().asNum("local-port");
1013 parseService(*i
, st
);
1017 memset(&sin
, 0, sizeof(sin
));
1018 sin
.sin4
.sin_family
= AF_INET
;
1019 if(!IpToU32(st
.host
.c_str() , (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
1020 sin
.sin6
.sin6_family
= AF_INET6
;
1021 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
1022 throw PDNSException("Unable to resolve local address for UDP server on '"+ st
.host
+"'");
1025 int fd
=socket(sin
.sin4
.sin_family
, SOCK_DGRAM
, 0);
1026 Utility::setCloseOnExec(fd
);
1029 throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
1032 setSocketReceiveBuffer(fd
, 200000);
1033 sin
.sin4
.sin_port
= htons(st
.port
);
1035 int socklen
=sin
.sin4
.sin_family
==AF_INET
? sizeof(sin
.sin4
) : sizeof(sin
.sin6
);
1036 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
1037 throw PDNSException("Resolver binding to server socket on port "+ lexical_cast
<string
>(st
.port
) +" for "+ st
.host
+": "+stringerror());
1039 Utility::setNonBlocking(fd
);
1041 deferredAdd
.push_back(make_pair(fd
, handleNewUDPQuestion
));
1042 g_listenSocketsAddresses
[fd
]=sin
; // this is written to only from the startup thread, not from the workers
1043 if(sin
.sin4
.sin_family
== AF_INET
)
1044 L
<<Logger::Error
<<"Listening for UDP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
1046 L
<<Logger::Error
<<"Listening for UDP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
1051 void daemonize(void)
1058 int i
=open("/dev/null",O_RDWR
); /* open stdin */
1060 L
<<Logger::Critical
<<"Unable to open /dev/null: "<<stringerror()<<endl
;
1062 dup2(i
,0); /* stdin */
1063 dup2(i
,1); /* stderr */
1064 dup2(i
,2); /* stderr */
1072 void usr1Handler(int)
1077 void usr2Handler(int)
1079 SyncRes::setDefaultLogMode(SyncRes::Log
);
1081 ::arg().set("quiet")="no";
1087 static time_t lastOutputTime
;
1088 static uint64_t lastQueryCount
;
1090 if(g_stats
.qcounter
&& (t_RC
->cacheHits
+ t_RC
->cacheMisses
) && SyncRes::s_queries
&& SyncRes::s_outqueries
) { // this only runs once thread 0 has had hits
1091 uint64_t cacheHits
= broadcastAccFunction
<uint64_t>(pleaseGetCacheHits
);
1092 uint64_t cacheMisses
= broadcastAccFunction
<uint64_t>(pleaseGetCacheMisses
);
1094 L
<<Logger::Warning
<<"stats: "<<g_stats
.qcounter
<<" questions, "<<
1095 broadcastAccFunction
<uint64_t>(pleaseGetCacheSize
)<< " cache entries, "<<
1096 broadcastAccFunction
<uint64_t>(pleaseGetNegCacheSize
)<<" negative entries, "<<
1097 (int)((cacheHits
*100.0)/(cacheHits
+cacheMisses
))<<"% cache hits"<<endl
;
1099 L
<<Logger::Warning
<<"stats: throttle map: "
1100 << broadcastAccFunction
<uint64_t>(pleaseGetThrottleSize
) <<", ns speeds: "
1101 << broadcastAccFunction
<uint64_t>(pleaseGetNsSpeedsSize
)<<endl
;
1102 L
<<Logger::Warning
<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries
*100.0/SyncRes::s_queries
)<<"%";
1103 L
<<Logger::Warning
<<", "<<(int)(SyncRes::s_throttledqueries
*100.0/(SyncRes::s_outqueries
+SyncRes::s_throttledqueries
))<<"% throttled, "
1104 <<SyncRes::s_nodelegated
<<" no-delegation drops"<<endl
;
1105 L
<<Logger::Warning
<<"stats: "<<SyncRes::s_tcpoutqueries
<<" outgoing tcp connections, "<<
1106 broadcastAccFunction
<uint64_t>(pleaseGetConcurrentQueries
)<<" queries running, "<<SyncRes::s_outgoingtimeouts
<<" outgoing timeouts"<<endl
;
1108 //L<<Logger::Warning<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
1109 //g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
1111 L
<<Logger::Warning
<<"stats: " << broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheSize
) <<
1112 " packet cache entries, "<<(int)(100.0*broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheHits
)/SyncRes::s_queries
) << "% packet cache hits"<<endl
;
1114 time_t now
= time(0);
1115 if(lastOutputTime
&& lastQueryCount
&& now
!= lastOutputTime
) {
1116 L
<<Logger::Warning
<<"stats: "<< (SyncRes::s_queries
- lastQueryCount
) / (now
- lastOutputTime
) <<" qps (average over "<< (now
- lastOutputTime
) << " seconds)"<<endl
;
1118 lastOutputTime
= now
;
1119 lastQueryCount
= SyncRes::s_queries
;
1121 else if(statsWanted
)
1122 L
<<Logger::Warning
<<"stats: no stats yet!"<<endl
;
1127 static void houseKeeping(void *)
1130 static __thread
time_t last_stat
, last_rootupdate
, last_prune
;
1131 static __thread
int cleanCounter
=0;
1133 Utility::gettimeofday(&now
, 0);
1135 // clog<<"* "<<t_id<<" "<<(void*)&last_stat<<"\t"<<(unsigned int)last_stat<<endl;
1137 if(now
.tv_sec
- last_prune
> (time_t)(5 + t_id
)) {
1140 t_RC
->doPrune(); // this function is local to a thread, so fine anyhow
1141 t_packetCache
->doPruneTo(::arg().asNum("max-packetcache-entries") / g_numThreads
);
1143 pruneCollection(t_sstorage
->negcache
, ::arg().asNum("max-cache-entries") / (g_numThreads
* 10), 200);
1145 if(!((cleanCounter
++)%40)) { // this is a full scan!
1146 time_t limit
=now
.tv_sec
-300;
1147 for(SyncRes::nsspeeds_t::iterator i
= t_sstorage
->nsSpeeds
.begin() ; i
!= t_sstorage
->nsSpeeds
.end(); )
1148 if(i
->second
.stale(limit
))
1149 t_sstorage
->nsSpeeds
.erase(i
++);
1153 // L<<Logger::Warning<<"Spent "<<dt.udiff()/1000<<" msec cleaning"<<endl;
1158 if(now
.tv_sec
- last_stat
> 1800) {
1164 if(now
.tv_sec
- last_rootupdate
> 7200) {
1166 sr
.setDoEDNS0(true);
1167 vector
<DNSResourceRecord
> ret
;
1170 int res
=sr
.beginResolve(".", QType(QType::NS
), 1, ret
);
1172 L
<<Logger::Warning
<<"Refreshed . records"<<endl
;
1173 last_rootupdate
=now
.tv_sec
;
1176 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;
1179 catch(PDNSException
& ae
)
1181 L
<<Logger::Error
<<"Fatal error: "<<ae
.reason
<<endl
;
1186 void makeThreadPipes()
1188 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
1189 struct ThreadPipeSet tps
;
1192 unixDie("Creating pipe for inter-thread communications");
1194 tps
.readToThread
= fd
[0];
1195 tps
.writeToThread
= fd
[1];
1198 unixDie("Creating pipe for inter-thread communications");
1199 tps
.readFromThread
= fd
[0];
1200 tps
.writeFromThread
= fd
[1];
1202 g_pipes
.push_back(tps
);
1212 void broadcastFunction(const pipefunc_t
& func
, bool skipSelf
)
1215 BOOST_FOREACH(ThreadPipeSet
& tps
, g_pipes
)
1219 func(); // don't write to ourselves!
1223 ThreadMSG
* tmsg
= new ThreadMSG();
1225 tmsg
->wantAnswer
= true;
1226 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
))
1227 unixDie("write to thread pipe returned wrong size or error");
1230 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
1231 unixDie("read from thread pipe returned wrong size or error");
1234 // cerr <<"got response: " << *resp << endl;
1239 void distributeAsyncFunction(const pipefunc_t
& func
)
1241 static unsigned int counter
;
1242 unsigned int target
= 1 + (++counter
% (g_pipes
.size()-1));
1243 // cerr<<"Sending to: "<<target<<endl;
1244 if(target
== t_id
) {
1248 ThreadPipeSet
& tps
= g_pipes
[target
];
1249 ThreadMSG
* tmsg
= new ThreadMSG();
1251 tmsg
->wantAnswer
= false;
1253 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
))
1254 unixDie("write to thread pipe returned wrong size or error");
1258 void handlePipeRequest(int fd
, FDMultiplexer::funcparam_t
& var
)
1262 if(read(fd
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) { // fd == readToThread
1263 unixDie("read from thread pipe returned wrong size or error");
1266 void *resp
= tmsg
->func();
1267 if(tmsg
->wantAnswer
)
1268 if(write(g_pipes
[t_id
].writeFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
1269 unixDie("write to thread pipe returned wrong size or error");
1274 template<class T
> void *voider(const boost::function
<T
*()>& func
)
1279 vector
<ComboAddress
>& operator+=(vector
<ComboAddress
>&a
, const vector
<ComboAddress
>& b
)
1281 a
.insert(a
.end(), b
.begin(), b
.end());
1285 template<class T
> T
broadcastAccFunction(const boost::function
<T
*()>& func
, bool skipSelf
)
1289 BOOST_FOREACH(ThreadPipeSet
& tps
, g_pipes
)
1293 T
* resp
= (T
*)func(); // don't write to ourselves!
1295 //~ cerr <<"got direct: " << *resp << endl;
1303 ThreadMSG
* tmsg
= new ThreadMSG();
1304 tmsg
->func
= boost::bind(voider
<T
>, func
);
1305 tmsg
->wantAnswer
= true;
1307 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
))
1308 unixDie("write to thread pipe returned wrong size or error");
1312 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
1313 unixDie("read from thread pipe returned wrong size or error");
1316 //~ cerr <<"got response: " << *resp << endl;
1324 template string
broadcastAccFunction(const boost::function
<string
*()>& fun
, bool skipSelf
); // explicit instantiation
1325 template uint64_t broadcastAccFunction(const boost::function
<uint64_t*()>& fun
, bool skipSelf
); // explicit instantiation
1326 template vector
<ComboAddress
> broadcastAccFunction(const boost::function
<vector
<ComboAddress
> *()>& fun
, bool skipSelf
); // explicit instantiation
1328 void handleRCC(int fd
, FDMultiplexer::funcparam_t
& var
)
1331 string msg
=s_rcc
.recv(&remote
);
1332 RecursorControlParser rcp
;
1333 RecursorControlParser::func_t
* command
;
1335 string answer
=rcp
.getAnswer(msg
, &command
);
1337 s_rcc
.send(answer
, &remote
);
1340 catch(std::exception
& e
) {
1341 L
<<Logger::Error
<<"Error dealing with control socket request: "<<e
.what()<<endl
;
1343 catch(PDNSException
& ae
) {
1344 L
<<Logger::Error
<<"Error dealing with control socket request: "<<ae
.reason
<<endl
;
1348 void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
)
1350 PacketID
* pident
=any_cast
<PacketID
>(&var
);
1351 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
1353 shared_array
<char> buffer(new char[pident
->inNeeded
]);
1355 int ret
=recv(fd
, buffer
.get(), pident
->inNeeded
,0);
1357 pident
->inMSG
.append(&buffer
[0], &buffer
[ret
]);
1358 pident
->inNeeded
-=ret
;
1359 if(!pident
->inNeeded
) {
1360 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
1361 PacketID pid
=*pident
;
1362 string msg
=pident
->inMSG
;
1364 t_fdm
->removeReadFD(fd
);
1365 MT
->sendEvent(pid
, &msg
);
1368 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
1372 PacketID tmp
=*pident
;
1373 t_fdm
->removeReadFD(fd
); // pident might now be invalid (it isn't, but still)
1375 MT
->sendEvent(tmp
, &empty
); // this conveys error status
1379 void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
)
1381 PacketID
* pid
=any_cast
<PacketID
>(&var
);
1382 int ret
=send(fd
, pid
->outMSG
.c_str() + pid
->outPos
, pid
->outMSG
.size() - pid
->outPos
,0);
1385 if(pid
->outPos
==pid
->outMSG
.size()) {
1387 t_fdm
->removeWriteFD(fd
);
1388 MT
->sendEvent(tmp
, &tmp
.outMSG
); // send back what we sent to convey everything is ok
1391 else { // error or EOF
1393 t_fdm
->removeWriteFD(fd
);
1395 MT
->sendEvent(tmp
, &sent
); // we convey error status by sending empty string
1399 // resend event to everybody chained onto it
1400 void doResends(MT_t::waiters_t::iterator
& iter
, PacketID resend
, const string
& content
)
1402 if(iter
->key
.chain
.empty())
1404 // cerr<<"doResends called!\n";
1405 for(PacketID::chain_t::iterator i
=iter
->key
.chain
.begin(); i
!= iter
->key
.chain
.end() ; ++i
) {
1408 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
1410 MT
->sendEvent(resend
, &content
);
1411 g_stats
.chainResends
++;
1415 void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
1417 PacketID pid
=any_cast
<PacketID
>(var
);
1420 ComboAddress fromaddr
;
1421 socklen_t addrlen
=sizeof(fromaddr
);
1423 len
=recvfrom(fd
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
);
1425 if(len
< (int)sizeof(dnsheader
)) {
1427 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
1429 g_stats
.serverParseError
++;
1430 if(g_logCommonErrors
)
1431 L
<<Logger::Error
<<"Unable to parse packet from remote UDP server "<< fromaddr
.toString() <<
1432 ": packet smaller than DNS header"<<endl
;
1435 t_udpclientsocks
->returnSocket(fd
);
1438 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pid
);
1439 if(iter
!= MT
->d_waiters
.end())
1440 doResends(iter
, pid
, empty
);
1442 MT
->sendEvent(pid
, &empty
); // this denotes error (does lookup again.. at least L1 will be hot)
1447 memcpy(&dh
, data
, sizeof(dh
));
1450 pident
.remote
=fromaddr
;
1455 L
<<Logger::Warning
<<"Not taking data from question on outgoing socket from "<< fromaddr
.toStringWithPort() <<endl
;
1458 if(!dh
.qdcount
|| // UPC, Nominum, very old BIND on FormErr, NSD
1459 !dh
.qr
) { // one weird server
1460 pident
.domain
.clear();
1465 pident
.domain
=questionExpand(data
, len
, pident
.type
); // don't copy this from above - we need to do the actual read
1467 catch(std::exception
& e
) {
1468 g_stats
.serverParseError
++; // won't be fed to lwres.cc, so we have to increment
1469 L
<<Logger::Warning
<<"Error in packet from "<< fromaddr
.toStringWithPort() << ": "<<e
.what() << endl
;
1474 packet
.assign(data
, len
);
1476 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pident
);
1477 if(iter
!= MT
->d_waiters
.end()) {
1478 doResends(iter
, pident
, packet
);
1483 if(!MT
->sendEvent(pident
, &packet
)) {
1484 // 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
1485 for(MT_t::waiters_t::iterator mthread
=MT
->d_waiters
.begin(); mthread
!=MT
->d_waiters
.end(); ++mthread
) {
1486 if(pident
.fd
==mthread
->key
.fd
&& mthread
->key
.remote
==pident
.remote
&& mthread
->key
.type
== pident
.type
&&
1487 pdns_iequals(pident
.domain
, mthread
->key
.domain
)) {
1488 mthread
->key
.nearMisses
++;
1491 // be a bit paranoid here since we're weakening our matching
1492 if(pident
.domain
.empty() && !mthread
->key
.domain
.empty() && !pident
.type
&& mthread
->key
.type
&&
1493 pident
.id
== mthread
->key
.id
&& mthread
->key
.remote
== pident
.remote
) {
1494 // cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
1495 pident
.domain
= mthread
->key
.domain
;
1496 pident
.type
= mthread
->key
.type
;
1497 goto retryWithName
; // note that this only passes on an error, lwres will still reject the packet
1500 g_stats
.unexpectedCount
++; // if we made it here, it really is an unexpected answer
1501 if(g_logCommonErrors
) {
1502 L
<<Logger::Warning
<<"Discarding unexpected packet from "<<fromaddr
.toStringWithPort()<<": "<<pident
.domain
<<", "<<pident
.type
<<", "<<MT
->d_waiters
.size()<<" waiters"<<endl
;
1506 t_udpclientsocks
->returnSocket(fd
);
1510 FDMultiplexer
* getMultiplexer()
1513 for(FDMultiplexer::FDMultiplexermap_t::const_iterator i
= FDMultiplexer::getMultiplexerMap().begin();
1514 i
!= FDMultiplexer::getMultiplexerMap().end(); ++i
) {
1519 catch(FDMultiplexerException
&fe
) {
1520 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer ("<<fe
.what()<<"), falling back"<<endl
;
1523 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer"<<endl
;
1526 L
<<Logger::Error
<<"No working multiplexer found!"<<endl
;
1531 string
* doReloadLuaScript()
1533 string fname
= ::arg()["lua-dns-script"];
1537 L
<<Logger::Error
<<t_id
<<" Unloaded current lua script"<<endl
;
1538 return new string("unloaded\n");
1541 *t_pdl
= shared_ptr
<RecursorLua
>(new RecursorLua(fname
));
1544 catch(std::exception
& e
) {
1545 L
<<Logger::Error
<<t_id
<<" Retaining current script, error from '"<<fname
<<"': "<< e
.what() <<endl
;
1546 return new string("retaining current script, error from '"+fname
+"': "+e
.what()+"\n");
1549 L
<<Logger::Warning
<<t_id
<<" (Re)loaded lua script from '"<<fname
<<"'"<<endl
;
1550 return new string("(re)loaded '"+fname
+"'\n");
1553 string
doQueueReloadLuaScript(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
1556 ::arg().set("lua-dns-script") = *begin
;
1558 return broadcastAccFunction
<string
>(doReloadLuaScript
);
1561 string
* pleaseUseNewTraceRegex(const std::string
& newRegex
)
1564 if(newRegex
.empty()) {
1565 t_traceRegex
->reset();
1566 return new string("unset\n");
1569 (*t_traceRegex
) = shared_ptr
<Regex
>(new Regex(newRegex
));
1570 return new string("ok\n");
1573 catch(PDNSException
& ae
)
1575 return new string(ae
.reason
+"\n");
1578 string
doTraceRegex(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
1580 return broadcastAccFunction
<string
>(boost::bind(pleaseUseNewTraceRegex
, begin
!=end
? *begin
: ""));
1584 void* recursorThread(void*);
1586 void* pleaseSupplantACLs(NetmaskGroup
*ng
)
1597 static bool l_initialized
;
1599 if(l_initialized
) { // only reload configuration file on second call
1600 string configname
=::arg()["config-dir"]+"/recursor.conf";
1601 cleanSlashes(configname
);
1603 if(!::arg().preParseFile(configname
.c_str(), "allow-from-file"))
1604 L
<<Logger::Warning
<<"Unable to re-parse configuration file '"<<configname
<<"'"<<endl
;
1605 ::arg().preParse(g_argc
, g_argv
, "allow-from-file");
1606 ::arg().preParseFile(configname
.c_str(), "allow-from", LOCAL_NETS
);
1607 ::arg().preParse(g_argc
, g_argv
, "allow-from");
1610 NetmaskGroup
* oldAllowFrom
= t_allowFrom
, *allowFrom
=new NetmaskGroup
;
1612 if(!::arg()["allow-from-file"].empty()) {
1614 ifstream
ifs(::arg()["allow-from-file"].c_str());
1617 throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
1620 string::size_type pos
;
1621 while(getline(ifs
,line
)) {
1623 if(pos
!=string::npos
)
1629 allowFrom
->addMask(line
);
1631 L
<<Logger::Warning
<<"Done parsing " << allowFrom
->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl
;
1633 else if(!::arg()["allow-from"].empty()) {
1635 stringtok(ips
, ::arg()["allow-from"], ", ");
1637 L
<<Logger::Warning
<<"Only allowing queries from: ";
1638 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
1639 allowFrom
->addMask(*i
);
1641 L
<<Logger::Warning
<<", ";
1642 L
<<Logger::Warning
<<*i
;
1644 L
<<Logger::Warning
<<endl
;
1647 if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
1648 L
<<Logger::Error
<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl
;
1653 g_initialAllowFrom
= allowFrom
;
1654 broadcastFunction(boost::bind(pleaseSupplantACLs
, allowFrom
));
1655 delete oldAllowFrom
;
1657 l_initialized
= true;
1660 int serviceMain(int argc
, char*argv
[])
1664 L
.setName(s_programname
);
1666 L
.setLoglevel((Logger::Urgency
)(6)); // info and up
1668 if(!::arg()["logging-facility"].empty()) {
1669 int val
=logFacilityToLOG(::arg().asNum("logging-facility") );
1671 theL().setFacility(val
);
1673 L
<<Logger::Error
<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl
;
1676 showProductVersion();
1679 unsigned int maxFDs
, curFDs
;
1680 getFDLimits(curFDs
, maxFDs
);
1682 L
<<Logger::Warning
<<"Only "<<curFDs
<<" file descriptors available (out of: "<<maxFDs
<<"), may not be suitable for high performance"<<endl
;
1685 seedRandom(::arg()["entropy-source"]);
1689 if(!::arg()["dont-query"].empty()) {
1690 g_dontQuery
=new NetmaskGroup
;
1692 stringtok(ips
, ::arg()["dont-query"], ", ");
1693 ips
.push_back("0.0.0.0");
1694 ips
.push_back("::");
1696 L
<<Logger::Warning
<<"Will not send queries to: ";
1697 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
1698 g_dontQuery
->addMask(*i
);
1700 L
<<Logger::Warning
<<", ";
1701 L
<<Logger::Warning
<<*i
;
1703 L
<<Logger::Warning
<<endl
;
1706 g_quiet
=::arg().mustDo("quiet");
1707 g_weDistributeQueries
= ::arg().mustDo("pdns-distributes-queries");
1708 if(g_weDistributeQueries
) {
1709 L
<<Logger::Warning
<<"PowerDNS Recursor itself will distribute queries over threads"<<endl
;
1712 if(::arg()["trace"]=="fail") {
1713 SyncRes::setDefaultLogMode(SyncRes::Store
);
1715 else if(::arg().mustDo("trace")) {
1716 SyncRes::setDefaultLogMode(SyncRes::Log
);
1717 ::arg().set("quiet")="no";
1723 vector
<string
> addrs
;
1724 if(!::arg()["query-local-address6"].empty()) {
1725 SyncRes::s_doIPv6
=true;
1726 L
<<Logger::Warning
<<"Enabling IPv6 transport for outgoing queries"<<endl
;
1728 stringtok(addrs
, ::arg()["query-local-address6"], ", ;");
1729 BOOST_FOREACH(const string
& addr
, addrs
) {
1730 g_localQueryAddresses6
.push_back(ComboAddress(addr
));
1734 L
<<Logger::Warning
<<"NOT using IPv6 for outgoing queries - set 'query-local-address6=::' to enable"<<endl
;
1737 stringtok(addrs
, ::arg()["query-local-address"], ", ;");
1738 BOOST_FOREACH(const string
& addr
, addrs
) {
1739 g_localQueryAddresses4
.push_back(ComboAddress(addr
));
1742 catch(std::exception
& e
) {
1743 L
<<Logger::Error
<<"Assigning local query addresses: "<<e
.what();
1747 SyncRes::s_doAAAAAdditionalProcessing
= ::arg().mustDo("aaaa-additional-processing");
1748 SyncRes::s_doAdditionalProcessing
= ::arg().mustDo("additional-processing") | SyncRes::s_doAAAAAdditionalProcessing
;
1750 SyncRes::s_noEDNSPing
= true; // ::arg().mustDo("disable-edns-ping");
1751 SyncRes::s_noEDNS
= ::arg().mustDo("disable-edns");
1752 if(!SyncRes::s_noEDNS
) {
1753 L
<<Logger::Warning
<<"Running in experimental EDNS mode - may cause problems"<<endl
;
1756 SyncRes::s_nopacketcache
= ::arg().mustDo("disable-packetcache");
1758 SyncRes::s_maxnegttl
=::arg().asNum("max-negative-ttl");
1759 SyncRes::s_maxcachettl
=::arg().asNum("max-cache-ttl");
1760 SyncRes::s_packetcachettl
=::arg().asNum("packetcache-ttl");
1761 SyncRes::s_packetcacheservfailttl
=::arg().asNum("packetcache-servfail-ttl");
1762 SyncRes::s_serverID
=::arg()["server-id"];
1763 if(SyncRes::s_serverID
.empty()) {
1765 gethostname(tmp
, sizeof(tmp
)-1);
1766 SyncRes::s_serverID
=tmp
;
1769 g_networkTimeoutMsec
= ::arg().asNum("network-timeout");
1771 g_initialDomainMap
= parseAuthAndForwards();
1774 g_logCommonErrors
=::arg().mustDo("log-common-errors");
1776 makeUDPServerSockets();
1777 makeTCPServerSockets();
1780 for(forks
= 0; forks
< ::arg().asNum("processes") - 1; ++forks
) {
1781 if(!fork()) // we are child
1785 s_pidfname
=::arg()["socket-dir"]+"/pdns_"+s_programname
+".pid";
1786 if(!s_pidfname
.empty())
1787 unlink(s_pidfname
.c_str()); // remove possible old pid file
1789 if(::arg().mustDo("daemon")) {
1790 L
<<Logger::Warning
<<"Calling daemonize, going to background"<<endl
;
1791 L
.toConsole(Logger::Critical
);
1794 signal(SIGUSR1
,usr1Handler
);
1795 signal(SIGUSR2
,usr2Handler
);
1796 signal(SIGPIPE
,SIG_IGN
);
1798 makeControlChannelSocket( ::arg().asNum("processes") > 1 ? forks
: -1);
1801 if(!::arg()["setgid"].empty())
1802 newgid
=Utility::makeGidNumeric(::arg()["setgid"]);
1804 if(!::arg()["setuid"].empty())
1805 newuid
=Utility::makeUidNumeric(::arg()["setuid"]);
1807 if (!::arg()["chroot"].empty()) {
1808 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
1809 L
<<Logger::Error
<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno
)<<", exiting"<<endl
;
1814 Utility::dropPrivs(newuid
, newgid
);
1815 g_numThreads
= ::arg().asNum("threads") + ::arg().mustDo("pdns-distributes-queries");
1819 g_tcpTimeout
=::arg().asNum("client-tcp-timeout");
1820 g_maxTCPPerClient
=::arg().asNum("max-tcp-per-client");
1821 g_maxMThreads
=::arg().asNum("max-mthreads");
1823 if(g_numThreads
== 1) {
1824 L
<<Logger::Warning
<<"Operating unthreaded"<<endl
;
1829 L
<<Logger::Warning
<<"Launching "<< g_numThreads
<<" threads"<<endl
;
1830 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
1831 pthread_create(&tid
, 0, recursorThread
, (void*)(long)n
);
1836 pthread_join(tid
, &res
);
1841 void* recursorThread(void* ptr
)
1844 t_id
=(int) (long) ptr
;
1845 SyncRes
tmp(g_now
); // make sure it allocates tsstorage before we do anything, like primeHints or so..
1846 t_sstorage
->domainmap
= g_initialDomainMap
;
1847 t_allowFrom
= g_initialAllowFrom
;
1848 t_udpclientsocks
= new UDPClientSocks();
1849 t_tcpClientCounts
= new tcpClientCounts_t();
1852 t_packetCache
= new RecursorPacketCache();
1854 L
<<Logger::Warning
<<"Done priming cache with root hints"<<endl
;
1856 t_pdl
= new shared_ptr
<RecursorLua
>();
1859 if(!::arg()["lua-dns-script"].empty()) {
1860 *t_pdl
= shared_ptr
<RecursorLua
>(new RecursorLua(::arg()["lua-dns-script"]));
1861 L
<<Logger::Warning
<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl
;
1865 catch(std::exception
&e
) {
1866 L
<<Logger::Error
<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e
.what()<<endl
;
1870 t_traceRegex
= new shared_ptr
<Regex
>();
1873 t_remotes
= new RemoteKeeper();
1874 t_remotes
->remotes
.resize(::arg().asNum("remotes-ringbuffer-entries") / g_numThreads
);
1876 if(!t_remotes
->remotes
.empty())
1877 memset(&t_remotes
->remotes
[0], 0, t_remotes
->remotes
.size() * sizeof(RemoteKeeper::remotes_t::value_type
));
1880 MT
=new MTasker
<PacketID
,string
>(::arg().asNum("stack-size"));
1884 t_fdm
=getMultiplexer();
1886 if(::arg().mustDo("experimental-json-interface")) {
1887 L
<<Logger::Warning
<< "Enabling JSON interface" << endl
;
1889 new JWebserver(t_fdm
);
1891 catch(PDNSException
&e
) {
1892 L
<<Logger::Error
<<"Exception: "<<e
.reason
<<endl
;
1896 L
<<Logger::Error
<<"Enabled '"<< t_fdm
->getName() << "' multiplexer"<<endl
;
1899 t_fdm
->addReadFD(g_pipes
[t_id
].readToThread
, handlePipeRequest
);
1901 if(!g_weDistributeQueries
|| !t_id
) // if we distribute queries, only t_id = 0 listens
1902 for(deferredAdd_t::const_iterator i
=deferredAdd
.begin(); i
!=deferredAdd
.end(); ++i
)
1903 t_fdm
->addReadFD(i
->first
, i
->second
);
1906 t_fdm
->addReadFD(s_rcc
.d_fd
, handleRCC
); // control channel
1909 unsigned int maxTcpClients
=::arg().asNum("max-tcp-clients");
1911 bool listenOnTCP(true);
1913 counter
=0; // used to periodically execute certain tasks
1915 while(MT
->schedule(&g_now
)); // MTasker letting the mthreads do their thing
1917 if(!(counter
%500)) {
1918 MT
->makeThread(houseKeeping
, 0);
1922 typedef vector
<pair
<int, FDMultiplexer::funcparam_t
> > expired_t
;
1923 expired_t expired
=t_fdm
->getTimeouts(g_now
);
1925 for(expired_t::iterator i
=expired
.begin() ; i
!= expired
.end(); ++i
) {
1926 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(i
->second
);
1927 if(g_logCommonErrors
)
1928 L
<<Logger::Warning
<<"Timeout from remote TCP client "<< conn
->d_remote
.toString() <<endl
;
1929 t_fdm
->removeReadFD(i
->first
);
1935 if(!t_id
&& statsWanted
) {
1939 Utility::gettimeofday(&g_now
, 0);
1941 // 'run' updates g_now for us
1944 if(TCPConnection::getCurrentConnections() > maxTcpClients
) { // shutdown, too many connections
1945 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
1946 t_fdm
->removeReadFD(*i
);
1951 if(TCPConnection::getCurrentConnections() <= maxTcpClients
) { // reenable
1952 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
1953 t_fdm
->addReadFD(*i
, handleNewTCPQuestion
);
1959 catch(PDNSException
&ae
) {
1960 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
1963 catch(std::exception
&e
) {
1964 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
1968 L
<<Logger::Error
<<"any other exception in main: "<<endl
;
1973 int main(int argc
, char **argv
)
1977 g_stats
.startupTime
=time(0);
1978 versionSetProduct("Recursor");
1982 int ret
= EXIT_SUCCESS
;
1985 ::arg().set("stack-size","stack size per mthread")="200000";
1986 ::arg().set("soa-minimum-ttl","Don't change")="0";
1987 ::arg().set("soa-serial-offset","Don't change")="0";
1988 ::arg().set("no-shuffle","Don't change")="off";
1989 ::arg().set("additional-processing","turn on to do additional processing")="off";
1990 ::arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off";
1991 ::arg().set("local-port","port to listen on")="53";
1992 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
1993 ::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
1994 ::arg().set("daemon","Operate as a daemon")="yes";
1995 ::arg().set("log-common-errors","If we should log rather common errors")="yes";
1996 ::arg().set("chroot","switch to chroot jail")="";
1997 ::arg().set("setgid","If set, change group id to this gid for more security")="";
1998 ::arg().set("setuid","If set, change user id to this uid for more security")="";
1999 ::arg().set("network-timeout", "Wait this nummer of milliseconds for network i/o")="1500";
2000 ::arg().set("threads", "Launch this number of threads")="2";
2001 ::arg().set("processes", "Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)")="1";
2002 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
2003 ::arg().set( "experimental-logfile", "Filename of the log file for JSON parser" )= "/var/log/pdns.log";
2004 ::arg().setSwitch( "experimental-json-interface", "If we should run a JSON webserver") = "no";
2005 ::arg().set("quiet","Suppress logging of questions and answers")="";
2006 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
2007 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR
;
2008 ::arg().set("socket-owner","Owner of socket")="";
2009 ::arg().set("socket-group","Group of socket")="";
2010 ::arg().set("socket-mode", "Permissions for socket")="";
2012 ::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR
;
2013 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
2014 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
2015 ::arg().set("query-local-address6","Source IPv6 address for sending queries. IF UNSET, IPv6 WILL NOT BE USED FOR OUTGOING QUERIES")="";
2016 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
2017 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
2018 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
2019 ::arg().set("hint-file", "If set, load root hints from this file")="";
2020 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
2021 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
2022 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
2023 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
2024 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000";
2025 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
2026 ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")="";
2027 ::arg().set("remotes-ringbuffer-entries", "maximum number of packets to store statistics for")="0";
2028 ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString();
2029 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS
;
2030 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
2031 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
2032 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=LOCAL_NETS
;
2033 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
2034 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
2035 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
2036 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
2037 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
2038 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
2039 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")="";
2040 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
2041 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")="";
2042 ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
2043 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="";
2044 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
2045 // ::arg().setSwitch( "disable-edns-ping", "Disable EDNSPing - EXPERIMENTAL, LEAVE DISABLED" )= "no";
2046 ::arg().setSwitch( "disable-edns", "Disable EDNS - EXPERIMENTAL, LEAVE DISABLED" )= "";
2047 ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
2048 ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads (EXPERIMENTAL)")="no";
2049 ::arg().set("include-dir","Include *.conf files from this directory")="";
2051 ::arg().setCmd("help","Provide a helpful message");
2052 ::arg().setCmd("version","Print version string");
2053 ::arg().setCmd("config","Output blank configuration");
2054 L
.toConsole(Logger::Info
);
2055 ::arg().laxParse(argc
,argv
); // do a lax parse
2057 if(::arg()["config-name"]!="")
2058 s_programname
+="-"+::arg()["config-name"];
2061 if(::arg().mustDo("config")) {
2062 cout
<<::arg().configstring()<<endl
;
2067 string configname
=::arg()["config-dir"]+"/"+s_programname
+".conf";
2068 cleanSlashes(configname
);
2070 if(!::arg().file(configname
.c_str()))
2071 L
<<Logger::Warning
<<"Unable to parse configuration file '"<<configname
<<"'"<<endl
;
2073 ::arg().parse(argc
,argv
);
2075 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
2077 if(::arg().mustDo("help")) {
2078 cerr
<<"syntax:"<<endl
<<endl
;
2079 cerr
<<::arg().helpstring(::arg()["help"])<<endl
;
2082 if(::arg().mustDo("version")) {
2083 showProductVersion();
2084 showBuildConfiguration();
2088 serviceMain(argc
, argv
);
2090 catch(PDNSException
&ae
) {
2091 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
2094 catch(std::exception
&e
) {
2095 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
2099 L
<<Logger::Error
<<"any other exception in main: "<<endl
;