]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
e9b863ea3436fa40ecd3e2053aa2ff1d036166a1
[user/henk/code/inspircd.git] / src / dns.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                     E-mail:
7  *              <brain@chatspike.net>
8  *              <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *          the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 /*
18 dns.cpp - Nonblocking DNS functions.
19 Very very loosely based on the firedns library,
20 Copyright (C) 2002 Ian Gulliver. This file is no
21 longer anything like firedns, there are many major
22 differences between this code and the original.
23 Please do not assume that firedns works like this,
24 looks like this, walks like this or tastes like this.
25 */
26
27 using namespace std;
28
29 #include <string>
30 #include <time.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <map>
39 #include "dns.h"
40 #include "inspircd.h"
41 #include "helperfuncs.h"
42 #include "inspircd_config.h"
43 #include "socketengine.h"
44 #include "configreader.h"
45
46 /* We need these */
47 extern InspIRCd* ServerInstance;
48 extern ServerConfig* Config;
49
50 /* Master file descriptor */
51 int DNS::MasterSocket;
52
53 /* Masks to mask off the responses we get from the DNSRequest methods */
54 enum QueryInfo
55 {
56         ERROR_MASK      = 0x10000       /* Result is an error */
57 };
58
59 /* Flags which can be ORed into a request or reply for different meanings */
60 enum QueryFlags
61 {
62         FLAGS_MASK_RD           = 0x01, /* Recursive */
63         FLAGS_MASK_TC           = 0x02,
64         FLAGS_MASK_AA           = 0x04, /* Authoritative */
65         FLAGS_MASK_OPCODE       = 0x78,
66         FLAGS_MASK_QR           = 0x80,
67         FLAGS_MASK_RCODE        = 0x0F, /* Request */
68         FLAGS_MASK_Z            = 0x70,
69         FLAGS_MASK_RA           = 0x80
70 };
71
72
73 /* Represents a dns resource record (rr) */
74 class ResourceRecord
75 {
76  public:
77         QueryType       type;           /* Record type */
78         unsigned int    rr_class;       /* Record class */
79         unsigned long   ttl;            /* Time to live */
80         unsigned int    rdlength;       /* Record length */
81 };
82
83 /* Represents a dns request/reply header, and its payload as opaque data.
84  */
85 class DNSHeader
86 {
87  public:
88         unsigned char   id[2];          /* Request id */
89         unsigned int    flags1;         /* Flags */
90         unsigned int    flags2;         /* Flags */
91         unsigned int    qdcount;
92         unsigned int    ancount;        /* Answer count */
93         unsigned int    nscount;        /* Nameserver count */
94         unsigned int    arcount;
95         unsigned char   payload[512];   /* Packet payload */
96 };
97
98 /* Represents a request 'on the wire' with routing information relating to
99  * where to call when we get a result
100  */
101 class DNSRequest
102 {
103  public:
104         unsigned char   id[2];          /* Request id */
105         unsigned char*  res;            /* Result processing buffer */
106         unsigned int    rr_class;       /* Request class */
107         QueryType       type;           /* Request type */
108         insp_inaddr     myserver;       /* DNS server address*/
109
110         /* Allocate the processing buffer */
111         DNSRequest(insp_inaddr server)
112         {
113                 res = new unsigned char[512];
114                 *res = 0;
115                 memcpy(&myserver, &server, sizeof(insp_inaddr));
116         }
117
118         /* Deallocate the processing buffer */
119         ~DNSRequest()
120         {
121                 delete[] res;
122         }
123
124         /* Called when a result is ready to be processed which matches this id */
125         DNSInfo ResultIsReady(DNSHeader &h, int length);
126
127         /* Called when there are requests to be sent out */
128         int SendRequests(const DNSHeader *header, const int length, QueryType qt);
129 };
130
131 /* Fill a ResourceRecord class based on raw data input */
132 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
133 {
134         rr->type = (QueryType)((input[0] << 8) + input[1]);
135         rr->rr_class = (input[2] << 8) + input[3];
136         rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
137         rr->rdlength = (input[8] << 8) + input[9];
138 }
139
140 /* Fill a DNSHeader class based on raw data input of a given length */
141 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
142 {
143         header->id[0] = input[0];
144         header->id[1] = input[1];
145         header->flags1 = input[2];
146         header->flags2 = input[3];
147         header->qdcount = (input[4] << 8) + input[5];
148         header->ancount = (input[6] << 8) + input[7];
149         header->nscount = (input[8] << 8) + input[9];
150         header->arcount = (input[10] << 8) + input[11];
151         memcpy(header->payload,&input[12],length);
152 }
153
154 /* Empty a DNSHeader class out into raw data, ready for transmission */
155 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
156 {
157         output[0] = header->id[0];
158         output[1] = header->id[1];
159         output[2] = header->flags1;
160         output[3] = header->flags2;
161         output[4] = header->qdcount >> 8;
162         output[5] = header->qdcount & 0xFF;
163         output[6] = header->ancount >> 8;
164         output[7] = header->ancount & 0xFF;
165         output[8] = header->nscount >> 8;
166         output[9] = header->nscount & 0xFF;
167         output[10] = header->arcount >> 8;
168         output[11] = header->arcount & 0xFF;
169         memcpy(&output[12],header->payload,length);
170 }
171
172 /* Send requests we have previously built down the UDP socket */
173 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
174 {
175         insp_sockaddr addr;
176         unsigned char payload[sizeof(DNSHeader)];
177
178         this->rr_class = 1;
179         this->type = qt;
180                 
181         DNS::EmptyHeader(payload,header,length);
182
183         memset(&addr,0,sizeof(addr));
184 #ifdef IPV6
185         memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
186         addr.sin6_family = AF_FAMILY;
187         addr.sin6_port = htons(DNS::QUERY_PORT);
188 #else
189         memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
190         addr.sin_family = AF_FAMILY;
191         addr.sin_port = htons(DNS::QUERY_PORT);
192 #endif
193         if (sendto(DNS::GetMasterSocket(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
194         {
195                 log(DEBUG,"Error in sendto!");
196                 return -1;
197         }
198
199         return 0;
200 }
201
202 /* Add a query with a predefined header, and allocate an ID for it. */
203 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
204 {
205         if (requests.size() == DNS::MAX_REQUEST_ID + 1)
206                 return NULL;
207         
208         id = this->PRNG() & DNS::MAX_REQUEST_ID;
209
210         /* This id is already 'in flight', pick another.
211          * -- Thanks jilles 
212          */
213         while (requests.find(id) != requests.end())
214                 id = this->PRNG() & DNS::MAX_REQUEST_ID;
215
216         DNSRequest* req = new DNSRequest(this->myserver);
217
218         header->id[0] = req->id[0] = id >> 8;
219         header->id[1] = req->id[1] = id & 0xFF;
220         header->flags1 = FLAGS_MASK_RD;
221         header->flags2 = 0;
222         header->qdcount = 1;
223         header->ancount = 0;
224         header->nscount = 0;
225         header->arcount = 0;
226
227         /* At this point we already know the id doesnt exist,
228          * so there needs to be no second check for the ::end()
229          */
230         requests[id] = req;
231
232         /* According to the C++ spec, new never returns NULL. */
233         return req;
234 }
235
236 int DNS::GetMasterSocket()
237 {
238         return MasterSocket;
239 }
240
241 /* Initialise the DNS UDP socket so that we can send requests */
242 DNS::DNS()
243 {
244         insp_inaddr addr;
245
246         /* Clear the Resolver class table */
247         memset(Classes,0,sizeof(Classes));
248
249         /* Set the id of the next request to 0
250          */
251         currid = 0;
252
253         /* Clear the namesever address */
254         memset(&myserver,0,sizeof(insp_inaddr));
255
256         /* Convert the nameserver address into an insp_inaddr */
257         if (insp_aton(Config->DNSServer,&addr) > 0)
258                 memcpy(&myserver,&addr,sizeof(insp_inaddr));
259
260         /* Initialize mastersocket */
261         MasterSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
262         if (MasterSocket != -1)
263         {
264                 /* Did it succeed? */
265                 if (fcntl(MasterSocket, F_SETFL, O_NONBLOCK) != 0)
266                 {
267                         /* Couldn't make the socket nonblocking */
268                         shutdown(MasterSocket,2);
269                         close(MasterSocket);
270                         MasterSocket = -1;
271                 }
272         }
273         /* Have we got a socket and is it nonblocking? */
274         if (MasterSocket != -1)
275         {
276 #ifdef IPV6
277                 insp_sockaddr addr;
278                 memset(&addr,0,sizeof(addr));
279                 addr.sin6_family = AF_FAMILY;
280                 addr.sin6_port = 0;
281                 memset(&addr.sin6_addr,255,sizeof(in6_addr));
282 #else
283                 insp_sockaddr addr;
284                 memset(&addr,0,sizeof(addr));
285                 addr.sin_family = AF_FAMILY;
286                 addr.sin_port = 0;
287                 addr.sin_addr.s_addr = INADDR_ANY;
288 #endif
289                 /* Bind the port */
290                 if (bind(MasterSocket,(sockaddr *)&addr,sizeof(addr)) != 0)
291                 {
292                         /* Failed to bind */
293                         log(DEBUG,"Cant bind DNS::MasterSocket");
294                         shutdown(MasterSocket,2);
295                         close(MasterSocket);
296                         MasterSocket = -1;
297                 }
298
299                 if (MasterSocket >= 0)
300                 {
301                         /* Hook the descriptor into the socket engine */
302                         if (ServerInstance && ServerInstance->SE)
303                                 ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS);
304                 }
305         }
306 }
307
308 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
309 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
310 {
311         short payloadpos = 0;
312         const char* tempchr, *tempchr2 = name;
313         unsigned short length;
314
315         /* split name up into labels, create query */
316         while ((tempchr = strchr(tempchr2,'.')) != NULL)
317         {
318                 length = tempchr - tempchr2;
319                 if (payloadpos + length + 1 > 507)
320                         return -1;
321                 payload[payloadpos++] = length;
322                 memcpy(&payload[payloadpos],tempchr2,length);
323                 payloadpos += length;
324                 tempchr2 = &tempchr[1];
325         }
326         length = strlen(tempchr2);
327         if (length)
328         {
329                 if (payloadpos + length + 2 > 507)
330                         return -1;
331                 payload[payloadpos++] = length;
332                 memcpy(&payload[payloadpos],tempchr2,length);
333                 payloadpos += length;
334                 payload[payloadpos++] = 0;
335         }
336         if (payloadpos > 508)
337                 return -1;
338         length = htons(rr);
339         memcpy(&payload[payloadpos],&length,2);
340         length = htons(rr_class);
341         memcpy(&payload[payloadpos + 2],&length,2);
342         return payloadpos + 4;
343 }
344
345 /* Start lookup of an hostname to an IP address */
346 int DNS::GetIP(const char *name)
347 {
348         DNSHeader h;
349         int id;
350         int length;
351         
352         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
353                 return -1;
354
355         DNSRequest* req = this->AddQuery(&h, id);
356
357         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
358                 return -1;
359
360         return id;
361 }
362
363 /* Start lookup of an IP address to a hostname */
364 int DNS::GetName(const insp_inaddr *ip)
365 {
366 #ifdef IPV6
367         return -1;
368 #else
369         char query[29];
370         DNSHeader h;
371         int id;
372         int length;
373
374         unsigned char* c = (unsigned char*)&ip->s_addr;
375
376         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
377
378         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
379                 return -1;
380
381         DNSRequest* req = this->AddQuery(&h, id);
382
383         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
384                 return -1;
385
386         return id;
387 #endif
388 }
389
390 /* Return the next id which is ready, and the result attached to it */
391 DNSResult DNS::GetResult()
392 {
393         /* Fetch dns query response and decide where it belongs */
394         DNSHeader header;
395         DNSRequest *req;
396         unsigned char buffer[sizeof(DNSHeader)];
397         sockaddr from;
398         socklen_t x = sizeof(from);
399         const char* ipaddr_from = "";
400         unsigned short int port_from = 0;
401
402         int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
403
404         /* Did we get the whole header? */
405         if (length < 12)
406                 /* Nope - something screwed up. */
407                 return std::make_pair(-1,"");
408
409         /* Check wether the reply came from a different DNS
410          * server to the one we sent it to, or the source-port
411          * is not 53.
412          * A user could in theory still spoof dns packets anyway
413          * but this is less trivial than just sending garbage
414          * to the client, which is possible without this check.
415          *
416          * -- Thanks jilles for pointing this one out.
417          */
418 #ifdef IPV6
419         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin6_addr);
420         port_from = ntohs(((sockaddr_in*)&from)->sin6_port);
421 #else
422         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
423         port_from = ntohs(((sockaddr_in*)&from)->sin_port);
424 #endif
425
426         if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, Config->DNSServer)))
427                 return std::make_pair(-1,"");
428
429         /* Put the read header info into a header class */
430         DNS::FillHeader(&header,buffer,length - 12);
431
432         /* Get the id of this request.
433          * Its a 16 bit value stored in two char's,
434          * so we use logic shifts to create the value.
435          */
436         unsigned long this_id = header.id[1] + (header.id[0] << 8);
437
438         /* Do we have a pending request matching this id? */
439         requestlist_iter n_iter = requests.find(this_id);
440         if (n_iter == requests.end())
441         {
442                 /* Somehow we got a DNS response for a request we never made... */
443                 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
444                 return std::make_pair(-1,"");
445         }
446         else
447         {
448                 /* Remove the query from the list of pending queries */
449                 req = (DNSRequest*)n_iter->second;
450                 requests.erase(n_iter);
451         }
452
453         /* Inform the DNSRequest class that it has a result to be read.
454          * When its finished it will return a DNSInfo which is a pair of
455          * unsigned char* resource record data, and an error message.
456          */
457         DNSInfo data = req->ResultIsReady(header, length);
458         std::string resultstr;
459
460         /* Check if we got a result, if we didnt, its an error */
461         if (data.first == NULL)
462         {
463                 /* An error.
464                  * Mask the ID with the value of ERROR_MASK, so that
465                  * the dns_deal_with_classes() function knows that its
466                  * an error response and needs to be treated uniquely.
467                  * Put the error message in the second field.
468                  */
469                 delete req;
470                 return std::make_pair(this_id | ERROR_MASK, data.second);
471         }
472         else
473         {
474                 /* Forward lookups come back as binary data. We must format them into ascii */
475                 if (req->type == DNS_QUERY_A)
476                 {
477                         char formatted[16];
478                         snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
479                         resultstr = formatted;
480                 }
481                 else
482                 {
483                         /* Reverse lookups just come back as char* */
484                         resultstr = std::string((const char*)data.first);
485                 }
486
487                 /* Build the reply with the id and hostname/ip in it */
488                 delete req;
489                 return std::make_pair(this_id,resultstr);
490         }
491 }
492
493 /* A result is ready, process it */
494 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
495 {
496         int i = 0;
497         int q = 0;
498         int curanswer, o;
499         ResourceRecord rr;
500         unsigned short ptr;
501                         
502         if (!(header.flags1 & FLAGS_MASK_QR))
503                 return std::make_pair((unsigned char*)NULL,"Not a query result");
504
505         if (header.flags1 & FLAGS_MASK_OPCODE)
506                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
507
508         if (header.flags2 & FLAGS_MASK_RCODE)
509                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
510
511         if (header.ancount < 1)
512                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
513
514         /* Subtract the length of the header from the length of the packet */
515         length -= 12;
516
517         while ((unsigned int)q < header.qdcount && i < length)
518         {
519                 if (header.payload[i] > 63)
520                 {
521                         i += 6;
522                         q++;
523                 }
524                 else
525                 {
526                         if (header.payload[i] == 0)
527                         {
528                                 q++;
529                                 i += 5;
530                         }
531                         else i += header.payload[i] + 1;
532                 }
533         }
534         curanswer = 0;
535         while ((unsigned)curanswer < header.ancount)
536         {
537                 q = 0;
538                 while (q == 0 && i < length)
539                 {
540                         if (header.payload[i] > 63)
541                         {
542                                 i += 2;
543                                 q = 1;
544                         }
545                         else
546                         {
547                                 if (header.payload[i] == 0)
548                                 {
549                                         i++;
550                                         q = 1;
551                                 }
552                                 else i += header.payload[i] + 1; /* skip length and label */
553                         }
554                 }
555                 if (length - i < 10)
556                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
557
558                 DNS::FillResourceRecord(&rr,&header.payload[i]);
559                 i += 10;
560                 if (rr.type != this->type)
561                 {
562                         curanswer++;
563                         i += rr.rdlength;
564                         continue;
565                 }
566                 if (rr.rr_class != this->rr_class)
567                 {
568                         curanswer++;
569                         i += rr.rdlength;
570                         continue;
571                 }
572                 break;
573         }
574         if ((unsigned int)curanswer == header.ancount)
575                 return std::make_pair((unsigned char*)NULL,"No valid answers");
576
577         if (i + rr.rdlength > (unsigned int)length)
578                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
579
580         if (rr.rdlength > 1023)
581                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
582
583         switch (rr.type)
584         {
585                 case DNS_QUERY_PTR:
586                         o = 0;
587                         q = 0;
588                         while (q == 0 && i < length && o + 256 < 1023)
589                         {
590                                 if (header.payload[i] > 63)
591                                 {
592                                         memcpy(&ptr,&header.payload[i],2);
593                                         i = ntohs(ptr) - 0xC000 - 12;
594                                 }
595                                 else
596                                 {
597                                         if (header.payload[i] == 0)
598                                         {
599                                                 q = 1;
600                                         }
601                                         else
602                                         {
603                                                 res[o] = 0;
604                                                 if (o != 0)
605                                                         res[o++] = '.';
606                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
607                                                 o += header.payload[i];
608                                                 i += header.payload[i] + 1;
609                                         }
610                                 }
611                         }
612                         res[o] = 0;
613                 break;
614                 case DNS_QUERY_A:
615                         memcpy(res,&header.payload[i],rr.rdlength);
616                         res[rr.rdlength] = 0;
617                         break;
618                 default:
619                         memcpy(res,&header.payload[i],rr.rdlength);
620                         res[rr.rdlength] = 0;
621                         break;
622         }
623         return std::make_pair(res,"No error");;
624 }
625
626 /* Close the master socket */
627 DNS::~DNS()
628 {
629         shutdown(MasterSocket, 2);
630         close(MasterSocket);
631 }
632
633 /* High level abstraction of dns used by application at large */
634 Resolver::Resolver(const std::string &source, bool forward) : input(source), fwd(forward)
635 {
636         if (forward)
637         {
638                 log(DEBUG,"Resolver: Forward lookup on %s",source.c_str());
639                 this->myid = ServerInstance->Res->GetIP(source.c_str());
640         }
641         else
642         {
643                 log(DEBUG,"Resolver: Reverse lookup on %s",source.c_str());
644                 insp_inaddr binip;
645                 if (insp_aton(source.c_str(), &binip) > 0)
646                 {
647                         /* Valid ip address */
648                         this->myid = ServerInstance->Res->GetName(&binip);
649                 }
650                 else
651                 {
652                         this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
653                         throw ModuleException("Resolver: Bad IP address");
654                         return;
655                 }
656         }
657         if (this->myid == -1)
658         {
659                 log(DEBUG,"Resolver::Resolver: Could not get an id!");
660                 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
661                 throw ModuleException("Resolver: Couldnt get an id to make a request");
662                 /* We shouldnt get here really */
663                 return;
664         }
665
666         log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
667 }
668
669 void Resolver::OnError(ResolverError e, const std::string &errormessage)
670 {
671         /* Nothing in here */
672 }
673
674 Resolver::~Resolver()
675 {
676         /* Nothing here (yet) either */
677 }
678
679 /* Get the request id associated with this class */
680 int Resolver::GetId()
681 {
682         return this->myid;
683 }
684
685 /* Process a socket read event */
686 void DNS::MarshallReads(int fd)
687 {
688         /* We are only intrested in our single fd */
689         if (fd == GetMasterSocket())
690         {
691                 /* Fetch the id and result of the next available packet */
692                 DNSResult res = this->GetResult();
693                 /* Is there a usable request id? */
694                 if (res.first != -1)
695                 {
696                         /* Its an error reply */
697                         if (res.first & ERROR_MASK)
698                         {
699                                 /* Mask off the error bit */
700                                 res.first -= ERROR_MASK;
701
702                                 /* Marshall the error to the correct class */
703                                 log(DEBUG,"Error available, id=%d",res.first);
704                                 if (Classes[res.first])
705                                 {
706                                         if (ServerInstance && ServerInstance->stats)
707                                                 ServerInstance->stats->statsDnsBad++;
708                                         Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
709                                         delete Classes[res.first];
710                                         Classes[res.first] = NULL;
711                                 }
712                         }
713                         else
714                         {
715                                 /* It is a non-error result */
716                                 log(DEBUG,"Result available, id=%d",res.first);
717                                 /* Marshall the result to the correct class */
718                                 if (Classes[res.first])
719                                 {
720                                         if (ServerInstance && ServerInstance->stats)
721                                                 ServerInstance->stats->statsDnsGood++;
722                                         Classes[res.first]->OnLookupComplete(res.second);
723                                         delete Classes[res.first];
724                                         Classes[res.first] = NULL;
725                                 }
726                         }
727
728                         if (ServerInstance && ServerInstance->stats)
729                                 ServerInstance->stats->statsDns++;
730
731                 }
732         }
733 }
734
735 /* Add a derived Resolver to the working set */
736 bool DNS::AddResolverClass(Resolver* r)
737 {
738         /* Check the pointers validity and the id's validity */
739         if ((r) && (r->GetId() > -1))
740         {
741                 /* Check the slot isnt already occupied -
742                  * This should NEVER happen unless we have
743                  * a severely broken DNS server somewhere
744                  */
745                 if (!Classes[r->GetId()])
746                 {
747                         /* Set up the pointer to the class */
748                         Classes[r->GetId()] = r;
749                         return true;
750                 }
751                 else
752                         /* Duplicate id */
753                         return false;
754         }
755         else
756         {
757                 /* Pointer or id not valid.
758                  * Free the item and return
759                  */
760                 if (r)
761                         delete r;
762
763                 return false;
764         }
765 }
766
767 unsigned long DNS::PRNG()
768 {
769         unsigned long val = 0;
770         timeval n;
771         serverstats* s = ServerInstance->stats;
772         gettimeofday(&n,NULL);
773         val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
774         val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
775         val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;
776         return val;
777 }
778