]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/nameserver.cc
Merge pull request #5523 from rubenk/fix-typos-in-logmessage
[thirdparty/pdns.git] / pdns / nameserver.cc
CommitLineData
12c86877 1/*
12471842
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
12c86877
BH
25#include "utility.hh"
26#include <cstdio>
27#include <cstring>
28#include <cstdlib>
29#include <cerrno>
30#include <iostream>
31#include <string>
32#include <sys/types.h>
46c6975c 33#include "responsestats.hh"
dd7da6cd 34
12c86877
BH
35#include "dns.hh"
36#include "dnsbackend.hh"
37#include "dnspacket.hh"
38#include "nameserver.hh"
39#include "distributor.hh"
40#include "logger.hh"
41#include "arguments.hh"
42#include "statbag.hh"
43
61b26744 44#include "namespaces.hh"
30b4da87 45
12c86877
BH
46extern StatBag S;
47
48/** \mainpage
f28307ad 49 PowerDNS is a very versatile nameserver that can answer questions from different backends. To implement your
12c86877
BH
50 own backend, see the documentation for the DNSBackend class.
51
52 \section copyright Copyright and License
657e9124 53 PowerDNS is (C) 2001-2008 PowerDNS.COM BV. It is distributed according to the terms of the General Public License version 2.
12c86877
BH
54
55 \section overview High level overview
56
bdc9f8d2 57 The Distributor contains a configurable number of PacketHandler instances, each in its own thread, for connection pooling.
3f81d239 58 PacketHandler instances are recycled of they let escape an PDNSException.
12c86877
BH
59
60 The PacketHandler implements the RFC1034 algorithm and converts question packets into DNSBackend queries.
61
62 A DNSBackend is an entity that returns DNSResourceRecord objects in return to explicit questions for domains with a specified QType
63
bdc9f8d2
BH
64 PowerDNS uses the UeberBackend as its DNSBackend. The UeberBackend by default has no DNSBackends within itself, those are loaded
65 using the pdns_control tool. This way DNSBackend implementations can be kept completely separate (but they often aren't).s
12c86877
BH
66
67 If one or more DNSBackends are loaded, the UeberBackend fields the queries to all of them until one answers.
68
69 \section TCP TCP Operations
70
71 The TCP operation runs within a single thread called tcpreceiver(), that also queries the PacketHandler.
72
73 \section Cache Caching
74
75 On its own, this setup is not suitable for high performance operations. A single DNS query can turn into many DNSBackend questions,
abc1d928 76 each taking many milliseconds to complete. This is why the qthread() first checks the PacketCache to see if an answer is known to a packet
12c86877
BH
77 asking this question. If so, the entire Distributor is shunted, and the answer is sent back *directly*, within a few microseconds.
78
12c86877
BH
79 \section misc Miscellaneous
80 Configuration details are available via the ArgvMap instance arg. Statistics are created by making calls to the StatBag object called S.
81 These statistics are made available via the UeberBackend on the same socket that is used for dynamic module commands.
82
83 \section Main Main
bdc9f8d2 84 The main() of PowerDNS can be found in receiver.cc - start reading there for further insights into the operation of the nameserver
12c86877
BH
85*/
86
d0854a6c 87vector<ComboAddress> g_localaddresses; // not static, our unit tests need to poke this
2b6f1436 88
12c86877
BH
89void UDPNameserver::bindIPv4()
90{
91 vector<string>locals;
43d347d3 92 stringtok(locals,::arg()["local-address"]," ,");
4ee30c66 93 int one = 1;
12c86877
BH
94
95 if(locals.empty())
3f81d239 96 throw PDNSException("No local address specified");
12c86877
BH
97
98 int s;
99 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
100 string localname(*i);
8db49a64 101 ComboAddress locala;
12c86877
BH
102
103 s=socket(AF_INET,SOCK_DGRAM,0);
42c235e5 104
a738556b 105 if(s<0) {
c057bfaa 106 L<<Logger::Error<<"Unable to acquire UDP socket: "+string(strerror(errno)) << endl;
3f81d239 107 throw PDNSException("Unable to acquire a UDP socket: "+string(strerror(errno)));
a738556b 108 }
91dd9c00 109
3897b9e1 110 setCloseOnExec(s);
2b6f1436 111
3897b9e1 112 if(!setNonBlocking(s))
3f81d239 113 throw PDNSException("Unable to set UDP socket to non-blocking: "+stringerror());
12c86877
BH
114
115 memset(&locala,0,sizeof(locala));
8db49a64 116 locala.sin4.sin_family=AF_INET;
12c86877 117
4ee30c66
MZ
118 if(localname=="0.0.0.0")
119 setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one));
120
915b0c39
AT
121 if (!setSocketTimestamps(s))
122 L<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
9ae194e2 123
4ee30c66 124#ifdef SO_REUSEPORT
3a56adcc
MZ
125 if( d_can_reuseport )
126 if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
127 d_can_reuseport = false;
4ee30c66
MZ
128#endif
129
fec7dd5a
SS
130 if( ::arg().mustDo("non-local-bind") )
131 Utility::setBindAny(AF_INET, s);
132
f929cdb2 133 locala=ComboAddress(localname, ::arg().asNum("local-port"));
134 if(locala.sin4.sin_family != AF_INET)
3f81d239 135 throw PDNSException("Attempting to bind IPv4 socket to IPv6 address");
12c86877 136
3a56adcc
MZ
137 if( !d_additional_socket )
138 g_localaddresses.push_back(locala);
1d586b37 139
8db49a64 140 if(::bind(s, (sockaddr*)&locala, locala.getSocklen()) < 0) {
ed3afdfc 141 string binderror = strerror(errno);
2c896042 142 close(s);
5ecb2885
MZ
143 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
144 L<<Logger::Error<<"IPv4 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
145 continue;
146 } else {
c057bfaa 147 L<<Logger::Error<<"Unable to bind UDP socket to '"+locala.toStringWithPort()+"': "<<binderror<<endl;
5ecb2885
MZ
148 throw PDNSException("Unable to bind to UDP socket");
149 }
12c86877 150 }
12c86877 151 d_sockets.push_back(s);
f929cdb2 152 L<<Logger::Error<<"UDP server bound to "<<locala.toStringWithPort()<<endl;
6e242246
BH
153 struct pollfd pfd;
154 pfd.fd = s;
cd5e1584 155 pfd.events = POLLIN;
6e242246
BH
156 pfd.revents = 0;
157 d_rfds.push_back(pfd);
12c86877
BH
158 }
159}
160
8db49a64 161bool AddressIsUs(const ComboAddress& remote)
162{
ef7cd021 163 for(const ComboAddress& us : g_localaddresses) {
8db49a64 164 if(remote == us)
165 return true;
166 if(IsAnyAddress(us)) {
d0854a6c 167 int s = socket(remote.sin4.sin_family, SOCK_DGRAM, 0);
8db49a64 168 if(s < 0)
232f0877 169 continue;
8db49a64 170
171 if(connect(s, (struct sockaddr*)&remote, remote.getSocklen()) < 0) {
232f0877
CH
172 close(s);
173 continue;
8db49a64 174 }
175
176 ComboAddress actualLocal;
177 actualLocal.sin4.sin_family = remote.sin4.sin_family;
178 socklen_t socklen = actualLocal.getSocklen();
179
180 if(getsockname(s, (struct sockaddr*) &actualLocal, &socklen) < 0) {
232f0877
CH
181 close(s);
182 continue;
8db49a64 183 }
184 close(s);
185 actualLocal.sin4.sin_port = us.sin4.sin_port;
186 if(actualLocal == remote)
232f0877 187 return true;
8db49a64 188 }
189 }
190 return false;
191}
192
193
12c86877
BH
194void UDPNameserver::bindIPv6()
195{
2b6f1436 196 vector<string> locals;
43d347d3 197 stringtok(locals,::arg()["local-ipv6"]," ,");
4ee30c66 198 int one=1;
12c86877
BH
199
200 if(locals.empty())
201 return;
202
12c86877
BH
203 int s;
204 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
205 string localname(*i);
12c86877
BH
206
207 s=socket(AF_INET6,SOCK_DGRAM,0);
a738556b 208 if(s<0) {
883ad072
YG
209 if( errno == EAFNOSUPPORT ) {
210 L<<Logger::Error<<"IPv6 Address Family is not supported - skipping UDPv6 bind" << endl;
211 return;
212 } else {
213 L<<Logger::Error<<"Unable to acquire a UDPv6 socket: "+string(strerror(errno)) << endl;
214 throw PDNSException("Unable to acquire a UDPv6 socket: "+string(strerror(errno)));
215 }
a738556b 216 }
2b6f1436 217
3897b9e1 218 setCloseOnExec(s);
219 if(!setNonBlocking(s))
3f81d239 220 throw PDNSException("Unable to set UDPv6 socket to non-blocking: "+stringerror());
315dd2e6 221
2b6f1436
BH
222 ComboAddress locala(localname, ::arg().asNum("local-port"));
223
224 if(IsAnyAddress(locala)) {
4ee30c66 225 setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
199f29bf 226#ifdef IPV6_RECVPKTINFO
4ee30c66 227 setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
199f29bf 228#endif
4ee30c66 229 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); // if this fails, we report an error in tcpreceiver too
12c86877 230 }
4ee30c66 231
c2e30378 232 if (!setSocketTimestamps(s))
915b0c39 233 L<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
9ae194e2 234
4ee30c66 235#ifdef SO_REUSEPORT
3a56adcc
MZ
236 if( d_can_reuseport )
237 if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
238 d_can_reuseport = false;
4ee30c66
MZ
239#endif
240
fec7dd5a
SS
241 if( ::arg().mustDo("non-local-bind") )
242 Utility::setBindAny(AF_INET6, s);
243
3a56adcc
MZ
244 if( !d_additional_socket )
245 g_localaddresses.push_back(locala);
43986156 246 if(::bind(s, (sockaddr*)&locala, sizeof(locala))<0) {
2c896042 247 close(s);
5ecb2885
MZ
248 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
249 L<<Logger::Error<<"IPv6 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
250 continue;
251 } else {
c057bfaa
RK
252 L<<Logger::Error<<"Unable to bind to UDPv6 socket "<< localname <<": "<<strerror(errno)<<endl;
253 throw PDNSException("Unable to bind to UDPv6 socket");
5ecb2885 254 }
12c86877 255 }
12c86877 256 d_sockets.push_back(s);
6e242246
BH
257 struct pollfd pfd;
258 pfd.fd = s;
cd5e1584 259 pfd.events = POLLIN;
6e242246
BH
260 pfd.revents = 0;
261 d_rfds.push_back(pfd);
506a9050 262 L<<Logger::Error<<"UDPv6 server bound to "<<locala.toStringWithPort()<<endl;
12c86877 263 }
12c86877
BH
264}
265
3a56adcc 266UDPNameserver::UDPNameserver( bool additional_socket )
12c86877 267{
4ee30c66 268#ifdef SO_REUSEPORT
3a56adcc 269 d_can_reuseport = ::arg().mustDo("reuseport");
4ee30c66 270#endif
3a56adcc
MZ
271 // Are we the main socket (false) or a rebinding using SO_REUSEPORT ?
272 d_additional_socket = additional_socket;
4ee30c66 273
43d347d3 274 if(!::arg()["local-address"].empty())
12c86877 275 bindIPv4();
43d347d3 276 if(!::arg()["local-ipv6"].empty())
12c86877
BH
277 bindIPv6();
278
43d347d3 279 if(::arg()["local-address"].empty() && ::arg()["local-ipv6"].empty())
2b6f1436 280 L<<Logger::Critical<<"PDNS is deaf and mute! Not listening on any interfaces"<<endl;
12c86877 281}
46c6975c 282
12c86877
BH
283void UDPNameserver::send(DNSPacket *p)
284{
b552d7b1
PL
285 string buffer=p->getString();
286 g_rs.submitResponse(*p, true);
46c6975c 287
2b6f1436 288 struct msghdr msgh;
2b6f1436
BH
289 struct iovec iov;
290 char cbuf[256];
6865d5c0 291
b71b60ee 292 fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)buffer.c_str(), buffer.length(), &p->d_remote);
2b6f1436 293
3eae691f 294 msgh.msg_control=NULL;
2b6f1436 295 if(p->d_anyLocal) {
fbe2a2e0 296 addCMsgSrcAddr(&msgh, cbuf, p->d_anyLocal.get_ptr(), 0);
2b6f1436 297 }
39bc3e49 298 DLOG(L<<Logger::Notice<<"Sending a packet to "<< p->getRemote() <<" ("<< buffer.length()<<" octets)"<<endl);
1bd5361b 299 if(buffer.length() > p->getMaxReplyLen()) {
46c6975c 300 L<<Logger::Error<<"Weird, trying to send a message that needs truncation, "<< buffer.length()<<" > "<<p->getMaxReplyLen()<<endl;
12c86877 301 }
2b6f1436 302 if(sendmsg(p->getSocket(), &msgh, 0) < 0)
4f217ce4 303 L<<Logger::Error<<"Error sending reply with sendmsg (socket="<<p->getSocket()<<", dest="<<p->d_remote.toStringWithPort()<<"): "<<strerror(errno)<<endl;
12c86877
BH
304}
305
2b6f1436
BH
306DNSPacket *UDPNameserver::receive(DNSPacket *prefilled)
307{
308 ComboAddress remote;
309 extern StatBag S;
a683e8bd 310 ssize_t len=-1;
1cd66b8e 311 char mesg[DNSPacket::s_udpTruncationThreshold];
2b6f1436 312 Utility::sock_t sock=-1;
1cd66b8e 313
2b6f1436
BH
314 struct msghdr msgh;
315 struct iovec iov;
316 char cbuf[256];
317
b71b60ee 318 remote.sin6.sin6_family=AF_INET6; // make sure it is big enough
319 fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), mesg, sizeof(mesg), &remote);
2b6f1436
BH
320
321 int err;
223066c6 322 vector<struct pollfd> rfds= d_rfds;
315dd2e6 323
28c266da 324 for(auto &pfd : rfds) {
315dd2e6 325 pfd.events = POLLIN;
326 pfd.revents = 0;
327 }
2b6f1436 328
ee79512a 329 retry:;
330
315dd2e6 331 err = poll(&rfds[0], rfds.size(), -1);
ee79512a 332 if(err < 0) {
333 if(errno==EINTR)
334 goto retry;
315dd2e6 335 unixDie("Unable to poll for new UDP events");
ee79512a 336 }
2b6f1436 337
28c266da 338 for(auto &pfd : rfds) {
315dd2e6 339 if(pfd.revents & POLLIN) {
340 sock=pfd.fd;
315dd2e6 341 if((len=recvmsg(sock, &msgh, 0)) < 0 ) {
232f0877
CH
342 if(errno != EAGAIN)
343 L<<Logger::Error<<"recvfrom gave error, ignoring: "<<strerror(errno)<<endl;
344 return 0;
2b6f1436 345 }
315dd2e6 346 break;
2b6f1436
BH
347 }
348 }
315dd2e6 349 if(sock==-1)
3f81d239 350 throw PDNSException("poll betrayed us! (should not happen)");
2b6f1436 351
2b6f1436 352 DLOG(L<<"Received a packet " << len <<" bytes long from "<< remote.toString()<<endl);
81859ba5 353
354 BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
355
356 if(remote.sin4.sin_port == 0) // would generate error on responding. sin4 also works for ipv6
357 return 0;
2b6f1436
BH
358
359 DNSPacket *packet;
360 if(prefilled) // they gave us a preallocated packet
361 packet=prefilled;
362 else
27c0050c 363 packet=new DNSPacket(true); // don't forget to free it!
9ae194e2 364
2b6f1436
BH
365 packet->setSocket(sock);
366 packet->setRemote(&remote);
367
368 ComboAddress dest;
369 if(HarvestDestinationAddress(&msgh, &dest)) {
370// cerr<<"Setting d_anyLocal to '"<<dest.toString()<<"'"<<endl;
371 packet->d_anyLocal = dest;
232f0877 372 }
2b6f1436 373
9ae194e2 374 struct timeval recvtv;
375 if(HarvestTimestamp(&msgh, &recvtv)) {
376 packet->d_dt.setTimeval(recvtv);
377 }
378 else
379 packet->d_dt.set(); // timing
380
a683e8bd 381 if(packet->parse(mesg, (size_t) len)<0) {
2b6f1436 382 S.inc("corrupt-packets");
4eb26e0f 383 S.ringAccount("remotes-corrupt", packet->d_remote);
2b6f1436
BH
384
385 if(!prefilled)
386 delete packet;
387 return 0; // unable to parse
388 }
389
390 return packet;
391}