]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/nameserver.cc
auth: switch circleci mssql image
[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
35520716
CH
64 PowerDNS uses the UeberBackend, which hosts DNSBackends. By default it has no DNSBackends within itself, those are loaded
65 by setting --load=<list of backends>. This way DNSBackend implementations can be kept completely separate, but most aren't.
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) {
e6a9dde5 106 g_log<<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());
d38e2ba9 114
36025a51 115 locala=ComboAddress(localname, ::arg().asNum("local-port"));
116
117 if(locala.sin4.sin_family != AF_INET)
118 throw PDNSException("Attempting to bind IPv4 socket to IPv6 address");
12c86877 119
36025a51 120 if(IsAnyAddress(locala))
4ee30c66
MZ
121 setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one));
122
915b0c39 123 if (!setSocketTimestamps(s))
e6a9dde5 124 g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
9ae194e2 125
90f9fbc0
RG
126 if (locala.isIPv4()) {
127 try {
128 setSocketIgnorePMTU(s);
129 }
130 catch(const std::exception& e) {
131 g_log<<Logger::Warning<<"Failed to set IP_MTU_DISCOVER on UDP server socket: "<<e.what()<<endl;
132 }
133 }
134
4ee30c66 135#ifdef SO_REUSEPORT
3a56adcc
MZ
136 if( d_can_reuseport )
137 if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
138 d_can_reuseport = false;
4ee30c66
MZ
139#endif
140
fec7dd5a
SS
141 if( ::arg().mustDo("non-local-bind") )
142 Utility::setBindAny(AF_INET, s);
143
12c86877 144
3a56adcc
MZ
145 if( !d_additional_socket )
146 g_localaddresses.push_back(locala);
1d586b37 147
8db49a64 148 if(::bind(s, (sockaddr*)&locala, locala.getSocklen()) < 0) {
ed3afdfc 149 string binderror = strerror(errno);
2c896042 150 close(s);
5ecb2885 151 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
e6a9dde5 152 g_log<<Logger::Error<<"IPv4 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
5ecb2885
MZ
153 continue;
154 } else {
e6a9dde5 155 g_log<<Logger::Error<<"Unable to bind UDP socket to '"+locala.toStringWithPort()+"': "<<binderror<<endl;
5ecb2885
MZ
156 throw PDNSException("Unable to bind to UDP socket");
157 }
12c86877 158 }
12c86877 159 d_sockets.push_back(s);
e6a9dde5 160 g_log<<Logger::Error<<"UDP server bound to "<<locala.toStringWithPort()<<endl;
6e242246
BH
161 struct pollfd pfd;
162 pfd.fd = s;
cd5e1584 163 pfd.events = POLLIN;
6e242246
BH
164 pfd.revents = 0;
165 d_rfds.push_back(pfd);
12c86877
BH
166 }
167}
168
8db49a64 169bool AddressIsUs(const ComboAddress& remote)
170{
ef7cd021 171 for(const ComboAddress& us : g_localaddresses) {
8db49a64 172 if(remote == us)
173 return true;
174 if(IsAnyAddress(us)) {
d0854a6c 175 int s = socket(remote.sin4.sin_family, SOCK_DGRAM, 0);
8db49a64 176 if(s < 0)
232f0877 177 continue;
8db49a64 178
179 if(connect(s, (struct sockaddr*)&remote, remote.getSocklen()) < 0) {
232f0877
CH
180 close(s);
181 continue;
8db49a64 182 }
183
184 ComboAddress actualLocal;
185 actualLocal.sin4.sin_family = remote.sin4.sin_family;
186 socklen_t socklen = actualLocal.getSocklen();
187
188 if(getsockname(s, (struct sockaddr*) &actualLocal, &socklen) < 0) {
232f0877
CH
189 close(s);
190 continue;
8db49a64 191 }
192 close(s);
193 actualLocal.sin4.sin_port = us.sin4.sin_port;
194 if(actualLocal == remote)
232f0877 195 return true;
8db49a64 196 }
197 }
198 return false;
199}
200
201
12c86877
BH
202void UDPNameserver::bindIPv6()
203{
2b6f1436 204 vector<string> locals;
43d347d3 205 stringtok(locals,::arg()["local-ipv6"]," ,");
4ee30c66 206 int one=1;
12c86877
BH
207
208 if(locals.empty())
209 return;
210
12c86877
BH
211 int s;
212 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
213 string localname(*i);
12c86877
BH
214
215 s=socket(AF_INET6,SOCK_DGRAM,0);
a738556b 216 if(s<0) {
883ad072 217 if( errno == EAFNOSUPPORT ) {
e6a9dde5 218 g_log<<Logger::Error<<"IPv6 Address Family is not supported - skipping UDPv6 bind" << endl;
883ad072
YG
219 return;
220 } else {
e6a9dde5 221 g_log<<Logger::Error<<"Unable to acquire a UDPv6 socket: "+string(strerror(errno)) << endl;
883ad072
YG
222 throw PDNSException("Unable to acquire a UDPv6 socket: "+string(strerror(errno)));
223 }
a738556b 224 }
2b6f1436 225
3897b9e1 226 setCloseOnExec(s);
227 if(!setNonBlocking(s))
3f81d239 228 throw PDNSException("Unable to set UDPv6 socket to non-blocking: "+stringerror());
315dd2e6 229
2b6f1436
BH
230 ComboAddress locala(localname, ::arg().asNum("local-port"));
231
232 if(IsAnyAddress(locala)) {
4ee30c66 233 setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
199f29bf 234#ifdef IPV6_RECVPKTINFO
4ee30c66 235 setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
199f29bf 236#endif
4ee30c66 237 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); // if this fails, we report an error in tcpreceiver too
12c86877 238 }
4ee30c66 239
c2e30378 240 if (!setSocketTimestamps(s))
e6a9dde5 241 g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
9ae194e2 242
4ee30c66 243#ifdef SO_REUSEPORT
3a56adcc
MZ
244 if( d_can_reuseport )
245 if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
246 d_can_reuseport = false;
4ee30c66
MZ
247#endif
248
fec7dd5a
SS
249 if( ::arg().mustDo("non-local-bind") )
250 Utility::setBindAny(AF_INET6, s);
251
3a56adcc
MZ
252 if( !d_additional_socket )
253 g_localaddresses.push_back(locala);
4324d44e 254 if(::bind(s, (sockaddr*)&locala, locala.getSocklen())<0) {
2c896042 255 close(s);
5ecb2885 256 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
e6a9dde5 257 g_log<<Logger::Error<<"IPv6 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
5ecb2885
MZ
258 continue;
259 } else {
e6a9dde5 260 g_log<<Logger::Error<<"Unable to bind to UDPv6 socket "<< localname <<": "<<strerror(errno)<<endl;
c057bfaa 261 throw PDNSException("Unable to bind to UDPv6 socket");
5ecb2885 262 }
12c86877 263 }
12c86877 264 d_sockets.push_back(s);
6e242246
BH
265 struct pollfd pfd;
266 pfd.fd = s;
cd5e1584 267 pfd.events = POLLIN;
6e242246
BH
268 pfd.revents = 0;
269 d_rfds.push_back(pfd);
e6a9dde5 270 g_log<<Logger::Error<<"UDPv6 server bound to "<<locala.toStringWithPort()<<endl;
12c86877 271 }
12c86877
BH
272}
273
3a56adcc 274UDPNameserver::UDPNameserver( bool additional_socket )
12c86877 275{
4ee30c66 276#ifdef SO_REUSEPORT
3a56adcc 277 d_can_reuseport = ::arg().mustDo("reuseport");
4ee30c66 278#endif
3a56adcc
MZ
279 // Are we the main socket (false) or a rebinding using SO_REUSEPORT ?
280 d_additional_socket = additional_socket;
4ee30c66 281
43d347d3 282 if(!::arg()["local-address"].empty())
12c86877 283 bindIPv4();
43d347d3 284 if(!::arg()["local-ipv6"].empty())
12c86877
BH
285 bindIPv6();
286
43d347d3 287 if(::arg()["local-address"].empty() && ::arg()["local-ipv6"].empty())
e6a9dde5 288 g_log<<Logger::Critical<<"PDNS is deaf and mute! Not listening on any interfaces"<<endl;
12c86877 289}
46c6975c 290
12c86877
BH
291void UDPNameserver::send(DNSPacket *p)
292{
b552d7b1
PL
293 string buffer=p->getString();
294 g_rs.submitResponse(*p, true);
46c6975c 295
2b6f1436 296 struct msghdr msgh;
2b6f1436
BH
297 struct iovec iov;
298 char cbuf[256];
6865d5c0 299
b71b60ee 300 fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)buffer.c_str(), buffer.length(), &p->d_remote);
2b6f1436 301
3eae691f 302 msgh.msg_control=NULL;
2b6f1436 303 if(p->d_anyLocal) {
fbe2a2e0 304 addCMsgSrcAddr(&msgh, cbuf, p->d_anyLocal.get_ptr(), 0);
2b6f1436 305 }
e6a9dde5 306 DLOG(g_log<<Logger::Notice<<"Sending a packet to "<< p->getRemote() <<" ("<< buffer.length()<<" octets)"<<endl);
1bd5361b 307 if(buffer.length() > p->getMaxReplyLen()) {
dfa4c4a6 308 g_log<<Logger::Error<<"Weird, trying to send a message that needs truncation, "<< buffer.length()<<" > "<<p->getMaxReplyLen()<<". Question was for "<<p->qdomain<<"|"<<p->qtype.getName()<<endl;
12c86877 309 }
2b6f1436 310 if(sendmsg(p->getSocket(), &msgh, 0) < 0)
e6a9dde5 311 g_log<<Logger::Error<<"Error sending reply with sendmsg (socket="<<p->getSocket()<<", dest="<<p->d_remote.toStringWithPort()<<"): "<<strerror(errno)<<endl;
12c86877
BH
312}
313
2c001eb6 314DNSPacket *UDPNameserver::receive(DNSPacket *prefilled, std::string& buffer)
2b6f1436
BH
315{
316 ComboAddress remote;
317 extern StatBag S;
a683e8bd 318 ssize_t len=-1;
2b6f1436 319 Utility::sock_t sock=-1;
1cd66b8e 320
2b6f1436
BH
321 struct msghdr msgh;
322 struct iovec iov;
323 char cbuf[256];
324
b71b60ee 325 remote.sin6.sin6_family=AF_INET6; // make sure it is big enough
2c001eb6 326 fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), &buffer.at(0), buffer.size(), &remote);
2b6f1436
BH
327
328 int err;
223066c6 329 vector<struct pollfd> rfds= d_rfds;
315dd2e6 330
28c266da 331 for(auto &pfd : rfds) {
315dd2e6 332 pfd.events = POLLIN;
333 pfd.revents = 0;
334 }
2b6f1436 335
ee79512a 336 retry:;
337
315dd2e6 338 err = poll(&rfds[0], rfds.size(), -1);
ee79512a 339 if(err < 0) {
340 if(errno==EINTR)
341 goto retry;
315dd2e6 342 unixDie("Unable to poll for new UDP events");
ee79512a 343 }
2b6f1436 344
28c266da 345 for(auto &pfd : rfds) {
315dd2e6 346 if(pfd.revents & POLLIN) {
347 sock=pfd.fd;
315dd2e6 348 if((len=recvmsg(sock, &msgh, 0)) < 0 ) {
232f0877 349 if(errno != EAGAIN)
e6a9dde5 350 g_log<<Logger::Error<<"recvfrom gave error, ignoring: "<<strerror(errno)<<endl;
232f0877 351 return 0;
2b6f1436 352 }
315dd2e6 353 break;
2b6f1436
BH
354 }
355 }
315dd2e6 356 if(sock==-1)
3f81d239 357 throw PDNSException("poll betrayed us! (should not happen)");
2b6f1436 358
e6a9dde5 359 DLOG(g_log<<"Received a packet " << len <<" bytes long from "<< remote.toString()<<endl);
81859ba5 360
361 BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
362
363 if(remote.sin4.sin_port == 0) // would generate error on responding. sin4 also works for ipv6
364 return 0;
2b6f1436
BH
365
366 DNSPacket *packet;
367 if(prefilled) // they gave us a preallocated packet
368 packet=prefilled;
369 else
27c0050c 370 packet=new DNSPacket(true); // don't forget to free it!
9ae194e2 371
2b6f1436
BH
372 packet->setSocket(sock);
373 packet->setRemote(&remote);
374
375 ComboAddress dest;
376 if(HarvestDestinationAddress(&msgh, &dest)) {
377// cerr<<"Setting d_anyLocal to '"<<dest.toString()<<"'"<<endl;
378 packet->d_anyLocal = dest;
232f0877 379 }
2b6f1436 380
9ae194e2 381 struct timeval recvtv;
382 if(HarvestTimestamp(&msgh, &recvtv)) {
383 packet->d_dt.setTimeval(recvtv);
384 }
385 else
386 packet->d_dt.set(); // timing
387
2c001eb6 388 if(packet->parse(&buffer.at(0), (size_t) len)<0) {
2b6f1436 389 S.inc("corrupt-packets");
4eb26e0f 390 S.ringAccount("remotes-corrupt", packet->d_remote);
2b6f1436
BH
391
392 if(!prefilled)
393 delete packet;
394 return 0; // unable to parse
395 }
396
397 return packet;
398}