]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/pdns_recursor.cc
move 'resolver.cc' to MOADNSParser, which allows us to rip out 'getAnswers' hideousit...
[thirdparty/pdns.git] / pdns / pdns_recursor.cc
CommitLineData
288f4aa9
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
22c012a8 3 Copyright (C) 2003 - 2006 PowerDNS.COM BV
288f4aa9
BH
4
5 This program is free software; you can redistribute it and/or modify
f28307ad
BH
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
288f4aa9
BH
8
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.
13
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
06bd9ccf 16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
288f4aa9 17*/
caa6eefa 18
705f31ae 19#ifndef WIN32
f7c1d4e3
BH
20# include <netdb.h>
21# include <unistd.h>
22#else
23 #include "ntservice.hh"
24 #include "recursorservice.hh"
705f31ae
BH
25#endif // WIN32
26
caa6eefa 27#include "utility.hh"
288f4aa9
BH
28#include <iostream>
29#include <errno.h>
30#include <map>
31#include <set>
97bb160b 32#include "recursor_cache.hh"
288f4aa9 33#include <stdio.h>
c75a6a9e 34#include <signal.h>
288f4aa9 35#include <stdlib.h>
c038218b 36
288f4aa9
BH
37#include "mtasker.hh"
38#include <utility>
288f4aa9
BH
39#include "arguments.hh"
40#include "syncres.hh"
88def049
BH
41#include <fcntl.h>
42#include <fstream>
5c633640
BH
43#include "sstuff.hh"
44#include <boost/tuple/tuple.hpp>
45#include <boost/tuple/tuple_comparison.hpp>
72df400f 46#include <boost/shared_array.hpp>
ea634573 47#include <boost/lexical_cast.hpp>
7f1fa77d 48#include <boost/function.hpp>
5605c067 49#include <boost/algorithm/string.hpp>
ea634573
BH
50#include "dnsparser.hh"
51#include "dnswriter.hh"
52#include "dnsrecords.hh"
f814d7c8 53#include "zoneparser-tng.hh"
1d5b3ce6 54#include "rec_channel.hh"
aaacf7f2 55#include "logger.hh"
c8ddb7c2 56#include "iputils.hh"
09e6702a 57#include "mplexer.hh"
c038218b 58#include "config.h"
1d5b3ce6 59
a2bfc3ff
BH
60#ifndef RECURSOR
61#include "statbag.hh"
62StatBag S;
63#endif
64
09e6702a
BH
65FDMultiplexer* g_fdm;
66unsigned int g_maxTCPPerClient;
67bool g_logCommonErrors;
33988bfb 68using namespace boost;
5c633640 69
27adc173 70#ifdef __FreeBSD__ // see cvstrac ticket #26
7f617eb9
BH
71#include <pthread.h>
72#include <semaphore.h>
73#endif
74
eefd15f9 75MemRecursorCache RC;
1d5b3ce6
BH
76RecursorStats g_stats;
77bool g_quiet;
c8ddb7c2 78NetmaskGroup* g_allowFrom;
eb5bae86 79NetmaskGroup* g_dontQuery;
88def049 80string s_programname="pdns_recursor";
0e7d73e9
BH
81typedef vector<int> g_tcpListenSockets_t;
82g_tcpListenSockets_t g_tcpListenSockets;
3159c9ef 83int g_tcpTimeout;
288f4aa9 84
ea634573 85struct DNSComboWriter {
c9e9e5e0 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)
ea634573
BH
87 {}
88 MOADNSParser d_mdp;
37d3f960 89 void setRemote(ComboAddress* sa)
ea634573 90 {
37d3f960 91 d_remote=*sa;
ea634573
BH
92 }
93
94 void setSocket(int sock)
95 {
96 d_socket=sock;
97 }
a1754c6a
BH
98
99 string getRemote() const
100 {
37d3f960 101 return d_remote.toString();
a1754c6a
BH
102 }
103
c9e9e5e0 104 struct timeval d_now;
37d3f960 105 ComboAddress d_remote;
ea634573
BH
106 bool d_tcp;
107 int d_socket;
108};
109
110
27adc173
BH
111#ifndef WIN32
112#ifndef __FreeBSD__
288f4aa9
BH
113extern "C" {
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;}
dcf9bd8f 119 pthread_t pthread_self(void){return (pthread_t) 0;}
98e05fce 120 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr){ return 0; }
dcf9bd8f
BH
121 int pthread_mutex_lock(pthread_mutex_t *mutex){ return 0; }
122 int pthread_mutex_unlock(pthread_mutex_t *mutex) { return 0; }
df38dbe8 123 int pthread_mutex_destroy(pthread_mutex_t *mutex) { return 0; }
288f4aa9 124}
27adc173 125#endif // __FreeBSD__
caa6eefa 126#endif // WIN32
288f4aa9 127
288f4aa9
BH
128ArgvMap &arg()
129{
130 static ArgvMap theArg;
131 return theArg;
132}
4ef015cd 133
09e6702a 134struct timeval g_now;
cd50f30d 135typedef vector<int> tcpserversocks_t;
5c633640 136
d2392145 137MT_t* MT; // the big MTasker
09e6702a
BH
138
139void handleTCPClientWritable(int fd, boost::any& var);
140
50c81227 141// -1 is error, 0 is timeout, 1 is success
5c633640
BH
142int asendtcp(const string& data, Socket* sock)
143{
144 PacketID pident;
145 pident.sock=sock;
146 pident.outMSG=data;
5c633640 147
09e6702a 148 g_fdm->addWriteFD(sock->getHandle(), handleTCPClientWritable, pident);
50c81227 149 string packet;
5c633640 150
9170fbaf
BH
151 int ret=MT->waitEvent(pident,&packet,1);
152 if(!ret || ret==-1) { // timeout
09e6702a 153 g_fdm->removeWriteFD(sock->getHandle());
5c633640 154 }
50c81227
BH
155 else if(packet.size() !=data.size()) { // main loop tells us what it sent out, or empty in case of an error
156 return -1;
157 }
9170fbaf 158 return ret;
5c633640
BH
159}
160
09e6702a
BH
161void handleTCPClientReadable(int fd, boost::any& var);
162
9170fbaf 163// -1 is error, 0 is timeout, 1 is success
5c633640 164int arecvtcp(string& data, int len, Socket* sock)
288f4aa9 165{
50c81227 166 data.clear();
5c633640
BH
167 PacketID pident;
168 pident.sock=sock;
169 pident.inNeeded=len;
09e6702a 170 g_fdm->addReadFD(sock->getHandle(), handleTCPClientReadable, pident);
5c633640 171
9170fbaf
BH
172 int ret=MT->waitEvent(pident,&data,1);
173 if(!ret || ret==-1) { // timeout
09e6702a 174 g_fdm->removeReadFD(sock->getHandle());
288f4aa9 175 }
50c81227
BH
176 else if(data.empty()) {// error, EOF or other
177 return -1;
178 }
179
9170fbaf 180 return ret;
288f4aa9
BH
181}
182
998a4334 183// returns -1 for errors which might go away, throws for ones that won't
996c89cc 184int makeClientSocket(int family)
4ef015cd 185{
705f31ae 186 int ret=(int)socket(family, SOCK_DGRAM, 0);
998a4334
BH
187 if(ret < 0 && errno==EMFILE) // this is not a catastrophic error
188 return ret;
189
4ef015cd
BH
190 if(ret<0)
191 throw AhuException("Making a socket for resolver: "+stringerror());
192
996c89cc
BH
193 static optional<ComboAddress> sin4;
194 if(!sin4) {
195 sin4=ComboAddress(::arg()["query-local-address"]);
4ef015cd 196 }
996c89cc
BH
197 static optional<ComboAddress> sin6;
198 if(!sin6) {
199 if(!::arg()["query-local-address6"].empty())
200 sin6=ComboAddress(::arg()["query-local-address6"]);
201 }
202
998a4334 203 int tries=10;
4ef015cd 204 while(--tries) {
998a4334
BH
205 uint16_t port=1025+Utility::random()%64510;
206 if(tries==1) // fall back to kernel 'random'
207 port=0;
78983f94 208
996c89cc
BH
209 if(family==AF_INET) {
210 sin4->sin4.sin_port = htons(port);
211
779828c4 212 if (::bind(ret, (struct sockaddr *)&*sin4, sin4->getSocklen()) >= 0)
996c89cc
BH
213 break;
214 }
215 else {
216 sin6->sin6.sin6_port = htons(port);
217
779828c4 218 if (::bind(ret, (struct sockaddr *)&*sin6, sin6->getSocklen()) >= 0)
996c89cc
BH
219 break;
220 }
4ef015cd
BH
221 }
222 if(!tries)
223 throw AhuException("Resolver binding to local query client socket: "+stringerror());
224
225 Utility::setNonBlocking(ret);
226 return ret;
227}
228
09e6702a
BH
229void handleUDPServerResponse(int fd, boost::any&);
230
4ef015cd
BH
231// you can ask this class for a UDP socket to send a query from
232// this socket is not yours, don't even think about deleting it
233// but after you call 'returnSocket' on it, don't assume anything anymore
234class UDPClientSocks
235{
4ef015cd
BH
236 unsigned int d_numsocks;
237 unsigned int d_maxsocks;
998a4334 238
4ef015cd 239public:
998a4334 240 UDPClientSocks() : d_numsocks(0), d_maxsocks(5000)
4ef015cd
BH
241 {
242 }
243
996c89cc 244 typedef set<int> socks_t;
4ef015cd
BH
245 socks_t d_socks;
246
998a4334 247 // returning -1 means: temporary OS error (ie, out of files)
996c89cc 248 int getSocket(uint16_t family)
4ef015cd 249 {
996c89cc
BH
250 int fd=makeClientSocket(family);
251 if(fd < 0) // temporary error - receive exception otherwise
998a4334
BH
252 return -1;
253
996c89cc 254 d_socks.insert(fd);
998a4334 255 d_numsocks++;
996c89cc 256 return fd;
4ef015cd
BH
257 }
258
095c3045
BH
259 void returnSocket(int fd)
260 {
261 socks_t::iterator i=d_socks.find(fd);
34801ab1
BH
262 if(i==d_socks.end()) {
263 throw AhuException("Trying to return a socket (fd="+lexical_cast<string>(fd)+") not in the pool");
264 }
095c3045
BH
265 returnSocket(i);
266 }
267
4ef015cd 268 // return a socket to the pool, or simply erase it
095c3045 269 void returnSocket(socks_t::iterator& i)
4ef015cd 270 {
600fc20b
BH
271 if(i==d_socks.end()) {
272 throw AhuException("Trying to return a socket not in the pool");
273 }
80baf329
BH
274 try {
275 g_fdm->removeReadFD(*i);
276 }
277 catch(FDMultiplexerException& e) {
278 // we sometimes return a socket that has not yet been assigned to g_fdm
279 }
c038218b 280 Utility::closesocket(*i);
998a4334
BH
281
282 d_socks.erase(i++);
283 --d_numsocks;
4ef015cd 284 }
b23b8614 285} g_udpclientsocks;
4ef015cd 286
288f4aa9
BH
287
288/* these two functions are used by LWRes */
34801ab1 289// -2 is OS error, -1 is error that depends on the remote, > 0 is success
787e5eab
BH
290int asendto(const char *data, int len, int flags,
291 const ComboAddress& toaddr, uint16_t id, const string& domain, uint16_t qtype, int* fd)
288f4aa9 292{
34801ab1
BH
293
294 PacketID pident;
787e5eab
BH
295 pident.domain = domain;
296 pident.remote = toaddr;
297 pident.type = qtype;
34801ab1
BH
298
299 // see if there is an existing outstanding request we can chain on to, using partial equivalence function
300 pair<MT_t::waiters_t::iterator, MT_t::waiters_t::iterator> chain=MT->d_waiters.equal_range(pident, PacketIDBirthdayCompare());
301
302 for(; chain.first != chain.second; chain.first++) {
303 if(chain.first->key.fd > -1) { // don't chain onto existing chained waiter!
304 // cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
305 // cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
306 // <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
307
308 chain.first->key.chain.insert(id); // we can chain
309 *fd=-1; // gets used in waitEvent / sendEvent later on
310 return 1;
311 }
312 }
313
996c89cc 314 *fd=g_udpclientsocks.getSocket(toaddr.sin4.sin_family);
998a4334
BH
315 if(*fd < 0)
316 return -2;
34801ab1 317
998a4334
BH
318 pident.fd=*fd;
319 pident.id=id;
998a4334 320
996c89cc 321 int ret=connect(*fd, (struct sockaddr*)(&toaddr), toaddr.getSocklen());
7f240371 322 if(ret < 0) {
8f12cea9 323 g_udpclientsocks.returnSocket(*fd);
7f240371
BH
324 if(errno==ENETUNREACH) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
325 return -2;
998a4334 326 return ret;
7f240371 327 }
998a4334
BH
328
329 g_fdm->addReadFD(*fd, handleUDPServerResponse, pident);
7302ed0a
BH
330 ret=send(*fd, data, len, 0);
331 if(ret < 0)
332 g_udpclientsocks.returnSocket(*fd);
333 return ret;
288f4aa9
BH
334}
335
9170fbaf 336// -1 is error, 0 is timeout, 1 is success
787e5eab 337int arecvfrom(char *data, int len, int flags, const ComboAddress& fromaddr, int *d_len,
f6c254c1 338 uint16_t id, const string& domain, uint16_t qtype, int fd, unsigned int now)
288f4aa9 339{
0d5f0a9f
BH
340 static optional<unsigned int> nearMissLimit;
341 if(!nearMissLimit)
342 nearMissLimit=::arg().asNum("spoof-nearmiss-max");
343
288f4aa9 344 PacketID pident;
4ef015cd 345 pident.fd=fd;
288f4aa9 346 pident.id=id;
0d5f0a9f 347 pident.domain=domain;
787e5eab 348 pident.type = qtype;
996c89cc 349 pident.remote=fromaddr;
b636533b 350
288f4aa9 351 string packet;
f6c254c1 352 int ret=MT->waitEvent(pident, &packet, 1, now);
34801ab1 353
9170fbaf 354 if(ret > 0) {
996c89cc 355 if(packet.empty()) // means "error"
998a4334 356 return -1;
998a4334 357
705f31ae 358 *d_len=(int)packet.size();
9170fbaf 359 memcpy(data,packet.c_str(),min(len,*d_len));
0d5f0a9f 360 if(*nearMissLimit && pident.nearMisses > *nearMissLimit) {
996c89cc 361 L<<Logger::Error<<"Too many ("<<pident.nearMisses<<" > "<<*nearMissLimit<<") bogus answers for '"<<domain<<"' from "<<fromaddr.toString()<<", assuming spoof attempt."<<endl;
0d5f0a9f 362 g_stats.spoofCount++;
35ce8576
BH
363 return -1;
364 }
288f4aa9 365 }
09e6702a 366 else {
34801ab1
BH
367 if(fd >= 0)
368 g_udpclientsocks.returnSocket(fd);
09e6702a 369 }
9170fbaf 370 return ret;
288f4aa9
BH
371}
372
aa4e4cbf 373void setBuffer(int fd, int optname, uint32_t size)
ce8deb27 374{
9b356afc 375 uint32_t psize=0;
91e4ecf3 376 socklen_t len=sizeof(psize);
9b356afc 377
aa4e4cbf 378 if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
a19fb8e8 379 L<<Logger::Error<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
9b356afc
BH
380 return;
381 }
382
aa4e4cbf 383 if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0 )
a19fb8e8 384 L<<Logger::Error<<"Warning: unable to raise socket buffer size to "<<size<<": "<<strerror(errno)<<endl;
ce8deb27
BH
385}
386
387
aa4e4cbf
BH
388static void setReceiveBuffer(int fd, uint32_t size)
389{
390 setBuffer(fd, SO_RCVBUF, size);
391}
392
393static void setSendBuffer(int fd, uint32_t size)
394{
395 setBuffer(fd, SO_SNDBUF, size);
396}
397
b23b8614 398
88def049
BH
399static void writePid(void)
400{
2e3d8a19 401 string fname=::arg()["socket-dir"]+"/"+s_programname+".pid";
88def049
BH
402 ofstream of(fname.c_str());
403 if(of)
705f31ae 404 of<< Utility::getpid() <<endl;
88def049 405 else
705f31ae 406 L<<Logger::Error<<"Requested to write pid for "<<Utility::getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl;
88def049
BH
407}
408
bdf40704 409void primeHints(void)
288f4aa9
BH
410{
411 // prime root cache
288f4aa9 412 set<DNSResourceRecord>nsset;
f814d7c8 413
2e3d8a19 414 if(::arg()["hint-file"].empty()) {
f814d7c8
BH
415 static 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", "192.112.36.4", "128.63.2.53",
416 "192.36.148.17","192.58.128.30", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
417 DNSResourceRecord arr, nsrr;
418 arr.qtype=QType::A;
419 arr.ttl=time(0)+3600000;
420 nsrr.qtype=QType::NS;
421 nsrr.ttl=time(0)+3600000;
422
5456e605 423 for(char c='a';c<='m';++c) {
f814d7c8 424 static char templ[40];
7738a23f 425 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
f814d7c8
BH
426 *templ=c;
427 arr.qname=nsrr.content=templ;
5456e605 428 arr.content=ips[c-'a'];
f814d7c8
BH
429 set<DNSResourceRecord> aset;
430 aset.insert(arr);
61973281 431 RC.replace(time(0), string(templ), QType(QType::A), aset, true); // auth, nuke it all
f814d7c8
BH
432
433 nsset.insert(nsrr);
434 }
435 }
436 else {
2e3d8a19 437 ZoneParserTNG zpt(::arg()["hint-file"]);
f814d7c8 438 DNSResourceRecord rr;
ea634573 439 set<DNSResourceRecord> aset;
288f4aa9 440
f814d7c8 441 while(zpt.get(rr)) {
f814d7c8
BH
442 rr.ttl+=time(0);
443 if(rr.qtype.getCode()==QType::A) {
444 set<DNSResourceRecord> aset;
445 aset.insert(rr);
61973281 446 RC.replace(time(0), rr.qname, QType(QType::A), aset, true); // auth, etc see above
f814d7c8
BH
447 }
448 if(rr.qtype.getCode()==QType::NS) {
e2e2c5d8 449 rr.content=toLower(rr.content);
f814d7c8
BH
450 nsset.insert(rr);
451 }
452 }
288f4aa9 453 }
61973281 454 RC.replace(time(0),".", QType(QType::NS), nsset, true); // and stuff in the cache (auth)
288f4aa9
BH
455}
456
37d3f960 457map<ComboAddress, uint32_t> g_tcpClientCounts;
0e9d9ce2
BH
458
459struct TCPConnection
460{
461 int fd;
7f1fa77d 462 enum stateenum {BYTE0, BYTE1, GETQUESTION, DONE} state;
0e9d9ce2
BH
463 int qlen;
464 int bytesread;
37d3f960 465 ComboAddress remote;
0e9d9ce2
BH
466 char data[65535];
467 time_t startTime;
468
879b3f70 469 static void closeAndCleanup(int fd, const ComboAddress& remote)
0e9d9ce2 470 {
705f31ae 471 Utility::closesocket(fd);
37d3f960
BH
472 if(!g_tcpClientCounts[remote]--)
473 g_tcpClientCounts.erase(remote);
6dcd28c3 474 s_currentConnections--;
0e9d9ce2 475 }
879b3f70
BH
476 void closeAndCleanup()
477 {
478 closeAndCleanup(fd, remote);
479 }
6dcd28c3 480 static unsigned int s_currentConnections; //!< total number of current TCP connections
0e9d9ce2
BH
481};
482
6dcd28c3 483unsigned int TCPConnection::s_currentConnections;
879b3f70 484void handleRunningTCPQuestion(int fd, boost::any& var);
6dcd28c3 485
288f4aa9
BH
486void startDoResolve(void *p)
487{
7b1469bb 488 DNSComboWriter* dc=(DNSComboWriter *)p;
b23b8614 489
288f4aa9 490 try {
10321a98
BH
491 uint16_t maxudpsize=512;
492 MOADNSParser::EDNSOpts edo;
493 if(dc->d_mdp.getEDNSOpts(&edo)) {
494 maxudpsize=edo.d_packetsize;
495 }
09e6702a 496
ea634573 497 vector<DNSResourceRecord> ret;
ea634573 498 vector<uint8_t> packet;
b23b8614
BH
499
500 DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
ea634573
BH
501
502 pw.getHeader()->aa=0;
503 pw.getHeader()->ra=1;
c154c8a4 504 pw.getHeader()->qr=1;
ea634573 505 pw.getHeader()->id=dc->d_mdp.d_header.id;
10321a98 506 pw.getHeader()->rd=dc->d_mdp.d_header.rd;
ea634573 507
c9e9e5e0 508 SyncRes sr(dc->d_now);
1d5b3ce6 509 if(!g_quiet)
8a63d3ce
BH
510 L<<Logger::Error<<"["<<MT->getTid()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<<dc->d_mdp.d_qname<<"|"
511 <<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<"' from "<<dc->getRemote()<<endl;
c75a6a9e 512
fededf47 513 sr.setId(MT->getTid());
67828389 514 if(!dc->d_mdp.d_header.rd)
c836dc19
BH
515 sr.setCacheOnly();
516
a9af3782 517 int res=sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
b23b8614 518
1d5b3ce6 519 if(res<0) {
ea634573 520 pw.getHeader()->rcode=RCode::ServFail;
bec87d21 521 // no commit here, because no record
1d5b3ce6
BH
522 g_stats.servFails++;
523 }
288f4aa9 524 else {
ea634573 525 pw.getHeader()->rcode=res;
1d5b3ce6 526 switch(res) {
5e4a2466
BH
527 case RCode::ServFail:
528 g_stats.servFails++;
529 break;
1d5b3ce6
BH
530 case RCode::NXDomain:
531 g_stats.nxDomains++;
532 break;
533 case RCode::NoError:
534 g_stats.noErrors++;
535 break;
536 }
537
c154c8a4 538 if(ret.size()) {
e67e250f 539 shuffle(ret);
b23b8614
BH
540
541 for(vector<DNSResourceRecord>::const_iterator i=ret.begin(); i!=ret.end(); ++i) {
542 pw.startRecord(i->qname, i->qtype.getCode(), i->ttl, i->qclass, (DNSPacketWriter::Place)i->d_place);
7b1469bb 543
b23b8614
BH
544 if(i->qtype.getCode() == QType::A) { // blast out A record w/o doing whole dnswriter thing
545 uint32_t ip=0;
546 IpToU32(i->content, &ip);
547 pw.xfr32BitInt(htonl(ip));
548 } else {
549 shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(i->qtype.getCode(), i->qclass, i->content));
550 drc->toPacket(pw);
551 }
10321a98
BH
552 if(!dc->d_tcp && pw.size() > maxudpsize) {
553 pw.rollback();
1791e3c4
BH
554 if(i->d_place==DNSResourceRecord::ANSWER) // only truncate if we actually omitted parts of the answer
555 pw.getHeader()->tc=1;
10321a98
BH
556 goto sendit; // need to jump over pw.commit
557 }
c154c8a4 558 }
b23b8614 559
c154c8a4 560 pw.commit();
ea634573 561 }
288f4aa9 562 }
10321a98 563 sendit:;
ea634573 564 if(!dc->d_tcp) {
c038218b 565 sendto(dc->d_socket, (const char*)&*packet.begin(), packet.size(), 0, (struct sockaddr *)(&dc->d_remote), dc->d_remote.getSocklen());
feccc9fc 566 }
9c495589
BH
567 else {
568 char buf[2];
ea634573
BH
569 buf[0]=packet.size()/256;
570 buf[1]=packet.size()%256;
feccc9fc 571
c038218b 572 Utility::iovec iov[2];
feccc9fc 573
ea634573
BH
574 iov[0].iov_base=(void*)buf; iov[0].iov_len=2;
575 iov[1].iov_base=(void*)&*packet.begin(); iov[1].iov_len = packet.size();
feccc9fc 576
c038218b 577 int ret=Utility::writev(dc->d_socket, iov, 2);
0e9d9ce2 578 bool hadError=true;
feccc9fc 579
0e9d9ce2
BH
580 if(ret == 0)
581 L<<Logger::Error<<"EOF writing TCP answer to "<<dc->getRemote()<<endl;
582 else if(ret < 0 )
583 L<<Logger::Error<<"Error writing TCP answer to "<<dc->getRemote()<<": "<< strerror(errno) <<endl;
ea634573 584 else if((unsigned int)ret != 2 + packet.size())
aa4e4cbf 585 L<<Logger::Error<<"Oops, partial answer sent to "<<dc->getRemote()<<" for "<<dc->d_mdp.d_qname<<" (size="<< (2 + packet.size()) <<", sent "<<ret<<")"<<endl;
0e9d9ce2
BH
586 else
587 hadError=false;
09e6702a
BH
588
589 // update tcp connection status, either by closing or moving to 'BYTE0'
590
591 if(hadError) {
592 g_fdm->removeReadFD(dc->d_socket);
879b3f70 593 TCPConnection::closeAndCleanup(dc->d_socket, dc->d_remote);
09e6702a 594 }
a6ae6414 595 else {
879b3f70
BH
596 TCPConnection tc;
597 tc.fd=dc->d_socket;
598 tc.state=TCPConnection::BYTE0;
599 tc.remote=dc->d_remote;
600 Utility::gettimeofday(&g_now, 0); // needs to be updated
601 tc.startTime=g_now.tv_sec;
602 g_fdm->addReadFD(tc.fd, handleRunningTCPQuestion, tc);
603 g_fdm->setReadTTD(tc.fd, g_now, g_tcpTimeout);
0e9d9ce2 604 }
9c495589 605 }
b23b8614 606
1d5b3ce6 607 if(!g_quiet) {
8a63d3ce 608 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);
ea634573 609 L<<"': "<<ntohs(pw.getHeader()->ancount)<<" answers, "<<ntohs(pw.getHeader()->arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<<
5c633640 610 sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, "<<sr.d_tcpoutqueries<<" tcp connections, rcode="<<res<<endl;
c75a6a9e 611 }
b23b8614 612
eefd15f9 613 sr.d_outqueries ? RC.cacheMisses++ : RC.cacheHits++;
fe213470
BH
614 float spent=makeFloat(sr.d_now-dc->d_now);
615 if(spent < 0.001)
616 g_stats.answers0_1++;
617 else if(spent < 0.010)
618 g_stats.answers1_10++;
619 else if(spent < 0.1)
620 g_stats.answers10_100++;
621 else if(spent < 1.0)
622 g_stats.answers100_1000++;
623 else
624 g_stats.answersSlow++;
625
574af7ea 626 uint64_t newLat=(uint64_t)(spent*1000000);
87b8e43a
BH
627 if(newLat < 1000000) // outliers of several minutes exist..
628 g_stats.avgLatencyUsec=(uint64_t)((1-0.0001)*g_stats.avgLatencyUsec + 0.0001*newLat);
b23b8614 629
ea634573 630 delete dc;
288f4aa9
BH
631 }
632 catch(AhuException &ae) {
c836dc19 633 L<<Logger::Error<<"startDoResolve problem: "<<ae.reason<<endl;
288f4aa9 634 }
7b1469bb
BH
635 catch(MOADNSException& e) {
636 L<<Logger::Error<<"DNS parser error: "<<dc->d_mdp.d_qname<<", "<<e.what()<<endl;
637 }
c154c8a4
BH
638 catch(exception& e) {
639 L<<Logger::Error<<"STL error: "<<e.what()<<endl;
640 }
288f4aa9 641 catch(...) {
c836dc19 642 L<<Logger::Error<<"Any other exception in a resolver context"<<endl;
288f4aa9
BH
643 }
644}
645
1d5b3ce6
BH
646RecursorControlChannel s_rcc;
647
648void makeControlChannelSocket()
649{
41f7a068
BH
650 string sockname=::arg()["socket-dir"]+"/pdns_recursor.controlsocket";
651 if(::arg().mustDo("fork")) {
705f31ae 652 sockname+="."+lexical_cast<string>(Utility::getpid());
41f7a068
BH
653 L<<Logger::Warning<<"Forked control socket name: "<<sockname<<endl;
654 }
655 s_rcc.listen(sockname);
1d5b3ce6
BH
656}
657
09e6702a
BH
658void handleRunningTCPQuestion(int fd, boost::any& var)
659{
0b18b22e 660 TCPConnection* conn=any_cast<TCPConnection>(&var);
c038218b 661
879b3f70 662 if(conn->state==TCPConnection::BYTE0) {
c038218b 663 int bytes=recv(conn->fd, conn->data, 2, 0);
09e6702a 664 if(bytes==1)
667f7e60 665 conn->state=TCPConnection::BYTE1;
09e6702a 666 if(bytes==2) {
a0aa4f64 667 conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
667f7e60
BH
668 conn->bytesread=0;
669 conn->state=TCPConnection::GETQUESTION;
09e6702a
BH
670 }
671 if(!bytes || bytes < 0) {
667f7e60 672 TCPConnection tmp(*conn);
09e6702a 673 g_fdm->removeReadFD(fd);
6dcd28c3 674 tmp.closeAndCleanup();
09e6702a
BH
675 return;
676 }
677 }
667f7e60 678 else if(conn->state==TCPConnection::BYTE1) {
a0aa4f64 679 int bytes=recv(conn->fd, conn->data+1, 1, 0);
09e6702a 680 if(bytes==1) {
667f7e60 681 conn->state=TCPConnection::GETQUESTION;
a0aa4f64 682 conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1];
667f7e60 683 conn->bytesread=0;
09e6702a
BH
684 }
685 if(!bytes || bytes < 0) {
686 if(g_logCommonErrors)
667f7e60
BH
687 L<<Logger::Error<<"TCP client "<< conn->remote.toString() <<" disconnected after first byte"<<endl;
688 TCPConnection tmp(*conn);
09e6702a 689 g_fdm->removeReadFD(fd);
6dcd28c3 690 tmp.closeAndCleanup(); // conn loses validity here..
09e6702a
BH
691 return;
692 }
693 }
667f7e60 694 else if(conn->state==TCPConnection::GETQUESTION) {
a0aa4f64 695 int bytes=recv(conn->fd, conn->data + conn->bytesread, conn->qlen - conn->bytesread, 0);
09e6702a 696 if(!bytes || bytes < 0) {
667f7e60
BH
697 L<<Logger::Error<<"TCP client "<< conn->remote.toString() <<" disconnected while reading question body"<<endl;
698 TCPConnection tmp(*conn);
09e6702a 699 g_fdm->removeReadFD(fd);
6dcd28c3 700 tmp.closeAndCleanup(); // conn loses validity here..
09e6702a
BH
701
702 return;
703 }
667f7e60
BH
704 conn->bytesread+=bytes;
705 if(conn->bytesread==conn->qlen) {
879b3f70
BH
706 TCPConnection tconn(*conn);
707 g_fdm->removeReadFD(fd); // should no longer awake ourselves when there is data to read
708
09e6702a
BH
709 DNSComboWriter* dc=0;
710 try {
879b3f70 711 dc=new DNSComboWriter(tconn.data, tconn.qlen, g_now);
09e6702a
BH
712 }
713 catch(MOADNSException &mde) {
714 g_stats.clientParseError++;
84e66a59
BH
715 if(g_logCommonErrors)
716 L<<Logger::Error<<"Unable to parse packet from TCP client "<< tconn.remote.toString() <<endl;
879b3f70 717 tconn.closeAndCleanup();
09e6702a
BH
718 return;
719 }
720
879b3f70 721 dc->setSocket(tconn.fd);
09e6702a 722 dc->d_tcp=true;
879b3f70 723 dc->setRemote(&tconn.remote);
879b3f70
BH
724 if(dc->d_mdp.d_header.qr) {
725 delete dc;
09e6702a 726 L<<Logger::Error<<"Ignoring answer on server socket!"<<endl;
879b3f70
BH
727 tconn.closeAndCleanup();
728 return;
729 }
09e6702a
BH
730 else {
731 ++g_stats.qcounter;
732 ++g_stats.tcpqcounter;
612bc398 733 MT->makeThread(startDoResolve, dc); // deletes dc
09e6702a
BH
734 return;
735 }
736 }
737 }
738}
739
6dcd28c3 740//! Handle new incoming TCP connection
09e6702a
BH
741void handleNewTCPQuestion(int fd, boost::any& )
742{
37d3f960 743 ComboAddress addr;
09e6702a 744 socklen_t addrlen=sizeof(addr);
705f31ae 745 int newsock=(int)accept(fd, (struct sockaddr*)&addr, &addrlen);
09e6702a 746 if(newsock>0) {
a9af3782 747 g_stats.addRemote(addr);
09e6702a 748 if(g_allowFrom && !g_allowFrom->match(&addr)) {
2914b022
BH
749 if(!g_quiet)
750 L<<Logger::Error<<"["<<MT->getTid()<<"] dropping TCP query from "<<addr.toString()<<", address not matched by allow-from"<<endl;
751
09e6702a 752 g_stats.unauthorizedTCP++;
705f31ae 753 Utility::closesocket(newsock);
09e6702a
BH
754 return;
755 }
756
37d3f960 757 if(g_maxTCPPerClient && g_tcpClientCounts.count(addr) && g_tcpClientCounts[addr] >= g_maxTCPPerClient) {
09e6702a 758 g_stats.tcpClientOverflow++;
705f31ae 759 Utility::closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
09e6702a
BH
760 return;
761 }
37d3f960 762 g_tcpClientCounts[addr]++;
09e6702a
BH
763 Utility::setNonBlocking(newsock);
764 TCPConnection tc;
765 tc.fd=newsock;
766 tc.state=TCPConnection::BYTE0;
767 tc.remote=addr;
768 tc.startTime=g_now.tv_sec;
6dcd28c3 769 TCPConnection::s_currentConnections++;
09e6702a 770 g_fdm->addReadFD(tc.fd, handleRunningTCPQuestion, tc);
c038218b 771
0bff046b 772 struct timeval now;
c038218b 773 Utility::gettimeofday(&now, 0);
3159c9ef 774 g_fdm->setReadTTD(tc.fd, now, g_tcpTimeout);
09e6702a
BH
775 }
776}
2914b022 777
b23b8614
BH
778void questionExpand(const char* packet, uint16_t len, char* qname, int maxlen, uint16_t& type)
779{
780 type=0;
781 const unsigned char* end=(const unsigned char*)packet+len;
782 unsigned char* lbegin=(unsigned char*)packet+12;
783 unsigned char* pos=lbegin;
784 unsigned char labellen;
785
786 // 3www4ds9a2nl0
787 char *dst=qname;
788 char* lend=dst + maxlen;
789
790 if(!*pos)
791 *dst++='.';
792
793 while((labellen=*pos++) && pos < end) { // "scan and copy"
794 if(dst >= lend)
795 throw runtime_error("Label length exceeded destination length");
796 for(;labellen;--labellen)
797 *dst++ = *pos++;
798 *dst++='.';
799 }
800 *dst=0;
801
802 if(pos + labellen + 2 <= end) // is this correct XXX FIXME?
803 type=(*pos)*256 + *(pos+1);
804
805
806 // cerr<<"Returning: '"<< string(tmp+1, pos) <<"'\n";
807}
808
809string questionExpand(const char* packet, uint16_t len, uint16_t& type)
810{
811 char tmp[512];
812 questionExpand(packet, len, tmp, sizeof(tmp), type);
813 return tmp;
814}
815
5db529f8
BH
816void handleNewUDPQuestion(int fd, boost::any& var)
817{
a9af3782 818 int len;
5db529f8
BH
819 char data[1500];
820 ComboAddress fromaddr;
821 socklen_t addrlen=sizeof(fromaddr);
b23b8614 822 uint64_t tsc1, tsc2;
5db529f8 823
a9af3782 824 if((len=recvfrom(fd, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen)) >= 0) {
b23b8614 825 RDTSC(tsc1);
a9af3782 826 g_stats.addRemote(fromaddr);
b23b8614 827
5db529f8 828 if(g_allowFrom && !g_allowFrom->match(&fromaddr)) {
2914b022
BH
829 if(!g_quiet)
830 L<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toString()<<", address not matched by allow-from"<<endl;
831
5db529f8 832 g_stats.unauthorizedUDP++;
a9af3782 833 return;
5db529f8 834 }
5db529f8 835 try {
b23b8614 836 dnsheader* dh=(dnsheader*)data;
5db529f8 837
b23b8614 838 if(dh->qr) {
5db529f8 839 if(g_logCommonErrors)
b23b8614 840 L<<Logger::Error<<"Ignoring answer from "<<fromaddr.toString()<<" on server socket!"<<endl;
5db529f8
BH
841 }
842 else {
843 ++g_stats.qcounter;
b23b8614
BH
844 uint16_t type;
845 char qname[256];
0ba0f794
BH
846 try {
847 questionExpand(data, len, qname, sizeof(qname), type);
848 }
849 catch(exception &e)
850 {
851 throw MOADNSException(e.what());
852 }
b23b8614
BH
853
854 // must all be same length answers right now!
855 if((type==QType::A || type==QType::AAAA) && dh->arcount==0 && dh->ancount==0 && dh->nscount ==0 && ntohs(dh->qdcount)==1 ) {
856 char *record[10];
857 uint16_t rlen[10];
858 uint32_t ttd[10];
859 int count;
860 if((count=RC.getDirect(g_now.tv_sec, qname, QType(type), ttd, record, rlen))) {
861 if(len + count*(sizeof(dnsrecordheader) + 2 + rlen[0]) > 512)
862 goto slow;
863
864 random_shuffle(record, &record[count]);
865 dh->qr=1;
866 dh->ra=1;
867 dh->ancount=ntohs(count);
868 for(int n=0; n < count ; ++n) {
869 memcpy(data+len, "\xc0\x0c", 2); // answer label pointer
870 len+=2;
871 struct dnsrecordheader drh;
872 drh.d_type=htons(type);
873 drh.d_class=htons(1);
874 drh.d_ttl=htonl(ttd[n] - g_now.tv_sec);
875 drh.d_clen=htons(rlen[n]);
876 memcpy(data+len, &drh, sizeof(drh));
877 len+=sizeof(drh);
878 memcpy(data+len, record[n], rlen[n]);
879 len+=rlen[n];
880 }
881 RDTSC(tsc2);
882 g_stats.shunted++;
883 sendto(fd, data, len, 0, (struct sockaddr *)(&fromaddr), fromaddr.getSocklen());
0ba0f794 884// cerr<<"shunted: " << (tsc2-tsc1) / 3000.0 << endl;
b23b8614
BH
885 return;
886 }
887 }
0ba0f794
BH
888 else {
889 if(type!=QType::A && type!=QType::AAAA)
890 g_stats.noShuntWrongType++;
891 else
892 g_stats.noShuntWrongQuestion++;
893 }
b23b8614
BH
894 slow:
895 DNSComboWriter* dc = new DNSComboWriter(data, len, g_now);
5db529f8 896 dc->setSocket(fd);
b23b8614
BH
897 dc->setRemote(&fromaddr);
898
5db529f8 899 dc->d_tcp=false;
b23b8614 900
612bc398 901 MT->makeThread(startDoResolve, (void*) dc); // deletes dc
5db529f8
BH
902 }
903 }
904 catch(MOADNSException& mde) {
905 g_stats.clientParseError++;
84e66a59
BH
906 if(g_logCommonErrors)
907 L<<Logger::Error<<"Unable to parse packet from remote UDP client "<<fromaddr.toString() <<": "<<mde.what()<<endl;
5db529f8
BH
908 }
909 }
910}
911
912typedef vector<pair<int, function< void(int, any&) > > > deferredAdd_t;
913deferredAdd_t deferredAdd;
914
f28307ad 915void makeTCPServerSockets()
9c495589 916{
37d3f960 917 int fd;
f28307ad 918 vector<string>locals;
2e3d8a19 919 stringtok(locals,::arg()["local-address"]," ,");
9c495589 920
f28307ad
BH
921 if(locals.empty())
922 throw AhuException("No local address specified");
923
f28307ad 924 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
32252594
BH
925 ServiceTuple st;
926 st.port=::arg().asNum("local-port");
927 parseService(*i, st);
928
929 ComboAddress sin;
930
f28307ad 931 memset((char *)&sin,0, sizeof(sin));
37d3f960 932 sin.sin4.sin_family = AF_INET;
32252594 933 if(!IpToU32(st.host, (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
37d3f960 934 sin.sin6.sin6_family = AF_INET6;
32252594
BH
935 if(Utility::inet_pton(AF_INET6, st.host.c_str(), &sin.sin6.sin6_addr) <= 0)
936 throw AhuException("Unable to resolve local address for TCP server on '"+ st.host +"'");
37d3f960
BH
937 }
938
939 fd=socket(sin.sin6.sin6_family, SOCK_STREAM, 0);
940 if(fd<0)
941 throw AhuException("Making a TCP server socket for resolver: "+stringerror());
f28307ad
BH
942
943 int tmp=1;
37d3f960 944 if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
f28307ad 945 L<<Logger::Error<<"Setsockopt failed for TCP listening socket"<<endl;
c8ddb7c2 946 exit(1);
f28307ad
BH
947 }
948
c8ddb7c2 949#ifdef TCP_DEFER_ACCEPT
37d3f960
BH
950 if(setsockopt(fd, SOL_TCP,TCP_DEFER_ACCEPT,(char*)&tmp,sizeof tmp) >= 0) {
951 if(i==locals.begin())
952 L<<Logger::Error<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl;
c8ddb7c2
BH
953 }
954#endif
955
32252594 956 sin.sin4.sin_port = htons(st.port);
37d3f960
BH
957 int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
958 if (::bind(fd, (struct sockaddr *)&sin, socklen )<0)
32252594 959 throw AhuException("Binding TCP server socket for "+ st.host +": "+stringerror());
f28307ad 960
37d3f960
BH
961 Utility::setNonBlocking(fd);
962 setSendBuffer(fd, 65000);
963 listen(fd, 128);
5db529f8 964 deferredAdd.push_back(make_pair(fd, handleNewTCPQuestion));
c2136bf0
BH
965 g_tcpListenSockets.push_back(fd);
966
aa136564 967 if(sin.sin4.sin_family == AF_INET)
32252594 968 L<<Logger::Error<<"Listening for TCP queries on "<< sin.toString() <<":"<<st.port<<endl;
aa136564 969 else
32252594 970 L<<Logger::Error<<"Listening for TCP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
f28307ad 971 }
9c495589
BH
972}
973
f28307ad 974void makeUDPServerSockets()
288f4aa9 975{
f28307ad 976 vector<string>locals;
2e3d8a19 977 stringtok(locals,::arg()["local-address"]," ,");
288f4aa9 978
f28307ad
BH
979 if(locals.empty())
980 throw AhuException("No local address specified");
981
2e3d8a19 982 if(::arg()["local-address"]=="0.0.0.0") {
c836dc19 983 L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-address option"<<endl;
288f4aa9 984 }
525b8a7c 985
f28307ad 986 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
32252594
BH
987 ServiceTuple st;
988 st.port=::arg().asNum("local-port");
989 parseService(*i, st);
990
37d3f960 991 ComboAddress sin;
996c89cc 992
37d3f960
BH
993 memset(&sin, 0, sizeof(sin));
994 sin.sin4.sin_family = AF_INET;
32252594 995 if(!IpToU32(st.host.c_str() , (uint32_t*)&sin.sin4.sin_addr.s_addr)) {
37d3f960 996 sin.sin6.sin6_family = AF_INET6;
32252594
BH
997 if(Utility::inet_pton(AF_INET6, st.host.c_str(), &sin.sin6.sin6_addr) <= 0)
998 throw AhuException("Unable to resolve local address for UDP server on '"+ st.host +"'");
37d3f960
BH
999 }
1000
1001 int fd=socket(sin.sin4.sin_family, SOCK_DGRAM,0);
d3b4137e
BH
1002 if(fd < 0) {
1003 throw AhuException("Making a UDP server socket for resolver: "+netstringerror());
1004 }
37d3f960 1005
a19fb8e8 1006 setReceiveBuffer(fd, 200000);
32252594 1007 sin.sin4.sin_port = htons(st.port);
37d3f960
BH
1008
1009 int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
1010 if (::bind(fd, (struct sockaddr *)&sin, socklen)<0)
32252594 1011 throw AhuException("Resolver binding to server socket on port "+ lexical_cast<string>(st.port) +" for "+ st.host+": "+stringerror());
f28307ad
BH
1012
1013 Utility::setNonBlocking(fd);
5db529f8
BH
1014 // g_fdm->addReadFD(fd, handleNewUDPQuestion);
1015 deferredAdd.push_back(make_pair(fd, handleNewUDPQuestion));
c2136bf0 1016
aa136564 1017 if(sin.sin4.sin_family == AF_INET)
32252594 1018 L<<Logger::Error<<"Listening for UDP queries on "<< sin.toString() <<":"<<st.port<<endl;
aa136564 1019 else
32252594 1020 L<<Logger::Error<<"Listening for UDP queries on ["<< sin.toString() <<"]:"<<st.port<<endl;
f28307ad 1021 }
c836dc19 1022}
caa6eefa 1023
9c495589 1024
caa6eefa 1025#ifndef WIN32
c836dc19
BH
1026void daemonize(void)
1027{
1028 if(fork())
1029 exit(0); // bye bye
1030
1031 setsid();
1032
27a5ead5
BH
1033 int i=open("/dev/null",O_RDWR); /* open stdin */
1034 if(i < 0)
1035 L<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
1036 else {
1037 dup2(i,0); /* stdin */
1038 dup2(i,1); /* stderr */
1039 dup2(i,2); /* stderr */
1040 close(i);
1041 }
288f4aa9 1042}
caa6eefa
BH
1043#endif
1044
aaacf7f2 1045uint64_t counter;
c75a6a9e
BH
1046bool statsWanted;
1047
1d5b3ce6 1048
c75a6a9e
BH
1049void usr1Handler(int)
1050{
1051 statsWanted=true;
1052}
ae1b2e98 1053
c9e9e5e0
BH
1054
1055
9170fbaf
BH
1056void usr2Handler(int)
1057{
1058 SyncRes::setLog(true);
1d5b3ce6
BH
1059 g_quiet=false;
1060 ::arg().set("quiet")="no";
c9e9e5e0 1061
9170fbaf
BH
1062}
1063
c75a6a9e
BH
1064void doStats(void)
1065{
8f76c7d4 1066 if(g_stats.qcounter && (RC.cacheHits + RC.cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) {
70c2c8b1 1067 L<<Logger::Warning<<"stats: "<<g_stats.qcounter<<" questions, "<<RC.size()<<" cache entries, "<<SyncRes::s_negcache.size()<<" negative entries, "
8a5602d4 1068 <<(int)((RC.cacheHits*100.0)/(RC.cacheHits+RC.cacheMisses))<<"% cache hits"<<endl;
70c2c8b1 1069 L<<Logger::Warning<<"stats: throttle map: "<<SyncRes::s_throttle.size()<<", ns speeds: "
8cd5b55e 1070 <<SyncRes::s_nsSpeeds.size()<<endl; // ", bytes: "<<RC.bytes()<<endl;
70c2c8b1
BH
1071 L<<Logger::Warning<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%";
1072 L<<Logger::Warning<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, "
525b8a7c 1073 <<SyncRes::s_nodelegated<<" no-delegation drops"<<endl;
70c2c8b1 1074 L<<Logger::Warning<<"stats: "<<SyncRes::s_tcpoutqueries<<" outgoing tcp connections, "<<MT->numProcesses()<<" queries running, "<<SyncRes::s_outgoingtimeouts<<" outgoing timeouts"<<endl;
c75a6a9e 1075 }
7becf07f 1076 else if(statsWanted)
70c2c8b1 1077 L<<Logger::Warning<<"stats: no stats yet!"<<endl;
7becf07f 1078
c75a6a9e
BH
1079 statsWanted=false;
1080}
c836dc19 1081
29f0b1ce 1082static void houseKeeping(void *)
779828c4 1083try
c836dc19 1084{
ae1b2e98 1085 static time_t last_stat, last_rootupdate, last_prune;
c9e9e5e0 1086 struct timeval now;
c038218b 1087 Utility::gettimeofday(&now, 0);
c9e9e5e0 1088
255e0a07 1089 if(now.tv_sec - last_prune > 300) {
5e4a2466
BH
1090 DTime dt;
1091 dt.setTimeval(now);
eefd15f9 1092 RC.doPrune();
33988bfb
BH
1093
1094 typedef SyncRes::negcache_t::nth_index<1>::type negcache_by_ttd_index_t;
1095 negcache_by_ttd_index_t& ttdindex=boost::multi_index::get<1>(SyncRes::s_negcache);
1096
1097 negcache_by_ttd_index_t::iterator i=ttdindex.lower_bound(now.tv_sec);
1098 ttdindex.erase(ttdindex.begin(), i);
2e3d8a19 1099
c9e9e5e0 1100 time_t limit=now.tv_sec-300;
2e3d8a19
BH
1101 for(SyncRes::nsspeeds_t::iterator i = SyncRes::s_nsSpeeds.begin() ; i!= SyncRes::s_nsSpeeds.end(); )
1102 if(i->second.stale(limit))
1103 SyncRes::s_nsSpeeds.erase(i++);
1104 else
1105 ++i;
1106
255e0a07 1107 // cerr<<"Pruned "<<pruned<<" records, left "<<SyncRes::s_negcache.size()<<"\n";
5e4a2466 1108// cout<<"Prune took "<<dt.udiff()<<"usec\n";
ae1b2e98
BH
1109 last_prune=time(0);
1110 }
c9e9e5e0 1111 if(now.tv_sec - last_stat>1800) {
c75a6a9e 1112 doStats();
c836dc19
BH
1113 last_stat=time(0);
1114 }
c038218b 1115 if(now.tv_sec - last_rootupdate > 7200) {
c9e9e5e0 1116 SyncRes sr(now);
ea634573 1117 vector<DNSResourceRecord> ret;
c836dc19
BH
1118
1119 sr.setNoCache();
a9af3782 1120 int res=sr.beginResolve(".", QType(QType::NS), 1, ret);
c836dc19 1121 if(!res) {
70c2c8b1 1122 L<<Logger::Warning<<"Refreshed . records"<<endl;
c9e9e5e0 1123 last_rootupdate=now.tv_sec;
c836dc19
BH
1124 }
1125 else
1126 L<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
1127 }
1128}
779828c4
BH
1129catch(AhuException& ae)
1130{
1131 L<<Logger::Error<<"Fatal error: "<<ae.reason<<endl;
1132 throw;
1133}
705f31ae 1134;
d6d5dea7 1135
09e6702a
BH
1136
1137void handleRCC(int fd, boost::any& var)
1138{
1139 string remote;
1140 string msg=s_rcc.recv(&remote);
1141 RecursorControlParser rcp;
1142 RecursorControlParser::func_t* command;
1143 string answer=rcp.getAnswer(msg, &command);
ab5c053d
BH
1144 try {
1145 s_rcc.send(answer, &remote);
1146 command();
1147 }
1148 catch(exception& e) {
1149 L<<Logger::Error<<"Error dealing with control socket request: "<<e.what()<<endl;
1150 }
1151 catch(AhuException& ae) {
1152 L<<Logger::Error<<"Error dealing with control socket request: "<<ae.reason<<endl;
1153 }
09e6702a
BH
1154}
1155
1156void handleTCPClientReadable(int fd, boost::any& var)
1157{
0b18b22e 1158 PacketID* pident=any_cast<PacketID>(&var);
667f7e60 1159 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
09e6702a 1160
667f7e60 1161 shared_array<char> buffer(new char[pident->inNeeded]);
09e6702a 1162
705f31ae 1163 int ret=recv(fd, buffer.get(), pident->inNeeded,0);
09e6702a 1164 if(ret > 0) {
667f7e60
BH
1165 pident->inMSG.append(&buffer[0], &buffer[ret]);
1166 pident->inNeeded-=ret;
1167 if(!pident->inNeeded) {
1168 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
1169 PacketID pid=*pident;
1170 string msg=pident->inMSG;
09e6702a
BH
1171
1172 g_fdm->removeReadFD(fd);
1173 MT->sendEvent(pid, &msg);
1174 }
1175 else {
667f7e60 1176 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
09e6702a
BH
1177 }
1178 }
1179 else {
667f7e60 1180 PacketID tmp=*pident;
09e6702a
BH
1181 g_fdm->removeReadFD(fd); // pident might now be invalid (it isn't, but still)
1182 string empty;
1183 MT->sendEvent(tmp, &empty); // this conveys error status
1184 }
1185}
1186
1187void handleTCPClientWritable(int fd, boost::any& var)
1188{
0b18b22e 1189 PacketID* pid=any_cast<PacketID>(&var);
09e6702a 1190
4ca15bca 1191 int ret=send(fd, pid->outMSG.c_str() + pid->outPos, pid->outMSG.size() - pid->outPos,0);
09e6702a 1192 if(ret > 0) {
667f7e60
BH
1193 pid->outPos+=ret;
1194 if(pid->outPos==pid->outMSG.size()) {
1195 PacketID tmp=*pid;
09e6702a
BH
1196 g_fdm->removeWriteFD(fd);
1197 MT->sendEvent(tmp, &tmp.outMSG); // send back what we sent to convey everything is ok
1198 }
1199 }
1200 else { // error or EOF
667f7e60 1201 PacketID tmp(*pid);
09e6702a
BH
1202 g_fdm->removeWriteFD(fd);
1203 string sent;
998a4334 1204 MT->sendEvent(tmp, &sent); // we convey error status by sending empty string
09e6702a
BH
1205 }
1206}
1207
34801ab1
BH
1208// resend event to everybody chained onto it
1209void doResends(MT_t::waiters_t::iterator& iter, PacketID resend, const string& content)
1210{
1211 if(iter->key.chain.empty())
1212 return;
1213
1214 for(PacketID::chain_t::iterator i=iter->key.chain.begin(); i != iter->key.chain.end() ; ++i) {
1215 resend.fd=-1;
1216 resend.id=*i;
1217 MT->sendEvent(resend, &content);
1218 g_stats.chainResends++;
1219 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<": "<< res <<endl;
1220 }
1221}
1222
998a4334 1223void handleUDPServerResponse(int fd, boost::any& var)
09e6702a 1224{
600fc20b 1225 PacketID pid=any_cast<PacketID>(var);
998a4334 1226 int len;
09e6702a 1227 char data[1500];
996c89cc 1228 ComboAddress fromaddr;
09e6702a
BH
1229 socklen_t addrlen=sizeof(fromaddr);
1230
998a4334 1231 len=recvfrom(fd, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);
600fc20b 1232
998a4334
BH
1233 if(len < (int)sizeof(dnsheader)) {
1234 if(len < 0)
996c89cc 1235 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
09e6702a
BH
1236 else {
1237 g_stats.serverParseError++;
1238 if(g_logCommonErrors)
37d3f960 1239 L<<Logger::Error<<"Unable to parse packet from remote UDP server "<< sockAddrToString((struct sockaddr_in*) &fromaddr) <<
998a4334
BH
1240 ": packet smalller than DNS header"<<endl;
1241 }
34801ab1 1242
600fc20b 1243 g_udpclientsocks.returnSocket(fd);
34801ab1
BH
1244 string empty;
1245
1246 MT_t::waiters_t::iterator iter=MT->d_waiters.find(pid);
1247 if(iter != MT->d_waiters.end())
1248 doResends(iter, pid, empty);
1249
1250 MT->sendEvent(pid, &empty); // this denotes error (does lookup again.. at least L1 will be hot)
998a4334
BH
1251 return;
1252 }
1253
1254 dnsheader dh;
1255 memcpy(&dh, data, sizeof(dh));
1256
1257 if(!dh.qdcount) // UPC, Nominum?
1258 return;
1259
1260 if(dh.qr) {
1261 PacketID pident;
1262 pident.remote=fromaddr;
1263 pident.id=dh.id;
1264 pident.fd=fd;
787e5eab 1265 pident.domain=questionExpand(data, len, pident.type); // don't copy this from above - we need to do the actual read
998a4334
BH
1266 string packet;
1267 packet.assign(data, len);
34801ab1
BH
1268
1269 MT_t::waiters_t::iterator iter=MT->d_waiters.find(pident);
1270 if(iter != MT->d_waiters.end()) {
1271 doResends(iter, pident, packet);
1272 }
1273
998a4334 1274 if(!MT->sendEvent(pident, &packet)) {
b94abaa2
BH
1275// if(g_logCommonErrors)
1276// L<<Logger::Warning<<"Discarding unexpected packet from "<<fromaddr.toString()<<": "<<pident.type<<endl;
998a4334
BH
1277 g_stats.unexpectedCount++;
1278
1279 for(MT_t::waiters_t::iterator mthread=MT->d_waiters.begin(); mthread!=MT->d_waiters.end(); ++mthread) {
787e5eab 1280 if(pident.fd==mthread->key.fd && mthread->key.remote==pident.remote && mthread->key.type == pident.type &&
34801ab1 1281 !Utility::strcasecmp(pident.domain.c_str(), mthread->key.domain.c_str())) {
998a4334
BH
1282 mthread->key.nearMisses++;
1283 }
1284 }
09e6702a 1285 }
34801ab1 1286 else if(fd >= 0)
2a5e6212 1287 g_udpclientsocks.returnSocket(fd);
09e6702a 1288 }
998a4334 1289 else
37d3f960 1290 L<<Logger::Warning<<"Ignoring question on outgoing socket from "<< sockAddrToString((struct sockaddr_in*) &fromaddr) <<endl;
09e6702a
BH
1291}
1292
1f4abb20
BH
1293FDMultiplexer* getMultiplexer()
1294{
1295 FDMultiplexer* ret;
1296 for(FDMultiplexer::FDMultiplexermap_t::const_iterator i = FDMultiplexer::getMultiplexerMap().begin();
1297 i != FDMultiplexer::getMultiplexerMap().end(); ++i) {
1298 try {
1299 ret=i->second();
1300 L<<Logger::Error<<"Enabled '"<<ret->getName()<<"' multiplexer"<<endl;
1301 return ret;
1302 }
98d0ee4a 1303 catch(FDMultiplexerException &fe) {
0a7f24cb 1304 L<<Logger::Error<<"Non-fatal error initializing possible multiplexer ("<<fe.what()<<"), falling back"<<endl;
98d0ee4a
BH
1305 }
1306 catch(...) {
1307 L<<Logger::Error<<"Non-fatal error initializing possible multiplexer"<<endl;
1308 }
1f4abb20
BH
1309 }
1310 L<<Logger::Error<<"No working multiplexer found!"<<endl;
1311 exit(1);
1312}
1313
5605c067
BH
1314static void makeNameToIPZone(const string& hostname, const string& ip)
1315{
1316 SyncRes::AuthDomain ad;
1317 DNSResourceRecord rr;
1318 rr.qname=toCanonic("", hostname);
1319 rr.d_place=DNSResourceRecord::ANSWER;
1320 rr.ttl=86400;
1321 rr.qtype=QType::SOA;
c0247d0e 1322 rr.content="localhost. root 1 604800 86400 2419200 604800";
5605c067
BH
1323
1324 ad.d_records.insert(rr);
1325
1326 rr.qtype=QType::NS;
1327 rr.content="localhost.";
1328
1329 ad.d_records.insert(rr);
1330
1331 rr.qtype=QType::A;
1332 rr.content=ip;
1333 ad.d_records.insert(rr);
1334
1335 if(SyncRes::s_domainmap.count(rr.qname)) {
1336 L<<Logger::Warning<<"Hosts file will not overwrite zone '"<<rr.qname<<"' already loaded"<<endl;
1337 }
1338 else {
1339 L<<Logger::Warning<<"Inserting forward zone '"<<rr.qname<<"' based on hosts file"<<endl;
1340 SyncRes::s_domainmap[rr.qname]=ad;
1341 }
1342}
1343
9bc8c14c 1344//! parts[0] must be an IP address, the rest must be host names
5605c067
BH
1345static void makeIPToNamesZone(const vector<string>& parts)
1346{
1347 string address=parts[0];
1348 vector<string> ipparts;
1349 stringtok(ipparts, address,".");
5605c067 1350
5605c067
BH
1351 SyncRes::AuthDomain ad;
1352 DNSResourceRecord rr;
9bc8c14c 1353 for(int n=ipparts.size()-1; n>=0 ; --n) {
5605c067
BH
1354 rr.qname.append(ipparts[n]);
1355 rr.qname.append(1,'.');
1356 }
1357 rr.qname.append("in-addr.arpa.");
1358
1359 rr.d_place=DNSResourceRecord::ANSWER;
1360 rr.ttl=86400;
1361 rr.qtype=QType::SOA;
9bc8c14c 1362 rr.content="localhost. root. 1 604800 86400 2419200 604800";
5605c067
BH
1363
1364 ad.d_records.insert(rr);
1365
1366 rr.qtype=QType::NS;
1367 rr.content="localhost.";
1368
1369 ad.d_records.insert(rr);
1370 rr.qtype=QType::PTR;
1371
9bc8c14c
BH
1372 if(ipparts.size()==4) // otherwise this is a partial zone
1373 for(unsigned int n=1; n < parts.size(); ++n) {
1374 rr.content=toCanonic("", parts[n]);
1375 ad.d_records.insert(rr);
1376 }
5605c067
BH
1377
1378 if(SyncRes::s_domainmap.count(rr.qname)) {
9bc8c14c 1379 L<<Logger::Warning<<"Will not overwrite zone '"<<rr.qname<<"' already loaded"<<endl;
5605c067
BH
1380 }
1381 else {
9bc8c14c
BH
1382 if(ipparts.size()==4)
1383 L<<Logger::Warning<<"Inserting reverse zone '"<<rr.qname<<"' based on hosts file"<<endl;
5605c067
BH
1384 SyncRes::s_domainmap[rr.qname]=ad;
1385 }
1386}
1387
ee1ada80
BH
1388
1389void parseAuthAndForwards();
1390
1391string reloadAuthAndForwards()
1392{
1393 SyncRes::domainmap_t original=SyncRes::s_domainmap;
1394
1395 try {
1396 L<<Logger::Warning<<"Reloading zones, purging data from cache"<<endl;
1397
1398 for(SyncRes::domainmap_t::const_iterator i = SyncRes::s_domainmap.begin(); i != SyncRes::s_domainmap.end(); ++i) {
1399 for(SyncRes::AuthDomain::records_t::const_iterator j = i->second.d_records.begin(); j != i->second.d_records.end(); ++j)
1400 RC.doWipeCache(j->qname);
1401 }
1402
1403 string configname=::arg()["config-dir"]+"/recursor.conf";
1404 cleanSlashes(configname);
1405
1406 if(!::arg().preParseFile(configname.c_str(), "forward-zones"))
1407 L<<Logger::Warning<<"Unable to re-parse configuration file '"<<configname<<"'"<<endl;
1408
1409 ::arg().preParseFile(configname.c_str(), "auth-zones");
1410 ::arg().preParseFile(configname.c_str(), "export-etc-hosts");
1411 ::arg().preParseFile(configname.c_str(), "serve-rfc1918");
1412
1413 parseAuthAndForwards();
1414
1415 // purge again - new zones need to blank out the cache
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);
1419 }
1420
1421 // this is pretty blunt
1422 SyncRes::s_negcache.clear();
1423 return "ok\n";
1424 }
1425 catch(exception& e) {
1426 L<<Logger::Error<<"Had error reloading zones, keeping original data: "<<e.what()<<endl;
1427 }
1428 catch(AhuException& ae) {
1429 L<<Logger::Error<<"Encountered error reloading zones, keeping original data: "<<ae.reason<<endl;
1430 }
1431 catch(...) {
1432 L<<Logger::Error<<"Encountered unknown error reloading zones, keeping original data"<<endl;
1433 }
1434 SyncRes::s_domainmap.swap(original);
1435 return "reloading failed, see log\n";
1436}
1437
5605c067
BH
1438void parseAuthAndForwards()
1439{
1440 SyncRes::s_domainmap.clear(); // this makes us idempotent
1441
ee1ada80
BH
1442 TXTRecordContent::report();
1443
5605c067
BH
1444 typedef vector<string> parts_t;
1445 parts_t parts;
1446 for(int n=0; n < 2 ; ++n ) {
1447 parts.clear();
1448 stringtok(parts, ::arg()[n ? "forward-zones" : "auth-zones"], ",\t\n\r");
1449 for(parts_t::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) {
1450 SyncRes::AuthDomain ad;
1451 pair<string,string> headers=splitField(*iter, '=');
1452 trim(headers.first);
1453 trim(headers.second);
1454 headers.first=toCanonic("", headers.first);
1455 if(n==0) {
1456 L<<Logger::Error<<"Parsing authoritative data for zone '"<<headers.first<<"' from file '"<<headers.second<<"'"<<endl;
1457 ZoneParserTNG zpt(headers.second, headers.first);
1458 DNSResourceRecord rr;
1459 while(zpt.get(rr)) {
ee1ada80
BH
1460 try {
1461 string tmp=DNSRR2String(rr);
1462 rr=String2DNSRR(rr.qname, rr.qtype, tmp, 3600);
1463 }
1464 catch(exception &e) {
1465 throw AhuException("Error parsing record '"+rr.qname+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"': "+e.what());
1466 }
1467 catch(...) {
1468 throw AhuException("Error parsing record '"+rr.qname+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"'");
1469 }
1470
5605c067 1471 ad.d_records.insert(rr);
ee1ada80 1472
5605c067
BH
1473 }
1474 }
1475 else {
1476 L<<Logger::Error<<"Redirecting queries for zone '"<<headers.first<<"' to IP '"<<headers.second<<"'"<<endl;
1477 ad.d_server=headers.second;
1478 }
1479
1480 SyncRes::s_domainmap[headers.first]=ad;
1481 }
1482 }
1483
9bc8c14c
BH
1484 if(::arg().mustDo("export-etc-hosts")) {
1485 string line;
1486 string fname;
5605c067 1487
9bc8c14c
BH
1488 ifstream ifs("/etc/hosts");
1489 if(!ifs) {
1490 L<<Logger::Warning<<"Could not open /etc/hosts for reading"<<endl;
1491 return;
1492 }
1493
1494 string::size_type pos;
1495 while(getline(ifs,line)) {
1496 pos=line.find('#');
1497 if(pos!=string::npos)
1498 line.resize(pos);
1499 trim(line);
1500 if(line.empty())
1501 continue;
1502 parts.clear();
1503 stringtok(parts, line, "\t\r\n ");
1504 if(parts[0].find(':')!=string::npos)
1505 continue;
1506
1507 for(unsigned int n=1; n < parts.size(); ++n)
1508 makeNameToIPZone(parts[n], parts[0]);
1509 makeIPToNamesZone(parts);
1510 }
1511 }
1512 if(::arg().mustDo("serve-rfc1918")) {
1513 L<<Logger::Warning<<"Inserting rfc 1918 private space zones"<<endl;
5605c067 1514 parts.clear();
9bc8c14c
BH
1515 parts.push_back("127");
1516 makeIPToNamesZone(parts);
1517 parts[0]="10";
1518 makeIPToNamesZone(parts);
5605c067 1519
9bc8c14c 1520 parts[0]="192.168";
5605c067 1521 makeIPToNamesZone(parts);
9bc8c14c
BH
1522 for(int n=16; n < 32; n++) {
1523 parts[0]="172."+lexical_cast<string>(n);
1524 makeIPToNamesZone(parts);
1525 }
5605c067
BH
1526 }
1527}
1528
6424093e 1529int serviceMain(int argc, char*argv[])
f7c1d4e3
BH
1530{
1531 L.setName("pdns_recursor");
f27e6356
BH
1532
1533 L.setLoglevel((Logger::Urgency)(6)); // info and up
1534
1535 if(!::arg()["logging-facility"].empty()) {
1536 boost::optional<int> val=logFacilityToLOG(::arg().asNum("logging-facility") );
1537 if(val)
1538 theL().setFacility(*val);
1539 else
1540 L<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
1541 }
f7c1d4e3
BH
1542
1543 L<<Logger::Warning<<"PowerDNS recursor "<<VERSION<<" (C) 2001-2006 PowerDNS.COM BV ("<<__DATE__", "__TIME__;
1544#ifdef __GNUC__
1545 L<<", gcc "__VERSION__;
1546#endif // add other compilers here
1547#ifdef _MSC_VER
1548 L<<", MSVC "<<_MSC_VER;
1549#endif
1550 L<<") starting up"<<endl;
1551
1552 L<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
1553 "This is free software, and you are welcome to redistribute it "
1554 "according to the terms of the GPL version 2."<<endl;
1555
1556 L<<Logger::Warning<<"Operating in "<<(sizeof(unsigned long)*8) <<" bits mode"<<endl;
1557
1558 if(!::arg()["allow-from"].empty()) {
1559 g_allowFrom=new NetmaskGroup;
1560 vector<string> ips;
1561 stringtok(ips, ::arg()["allow-from"], ", ");
1562 L<<Logger::Warning<<"Only allowing queries from: ";
1563 for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
1564 g_allowFrom->addMask(*i);
1565 if(i!=ips.begin())
1566 L<<Logger::Warning<<", ";
1567 L<<Logger::Warning<<*i;
1568 }
1569 L<<Logger::Warning<<endl;
1570 }
1571 else if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
1572 L<<Logger::Error<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl;
1573
eb5bae86
BH
1574 if(!::arg()["dont-query"].empty()) {
1575 g_dontQuery=new NetmaskGroup;
1576 vector<string> ips;
1577 stringtok(ips, ::arg()["dont-query"], ", ");
1578 L<<Logger::Warning<<"Will not send queries to: ";
1579 for(vector<string>::const_iterator i = ips.begin(); i!= ips.end(); ++i) {
1580 g_dontQuery->addMask(*i);
1581 if(i!=ips.begin())
1582 L<<Logger::Warning<<", ";
1583 L<<Logger::Warning<<*i;
1584 }
1585 L<<Logger::Warning<<endl;
1586 }
1587
f7c1d4e3
BH
1588 g_quiet=::arg().mustDo("quiet");
1589 if(::arg().mustDo("trace")) {
1590 SyncRes::setLog(true);
1591 ::arg().set("quiet")="no";
1592 g_quiet=false;
1593 }
36cbe5c8
BH
1594
1595 RC.d_followRFC2181=::arg().mustDo("auth-can-lower-ttl");
f7c1d4e3
BH
1596
1597 if(!::arg()["query-local-address6"].empty()) {
1598 SyncRes::s_doIPv6=true;
1599 L<<Logger::Error<<"Enabling IPv6 transport for outgoing queries"<<endl;
1600 }
1601
1602 SyncRes::s_maxnegttl=::arg().asNum("max-negative-ttl");
1603 SyncRes::s_serverID=::arg()["server-id"];
1604 if(SyncRes::s_serverID.empty()) {
1605 char tmp[128];
1606 gethostname(tmp, sizeof(tmp)-1);
1607 SyncRes::s_serverID=tmp;
1608 }
1609
1610
1611 parseAuthAndForwards();
1612
1613 g_stats.remotes.resize(::arg().asNum("remotes-ringbuffer-entries"));
1614 if(!g_stats.remotes.empty())
1615 memset(&g_stats.remotes[0], 0, g_stats.remotes.size() * sizeof(RecursorStats::remotes_t::value_type));
1616 g_logCommonErrors=::arg().mustDo("log-common-errors");
1617
1618 makeUDPServerSockets();
1619 makeTCPServerSockets();
1620
1621#ifndef WIN32
1622 if(::arg().mustDo("fork")) {
1623 fork();
1624 L<<Logger::Warning<<"This is forked pid "<<getpid()<<endl;
1625 }
1626#endif
1627
f888311c 1628 MT=new MTasker<PacketID,string>(::arg().asNum("stack-size"));
f7c1d4e3
BH
1629 makeControlChannelSocket();
1630 PacketID pident;
1631 primeHints();
1632 L<<Logger::Warning<<"Done priming cache with root hints"<<endl;
1633#ifndef WIN32
1634 if(::arg().mustDo("daemon")) {
1635 L<<Logger::Warning<<"Calling daemonize, going to background"<<endl;
1636 L.toConsole(Logger::Critical);
f7c1d4e3
BH
1637 daemonize();
1638 }
1639 signal(SIGUSR1,usr1Handler);
1640 signal(SIGUSR2,usr2Handler);
1641 signal(SIGPIPE,SIG_IGN);
1642 writePid();
1643#endif
1644 g_fdm=getMultiplexer();
1645
1646 for(deferredAdd_t::const_iterator i=deferredAdd.begin(); i!=deferredAdd.end(); ++i)
1647 g_fdm->addReadFD(i->first, i->second);
1648
1649 int newgid=0;
1650 if(!::arg()["setgid"].empty())
1651 newgid=Utility::makeGidNumeric(::arg()["setgid"]);
1652 int newuid=0;
1653 if(!::arg()["setuid"].empty())
1654 newuid=Utility::makeUidNumeric(::arg()["setuid"]);
1655
1656#ifndef WIN32
1657 if (!::arg()["chroot"].empty()) {
b27151e4 1658 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
f7c1d4e3
BH
1659 L<<Logger::Error<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno)<<", exiting"<<endl;
1660 exit(1);
1661 }
1662 }
1663
1664 Utility::dropPrivs(newuid, newgid);
1665 g_fdm->addReadFD(s_rcc.d_fd, handleRCC); // control channel
1666#endif
1667
1668 counter=0;
1669 unsigned int maxTcpClients=::arg().asNum("max-tcp-clients");
1670 g_tcpTimeout=::arg().asNum("client-tcp-timeout");
1671
1672 g_maxTCPPerClient=::arg().asNum("max-tcp-per-client");
1673
1674
1675 bool listenOnTCP(true);
1676
1677 for(;;) {
f6c254c1 1678 while(MT->schedule(g_now.tv_sec)); // housekeeping, let threads do their thing
f7c1d4e3
BH
1679
1680 if(!(counter%500)) {
1681 MT->makeThread(houseKeeping,0);
1682 }
1683
d2392145 1684 if(!(counter%55)) {
f7c1d4e3
BH
1685 typedef vector<pair<int, boost::any> > expired_t;
1686 expired_t expired=g_fdm->getTimeouts(g_now);
1687
1688 for(expired_t::iterator i=expired.begin() ; i != expired.end(); ++i) {
1689 TCPConnection conn=any_cast<TCPConnection>(i->second);
879b3f70
BH
1690 if(g_logCommonErrors)
1691 L<<Logger::Warning<<"Timeout from remote TCP client "<< conn.remote.toString() <<endl;
1692 g_fdm->removeReadFD(i->first);
1693 conn.closeAndCleanup();
f7c1d4e3
BH
1694 }
1695 }
1696
1697 counter++;
1698
1699 if(statsWanted) {
1700 doStats();
1701 }
1702
1703 Utility::gettimeofday(&g_now, 0);
1704 g_fdm->run(&g_now);
1705
1706 if(listenOnTCP) {
1707 if(TCPConnection::s_currentConnections > maxTcpClients) { // shutdown
1708 for(g_tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i)
1709 g_fdm->removeReadFD(*i);
1710 listenOnTCP=false;
1711 }
1712 }
1713 else {
1714 if(TCPConnection::s_currentConnections <= maxTcpClients) { // reenable
1715 for(g_tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i)
1716 g_fdm->addReadFD(*i, handleNewTCPQuestion);
1717 listenOnTCP=true;
1718 }
1719 }
1720 }
1721}
1722#ifdef WIN32
1723void doWindowsServiceArguments(RecursorService& recursor)
1724{
1725 if(::arg().mustDo( "register-service" )) {
1726 if ( !recursor.registerService( "The PowerDNS Recursor.", true )) {
1727 cerr << "Could not register service." << endl;
1728 exit( 99 );
1729 }
1730
1731 exit( 0 );
1732 }
1733
1734 if ( ::arg().mustDo( "unregister-service" )) {
1735 recursor.unregisterService();
1736 exit( 0 );
1737 }
1738}
1739#endif
1740
288f4aa9
BH
1741int main(int argc, char **argv)
1742{
5e3de507 1743 g_stats.startupTime=time(0);
8a63d3ce 1744 reportBasicTypes();
ea634573 1745
22030c37 1746 int ret = EXIT_SUCCESS;
caa6eefa 1747#ifdef WIN32
f7c1d4e3
BH
1748 RecursorService service;
1749 WSADATA wsaData;
1750 if(WSAStartup( MAKEWORD( 2, 2 ), &wsaData )) {
1751 cerr<<"Unable to initialize winsock\n";
1752 exit(1);
1753 }
caa6eefa
BH
1754#endif // WIN32
1755
288f4aa9 1756 try {
caa6eefa 1757 Utility::srandom(time(0));
f888311c 1758 ::arg().set("stack-size","stack size per mthread")="200000";
2e3d8a19
BH
1759 ::arg().set("soa-minimum-ttl","Don't change")="0";
1760 ::arg().set("soa-serial-offset","Don't change")="0";
1761 ::arg().set("no-shuffle","Don't change")="off";
1762 ::arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off";
1763 ::arg().set("local-port","port to listen on")="53";
32252594 1764 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
2e3d8a19
BH
1765 ::arg().set("trace","if we should output heaps of logging")="off";
1766 ::arg().set("daemon","Operate as a daemon")="yes";
0e9d9ce2 1767 ::arg().set("log-common-errors","If we should log rather common errors")="yes";
2e3d8a19
BH
1768 ::arg().set("chroot","switch to chroot jail")="";
1769 ::arg().set("setgid","If set, change group id to this gid for more security")="";
1770 ::arg().set("setuid","If set, change user id to this uid for more security")="";
c038218b
BH
1771#ifdef WIN32
1772 ::arg().set("quiet","Suppress logging of questions and answers")="off";
f7c1d4e3
BH
1773 ::arg().setSwitch( "register-service", "Register the service" )= "no";
1774 ::arg().setSwitch( "unregister-service", "Unregister the service" )= "no";
1775 ::arg().setSwitch( "ntservice", "Run as service" )= "no";
1776 ::arg().setSwitch( "use-ntlog", "Use the NT logging facilities" )= "yes";
1777 ::arg().setSwitch( "use-logfile", "Use a log file" )= "no";
1778 ::arg().setSwitch( "logfile", "Filename of the log file" )= "recursor.log";
c038218b
BH
1779#else
1780 ::arg().set("quiet","Suppress logging of questions and answers")="";
f27e6356 1781 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
c038218b 1782#endif
2e3d8a19
BH
1783 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR;
1784 ::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR;
1785 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
1786 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
996c89cc 1787 ::arg().set("query-local-address6","Source IPv6 address for sending queries")="";
2e3d8a19
BH
1788 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
1789 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
1790 ::arg().set("hint-file", "If set, load root hints from this file")="";
bec87d21 1791 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="0";
a9af3782
BH
1792 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
1793 ::arg().set("server-id", "Returned when queried for 'server.id' TXT, defaults to hostname")="";
1794 ::arg().set("remotes-ringbuffer-entries", "maximum number of packets to store statistics for")="0";
d5141417 1795 ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Recursor "VERSION" $Id$";
d8f13d03 1796 ::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";
eb5bae86 1797 ::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";
4e120339 1798 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
41f7a068 1799 ::arg().set("fork", "If set, fork the daemon for possible double performance")="no";
0d5f0a9f 1800 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
4ef015cd 1801 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
5605c067
BH
1802 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
1803 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
1804 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
9bc8c14c 1805 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="";
36cbe5c8 1806 ::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";
c34d9fe9 1807 ::arg().setSwitch( "ignore-rd-bit", "Assume each packet requires recursion, for compatability" )= "off";
2e3d8a19
BH
1808
1809 ::arg().setCmd("help","Provide a helpful message");
5e3de507 1810 ::arg().setCmd("version","Print version string ("VERSION")");
d5141417 1811 ::arg().setCmd("config","Output blank configuration");
f27e6356 1812 L.toConsole(Logger::Info);
2e3d8a19 1813 ::arg().laxParse(argc,argv); // do a lax parse
c75a6a9e 1814
2e3d8a19 1815 string configname=::arg()["config-dir"]+"/recursor.conf";
c75a6a9e
BH
1816 cleanSlashes(configname);
1817
2e3d8a19 1818 if(!::arg().file(configname.c_str()))
c75a6a9e
BH
1819 L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
1820
2e3d8a19 1821 ::arg().parse(argc,argv);
c836dc19 1822
2e3d8a19 1823 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
562588a3 1824
2e3d8a19 1825 if(::arg().mustDo("help")) {
b636533b 1826 cerr<<"syntax:"<<endl<<endl;
2e3d8a19 1827 cerr<<::arg().helpstring(::arg()["help"])<<endl;
b636533b
BH
1828 exit(99);
1829 }
5e3de507
BH
1830 if(::arg().mustDo("version")) {
1831 cerr<<"version: "VERSION<<endl;
1832 exit(99);
1833 }
b636533b 1834
d5141417
BH
1835 if(::arg().mustDo("config")) {
1836 cout<<::arg().configstring()<<endl;
1837 exit(0);
1838 }
1839
caa6eefa 1840#ifndef WIN32
f7c1d4e3
BH
1841 serviceMain(argc, argv);
1842#else
6a0bb0cf 1843 doWindowsServiceArguments(service);
6424093e 1844 L.toNTLog();
f7c1d4e3 1845 RecursorService::instance()->start( argc, argv, ::arg().mustDo( "ntservice" ));
caa6eefa 1846#endif
998a4334 1847
288f4aa9
BH
1848 }
1849 catch(AhuException &ae) {
c836dc19 1850 L<<Logger::Error<<"Exception: "<<ae.reason<<endl;
22030c37 1851 ret=EXIT_FAILURE;
288f4aa9
BH
1852 }
1853 catch(exception &e) {
c836dc19 1854 L<<Logger::Error<<"STL Exception: "<<e.what()<<endl;
22030c37 1855 ret=EXIT_FAILURE;
288f4aa9
BH
1856 }
1857 catch(...) {
c836dc19 1858 L<<Logger::Error<<"any other exception in main: "<<endl;
22030c37 1859 ret=EXIT_FAILURE;
288f4aa9 1860 }
caa6eefa
BH
1861
1862#ifdef WIN32
1863 WSACleanup();
1864#endif // WIN32
1865
22030c37 1866 return ret;
288f4aa9 1867}