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