1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
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.
31 #include <sys/types.h>
32 #include <sys/socket.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
41 #include "helperfuncs.h"
42 #include "inspircd_config.h"
43 #include "socketengine.h"
44 #include "configreader.h"
47 extern InspIRCd* ServerInstance;
49 /* Master file descriptor */
50 int DNS::MasterSocket;
52 /* Masks to mask off the responses we get from the DNSRequest methods */
55 ERROR_MASK = 0x10000 /* Result is an error */
58 /* Flags which can be ORed into a request or reply for different meanings */
61 FLAGS_MASK_RD = 0x01, /* Recursive */
63 FLAGS_MASK_AA = 0x04, /* Authoritative */
64 FLAGS_MASK_OPCODE = 0x78,
66 FLAGS_MASK_RCODE = 0x0F, /* Request */
72 /* Represents a dns resource record (rr) */
76 QueryType type; /* Record type */
77 unsigned int rr_class; /* Record class */
78 unsigned long ttl; /* Time to live */
79 unsigned int rdlength; /* Record length */
82 /* Represents a dns request/reply header, and its payload as opaque data.
87 unsigned char id[2]; /* Request id */
88 unsigned int flags1; /* Flags */
89 unsigned int flags2; /* Flags */
91 unsigned int ancount; /* Answer count */
92 unsigned int nscount; /* Nameserver count */
94 unsigned char payload[512]; /* Packet payload */
97 /* Represents a request 'on the wire' with routing information relating to
98 * where to call when we get a result
103 unsigned char id[2]; /* Request id */
104 unsigned char* res; /* Result processing buffer */
105 unsigned int rr_class; /* Request class */
106 QueryType type; /* Request type */
107 insp_inaddr myserver; /* DNS server address*/
109 /* Allocate the processing buffer */
110 DNSRequest(insp_inaddr server)
112 res = new unsigned char[512];
114 memcpy(&myserver, &server, sizeof(insp_inaddr));
117 /* Deallocate the processing buffer */
123 /* Called when a result is ready to be processed which matches this id */
124 DNSInfo ResultIsReady(DNSHeader &h, int length);
126 /* Called when there are requests to be sent out */
127 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
130 /* Fill a ResourceRecord class based on raw data input */
131 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
133 rr->type = (QueryType)((input[0] << 8) + input[1]);
134 rr->rr_class = (input[2] << 8) + input[3];
135 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
136 rr->rdlength = (input[8] << 8) + input[9];
139 /* Fill a DNSHeader class based on raw data input of a given length */
140 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
142 header->id[0] = input[0];
143 header->id[1] = input[1];
144 header->flags1 = input[2];
145 header->flags2 = input[3];
146 header->qdcount = (input[4] << 8) + input[5];
147 header->ancount = (input[6] << 8) + input[7];
148 header->nscount = (input[8] << 8) + input[9];
149 header->arcount = (input[10] << 8) + input[11];
150 memcpy(header->payload,&input[12],length);
153 /* Empty a DNSHeader class out into raw data, ready for transmission */
154 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
156 output[0] = header->id[0];
157 output[1] = header->id[1];
158 output[2] = header->flags1;
159 output[3] = header->flags2;
160 output[4] = header->qdcount >> 8;
161 output[5] = header->qdcount & 0xFF;
162 output[6] = header->ancount >> 8;
163 output[7] = header->ancount & 0xFF;
164 output[8] = header->nscount >> 8;
165 output[9] = header->nscount & 0xFF;
166 output[10] = header->arcount >> 8;
167 output[11] = header->arcount & 0xFF;
168 memcpy(&output[12],header->payload,length);
171 /* Send requests we have previously built down the UDP socket */
172 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
175 unsigned char payload[sizeof(DNSHeader)];
180 DNS::EmptyHeader(payload,header,length);
182 memset(&addr,0,sizeof(addr));
184 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
185 addr.sin6_family = AF_FAMILY;
186 addr.sin6_port = htons(DNS::QUERY_PORT);
188 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
189 addr.sin_family = AF_FAMILY;
190 addr.sin_port = htons(DNS::QUERY_PORT);
192 if (sendto(DNS::GetMasterSocket(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
194 log(DEBUG,"Error in sendto! (%s)",strerror(errno));
201 /* Add a query with a predefined header, and allocate an ID for it. */
202 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
204 /* Is the DNS connection down? */
205 if (MasterSocket == -1)
208 /* Are there already the max number of requests on the go? */
209 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
213 id = this->PRNG() & DNS::MAX_REQUEST_ID;
215 /* If this id is already 'in flight', pick another. */
216 while (requests.find(id) != requests.end())
217 id = this->PRNG() & DNS::MAX_REQUEST_ID;
219 DNSRequest* req = new DNSRequest(this->myserver);
221 header->id[0] = req->id[0] = id >> 8;
222 header->id[1] = req->id[1] = id & 0xFF;
223 header->flags1 = FLAGS_MASK_RD;
230 /* At this point we already know the id doesnt exist,
231 * so there needs to be no second check for the ::end()
235 /* According to the C++ spec, new never returns NULL. */
239 int DNS::GetMasterSocket()
244 /* Initialise the DNS UDP socket so that we can send requests */
249 /* Clear the Resolver class table */
250 memset(Classes,0,sizeof(Classes));
252 /* Set the id of the next request to 0
256 /* Clear the namesever address */
257 memset(&myserver,0,sizeof(insp_inaddr));
259 /* Convert the nameserver address into an insp_inaddr */
260 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
262 memcpy(&myserver,&addr,sizeof(insp_inaddr));
263 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
265 /* These dont come back looking like they did when they went in.
266 * We're forced to turn some checks off.
267 * If anyone knows how to fix this, let me know. --Brain
269 log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
270 log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
271 log(DEFAULT," to a true IPv6 environment.");
272 this->ip6munge = true;
274 log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
278 log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
281 /* Initialize mastersocket */
282 MasterSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
283 if (MasterSocket != -1)
285 /* Did it succeed? */
286 if (fcntl(MasterSocket, F_SETFL, O_NONBLOCK) != 0)
288 /* Couldn't make the socket nonblocking */
289 shutdown(MasterSocket,2);
296 log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
298 /* Have we got a socket and is it nonblocking? */
299 if (MasterSocket != -1)
303 memset(&addr,0,sizeof(addr));
304 addr.sin6_family = AF_FAMILY;
306 addr.sin6_addr = in6addr_any;
309 memset(&addr,0,sizeof(addr));
310 addr.sin_family = AF_FAMILY;
312 addr.sin_addr.s_addr = INADDR_ANY;
315 if (bind(MasterSocket,(sockaddr *)&addr,sizeof(addr)) != 0)
318 log(DEBUG,"Cant bind DNS::MasterSocket");
319 shutdown(MasterSocket,2);
324 if (MasterSocket >= 0)
326 log(DEBUG,"Add master socket %d",MasterSocket);
327 /* Hook the descriptor into the socket engine */
328 if (ServerInstance && ServerInstance->SE)
330 if (!ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS))
332 log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
333 shutdown(MasterSocket,2);
342 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
343 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
345 short payloadpos = 0;
346 const char* tempchr, *tempchr2 = name;
347 unsigned short length;
349 /* split name up into labels, create query */
350 while ((tempchr = strchr(tempchr2,'.')) != NULL)
352 length = tempchr - tempchr2;
353 if (payloadpos + length + 1 > 507)
355 payload[payloadpos++] = length;
356 memcpy(&payload[payloadpos],tempchr2,length);
357 payloadpos += length;
358 tempchr2 = &tempchr[1];
360 length = strlen(tempchr2);
363 if (payloadpos + length + 2 > 507)
365 payload[payloadpos++] = length;
366 memcpy(&payload[payloadpos],tempchr2,length);
367 payloadpos += length;
368 payload[payloadpos++] = 0;
370 if (payloadpos > 508)
373 memcpy(&payload[payloadpos],&length,2);
374 length = htons(rr_class);
375 memcpy(&payload[payloadpos + 2],&length,2);
376 return payloadpos + 4;
379 /* Start lookup of an hostname to an IP address */
380 int DNS::GetIP(const char *name)
386 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
389 DNSRequest* req = this->AddQuery(&h, id);
391 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
397 /* Start lookup of an hostname to an IPv6 address */
398 int DNS::GetIP6(const char *name)
404 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
407 DNSRequest* req = this->AddQuery(&h, id);
409 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
415 /* Start lookup of a cname to another name */
416 int DNS::GetCName(const char *alias)
422 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
425 DNSRequest* req = this->AddQuery(&h, id);
427 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
433 /* Start lookup of an IP address to a hostname */
434 int DNS::GetName(const insp_inaddr *ip)
442 DNS::MakeIP6Int(query, (in6_addr*)ip);
444 unsigned char* c = (unsigned char*)&ip->s_addr;
446 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
449 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
452 DNSRequest* req = this->AddQuery(&h, id);
454 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
460 /* Start lookup of an IP address to a hostname */
461 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
467 #ifdef SUPPORT_IP6LINKS
468 if (fp == PROTOCOL_IPV6)
471 if (inet_pton(AF_INET6, ip, &i) > 0)
473 DNS::MakeIP6Int(query, &i);
476 /* Invalid IP address */
483 if (inet_aton(ip, &i))
485 unsigned char* c = (unsigned char*)&i.s_addr;
486 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
489 /* Invalid IP address */
493 log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
495 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
498 DNSRequest* req = this->AddQuery(&h, id);
500 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
506 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
508 #ifdef SUPPORT_IP6LINKS
509 const char* hex = "0123456789abcdef";
510 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
514 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
517 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
518 *query++ = '.'; /* Seperator */
520 strcpy(query,"ip6.arpa"); /* Suffix the string */
526 /* Return the next id which is ready, and the result attached to it */
527 DNSResult DNS::GetResult()
529 /* Fetch dns query response and decide where it belongs */
532 unsigned char buffer[sizeof(DNSHeader)];
534 socklen_t x = sizeof(from);
535 const char* ipaddr_from = "";
536 unsigned short int port_from = 0;
538 int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
541 log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
543 /* Did we get the whole header? */
546 /* Nope - something screwed up. */
547 log(DEBUG,"Whole header not read!");
548 return std::make_pair(-1,"");
551 /* Check wether the reply came from a different DNS
552 * server to the one we sent it to, or the source-port
554 * A user could in theory still spoof dns packets anyway
555 * but this is less trivial than just sending garbage
556 * to the client, which is possible without this check.
558 * -- Thanks jilles for pointing this one out.
561 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
562 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
564 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
565 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
568 /* We cant perform this security check if you're using 4in6.
569 * Tough luck to you, choose one or't other!
573 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
575 log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
576 return std::make_pair(-1,"");
580 /* Put the read header info into a header class */
581 DNS::FillHeader(&header,buffer,length - 12);
583 /* Get the id of this request.
584 * Its a 16 bit value stored in two char's,
585 * so we use logic shifts to create the value.
587 unsigned long this_id = header.id[1] + (header.id[0] << 8);
589 /* Do we have a pending request matching this id? */
590 requestlist_iter n_iter = requests.find(this_id);
591 if (n_iter == requests.end())
593 /* Somehow we got a DNS response for a request we never made... */
594 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
595 return std::make_pair(-1,"");
599 /* Remove the query from the list of pending queries */
600 req = (DNSRequest*)n_iter->second;
601 requests.erase(n_iter);
604 /* Inform the DNSRequest class that it has a result to be read.
605 * When its finished it will return a DNSInfo which is a pair of
606 * unsigned char* resource record data, and an error message.
608 DNSInfo data = req->ResultIsReady(header, length);
609 std::string resultstr;
611 /* Check if we got a result, if we didnt, its an error */
612 if (data.first == NULL)
615 * Mask the ID with the value of ERROR_MASK, so that
616 * the dns_deal_with_classes() function knows that its
617 * an error response and needs to be treated uniquely.
618 * Put the error message in the second field.
621 return std::make_pair(this_id | ERROR_MASK, data.second);
627 /* Forward lookups come back as binary data. We must format them into ascii */
631 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
632 resultstr = formatted;
637 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
638 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
639 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
640 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
641 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
642 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
643 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
644 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
645 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
646 char* c = strstr(formatted,":0:");
649 memmove(c+1,c+2,strlen(c+2) + 1);
651 while (memcmp(c,"0:",2) == 0)
652 memmove(c,c+2,strlen(c+2) + 1);
653 if (memcmp(c,"0",2) == 0)
655 if (memcmp(formatted,"0::",3) == 0)
656 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
658 resultstr = formatted;
660 /* Special case. Sending ::1 around between servers
661 * and to clients is dangerous, because the : on the
662 * start makes the client or server interpret the IP
663 * as the last parameter on the line with a value ":1".
665 if (*formatted == ':')
666 resultstr = "0" + resultstr;
670 case DNS_QUERY_CNAME:
671 /* Identical handling to PTR */
674 /* Reverse lookups just come back as char* */
675 resultstr = std::string((const char*)data.first);
679 log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
684 /* Build the reply with the id and hostname/ip in it */
686 return std::make_pair(this_id,resultstr);
690 /* A result is ready, process it */
691 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
699 if (!(header.flags1 & FLAGS_MASK_QR))
700 return std::make_pair((unsigned char*)NULL,"Not a query result");
702 if (header.flags1 & FLAGS_MASK_OPCODE)
703 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
705 if (header.flags2 & FLAGS_MASK_RCODE)
706 return std::make_pair((unsigned char*)NULL,"Domain name not found");
708 if (header.ancount < 1)
709 return std::make_pair((unsigned char*)NULL,"No resource records returned");
711 /* Subtract the length of the header from the length of the packet */
714 while ((unsigned int)q < header.qdcount && i < length)
716 if (header.payload[i] > 63)
723 if (header.payload[i] == 0)
728 else i += header.payload[i] + 1;
732 while ((unsigned)curanswer < header.ancount)
735 while (q == 0 && i < length)
737 if (header.payload[i] > 63)
744 if (header.payload[i] == 0)
749 else i += header.payload[i] + 1; /* skip length and label */
753 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
755 DNS::FillResourceRecord(&rr,&header.payload[i]);
757 if (rr.type != this->type)
763 if (rr.rr_class != this->rr_class)
771 if ((unsigned int)curanswer == header.ancount)
772 return std::make_pair((unsigned char*)NULL,"No valid answers");
774 if (i + rr.rdlength > (unsigned int)length)
775 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
777 if (rr.rdlength > 1023)
778 return std::make_pair((unsigned char*)NULL,"Resource record too large");
782 case DNS_QUERY_CNAME:
783 /* CNAME and PTR have the same processing code */
787 while (q == 0 && i < length && o + 256 < 1023)
789 if (header.payload[i] > 63)
791 memcpy(&ptr,&header.payload[i],2);
792 i = ntohs(ptr) - 0xC000 - 12;
796 if (header.payload[i] == 0)
805 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
806 o += header.payload[i];
807 i += header.payload[i] + 1;
814 memcpy(res,&header.payload[i],rr.rdlength);
815 res[rr.rdlength] = 0;
818 memcpy(res,&header.payload[i],rr.rdlength);
819 res[rr.rdlength] = 0;
822 memcpy(res,&header.payload[i],rr.rdlength);
823 res[rr.rdlength] = 0;
826 return std::make_pair(res,"No error");;
829 /* Close the master socket */
832 shutdown(MasterSocket, 2);
836 /* High level abstraction of dns used by application at large */
837 Resolver::Resolver(const std::string &source, QueryType qt) : input(source), querytype(qt)
844 this->myid = ServerInstance->Res->GetIP(source.c_str());
848 if (insp_aton(source.c_str(), &binip) > 0)
850 /* Valid ip address */
851 this->myid = ServerInstance->Res->GetName(&binip);
855 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
856 throw ModuleException("Resolver: Bad IP address");
862 querytype = DNS_QUERY_PTR;
863 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
867 querytype = DNS_QUERY_PTR;
868 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
872 this->myid = ServerInstance->Res->GetIP6(source.c_str());
875 case DNS_QUERY_CNAME:
876 this->myid = ServerInstance->Res->GetCName(source.c_str());
883 if (this->myid == -1)
885 log(DEBUG,"Resolver::Resolver: Could not get an id!");
886 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
887 throw ModuleException("Resolver: Couldnt get an id to make a request");
888 /* We shouldnt get here really */
892 log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
895 void Resolver::OnError(ResolverError e, const std::string &errormessage)
897 /* Nothing in here */
900 Resolver::~Resolver()
902 /* Nothing here (yet) either */
905 /* Get the request id associated with this class */
906 int Resolver::GetId()
911 /* Process a socket read event */
912 void DNS::MarshallReads(int fd)
914 log(DEBUG,"Marshall reads: %d %d",fd,GetMasterSocket());
915 /* We are only intrested in our single fd */
916 if (fd == GetMasterSocket())
918 /* Fetch the id and result of the next available packet */
919 DNSResult res = this->GetResult();
920 /* Is there a usable request id? */
923 /* Its an error reply */
924 if (res.first & ERROR_MASK)
926 /* Mask off the error bit */
927 res.first -= ERROR_MASK;
929 /* Marshall the error to the correct class */
930 log(DEBUG,"Error available, id=%d",res.first);
931 if (Classes[res.first])
933 if (ServerInstance && ServerInstance->stats)
934 ServerInstance->stats->statsDnsBad++;
935 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
936 delete Classes[res.first];
937 Classes[res.first] = NULL;
942 /* It is a non-error result */
943 log(DEBUG,"Result available, id=%d",res.first);
944 /* Marshall the result to the correct class */
945 if (Classes[res.first])
947 if (ServerInstance && ServerInstance->stats)
948 ServerInstance->stats->statsDnsGood++;
949 Classes[res.first]->OnLookupComplete(res.second);
950 delete Classes[res.first];
951 Classes[res.first] = NULL;
955 if (ServerInstance && ServerInstance->stats)
956 ServerInstance->stats->statsDns++;
962 /* Add a derived Resolver to the working set */
963 bool DNS::AddResolverClass(Resolver* r)
965 /* Check the pointers validity and the id's validity */
966 if ((r) && (r->GetId() > -1))
968 /* Check the slot isnt already occupied -
969 * This should NEVER happen unless we have
970 * a severely broken DNS server somewhere
972 if (!Classes[r->GetId()])
974 /* Set up the pointer to the class */
975 Classes[r->GetId()] = r;
984 /* Pointer or id not valid.
985 * Free the item and return
994 unsigned long DNS::PRNG()
996 unsigned long val = 0;
998 serverstats* s = ServerInstance->stats;
999 gettimeofday(&n,NULL);
1000 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1001 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1002 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;