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 */
49 ERROR_MASK = 0x10000 /* Result is an error */
52 /* Flags which can be ORed into a request or reply for different meanings */
55 FLAGS_MASK_RD = 0x01, /* Recursive */
57 FLAGS_MASK_AA = 0x04, /* Authoritative */
58 FLAGS_MASK_OPCODE = 0x78,
60 FLAGS_MASK_RCODE = 0x0F, /* Request */
66 /* Represents a dns resource record (rr) */
70 QueryType type; /* Record type */
71 unsigned int rr_class; /* Record class */
72 unsigned long ttl; /* Time to live */
73 unsigned int rdlength; /* Record length */
76 /* Represents a dns request/reply header, and its payload as opaque data.
81 unsigned char id[2]; /* Request id */
82 unsigned int flags1; /* Flags */
83 unsigned int flags2; /* Flags */
85 unsigned int ancount; /* Answer count */
86 unsigned int nscount; /* Nameserver count */
88 unsigned char payload[512]; /* Packet payload */
91 /* Represents a request 'on the wire' with routing information relating to
92 * where to call when we get a result
97 unsigned char id[2]; /* Request id */
98 unsigned char* res; /* Result processing buffer */
99 unsigned int rr_class; /* Request class */
100 QueryType type; /* Request type */
101 insp_inaddr myserver; /* DNS server address*/
102 DNS* dnsobj; /* DNS caller (where we get our FD from) */
104 /* Allocate the processing buffer */
105 DNSRequest(DNS* dns, insp_inaddr server) : dnsobj(dns)
107 res = new unsigned char[512];
109 memcpy(&myserver, &server, sizeof(insp_inaddr));
112 /* Deallocate the processing buffer */
118 /* Called when a result is ready to be processed which matches this id */
119 DNSInfo ResultIsReady(DNSHeader &h, int length);
121 /* Called when there are requests to be sent out */
122 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
125 /* Fill a ResourceRecord class based on raw data input */
126 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
128 rr->type = (QueryType)((input[0] << 8) + input[1]);
129 rr->rr_class = (input[2] << 8) + input[3];
130 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
131 rr->rdlength = (input[8] << 8) + input[9];
134 /* Fill a DNSHeader class based on raw data input of a given length */
135 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
137 header->id[0] = input[0];
138 header->id[1] = input[1];
139 header->flags1 = input[2];
140 header->flags2 = input[3];
141 header->qdcount = (input[4] << 8) + input[5];
142 header->ancount = (input[6] << 8) + input[7];
143 header->nscount = (input[8] << 8) + input[9];
144 header->arcount = (input[10] << 8) + input[11];
145 memcpy(header->payload,&input[12],length);
148 /* Empty a DNSHeader class out into raw data, ready for transmission */
149 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
151 output[0] = header->id[0];
152 output[1] = header->id[1];
153 output[2] = header->flags1;
154 output[3] = header->flags2;
155 output[4] = header->qdcount >> 8;
156 output[5] = header->qdcount & 0xFF;
157 output[6] = header->ancount >> 8;
158 output[7] = header->ancount & 0xFF;
159 output[8] = header->nscount >> 8;
160 output[9] = header->nscount & 0xFF;
161 output[10] = header->arcount >> 8;
162 output[11] = header->arcount & 0xFF;
163 memcpy(&output[12],header->payload,length);
166 /* Send requests we have previously built down the UDP socket */
167 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
170 unsigned char payload[sizeof(DNSHeader)];
175 DNS::EmptyHeader(payload,header,length);
177 memset(&addr,0,sizeof(addr));
179 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
180 addr.sin6_family = AF_FAMILY;
181 addr.sin6_port = htons(DNS::QUERY_PORT);
183 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
184 addr.sin_family = AF_FAMILY;
185 addr.sin_port = htons(DNS::QUERY_PORT);
187 if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
193 /* Add a query with a predefined header, and allocate an ID for it. */
194 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
196 /* Is the DNS connection down? */
197 if (this->GetFd() == -1)
200 /* Are there already the max number of requests on the go? */
201 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
205 id = this->PRNG() & DNS::MAX_REQUEST_ID;
207 /* If this id is already 'in flight', pick another. */
208 while (requests.find(id) != requests.end())
209 id = this->PRNG() & DNS::MAX_REQUEST_ID;
211 DNSRequest* req = new DNSRequest(this, this->myserver);
213 header->id[0] = req->id[0] = id >> 8;
214 header->id[1] = req->id[1] = id & 0xFF;
215 header->flags1 = FLAGS_MASK_RD;
222 /* At this point we already know the id doesnt exist,
223 * so there needs to be no second check for the ::end()
227 /* According to the C++ spec, new never returns NULL. */
231 /* Initialise the DNS UDP socket so that we can send requests */
232 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
234 ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
238 /* Clear the Resolver class table */
239 memset(Classes,0,sizeof(Classes));
241 /* Set the id of the next request to 0
245 /* By default we're not munging ip's
249 /* Clear the namesever address */
250 memset(&myserver,0,sizeof(insp_inaddr));
252 /* Convert the nameserver address into an insp_inaddr */
253 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
255 memcpy(&myserver,&addr,sizeof(insp_inaddr));
256 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
258 /* These dont come back looking like they did when they went in.
259 * We're forced to turn some checks off.
260 * If anyone knows how to fix this, let me know. --Brain
262 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
263 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
264 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
265 this->ip6munge = true;
267 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
271 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
274 /* Initialize mastersocket */
275 this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
276 if (this->GetFd() != -1)
278 /* Did it succeed? */
279 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
281 /* Couldn't make the socket nonblocking */
282 shutdown(this->GetFd(),2);
283 close(this->GetFd());
289 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
291 /* Have we got a socket and is it nonblocking? */
292 if (this->GetFd() != -1)
296 memset(&addr,0,sizeof(addr));
297 addr.sin6_family = AF_FAMILY;
299 addr.sin6_addr = in6addr_any;
302 memset(&addr,0,sizeof(addr));
303 addr.sin_family = AF_FAMILY;
305 addr.sin_addr.s_addr = INADDR_ANY;
308 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
311 ServerInstance->Log(DEBUG,"Cant bind DNS fd");
312 shutdown(this->GetFd(),2);
313 close(this->GetFd());
317 if (this->GetFd() >= 0)
319 ServerInstance->Log(DEBUG,"Add master socket %d",this->GetFd());
320 /* Hook the descriptor into the socket engine */
321 if (ServerInstance && ServerInstance->SE)
323 if (!ServerInstance->SE->AddFd(this))
325 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
326 shutdown(this->GetFd(),2);
327 close(this->GetFd());
335 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
336 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
338 short payloadpos = 0;
339 const char* tempchr, *tempchr2 = name;
340 unsigned short length;
342 /* split name up into labels, create query */
343 while ((tempchr = strchr(tempchr2,'.')) != NULL)
345 length = tempchr - tempchr2;
346 if (payloadpos + length + 1 > 507)
348 payload[payloadpos++] = length;
349 memcpy(&payload[payloadpos],tempchr2,length);
350 payloadpos += length;
351 tempchr2 = &tempchr[1];
353 length = strlen(tempchr2);
356 if (payloadpos + length + 2 > 507)
358 payload[payloadpos++] = length;
359 memcpy(&payload[payloadpos],tempchr2,length);
360 payloadpos += length;
361 payload[payloadpos++] = 0;
363 if (payloadpos > 508)
366 memcpy(&payload[payloadpos],&length,2);
367 length = htons(rr_class);
368 memcpy(&payload[payloadpos + 2],&length,2);
369 return payloadpos + 4;
372 /* Start lookup of an hostname to an IP address */
373 int DNS::GetIP(const char *name)
379 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
382 DNSRequest* req = this->AddQuery(&h, id);
384 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
390 /* Start lookup of an hostname to an IPv6 address */
391 int DNS::GetIP6(const char *name)
397 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
400 DNSRequest* req = this->AddQuery(&h, id);
402 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
408 /* Start lookup of a cname to another name */
409 int DNS::GetCName(const char *alias)
415 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
418 DNSRequest* req = this->AddQuery(&h, id);
420 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
426 /* Start lookup of an IP address to a hostname */
427 int DNS::GetName(const insp_inaddr *ip)
435 DNS::MakeIP6Int(query, (in6_addr*)ip);
437 unsigned char* c = (unsigned char*)&ip->s_addr;
439 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
442 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
445 DNSRequest* req = this->AddQuery(&h, id);
447 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
453 /* Start lookup of an IP address to a hostname */
454 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
460 #ifdef SUPPORT_IP6LINKS
461 if (fp == PROTOCOL_IPV6)
464 if (inet_pton(AF_INET6, ip, &i) > 0)
466 DNS::MakeIP6Int(query, &i);
469 /* Invalid IP address */
476 if (inet_aton(ip, &i))
478 unsigned char* c = (unsigned char*)&i.s_addr;
479 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
482 /* Invalid IP address */
486 ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
488 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
491 DNSRequest* req = this->AddQuery(&h, id);
493 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
499 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
501 #ifdef SUPPORT_IP6LINKS
502 const char* hex = "0123456789abcdef";
503 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
507 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
510 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
511 *query++ = '.'; /* Seperator */
513 strcpy(query,"ip6.arpa"); /* Suffix the string */
519 /* Return the next id which is ready, and the result attached to it */
520 DNSResult DNS::GetResult()
522 /* Fetch dns query response and decide where it belongs */
525 unsigned char buffer[sizeof(DNSHeader)];
527 socklen_t x = sizeof(from);
528 const char* ipaddr_from = "";
529 unsigned short int port_from = 0;
531 int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
534 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
536 /* Did we get the whole header? */
539 /* Nope - something screwed up. */
540 ServerInstance->Log(DEBUG,"Whole header not read!");
541 return std::make_pair(-1,"");
544 /* Check wether the reply came from a different DNS
545 * server to the one we sent it to, or the source-port
547 * A user could in theory still spoof dns packets anyway
548 * but this is less trivial than just sending garbage
549 * to the client, which is possible without this check.
551 * -- Thanks jilles for pointing this one out.
554 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
555 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
557 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
558 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
561 /* We cant perform this security check if you're using 4in6.
562 * Tough luck to you, choose one or't other!
566 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
568 ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
569 return std::make_pair(-1,"");
573 /* Put the read header info into a header class */
574 DNS::FillHeader(&header,buffer,length - 12);
576 /* Get the id of this request.
577 * Its a 16 bit value stored in two char's,
578 * so we use logic shifts to create the value.
580 unsigned long this_id = header.id[1] + (header.id[0] << 8);
582 /* Do we have a pending request matching this id? */
583 requestlist_iter n_iter = requests.find(this_id);
584 if (n_iter == requests.end())
586 /* Somehow we got a DNS response for a request we never made... */
587 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
588 return std::make_pair(-1,"");
592 /* Remove the query from the list of pending queries */
593 req = (DNSRequest*)n_iter->second;
594 requests.erase(n_iter);
597 /* Inform the DNSRequest class that it has a result to be read.
598 * When its finished it will return a DNSInfo which is a pair of
599 * unsigned char* resource record data, and an error message.
601 DNSInfo data = req->ResultIsReady(header, length);
602 std::string resultstr;
604 /* Check if we got a result, if we didnt, its an error */
605 if (data.first == NULL)
608 * Mask the ID with the value of ERROR_MASK, so that
609 * the dns_deal_with_classes() function knows that its
610 * an error response and needs to be treated uniquely.
611 * Put the error message in the second field.
614 return std::make_pair(this_id | ERROR_MASK, data.second);
620 /* Forward lookups come back as binary data. We must format them into ascii */
624 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
625 resultstr = formatted;
630 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
631 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
632 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
633 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
634 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
635 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
636 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
637 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
638 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
639 char* c = strstr(formatted,":0:");
642 memmove(c+1,c+2,strlen(c+2) + 1);
644 while (memcmp(c,"0:",2) == 0)
645 memmove(c,c+2,strlen(c+2) + 1);
646 if (memcmp(c,"0",2) == 0)
648 if (memcmp(formatted,"0::",3) == 0)
649 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
651 resultstr = formatted;
653 /* Special case. Sending ::1 around between servers
654 * and to clients is dangerous, because the : on the
655 * start makes the client or server interpret the IP
656 * as the last parameter on the line with a value ":1".
658 if (*formatted == ':')
659 resultstr = "0" + resultstr;
663 case DNS_QUERY_CNAME:
664 /* Identical handling to PTR */
667 /* Reverse lookups just come back as char* */
668 resultstr = std::string((const char*)data.first);
672 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
677 /* Build the reply with the id and hostname/ip in it */
679 return std::make_pair(this_id,resultstr);
683 /* A result is ready, process it */
684 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
692 if (!(header.flags1 & FLAGS_MASK_QR))
693 return std::make_pair((unsigned char*)NULL,"Not a query result");
695 if (header.flags1 & FLAGS_MASK_OPCODE)
696 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
698 if (header.flags2 & FLAGS_MASK_RCODE)
699 return std::make_pair((unsigned char*)NULL,"Domain name not found");
701 if (header.ancount < 1)
702 return std::make_pair((unsigned char*)NULL,"No resource records returned");
704 /* Subtract the length of the header from the length of the packet */
707 while ((unsigned int)q < header.qdcount && i < length)
709 if (header.payload[i] > 63)
716 if (header.payload[i] == 0)
721 else i += header.payload[i] + 1;
725 while ((unsigned)curanswer < header.ancount)
728 while (q == 0 && i < length)
730 if (header.payload[i] > 63)
737 if (header.payload[i] == 0)
742 else i += header.payload[i] + 1; /* skip length and label */
746 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
748 DNS::FillResourceRecord(&rr,&header.payload[i]);
750 if (rr.type != this->type)
756 if (rr.rr_class != this->rr_class)
764 if ((unsigned int)curanswer == header.ancount)
765 return std::make_pair((unsigned char*)NULL,"No valid answers");
767 if (i + rr.rdlength > (unsigned int)length)
768 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
770 if (rr.rdlength > 1023)
771 return std::make_pair((unsigned char*)NULL,"Resource record too large");
775 case DNS_QUERY_CNAME:
776 /* CNAME and PTR have the same processing code */
780 while (q == 0 && i < length && o + 256 < 1023)
782 if (header.payload[i] > 63)
784 memcpy(&ptr,&header.payload[i],2);
785 i = ntohs(ptr) - 0xC000 - 12;
789 if (header.payload[i] == 0)
798 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
799 o += header.payload[i];
800 i += header.payload[i] + 1;
807 memcpy(res,&header.payload[i],rr.rdlength);
808 res[rr.rdlength] = 0;
811 memcpy(res,&header.payload[i],rr.rdlength);
812 res[rr.rdlength] = 0;
815 memcpy(res,&header.payload[i],rr.rdlength);
816 res[rr.rdlength] = 0;
819 return std::make_pair(res,"No error");;
822 /* Close the master socket */
825 shutdown(this->GetFd(), 2);
826 close(this->GetFd());
829 /* High level abstraction of dns used by application at large */
830 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
832 ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
839 this->myid = ServerInstance->Res->GetIP(source.c_str());
843 if (insp_aton(source.c_str(), &binip) > 0)
845 /* Valid ip address */
846 this->myid = ServerInstance->Res->GetName(&binip);
850 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
851 throw ModuleException("Resolver: Bad IP address");
857 querytype = DNS_QUERY_PTR;
858 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
862 querytype = DNS_QUERY_PTR;
863 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
867 this->myid = ServerInstance->Res->GetIP6(source.c_str());
870 case DNS_QUERY_CNAME:
871 this->myid = ServerInstance->Res->GetCName(source.c_str());
878 if (this->myid == -1)
880 ServerInstance->Log(DEBUG,"Resolver::Resolver: Could not get an id!");
881 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
882 throw ModuleException("Resolver: Couldnt get an id to make a request");
883 /* We shouldnt get here really */
887 ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
890 void Resolver::OnError(ResolverError e, const std::string &errormessage)
892 /* Nothing in here */
895 Resolver::~Resolver()
897 /* Nothing here (yet) either */
900 /* Get the request id associated with this class */
901 int Resolver::GetId()
906 /* Process a socket read event */
907 void DNS::HandleEvent(EventType et)
909 ServerInstance->Log(DEBUG,"Marshall reads: %d",this->GetFd());
910 /* Fetch the id and result of the next available packet */
911 DNSResult res = this->GetResult();
912 /* Is there a usable request id? */
915 /* Its an error reply */
916 if (res.first & ERROR_MASK)
918 /* Mask off the error bit */
919 res.first -= ERROR_MASK;
920 /* Marshall the error to the correct class */
921 ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
922 if (Classes[res.first])
924 if (ServerInstance && ServerInstance->stats)
925 ServerInstance->stats->statsDnsBad++;
926 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
927 delete Classes[res.first];
928 Classes[res.first] = NULL;
933 /* It is a non-error result */
934 ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
935 /* Marshall the result to the correct class */
936 if (Classes[res.first])
938 if (ServerInstance && ServerInstance->stats)
939 ServerInstance->stats->statsDnsGood++;
940 Classes[res.first]->OnLookupComplete(res.second);
941 delete Classes[res.first];
942 Classes[res.first] = NULL;
946 if (ServerInstance && ServerInstance->stats)
947 ServerInstance->stats->statsDns++;
951 /* Add a derived Resolver to the working set */
952 bool DNS::AddResolverClass(Resolver* r)
954 /* Check the pointers validity and the id's validity */
955 if ((r) && (r->GetId() > -1))
957 /* Check the slot isnt already occupied -
958 * This should NEVER happen unless we have
959 * a severely broken DNS server somewhere
961 if (!Classes[r->GetId()])
963 /* Set up the pointer to the class */
964 Classes[r->GetId()] = r;
973 /* Pointer or id not valid.
974 * Free the item and return
983 unsigned long DNS::PRNG()
985 unsigned long val = 0;
987 serverstats* s = ServerInstance->stats;
988 gettimeofday(&n,NULL);
989 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
990 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
991 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;