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