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>
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)
202 /* Add a query with a predefined header, and allocate an ID for it. */
203 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
205 /* Is the DNS connection down? */
206 if (MasterSocket == -1)
209 /* Are there already the max number of requests on the go? */
210 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
214 id = this->PRNG() & DNS::MAX_REQUEST_ID;
216 /* If this id is already 'in flight', pick another. */
217 while (requests.find(id) != requests.end())
218 id = this->PRNG() & DNS::MAX_REQUEST_ID;
220 DNSRequest* req = new DNSRequest(this->myserver);
222 header->id[0] = req->id[0] = id >> 8;
223 header->id[1] = req->id[1] = id & 0xFF;
224 header->flags1 = FLAGS_MASK_RD;
231 /* At this point we already know the id doesnt exist,
232 * so there needs to be no second check for the ::end()
236 /* According to the C++ spec, new never returns NULL. */
240 int DNS::GetMasterSocket()
245 /* Initialise the DNS UDP socket so that we can send requests */
246 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
248 ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
252 /* Clear the Resolver class table */
253 memset(Classes,0,sizeof(Classes));
255 /* Set the id of the next request to 0
259 /* Clear the namesever address */
260 memset(&myserver,0,sizeof(insp_inaddr));
262 /* Convert the nameserver address into an insp_inaddr */
263 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
265 memcpy(&myserver,&addr,sizeof(insp_inaddr));
266 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
268 /* These dont come back looking like they did when they went in.
269 * We're forced to turn some checks off.
270 * If anyone knows how to fix this, let me know. --Brain
272 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
273 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
274 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
275 this->ip6munge = true;
277 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
281 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
284 /* Initialize mastersocket */
285 MasterSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
286 if (MasterSocket != -1)
288 /* Did it succeed? */
289 if (fcntl(MasterSocket, F_SETFL, O_NONBLOCK) != 0)
291 /* Couldn't make the socket nonblocking */
292 shutdown(MasterSocket,2);
299 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
301 /* Have we got a socket and is it nonblocking? */
302 if (MasterSocket != -1)
306 memset(&addr,0,sizeof(addr));
307 addr.sin6_family = AF_FAMILY;
309 addr.sin6_addr = in6addr_any;
312 memset(&addr,0,sizeof(addr));
313 addr.sin_family = AF_FAMILY;
315 addr.sin_addr.s_addr = INADDR_ANY;
318 if (bind(MasterSocket,(sockaddr *)&addr,sizeof(addr)) != 0)
321 ServerInstance->Log(DEBUG,"Cant bind DNS::MasterSocket");
322 shutdown(MasterSocket,2);
327 if (MasterSocket >= 0)
329 ServerInstance->Log(DEBUG,"Add master socket %d",MasterSocket);
330 /* Hook the descriptor into the socket engine */
331 if (ServerInstance && ServerInstance->SE)
333 if (!ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS))
335 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
336 shutdown(MasterSocket,2);
345 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
346 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
348 short payloadpos = 0;
349 const char* tempchr, *tempchr2 = name;
350 unsigned short length;
352 /* split name up into labels, create query */
353 while ((tempchr = strchr(tempchr2,'.')) != NULL)
355 length = tempchr - tempchr2;
356 if (payloadpos + length + 1 > 507)
358 payload[payloadpos++] = length;
359 memcpy(&payload[payloadpos],tempchr2,length);
360 payloadpos += length;
361 tempchr2 = &tempchr[1];
363 length = strlen(tempchr2);
366 if (payloadpos + length + 2 > 507)
368 payload[payloadpos++] = length;
369 memcpy(&payload[payloadpos],tempchr2,length);
370 payloadpos += length;
371 payload[payloadpos++] = 0;
373 if (payloadpos > 508)
376 memcpy(&payload[payloadpos],&length,2);
377 length = htons(rr_class);
378 memcpy(&payload[payloadpos + 2],&length,2);
379 return payloadpos + 4;
382 /* Start lookup of an hostname to an IP address */
383 int DNS::GetIP(const char *name)
389 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
392 DNSRequest* req = this->AddQuery(&h, id);
394 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
400 /* Start lookup of an hostname to an IPv6 address */
401 int DNS::GetIP6(const char *name)
407 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
410 DNSRequest* req = this->AddQuery(&h, id);
412 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
418 /* Start lookup of a cname to another name */
419 int DNS::GetCName(const char *alias)
425 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
428 DNSRequest* req = this->AddQuery(&h, id);
430 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
436 /* Start lookup of an IP address to a hostname */
437 int DNS::GetName(const insp_inaddr *ip)
445 DNS::MakeIP6Int(query, (in6_addr*)ip);
447 unsigned char* c = (unsigned char*)&ip->s_addr;
449 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
452 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
455 DNSRequest* req = this->AddQuery(&h, id);
457 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
463 /* Start lookup of an IP address to a hostname */
464 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
470 #ifdef SUPPORT_IP6LINKS
471 if (fp == PROTOCOL_IPV6)
474 if (inet_pton(AF_INET6, ip, &i) > 0)
476 DNS::MakeIP6Int(query, &i);
479 /* Invalid IP address */
486 if (inet_aton(ip, &i))
488 unsigned char* c = (unsigned char*)&i.s_addr;
489 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
492 /* Invalid IP address */
496 ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
498 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
501 DNSRequest* req = this->AddQuery(&h, id);
503 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
509 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
511 #ifdef SUPPORT_IP6LINKS
512 const char* hex = "0123456789abcdef";
513 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
517 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
520 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
521 *query++ = '.'; /* Seperator */
523 strcpy(query,"ip6.arpa"); /* Suffix the string */
529 /* Return the next id which is ready, and the result attached to it */
530 DNSResult DNS::GetResult()
532 /* Fetch dns query response and decide where it belongs */
535 unsigned char buffer[sizeof(DNSHeader)];
537 socklen_t x = sizeof(from);
538 const char* ipaddr_from = "";
539 unsigned short int port_from = 0;
541 int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
544 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
546 /* Did we get the whole header? */
549 /* Nope - something screwed up. */
550 ServerInstance->Log(DEBUG,"Whole header not read!");
551 return std::make_pair(-1,"");
554 /* Check wether the reply came from a different DNS
555 * server to the one we sent it to, or the source-port
557 * A user could in theory still spoof dns packets anyway
558 * but this is less trivial than just sending garbage
559 * to the client, which is possible without this check.
561 * -- Thanks jilles for pointing this one out.
564 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
565 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
567 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
568 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
571 /* We cant perform this security check if you're using 4in6.
572 * Tough luck to you, choose one or't other!
576 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
578 ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
579 return std::make_pair(-1,"");
583 /* Put the read header info into a header class */
584 DNS::FillHeader(&header,buffer,length - 12);
586 /* Get the id of this request.
587 * Its a 16 bit value stored in two char's,
588 * so we use logic shifts to create the value.
590 unsigned long this_id = header.id[1] + (header.id[0] << 8);
592 /* Do we have a pending request matching this id? */
593 requestlist_iter n_iter = requests.find(this_id);
594 if (n_iter == requests.end())
596 /* Somehow we got a DNS response for a request we never made... */
597 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
598 return std::make_pair(-1,"");
602 /* Remove the query from the list of pending queries */
603 req = (DNSRequest*)n_iter->second;
604 requests.erase(n_iter);
607 /* Inform the DNSRequest class that it has a result to be read.
608 * When its finished it will return a DNSInfo which is a pair of
609 * unsigned char* resource record data, and an error message.
611 DNSInfo data = req->ResultIsReady(header, length);
612 std::string resultstr;
614 /* Check if we got a result, if we didnt, its an error */
615 if (data.first == NULL)
618 * Mask the ID with the value of ERROR_MASK, so that
619 * the dns_deal_with_classes() function knows that its
620 * an error response and needs to be treated uniquely.
621 * Put the error message in the second field.
624 return std::make_pair(this_id | ERROR_MASK, data.second);
630 /* Forward lookups come back as binary data. We must format them into ascii */
634 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
635 resultstr = formatted;
640 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
641 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
642 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
643 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
644 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
645 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
646 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
647 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
648 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
649 char* c = strstr(formatted,":0:");
652 memmove(c+1,c+2,strlen(c+2) + 1);
654 while (memcmp(c,"0:",2) == 0)
655 memmove(c,c+2,strlen(c+2) + 1);
656 if (memcmp(c,"0",2) == 0)
658 if (memcmp(formatted,"0::",3) == 0)
659 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
661 resultstr = formatted;
663 /* Special case. Sending ::1 around between servers
664 * and to clients is dangerous, because the : on the
665 * start makes the client or server interpret the IP
666 * as the last parameter on the line with a value ":1".
668 if (*formatted == ':')
669 resultstr = "0" + resultstr;
673 case DNS_QUERY_CNAME:
674 /* Identical handling to PTR */
677 /* Reverse lookups just come back as char* */
678 resultstr = std::string((const char*)data.first);
682 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
687 /* Build the reply with the id and hostname/ip in it */
689 return std::make_pair(this_id,resultstr);
693 /* A result is ready, process it */
694 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
702 if (!(header.flags1 & FLAGS_MASK_QR))
703 return std::make_pair((unsigned char*)NULL,"Not a query result");
705 if (header.flags1 & FLAGS_MASK_OPCODE)
706 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
708 if (header.flags2 & FLAGS_MASK_RCODE)
709 return std::make_pair((unsigned char*)NULL,"Domain name not found");
711 if (header.ancount < 1)
712 return std::make_pair((unsigned char*)NULL,"No resource records returned");
714 /* Subtract the length of the header from the length of the packet */
717 while ((unsigned int)q < header.qdcount && i < length)
719 if (header.payload[i] > 63)
726 if (header.payload[i] == 0)
731 else i += header.payload[i] + 1;
735 while ((unsigned)curanswer < header.ancount)
738 while (q == 0 && i < length)
740 if (header.payload[i] > 63)
747 if (header.payload[i] == 0)
752 else i += header.payload[i] + 1; /* skip length and label */
756 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
758 DNS::FillResourceRecord(&rr,&header.payload[i]);
760 if (rr.type != this->type)
766 if (rr.rr_class != this->rr_class)
774 if ((unsigned int)curanswer == header.ancount)
775 return std::make_pair((unsigned char*)NULL,"No valid answers");
777 if (i + rr.rdlength > (unsigned int)length)
778 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
780 if (rr.rdlength > 1023)
781 return std::make_pair((unsigned char*)NULL,"Resource record too large");
785 case DNS_QUERY_CNAME:
786 /* CNAME and PTR have the same processing code */
790 while (q == 0 && i < length && o + 256 < 1023)
792 if (header.payload[i] > 63)
794 memcpy(&ptr,&header.payload[i],2);
795 i = ntohs(ptr) - 0xC000 - 12;
799 if (header.payload[i] == 0)
808 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
809 o += header.payload[i];
810 i += header.payload[i] + 1;
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 memcpy(res,&header.payload[i],rr.rdlength);
826 res[rr.rdlength] = 0;
829 return std::make_pair(res,"No error");;
832 /* Close the master socket */
835 shutdown(MasterSocket, 2);
839 /* High level abstraction of dns used by application at large */
840 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
842 ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
849 this->myid = ServerInstance->Res->GetIP(source.c_str());
853 if (insp_aton(source.c_str(), &binip) > 0)
855 /* Valid ip address */
856 this->myid = ServerInstance->Res->GetName(&binip);
860 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
861 throw ModuleException("Resolver: Bad IP address");
867 querytype = DNS_QUERY_PTR;
868 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
872 querytype = DNS_QUERY_PTR;
873 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
877 this->myid = ServerInstance->Res->GetIP6(source.c_str());
880 case DNS_QUERY_CNAME:
881 this->myid = ServerInstance->Res->GetCName(source.c_str());
888 if (this->myid == -1)
890 ServerInstance->Log(DEBUG,"Resolver::Resolver: Could not get an id!");
891 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
892 throw ModuleException("Resolver: Couldnt get an id to make a request");
893 /* We shouldnt get here really */
897 ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
900 void Resolver::OnError(ResolverError e, const std::string &errormessage)
902 /* Nothing in here */
905 Resolver::~Resolver()
907 /* Nothing here (yet) either */
910 /* Get the request id associated with this class */
911 int Resolver::GetId()
916 /* Process a socket read event */
917 void DNS::MarshallReads(int fd)
919 ServerInstance->Log(DEBUG,"Marshall reads: %d %d",fd,GetMasterSocket());
920 /* We are only intrested in our single fd */
921 if (fd == GetMasterSocket())
923 /* Fetch the id and result of the next available packet */
924 DNSResult res = this->GetResult();
925 /* Is there a usable request id? */
928 /* Its an error reply */
929 if (res.first & ERROR_MASK)
931 /* Mask off the error bit */
932 res.first -= ERROR_MASK;
934 /* Marshall the error to the correct class */
935 ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
936 if (Classes[res.first])
938 if (ServerInstance && ServerInstance->stats)
939 ServerInstance->stats->statsDnsBad++;
940 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
941 delete Classes[res.first];
942 Classes[res.first] = NULL;
947 /* It is a non-error result */
948 ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
949 /* Marshall the result to the correct class */
950 if (Classes[res.first])
952 if (ServerInstance && ServerInstance->stats)
953 ServerInstance->stats->statsDnsGood++;
954 Classes[res.first]->OnLookupComplete(res.second);
955 delete Classes[res.first];
956 Classes[res.first] = NULL;
960 if (ServerInstance && ServerInstance->stats)
961 ServerInstance->stats->statsDns++;
967 /* Add a derived Resolver to the working set */
968 bool DNS::AddResolverClass(Resolver* r)
970 /* Check the pointers validity and the id's validity */
971 if ((r) && (r->GetId() > -1))
973 /* Check the slot isnt already occupied -
974 * This should NEVER happen unless we have
975 * a severely broken DNS server somewhere
977 if (!Classes[r->GetId()])
979 /* Set up the pointer to the class */
980 Classes[r->GetId()] = r;
989 /* Pointer or id not valid.
990 * Free the item and return
999 unsigned long DNS::PRNG()
1001 unsigned long val = 0;
1003 serverstats* s = ServerInstance->stats;
1004 gettimeofday(&n,NULL);
1005 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1006 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1007 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;