]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/nameserver.cc
1ef97afe52baa769208f22b0959710c6f3794571
[thirdparty/pdns.git] / pdns / nameserver.cc
1 /*
2 Copyright (C) 2002 PowerDNS.COM BV
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 // $Id: nameserver.cc,v 1.3 2002/12/10 13:36:26 ahu Exp $
19 #include "utility.hh"
20 #include <cstdio>
21 #include <cstring>
22 #include <cstdlib>
23 #include <cerrno>
24 #include <iostream>
25 #include <string>
26 #include <sys/types.h>
27
28 #include "dns.hh"
29 #include "dnsbackend.hh"
30 #include "dnspacket.hh"
31 #include "nameserver.hh"
32 #include "distributor.hh"
33 #include "logger.hh"
34 #include "arguments.hh"
35 #include "statbag.hh"
36
37 extern StatBag S;
38
39 /** \mainpage
40 ahudns is a very versatile nameserver that can answer questions from different backends. To implement your
41 own backend, see the documentation for the DNSBackend class.
42
43 \section copyright Copyright and License
44 AhuDNS is (C) 2002 PowerDNS BV.
45
46 AhuDNS is NOT open source (yet), so treat this code as a trade secret. If it has been supplied to you for evaluation,
47 this does not mean that you can deploy the code!
48
49 \section overview High level overview
50
51 AhuDNS is highly threaded, which means that several tasks each have their own process thread. Two of the pivotal
52 threads are the qthread() and the athread().
53
54 - The qthread() receives questions over the network (via the Nameserver class, which returns DNSPacket objects), and gives them to the Distributor.
55 - The athread() waits on the Distributor to return answers, ready to send back over the network, again via UDPNameserver.
56
57 The Distributor contains a configurable number of PacketHandler instances, each in its own thread, for connection pooling
58
59 The PacketHandler implements the RFC1034 algorithm and converts question packets into DNSBackend queries.
60
61 A DNSBackend is an entity that returns DNSResourceRecord objects in return to explicit questions for domains with a specified QType
62
63 AhuDNS uses the UeberBackend as its DNSBackend. The UeberBackend by default has no DNSBackends within itself, those are loaded
64 using the dynloader tool. This way DNSBackend implementations can be kept completely separate.
65
66 If one or more DNSBackends are loaded, the UeberBackend fields the queries to all of them until one answers.
67
68 \section TCP TCP Operations
69
70 The TCP operation runs within a single thread called tcpreceiver(), that also queries the PacketHandler.
71
72 \section Cache Caching
73
74 On its own, this setup is not suitable for high performance operations. A single DNS query can turn into many DNSBackend questions,
75 each taking many miliseconds to complete. This is why the qthread() first checks the PacketCache to see if an answer is known to a packet
76 asking this question. If so, the entire Distributor is shunted, and the answer is sent back *directly*, within a few microseconds.
77
78 In turn, the athread() offers each outgoing packet to the PacketCache for possible inclusion.
79
80 \section misc Miscellaneous
81 Configuration details are available via the ArgvMap instance arg. Statistics are created by making calls to the StatBag object called S.
82 These statistics are made available via the UeberBackend on the same socket that is used for dynamic module commands.
83
84 \section Main Main
85 The main() of AhuDNS can be found in receiver.cc - start reading there for further insights into the operation of the nameserver
86
87
88 */
89
90 void UDPNameserver::bindIPv4()
91 {
92 vector<string>locals;
93 stringtok(locals,arg()["local-address"]," ,");
94
95 if(locals.empty())
96 throw AhuException("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 struct sockaddr_in locala;
102
103 s=socket(AF_INET,SOCK_DGRAM,0);
104 if(s<0)
105 throw AhuException("Unable to acquire a UDP socket: "+string(strerror(errno)));
106
107 memset(&locala,0,sizeof(locala));
108 locala.sin_family=AF_INET;
109
110 if(localname=="0.0.0.0") {
111 L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-address option"<<endl;
112
113 locala.sin_addr.s_addr = INADDR_ANY;
114 }
115 else
116 {
117 struct hostent *h=0;
118 h=gethostbyname(localname.c_str());
119 if(!h)
120 throw AhuException("Unable to resolve local address");
121
122 locala.sin_addr.s_addr=*(int*)h->h_addr;
123 }
124
125 locala.sin_port=htons(arg().asNum("local-port"));
126
127 if(bind(s, (sockaddr*)&locala,sizeof(locala))<0) {
128 L<<Logger::Error<<"binding to UDP socket: "<<strerror(errno)<<endl;
129 throw AhuException("Unable to bind to UDP socket");
130 }
131 d_highfd=max(s,d_highfd);
132 d_sockets.push_back(s);
133 L<<Logger::Error<<"UDP server bound to "<<localname<<":"<<arg()["local-port"]<<endl;
134 FD_SET(s, &d_rfds);
135 }
136 }
137
138 void UDPNameserver::bindIPv6()
139 {
140 #if !WIN32 && HAVE_IPV6
141 vector<string>locals;
142 stringtok(locals,arg()["local-ipv6"]," ,");
143
144 if(locals.empty())
145 return;
146
147
148 int s;
149 for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
150 string localname(*i);
151
152 s=socket(AF_INET6,SOCK_DGRAM,0);
153 if(s<0)
154 throw AhuException("Unable to acquire a UDPv6 socket: "+string(strerror(errno)));
155
156 if(localname=="::0") {
157 L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-ipv6 option"<<endl;
158 }
159
160 sockaddr_in6 locala;
161 locala.sin6_port=ntohs(arg().asNum("local-port"));
162 if(!inet_pton(AF_INET6, localname.c_str(), (void *)&locala.sin6_addr)) {
163 addrinfo *addrinfos;
164 addrinfo hints;
165 memset(&hints,0,sizeof(hints));
166 hints.ai_socktype=SOCK_DGRAM;
167 hints.ai_family=AF_INET6;
168
169 if(getaddrinfo(localname.c_str(),arg()["local-port"].c_str(),&hints,&addrinfos))
170 throw AhuException("Unable to resolve local IPv6 address '"+localname+"'");
171 memcpy(&locala,addrinfos->ai_addr,addrinfos->ai_addrlen);
172 }
173
174 if(bind(s, (sockaddr*)&locala, sizeof(locala))<0) {
175 L<<Logger::Error<<"binding to UDP ipv6 socket: "<<strerror(errno)<<endl;
176 throw AhuException("Unable to bind to UDP ipv6 socket");
177 }
178 d_highfd=max(s,d_highfd);
179 d_sockets.push_back(s);
180 L<<Logger::Error<<"UDPv6 server bound to "<<localname<<":"<<arg()["local-port"]<<endl;
181 FD_SET(s, &d_rfds);
182 }
183 #endif // WIN32
184 }
185
186 UDPNameserver::UDPNameserver()
187 {
188 d_highfd=0;
189 FD_ZERO(&d_rfds);
190 if(!arg()["local-address"].empty())
191 bindIPv4();
192 if(!arg()["local-ipv6"].empty())
193 bindIPv6();
194
195 if(arg()["local-address"].empty() && arg()["local-ipv6"].empty())
196 L<<Logger::Critical<<"PDNS is deaf and mute! Not listening on any interfaces"<<endl;
197
198 }
199
200 void UDPNameserver::send(DNSPacket *p)
201 {
202 const char *buffer=p->getData();
203 DLOG(L<<Logger::Notice<<"Sending a packet to "<<inet_ntoa( reinterpret_cast< sockaddr_in * >(( p->remote ))->sin_addr)<<" ("<<p->len<<" octets)"<<endl);
204 if(p->len>512) {
205 p=new DNSPacket(*p);
206 p->truncate(512);
207 buffer=p->getData();
208 if(sendto(p->getSocket(),buffer,p->len,0,(struct sockaddr *)(p->remote),p->d_socklen)<0)
209 L<<Logger::Error<<"Error sending reply with sendto (socket="<<p->getSocket()<<"): "<<strerror(errno)<<endl;
210 delete p;
211 }
212 else {
213
214 if(sendto(p->getSocket(),buffer,p->len,0,(struct sockaddr *)(p->remote),p->d_socklen)<0)
215 L<<Logger::Error<<"Error sending reply with sendto (socket="<<p->getSocket()<<"): "<<strerror(errno)<<endl;
216
217
218
219 }
220 }
221