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"
48 using irc::sockets::insp_sockaddr;
49 using irc::sockets::insp_inaddr;
50 using irc::sockets::insp_ntoa;
51 using irc::sockets::insp_aton;
53 /* Master file descriptor */
54 int DNS::MasterSocket;
56 /* Masks to mask off the responses we get from the DNSRequest methods */
59 ERROR_MASK = 0x10000 /* Result is an error */
62 /* Flags which can be ORed into a request or reply for different meanings */
65 FLAGS_MASK_RD = 0x01, /* Recursive */
67 FLAGS_MASK_AA = 0x04, /* Authoritative */
68 FLAGS_MASK_OPCODE = 0x78,
70 FLAGS_MASK_RCODE = 0x0F, /* Request */
76 /* Represents a dns resource record (rr) */
80 QueryType type; /* Record type */
81 unsigned int rr_class; /* Record class */
82 unsigned long ttl; /* Time to live */
83 unsigned int rdlength; /* Record length */
86 /* Represents a dns request/reply header, and its payload as opaque data.
91 unsigned char id[2]; /* Request id */
92 unsigned int flags1; /* Flags */
93 unsigned int flags2; /* Flags */
95 unsigned int ancount; /* Answer count */
96 unsigned int nscount; /* Nameserver count */
98 unsigned char payload[512]; /* Packet payload */
101 /* Represents a request 'on the wire' with routing information relating to
102 * where to call when we get a result
107 unsigned char id[2]; /* Request id */
108 unsigned char* res; /* Result processing buffer */
109 unsigned int rr_class; /* Request class */
110 QueryType type; /* Request type */
111 insp_inaddr myserver; /* DNS server address*/
113 /* Allocate the processing buffer */
114 DNSRequest(insp_inaddr server)
116 res = new unsigned char[512];
118 memcpy(&myserver, &server, sizeof(insp_inaddr));
121 /* Deallocate the processing buffer */
127 /* Called when a result is ready to be processed which matches this id */
128 DNSInfo ResultIsReady(DNSHeader &h, int length);
130 /* Called when there are requests to be sent out */
131 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
134 /* Fill a ResourceRecord class based on raw data input */
135 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
137 rr->type = (QueryType)((input[0] << 8) + input[1]);
138 rr->rr_class = (input[2] << 8) + input[3];
139 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
140 rr->rdlength = (input[8] << 8) + input[9];
143 /* Fill a DNSHeader class based on raw data input of a given length */
144 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
146 header->id[0] = input[0];
147 header->id[1] = input[1];
148 header->flags1 = input[2];
149 header->flags2 = input[3];
150 header->qdcount = (input[4] << 8) + input[5];
151 header->ancount = (input[6] << 8) + input[7];
152 header->nscount = (input[8] << 8) + input[9];
153 header->arcount = (input[10] << 8) + input[11];
154 memcpy(header->payload,&input[12],length);
157 /* Empty a DNSHeader class out into raw data, ready for transmission */
158 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
160 output[0] = header->id[0];
161 output[1] = header->id[1];
162 output[2] = header->flags1;
163 output[3] = header->flags2;
164 output[4] = header->qdcount >> 8;
165 output[5] = header->qdcount & 0xFF;
166 output[6] = header->ancount >> 8;
167 output[7] = header->ancount & 0xFF;
168 output[8] = header->nscount >> 8;
169 output[9] = header->nscount & 0xFF;
170 output[10] = header->arcount >> 8;
171 output[11] = header->arcount & 0xFF;
172 memcpy(&output[12],header->payload,length);
175 /* Send requests we have previously built down the UDP socket */
176 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
179 unsigned char payload[sizeof(DNSHeader)];
184 DNS::EmptyHeader(payload,header,length);
186 memset(&addr,0,sizeof(addr));
188 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
189 addr.sin6_family = AF_FAMILY;
190 addr.sin6_port = htons(DNS::QUERY_PORT);
192 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
193 addr.sin_family = AF_FAMILY;
194 addr.sin_port = htons(DNS::QUERY_PORT);
196 if (sendto(DNS::GetMasterSocket(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
198 log(DEBUG,"Error in sendto! (%s)",strerror(errno));
205 /* Add a query with a predefined header, and allocate an ID for it. */
206 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
208 /* Is the DNS connection down? */
209 if (MasterSocket == -1)
212 /* Are there already the max number of requests on the go? */
213 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
217 id = this->PRNG() & DNS::MAX_REQUEST_ID;
219 /* If this id is already 'in flight', pick another. */
220 while (requests.find(id) != requests.end())
221 id = this->PRNG() & DNS::MAX_REQUEST_ID;
223 DNSRequest* req = new DNSRequest(this->myserver);
225 header->id[0] = req->id[0] = id >> 8;
226 header->id[1] = req->id[1] = id & 0xFF;
227 header->flags1 = FLAGS_MASK_RD;
234 /* At this point we already know the id doesnt exist,
235 * so there needs to be no second check for the ::end()
239 /* According to the C++ spec, new never returns NULL. */
243 int DNS::GetMasterSocket()
248 /* Initialise the DNS UDP socket so that we can send requests */
249 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
251 log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
255 /* Clear the Resolver class table */
256 memset(Classes,0,sizeof(Classes));
258 /* Set the id of the next request to 0
262 /* Clear the namesever address */
263 memset(&myserver,0,sizeof(insp_inaddr));
265 /* Convert the nameserver address into an insp_inaddr */
266 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
268 memcpy(&myserver,&addr,sizeof(insp_inaddr));
269 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
271 /* These dont come back looking like they did when they went in.
272 * We're forced to turn some checks off.
273 * If anyone knows how to fix this, let me know. --Brain
275 log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
276 log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
277 log(DEFAULT," to a true IPv6 environment.");
278 this->ip6munge = true;
280 log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
284 log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
287 /* Initialize mastersocket */
288 MasterSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
289 if (MasterSocket != -1)
291 /* Did it succeed? */
292 if (fcntl(MasterSocket, F_SETFL, O_NONBLOCK) != 0)
294 /* Couldn't make the socket nonblocking */
295 shutdown(MasterSocket,2);
302 log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
304 /* Have we got a socket and is it nonblocking? */
305 if (MasterSocket != -1)
309 memset(&addr,0,sizeof(addr));
310 addr.sin6_family = AF_FAMILY;
312 addr.sin6_addr = in6addr_any;
315 memset(&addr,0,sizeof(addr));
316 addr.sin_family = AF_FAMILY;
318 addr.sin_addr.s_addr = INADDR_ANY;
321 if (bind(MasterSocket,(sockaddr *)&addr,sizeof(addr)) != 0)
324 log(DEBUG,"Cant bind DNS::MasterSocket");
325 shutdown(MasterSocket,2);
330 if (MasterSocket >= 0)
332 log(DEBUG,"Add master socket %d",MasterSocket);
333 /* Hook the descriptor into the socket engine */
334 if (ServerInstance && ServerInstance->SE)
336 if (!ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS))
338 log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
339 shutdown(MasterSocket,2);
348 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
349 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
351 short payloadpos = 0;
352 const char* tempchr, *tempchr2 = name;
353 unsigned short length;
355 /* split name up into labels, create query */
356 while ((tempchr = strchr(tempchr2,'.')) != NULL)
358 length = tempchr - tempchr2;
359 if (payloadpos + length + 1 > 507)
361 payload[payloadpos++] = length;
362 memcpy(&payload[payloadpos],tempchr2,length);
363 payloadpos += length;
364 tempchr2 = &tempchr[1];
366 length = strlen(tempchr2);
369 if (payloadpos + length + 2 > 507)
371 payload[payloadpos++] = length;
372 memcpy(&payload[payloadpos],tempchr2,length);
373 payloadpos += length;
374 payload[payloadpos++] = 0;
376 if (payloadpos > 508)
379 memcpy(&payload[payloadpos],&length,2);
380 length = htons(rr_class);
381 memcpy(&payload[payloadpos + 2],&length,2);
382 return payloadpos + 4;
385 /* Start lookup of an hostname to an IP address */
386 int DNS::GetIP(const char *name)
392 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
395 DNSRequest* req = this->AddQuery(&h, id);
397 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
403 /* Start lookup of an hostname to an IPv6 address */
404 int DNS::GetIP6(const char *name)
410 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
413 DNSRequest* req = this->AddQuery(&h, id);
415 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
421 /* Start lookup of a cname to another name */
422 int DNS::GetCName(const char *alias)
428 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
431 DNSRequest* req = this->AddQuery(&h, id);
433 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
439 /* Start lookup of an IP address to a hostname */
440 int DNS::GetName(const insp_inaddr *ip)
448 DNS::MakeIP6Int(query, (in6_addr*)ip);
450 unsigned char* c = (unsigned char*)&ip->s_addr;
452 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
455 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
458 DNSRequest* req = this->AddQuery(&h, id);
460 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
466 /* Start lookup of an IP address to a hostname */
467 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
473 #ifdef SUPPORT_IP6LINKS
474 if (fp == PROTOCOL_IPV6)
477 if (inet_pton(AF_INET6, ip, &i) > 0)
479 DNS::MakeIP6Int(query, &i);
482 /* Invalid IP address */
489 if (inet_aton(ip, &i))
491 unsigned char* c = (unsigned char*)&i.s_addr;
492 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
495 /* Invalid IP address */
499 log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
501 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
504 DNSRequest* req = this->AddQuery(&h, id);
506 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
512 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
514 #ifdef SUPPORT_IP6LINKS
515 const char* hex = "0123456789abcdef";
516 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
520 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
523 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
524 *query++ = '.'; /* Seperator */
526 strcpy(query,"ip6.arpa"); /* Suffix the string */
532 /* Return the next id which is ready, and the result attached to it */
533 DNSResult DNS::GetResult()
535 /* Fetch dns query response and decide where it belongs */
538 unsigned char buffer[sizeof(DNSHeader)];
540 socklen_t x = sizeof(from);
541 const char* ipaddr_from = "";
542 unsigned short int port_from = 0;
544 int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
547 log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
549 /* Did we get the whole header? */
552 /* Nope - something screwed up. */
553 log(DEBUG,"Whole header not read!");
554 return std::make_pair(-1,"");
557 /* Check wether the reply came from a different DNS
558 * server to the one we sent it to, or the source-port
560 * A user could in theory still spoof dns packets anyway
561 * but this is less trivial than just sending garbage
562 * to the client, which is possible without this check.
564 * -- Thanks jilles for pointing this one out.
567 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
568 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
570 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
571 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
574 /* We cant perform this security check if you're using 4in6.
575 * Tough luck to you, choose one or't other!
579 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
581 log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
582 return std::make_pair(-1,"");
586 /* Put the read header info into a header class */
587 DNS::FillHeader(&header,buffer,length - 12);
589 /* Get the id of this request.
590 * Its a 16 bit value stored in two char's,
591 * so we use logic shifts to create the value.
593 unsigned long this_id = header.id[1] + (header.id[0] << 8);
595 /* Do we have a pending request matching this id? */
596 requestlist_iter n_iter = requests.find(this_id);
597 if (n_iter == requests.end())
599 /* Somehow we got a DNS response for a request we never made... */
600 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
601 return std::make_pair(-1,"");
605 /* Remove the query from the list of pending queries */
606 req = (DNSRequest*)n_iter->second;
607 requests.erase(n_iter);
610 /* Inform the DNSRequest class that it has a result to be read.
611 * When its finished it will return a DNSInfo which is a pair of
612 * unsigned char* resource record data, and an error message.
614 DNSInfo data = req->ResultIsReady(header, length);
615 std::string resultstr;
617 /* Check if we got a result, if we didnt, its an error */
618 if (data.first == NULL)
621 * Mask the ID with the value of ERROR_MASK, so that
622 * the dns_deal_with_classes() function knows that its
623 * an error response and needs to be treated uniquely.
624 * Put the error message in the second field.
627 return std::make_pair(this_id | ERROR_MASK, data.second);
633 /* Forward lookups come back as binary data. We must format them into ascii */
637 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
638 resultstr = formatted;
643 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
644 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
645 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
646 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
647 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
648 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
649 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
650 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
651 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
652 char* c = strstr(formatted,":0:");
655 memmove(c+1,c+2,strlen(c+2) + 1);
657 while (memcmp(c,"0:",2) == 0)
658 memmove(c,c+2,strlen(c+2) + 1);
659 if (memcmp(c,"0",2) == 0)
661 if (memcmp(formatted,"0::",3) == 0)
662 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
664 resultstr = formatted;
666 /* Special case. Sending ::1 around between servers
667 * and to clients is dangerous, because the : on the
668 * start makes the client or server interpret the IP
669 * as the last parameter on the line with a value ":1".
671 if (*formatted == ':')
672 resultstr = "0" + resultstr;
676 case DNS_QUERY_CNAME:
677 /* Identical handling to PTR */
680 /* Reverse lookups just come back as char* */
681 resultstr = std::string((const char*)data.first);
685 log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
690 /* Build the reply with the id and hostname/ip in it */
692 return std::make_pair(this_id,resultstr);
696 /* A result is ready, process it */
697 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
705 if (!(header.flags1 & FLAGS_MASK_QR))
706 return std::make_pair((unsigned char*)NULL,"Not a query result");
708 if (header.flags1 & FLAGS_MASK_OPCODE)
709 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
711 if (header.flags2 & FLAGS_MASK_RCODE)
712 return std::make_pair((unsigned char*)NULL,"Domain name not found");
714 if (header.ancount < 1)
715 return std::make_pair((unsigned char*)NULL,"No resource records returned");
717 /* Subtract the length of the header from the length of the packet */
720 while ((unsigned int)q < header.qdcount && i < length)
722 if (header.payload[i] > 63)
729 if (header.payload[i] == 0)
734 else i += header.payload[i] + 1;
738 while ((unsigned)curanswer < header.ancount)
741 while (q == 0 && i < length)
743 if (header.payload[i] > 63)
750 if (header.payload[i] == 0)
755 else i += header.payload[i] + 1; /* skip length and label */
759 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
761 DNS::FillResourceRecord(&rr,&header.payload[i]);
763 if (rr.type != this->type)
769 if (rr.rr_class != this->rr_class)
777 if ((unsigned int)curanswer == header.ancount)
778 return std::make_pair((unsigned char*)NULL,"No valid answers");
780 if (i + rr.rdlength > (unsigned int)length)
781 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
783 if (rr.rdlength > 1023)
784 return std::make_pair((unsigned char*)NULL,"Resource record too large");
788 case DNS_QUERY_CNAME:
789 /* CNAME and PTR have the same processing code */
793 while (q == 0 && i < length && o + 256 < 1023)
795 if (header.payload[i] > 63)
797 memcpy(&ptr,&header.payload[i],2);
798 i = ntohs(ptr) - 0xC000 - 12;
802 if (header.payload[i] == 0)
811 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
812 o += header.payload[i];
813 i += header.payload[i] + 1;
820 memcpy(res,&header.payload[i],rr.rdlength);
821 res[rr.rdlength] = 0;
824 memcpy(res,&header.payload[i],rr.rdlength);
825 res[rr.rdlength] = 0;
828 memcpy(res,&header.payload[i],rr.rdlength);
829 res[rr.rdlength] = 0;
832 return std::make_pair(res,"No error");;
835 /* Close the master socket */
838 shutdown(MasterSocket, 2);
842 /* High level abstraction of dns used by application at large */
843 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
845 log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
852 this->myid = ServerInstance->Res->GetIP(source.c_str());
856 if (insp_aton(source.c_str(), &binip) > 0)
858 /* Valid ip address */
859 this->myid = ServerInstance->Res->GetName(&binip);
863 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
864 throw ModuleException("Resolver: Bad IP address");
870 querytype = DNS_QUERY_PTR;
871 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
875 querytype = DNS_QUERY_PTR;
876 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
880 this->myid = ServerInstance->Res->GetIP6(source.c_str());
883 case DNS_QUERY_CNAME:
884 this->myid = ServerInstance->Res->GetCName(source.c_str());
891 if (this->myid == -1)
893 log(DEBUG,"Resolver::Resolver: Could not get an id!");
894 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
895 throw ModuleException("Resolver: Couldnt get an id to make a request");
896 /* We shouldnt get here really */
900 log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
903 void Resolver::OnError(ResolverError e, const std::string &errormessage)
905 /* Nothing in here */
908 Resolver::~Resolver()
910 /* Nothing here (yet) either */
913 /* Get the request id associated with this class */
914 int Resolver::GetId()
919 /* Process a socket read event */
920 void DNS::MarshallReads(int fd)
922 log(DEBUG,"Marshall reads: %d %d",fd,GetMasterSocket());
923 /* We are only intrested in our single fd */
924 if (fd == GetMasterSocket())
926 /* Fetch the id and result of the next available packet */
927 DNSResult res = this->GetResult();
928 /* Is there a usable request id? */
931 /* Its an error reply */
932 if (res.first & ERROR_MASK)
934 /* Mask off the error bit */
935 res.first -= ERROR_MASK;
937 /* Marshall the error to the correct class */
938 log(DEBUG,"Error available, id=%d",res.first);
939 if (Classes[res.first])
941 if (ServerInstance && ServerInstance->stats)
942 ServerInstance->stats->statsDnsBad++;
943 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
944 delete Classes[res.first];
945 Classes[res.first] = NULL;
950 /* It is a non-error result */
951 log(DEBUG,"Result available, id=%d",res.first);
952 /* Marshall the result to the correct class */
953 if (Classes[res.first])
955 if (ServerInstance && ServerInstance->stats)
956 ServerInstance->stats->statsDnsGood++;
957 Classes[res.first]->OnLookupComplete(res.second);
958 delete Classes[res.first];
959 Classes[res.first] = NULL;
963 if (ServerInstance && ServerInstance->stats)
964 ServerInstance->stats->statsDns++;
970 /* Add a derived Resolver to the working set */
971 bool DNS::AddResolverClass(Resolver* r)
973 /* Check the pointers validity and the id's validity */
974 if ((r) && (r->GetId() > -1))
976 /* Check the slot isnt already occupied -
977 * This should NEVER happen unless we have
978 * a severely broken DNS server somewhere
980 if (!Classes[r->GetId()])
982 /* Set up the pointer to the class */
983 Classes[r->GetId()] = r;
992 /* Pointer or id not valid.
993 * Free the item and return
1002 unsigned long DNS::PRNG()
1004 unsigned long val = 0;
1006 serverstats* s = ServerInstance->stats;
1007 gettimeofday(&n,NULL);
1008 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1009 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1010 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;