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