]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/nameserver.cc
auth: switch circleci mssql image
[thirdparty/pdns.git] / pdns / nameserver.cc
1 /*
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 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
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>
33 #include "responsestats.hh"
34
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
44 #include "namespaces.hh"
45
46 extern StatBag S;
47
48 /** \mainpage
49 PowerDNS is a very versatile nameserver that can answer questions from different backends. To implement your
50 own backend, see the documentation for the DNSBackend class.
51
52 \section copyright Copyright and License
53 PowerDNS is (C) 2001-2008 PowerDNS.COM BV. It is distributed according to the terms of the General Public License version 2.
54
55 \section overview High level overview
56
57 The Distributor contains a configurable number of PacketHandler instances, each in its own thread, for connection pooling.
58 PacketHandler instances are recycled of they let escape an PDNSException.
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
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.
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,
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
77 asking this question. If so, the entire Distributor is shunted, and the answer is sent back *directly*, within a few microseconds.
78
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
84 The main() of PowerDNS can be found in receiver.cc - start reading there for further insights into the operation of the nameserver
85 */
86
87 vector<ComboAddress> g_localaddresses; // not static, our unit tests need to poke this
88
89 void UDPNameserver::bindIPv4()
90 {
91 vector<string>locals;
92 stringtok(locals,::arg()["local-address"]," ,");
93 int one = 1;
94
95 if(locals.empty())
96 throw PDNSException("No local address specified");
97
98 int s;
99 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
100 string localname(*i);
101 ComboAddress locala;
102
103 s=socket(AF_INET,SOCK_DGRAM,0);
104
105 if(s<0) {
106 g_log<<Logger::Error<<"Unable to acquire UDP socket: "+string(strerror(errno)) << endl;
107 throw PDNSException("Unable to acquire a UDP socket: "+string(strerror(errno)));
108 }
109
110 setCloseOnExec(s);
111
112 if(!setNonBlocking(s))
113 throw PDNSException("Unable to set UDP socket to non-blocking: "+stringerror());
114
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");
119
120 if(IsAnyAddress(locala))
121 setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one));
122
123 if (!setSocketTimestamps(s))
124 g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
125
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
135 #ifdef SO_REUSEPORT
136 if( d_can_reuseport )
137 if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
138 d_can_reuseport = false;
139 #endif
140
141 if( ::arg().mustDo("non-local-bind") )
142 Utility::setBindAny(AF_INET, s);
143
144
145 if( !d_additional_socket )
146 g_localaddresses.push_back(locala);
147
148 if(::bind(s, (sockaddr*)&locala, locala.getSocklen()) < 0) {
149 string binderror = strerror(errno);
150 close(s);
151 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
152 g_log<<Logger::Error<<"IPv4 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
153 continue;
154 } else {
155 g_log<<Logger::Error<<"Unable to bind UDP socket to '"+locala.toStringWithPort()+"': "<<binderror<<endl;
156 throw PDNSException("Unable to bind to UDP socket");
157 }
158 }
159 d_sockets.push_back(s);
160 g_log<<Logger::Error<<"UDP server bound to "<<locala.toStringWithPort()<<endl;
161 struct pollfd pfd;
162 pfd.fd = s;
163 pfd.events = POLLIN;
164 pfd.revents = 0;
165 d_rfds.push_back(pfd);
166 }
167 }
168
169 bool AddressIsUs(const ComboAddress& remote)
170 {
171 for(const ComboAddress& us : g_localaddresses) {
172 if(remote == us)
173 return true;
174 if(IsAnyAddress(us)) {
175 int s = socket(remote.sin4.sin_family, SOCK_DGRAM, 0);
176 if(s < 0)
177 continue;
178
179 if(connect(s, (struct sockaddr*)&remote, remote.getSocklen()) < 0) {
180 close(s);
181 continue;
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) {
189 close(s);
190 continue;
191 }
192 close(s);
193 actualLocal.sin4.sin_port = us.sin4.sin_port;
194 if(actualLocal == remote)
195 return true;
196 }
197 }
198 return false;
199 }
200
201
202 void UDPNameserver::bindIPv6()
203 {
204 vector<string> locals;
205 stringtok(locals,::arg()["local-ipv6"]," ,");
206 int one=1;
207
208 if(locals.empty())
209 return;
210
211 int s;
212 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
213 string localname(*i);
214
215 s=socket(AF_INET6,SOCK_DGRAM,0);
216 if(s<0) {
217 if( errno == EAFNOSUPPORT ) {
218 g_log<<Logger::Error<<"IPv6 Address Family is not supported - skipping UDPv6 bind" << endl;
219 return;
220 } else {
221 g_log<<Logger::Error<<"Unable to acquire a UDPv6 socket: "+string(strerror(errno)) << endl;
222 throw PDNSException("Unable to acquire a UDPv6 socket: "+string(strerror(errno)));
223 }
224 }
225
226 setCloseOnExec(s);
227 if(!setNonBlocking(s))
228 throw PDNSException("Unable to set UDPv6 socket to non-blocking: "+stringerror());
229
230 ComboAddress locala(localname, ::arg().asNum("local-port"));
231
232 if(IsAnyAddress(locala)) {
233 setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
234 #ifdef IPV6_RECVPKTINFO
235 setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
236 #endif
237 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); // if this fails, we report an error in tcpreceiver too
238 }
239
240 if (!setSocketTimestamps(s))
241 g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
242
243 #ifdef SO_REUSEPORT
244 if( d_can_reuseport )
245 if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
246 d_can_reuseport = false;
247 #endif
248
249 if( ::arg().mustDo("non-local-bind") )
250 Utility::setBindAny(AF_INET6, s);
251
252 if( !d_additional_socket )
253 g_localaddresses.push_back(locala);
254 if(::bind(s, (sockaddr*)&locala, locala.getSocklen())<0) {
255 close(s);
256 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
257 g_log<<Logger::Error<<"IPv6 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
258 continue;
259 } else {
260 g_log<<Logger::Error<<"Unable to bind to UDPv6 socket "<< localname <<": "<<strerror(errno)<<endl;
261 throw PDNSException("Unable to bind to UDPv6 socket");
262 }
263 }
264 d_sockets.push_back(s);
265 struct pollfd pfd;
266 pfd.fd = s;
267 pfd.events = POLLIN;
268 pfd.revents = 0;
269 d_rfds.push_back(pfd);
270 g_log<<Logger::Error<<"UDPv6 server bound to "<<locala.toStringWithPort()<<endl;
271 }
272 }
273
274 UDPNameserver::UDPNameserver( bool additional_socket )
275 {
276 #ifdef SO_REUSEPORT
277 d_can_reuseport = ::arg().mustDo("reuseport");
278 #endif
279 // Are we the main socket (false) or a rebinding using SO_REUSEPORT ?
280 d_additional_socket = additional_socket;
281
282 if(!::arg()["local-address"].empty())
283 bindIPv4();
284 if(!::arg()["local-ipv6"].empty())
285 bindIPv6();
286
287 if(::arg()["local-address"].empty() && ::arg()["local-ipv6"].empty())
288 g_log<<Logger::Critical<<"PDNS is deaf and mute! Not listening on any interfaces"<<endl;
289 }
290
291 void UDPNameserver::send(DNSPacket *p)
292 {
293 string buffer=p->getString();
294 g_rs.submitResponse(*p, true);
295
296 struct msghdr msgh;
297 struct iovec iov;
298 char cbuf[256];
299
300 fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)buffer.c_str(), buffer.length(), &p->d_remote);
301
302 msgh.msg_control=NULL;
303 if(p->d_anyLocal) {
304 addCMsgSrcAddr(&msgh, cbuf, p->d_anyLocal.get_ptr(), 0);
305 }
306 DLOG(g_log<<Logger::Notice<<"Sending a packet to "<< p->getRemote() <<" ("<< buffer.length()<<" octets)"<<endl);
307 if(buffer.length() > p->getMaxReplyLen()) {
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;
309 }
310 if(sendmsg(p->getSocket(), &msgh, 0) < 0)
311 g_log<<Logger::Error<<"Error sending reply with sendmsg (socket="<<p->getSocket()<<", dest="<<p->d_remote.toStringWithPort()<<"): "<<strerror(errno)<<endl;
312 }
313
314 DNSPacket *UDPNameserver::receive(DNSPacket *prefilled, std::string& buffer)
315 {
316 ComboAddress remote;
317 extern StatBag S;
318 ssize_t len=-1;
319 Utility::sock_t sock=-1;
320
321 struct msghdr msgh;
322 struct iovec iov;
323 char cbuf[256];
324
325 remote.sin6.sin6_family=AF_INET6; // make sure it is big enough
326 fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), &buffer.at(0), buffer.size(), &remote);
327
328 int err;
329 vector<struct pollfd> rfds= d_rfds;
330
331 for(auto &pfd : rfds) {
332 pfd.events = POLLIN;
333 pfd.revents = 0;
334 }
335
336 retry:;
337
338 err = poll(&rfds[0], rfds.size(), -1);
339 if(err < 0) {
340 if(errno==EINTR)
341 goto retry;
342 unixDie("Unable to poll for new UDP events");
343 }
344
345 for(auto &pfd : rfds) {
346 if(pfd.revents & POLLIN) {
347 sock=pfd.fd;
348 if((len=recvmsg(sock, &msgh, 0)) < 0 ) {
349 if(errno != EAGAIN)
350 g_log<<Logger::Error<<"recvfrom gave error, ignoring: "<<strerror(errno)<<endl;
351 return 0;
352 }
353 break;
354 }
355 }
356 if(sock==-1)
357 throw PDNSException("poll betrayed us! (should not happen)");
358
359 DLOG(g_log<<"Received a packet " << len <<" bytes long from "<< remote.toString()<<endl);
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;
365
366 DNSPacket *packet;
367 if(prefilled) // they gave us a preallocated packet
368 packet=prefilled;
369 else
370 packet=new DNSPacket(true); // don't forget to free it!
371
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;
379 }
380
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
388 if(packet->parse(&buffer.at(0), (size_t) len)<0) {
389 S.inc("corrupt-packets");
390 S.ringAccount("remotes-corrupt", packet->d_remote);
391
392 if(!prefilled)
393 delete packet;
394 return 0; // unable to parse
395 }
396
397 return packet;
398 }