2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2003 - 2007 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
23 #include "ntservice.hh"
24 #include "recursorservice.hh"
32 #include "recursor_cache.hh"
39 #include "arguments.hh"
44 #include <boost/tuple/tuple.hpp>
45 #include <boost/tuple/tuple_comparison.hpp>
46 #include <boost/shared_array.hpp>
47 #include <boost/lexical_cast.hpp>
48 #include <boost/function.hpp>
49 #include <boost/algorithm/string.hpp>
50 #include "dnsparser.hh"
51 #include "dnswriter.hh"
52 #include "dnsrecords.hh"
53 #include "zoneparser-tng.hh"
54 #include "rec_channel.hh"
66 unsigned int g_maxTCPPerClient
;
67 bool g_logCommonErrors
;
68 using namespace boost
;
70 #ifdef __FreeBSD__ // see cvstrac ticket #26
72 #include <semaphore.h>
76 RecursorStats g_stats
;
78 NetmaskGroup
* g_allowFrom
;
79 NetmaskGroup
* g_dontQuery
;
80 string s_programname
="pdns_recursor";
81 typedef vector
<int> g_tcpListenSockets_t
;
82 g_tcpListenSockets_t g_tcpListenSockets
;
85 struct DNSComboWriter
{
86 DNSComboWriter(const char* data
, uint16_t len
, const struct timeval
& now
) : d_mdp(data
, len
), d_now(now
), d_tcp(false), d_socket(-1)
89 void setRemote(ComboAddress
* sa
)
94 void setSocket(int sock
)
99 string
getRemote() const
101 return d_remote
.toString();
104 struct timeval d_now
;
105 ComboAddress d_remote
;
114 int sem_init(sem_t
*, int, unsigned int){return 0;}
115 int sem_wait(sem_t
*){return 0;}
116 int sem_trywait(sem_t
*){return 0;}
117 int sem_post(sem_t
*){return 0;}
118 int sem_getvalue(sem_t
*, int*){return 0;}
119 pthread_t
pthread_self(void){return (pthread_t
) 0;}
120 int pthread_mutex_init(pthread_mutex_t
*mutex
, const pthread_mutexattr_t
*mutexattr
){ return 0; }
121 int pthread_mutex_lock(pthread_mutex_t
*mutex
){ return 0; }
122 int pthread_mutex_unlock(pthread_mutex_t
*mutex
) { return 0; }
123 int pthread_mutex_destroy(pthread_mutex_t
*mutex
) { return 0; }
125 #endif // __FreeBSD__
130 static ArgvMap theArg
;
134 struct timeval g_now
;
135 typedef vector
<int> tcpserversocks_t
;
137 MT_t
* MT
; // the big MTasker
139 void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
);
141 // -1 is error, 0 is timeout, 1 is success
142 int asendtcp(const string
& data
, Socket
* sock
)
148 g_fdm
->addWriteFD(sock
->getHandle(), handleTCPClientWritable
, pident
);
151 int ret
=MT
->waitEvent(pident
, &packet
, 1);
153 if(!ret
|| ret
==-1) { // timeout
154 g_fdm
->removeWriteFD(sock
->getHandle());
156 else if(packet
.size() !=data
.size()) { // main loop tells us what it sent out, or empty in case of an error
162 void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
);
164 // -1 is error, 0 is timeout, 1 is success
165 int arecvtcp(string
& data
, int len
, Socket
* sock
)
171 g_fdm
->addReadFD(sock
->getHandle(), handleTCPClientReadable
, pident
);
173 int ret
=MT
->waitEvent(pident
,&data
,1);
174 if(!ret
|| ret
==-1) { // timeout
175 g_fdm
->removeReadFD(sock
->getHandle());
177 else if(data
.empty()) {// error, EOF or other
185 void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
&);
187 // you can ask this class for a UDP socket to send a query from
188 // this socket is not yours, don't even think about deleting it
189 // but after you call 'returnSocket' on it, don't assume anything anymore
192 unsigned int d_numsocks
;
193 unsigned int d_maxsocks
;
196 UDPClientSocks() : d_numsocks(0), d_maxsocks(5000)
200 typedef set
<int> socks_t
;
203 // returning -1 means: temporary OS error (ie, out of files), -2 means OS error
204 int getSocket(const ComboAddress
& toaddr
, int* fd
)
206 *fd
=makeClientSocket(toaddr
.sin4
.sin_family
);
207 if(*fd
< 0) // temporary error - receive exception otherwise
210 if(connect(*fd
, (struct sockaddr
*)(&toaddr
), toaddr
.getSocklen()) < 0) {
213 if(err
==ENETUNREACH
) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
223 void returnSocket(int fd
)
225 socks_t::iterator i
=d_socks
.find(fd
);
226 if(i
==d_socks
.end()) {
227 throw AhuException("Trying to return a socket (fd="+lexical_cast
<string
>(fd
)+") not in the pool");
232 // return a socket to the pool, or simply erase it
233 void returnSocket(socks_t::iterator
& i
)
235 if(i
==d_socks
.end()) {
236 throw AhuException("Trying to return a socket not in the pool");
239 g_fdm
->removeReadFD(*i
);
241 catch(FDMultiplexerException
& e
) {
242 // we sometimes return a socket that has not yet been assigned to g_fdm
244 Utility::closesocket(*i
);
250 // returns -1 for errors which might go away, throws for ones that won't
251 int makeClientSocket(int family
)
253 int ret
=(int)socket(family
, SOCK_DGRAM
, 0);
254 if(ret
< 0 && errno
==EMFILE
) // this is not a catastrophic error
258 throw AhuException("Making a socket for resolver: "+stringerror());
260 static optional
<ComboAddress
> sin4
;
262 sin4
=ComboAddress(::arg()["query-local-address"]);
264 static optional
<ComboAddress
> sin6
;
266 if(!::arg()["query-local-address6"].empty())
267 sin6
=ComboAddress(::arg()["query-local-address6"]);
272 uint16_t port
=1025+Utility::random()%64510;
273 if(tries
==1) // fall back to kernel 'random'
276 if(family
==AF_INET
) {
277 sin4
->sin4
.sin_port
= htons(port
);
279 if (::bind(ret
, (struct sockaddr
*)&*sin4
, sin4
->getSocklen()) >= 0)
283 sin6
->sin6
.sin6_port
= htons(port
);
285 if (::bind(ret
, (struct sockaddr
*)&*sin6
, sin6
->getSocklen()) >= 0)
290 throw AhuException("Resolver binding to local query client socket: "+stringerror());
292 Utility::setNonBlocking(ret
);
300 /* these two functions are used by LWRes */
301 // -2 is OS error, -1 is error that depends on the remote, > 0 is success
302 int asendto(const char *data
, int len
, int flags
,
303 const ComboAddress
& toaddr
, uint16_t id
, const string
& domain
, uint16_t qtype
, int* fd
)
307 pident
.domain
= domain
;
308 pident
.remote
= toaddr
;
311 // see if there is an existing outstanding request we can chain on to, using partial equivalence function
312 pair
<MT_t::waiters_t::iterator
, MT_t::waiters_t::iterator
> chain
=MT
->d_waiters
.equal_range(pident
, PacketIDBirthdayCompare());
314 for(; chain
.first
!= chain
.second
; chain
.first
++) {
315 if(chain
.first
->key
.fd
> -1) { // don't chain onto existing chained waiter!
316 // cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
317 // cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
318 // <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
320 chain
.first
->key
.chain
.insert(id
); // we can chain
321 *fd
=-1; // gets used in waitEvent / sendEvent later on
326 int ret
=g_udpclientsocks
.getSocket(toaddr
, fd
);
333 g_fdm
->addReadFD(*fd
, handleUDPServerResponse
, pident
);
334 ret
=send(*fd
, data
, len
, 0);
336 g_udpclientsocks
.returnSocket(*fd
);
340 // -1 is error, 0 is timeout, 1 is success
341 int arecvfrom(char *data
, int len
, int flags
, const ComboAddress
& fromaddr
, int *d_len
,
342 uint16_t id
, const string
& domain
, uint16_t qtype
, int fd
, unsigned int now
)
344 static optional
<unsigned int> nearMissLimit
;
346 nearMissLimit
=::arg().asNum("spoof-nearmiss-max");
351 pident
.domain
=domain
;
353 pident
.remote
=fromaddr
;
356 int ret
=MT
->waitEvent(pident
, &packet
, 1, now
);
359 if(packet
.empty()) // means "error"
362 *d_len
=(int)packet
.size();
363 memcpy(data
,packet
.c_str(),min(len
,*d_len
));
364 if(*nearMissLimit
&& pident
.nearMisses
> *nearMissLimit
) {
365 L
<<Logger::Error
<<"Too many ("<<pident
.nearMisses
<<" > "<<*nearMissLimit
<<") bogus answers for '"<<domain
<<"' from "<<fromaddr
.toString()<<", assuming spoof attempt."<<endl
;
366 g_stats
.spoofCount
++;
372 g_udpclientsocks
.returnSocket(fd
);
377 void setBuffer(int fd
, int optname
, uint32_t size
)
380 socklen_t len
=sizeof(psize
);
382 if(!getsockopt(fd
, SOL_SOCKET
, optname
, (char*)&psize
, &len
) && psize
> size
) {
383 L
<<Logger::Error
<<"Not decreasing socket buffer size from "<<psize
<<" to "<<size
<<endl
;
387 if (setsockopt(fd
, SOL_SOCKET
, optname
, (char*)&size
, sizeof(size
)) < 0 )
388 L
<<Logger::Error
<<"Warning: unable to raise socket buffer size to "<<size
<<": "<<strerror(errno
)<<endl
;
392 static void setReceiveBuffer(int fd
, uint32_t size
)
394 setBuffer(fd
, SO_RCVBUF
, size
);
397 static void setSendBuffer(int fd
, uint32_t size
)
399 setBuffer(fd
, SO_SNDBUF
, size
);
403 static void writePid(void)
405 s_pidfname
=::arg()["socket-dir"]+"/"+s_programname
+".pid";
406 ofstream
of(s_pidfname
.c_str());
408 of
<< Utility::getpid() <<endl
;
410 L
<<Logger::Error
<<"Requested to write pid for "<<Utility::getpid()<<" to "<<s_pidfname
<<" failed: "<<strerror(errno
)<<endl
;
413 void primeHints(void)
416 set
<DNSResourceRecord
>nsset
;
418 if(::arg()["hint-file"].empty()) {
419 static const char*ips
[]={"198.41.0.4", "192.228.79.201", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241",
420 "192.112.36.4", "128.63.2.53",
421 "192.36.148.17","192.58.128.30", "193.0.14.129", "199.7.83.42", "202.12.27.33"};
422 DNSResourceRecord arr
, nsrr
;
424 arr
.ttl
=time(0)+3600000;
425 nsrr
.qtype
=QType::NS
;
426 nsrr
.ttl
=time(0)+3600000;
428 for(char c
='a';c
<='m';++c
) {
429 static char templ
[40];
430 strncpy(templ
,"a.root-servers.net.", sizeof(templ
) - 1);
432 arr
.qname
=nsrr
.content
=templ
;
433 arr
.content
=ips
[c
-'a'];
434 set
<DNSResourceRecord
> aset
;
436 RC
.replace(time(0), string(templ
), QType(QType::A
), aset
, true); // auth, nuke it all
442 ZoneParserTNG
zpt(::arg()["hint-file"]);
443 DNSResourceRecord rr
;
444 set
<DNSResourceRecord
> aset
;
448 if(rr
.qtype
.getCode()==QType::A
) {
449 set
<DNSResourceRecord
> aset
;
451 RC
.replace(time(0), rr
.qname
, QType(QType::A
), aset
, true); // auth, etc see above
453 if(rr
.qtype
.getCode()==QType::NS
) {
454 rr
.content
=toLower(rr
.content
);
459 RC
.replace(time(0),".", QType(QType::NS
), nsset
, true); // and stuff in the cache (auth)
462 map
<ComboAddress
, uint32_t> g_tcpClientCounts
;
467 enum stateenum
{BYTE0
, BYTE1
, GETQUESTION
, DONE
} state
;
474 static void closeAndCleanup(int fd
, const ComboAddress
& remote
)
476 Utility::closesocket(fd
);
477 if(!g_tcpClientCounts
[remote
]--)
478 g_tcpClientCounts
.erase(remote
);
479 s_currentConnections
--;
481 void closeAndCleanup()
483 closeAndCleanup(fd
, remote
);
485 static unsigned int s_currentConnections
; //!< total number of current TCP connections
488 unsigned int TCPConnection::s_currentConnections
;
489 void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
);
491 void startDoResolve(void *p
)
493 DNSComboWriter
* dc
=(DNSComboWriter
*)p
;
496 uint16_t maxudpsize
=512;
497 MOADNSParser::EDNSOpts edo
;
498 if(dc
->d_mdp
.getEDNSOpts(&edo
)) {
499 maxudpsize
=edo
.d_packetsize
;
502 vector
<DNSResourceRecord
> ret
;
503 vector
<uint8_t> packet
;
505 DNSPacketWriter
pw(packet
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
);
507 pw
.getHeader()->aa
=0;
508 pw
.getHeader()->ra
=1;
509 pw
.getHeader()->qr
=1;
510 pw
.getHeader()->id
=dc
->d_mdp
.d_header
.id
;
511 pw
.getHeader()->rd
=dc
->d_mdp
.d_header
.rd
;
513 SyncRes
sr(dc
->d_now
);
515 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] " << (dc
->d_tcp
? "TCP " : "") << "question for '"<<dc
->d_mdp
.d_qname
<<"|"
516 <<DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)<<"' from "<<dc
->getRemote()<<endl
;
518 sr
.setId(MT
->getTid());
519 if(!dc
->d_mdp
.d_header
.rd
)
522 int res
=sr
.beginResolve(dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), dc
->d_mdp
.d_qclass
, ret
);
525 pw
.getHeader()->rcode
=RCode::ServFail
;
526 // no commit here, because no record
530 pw
.getHeader()->rcode
=res
;
532 case RCode::ServFail
:
535 case RCode::NXDomain
:
546 for(vector
<DNSResourceRecord
>::const_iterator i
=ret
.begin(); i
!=ret
.end(); ++i
) {
547 pw
.startRecord(i
->qname
, i
->qtype
.getCode(), i
->ttl
, i
->qclass
, (DNSPacketWriter::Place
)i
->d_place
);
549 if(i
->qtype
.getCode() == QType::A
) { // blast out A record w/o doing whole dnswriter thing
551 IpToU32(i
->content
, &ip
);
552 pw
.xfr32BitInt(htonl(ip
));
554 shared_ptr
<DNSRecordContent
> drc(DNSRecordContent::mastermake(i
->qtype
.getCode(), i
->qclass
, i
->content
));
557 if(!dc
->d_tcp
&& pw
.size() > maxudpsize
) {
559 if(i
->d_place
==DNSResourceRecord::ANSWER
) // only truncate if we actually omitted parts of the answer
560 pw
.getHeader()->tc
=1;
561 goto sendit
; // need to jump over pw.commit
570 sendto(dc
->d_socket
, (const char*)&*packet
.begin(), packet
.size(), 0, (struct sockaddr
*)(&dc
->d_remote
), dc
->d_remote
.getSocklen());
574 buf
[0]=packet
.size()/256;
575 buf
[1]=packet
.size()%256;
577 Utility::iovec iov
[2];
579 iov
[0].iov_base
=(void*)buf
; iov
[0].iov_len
=2;
580 iov
[1].iov_base
=(void*)&*packet
.begin(); iov
[1].iov_len
= packet
.size();
582 int ret
=Utility::writev(dc
->d_socket
, iov
, 2);
586 L
<<Logger::Error
<<"EOF writing TCP answer to "<<dc
->getRemote()<<endl
;
588 L
<<Logger::Error
<<"Error writing TCP answer to "<<dc
->getRemote()<<": "<< strerror(errno
) <<endl
;
589 else if((unsigned int)ret
!= 2 + packet
.size())
590 L
<<Logger::Error
<<"Oops, partial answer sent to "<<dc
->getRemote()<<" for "<<dc
->d_mdp
.d_qname
<<" (size="<< (2 + packet
.size()) <<", sent "<<ret
<<")"<<endl
;
594 // update tcp connection status, either by closing or moving to 'BYTE0'
597 g_fdm
->removeReadFD(dc
->d_socket
);
598 TCPConnection::closeAndCleanup(dc
->d_socket
, dc
->d_remote
);
603 tc
.state
=TCPConnection::BYTE0
;
604 tc
.remote
=dc
->d_remote
;
605 Utility::gettimeofday(&g_now
, 0); // needs to be updated
606 tc
.startTime
=g_now
.tv_sec
;
607 g_fdm
->addReadFD(tc
.fd
, handleRunningTCPQuestion
, tc
);
608 g_fdm
->setReadTTD(tc
.fd
, g_now
, g_tcpTimeout
);
613 L
<<Logger::Error
<<"["<<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
);
614 L
<<"': "<<ntohs(pw
.getHeader()->ancount
)<<" answers, "<<ntohs(pw
.getHeader()->arcount
)<<" additional, took "<<sr
.d_outqueries
<<" packets, "<<
615 sr
.d_throttledqueries
<<" throttled, "<<sr
.d_timeouts
<<" timeouts, "<<sr
.d_tcpoutqueries
<<" tcp connections, rcode="<<res
<<endl
;
618 sr
.d_outqueries
? RC
.cacheMisses
++ : RC
.cacheHits
++;
619 float spent
=makeFloat(sr
.d_now
-dc
->d_now
);
621 g_stats
.answers0_1
++;
622 else if(spent
< 0.010)
623 g_stats
.answers1_10
++;
625 g_stats
.answers10_100
++;
627 g_stats
.answers100_1000
++;
629 g_stats
.answersSlow
++;
631 uint64_t newLat
=(uint64_t)(spent
*1000000);
632 if(newLat
< 1000000) // outliers of several minutes exist..
633 g_stats
.avgLatencyUsec
=(uint64_t)((1-0.0001)*g_stats
.avgLatencyUsec
+ 0.0001*newLat
);
637 catch(AhuException
&ae
) {
638 L
<<Logger::Error
<<"startDoResolve problem: "<<ae
.reason
<<endl
;
640 catch(MOADNSException
& e
) {
641 L
<<Logger::Error
<<"DNS parser error: "<<dc
->d_mdp
.d_qname
<<", "<<e
.what()<<endl
;
643 catch(exception
& e
) {
644 L
<<Logger::Error
<<"STL error: "<<e
.what()<<endl
;
647 L
<<Logger::Error
<<"Any other exception in a resolver context"<<endl
;
651 RecursorControlChannel s_rcc
;
653 void makeControlChannelSocket()
655 string sockname
=::arg()["socket-dir"]+"/pdns_recursor.controlsocket";
656 if(::arg().mustDo("fork")) {
657 sockname
+="."+lexical_cast
<string
>(Utility::getpid());
658 L
<<Logger::Warning
<<"Forked control socket name: "<<sockname
<<endl
;
660 s_rcc
.listen(sockname
);
663 void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
665 TCPConnection
* conn
=any_cast
<TCPConnection
>(&var
);
667 if(conn
->state
==TCPConnection::BYTE0
) {
668 int bytes
=recv(conn
->fd
, conn
->data
, 2, 0);
670 conn
->state
=TCPConnection::BYTE1
;
672 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
674 conn
->state
=TCPConnection::GETQUESTION
;
676 if(!bytes
|| bytes
< 0) {
677 TCPConnection
tmp(*conn
);
678 g_fdm
->removeReadFD(fd
);
679 tmp
.closeAndCleanup();
683 else if(conn
->state
==TCPConnection::BYTE1
) {
684 int bytes
=recv(conn
->fd
, conn
->data
+1, 1, 0);
686 conn
->state
=TCPConnection::GETQUESTION
;
687 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
690 if(!bytes
|| bytes
< 0) {
691 if(g_logCommonErrors
)
692 L
<<Logger::Error
<<"TCP client "<< conn
->remote
.toString() <<" disconnected after first byte"<<endl
;
693 TCPConnection
tmp(*conn
);
694 g_fdm
->removeReadFD(fd
);
695 tmp
.closeAndCleanup(); // conn loses validity here..
699 else if(conn
->state
==TCPConnection::GETQUESTION
) {
700 int bytes
=recv(conn
->fd
, conn
->data
+ conn
->bytesread
, conn
->qlen
- conn
->bytesread
, 0);
701 if(!bytes
|| bytes
< 0) {
702 L
<<Logger::Error
<<"TCP client "<< conn
->remote
.toString() <<" disconnected while reading question body"<<endl
;
703 TCPConnection
tmp(*conn
);
704 g_fdm
->removeReadFD(fd
);
705 tmp
.closeAndCleanup(); // conn loses validity here..
709 conn
->bytesread
+=bytes
;
710 if(conn
->bytesread
==conn
->qlen
) {
711 TCPConnection
tconn(*conn
);
712 g_fdm
->removeReadFD(fd
); // should no longer awake ourselves when there is data to read
714 DNSComboWriter
* dc
=0;
716 dc
=new DNSComboWriter(tconn
.data
, tconn
.qlen
, g_now
);
718 catch(MOADNSException
&mde
) {
719 g_stats
.clientParseError
++;
720 if(g_logCommonErrors
)
721 L
<<Logger::Error
<<"Unable to parse packet from TCP client "<< tconn
.remote
.toString() <<endl
;
722 tconn
.closeAndCleanup();
726 dc
->setSocket(tconn
.fd
);
728 dc
->setRemote(&tconn
.remote
);
729 if(dc
->d_mdp
.d_header
.qr
) {
731 L
<<Logger::Error
<<"Ignoring answer on server socket!"<<endl
;
732 tconn
.closeAndCleanup();
737 ++g_stats
.tcpqcounter
;
738 MT
->makeThread(startDoResolve
, dc
); // deletes dc
745 //! Handle new incoming TCP connection
746 void handleNewTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& )
749 socklen_t addrlen
=sizeof(addr
);
750 int newsock
=(int)accept(fd
, (struct sockaddr
*)&addr
, &addrlen
);
752 g_stats
.addRemote(addr
);
753 if(g_allowFrom
&& !g_allowFrom
->match(&addr
)) {
755 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping TCP query from "<<addr
.toString()<<", address not matched by allow-from"<<endl
;
757 g_stats
.unauthorizedTCP
++;
758 Utility::closesocket(newsock
);
762 if(g_maxTCPPerClient
&& g_tcpClientCounts
.count(addr
) && g_tcpClientCounts
[addr
] >= g_maxTCPPerClient
) {
763 g_stats
.tcpClientOverflow
++;
764 Utility::closesocket(newsock
); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
767 g_tcpClientCounts
[addr
]++;
768 Utility::setNonBlocking(newsock
);
771 tc
.state
=TCPConnection::BYTE0
;
773 tc
.startTime
=g_now
.tv_sec
;
774 TCPConnection::s_currentConnections
++;
775 g_fdm
->addReadFD(tc
.fd
, handleRunningTCPQuestion
, tc
);
778 Utility::gettimeofday(&now
, 0);
779 g_fdm
->setReadTTD(tc
.fd
, now
, g_tcpTimeout
);
783 void questionExpand(const char* packet
, uint16_t len
, char* qname
, int maxlen
, uint16_t& type
)
786 const unsigned char* end
=(const unsigned char*)packet
+len
;
787 unsigned char* lbegin
=(unsigned char*)packet
+12;
788 unsigned char* pos
=lbegin
;
789 unsigned char labellen
;
793 char* lend
=dst
+ maxlen
;
798 while((labellen
=*pos
++) && pos
< end
) { // "scan and copy"
800 throw runtime_error("Label length exceeded destination length");
801 for(;labellen
;--labellen
)
807 if(pos
+ labellen
+ 2 <= end
) // is this correct XXX FIXME?
808 type
=(*pos
)*256 + *(pos
+1);
811 // cerr<<"Returning: '"<< string(tmp+1, pos) <<"'\n";
814 string
questionExpand(const char* packet
, uint16_t len
, uint16_t& type
)
817 questionExpand(packet
, len
, tmp
, sizeof(tmp
), type
);
821 void handleNewUDPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
823 // static HTimer s_timer("udp new question processing");
824 // HTimerSentinel hts=s_timer.getSentinel();
827 ComboAddress fromaddr
;
828 socklen_t addrlen
=sizeof(fromaddr
);
829 // uint64_t tsc1, tsc2;
831 if((len
=recvfrom(fd
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
)) >= 0) {
833 g_stats
.addRemote(fromaddr
);
835 if(g_allowFrom
&& !g_allowFrom
->match(&fromaddr
)) {
837 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toString()<<", address not matched by allow-from"<<endl
;
839 g_stats
.unauthorizedUDP
++;
843 dnsheader
* dh
=(dnsheader
*)data
;
846 if(g_logCommonErrors
)
847 L
<<Logger::Error
<<"Ignoring answer from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
855 questionExpand(data
, len
, qname
, sizeof(qname
), type
);
859 throw MOADNSException(e
.what());
862 // must all be same length answers right now!
863 if((type
==QType::A
|| type
==QType::AAAA
) && dh
->arcount
==0 && dh
->ancount
==0 && dh
->nscount
==0 && ntohs(dh
->qdcount
)==1 ) {
868 if((count
=RC
.getDirect(g_now
.tv_sec
, qname
, QType(type
), ttd
, record
, rlen
))) {
869 if(len
+ count
*(sizeof(dnsrecordheader
) + 2 + rlen
[0]) > 512)
872 random_shuffle(record
, &record
[count
]);
875 dh
->ancount
=ntohs(count
);
876 for(int n
=0; n
< count
; ++n
) {
877 memcpy(data
+len
, "\xc0\x0c", 2); // answer label pointer
879 struct dnsrecordheader drh
;
880 drh
.d_type
=htons(type
);
881 drh
.d_class
=htons(1);
882 drh
.d_ttl
=htonl(ttd
[n
] - g_now
.tv_sec
);
883 drh
.d_clen
=htons(rlen
[n
]);
884 memcpy(data
+len
, &drh
, sizeof(drh
));
886 memcpy(data
+len
, record
[n
], rlen
[n
]);
891 sendto(fd
, data
, len
, 0, (struct sockaddr
*)(&fromaddr
), fromaddr
.getSocklen());
892 // cerr<<"shunted: " << (tsc2-tsc1) / 3000.0 << endl;
897 if(type
!=QType::A
&& type
!=QType::AAAA
)
898 g_stats
.noShuntWrongType
++;
900 g_stats
.noShuntWrongQuestion
++;
904 DNSComboWriter
* dc
= new DNSComboWriter(data
, len
, g_now
);
906 dc
->setRemote(&fromaddr
);
910 MT
->makeThread(startDoResolve
, (void*) dc
); // deletes dc
913 catch(MOADNSException
& mde
) {
914 g_stats
.clientParseError
++;
915 if(g_logCommonErrors
)
916 L
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<mde
.what()<<endl
;
921 typedef vector
<pair
<int, function
< void(int, any
&) > > > deferredAdd_t
;
922 deferredAdd_t deferredAdd
;
924 void makeTCPServerSockets()
927 vector
<string
>locals
;
928 stringtok(locals
,::arg()["local-address"]," ,");
931 throw AhuException("No local address specified");
933 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
935 st
.port
=::arg().asNum("local-port");
936 parseService(*i
, st
);
940 memset((char *)&sin
,0, sizeof(sin
));
941 sin
.sin4
.sin_family
= AF_INET
;
942 if(!IpToU32(st
.host
, (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
943 sin
.sin6
.sin6_family
= AF_INET6
;
944 if(Utility::inet_pton(AF_INET6
, st
.host
.c_str(), &sin
.sin6
.sin6_addr
) <= 0)
945 throw AhuException("Unable to resolve local address for TCP server on '"+ st
.host
+"'");
948 fd
=socket(sin
.sin6
.sin6_family
, SOCK_STREAM
, 0);
950 throw AhuException("Making a TCP server socket for resolver: "+stringerror());
953 if(setsockopt(fd
,SOL_SOCKET
,SO_REUSEADDR
,(char*)&tmp
,sizeof tmp
)<0) {
954 L
<<Logger::Error
<<"Setsockopt failed for TCP listening socket"<<endl
;
958 #ifdef TCP_DEFER_ACCEPT
959 if(setsockopt(fd
, SOL_TCP
,TCP_DEFER_ACCEPT
,(char*)&tmp
,sizeof tmp
) >= 0) {
960 if(i
==locals
.begin())
961 L
<<Logger::Error
<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl
;
965 sin
.sin4
.sin_port
= htons(st
.port
);
966 int socklen
=sin
.sin4
.sin_family
==AF_INET
? sizeof(sin
.sin4
) : sizeof(sin
.sin6
);
967 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
968 throw AhuException("Binding TCP server socket for "+ st
.host
+": "+stringerror());
970 Utility::setNonBlocking(fd
);
971 setSendBuffer(fd
, 65000);
973 deferredAdd
.push_back(make_pair(fd
, handleNewTCPQuestion
));
974 g_tcpListenSockets
.push_back(fd
);
976 if(sin
.sin4
.sin_family
== AF_INET
)
977 L
<<Logger::Error
<<"Listening for TCP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
979 L
<<Logger::Error
<<"Listening for TCP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
983 void makeUDPServerSockets()
985 vector
<string
>locals
;
986 stringtok(locals
,::arg()["local-address"]," ,");
989 throw AhuException("No local address specified");
991 if(::arg()["local-address"]=="0.0.0.0") {
992 L
<<Logger::Warning
<<"It is advised to bind to explicit addresses with the --local-address option"<<endl
;
995 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
997 st
.port
=::arg().asNum("local-port");
998 parseService(*i
, st
);
1002 memset(&sin
, 0, sizeof(sin
));
1003 sin
.sin4
.sin_family
= AF_INET
;
1004 if(!IpToU32(st
.host
.c_str() , (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
1005 sin
.sin6
.sin6_family
= AF_INET6
;
1006 if(Utility::inet_pton(AF_INET6
, st
.host
.c_str(), &sin
.sin6
.sin6_addr
) <= 0)
1007 throw AhuException("Unable to resolve local address for UDP server on '"+ st
.host
+"'");
1010 int fd
=socket(sin
.sin4
.sin_family
, SOCK_DGRAM
,0);
1012 throw AhuException("Making a UDP server socket for resolver: "+netstringerror());
1015 setReceiveBuffer(fd
, 200000);
1016 sin
.sin4
.sin_port
= htons(st
.port
);
1018 int socklen
=sin
.sin4
.sin_family
==AF_INET
? sizeof(sin
.sin4
) : sizeof(sin
.sin6
);
1019 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
1020 throw AhuException("Resolver binding to server socket on port "+ lexical_cast
<string
>(st
.port
) +" for "+ st
.host
+": "+stringerror());
1022 Utility::setNonBlocking(fd
);
1023 // g_fdm->addReadFD(fd, handleNewUDPQuestion);
1024 deferredAdd
.push_back(make_pair(fd
, handleNewUDPQuestion
));
1026 if(sin
.sin4
.sin_family
== AF_INET
)
1027 L
<<Logger::Error
<<"Listening for UDP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
1029 L
<<Logger::Error
<<"Listening for UDP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
1035 void daemonize(void)
1037 s_rcc
.d_dontclose
=true;
1043 int i
=open("/dev/null",O_RDWR
); /* open stdin */
1045 L
<<Logger::Critical
<<"Unable to open /dev/null: "<<stringerror()<<endl
;
1047 dup2(i
,0); /* stdin */
1048 dup2(i
,1); /* stderr */
1049 dup2(i
,2); /* stderr */
1059 void usr1Handler(int)
1066 void usr2Handler(int)
1068 SyncRes::setLog(true);
1070 ::arg().set("quiet")="no";
1076 if(g_stats
.qcounter
&& (RC
.cacheHits
+ RC
.cacheMisses
) && SyncRes::s_queries
&& SyncRes::s_outqueries
) {
1077 L
<<Logger::Warning
<<"stats: "<<g_stats
.qcounter
<<" questions, "<<RC
.size()<<" cache entries, "<<SyncRes::s_negcache
.size()<<" negative entries, "
1078 <<(int)((RC
.cacheHits
*100.0)/(RC
.cacheHits
+RC
.cacheMisses
))<<"% cache hits"<<endl
;
1079 L
<<Logger::Warning
<<"stats: throttle map: "<<SyncRes::s_throttle
.size()<<", ns speeds: "
1080 <<SyncRes::s_nsSpeeds
.size()<<endl
; // ", bytes: "<<RC.bytes()<<endl;
1081 L
<<Logger::Warning
<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries
*100.0/SyncRes::s_queries
)<<"%";
1082 L
<<Logger::Warning
<<", "<<(int)(SyncRes::s_throttledqueries
*100.0/(SyncRes::s_outqueries
+SyncRes::s_throttledqueries
))<<"% throttled, "
1083 <<SyncRes::s_nodelegated
<<" no-delegation drops"<<endl
;
1084 L
<<Logger::Warning
<<"stats: "<<SyncRes::s_tcpoutqueries
<<" outgoing tcp connections, "<<MT
->numProcesses()<<" queries running, "<<SyncRes::s_outgoingtimeouts
<<" outgoing timeouts"<<endl
;
1086 else if(statsWanted
)
1087 L
<<Logger::Warning
<<"stats: no stats yet!"<<endl
;
1089 // HTimer::listAll();
1094 static void houseKeeping(void *)
1097 static time_t last_stat
, last_rootupdate
, last_prune
;
1099 Utility::gettimeofday(&now
, 0);
1101 if(now
.tv_sec
- last_prune
> 300) {
1106 typedef SyncRes::negcache_t::nth_index
<1>::type negcache_by_ttd_index_t
;
1107 negcache_by_ttd_index_t
& ttdindex
=boost::multi_index::get
<1>(SyncRes::s_negcache
);
1109 negcache_by_ttd_index_t::iterator i
=ttdindex
.lower_bound(now
.tv_sec
);
1110 ttdindex
.erase(ttdindex
.begin(), i
);
1112 time_t limit
=now
.tv_sec
-300;
1113 for(SyncRes::nsspeeds_t::iterator i
= SyncRes::s_nsSpeeds
.begin() ; i
!= SyncRes::s_nsSpeeds
.end(); )
1114 if(i
->second
.stale(limit
))
1115 SyncRes::s_nsSpeeds
.erase(i
++);
1119 // cerr<<"Pruned "<<pruned<<" records, left "<<SyncRes::s_negcache.size()<<"\n";
1120 // cout<<"Prune took "<<dt.udiff()<<"usec\n";
1123 if(now
.tv_sec
- last_stat
>1800) {
1127 if(now
.tv_sec
- last_rootupdate
> 7200) {
1129 sr
.setDoEDNS0(true);
1130 vector
<DNSResourceRecord
> ret
;
1133 int res
=sr
.beginResolve(".", QType(QType::NS
), 1, ret
);
1135 L
<<Logger::Warning
<<"Refreshed . records"<<endl
;
1136 last_rootupdate
=now
.tv_sec
;
1139 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;
1142 catch(AhuException
& ae
)
1144 L
<<Logger::Error
<<"Fatal error: "<<ae
.reason
<<endl
;
1150 void handleRCC(int fd
, FDMultiplexer::funcparam_t
& var
)
1153 string msg
=s_rcc
.recv(&remote
);
1154 RecursorControlParser rcp
;
1155 RecursorControlParser::func_t
* command
;
1156 string answer
=rcp
.getAnswer(msg
, &command
);
1158 s_rcc
.send(answer
, &remote
);
1161 catch(exception
& e
) {
1162 L
<<Logger::Error
<<"Error dealing with control socket request: "<<e
.what()<<endl
;
1164 catch(AhuException
& ae
) {
1165 L
<<Logger::Error
<<"Error dealing with control socket request: "<<ae
.reason
<<endl
;
1169 void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
)
1171 PacketID
* pident
=any_cast
<PacketID
>(&var
);
1172 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
1174 shared_array
<char> buffer(new char[pident
->inNeeded
]);
1176 int ret
=recv(fd
, buffer
.get(), pident
->inNeeded
,0);
1178 pident
->inMSG
.append(&buffer
[0], &buffer
[ret
]);
1179 pident
->inNeeded
-=ret
;
1180 if(!pident
->inNeeded
) {
1181 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
1182 PacketID pid
=*pident
;
1183 string msg
=pident
->inMSG
;
1185 g_fdm
->removeReadFD(fd
);
1186 MT
->sendEvent(pid
, &msg
);
1189 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
1193 PacketID tmp
=*pident
;
1194 g_fdm
->removeReadFD(fd
); // pident might now be invalid (it isn't, but still)
1196 MT
->sendEvent(tmp
, &empty
); // this conveys error status
1200 void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
)
1202 PacketID
* pid
=any_cast
<PacketID
>(&var
);
1203 int ret
=send(fd
, pid
->outMSG
.c_str() + pid
->outPos
, pid
->outMSG
.size() - pid
->outPos
,0);
1206 if(pid
->outPos
==pid
->outMSG
.size()) {
1208 g_fdm
->removeWriteFD(fd
);
1209 MT
->sendEvent(tmp
, &tmp
.outMSG
); // send back what we sent to convey everything is ok
1212 else { // error or EOF
1214 g_fdm
->removeWriteFD(fd
);
1216 MT
->sendEvent(tmp
, &sent
); // we convey error status by sending empty string
1220 // resend event to everybody chained onto it
1221 void doResends(MT_t::waiters_t::iterator
& iter
, PacketID resend
, const string
& content
)
1223 if(iter
->key
.chain
.empty())
1226 for(PacketID::chain_t::iterator i
=iter
->key
.chain
.begin(); i
!= iter
->key
.chain
.end() ; ++i
) {
1229 MT
->sendEvent(resend
, &content
);
1230 g_stats
.chainResends
++;
1231 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<": "<< res <<endl;
1235 void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
1237 // static HTimer s_timer("udp server response processing");
1239 PacketID pid
=any_cast
<PacketID
>(var
);
1242 ComboAddress fromaddr
;
1243 socklen_t addrlen
=sizeof(fromaddr
);
1245 len
=recvfrom(fd
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
);
1246 // HTimerSentinel hts=s_timer.getSentinel();
1247 if(len
< (int)sizeof(dnsheader
)) {
1249 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
1251 g_stats
.serverParseError
++;
1252 if(g_logCommonErrors
)
1253 L
<<Logger::Error
<<"Unable to parse packet from remote UDP server "<< sockAddrToString((struct sockaddr_in
*) &fromaddr
) <<
1254 ": packet smalller than DNS header"<<endl
;
1257 g_udpclientsocks
.returnSocket(fd
);
1260 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pid
);
1261 if(iter
!= MT
->d_waiters
.end())
1262 doResends(iter
, pid
, empty
);
1264 MT
->sendEvent(pid
, &empty
); // this denotes error (does lookup again.. at least L1 will be hot)
1269 memcpy(&dh
, data
, sizeof(dh
));
1271 if(!dh
.qdcount
) // UPC, Nominum?
1276 pident
.remote
=fromaddr
;
1279 pident
.domain
=questionExpand(data
, len
, pident
.type
); // don't copy this from above - we need to do the actual read
1281 packet
.assign(data
, len
);
1283 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pident
);
1284 if(iter
!= MT
->d_waiters
.end()) {
1285 doResends(iter
, pident
, packet
);
1289 if(!MT
->sendEvent(pident
, &packet
)) {
1291 // if(g_logCommonErrors)
1292 // L<<Logger::Warning<<"Discarding unexpected packet from "<<fromaddr.toString()<<": "<<pident.type<<endl;
1293 g_stats
.unexpectedCount
++;
1295 for(MT_t::waiters_t::iterator mthread
=MT
->d_waiters
.begin(); mthread
!=MT
->d_waiters
.end(); ++mthread
) {
1296 if(pident
.fd
==mthread
->key
.fd
&& mthread
->key
.remote
==pident
.remote
&& mthread
->key
.type
== pident
.type
&&
1297 !Utility::strcasecmp(pident
.domain
.c_str(), mthread
->key
.domain
.c_str())) {
1298 mthread
->key
.nearMisses
++;
1304 g_udpclientsocks
.returnSocket(fd
);
1308 L
<<Logger::Warning
<<"Ignoring question on outgoing socket from "<< sockAddrToString((struct sockaddr_in
*) &fromaddr
) <<endl
;
1311 FDMultiplexer
* getMultiplexer()
1314 for(FDMultiplexer::FDMultiplexermap_t::const_iterator i
= FDMultiplexer::getMultiplexerMap().begin();
1315 i
!= FDMultiplexer::getMultiplexerMap().end(); ++i
) {
1318 L
<<Logger::Error
<<"Enabled '"<<ret
->getName()<<"' multiplexer"<<endl
;
1321 catch(FDMultiplexerException
&fe
) {
1322 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer ("<<fe
.what()<<"), falling back"<<endl
;
1325 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer"<<endl
;
1328 L
<<Logger::Error
<<"No working multiplexer found!"<<endl
;
1332 static void makeNameToIPZone(const string
& hostname
, const string
& ip
)
1334 SyncRes::AuthDomain ad
;
1335 DNSResourceRecord rr
;
1336 rr
.qname
=toCanonic("", hostname
);
1337 rr
.d_place
=DNSResourceRecord::ANSWER
;
1339 rr
.qtype
=QType::SOA
;
1340 rr
.content
="localhost. root 1 604800 86400 2419200 604800";
1342 ad
.d_records
.insert(rr
);
1345 rr
.content
="localhost.";
1347 ad
.d_records
.insert(rr
);
1351 ad
.d_records
.insert(rr
);
1353 if(SyncRes::s_domainmap
.count(rr
.qname
)) {
1354 L
<<Logger::Warning
<<"Hosts file will not overwrite zone '"<<rr
.qname
<<"' already loaded"<<endl
;
1357 L
<<Logger::Warning
<<"Inserting forward zone '"<<rr
.qname
<<"' based on hosts file"<<endl
;
1358 SyncRes::s_domainmap
[rr
.qname
]=ad
;
1362 //! parts[0] must be an IP address, the rest must be host names
1363 static void makeIPToNamesZone(const vector
<string
>& parts
)
1365 string address
=parts
[0];
1366 vector
<string
> ipparts
;
1367 stringtok(ipparts
, address
,".");
1369 SyncRes::AuthDomain ad
;
1370 DNSResourceRecord rr
;
1371 for(int n
=ipparts
.size()-1; n
>=0 ; --n
) {
1372 rr
.qname
.append(ipparts
[n
]);
1373 rr
.qname
.append(1,'.');
1375 rr
.qname
.append("in-addr.arpa.");
1377 rr
.d_place
=DNSResourceRecord::ANSWER
;
1379 rr
.qtype
=QType::SOA
;
1380 rr
.content
="localhost. root. 1 604800 86400 2419200 604800";
1382 ad
.d_records
.insert(rr
);
1385 rr
.content
="localhost.";
1387 ad
.d_records
.insert(rr
);
1388 rr
.qtype
=QType::PTR
;
1390 if(ipparts
.size()==4) // otherwise this is a partial zone
1391 for(unsigned int n
=1; n
< parts
.size(); ++n
) {
1392 rr
.content
=toCanonic("", parts
[n
]);
1393 ad
.d_records
.insert(rr
);
1396 if(SyncRes::s_domainmap
.count(rr
.qname
)) {
1397 L
<<Logger::Warning
<<"Will not overwrite zone '"<<rr
.qname
<<"' already loaded"<<endl
;
1400 if(ipparts
.size()==4)
1401 L
<<Logger::Warning
<<"Inserting reverse zone '"<<rr
.qname
<<"' based on hosts file"<<endl
;
1402 SyncRes::s_domainmap
[rr
.qname
]=ad
;
1407 void parseAuthAndForwards();
1409 string
reloadAuthAndForwards()
1411 SyncRes::domainmap_t original
=SyncRes::s_domainmap
;
1414 L
<<Logger::Warning
<<"Reloading zones, purging data from cache"<<endl
;
1416 for(SyncRes::domainmap_t::const_iterator i
= SyncRes::s_domainmap
.begin(); i
!= SyncRes::s_domainmap
.end(); ++i
) {
1417 for(SyncRes::AuthDomain::records_t::const_iterator j
= i
->second
.d_records
.begin(); j
!= i
->second
.d_records
.end(); ++j
)
1418 RC
.doWipeCache(j
->qname
);
1421 string configname
=::arg()["config-dir"]+"/recursor.conf";
1422 cleanSlashes(configname
);
1424 if(!::arg().preParseFile(configname
.c_str(), "forward-zones"))
1425 L
<<Logger::Warning
<<"Unable to re-parse configuration file '"<<configname
<<"'"<<endl
;
1427 ::arg().preParseFile(configname
.c_str(), "auth-zones");
1428 ::arg().preParseFile(configname
.c_str(), "export-etc-hosts");
1429 ::arg().preParseFile(configname
.c_str(), "serve-rfc1918");
1431 parseAuthAndForwards();
1433 // purge again - new zones need to blank out the cache
1434 for(SyncRes::domainmap_t::const_iterator i
= SyncRes::s_domainmap
.begin(); i
!= SyncRes::s_domainmap
.end(); ++i
) {
1435 for(SyncRes::AuthDomain::records_t::const_iterator j
= i
->second
.d_records
.begin(); j
!= i
->second
.d_records
.end(); ++j
)
1436 RC
.doWipeCache(j
->qname
);
1439 // this is pretty blunt
1440 SyncRes::s_negcache
.clear();
1443 catch(exception
& e
) {
1444 L
<<Logger::Error
<<"Had error reloading zones, keeping original data: "<<e
.what()<<endl
;
1446 catch(AhuException
& ae
) {
1447 L
<<Logger::Error
<<"Encountered error reloading zones, keeping original data: "<<ae
.reason
<<endl
;
1450 L
<<Logger::Error
<<"Encountered unknown error reloading zones, keeping original data"<<endl
;
1452 SyncRes::s_domainmap
.swap(original
);
1453 return "reloading failed, see log\n";
1456 void parseAuthAndForwards()
1458 SyncRes::s_domainmap
.clear(); // this makes us idempotent
1460 TXTRecordContent::report();
1462 typedef vector
<string
> parts_t
;
1464 for(int n
=0; n
< 2 ; ++n
) {
1466 stringtok(parts
, ::arg()[n
? "forward-zones" : "auth-zones"], ",\t\n\r");
1467 for(parts_t::const_iterator iter
= parts
.begin(); iter
!= parts
.end(); ++iter
) {
1468 SyncRes::AuthDomain ad
;
1469 pair
<string
,string
> headers
=splitField(*iter
, '=');
1470 trim(headers
.first
);
1471 trim(headers
.second
);
1472 headers
.first
=toCanonic("", headers
.first
);
1474 L
<<Logger::Error
<<"Parsing authoritative data for zone '"<<headers
.first
<<"' from file '"<<headers
.second
<<"'"<<endl
;
1475 ZoneParserTNG
zpt(headers
.second
, headers
.first
);
1476 DNSResourceRecord rr
;
1477 while(zpt
.get(rr
)) {
1479 string tmp
=DNSRR2String(rr
);
1480 rr
=String2DNSRR(rr
.qname
, rr
.qtype
, tmp
, 3600);
1482 catch(exception
&e
) {
1483 throw AhuException("Error parsing record '"+rr
.qname
+"' of type "+rr
.qtype
.getName()+" in zone '"+headers
.first
+"' from file '"+headers
.second
+"': "+e
.what());
1486 throw AhuException("Error parsing record '"+rr
.qname
+"' of type "+rr
.qtype
.getName()+" in zone '"+headers
.first
+"' from file '"+headers
.second
+"'");
1489 ad
.d_records
.insert(rr
);
1494 L
<<Logger::Error
<<"Redirecting queries for zone '"<<headers
.first
<<"' to IP '"<<headers
.second
<<"'"<<endl
;
1495 ad
.d_server
=headers
.second
;
1498 SyncRes::s_domainmap
[headers
.first
]=ad
;
1502 if(!::arg()["forward-zones-file"].empty()) {
1503 L
<<Logger::Warning
<<"Reading zone forwarding information from '"<<::arg()["forward-zones-file"]<<"'"<<endl
;
1504 SyncRes::AuthDomain ad
;
1505 FILE *rfp
=fopen(::arg()["forward-zones-file"].c_str(), "r");
1508 throw AhuException("Error opening forward-zones-file '"+::arg()["forward-zones-file"]+"': "+stringerror());
1510 shared_ptr
<FILE> fp
=shared_ptr
<FILE>(rfp
, fclose
);
1513 vector
<string
> parts
;
1515 uint64_t before
= SyncRes::s_domainmap
.size();
1516 while(linenum
++, fgets(line
, sizeof(line
)-1, fp
.get())) {
1518 stringtok(parts
,line
,"=, ");
1522 throw AhuException("Error parsing line "+lexical_cast
<string
>(linenum
)+" of " +::arg()["forward-zones-file"]);
1525 parts
[0]=toCanonic("", parts
[0]);
1526 ad
.d_server
=parts
[1];
1527 // cerr<<"Inserting '"<<domain<<"' to '"<<ad.d_server<<"'\n";
1528 SyncRes::s_domainmap
[parts
[0]]=ad
;
1530 L
<<Logger::Warning
<<"Done parsing " << SyncRes::s_domainmap
.size() - before
<<" forwarding instructions"<<endl
;
1533 if(::arg().mustDo("export-etc-hosts")) {
1537 ifstream
ifs("/etc/hosts");
1539 L
<<Logger::Warning
<<"Could not open /etc/hosts for reading"<<endl
;
1543 string::size_type pos
;
1544 while(getline(ifs
,line
)) {
1546 if(pos
!=string::npos
)
1552 stringtok(parts
, line
, "\t\r\n ");
1553 if(parts
[0].find(':')!=string::npos
)
1556 for(unsigned int n
=1; n
< parts
.size(); ++n
)
1557 makeNameToIPZone(parts
[n
], parts
[0]);
1558 makeIPToNamesZone(parts
);
1561 if(::arg().mustDo("serve-rfc1918")) {
1562 L
<<Logger::Warning
<<"Inserting rfc 1918 private space zones"<<endl
;
1564 parts
.push_back("127");
1565 makeIPToNamesZone(parts
);
1567 makeIPToNamesZone(parts
);
1570 makeIPToNamesZone(parts
);
1571 for(int n
=16; n
< 32; n
++) {
1572 parts
[0]="172."+lexical_cast
<string
>(n
);
1573 makeIPToNamesZone(parts
);
1578 int serviceMain(int argc
, char*argv
[])
1580 L
.setName("pdns_recursor");
1582 L
.setLoglevel((Logger::Urgency
)(6)); // info and up
1584 if(!::arg()["logging-facility"].empty()) {
1585 boost::optional
<int> val
=logFacilityToLOG(::arg().asNum("logging-facility") );
1587 theL().setFacility(*val
);
1589 L
<<Logger::Error
<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl
;
1592 L
<<Logger::Warning
<<"PowerDNS recursor "<<VERSION
<<" (C) 2001-2007 PowerDNS.COM BV ("<<__DATE__
", "__TIME__
;
1594 L
<<", gcc "__VERSION__
;
1595 #endif // add other compilers here
1597 L
<<", MSVC "<<_MSC_VER
;
1599 L
<<") starting up"<<endl
;
1601 L
<<Logger::Warning
<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
1602 "This is free software, and you are welcome to redistribute it "
1603 "according to the terms of the GPL version 2."<<endl
;
1605 L
<<Logger::Warning
<<"Operating in "<<(sizeof(unsigned long)*8) <<" bits mode"<<endl
;
1607 if(!::arg()["allow-from"].empty()) {
1608 g_allowFrom
=new NetmaskGroup
;
1610 stringtok(ips
, ::arg()["allow-from"], ", ");
1611 L
<<Logger::Warning
<<"Only allowing queries from: ";
1612 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
1613 g_allowFrom
->addMask(*i
);
1615 L
<<Logger::Warning
<<", ";
1616 L
<<Logger::Warning
<<*i
;
1618 L
<<Logger::Warning
<<endl
;
1620 else if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
1621 L
<<Logger::Error
<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl
;
1623 if(!::arg()["dont-query"].empty()) {
1624 g_dontQuery
=new NetmaskGroup
;
1626 stringtok(ips
, ::arg()["dont-query"], ", ");
1627 L
<<Logger::Warning
<<"Will not send queries to: ";
1628 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
1629 g_dontQuery
->addMask(*i
);
1631 L
<<Logger::Warning
<<", ";
1632 L
<<Logger::Warning
<<*i
;
1634 L
<<Logger::Warning
<<endl
;
1637 g_quiet
=::arg().mustDo("quiet");
1638 if(::arg().mustDo("trace")) {
1639 SyncRes::setLog(true);
1640 ::arg().set("quiet")="no";
1644 RC
.d_followRFC2181
=::arg().mustDo("auth-can-lower-ttl");
1646 if(!::arg()["query-local-address6"].empty()) {
1647 SyncRes::s_doIPv6
=true;
1648 L
<<Logger::Error
<<"Enabling IPv6 transport for outgoing queries"<<endl
;
1651 SyncRes::s_maxnegttl
=::arg().asNum("max-negative-ttl");
1652 SyncRes::s_serverID
=::arg()["server-id"];
1653 if(SyncRes::s_serverID
.empty()) {
1655 gethostname(tmp
, sizeof(tmp
)-1);
1656 SyncRes::s_serverID
=tmp
;
1659 parseAuthAndForwards();
1661 g_stats
.remotes
.resize(::arg().asNum("remotes-ringbuffer-entries"));
1662 if(!g_stats
.remotes
.empty())
1663 memset(&g_stats
.remotes
[0], 0, g_stats
.remotes
.size() * sizeof(RecursorStats::remotes_t::value_type
));
1664 g_logCommonErrors
=::arg().mustDo("log-common-errors");
1666 makeUDPServerSockets();
1667 makeTCPServerSockets();
1670 if(::arg().mustDo("fork")) {
1672 L
<<Logger::Warning
<<"This is forked pid "<<getpid()<<endl
;
1676 MT
=new MTasker
<PacketID
,string
>(::arg().asNum("stack-size"));
1677 makeControlChannelSocket();
1680 L
<<Logger::Warning
<<"Done priming cache with root hints"<<endl
;
1682 if(::arg().mustDo("daemon")) {
1683 L
<<Logger::Warning
<<"Calling daemonize, going to background"<<endl
;
1684 L
.toConsole(Logger::Critical
);
1687 signal(SIGUSR1
,usr1Handler
);
1688 signal(SIGUSR2
,usr2Handler
);
1689 signal(SIGPIPE
,SIG_IGN
);
1692 g_fdm
=getMultiplexer();
1694 for(deferredAdd_t::const_iterator i
=deferredAdd
.begin(); i
!=deferredAdd
.end(); ++i
)
1695 g_fdm
->addReadFD(i
->first
, i
->second
);
1698 if(!::arg()["setgid"].empty())
1699 newgid
=Utility::makeGidNumeric(::arg()["setgid"]);
1701 if(!::arg()["setuid"].empty())
1702 newuid
=Utility::makeUidNumeric(::arg()["setuid"]);
1705 if (!::arg()["chroot"].empty()) {
1706 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
1707 L
<<Logger::Error
<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno
)<<", exiting"<<endl
;
1712 Utility::dropPrivs(newuid
, newgid
);
1713 g_fdm
->addReadFD(s_rcc
.d_fd
, handleRCC
); // control channel
1717 unsigned int maxTcpClients
=::arg().asNum("max-tcp-clients");
1718 g_tcpTimeout
=::arg().asNum("client-tcp-timeout");
1720 g_maxTCPPerClient
=::arg().asNum("max-tcp-per-client");
1723 bool listenOnTCP(true);
1726 while(MT
->schedule(g_now
.tv_sec
)); // housekeeping, let threads do their thing
1728 if(!(counter
%500)) {
1729 MT
->makeThread(houseKeeping
,0);
1733 typedef vector
<pair
<int, FDMultiplexer::funcparam_t
> > expired_t
;
1734 expired_t expired
=g_fdm
->getTimeouts(g_now
);
1736 for(expired_t::iterator i
=expired
.begin() ; i
!= expired
.end(); ++i
) {
1737 TCPConnection conn
=any_cast
<TCPConnection
>(i
->second
);
1738 if(g_logCommonErrors
)
1739 L
<<Logger::Warning
<<"Timeout from remote TCP client "<< conn
.remote
.toString() <<endl
;
1740 g_fdm
->removeReadFD(i
->first
);
1741 conn
.closeAndCleanup();
1751 Utility::gettimeofday(&g_now
, 0);
1755 if(TCPConnection::s_currentConnections
> maxTcpClients
) { // shutdown
1756 for(g_tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
1757 g_fdm
->removeReadFD(*i
);
1762 if(TCPConnection::s_currentConnections
<= maxTcpClients
) { // reenable
1763 for(g_tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
1764 g_fdm
->addReadFD(*i
, handleNewTCPQuestion
);
1771 void doWindowsServiceArguments(RecursorService
& recursor
)
1773 if(::arg().mustDo( "register-service" )) {
1774 if ( !recursor
.registerService( "The PowerDNS Recursor.", true )) {
1775 cerr
<< "Could not register service." << endl
;
1782 if ( ::arg().mustDo( "unregister-service" )) {
1783 recursor
.unregisterService();
1789 int main(int argc
, char **argv
)
1791 // HTimer mtimer("main");
1794 g_stats
.startupTime
=time(0);
1797 int ret
= EXIT_SUCCESS
;
1799 RecursorService service
;
1801 if(WSAStartup( MAKEWORD( 2, 2 ), &wsaData
)) {
1802 cerr
<<"Unable to initialize winsock\n";
1808 Utility::srandom(time(0));
1809 ::arg().set("stack-size","stack size per mthread")="200000";
1810 ::arg().set("soa-minimum-ttl","Don't change")="0";
1811 ::arg().set("soa-serial-offset","Don't change")="0";
1812 ::arg().set("no-shuffle","Don't change")="off";
1813 ::arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off";
1814 ::arg().set("local-port","port to listen on")="53";
1815 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
1816 ::arg().set("trace","if we should output heaps of logging")="off";
1817 ::arg().set("daemon","Operate as a daemon")="yes";
1818 ::arg().set("log-common-errors","If we should log rather common errors")="yes";
1819 ::arg().set("chroot","switch to chroot jail")="";
1820 ::arg().set("setgid","If set, change group id to this gid for more security")="";
1821 ::arg().set("setuid","If set, change user id to this uid for more security")="";
1823 ::arg().set("quiet","Suppress logging of questions and answers")="off";
1824 ::arg().setSwitch( "register-service", "Register the service" )= "no";
1825 ::arg().setSwitch( "unregister-service", "Unregister the service" )= "no";
1826 ::arg().setSwitch( "ntservice", "Run as service" )= "no";
1827 ::arg().setSwitch( "use-ntlog", "Use the NT logging facilities" )= "yes";
1828 ::arg().setSwitch( "use-logfile", "Use a log file" )= "no";
1829 ::arg().setSwitch( "logfile", "Filename of the log file" )= "recursor.log";
1831 ::arg().set("quiet","Suppress logging of questions and answers")="";
1832 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
1834 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR
;
1835 ::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR
;
1836 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
1837 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
1838 ::arg().set("query-local-address6","Source IPv6 address for sending queries")="";
1839 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
1840 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
1841 ::arg().set("hint-file", "If set, load root hints from this file")="";
1842 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="0";
1843 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
1844 ::arg().set("server-id", "Returned when queried for 'server.id' TXT, defaults to hostname")="";
1845 ::arg().set("remotes-ringbuffer-entries", "maximum number of packets to store statistics for")="0";
1846 ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Recursor "VERSION
" $Id$";
1847 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")="127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10";
1848 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")="127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10";
1849 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
1850 ::arg().set("fork", "If set, fork the daemon for possible double performance")="no";
1851 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
1852 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
1853 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
1854 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
1855 ::arg().set("forward-zones-file", "File with domain=ip pairs for forwarding")="";
1856 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
1857 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="";
1858 ::arg().set("auth-can-lower-ttl", "If we follow RFC 2181 to the letter, an authoritative server can lower the TTL of NS records")="off";
1859 ::arg().setSwitch( "ignore-rd-bit", "Assume each packet requires recursion, for compatability" )= "off";
1861 ::arg().setCmd("help","Provide a helpful message");
1862 ::arg().setCmd("version","Print version string ("VERSION
")");
1863 ::arg().setCmd("config","Output blank configuration");
1864 L
.toConsole(Logger::Info
);
1865 ::arg().laxParse(argc
,argv
); // do a lax parse
1867 string configname
=::arg()["config-dir"]+"/recursor.conf";
1868 cleanSlashes(configname
);
1870 if(!::arg().file(configname
.c_str()))
1871 L
<<Logger::Warning
<<"Unable to parse configuration file '"<<configname
<<"'"<<endl
;
1873 ::arg().parse(argc
,argv
);
1875 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
1877 if(::arg().mustDo("help")) {
1878 cerr
<<"syntax:"<<endl
<<endl
;
1879 cerr
<<::arg().helpstring(::arg()["help"])<<endl
;
1882 if(::arg().mustDo("version")) {
1883 cerr
<<"version: "VERSION
<<endl
;
1887 if(::arg().mustDo("config")) {
1888 cout
<<::arg().configstring()<<endl
;
1893 serviceMain(argc
, argv
);
1895 doWindowsServiceArguments(service
);
1897 RecursorService::instance()->start( argc
, argv
, ::arg().mustDo( "ntservice" ));
1901 catch(AhuException
&ae
) {
1902 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
1905 catch(exception
&e
) {
1906 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
1910 L
<<Logger::Error
<<"any other exception in main: "<<endl
;