]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
0329ea71298ac9947fa361634c0da3676f34059d
[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         id = this->PRNG() & DNS::MAX_REQUEST_ID;
206
207         /* This id is already 'in flight', pick another.
208          * -- Thanks jilles 
209          */
210         while (requests.find(id) != requests.end())
211                 id = this->PRNG() & DNS::MAX_REQUEST_ID;
212
213         DNSRequest* req = new DNSRequest(this->myserver);
214
215         header->id[0] = req->id[0] = id >> 8;
216         header->id[1] = req->id[1] = id & 0xFF;
217         header->flags1 = FLAGS_MASK_RD;
218         header->flags2 = 0;
219         header->qdcount = 1;
220         header->ancount = 0;
221         header->nscount = 0;
222         header->arcount = 0;
223
224         /* At this point we already know the id doesnt exist,
225          * so there needs to be no second check for the ::end()
226          */
227         requests[id] = req;
228
229         /* According to the C++ spec, new never returns NULL. */
230         return req;
231 }
232
233 int DNS::GetMasterSocket()
234 {
235         return MasterSocket;
236 }
237
238 /* Initialise the DNS UDP socket so that we can send requests */
239 DNS::DNS()
240 {
241         insp_inaddr addr;
242
243         /* Clear the Resolver class table */
244         memset(Classes,0,sizeof(Classes));
245
246         /* Set the id of the next request to 0
247          */
248         currid = 0;
249
250         /* Clear the namesever address */
251         memset(&myserver,0,sizeof(insp_inaddr));
252
253         /* Convert the nameserver address into an insp_inaddr */
254         if (insp_aton(Config->DNSServer,&addr) > 0)
255                 memcpy(&myserver,&addr,sizeof(insp_inaddr));
256
257         /* Initialize mastersocket */
258         MasterSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
259         if (MasterSocket != -1)
260         {
261                 /* Did it succeed? */
262                 if (fcntl(MasterSocket, F_SETFL, O_NONBLOCK) != 0)
263                 {
264                         /* Couldn't make the socket nonblocking */
265                         shutdown(MasterSocket,2);
266                         close(MasterSocket);
267                         MasterSocket = -1;
268                 }
269         }
270         /* Have we got a socket and is it nonblocking? */
271         if (MasterSocket != -1)
272         {
273 #ifdef IPV6
274                 insp_sockaddr addr;
275                 memset(&addr,0,sizeof(addr));
276                 addr.sin6_family = AF_FAMILY;
277                 addr.sin6_port = 0;
278                 memset(&addr.sin6_addr,255,sizeof(in6_addr));
279 #else
280                 insp_sockaddr addr;
281                 memset(&addr,0,sizeof(addr));
282                 addr.sin_family = AF_FAMILY;
283                 addr.sin_port = 0;
284                 addr.sin_addr.s_addr = INADDR_ANY;
285 #endif
286                 /* Bind the port */
287                 if (bind(MasterSocket,(sockaddr *)&addr,sizeof(addr)) != 0)
288                 {
289                         /* Failed to bind */
290                         log(DEBUG,"Cant bind DNS::MasterSocket");
291                         shutdown(MasterSocket,2);
292                         close(MasterSocket);
293                         MasterSocket = -1;
294                 }
295
296                 if (MasterSocket >= 0)
297                 {
298                         /* Hook the descriptor into the socket engine */
299                         if (ServerInstance && ServerInstance->SE)
300                                 ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS);
301                 }
302         }
303 }
304
305 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
306 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
307 {
308         short payloadpos = 0;
309         const char* tempchr, *tempchr2 = name;
310         unsigned short length;
311
312         /* split name up into labels, create query */
313         while ((tempchr = strchr(tempchr2,'.')) != NULL)
314         {
315                 length = tempchr - tempchr2;
316                 if (payloadpos + length + 1 > 507)
317                         return -1;
318                 payload[payloadpos++] = length;
319                 memcpy(&payload[payloadpos],tempchr2,length);
320                 payloadpos += length;
321                 tempchr2 = &tempchr[1];
322         }
323         length = strlen(tempchr2);
324         if (length)
325         {
326                 if (payloadpos + length + 2 > 507)
327                         return -1;
328                 payload[payloadpos++] = length;
329                 memcpy(&payload[payloadpos],tempchr2,length);
330                 payloadpos += length;
331                 payload[payloadpos++] = 0;
332         }
333         if (payloadpos > 508)
334                 return -1;
335         length = htons(rr);
336         memcpy(&payload[payloadpos],&length,2);
337         length = htons(rr_class);
338         memcpy(&payload[payloadpos + 2],&length,2);
339         return payloadpos + 4;
340 }
341
342 /* Start lookup of an hostname to an IP address */
343 int DNS::GetIP(const char *name)
344 {
345         DNSHeader h;
346         int id;
347         int length;
348         
349         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
350                 return -1;
351
352         DNSRequest* req = this->AddQuery(&h, id);
353
354         if (req->SendRequests(&h, length, DNS_QUERY_A) == -1)
355                 return -1;
356
357         return id;
358 }
359
360 /* Start lookup of an IP address to a hostname */
361 int DNS::GetName(const insp_inaddr *ip)
362 {
363 #ifdef IPV6
364         return -1;
365 #else
366         char query[29];
367         DNSHeader h;
368         int id;
369         int length;
370
371         unsigned char* c = (unsigned char*)&ip->s_addr;
372
373         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
374
375         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
376                 return -1;
377
378         DNSRequest* req = this->AddQuery(&h, id);
379
380         if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1)
381                 return -1;
382
383         return id;
384 #endif
385 }
386
387 /* Return the next id which is ready, and the result attached to it */
388 DNSResult DNS::GetResult()
389 {
390         /* Fetch dns query response and decide where it belongs */
391         DNSHeader header;
392         DNSRequest *req;
393         unsigned char buffer[sizeof(DNSHeader)];
394         sockaddr from;
395         socklen_t x = sizeof(from);
396         const char* ipaddr_from = "";
397         unsigned short int port_from = 0;
398
399         int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
400
401         /* Did we get the whole header? */
402         if (length < 12)
403                 /* Nope - something screwed up. */
404                 return std::make_pair(-1,"");
405
406         /* Check wether the reply came from a different DNS
407          * server to the one we sent it to, or the source-port
408          * is not 53.
409          * A user could in theory still spoof dns packets anyway
410          * but this is less trivial than just sending garbage
411          * to the client, which is possible without this check.
412          *
413          * -- Thanks jilles for pointing this one out.
414          */
415 #ifdef IPV6
416         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin6_addr);
417         port_from = ntohs(((sockaddr_in*)&from)->sin6_port);
418 #else
419         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
420         port_from = ntohs(((sockaddr_in*)&from)->sin_port);
421 #endif
422
423         if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, Config->DNSServer)))
424                 return std::make_pair(-1,"");
425
426         /* Put the read header info into a header class */
427         DNS::FillHeader(&header,buffer,length - 12);
428
429         /* Get the id of this request.
430          * Its a 16 bit value stored in two char's,
431          * so we use logic shifts to create the value.
432          */
433         unsigned long this_id = header.id[1] + (header.id[0] << 8);
434
435         /* Do we have a pending request matching this id? */
436         requestlist_iter n_iter = requests.find(this_id);
437         if (n_iter == requests.end())
438         {
439                 /* Somehow we got a DNS response for a request we never made... */
440                 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
441                 return std::make_pair(-1,"");
442         }
443         else
444         {
445                 /* Remove the query from the list of pending queries */
446                 req = (DNSRequest*)n_iter->second;
447                 requests.erase(n_iter);
448         }
449
450         /* Inform the DNSRequest class that it has a result to be read.
451          * When its finished it will return a DNSInfo which is a pair of
452          * unsigned char* resource record data, and an error message.
453          */
454         DNSInfo data = req->ResultIsReady(header, length);
455         std::string resultstr;
456
457         /* Check if we got a result, if we didnt, its an error */
458         if (data.first == NULL)
459         {
460                 /* An error.
461                  * Mask the ID with the value of ERROR_MASK, so that
462                  * the dns_deal_with_classes() function knows that its
463                  * an error response and needs to be treated uniquely.
464                  * Put the error message in the second field.
465                  */
466                 delete req;
467                 return std::make_pair(this_id | ERROR_MASK, data.second);
468         }
469         else
470         {
471                 /* Forward lookups come back as binary data. We must format them into ascii */
472                 if (req->type == DNS_QUERY_A)
473                 {
474                         char formatted[16];
475                         snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
476                         resultstr = formatted;
477                 }
478                 else
479                 {
480                         /* Reverse lookups just come back as char* */
481                         resultstr = std::string((const char*)data.first);
482                 }
483
484                 /* Build the reply with the id and hostname/ip in it */
485                 delete req;
486                 return std::make_pair(this_id,resultstr);
487         }
488 }
489
490 /* A result is ready, process it */
491 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
492 {
493         int i = 0;
494         int q = 0;
495         int curanswer, o;
496         ResourceRecord rr;
497         unsigned short ptr;
498                         
499         if (!(header.flags1 & FLAGS_MASK_QR))
500                 return std::make_pair((unsigned char*)NULL,"Not a query result");
501
502         if (header.flags1 & FLAGS_MASK_OPCODE)
503                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
504
505         if (header.flags2 & FLAGS_MASK_RCODE)
506                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
507
508         if (header.ancount < 1)
509                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
510
511         /* Subtract the length of the header from the length of the packet */
512         length -= 12;
513
514         while ((unsigned int)q < header.qdcount && i < length)
515         {
516                 if (header.payload[i] > 63)
517                 {
518                         i += 6;
519                         q++;
520                 }
521                 else
522                 {
523                         if (header.payload[i] == 0)
524                         {
525                                 q++;
526                                 i += 5;
527                         }
528                         else i += header.payload[i] + 1;
529                 }
530         }
531         curanswer = 0;
532         while ((unsigned)curanswer < header.ancount)
533         {
534                 q = 0;
535                 while (q == 0 && i < length)
536                 {
537                         if (header.payload[i] > 63)
538                         {
539                                 i += 2;
540                                 q = 1;
541                         }
542                         else
543                         {
544                                 if (header.payload[i] == 0)
545                                 {
546                                         i++;
547                                         q = 1;
548                                 }
549                                 else i += header.payload[i] + 1; /* skip length and label */
550                         }
551                 }
552                 if (length - i < 10)
553                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
554
555                 DNS::FillResourceRecord(&rr,&header.payload[i]);
556                 i += 10;
557                 if (rr.type != this->type)
558                 {
559                         curanswer++;
560                         i += rr.rdlength;
561                         continue;
562                 }
563                 if (rr.rr_class != this->rr_class)
564                 {
565                         curanswer++;
566                         i += rr.rdlength;
567                         continue;
568                 }
569                 break;
570         }
571         if ((unsigned int)curanswer == header.ancount)
572                 return std::make_pair((unsigned char*)NULL,"No valid answers");
573
574         if (i + rr.rdlength > (unsigned int)length)
575                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
576
577         if (rr.rdlength > 1023)
578                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
579
580         switch (rr.type)
581         {
582                 case DNS_QUERY_PTR:
583                         o = 0;
584                         q = 0;
585                         while (q == 0 && i < length && o + 256 < 1023)
586                         {
587                                 if (header.payload[i] > 63)
588                                 {
589                                         memcpy(&ptr,&header.payload[i],2);
590                                         i = ntohs(ptr) - 0xC000 - 12;
591                                 }
592                                 else
593                                 {
594                                         if (header.payload[i] == 0)
595                                         {
596                                                 q = 1;
597                                         }
598                                         else
599                                         {
600                                                 res[o] = 0;
601                                                 if (o != 0)
602                                                         res[o++] = '.';
603                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
604                                                 o += header.payload[i];
605                                                 i += header.payload[i] + 1;
606                                         }
607                                 }
608                         }
609                         res[o] = 0;
610                 break;
611                 case DNS_QUERY_A:
612                         memcpy(res,&header.payload[i],rr.rdlength);
613                         res[rr.rdlength] = 0;
614                         break;
615                 default:
616                         memcpy(res,&header.payload[i],rr.rdlength);
617                         res[rr.rdlength] = 0;
618                         break;
619         }
620         return std::make_pair(res,"No error");;
621 }
622
623 /* Close the master socket */
624 DNS::~DNS()
625 {
626         shutdown(MasterSocket, 2);
627         close(MasterSocket);
628 }
629
630 /* High level abstraction of dns used by application at large */
631 Resolver::Resolver(const std::string &source, bool forward) : input(source), fwd(forward)
632 {
633         if (forward)
634         {
635                 log(DEBUG,"Resolver: Forward lookup on %s",source.c_str());
636                 this->myid = ServerInstance->Res->GetIP(source.c_str());
637         }
638         else
639         {
640                 log(DEBUG,"Resolver: Reverse lookup on %s",source.c_str());
641                 insp_inaddr binip;
642                 if (insp_aton(source.c_str(), &binip) > 0)
643                 {
644                         /* Valid ip address */
645                         this->myid = ServerInstance->Res->GetName(&binip);
646                 }
647                 else
648                 {
649                         this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
650                         throw ModuleException("Resolver: Bad IP address");
651                         return;
652                 }
653         }
654         if (this->myid == -1)
655         {
656                 log(DEBUG,"Resolver::Resolver: Could not get an id!");
657                 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
658                 throw ModuleException("Resolver: Couldnt get an id to make a request");
659                 /* We shouldnt get here really */
660                 return;
661         }
662
663         log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
664 }
665
666 void Resolver::OnError(ResolverError e, const std::string &errormessage)
667 {
668         /* Nothing in here */
669 }
670
671 Resolver::~Resolver()
672 {
673         /* Nothing here (yet) either */
674 }
675
676 /* Get the request id associated with this class */
677 int Resolver::GetId()
678 {
679         return this->myid;
680 }
681
682 /* Process a socket read event */
683 void DNS::MarshallReads(int fd)
684 {
685         /* We are only intrested in our single fd */
686         if (fd == GetMasterSocket())
687         {
688                 /* Fetch the id and result of the next available packet */
689                 DNSResult res = this->GetResult();
690                 /* Is there a usable request id? */
691                 if (res.first != -1)
692                 {
693                         /* Its an error reply */
694                         if (res.first & ERROR_MASK)
695                         {
696                                 /* Mask off the error bit */
697                                 res.first -= ERROR_MASK;
698
699                                 /* Marshall the error to the correct class */
700                                 log(DEBUG,"Error available, id=%d",res.first);
701                                 if (Classes[res.first])
702                                 {
703                                         if (ServerInstance && ServerInstance->stats)
704                                                 ServerInstance->stats->statsDnsBad++;
705                                         Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
706                                         delete Classes[res.first];
707                                         Classes[res.first] = NULL;
708                                 }
709                         }
710                         else
711                         {
712                                 /* It is a non-error result */
713                                 log(DEBUG,"Result available, id=%d",res.first);
714                                 /* Marshall the result to the correct class */
715                                 if (Classes[res.first])
716                                 {
717                                         if (ServerInstance && ServerInstance->stats)
718                                                 ServerInstance->stats->statsDnsGood++;
719                                         Classes[res.first]->OnLookupComplete(res.second);
720                                         delete Classes[res.first];
721                                         Classes[res.first] = NULL;
722                                 }
723                         }
724
725                         if (ServerInstance && ServerInstance->stats)
726                                 ServerInstance->stats->statsDns++;
727
728                 }
729         }
730 }
731
732 /* Add a derived Resolver to the working set */
733 bool DNS::AddResolverClass(Resolver* r)
734 {
735         /* Check the pointers validity and the id's validity */
736         if ((r) && (r->GetId() > -1))
737         {
738                 /* Check the slot isnt already occupied -
739                  * This should NEVER happen unless we have
740                  * a severely broken DNS server somewhere
741                  */
742                 if (!Classes[r->GetId()])
743                 {
744                         /* Set up the pointer to the class */
745                         Classes[r->GetId()] = r;
746                         return true;
747                 }
748                 else
749                         /* Duplicate id */
750                         return false;
751         }
752         else
753         {
754                 /* Pointer or id not valid.
755                  * Free the item and return
756                  */
757                 if (r)
758                         delete r;
759
760                 return false;
761         }
762 }
763
764 unsigned long DNS::PRNG()
765 {
766         unsigned long val = 0;
767         timeval n;
768         serverstats* s = ServerInstance->stats;
769         gettimeofday(&n,NULL);
770         val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
771         val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
772         val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;
773         return val;
774 }
775