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"
46 /* Master file descriptor */
47 int DNS::MasterSocket;
49 /* Masks to mask off the responses we get from the DNSRequest methods */
52 ERROR_MASK = 0x10000 /* Result is an error */
55 /* Flags which can be ORed into a request or reply for different meanings */
58 FLAGS_MASK_RD = 0x01, /* Recursive */
60 FLAGS_MASK_AA = 0x04, /* Authoritative */
61 FLAGS_MASK_OPCODE = 0x78,
63 FLAGS_MASK_RCODE = 0x0F, /* Request */
69 /* Represents a dns resource record (rr) */
73 QueryType type; /* Record type */
74 unsigned int rr_class; /* Record class */
75 unsigned long ttl; /* Time to live */
76 unsigned int rdlength; /* Record length */
79 /* Represents a dns request/reply header, and its payload as opaque data.
84 unsigned char id[2]; /* Request id */
85 unsigned int flags1; /* Flags */
86 unsigned int flags2; /* Flags */
88 unsigned int ancount; /* Answer count */
89 unsigned int nscount; /* Nameserver count */
91 unsigned char payload[512]; /* Packet payload */
94 /* Represents a request 'on the wire' with routing information relating to
95 * where to call when we get a result
100 unsigned char id[2]; /* Request id */
101 unsigned char* res; /* Result processing buffer */
102 unsigned int rr_class; /* Request class */
103 QueryType type; /* Request type */
104 insp_inaddr myserver; /* DNS server address*/
106 /* Allocate the processing buffer */
107 DNSRequest(insp_inaddr server)
109 res = new unsigned char[512];
111 memcpy(&myserver, &server, sizeof(insp_inaddr));
114 /* Deallocate the processing buffer */
120 /* Called when a result is ready to be processed which matches this id */
121 DNSInfo ResultIsReady(DNSHeader &h, int length);
123 /* Called when there are requests to be sent out */
124 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
127 /* Fill a ResourceRecord class based on raw data input */
128 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
130 rr->type = (QueryType)((input[0] << 8) + input[1]);
131 rr->rr_class = (input[2] << 8) + input[3];
132 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
133 rr->rdlength = (input[8] << 8) + input[9];
136 /* Fill a DNSHeader class based on raw data input of a given length */
137 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
139 header->id[0] = input[0];
140 header->id[1] = input[1];
141 header->flags1 = input[2];
142 header->flags2 = input[3];
143 header->qdcount = (input[4] << 8) + input[5];
144 header->ancount = (input[6] << 8) + input[7];
145 header->nscount = (input[8] << 8) + input[9];
146 header->arcount = (input[10] << 8) + input[11];
147 memcpy(header->payload,&input[12],length);
150 /* Empty a DNSHeader class out into raw data, ready for transmission */
151 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
153 output[0] = header->id[0];
154 output[1] = header->id[1];
155 output[2] = header->flags1;
156 output[3] = header->flags2;
157 output[4] = header->qdcount >> 8;
158 output[5] = header->qdcount & 0xFF;
159 output[6] = header->ancount >> 8;
160 output[7] = header->ancount & 0xFF;
161 output[8] = header->nscount >> 8;
162 output[9] = header->nscount & 0xFF;
163 output[10] = header->arcount >> 8;
164 output[11] = header->arcount & 0xFF;
165 memcpy(&output[12],header->payload,length);
168 /* Send requests we have previously built down the UDP socket */
169 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
172 unsigned char payload[sizeof(DNSHeader)];
177 DNS::EmptyHeader(payload,header,length);
179 memset(&addr,0,sizeof(addr));
181 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
182 addr.sin6_family = AF_FAMILY;
183 addr.sin6_port = htons(DNS::QUERY_PORT);
185 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
186 addr.sin_family = AF_FAMILY;
187 addr.sin_port = htons(DNS::QUERY_PORT);
189 if (sendto(DNS::GetMasterSocket(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
191 log(DEBUG,"Error in sendto! (%s)",strerror(errno));
198 /* Add a query with a predefined header, and allocate an ID for it. */
199 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
201 /* Is the DNS connection down? */
202 if (MasterSocket == -1)
205 /* Are there already the max number of requests on the go? */
206 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
210 id = this->PRNG() & DNS::MAX_REQUEST_ID;
212 /* If this id is already 'in flight', pick another. */
213 while (requests.find(id) != requests.end())
214 id = this->PRNG() & DNS::MAX_REQUEST_ID;
216 DNSRequest* req = new DNSRequest(this->myserver);
218 header->id[0] = req->id[0] = id >> 8;
219 header->id[1] = req->id[1] = id & 0xFF;
220 header->flags1 = FLAGS_MASK_RD;
227 /* At this point we already know the id doesnt exist,
228 * so there needs to be no second check for the ::end()
232 /* According to the C++ spec, new never returns NULL. */
236 int DNS::GetMasterSocket()
241 /* Initialise the DNS UDP socket so that we can send requests */
242 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
244 log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
248 /* Clear the Resolver class table */
249 memset(Classes,0,sizeof(Classes));
251 /* Set the id of the next request to 0
255 /* Clear the namesever address */
256 memset(&myserver,0,sizeof(insp_inaddr));
258 /* Convert the nameserver address into an insp_inaddr */
259 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
261 memcpy(&myserver,&addr,sizeof(insp_inaddr));
262 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
264 /* These dont come back looking like they did when they went in.
265 * We're forced to turn some checks off.
266 * If anyone knows how to fix this, let me know. --Brain
268 log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
269 log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
270 log(DEFAULT," to a true IPv6 environment.");
271 this->ip6munge = true;
273 log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
277 log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
280 /* Initialize mastersocket */
281 MasterSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
282 if (MasterSocket != -1)
284 /* Did it succeed? */
285 if (fcntl(MasterSocket, F_SETFL, O_NONBLOCK) != 0)
287 /* Couldn't make the socket nonblocking */
288 shutdown(MasterSocket,2);
295 log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
297 /* Have we got a socket and is it nonblocking? */
298 if (MasterSocket != -1)
302 memset(&addr,0,sizeof(addr));
303 addr.sin6_family = AF_FAMILY;
305 addr.sin6_addr = in6addr_any;
308 memset(&addr,0,sizeof(addr));
309 addr.sin_family = AF_FAMILY;
311 addr.sin_addr.s_addr = INADDR_ANY;
314 if (bind(MasterSocket,(sockaddr *)&addr,sizeof(addr)) != 0)
317 log(DEBUG,"Cant bind DNS::MasterSocket");
318 shutdown(MasterSocket,2);
323 if (MasterSocket >= 0)
325 log(DEBUG,"Add master socket %d",MasterSocket);
326 /* Hook the descriptor into the socket engine */
327 if (ServerInstance && ServerInstance->SE)
329 if (!ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS))
331 log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
332 shutdown(MasterSocket,2);
341 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
342 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
344 short payloadpos = 0;
345 const char* tempchr, *tempchr2 = name;
346 unsigned short length;
348 /* split name up into labels, create query */
349 while ((tempchr = strchr(tempchr2,'.')) != NULL)
351 length = tempchr - tempchr2;
352 if (payloadpos + length + 1 > 507)
354 payload[payloadpos++] = length;
355 memcpy(&payload[payloadpos],tempchr2,length);
356 payloadpos += length;
357 tempchr2 = &tempchr[1];
359 length = strlen(tempchr2);
362 if (payloadpos + length + 2 > 507)
364 payload[payloadpos++] = length;
365 memcpy(&payload[payloadpos],tempchr2,length);
366 payloadpos += length;
367 payload[payloadpos++] = 0;
369 if (payloadpos > 508)
372 memcpy(&payload[payloadpos],&length,2);
373 length = htons(rr_class);
374 memcpy(&payload[payloadpos + 2],&length,2);
375 return payloadpos + 4;
378 /* Start lookup of an hostname to an IP address */
379 int DNS::GetIP(const char *name)
385 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
388 DNSRequest* req = this->AddQuery(&h, id);
390 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
396 /* Start lookup of an hostname to an IPv6 address */
397 int DNS::GetIP6(const char *name)
403 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
406 DNSRequest* req = this->AddQuery(&h, id);
408 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
414 /* Start lookup of a cname to another name */
415 int DNS::GetCName(const char *alias)
421 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
424 DNSRequest* req = this->AddQuery(&h, id);
426 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
432 /* Start lookup of an IP address to a hostname */
433 int DNS::GetName(const insp_inaddr *ip)
441 DNS::MakeIP6Int(query, (in6_addr*)ip);
443 unsigned char* c = (unsigned char*)&ip->s_addr;
445 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
448 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
451 DNSRequest* req = this->AddQuery(&h, id);
453 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
459 /* Start lookup of an IP address to a hostname */
460 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
466 #ifdef SUPPORT_IP6LINKS
467 if (fp == PROTOCOL_IPV6)
470 if (inet_pton(AF_INET6, ip, &i) > 0)
472 DNS::MakeIP6Int(query, &i);
475 /* Invalid IP address */
482 if (inet_aton(ip, &i))
484 unsigned char* c = (unsigned char*)&i.s_addr;
485 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
488 /* Invalid IP address */
492 log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
494 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
497 DNSRequest* req = this->AddQuery(&h, id);
499 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
505 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
507 #ifdef SUPPORT_IP6LINKS
508 const char* hex = "0123456789abcdef";
509 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
513 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
516 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
517 *query++ = '.'; /* Seperator */
519 strcpy(query,"ip6.arpa"); /* Suffix the string */
525 /* Return the next id which is ready, and the result attached to it */
526 DNSResult DNS::GetResult()
528 /* Fetch dns query response and decide where it belongs */
531 unsigned char buffer[sizeof(DNSHeader)];
533 socklen_t x = sizeof(from);
534 const char* ipaddr_from = "";
535 unsigned short int port_from = 0;
537 int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
540 log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
542 /* Did we get the whole header? */
545 /* Nope - something screwed up. */
546 log(DEBUG,"Whole header not read!");
547 return std::make_pair(-1,"");
550 /* Check wether the reply came from a different DNS
551 * server to the one we sent it to, or the source-port
553 * A user could in theory still spoof dns packets anyway
554 * but this is less trivial than just sending garbage
555 * to the client, which is possible without this check.
557 * -- Thanks jilles for pointing this one out.
560 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
561 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
563 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
564 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
567 /* We cant perform this security check if you're using 4in6.
568 * Tough luck to you, choose one or't other!
572 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
574 log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
575 return std::make_pair(-1,"");
579 /* Put the read header info into a header class */
580 DNS::FillHeader(&header,buffer,length - 12);
582 /* Get the id of this request.
583 * Its a 16 bit value stored in two char's,
584 * so we use logic shifts to create the value.
586 unsigned long this_id = header.id[1] + (header.id[0] << 8);
588 /* Do we have a pending request matching this id? */
589 requestlist_iter n_iter = requests.find(this_id);
590 if (n_iter == requests.end())
592 /* Somehow we got a DNS response for a request we never made... */
593 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
594 return std::make_pair(-1,"");
598 /* Remove the query from the list of pending queries */
599 req = (DNSRequest*)n_iter->second;
600 requests.erase(n_iter);
603 /* Inform the DNSRequest class that it has a result to be read.
604 * When its finished it will return a DNSInfo which is a pair of
605 * unsigned char* resource record data, and an error message.
607 DNSInfo data = req->ResultIsReady(header, length);
608 std::string resultstr;
610 /* Check if we got a result, if we didnt, its an error */
611 if (data.first == NULL)
614 * Mask the ID with the value of ERROR_MASK, so that
615 * the dns_deal_with_classes() function knows that its
616 * an error response and needs to be treated uniquely.
617 * Put the error message in the second field.
620 return std::make_pair(this_id | ERROR_MASK, data.second);
626 /* Forward lookups come back as binary data. We must format them into ascii */
630 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
631 resultstr = formatted;
636 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
637 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
638 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
639 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
640 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
641 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
642 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
643 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
644 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
645 char* c = strstr(formatted,":0:");
648 memmove(c+1,c+2,strlen(c+2) + 1);
650 while (memcmp(c,"0:",2) == 0)
651 memmove(c,c+2,strlen(c+2) + 1);
652 if (memcmp(c,"0",2) == 0)
654 if (memcmp(formatted,"0::",3) == 0)
655 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
657 resultstr = formatted;
659 /* Special case. Sending ::1 around between servers
660 * and to clients is dangerous, because the : on the
661 * start makes the client or server interpret the IP
662 * as the last parameter on the line with a value ":1".
664 if (*formatted == ':')
665 resultstr = "0" + resultstr;
669 case DNS_QUERY_CNAME:
670 /* Identical handling to PTR */
673 /* Reverse lookups just come back as char* */
674 resultstr = std::string((const char*)data.first);
678 log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
683 /* Build the reply with the id and hostname/ip in it */
685 return std::make_pair(this_id,resultstr);
689 /* A result is ready, process it */
690 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
698 if (!(header.flags1 & FLAGS_MASK_QR))
699 return std::make_pair((unsigned char*)NULL,"Not a query result");
701 if (header.flags1 & FLAGS_MASK_OPCODE)
702 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
704 if (header.flags2 & FLAGS_MASK_RCODE)
705 return std::make_pair((unsigned char*)NULL,"Domain name not found");
707 if (header.ancount < 1)
708 return std::make_pair((unsigned char*)NULL,"No resource records returned");
710 /* Subtract the length of the header from the length of the packet */
713 while ((unsigned int)q < header.qdcount && i < length)
715 if (header.payload[i] > 63)
722 if (header.payload[i] == 0)
727 else i += header.payload[i] + 1;
731 while ((unsigned)curanswer < header.ancount)
734 while (q == 0 && i < length)
736 if (header.payload[i] > 63)
743 if (header.payload[i] == 0)
748 else i += header.payload[i] + 1; /* skip length and label */
752 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
754 DNS::FillResourceRecord(&rr,&header.payload[i]);
756 if (rr.type != this->type)
762 if (rr.rr_class != this->rr_class)
770 if ((unsigned int)curanswer == header.ancount)
771 return std::make_pair((unsigned char*)NULL,"No valid answers");
773 if (i + rr.rdlength > (unsigned int)length)
774 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
776 if (rr.rdlength > 1023)
777 return std::make_pair((unsigned char*)NULL,"Resource record too large");
781 case DNS_QUERY_CNAME:
782 /* CNAME and PTR have the same processing code */
786 while (q == 0 && i < length && o + 256 < 1023)
788 if (header.payload[i] > 63)
790 memcpy(&ptr,&header.payload[i],2);
791 i = ntohs(ptr) - 0xC000 - 12;
795 if (header.payload[i] == 0)
804 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
805 o += header.payload[i];
806 i += header.payload[i] + 1;
813 memcpy(res,&header.payload[i],rr.rdlength);
814 res[rr.rdlength] = 0;
817 memcpy(res,&header.payload[i],rr.rdlength);
818 res[rr.rdlength] = 0;
821 memcpy(res,&header.payload[i],rr.rdlength);
822 res[rr.rdlength] = 0;
825 return std::make_pair(res,"No error");;
828 /* Close the master socket */
831 shutdown(MasterSocket, 2);
835 /* High level abstraction of dns used by application at large */
836 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
838 log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
845 this->myid = ServerInstance->Res->GetIP(source.c_str());
849 if (insp_aton(source.c_str(), &binip) > 0)
851 /* Valid ip address */
852 this->myid = ServerInstance->Res->GetName(&binip);
856 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
857 throw ModuleException("Resolver: Bad IP address");
863 querytype = DNS_QUERY_PTR;
864 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
868 querytype = DNS_QUERY_PTR;
869 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
873 this->myid = ServerInstance->Res->GetIP6(source.c_str());
876 case DNS_QUERY_CNAME:
877 this->myid = ServerInstance->Res->GetCName(source.c_str());
884 if (this->myid == -1)
886 log(DEBUG,"Resolver::Resolver: Could not get an id!");
887 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
888 throw ModuleException("Resolver: Couldnt get an id to make a request");
889 /* We shouldnt get here really */
893 log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
896 void Resolver::OnError(ResolverError e, const std::string &errormessage)
898 /* Nothing in here */
901 Resolver::~Resolver()
903 /* Nothing here (yet) either */
906 /* Get the request id associated with this class */
907 int Resolver::GetId()
912 /* Process a socket read event */
913 void DNS::MarshallReads(int fd)
915 log(DEBUG,"Marshall reads: %d %d",fd,GetMasterSocket());
916 /* We are only intrested in our single fd */
917 if (fd == GetMasterSocket())
919 /* Fetch the id and result of the next available packet */
920 DNSResult res = this->GetResult();
921 /* Is there a usable request id? */
924 /* Its an error reply */
925 if (res.first & ERROR_MASK)
927 /* Mask off the error bit */
928 res.first -= ERROR_MASK;
930 /* Marshall the error to the correct class */
931 log(DEBUG,"Error available, id=%d",res.first);
932 if (Classes[res.first])
934 if (ServerInstance && ServerInstance->stats)
935 ServerInstance->stats->statsDnsBad++;
936 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
937 delete Classes[res.first];
938 Classes[res.first] = NULL;
943 /* It is a non-error result */
944 log(DEBUG,"Result available, id=%d",res.first);
945 /* Marshall the result to the correct class */
946 if (Classes[res.first])
948 if (ServerInstance && ServerInstance->stats)
949 ServerInstance->stats->statsDnsGood++;
950 Classes[res.first]->OnLookupComplete(res.second);
951 delete Classes[res.first];
952 Classes[res.first] = NULL;
956 if (ServerInstance && ServerInstance->stats)
957 ServerInstance->stats->statsDns++;
963 /* Add a derived Resolver to the working set */
964 bool DNS::AddResolverClass(Resolver* r)
966 /* Check the pointers validity and the id's validity */
967 if ((r) && (r->GetId() > -1))
969 /* Check the slot isnt already occupied -
970 * This should NEVER happen unless we have
971 * a severely broken DNS server somewhere
973 if (!Classes[r->GetId()])
975 /* Set up the pointer to the class */
976 Classes[r->GetId()] = r;
985 /* Pointer or id not valid.
986 * Free the item and return
995 unsigned long DNS::PRNG()
997 unsigned long val = 0;
999 serverstats* s = ServerInstance->stats;
1000 gettimeofday(&n,NULL);
1001 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1002 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1003 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;