]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/nameserver.cc
Merge pull request #7450 from omoerbeek/avoid-unaligned-access
[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 #ifdef SO_REUSEPORT
127 if( d_can_reuseport )
128 if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
129 d_can_reuseport = false;
130 #endif
131
132 if( ::arg().mustDo("non-local-bind") )
133 Utility::setBindAny(AF_INET, s);
134
135
136 if( !d_additional_socket )
137 g_localaddresses.push_back(locala);
138
139 if(::bind(s, (sockaddr*)&locala, locala.getSocklen()) < 0) {
140 string binderror = strerror(errno);
141 close(s);
142 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
143 g_log<<Logger::Error<<"IPv4 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
144 continue;
145 } else {
146 g_log<<Logger::Error<<"Unable to bind UDP socket to '"+locala.toStringWithPort()+"': "<<binderror<<endl;
147 throw PDNSException("Unable to bind to UDP socket");
148 }
149 }
150 d_sockets.push_back(s);
151 g_log<<Logger::Error<<"UDP server bound to "<<locala.toStringWithPort()<<endl;
152 struct pollfd pfd;
153 pfd.fd = s;
154 pfd.events = POLLIN;
155 pfd.revents = 0;
156 d_rfds.push_back(pfd);
157 }
158 }
159
160 bool AddressIsUs(const ComboAddress& remote)
161 {
162 for(const ComboAddress& us : g_localaddresses) {
163 if(remote == us)
164 return true;
165 if(IsAnyAddress(us)) {
166 int s = socket(remote.sin4.sin_family, SOCK_DGRAM, 0);
167 if(s < 0)
168 continue;
169
170 if(connect(s, (struct sockaddr*)&remote, remote.getSocklen()) < 0) {
171 close(s);
172 continue;
173 }
174
175 ComboAddress actualLocal;
176 actualLocal.sin4.sin_family = remote.sin4.sin_family;
177 socklen_t socklen = actualLocal.getSocklen();
178
179 if(getsockname(s, (struct sockaddr*) &actualLocal, &socklen) < 0) {
180 close(s);
181 continue;
182 }
183 close(s);
184 actualLocal.sin4.sin_port = us.sin4.sin_port;
185 if(actualLocal == remote)
186 return true;
187 }
188 }
189 return false;
190 }
191
192
193 void UDPNameserver::bindIPv6()
194 {
195 vector<string> locals;
196 stringtok(locals,::arg()["local-ipv6"]," ,");
197 int one=1;
198
199 if(locals.empty())
200 return;
201
202 int s;
203 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
204 string localname(*i);
205
206 s=socket(AF_INET6,SOCK_DGRAM,0);
207 if(s<0) {
208 if( errno == EAFNOSUPPORT ) {
209 g_log<<Logger::Error<<"IPv6 Address Family is not supported - skipping UDPv6 bind" << endl;
210 return;
211 } else {
212 g_log<<Logger::Error<<"Unable to acquire a UDPv6 socket: "+string(strerror(errno)) << endl;
213 throw PDNSException("Unable to acquire a UDPv6 socket: "+string(strerror(errno)));
214 }
215 }
216
217 setCloseOnExec(s);
218 if(!setNonBlocking(s))
219 throw PDNSException("Unable to set UDPv6 socket to non-blocking: "+stringerror());
220
221 ComboAddress locala(localname, ::arg().asNum("local-port"));
222
223 if(IsAnyAddress(locala)) {
224 setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
225 #ifdef IPV6_RECVPKTINFO
226 setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
227 #endif
228 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); // if this fails, we report an error in tcpreceiver too
229 }
230
231 if (!setSocketTimestamps(s))
232 g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
233
234 #ifdef SO_REUSEPORT
235 if( d_can_reuseport )
236 if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
237 d_can_reuseport = false;
238 #endif
239
240 if( ::arg().mustDo("non-local-bind") )
241 Utility::setBindAny(AF_INET6, s);
242
243 if( !d_additional_socket )
244 g_localaddresses.push_back(locala);
245 if(::bind(s, (sockaddr*)&locala, locala.getSocklen())<0) {
246 close(s);
247 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
248 g_log<<Logger::Error<<"IPv6 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
249 continue;
250 } else {
251 g_log<<Logger::Error<<"Unable to bind to UDPv6 socket "<< localname <<": "<<strerror(errno)<<endl;
252 throw PDNSException("Unable to bind to UDPv6 socket");
253 }
254 }
255 d_sockets.push_back(s);
256 struct pollfd pfd;
257 pfd.fd = s;
258 pfd.events = POLLIN;
259 pfd.revents = 0;
260 d_rfds.push_back(pfd);
261 g_log<<Logger::Error<<"UDPv6 server bound to "<<locala.toStringWithPort()<<endl;
262 }
263 }
264
265 UDPNameserver::UDPNameserver( bool additional_socket )
266 {
267 #ifdef SO_REUSEPORT
268 d_can_reuseport = ::arg().mustDo("reuseport");
269 #endif
270 // Are we the main socket (false) or a rebinding using SO_REUSEPORT ?
271 d_additional_socket = additional_socket;
272
273 if(!::arg()["local-address"].empty())
274 bindIPv4();
275 if(!::arg()["local-ipv6"].empty())
276 bindIPv6();
277
278 if(::arg()["local-address"].empty() && ::arg()["local-ipv6"].empty())
279 g_log<<Logger::Critical<<"PDNS is deaf and mute! Not listening on any interfaces"<<endl;
280 }
281
282 void UDPNameserver::send(DNSPacket *p)
283 {
284 string buffer=p->getString();
285 g_rs.submitResponse(*p, true);
286
287 struct msghdr msgh;
288 struct iovec iov;
289 char cbuf[256];
290
291 fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)buffer.c_str(), buffer.length(), &p->d_remote);
292
293 msgh.msg_control=NULL;
294 if(p->d_anyLocal) {
295 addCMsgSrcAddr(&msgh, cbuf, p->d_anyLocal.get_ptr(), 0);
296 }
297 DLOG(g_log<<Logger::Notice<<"Sending a packet to "<< p->getRemote() <<" ("<< buffer.length()<<" octets)"<<endl);
298 if(buffer.length() > p->getMaxReplyLen()) {
299 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;
300 }
301 if(sendmsg(p->getSocket(), &msgh, 0) < 0)
302 g_log<<Logger::Error<<"Error sending reply with sendmsg (socket="<<p->getSocket()<<", dest="<<p->d_remote.toStringWithPort()<<"): "<<strerror(errno)<<endl;
303 }
304
305 DNSPacket *UDPNameserver::receive(DNSPacket *prefilled, std::string& buffer)
306 {
307 ComboAddress remote;
308 extern StatBag S;
309 ssize_t len=-1;
310 Utility::sock_t sock=-1;
311
312 struct msghdr msgh;
313 struct iovec iov;
314 char cbuf[256];
315
316 remote.sin6.sin6_family=AF_INET6; // make sure it is big enough
317 fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), &buffer.at(0), buffer.size(), &remote);
318
319 int err;
320 vector<struct pollfd> rfds= d_rfds;
321
322 for(auto &pfd : rfds) {
323 pfd.events = POLLIN;
324 pfd.revents = 0;
325 }
326
327 retry:;
328
329 err = poll(&rfds[0], rfds.size(), -1);
330 if(err < 0) {
331 if(errno==EINTR)
332 goto retry;
333 unixDie("Unable to poll for new UDP events");
334 }
335
336 for(auto &pfd : rfds) {
337 if(pfd.revents & POLLIN) {
338 sock=pfd.fd;
339 if((len=recvmsg(sock, &msgh, 0)) < 0 ) {
340 if(errno != EAGAIN)
341 g_log<<Logger::Error<<"recvfrom gave error, ignoring: "<<strerror(errno)<<endl;
342 return 0;
343 }
344 break;
345 }
346 }
347 if(sock==-1)
348 throw PDNSException("poll betrayed us! (should not happen)");
349
350 DLOG(g_log<<"Received a packet " << len <<" bytes long from "<< remote.toString()<<endl);
351
352 BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
353
354 if(remote.sin4.sin_port == 0) // would generate error on responding. sin4 also works for ipv6
355 return 0;
356
357 DNSPacket *packet;
358 if(prefilled) // they gave us a preallocated packet
359 packet=prefilled;
360 else
361 packet=new DNSPacket(true); // don't forget to free it!
362
363 packet->setSocket(sock);
364 packet->setRemote(&remote);
365
366 ComboAddress dest;
367 if(HarvestDestinationAddress(&msgh, &dest)) {
368 // cerr<<"Setting d_anyLocal to '"<<dest.toString()<<"'"<<endl;
369 packet->d_anyLocal = dest;
370 }
371
372 struct timeval recvtv;
373 if(HarvestTimestamp(&msgh, &recvtv)) {
374 packet->d_dt.setTimeval(recvtv);
375 }
376 else
377 packet->d_dt.set(); // timing
378
379 if(packet->parse(&buffer.at(0), (size_t) len)<0) {
380 S.inc("corrupt-packets");
381 S.ringAccount("remotes-corrupt", packet->d_remote);
382
383 if(!prefilled)
384 delete packet;
385 return 0; // unable to parse
386 }
387
388 return packet;
389 }