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