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