]>
Commit | Line | Data |
---|---|---|
288f4aa9 BH |
1 | /* |
2 | PowerDNS Versatile Database Driven Nameserver | |
36c5ee42 | 3 | Copyright (C) 2005 PowerDNS.COM BV |
288f4aa9 BH |
4 | |
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. | |
9 | ||
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. | |
14 | ||
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 | |
18 | */ | |
caa6eefa BH |
19 | |
20 | #include "utility.hh" | |
288f4aa9 BH |
21 | #include <iostream> |
22 | #include <errno.h> | |
23 | #include <map> | |
24 | #include <set> | |
caa6eefa | 25 | #ifndef WIN32 |
288f4aa9 | 26 | #include <netdb.h> |
caa6eefa | 27 | #endif // WIN32 |
288f4aa9 | 28 | #include <stdio.h> |
c75a6a9e | 29 | #include <signal.h> |
288f4aa9 BH |
30 | #include <stdlib.h> |
31 | #include <unistd.h> | |
32 | #include "mtasker.hh" | |
33 | #include <utility> | |
34 | #include "dnspacket.hh" | |
35 | #include "statbag.hh" | |
36 | #include "arguments.hh" | |
37 | #include "syncres.hh" | |
88def049 BH |
38 | #include <fcntl.h> |
39 | #include <fstream> | |
eefd15f9 BH |
40 | #include "recursor_cache.hh" |
41 | ||
27adc173 | 42 | #ifdef __FreeBSD__ // see cvstrac ticket #26 |
7f617eb9 BH |
43 | #include <pthread.h> |
44 | #include <semaphore.h> | |
45 | #endif | |
46 | ||
eefd15f9 | 47 | MemRecursorCache RC; |
88def049 BH |
48 | |
49 | string s_programname="pdns_recursor"; | |
288f4aa9 | 50 | |
27adc173 BH |
51 | #ifndef WIN32 |
52 | #ifndef __FreeBSD__ | |
288f4aa9 BH |
53 | extern "C" { |
54 | int sem_init(sem_t*, int, unsigned int){return 0;} | |
55 | int sem_wait(sem_t*){return 0;} | |
56 | int sem_trywait(sem_t*){return 0;} | |
57 | int sem_post(sem_t*){return 0;} | |
58 | int sem_getvalue(sem_t*, int*){return 0;} | |
dcf9bd8f | 59 | pthread_t pthread_self(void){return (pthread_t) 0;} |
98e05fce | 60 | int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr){ return 0; } |
dcf9bd8f BH |
61 | int pthread_mutex_lock(pthread_mutex_t *mutex){ return 0; } |
62 | int pthread_mutex_unlock(pthread_mutex_t *mutex) { return 0; } | |
98e05fce | 63 | |
288f4aa9 | 64 | } |
27adc173 | 65 | #endif // __FreeBSD__ |
caa6eefa | 66 | #endif // WIN32 |
288f4aa9 BH |
67 | |
68 | StatBag S; | |
69 | ArgvMap &arg() | |
70 | { | |
71 | static ArgvMap theArg; | |
72 | return theArg; | |
73 | } | |
bacc40d9 BH |
74 | static int d_clientsock; |
75 | static int d_serversock; | |
76 | static int d_tcpserversock; | |
288f4aa9 BH |
77 | |
78 | struct PacketID | |
79 | { | |
80 | u_int16_t id; | |
81 | struct sockaddr_in remote; | |
82 | }; | |
83 | ||
84 | bool operator<(const PacketID& a, const PacketID& b) | |
85 | { | |
86 | if(a.id<b.id) | |
87 | return true; | |
88 | ||
89 | if(a.id==b.id) { | |
90 | if(a.remote.sin_addr.s_addr < b.remote.sin_addr.s_addr) | |
91 | return true; | |
92 | if(a.remote.sin_addr.s_addr == b.remote.sin_addr.s_addr) | |
93 | if(a.remote.sin_port < b.remote.sin_port) | |
94 | return true; | |
95 | } | |
96 | ||
97 | return false; | |
98 | } | |
99 | ||
fededf47 | 100 | MTasker<PacketID,string>* MT; |
288f4aa9 BH |
101 | |
102 | /* these two functions are used by LWRes */ | |
103 | int asendto(const char *data, int len, int flags, struct sockaddr *toaddr, int addrlen, int id) | |
104 | { | |
105 | return sendto(d_clientsock, data, len, flags, toaddr, addrlen); | |
106 | } | |
107 | ||
caa6eefa | 108 | int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, Utility::socklen_t *addrlen, int *d_len, int id) |
288f4aa9 BH |
109 | { |
110 | PacketID pident; | |
111 | pident.id=id; | |
112 | memcpy(&pident.remote,toaddr,sizeof(pident.remote)); | |
b636533b | 113 | |
288f4aa9 | 114 | string packet; |
fededf47 | 115 | if(!MT->waitEvent(pident,&packet,1)) { // timeout |
288f4aa9 BH |
116 | return 0; |
117 | } | |
118 | ||
119 | *d_len=packet.size(); | |
120 | memcpy(data,packet.c_str(),min(len,*d_len)); | |
121 | ||
122 | return 1; | |
123 | } | |
124 | ||
c75a6a9e | 125 | |
ae1b2e98 BH |
126 | |
127 | ||
88def049 BH |
128 | static void writePid(void) |
129 | { | |
130 | string fname=arg()["socket-dir"]+"/"+s_programname+".pid"; | |
131 | ofstream of(fname.c_str()); | |
132 | if(of) | |
133 | of<<getpid()<<endl; | |
134 | else | |
562588a3 | 135 | L<<Logger::Error<<"Requested to write pid for "<<getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl; |
88def049 BH |
136 | } |
137 | ||
bdf40704 | 138 | void primeHints(void) |
288f4aa9 BH |
139 | { |
140 | // prime root cache | |
49f076e8 BH |
141 | |
142 | static char*ips[]={"198.41.0.4", "192.228.79.201", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53", | |
c75a6a9e | 143 | "192.36.148.17","192.58.128.30", "193.0.14.129", "198.32.64.12", "202.12.27.33"}; |
288f4aa9 BH |
144 | DNSResourceRecord arr, nsrr; |
145 | arr.qtype=QType::A; | |
146 | arr.ttl=time(0)+3600000; | |
147 | nsrr.qtype=QType::NS; | |
148 | nsrr.ttl=time(0)+3600000; | |
149 | ||
150 | set<DNSResourceRecord>nsset; | |
151 | for(char c='a';c<='m';++c) { | |
152 | static char templ[40]; | |
153 | strncpy(templ,"a.root-servers.net", sizeof(templ) - 1); | |
154 | *templ=c; | |
155 | arr.qname=nsrr.content=templ; | |
156 | arr.content=ips[c-'a']; | |
157 | set<DNSResourceRecord>aset; | |
158 | aset.insert(arr); | |
eefd15f9 | 159 | RC.replace(string(templ),QType(QType::A),aset); |
288f4aa9 BH |
160 | |
161 | nsset.insert(nsrr); | |
162 | } | |
eefd15f9 | 163 | RC.replace("",QType(QType::NS),nsset); |
288f4aa9 BH |
164 | } |
165 | ||
166 | void startDoResolve(void *p) | |
167 | { | |
168 | try { | |
c75a6a9e | 169 | bool quiet=arg().mustDo("quiet"); |
288f4aa9 | 170 | DNSPacket P=*(DNSPacket *)p; |
b636533b | 171 | |
288f4aa9 | 172 | delete (DNSPacket *)p; |
b636533b | 173 | |
288f4aa9 BH |
174 | vector<DNSResourceRecord>ret; |
175 | DNSPacket *R=P.replyPacket(); | |
176 | R->setA(false); | |
177 | R->setRA(true); | |
178 | ||
7b35aa49 | 179 | SyncRes sr; |
c75a6a9e | 180 | if(!quiet) |
fededf47 | 181 | L<<Logger::Error<<"["<<MT->getTid()<<"] question for '"<<P.qdomain<<"|"<<P.qtype.getName()<<"' from "<<P.getRemote()<<endl; |
c75a6a9e | 182 | |
fededf47 | 183 | sr.setId(MT->getTid()); |
c836dc19 BH |
184 | if(!P.d.rd) |
185 | sr.setCacheOnly(); | |
186 | ||
288f4aa9 BH |
187 | int res=sr.beginResolve(P.qdomain, P.qtype, ret); |
188 | if(res<0) | |
189 | R->setRcode(RCode::ServFail); | |
190 | else { | |
191 | R->setRcode(res); | |
192 | for(vector<DNSResourceRecord>::const_iterator i=ret.begin();i!=ret.end();++i) | |
193 | R->addRecord(*i); | |
194 | } | |
195 | ||
196 | const char *buffer=R->getData(); | |
9c495589 BH |
197 | if(!R->getSocket()) |
198 | sendto(d_serversock,buffer,R->len,0,(struct sockaddr *)(R->remote),R->d_socklen); | |
199 | else { | |
200 | char buf[2]; | |
201 | buf[0]=R->len/256; | |
202 | buf[1]=R->len%256; | |
203 | if(write(R->getSocket(),buf,2)!=2 || write(R->getSocket(),buffer,R->len)!=R->len) | |
204 | L<<Logger::Error<<"Oops, partial answer sent to "<<P.getRemote()<<" - probably would have trouble receiving our answer anyhow (size="<<R->len<<")"<<endl; | |
205 | } | |
206 | ||
c75a6a9e | 207 | if(!quiet) { |
fededf47 | 208 | L<<Logger::Error<<"["<<MT->getTid()<<"] answer to "<<(P.d.rd?"":"non-rd ")<<"question '"<<P.qdomain<<"|"<<P.qtype.getName(); |
3de83124 | 209 | L<<"': "<<ntohs(R->d.ancount)<<" answers, "<<ntohs(R->d.arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<< |
d77df2e1 | 210 | sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, rcode="<<res<<endl; |
c75a6a9e BH |
211 | } |
212 | ||
eefd15f9 | 213 | sr.d_outqueries ? RC.cacheMisses++ : RC.cacheHits++; |
b636533b | 214 | |
288f4aa9 BH |
215 | delete R; |
216 | } | |
217 | catch(AhuException &ae) { | |
c836dc19 | 218 | L<<Logger::Error<<"startDoResolve problem: "<<ae.reason<<endl; |
288f4aa9 BH |
219 | } |
220 | catch(...) { | |
c836dc19 | 221 | L<<Logger::Error<<"Any other exception in a resolver context"<<endl; |
288f4aa9 BH |
222 | } |
223 | } | |
224 | ||
225 | void makeClientSocket() | |
226 | { | |
227 | d_clientsock=socket(AF_INET, SOCK_DGRAM,0); | |
228 | if(d_clientsock<0) | |
229 | throw AhuException("Making a socket for resolver: "+stringerror()); | |
230 | ||
231 | struct sockaddr_in sin; | |
232 | memset((char *)&sin,0, sizeof(sin)); | |
233 | ||
234 | sin.sin_family = AF_INET; | |
235 | sin.sin_addr.s_addr = INADDR_ANY; | |
236 | ||
237 | int tries=10; | |
238 | while(--tries) { | |
caa6eefa | 239 | u_int16_t port=10000+Utility::random()%10000; |
288f4aa9 BH |
240 | sin.sin_port = htons(port); |
241 | ||
c836dc19 | 242 | if (bind(d_clientsock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) |
288f4aa9 | 243 | break; |
288f4aa9 BH |
244 | |
245 | } | |
246 | if(!tries) | |
247 | throw AhuException("Resolver binding to local socket: "+stringerror()); | |
976196d2 BH |
248 | |
249 | Utility::setNonBlocking(d_clientsock); | |
288f4aa9 BH |
250 | } |
251 | ||
9c495589 BH |
252 | void makeTCPServerSocket() |
253 | { | |
254 | d_tcpserversock=socket(AF_INET, SOCK_STREAM,0); | |
255 | if(d_tcpserversock<0) | |
256 | throw AhuException("Making a server socket for resolver: "+stringerror()); | |
257 | ||
258 | struct sockaddr_in sin; | |
259 | memset((char *)&sin,0, sizeof(sin)); | |
260 | ||
261 | sin.sin_family = AF_INET; | |
262 | ||
263 | if(arg()["local-address"]=="0.0.0.0") { | |
264 | sin.sin_addr.s_addr = INADDR_ANY; | |
265 | } | |
266 | else { | |
525b8a7c | 267 | if(!IpToU32(arg()["local-address"], &sin.sin_addr.s_addr)) |
9c495589 | 268 | throw AhuException("Unable to resolve local address"); |
9c495589 BH |
269 | } |
270 | ||
271 | sin.sin_port = htons(arg().asNum("local-port")); | |
bacc40d9 | 272 | |
9c495589 BH |
273 | int tmp=1; |
274 | if(setsockopt(d_tcpserversock,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) { | |
275 | L<<Logger::Error<<"Setsockopt failed"<<endl; | |
276 | exit(1); | |
277 | } | |
bacc40d9 BH |
278 | |
279 | if (bind(d_tcpserversock, (struct sockaddr *)&sin, sizeof(sin))<0) | |
280 | throw AhuException("TCP Resolver binding to server socket: "+stringerror()); | |
281 | ||
282 | ||
283 | Utility::setNonBlocking(d_tcpserversock); | |
9c495589 BH |
284 | |
285 | listen(d_tcpserversock, 128); | |
286 | } | |
287 | ||
288f4aa9 BH |
288 | void makeServerSocket() |
289 | { | |
290 | d_serversock=socket(AF_INET, SOCK_DGRAM,0); | |
291 | if(d_serversock<0) | |
292 | throw AhuException("Making a server socket for resolver: "+stringerror()); | |
293 | ||
294 | struct sockaddr_in sin; | |
295 | memset((char *)&sin,0, sizeof(sin)); | |
296 | ||
297 | sin.sin_family = AF_INET; | |
298 | ||
299 | if(arg()["local-address"]=="0.0.0.0") { | |
c836dc19 | 300 | L<<Logger::Warning<<"It is advised to bind to explicit addresses with the --local-address option"<<endl; |
288f4aa9 BH |
301 | sin.sin_addr.s_addr = INADDR_ANY; |
302 | } | |
303 | else { | |
288f4aa9 | 304 | |
525b8a7c BH |
305 | if(!IpToU32(arg()["local-address"], &sin.sin_addr.s_addr)) |
306 | throw AhuException("Unable to resolve local address"); | |
307 | ||
288f4aa9 BH |
308 | } |
309 | ||
310 | sin.sin_port = htons(arg().asNum("local-port")); | |
311 | ||
312 | if (bind(d_serversock, (struct sockaddr *)&sin, sizeof(sin))<0) | |
313 | throw AhuException("Resolver binding to server socket: "+stringerror()); | |
bacc40d9 BH |
314 | |
315 | Utility::setNonBlocking(d_serversock); | |
316 | ||
c836dc19 BH |
317 | L<<Logger::Error<<"Incoming query source port: "<<arg().asNum("local-port")<<endl; |
318 | } | |
caa6eefa | 319 | |
9c495589 | 320 | |
caa6eefa | 321 | #ifndef WIN32 |
c836dc19 BH |
322 | void daemonize(void) |
323 | { | |
324 | if(fork()) | |
325 | exit(0); // bye bye | |
326 | ||
327 | setsid(); | |
328 | ||
329 | // cleanup open fds, but skip sockets | |
330 | close(0); | |
331 | close(1); | |
332 | close(2); | |
333 | ||
288f4aa9 | 334 | } |
caa6eefa BH |
335 | #endif |
336 | ||
c836dc19 | 337 | int counter, qcounter; |
c75a6a9e BH |
338 | bool statsWanted; |
339 | ||
340 | void usr1Handler(int) | |
341 | { | |
342 | statsWanted=true; | |
343 | } | |
ae1b2e98 BH |
344 | |
345 | ||
c75a6a9e BH |
346 | void doStats(void) |
347 | { | |
348 | if(qcounter) { | |
eefd15f9 BH |
349 | |
350 | L<<Logger::Error<<"stats: "<<qcounter<<" questions, "<<RC.size()<<" cache entries, "<<SyncRes::s_negcache.size()<<" negative entries, " | |
351 | <<(int)((RC.cacheHits*100.0)/(RC.cacheHits+RC.cacheMisses))<<"% cache hits"; | |
3de83124 | 352 | L<<Logger::Error<<", outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%"; |
525b8a7c BH |
353 | L<<Logger::Error<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, " |
354 | <<SyncRes::s_nodelegated<<" no-delegation drops"<<endl; | |
e5d684f9 | 355 | L<<Logger::Error<<"queries running: "<<MT->numProcesses()<<endl; |
eefd15f9 | 356 | |
c75a6a9e BH |
357 | } |
358 | statsWanted=false; | |
359 | } | |
c836dc19 BH |
360 | |
361 | void houseKeeping(void *) | |
362 | { | |
ae1b2e98 | 363 | static time_t last_stat, last_rootupdate, last_prune; |
36c5ee42 BH |
364 | time_t now=time(0); |
365 | if(now - last_stat>60) { | |
eefd15f9 | 366 | RC.doPrune(); |
ae1b2e98 BH |
367 | last_prune=time(0); |
368 | } | |
36c5ee42 | 369 | if(now - last_stat>1800) { |
c75a6a9e | 370 | doStats(); |
c836dc19 BH |
371 | last_stat=time(0); |
372 | } | |
36c5ee42 | 373 | if(now -last_rootupdate>7200) { |
7b35aa49 | 374 | SyncRes sr; |
c836dc19 BH |
375 | vector<DNSResourceRecord>ret; |
376 | ||
377 | sr.setNoCache(); | |
378 | int res=sr.beginResolve("", QType(QType::NS), ret); | |
379 | if(!res) { | |
380 | L<<Logger::Error<<"Refreshed . records"<<endl; | |
36c5ee42 | 381 | last_rootupdate=now; |
c836dc19 BH |
382 | } |
383 | else | |
384 | L<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl; | |
385 | } | |
386 | } | |
288f4aa9 | 387 | |
9c495589 BH |
388 | struct TCPConnection |
389 | { | |
390 | int fd; | |
391 | enum {BYTE0, BYTE1, GETQUESTION} state; | |
392 | int qlen; | |
393 | int bytesread; | |
394 | struct sockaddr_in remote; | |
395 | char data[65535]; | |
396 | }; | |
397 | ||
288f4aa9 BH |
398 | int main(int argc, char **argv) |
399 | { | |
caa6eefa BH |
400 | #ifdef WIN32 |
401 | WSADATA wsaData; | |
402 | WSAStartup( MAKEWORD( 2, 0 ), &wsaData ); | |
403 | #endif // WIN32 | |
404 | ||
288f4aa9 | 405 | try { |
caa6eefa | 406 | Utility::srandom(time(0)); |
b636533b BH |
407 | arg().set("soa-minimum-ttl","Don't change")="0"; |
408 | arg().set("soa-serial-offset","Don't change")="0"; | |
87da00e7 | 409 | arg().set("no-shuffle","Don't change")="off"; |
b636533b | 410 | arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off"; |
c75a6a9e | 411 | arg().set("local-port","port to listen on")="53"; |
ba7b2cb5 | 412 | arg().set("local-address","single address to listen on")="0.0.0.0"; |
7b35aa49 | 413 | arg().set("trace","if we should output heaps of logging")="off"; |
c75a6a9e BH |
414 | arg().set("daemon","Operate as a daemon")="yes"; |
415 | arg().set("quiet","Suppress logging of questions and answers")="off"; | |
416 | arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR; | |
88def049 | 417 | arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR; |
562588a3 | 418 | arg().set("delegation-only","Which domains we only accept delegations from")=""; |
b636533b | 419 | arg().setCmd("help","Provide a helpful message"); |
c75a6a9e BH |
420 | L.toConsole(Logger::Warning); |
421 | arg().laxParse(argc,argv); // do a lax parse | |
422 | ||
423 | string configname=arg()["config-dir"]+"/recursor.conf"; | |
424 | cleanSlashes(configname); | |
425 | ||
426 | if(!arg().file(configname.c_str())) | |
427 | L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl; | |
428 | ||
429 | arg().parse(argc,argv); | |
c836dc19 | 430 | |
562588a3 BH |
431 | arg().set("delegation-only")=toLower(arg()["delegation-only"]); |
432 | ||
b636533b BH |
433 | if(arg().mustDo("help")) { |
434 | cerr<<"syntax:"<<endl<<endl; | |
435 | cerr<<arg().helpstring(arg()["help"])<<endl; | |
436 | exit(99); | |
437 | } | |
438 | ||
c836dc19 | 439 | L.setName("pdns_recursor"); |
288f4aa9 | 440 | |
c836dc19 | 441 | if(arg().mustDo("trace")) |
7b35aa49 | 442 | SyncRes::setLog(true); |
288f4aa9 BH |
443 | |
444 | makeClientSocket(); | |
445 | makeServerSocket(); | |
9c495589 | 446 | makeTCPServerSocket(); |
288f4aa9 | 447 | |
fededf47 | 448 | MT=new MTasker<PacketID,string>(100000); |
562588a3 | 449 | |
288f4aa9 BH |
450 | char data[1500]; |
451 | struct sockaddr_in fromaddr; | |
452 | ||
453 | PacketID pident; | |
bdf40704 | 454 | primeHints(); |
c836dc19 | 455 | L<<Logger::Warning<<"Done priming cache with root hints"<<endl; |
caa6eefa | 456 | #ifndef WIN32 |
c836dc19 BH |
457 | if(arg().mustDo("daemon")) { |
458 | L.toConsole(Logger::Critical); | |
459 | daemonize(); | |
460 | } | |
c75a6a9e | 461 | signal(SIGUSR1,usr1Handler); |
88def049 BH |
462 | |
463 | writePid(); | |
caa6eefa | 464 | #endif |
c75a6a9e | 465 | |
9c495589 | 466 | vector<TCPConnection> tcpconnections; |
49f076e8 | 467 | counter=0; |
288f4aa9 | 468 | for(;;) { |
fededf47 | 469 | while(MT->schedule()); // housekeeping, let threads do their thing |
288f4aa9 | 470 | |
c75a6a9e | 471 | if(!((counter++)%100)) |
fededf47 | 472 | MT->makeThread(houseKeeping,0); |
c75a6a9e BH |
473 | if(statsWanted) |
474 | doStats(); | |
c836dc19 | 475 | |
caa6eefa | 476 | Utility::socklen_t addrlen=sizeof(fromaddr); |
288f4aa9 BH |
477 | int d_len; |
478 | DNSPacket P; | |
479 | ||
480 | struct timeval tv; | |
481 | tv.tv_sec=0; | |
482 | tv.tv_usec=500000; | |
483 | ||
484 | fd_set readfds; | |
485 | FD_ZERO( &readfds ); | |
486 | FD_SET( d_clientsock, &readfds ); | |
487 | FD_SET( d_serversock, &readfds ); | |
9c495589 BH |
488 | FD_SET( d_tcpserversock, &readfds ); |
489 | int fdmax=max(d_tcpserversock,max(d_clientsock,d_serversock)); | |
490 | for(vector<TCPConnection>::const_iterator i=tcpconnections.begin();i!=tcpconnections.end();++i) { | |
491 | FD_SET(i->fd, &readfds); | |
492 | fdmax=max(fdmax,i->fd); | |
493 | } | |
8d022964 | 494 | |
8d022964 | 495 | /* this should listen on a TCP port as well for new connections, */ |
9c495589 | 496 | int selret = select( fdmax + 1, &readfds, NULL, NULL, &tv ); |
c75a6a9e BH |
497 | if(selret<=0) |
498 | if (selret == -1 && errno!=EINTR) | |
288f4aa9 | 499 | throw AhuException("Select returned: "+stringerror()); |
c75a6a9e BH |
500 | else |
501 | continue; | |
502 | ||
288f4aa9 BH |
503 | if(FD_ISSET(d_clientsock,&readfds)) { // do we have a question response? |
504 | d_len=recvfrom(d_clientsock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen); | |
c836dc19 | 505 | if(d_len<0) |
288f4aa9 | 506 | continue; |
288f4aa9 BH |
507 | |
508 | P.setRemote((struct sockaddr *)&fromaddr, addrlen); | |
509 | if(P.parse(data,d_len)<0) { | |
c836dc19 | 510 | L<<Logger::Error<<"Unparseable packet from remote server "<<P.getRemote()<<endl; |
288f4aa9 BH |
511 | } |
512 | else { | |
513 | if(P.d.qr) { | |
c836dc19 | 514 | |
288f4aa9 BH |
515 | pident.remote=fromaddr; |
516 | pident.id=P.d.id; | |
c836dc19 BH |
517 | string packet; |
518 | packet.assign(data,d_len); | |
fededf47 | 519 | MT->sendEvent(pident,&packet); |
288f4aa9 BH |
520 | } |
521 | else | |
c836dc19 | 522 | L<<Logger::Warning<<"Ignoring question on outgoing socket from "<<P.getRemote()<<endl; |
288f4aa9 BH |
523 | } |
524 | } | |
525 | ||
9c495589 | 526 | if(FD_ISSET(d_serversock,&readfds)) { // do we have a new question on udp? |
288f4aa9 | 527 | d_len=recvfrom(d_serversock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen); |
c836dc19 | 528 | if(d_len<0) |
288f4aa9 | 529 | continue; |
288f4aa9 BH |
530 | P.setRemote((struct sockaddr *)&fromaddr, addrlen); |
531 | if(P.parse(data,d_len)<0) { | |
c836dc19 | 532 | L<<Logger::Error<<"Unparseable packet from remote client "<<P.getRemote()<<endl; |
288f4aa9 BH |
533 | } |
534 | else { | |
535 | if(P.d.qr) | |
c836dc19 | 536 | L<<Logger::Error<<"Ignoring answer on server socket!"<<endl; |
288f4aa9 | 537 | else { |
c836dc19 | 538 | ++qcounter; |
9c495589 | 539 | P.setSocket(0); |
fededf47 | 540 | MT->makeThread(startDoResolve,(void*)new DNSPacket(P)); |
c836dc19 | 541 | |
288f4aa9 BH |
542 | } |
543 | } | |
544 | } | |
9c495589 BH |
545 | |
546 | if(FD_ISSET(d_tcpserversock,&readfds)) { // do we have a new TCP connection | |
547 | struct sockaddr_in addr; | |
548 | socklen_t addrlen=sizeof(addr); | |
549 | int newsock=accept(d_tcpserversock, (struct sockaddr*)&addr, &addrlen); | |
bacc40d9 | 550 | |
9c495589 | 551 | if(newsock>0) { |
bacc40d9 | 552 | Utility::setNonBlocking(newsock); |
9c495589 BH |
553 | TCPConnection tc; |
554 | tc.fd=newsock; | |
555 | tc.state=TCPConnection::BYTE0; | |
556 | tc.remote=addr; | |
9c495589 BH |
557 | tcpconnections.push_back(tc); |
558 | } | |
559 | } | |
560 | ||
561 | for(vector<TCPConnection>::iterator i=tcpconnections.begin();i!=tcpconnections.end();++i) { | |
562 | if(FD_ISSET(i->fd, &readfds)) { | |
563 | if(i->state==TCPConnection::BYTE0) { | |
564 | int bytes=read(i->fd,i->data,2); | |
565 | if(bytes==1) | |
566 | i->state=TCPConnection::BYTE1; | |
567 | if(bytes==2) { | |
568 | i->qlen=(i->data[0]<<8)+i->data[1]; | |
569 | i->bytesread=0; | |
570 | i->state=TCPConnection::GETQUESTION; | |
571 | } | |
572 | if(!bytes || bytes < 0) { | |
9c495589 BH |
573 | close(i->fd); |
574 | tcpconnections.erase(i); | |
575 | break; | |
576 | } | |
577 | } | |
578 | else if(i->state==TCPConnection::BYTE1) { | |
579 | int bytes=read(i->fd,i->data+1,1); | |
580 | if(bytes==1) { | |
581 | i->state=TCPConnection::GETQUESTION; | |
582 | i->qlen=(i->data[0]<<8)+i->data[1]; | |
583 | i->bytesread=0; | |
584 | } | |
585 | if(!bytes || bytes < 0) { | |
586 | L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&i->remote,sizeof(i->remote))<<" disconnected after first byte"<<endl; | |
587 | close(i->fd); | |
588 | tcpconnections.erase(i); | |
589 | break; | |
590 | } | |
591 | ||
592 | } | |
593 | else if(i->state==TCPConnection::GETQUESTION) { | |
594 | int bytes=read(i->fd,i->data + i->bytesread,i->qlen - i->bytesread); | |
595 | if(!bytes || bytes < 0) { | |
596 | L<<Logger::Error<<"TCP Remote "<<sockAddrToString(&i->remote,sizeof(i->remote))<<" disconnected while reading question body"<<endl; | |
597 | close(i->fd); | |
598 | tcpconnections.erase(i); | |
599 | break; | |
600 | } | |
601 | i->bytesread+=bytes; | |
602 | if(i->bytesread==i->qlen) { | |
603 | i->state=TCPConnection::BYTE0; | |
604 | ||
605 | if(P.parse(i->data,i->qlen)<0) { | |
606 | L<<Logger::Error<<"Unparseable packet from remote client "<<P.getRemote()<<endl; | |
607 | close(i->fd); | |
608 | tcpconnections.erase(i); | |
609 | break; | |
610 | } | |
611 | else { | |
612 | P.setSocket(i->fd); | |
613 | P.setRemote((struct sockaddr *)&i->remote,sizeof(i->remote)); | |
614 | if(P.d.qr) | |
615 | L<<Logger::Error<<"Ignoring answer on server socket!"<<endl; | |
616 | else { | |
617 | ++qcounter; | |
fededf47 | 618 | MT->makeThread(startDoResolve,(void*)new DNSPacket(P)); |
9c495589 BH |
619 | } |
620 | } | |
621 | } | |
622 | } | |
623 | } | |
624 | } | |
288f4aa9 BH |
625 | } |
626 | } | |
627 | catch(AhuException &ae) { | |
c836dc19 | 628 | L<<Logger::Error<<"Exception: "<<ae.reason<<endl; |
288f4aa9 BH |
629 | } |
630 | catch(exception &e) { | |
c836dc19 | 631 | L<<Logger::Error<<"STL Exception: "<<e.what()<<endl; |
288f4aa9 BH |
632 | } |
633 | catch(...) { | |
c836dc19 | 634 | L<<Logger::Error<<"any other exception in main: "<<endl; |
288f4aa9 | 635 | } |
caa6eefa BH |
636 | |
637 | #ifdef WIN32 | |
638 | WSACleanup(); | |
639 | #endif // WIN32 | |
640 | ||
641 | return 0; | |
288f4aa9 | 642 | } |