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.
29 #include <sys/types.h>
30 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
36 #include "socketengine.h"
37 #include "configreader.h"
41 using irc::sockets::insp_sockaddr;
42 using irc::sockets::insp_inaddr;
43 using irc::sockets::insp_ntoa;
44 using irc::sockets::insp_aton;
46 /** Masks to mask off the responses we get from the DNSRequest methods
50 ERROR_MASK = 0x10000 /* Result is an error */
53 /** Flags which can be ORed into a request or reply for different meanings
57 FLAGS_MASK_RD = 0x01, /* Recursive */
59 FLAGS_MASK_AA = 0x04, /* Authoritative */
60 FLAGS_MASK_OPCODE = 0x78,
62 FLAGS_MASK_RCODE = 0x0F, /* Request */
68 /** 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*/
105 DNS* dnsobj; /* DNS caller (where we get our FD from) */
107 /* Allocate the processing buffer */
108 DNSRequest(DNS* dns, insp_inaddr server) : dnsobj(dns)
110 res = new unsigned char[512];
112 memcpy(&myserver, &server, sizeof(insp_inaddr));
115 /* Deallocate the processing buffer */
121 /* Called when a result is ready to be processed which matches this id */
122 DNSInfo ResultIsReady(DNSHeader &h, int length);
124 /* Called when there are requests to be sent out */
125 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
128 /** Fill a ResourceRecord class based on raw data input */
129 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
131 rr->type = (QueryType)((input[0] << 8) + input[1]);
132 rr->rr_class = (input[2] << 8) + input[3];
133 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
134 rr->rdlength = (input[8] << 8) + input[9];
137 /** Fill a DNSHeader class based on raw data input of a given length */
138 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
140 header->id[0] = input[0];
141 header->id[1] = input[1];
142 header->flags1 = input[2];
143 header->flags2 = input[3];
144 header->qdcount = (input[4] << 8) + input[5];
145 header->ancount = (input[6] << 8) + input[7];
146 header->nscount = (input[8] << 8) + input[9];
147 header->arcount = (input[10] << 8) + input[11];
148 memcpy(header->payload,&input[12],length);
151 /** Empty a DNSHeader class out into raw data, ready for transmission */
152 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
154 output[0] = header->id[0];
155 output[1] = header->id[1];
156 output[2] = header->flags1;
157 output[3] = header->flags2;
158 output[4] = header->qdcount >> 8;
159 output[5] = header->qdcount & 0xFF;
160 output[6] = header->ancount >> 8;
161 output[7] = header->ancount & 0xFF;
162 output[8] = header->nscount >> 8;
163 output[9] = header->nscount & 0xFF;
164 output[10] = header->arcount >> 8;
165 output[11] = header->arcount & 0xFF;
166 memcpy(&output[12],header->payload,length);
169 /** Send requests we have previously built down the UDP socket */
170 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
173 unsigned char payload[sizeof(DNSHeader)];
178 DNS::EmptyHeader(payload,header,length);
180 memset(&addr,0,sizeof(addr));
182 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
183 addr.sin6_family = AF_FAMILY;
184 addr.sin6_port = htons(DNS::QUERY_PORT);
186 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
187 addr.sin_family = AF_FAMILY;
188 addr.sin_port = htons(DNS::QUERY_PORT);
190 if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
196 /** Add a query with a predefined header, and allocate an ID for it. */
197 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
199 /* Is the DNS connection down? */
200 if (this->GetFd() == -1)
203 /* Are there already the max number of requests on the go? */
204 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
208 id = this->PRNG() & DNS::MAX_REQUEST_ID;
210 /* If this id is already 'in flight', pick another. */
211 while (requests.find(id) != requests.end())
212 id = this->PRNG() & DNS::MAX_REQUEST_ID;
214 DNSRequest* req = new DNSRequest(this, this->myserver);
216 header->id[0] = req->id[0] = id >> 8;
217 header->id[1] = req->id[1] = id & 0xFF;
218 header->flags1 = FLAGS_MASK_RD;
225 /* At this point we already know the id doesnt exist,
226 * so there needs to be no second check for the ::end()
230 /* According to the C++ spec, new never returns NULL. */
234 /** Initialise the DNS UDP socket so that we can send requests */
235 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
237 ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
241 /* Clear the Resolver class table */
242 memset(Classes,0,sizeof(Classes));
244 /* Set the id of the next request to 0
248 /* By default we're not munging ip's
252 /* Clear the namesever address */
253 memset(&myserver,0,sizeof(insp_inaddr));
255 /* Convert the nameserver address into an insp_inaddr */
256 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
258 memcpy(&myserver,&addr,sizeof(insp_inaddr));
259 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
261 /* These dont come back looking like they did when they went in.
262 * We're forced to turn some checks off.
263 * If anyone knows how to fix this, let me know. --Brain
265 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
266 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
267 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
268 this->ip6munge = true;
270 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
274 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
277 /* Initialize mastersocket */
278 this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
279 if (this->GetFd() != -1)
281 /* Did it succeed? */
282 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
284 /* Couldn't make the socket nonblocking */
285 shutdown(this->GetFd(),2);
286 close(this->GetFd());
292 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
294 /* Have we got a socket and is it nonblocking? */
295 if (this->GetFd() != -1)
299 memset(&addr,0,sizeof(addr));
300 addr.sin6_family = AF_FAMILY;
302 addr.sin6_addr = in6addr_any;
305 memset(&addr,0,sizeof(addr));
306 addr.sin_family = AF_FAMILY;
308 addr.sin_addr.s_addr = INADDR_ANY;
311 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
314 ServerInstance->Log(DEBUG,"Cant bind DNS fd");
315 shutdown(this->GetFd(),2);
316 close(this->GetFd());
320 if (this->GetFd() >= 0)
322 ServerInstance->Log(DEBUG,"Add master socket %d",this->GetFd());
323 /* Hook the descriptor into the socket engine */
324 if (ServerInstance && ServerInstance->SE)
326 if (!ServerInstance->SE->AddFd(this))
328 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
329 shutdown(this->GetFd(),2);
330 close(this->GetFd());
338 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
339 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
341 short payloadpos = 0;
342 const char* tempchr, *tempchr2 = name;
343 unsigned short length;
345 /* split name up into labels, create query */
346 while ((tempchr = strchr(tempchr2,'.')) != NULL)
348 length = tempchr - tempchr2;
349 if (payloadpos + length + 1 > 507)
351 payload[payloadpos++] = length;
352 memcpy(&payload[payloadpos],tempchr2,length);
353 payloadpos += length;
354 tempchr2 = &tempchr[1];
356 length = strlen(tempchr2);
359 if (payloadpos + length + 2 > 507)
361 payload[payloadpos++] = length;
362 memcpy(&payload[payloadpos],tempchr2,length);
363 payloadpos += length;
364 payload[payloadpos++] = 0;
366 if (payloadpos > 508)
369 memcpy(&payload[payloadpos],&length,2);
370 length = htons(rr_class);
371 memcpy(&payload[payloadpos + 2],&length,2);
372 return payloadpos + 4;
375 /** Start lookup of an hostname to an IP address */
376 int DNS::GetIP(const char *name)
382 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
385 DNSRequest* req = this->AddQuery(&h, id);
387 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
393 /** Start lookup of an hostname to an IPv6 address */
394 int DNS::GetIP6(const char *name)
400 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
403 DNSRequest* req = this->AddQuery(&h, id);
405 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
411 /** Start lookup of a cname to another name */
412 int DNS::GetCName(const char *alias)
418 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
421 DNSRequest* req = this->AddQuery(&h, id);
423 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
429 /** Start lookup of an IP address to a hostname */
430 int DNS::GetName(const insp_inaddr *ip)
438 DNS::MakeIP6Int(query, (in6_addr*)ip);
440 unsigned char* c = (unsigned char*)&ip->s_addr;
442 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
445 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
448 DNSRequest* req = this->AddQuery(&h, id);
450 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
456 /** Start lookup of an IP address to a hostname */
457 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
463 #ifdef SUPPORT_IP6LINKS
464 if (fp == PROTOCOL_IPV6)
467 if (inet_pton(AF_INET6, ip, &i) > 0)
469 DNS::MakeIP6Int(query, &i);
472 /* Invalid IP address */
479 if (inet_aton(ip, &i))
481 unsigned char* c = (unsigned char*)&i.s_addr;
482 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
485 /* Invalid IP address */
489 ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
491 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
494 DNSRequest* req = this->AddQuery(&h, id);
496 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
502 /** Build an ipv6 reverse domain from an in6_addr
504 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
506 #ifdef SUPPORT_IP6LINKS
507 const char* hex = "0123456789abcdef";
508 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
512 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
515 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
516 *query++ = '.'; /* Seperator */
518 strcpy(query,"ip6.arpa"); /* Suffix the string */
524 /** Return the next id which is ready, and the result attached to it */
525 DNSResult DNS::GetResult()
527 /* Fetch dns query response and decide where it belongs */
530 unsigned char buffer[sizeof(DNSHeader)];
532 socklen_t x = sizeof(from);
533 const char* ipaddr_from = "";
534 unsigned short int port_from = 0;
536 int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
539 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
541 /* Did we get the whole header? */
544 /* Nope - something screwed up. */
545 ServerInstance->Log(DEBUG,"Whole header not read!");
546 return std::make_pair(-1,"");
549 /* Check wether the reply came from a different DNS
550 * server to the one we sent it to, or the source-port
552 * A user could in theory still spoof dns packets anyway
553 * but this is less trivial than just sending garbage
554 * to the client, which is possible without this check.
556 * -- Thanks jilles for pointing this one out.
559 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
560 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
562 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
563 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
566 /* We cant perform this security check if you're using 4in6.
567 * Tough luck to you, choose one or't other!
571 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
573 ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
574 return std::make_pair(-1,"");
578 /* Put the read header info into a header class */
579 DNS::FillHeader(&header,buffer,length - 12);
581 /* Get the id of this request.
582 * Its a 16 bit value stored in two char's,
583 * so we use logic shifts to create the value.
585 unsigned long this_id = header.id[1] + (header.id[0] << 8);
587 /* Do we have a pending request matching this id? */
588 requestlist_iter n_iter = requests.find(this_id);
589 if (n_iter == requests.end())
591 /* Somehow we got a DNS response for a request we never made... */
592 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
593 return std::make_pair(-1,"");
597 /* Remove the query from the list of pending queries */
598 req = (DNSRequest*)n_iter->second;
599 requests.erase(n_iter);
602 /* Inform the DNSRequest class that it has a result to be read.
603 * When its finished it will return a DNSInfo which is a pair of
604 * unsigned char* resource record data, and an error message.
606 DNSInfo data = req->ResultIsReady(header, length);
607 std::string resultstr;
609 /* Check if we got a result, if we didnt, its an error */
610 if (data.first == NULL)
613 * Mask the ID with the value of ERROR_MASK, so that
614 * the dns_deal_with_classes() function knows that its
615 * an error response and needs to be treated uniquely.
616 * Put the error message in the second field.
619 return std::make_pair(this_id | ERROR_MASK, data.second);
625 /* Forward lookups come back as binary data. We must format them into ascii */
629 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
630 resultstr = formatted;
635 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
636 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
637 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
638 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
639 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
640 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
641 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
642 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
643 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
644 char* c = strstr(formatted,":0:");
647 memmove(c+1,c+2,strlen(c+2) + 1);
649 while (memcmp(c,"0:",2) == 0)
650 memmove(c,c+2,strlen(c+2) + 1);
651 if (memcmp(c,"0",2) == 0)
653 if (memcmp(formatted,"0::",3) == 0)
654 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
656 resultstr = formatted;
658 /* Special case. Sending ::1 around between servers
659 * and to clients is dangerous, because the : on the
660 * start makes the client or server interpret the IP
661 * as the last parameter on the line with a value ":1".
663 if (*formatted == ':')
664 resultstr = "0" + resultstr;
668 case DNS_QUERY_CNAME:
669 /* Identical handling to PTR */
672 /* Reverse lookups just come back as char* */
673 resultstr = std::string((const char*)data.first);
677 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
682 /* Build the reply with the id and hostname/ip in it */
684 return std::make_pair(this_id,resultstr);
688 /** A result is ready, process it */
689 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
697 if (!(header.flags1 & FLAGS_MASK_QR))
698 return std::make_pair((unsigned char*)NULL,"Not a query result");
700 if (header.flags1 & FLAGS_MASK_OPCODE)
701 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
703 if (header.flags2 & FLAGS_MASK_RCODE)
704 return std::make_pair((unsigned char*)NULL,"Domain name not found");
706 if (header.ancount < 1)
707 return std::make_pair((unsigned char*)NULL,"No resource records returned");
709 /* Subtract the length of the header from the length of the packet */
712 while ((unsigned int)q < header.qdcount && i < length)
714 if (header.payload[i] > 63)
721 if (header.payload[i] == 0)
726 else i += header.payload[i] + 1;
730 while ((unsigned)curanswer < header.ancount)
733 while (q == 0 && i < length)
735 if (header.payload[i] > 63)
742 if (header.payload[i] == 0)
747 else i += header.payload[i] + 1; /* skip length and label */
751 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
753 DNS::FillResourceRecord(&rr,&header.payload[i]);
755 if (rr.type != this->type)
761 if (rr.rr_class != this->rr_class)
769 if ((unsigned int)curanswer == header.ancount)
770 return std::make_pair((unsigned char*)NULL,"No valid answers");
772 if (i + rr.rdlength > (unsigned int)length)
773 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
775 if (rr.rdlength > 1023)
776 return std::make_pair((unsigned char*)NULL,"Resource record too large");
780 case DNS_QUERY_CNAME:
781 /* CNAME and PTR have the same processing code */
785 while (q == 0 && i < length && o + 256 < 1023)
787 if (header.payload[i] > 63)
789 memcpy(&ptr,&header.payload[i],2);
790 i = ntohs(ptr) - 0xC000 - 12;
794 if (header.payload[i] == 0)
803 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
804 o += header.payload[i];
805 i += header.payload[i] + 1;
812 memcpy(res,&header.payload[i],rr.rdlength);
813 res[rr.rdlength] = 0;
816 memcpy(res,&header.payload[i],rr.rdlength);
817 res[rr.rdlength] = 0;
820 memcpy(res,&header.payload[i],rr.rdlength);
821 res[rr.rdlength] = 0;
824 return std::make_pair(res,"No error");;
827 /** Close the master socket */
830 shutdown(this->GetFd(), 2);
831 close(this->GetFd());
834 /** High level abstraction of dns used by application at large */
835 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
837 ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
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 ServerInstance->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 ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
895 /** Called when an error occurs */
896 void Resolver::OnError(ResolverError e, const std::string &errormessage)
898 /* Nothing in here */
901 /** Destroy a resolver */
902 Resolver::~Resolver()
904 /* Nothing here (yet) either */
907 /** Get the request id associated with this class */
908 int Resolver::GetId()
913 /** Process a socket read event */
914 void DNS::HandleEvent(EventType et)
916 ServerInstance->Log(DEBUG,"Marshall reads: %d",this->GetFd());
917 /* Fetch the id and result of the next available packet */
918 DNSResult res = this->GetResult();
919 /* Is there a usable request id? */
922 /* Its an error reply */
923 if (res.first & ERROR_MASK)
925 /* Mask off the error bit */
926 res.first -= ERROR_MASK;
927 /* Marshall the error to the correct class */
928 ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
929 if (Classes[res.first])
931 if (ServerInstance && ServerInstance->stats)
932 ServerInstance->stats->statsDnsBad++;
933 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
934 delete Classes[res.first];
935 Classes[res.first] = NULL;
940 /* It is a non-error result */
941 ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
942 /* Marshall the result to the correct class */
943 if (Classes[res.first])
945 if (ServerInstance && ServerInstance->stats)
946 ServerInstance->stats->statsDnsGood++;
947 Classes[res.first]->OnLookupComplete(res.second);
948 delete Classes[res.first];
949 Classes[res.first] = NULL;
953 if (ServerInstance && ServerInstance->stats)
954 ServerInstance->stats->statsDns++;
958 /** Add a derived Resolver to the working set */
959 bool DNS::AddResolverClass(Resolver* r)
961 /* Check the pointers validity and the id's validity */
962 if ((r) && (r->GetId() > -1))
964 /* Check the slot isnt already occupied -
965 * This should NEVER happen unless we have
966 * a severely broken DNS server somewhere
968 if (!Classes[r->GetId()])
970 /* Set up the pointer to the class */
971 Classes[r->GetId()] = r;
980 /* Pointer or id not valid.
981 * Free the item and return
990 /** Generate pseudo-random number */
991 unsigned long DNS::PRNG()
993 unsigned long val = 0;
995 serverstats* s = ServerInstance->stats;
996 gettimeofday(&n,NULL);
997 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
998 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
999 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;