]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/nameserver.cc
Limit the number of queries sent out to get NS addresses per query.
[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::bindAddresses()
90 {
91 vector<string>locals;
92 stringtok(locals,::arg()["local-ipv6"]," ,");
93 if (!locals.empty()) {
94 g_log<<Logger::Error<<"NOTE: Deprecated local-ipv6 setting used. Please move those addresses to the local-address setting."<<endl;
95 }
96 stringtok(locals,::arg()["local-address"]," ,");
97
98 int one = 1;
99
100 if(locals.empty())
101 throw PDNSException("No local address specified");
102
103 int s;
104 // for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
105 for (const auto &local : locals) {
106 ComboAddress locala(local, ::arg().asNum("local-port"));
107
108 s = socket(locala.sin4.sin_family, SOCK_DGRAM, 0);
109
110 if(s < 0) {
111 if(errno == EAFNOSUPPORT) {
112 g_log<<Logger::Error<<"Binding "<<locala.toStringWithPort()<<": Address Family is not supported - skipping bind" << endl;
113 return;
114 }
115 throw PDNSException("Unable to acquire a UDP socket: "+stringerror());
116 }
117
118 setCloseOnExec(s);
119 if(!setNonBlocking(s))
120 throw PDNSException("Unable to set UDP socket " + locala.toStringWithPort() + " to non-blocking: "+stringerror());
121
122 if(IsAnyAddress(locala)) {
123 setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one));
124 if (locala.isIPv6()) {
125 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); // if this fails, we report an error in tcpreceiver too
126 #ifdef IPV6_RECVPKTINFO
127 setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
128 #endif
129 }
130 }
131
132 if (!setSocketTimestamps(s))
133 g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket "<<locala.toStringWithPort()<<endl;
134
135 if (locala.isIPv4()) {
136 try {
137 setSocketIgnorePMTU(s);
138 }
139 catch(const std::exception& e) {
140 g_log<<Logger::Warning<<"Failed to set IP_MTU_DISCOVER on UDP server socket: "<<e.what()<<endl;
141 }
142 }
143
144 #ifdef SO_REUSEPORT
145 if( d_can_reuseport )
146 if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
147 d_can_reuseport = false;
148 #endif
149
150 if( ::arg().mustDo("non-local-bind") )
151 Utility::setBindAny(locala.sin4.sin_family, s);
152
153 if( !d_additional_socket )
154 g_localaddresses.push_back(locala);
155
156 if(::bind(s, (sockaddr*)&locala, locala.getSocklen()) < 0) {
157 string binderror = stringerror();
158 close(s);
159 if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
160 g_log<<Logger::Error<<"Address " << locala << " does not exist on this server - skipping UDP bind" << endl;
161 continue;
162 } else {
163 g_log<<Logger::Error<<"Unable to bind UDP socket to '"+locala.toStringWithPort()+"': "<<binderror<<endl;
164 throw PDNSException("Unable to bind to UDP socket");
165 }
166 }
167 d_sockets.push_back(s);
168 struct pollfd pfd;
169 pfd.fd = s;
170 pfd.events = POLLIN;
171 pfd.revents = 0;
172 d_rfds.push_back(pfd);
173 g_log<<Logger::Error<<"UDP server bound to "<<locala.toStringWithPort()<<endl;
174 }
175 }
176
177 bool AddressIsUs(const ComboAddress& remote)
178 {
179 for(const ComboAddress& us : g_localaddresses) {
180 if(remote == us)
181 return true;
182 if(IsAnyAddress(us)) {
183 int s = socket(remote.sin4.sin_family, SOCK_DGRAM, 0);
184 if(s < 0)
185 continue;
186
187 if(connect(s, (struct sockaddr*)&remote, remote.getSocklen()) < 0) {
188 close(s);
189 continue;
190 }
191
192 ComboAddress actualLocal;
193 actualLocal.sin4.sin_family = remote.sin4.sin_family;
194 socklen_t socklen = actualLocal.getSocklen();
195
196 if(getsockname(s, (struct sockaddr*) &actualLocal, &socklen) < 0) {
197 close(s);
198 continue;
199 }
200 close(s);
201 actualLocal.sin4.sin_port = us.sin4.sin_port;
202 if(actualLocal == remote)
203 return true;
204 }
205 }
206 return false;
207 }
208
209 UDPNameserver::UDPNameserver( bool additional_socket )
210 {
211 #ifdef SO_REUSEPORT
212 d_can_reuseport = ::arg().mustDo("reuseport");
213 #endif
214 // Are we the main socket (false) or a rebinding using SO_REUSEPORT ?
215 d_additional_socket = additional_socket;
216
217 if(::arg()["local-address"].empty())
218 g_log<<Logger::Critical<<"PDNS is deaf and mute! Not listening on any interfaces"<<endl;
219
220 bindAddresses();
221 }
222
223 void UDPNameserver::send(DNSPacket& p)
224 {
225 const string& buffer=p.getString();
226 g_rs.submitResponse(p, true);
227
228 struct msghdr msgh;
229 struct iovec iov;
230 cmsgbuf_aligned cbuf;
231
232 fillMSGHdr(&msgh, &iov, &cbuf, 0, (char*)buffer.c_str(), buffer.length(), &p.d_remote);
233
234 msgh.msg_control=NULL;
235 if(p.d_anyLocal) {
236 addCMsgSrcAddr(&msgh, &cbuf, p.d_anyLocal.get_ptr(), 0);
237 }
238 DLOG(g_log<<Logger::Notice<<"Sending a packet to "<< p.getRemote() <<" ("<< buffer.length()<<" octets)"<<endl);
239 if(buffer.length() > p.getMaxReplyLen()) {
240 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;
241 }
242 if(sendmsg(p.getSocket(), &msgh, 0) < 0)
243 g_log<<Logger::Error<<"Error sending reply with sendmsg (socket="<<p.getSocket()<<", dest="<<p.d_remote.toStringWithPort()<<"): "<<stringerror()<<endl;
244 }
245
246 bool UDPNameserver::receive(DNSPacket& packet, std::string& buffer)
247 {
248 ComboAddress remote;
249 extern StatBag S;
250 ssize_t len=-1;
251 Utility::sock_t sock=-1;
252
253 struct msghdr msgh;
254 struct iovec iov;
255 cmsgbuf_aligned cbuf;
256
257 remote.sin6.sin6_family=AF_INET6; // make sure it is big enough
258 fillMSGHdr(&msgh, &iov, &cbuf, sizeof(cbuf), &buffer.at(0), buffer.size(), &remote);
259
260 int err;
261 vector<struct pollfd> rfds= d_rfds;
262
263 for(auto &pfd : rfds) {
264 pfd.events = POLLIN;
265 pfd.revents = 0;
266 }
267
268 retry:;
269
270 err = poll(&rfds[0], rfds.size(), -1);
271 if(err < 0) {
272 if(errno==EINTR)
273 goto retry;
274 unixDie("Unable to poll for new UDP events");
275 }
276
277 for(auto &pfd : rfds) {
278 if(pfd.revents & POLLIN) {
279 sock=pfd.fd;
280 if((len=recvmsg(sock, &msgh, 0)) < 0 ) {
281 if(errno != EAGAIN)
282 g_log<<Logger::Error<<"recvfrom gave error, ignoring: "<<stringerror()<<endl;
283 return 0;
284 }
285 break;
286 }
287 }
288 if(sock==-1)
289 throw PDNSException("poll betrayed us! (should not happen)");
290
291 DLOG(g_log<<"Received a packet " << len <<" bytes long from "<< remote.toString()<<endl);
292
293 BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
294
295 if(remote.sin4.sin_port == 0) // would generate error on responding. sin4 also works for ipv6
296 return 0;
297
298 packet.setSocket(sock);
299 packet.setRemote(&remote);
300
301 ComboAddress dest;
302 if(HarvestDestinationAddress(&msgh, &dest)) {
303 // cerr<<"Setting d_anyLocal to '"<<dest.toString()<<"'"<<endl;
304 packet.d_anyLocal = dest;
305 }
306
307 struct timeval recvtv;
308 if(HarvestTimestamp(&msgh, &recvtv)) {
309 packet.d_dt.setTimeval(recvtv);
310 }
311 else
312 packet.d_dt.set(); // timing
313
314 if(packet.parse(&buffer.at(0), (size_t) len)<0) {
315 S.inc("corrupt-packets");
316 S.ringAccount("remotes-corrupt", packet.d_remote);
317
318 return false; // unable to parse
319 }
320
321 return true;
322 }