]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/pdns_recursor.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 PowerDNS.COM BV
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include "dnspacket.hh"
33 #include "arguments.hh"
37 int sem_init(sem_t
*, int, unsigned int){return 0;}
38 int sem_wait(sem_t
*){return 0;}
39 int sem_trywait(sem_t
*){return 0;}
40 int sem_post(sem_t
*){return 0;}
41 int sem_getvalue(sem_t
*, int*){return 0;}
47 static ArgvMap theArg
;
56 struct sockaddr_in remote
;
59 bool operator<(const PacketID
& a
, const PacketID
& b
)
65 if(a
.remote
.sin_addr
.s_addr
< b
.remote
.sin_addr
.s_addr
)
67 if(a
.remote
.sin_addr
.s_addr
== b
.remote
.sin_addr
.s_addr
)
68 if(a
.remote
.sin_port
< b
.remote
.sin_port
)
75 MTasker
<PacketID
,string
> MT(100000); // could probably be way lower
77 /* these two functions are used by LWRes */
78 int asendto(const char *data
, int len
, int flags
, struct sockaddr
*toaddr
, int addrlen
, int id
)
80 return sendto(d_clientsock
, data
, len
, flags
, toaddr
, addrlen
);
83 int arecvfrom(char *data
, int len
, int flags
, struct sockaddr
*toaddr
, socklen_t
*addrlen
, int *d_len
, int id
)
87 memcpy(&pident
.remote
,toaddr
,sizeof(pident
.remote
));
90 if(!MT
.waitEvent(pident
,&packet
,1)) { // timeout
95 memcpy(data
,packet
.c_str(),min(len
,*d_len
));
100 typedef map
<string
,set
<DNSResourceRecord
> > cache_t
;
102 int cacheHits
, cacheMisses
;
103 int getCache(const string
&qname
, const QType
& qt
, set
<DNSResourceRecord
>* res
)
105 cache_t::const_iterator j
=cache
.find(toLower(qname
)+"|"+qt
.getName());
106 if(j
!=cache
.end() && j
->first
==toLower(qname
)+"|"+qt
.getName() && j
->second
.begin()->ttl
>(unsigned int)time(0)) {
110 return (unsigned int)j
->second
.begin()->ttl
-time(0);
116 void replaceCache(const string
&qname
, const QType
& qt
, const set
<DNSResourceRecord
>& content
)
118 cache
[toLower(qname
)+"|"+qt
.getName()]=content
;
128 static char*ips
[]={"198.41.0.4", "128.9.0.107", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53",
129 "192.36.148.17","192.58.128.30", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
130 DNSResourceRecord arr
, nsrr
;
132 arr
.ttl
=time(0)+3600000;
133 nsrr
.qtype
=QType::NS
;
134 nsrr
.ttl
=time(0)+3600000;
136 set
<DNSResourceRecord
>nsset
;
137 for(char c
='a';c
<='m';++c
) {
138 static char templ
[40];
139 strncpy(templ
,"a.root-servers.net", sizeof(templ
) - 1);
141 arr
.qname
=nsrr
.content
=templ
;
142 arr
.content
=ips
[c
-'a'];
143 set
<DNSResourceRecord
>aset
;
145 replaceCache(string(templ
),QType(QType::A
),aset
);
149 replaceCache("",QType(QType::NS
),nsset
);
152 void startDoResolve(void *p
)
155 bool quiet
=arg().mustDo("quiet");
156 DNSPacket P
=*(DNSPacket
*)p
;
158 delete (DNSPacket
*)p
;
160 vector
<DNSResourceRecord
>ret
;
161 DNSPacket
*R
=P
.replyPacket();
167 L
<<Logger::Error
<<"["<<MT
.getTid()<<"] question for '"<<P
.qdomain
<<"|"<<P
.qtype
.getName()<<"' from "<<P
.getRemote()<<endl
;
169 sr
.setId(MT
.getTid());
173 int res
=sr
.beginResolve(P
.qdomain
, P
.qtype
, ret
);
175 R
->setRcode(RCode::ServFail
);
178 for(vector
<DNSResourceRecord
>::const_iterator i
=ret
.begin();i
!=ret
.end();++i
)
182 const char *buffer
=R
->getData();
183 sendto(d_serversock
,buffer
,R
->len
,0,(struct sockaddr
*)(R
->remote
),R
->d_socklen
);
185 L
<<Logger::Error
<<"["<<MT
.getTid()<<"] answer to "<<(P
.d
.rd
?"":"non-rd ")<<"question '"<<P
.qdomain
<<"|"<<P
.qtype
.getName();
186 L
<<"': "<<ntohs(R
->d
.ancount
)<<" answers, "<<ntohs(R
->d
.arcount
)<<" additional, took "<<sr
.d_outqueries
<<" packets, rcode="<<res
<<endl
;
189 sr
.d_outqueries
? cacheMisses
++ : cacheHits
++;
193 catch(AhuException
&ae
) {
194 L
<<Logger::Error
<<"startDoResolve problem: "<<ae
.reason
<<endl
;
197 L
<<Logger::Error
<<"Any other exception in a resolver context"<<endl
;
201 void makeClientSocket()
203 d_clientsock
=socket(AF_INET
, SOCK_DGRAM
,0);
205 throw AhuException("Making a socket for resolver: "+stringerror());
207 struct sockaddr_in sin
;
208 memset((char *)&sin
,0, sizeof(sin
));
210 sin
.sin_family
= AF_INET
;
211 sin
.sin_addr
.s_addr
= INADDR_ANY
;
215 u_int16_t port
=10000+random()%10000;
216 sin
.sin_port
= htons(port
);
218 if (bind(d_clientsock
, (struct sockaddr
*)&sin
, sizeof(sin
)) >= 0)
223 throw AhuException("Resolver binding to local socket: "+stringerror());
226 void makeServerSocket()
228 d_serversock
=socket(AF_INET
, SOCK_DGRAM
,0);
230 throw AhuException("Making a server socket for resolver: "+stringerror());
232 struct sockaddr_in sin
;
233 memset((char *)&sin
,0, sizeof(sin
));
235 sin
.sin_family
= AF_INET
;
237 if(arg()["local-address"]=="0.0.0.0") {
238 L
<<Logger::Warning
<<"It is advised to bind to explicit addresses with the --local-address option"<<endl
;
239 sin
.sin_addr
.s_addr
= INADDR_ANY
;
243 h
=gethostbyname(arg()["local-address"].c_str());
245 throw AhuException("Unable to resolve local address");
247 sin
.sin_addr
.s_addr
=*(int*)h
->h_addr
;
250 sin
.sin_port
= htons(arg().asNum("local-port"));
252 if (bind(d_serversock
, (struct sockaddr
*)&sin
, sizeof(sin
))<0)
253 throw AhuException("Resolver binding to server socket: "+stringerror());
254 L
<<Logger::Error
<<"Incoming query source port: "<<arg().asNum("local-port")<<endl
;
263 // cleanup open fds, but skip sockets
269 int counter
, qcounter
;
272 void usr1Handler(int)
279 L
<<Logger::Error
<<"stats: "<<qcounter
<<" questions, "<<cache
.size()<<" cache entries, "<<SyncRes::s_negcache
.size()<<" negative entries, "
280 <<(int)((cacheHits
*100.0)/(cacheHits
+cacheMisses
))<<"% cache hits";
281 L
<<Logger::Error
<<", outpacket/query ratio "<<(int)(SyncRes::s_outqueries
*100.0/SyncRes::s_queries
)<<"%"<<endl
;
286 void houseKeeping(void *)
288 static time_t last_stat
, last_rootupdate
;
290 if(time(0)-last_stat
>1800) {
294 if(time(0)-last_rootupdate
>7200) {
296 vector
<DNSResourceRecord
>ret
;
299 int res
=sr
.beginResolve("", QType(QType::NS
), ret
);
301 L
<<Logger::Error
<<"Refreshed . records"<<endl
;
302 last_rootupdate
=time(0);
305 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;
309 int main(int argc
, char **argv
)
313 arg().set("soa-minimum-ttl","Don't change")="0";
314 arg().set("soa-serial-offset","Don't change")="0";
315 arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off";
316 arg().set("local-port","port to listen on")="53";
317 arg().set("local-address","port to listen on")="0.0.0.0";
318 arg().set("trace","if we should output heaps of logging")="off";
319 arg().set("daemon","Operate as a daemon")="yes";
320 arg().set("quiet","Suppress logging of questions and answers")="off";
321 arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR
;
322 arg().setCmd("help","Provide a helpful message");
323 L
.toConsole(Logger::Warning
);
324 arg().laxParse(argc
,argv
); // do a lax parse
326 string configname
=arg()["config-dir"]+"/recursor.conf";
327 cleanSlashes(configname
);
329 if(!arg().file(configname
.c_str()))
330 L
<<Logger::Warning
<<"Unable to parse configuration file '"<<configname
<<"'"<<endl
;
332 arg().parse(argc
,argv
);
335 if(arg().mustDo("help")) {
336 cerr
<<"syntax:"<<endl
<<endl
;
337 cerr
<<arg().helpstring(arg()["help"])<<endl
;
341 L
.setName("pdns_recursor");
343 if(arg().mustDo("trace"))
344 SyncRes::setLog(true);
350 struct sockaddr_in fromaddr
;
354 L
<<Logger::Warning
<<"Done priming cache with root hints"<<endl
;
356 if(arg().mustDo("daemon")) {
357 L
.toConsole(Logger::Critical
);
360 signal(SIGUSR1
,usr1Handler
);
363 while(MT
.schedule()); // housekeeping, let threads do their thing
365 if(!((counter
++)%100))
366 MT
.makeThread(houseKeeping
,0);
370 socklen_t addrlen
=sizeof(fromaddr
);
380 FD_SET( d_clientsock
, &readfds
);
381 FD_SET( d_serversock
, &readfds
);
382 int selret
= select( max(d_clientsock
,d_serversock
) + 1, &readfds
, NULL
, NULL
, &tv
);
384 if (selret
== -1 && errno
!=EINTR
)
385 throw AhuException("Select returned: "+stringerror());
390 if(FD_ISSET(d_clientsock
,&readfds
)) { // do we have a question response?
391 d_len
=recvfrom(d_clientsock
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
);
395 P
.setRemote((struct sockaddr
*)&fromaddr
, addrlen
);
396 if(P
.parse(data
,d_len
)<0) {
397 L
<<Logger::Error
<<"Unparseable packet from remote server "<<P
.getRemote()<<endl
;
402 pident
.remote
=fromaddr
;
405 packet
.assign(data
,d_len
);
406 MT
.sendEvent(pident
,&packet
);
409 L
<<Logger::Warning
<<"Ignoring question on outgoing socket from "<<P
.getRemote()<<endl
;
413 if(FD_ISSET(d_serversock
,&readfds
)) { // do we have a new question?
414 d_len
=recvfrom(d_serversock
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
);
417 P
.setRemote((struct sockaddr
*)&fromaddr
, addrlen
);
418 if(P
.parse(data
,d_len
)<0) {
419 L
<<Logger::Error
<<"Unparseable packet from remote client "<<P
.getRemote()<<endl
;
423 L
<<Logger::Error
<<"Ignoring answer on server socket!"<<endl
;
426 MT
.makeThread(startDoResolve
,(void*)new DNSPacket(P
));
433 catch(AhuException
&ae
) {
434 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
436 catch(exception
&e
) {
437 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
440 L
<<Logger::Error
<<"any other exception in main: "<<endl
;