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"
47 extern InspIRCd* ServerInstance;
48 extern ServerConfig* Config;
50 /* Master file descriptor */
51 int DNS::MasterSocket;
53 /* Masks to mask off the responses we get from the DNSRequest methods */
56 ERROR_MASK = 0x10000 /* Result is an error */
59 /* Flags which can be ORed into a request or reply for different meanings */
62 FLAGS_MASK_RD = 0x01, /* Recursive */
64 FLAGS_MASK_AA = 0x04, /* Authoritative */
65 FLAGS_MASK_OPCODE = 0x78,
67 FLAGS_MASK_RCODE = 0x0F, /* Request */
73 /* Represents a dns resource record (rr) */
77 QueryType type; /* Record type */
78 unsigned int rr_class; /* Record class */
79 unsigned long ttl; /* Time to live */
80 unsigned int rdlength; /* Record length */
83 /* Represents a dns request/reply header, and its payload as opaque data.
88 unsigned char id[2]; /* Request id */
89 unsigned int flags1; /* Flags */
90 unsigned int flags2; /* Flags */
92 unsigned int ancount; /* Answer count */
93 unsigned int nscount; /* Nameserver count */
95 unsigned char payload[512]; /* Packet payload */
98 /* Represents a request 'on the wire' with routing information relating to
99 * where to call when we get a result
104 unsigned char id[2]; /* Request id */
105 unsigned char* res; /* Result processing buffer */
106 unsigned int rr_class; /* Request class */
107 QueryType type; /* Request type */
108 insp_inaddr myserver; /* DNS server address*/
110 /* Allocate the processing buffer */
111 DNSRequest(insp_inaddr server)
113 res = new unsigned char[512];
115 memcpy(&myserver, &server, sizeof(insp_inaddr));
118 /* Deallocate the processing buffer */
124 /* Called when a result is ready to be processed which matches this id */
125 DNSInfo ResultIsReady(DNSHeader &h, int length);
127 /* Called when there are requests to be sent out */
128 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
131 /* Fill a ResourceRecord class based on raw data input */
132 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
134 rr->type = (QueryType)((input[0] << 8) + input[1]);
135 rr->rr_class = (input[2] << 8) + input[3];
136 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
137 rr->rdlength = (input[8] << 8) + input[9];
140 /* Fill a DNSHeader class based on raw data input of a given length */
141 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
143 header->id[0] = input[0];
144 header->id[1] = input[1];
145 header->flags1 = input[2];
146 header->flags2 = input[3];
147 header->qdcount = (input[4] << 8) + input[5];
148 header->ancount = (input[6] << 8) + input[7];
149 header->nscount = (input[8] << 8) + input[9];
150 header->arcount = (input[10] << 8) + input[11];
151 memcpy(header->payload,&input[12],length);
154 /* Empty a DNSHeader class out into raw data, ready for transmission */
155 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
157 output[0] = header->id[0];
158 output[1] = header->id[1];
159 output[2] = header->flags1;
160 output[3] = header->flags2;
161 output[4] = header->qdcount >> 8;
162 output[5] = header->qdcount & 0xFF;
163 output[6] = header->ancount >> 8;
164 output[7] = header->ancount & 0xFF;
165 output[8] = header->nscount >> 8;
166 output[9] = header->nscount & 0xFF;
167 output[10] = header->arcount >> 8;
168 output[11] = header->arcount & 0xFF;
169 memcpy(&output[12],header->payload,length);
172 /* Send requests we have previously built down the UDP socket */
173 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
176 unsigned char payload[sizeof(DNSHeader)];
181 DNS::EmptyHeader(payload,header,length);
183 memset(&addr,0,sizeof(addr));
185 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
186 addr.sin6_family = AF_FAMILY;
187 addr.sin6_port = htons(DNS::QUERY_PORT);
189 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
190 addr.sin_family = AF_FAMILY;
191 addr.sin_port = htons(DNS::QUERY_PORT);
193 if (sendto(DNS::GetMasterSocket(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
195 log(DEBUG,"Error in sendto! (%s)",strerror(errno));
202 /* Add a query with a predefined header, and allocate an ID for it. */
203 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
205 /* Are there already the max number of requests on the go? */
206 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
210 id = this->PRNG() & DNS::MAX_REQUEST_ID;
212 /* If this id is already 'in flight', pick another. */
213 while (requests.find(id) != requests.end())
214 id = this->PRNG() & DNS::MAX_REQUEST_ID;
216 DNSRequest* req = new DNSRequest(this->myserver);
218 header->id[0] = req->id[0] = id >> 8;
219 header->id[1] = req->id[1] = id & 0xFF;
220 header->flags1 = FLAGS_MASK_RD;
227 /* At this point we already know the id doesnt exist,
228 * so there needs to be no second check for the ::end()
232 /* According to the C++ spec, new never returns NULL. */
236 int DNS::GetMasterSocket()
241 /* Initialise the DNS UDP socket so that we can send requests */
246 /* Clear the Resolver class table */
247 memset(Classes,0,sizeof(Classes));
249 /* Set the id of the next request to 0
253 /* Clear the namesever address */
254 memset(&myserver,0,sizeof(insp_inaddr));
256 /* Convert the nameserver address into an insp_inaddr */
257 if (insp_aton(Config->DNSServer,&addr) > 0)
259 memcpy(&myserver,&addr,sizeof(insp_inaddr));
260 if ((strstr(Config->DNSServer,"::ffff:") == (char*)&Config->DNSServer) || (strstr(Config->DNSServer,"::FFFF:") == (char*)&Config->DNSServer))
262 /* These dont come back looking like they did when they went in.
263 * We're forced to turn some checks off.
264 * If anyone knows how to fix this, let me know. --Brain
266 log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
267 log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
268 log(DEFAULT," to a true IPv6 environment.");
269 this->ip6munge = true;
271 log(DEBUG,"Added nameserver '%s'",Config->DNSServer);
275 log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",Config->DNSServer);
278 /* Initialize mastersocket */
279 MasterSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
280 if (MasterSocket != -1)
282 /* Did it succeed? */
283 if (fcntl(MasterSocket, F_SETFL, O_NONBLOCK) != 0)
285 /* Couldn't make the socket nonblocking */
286 shutdown(MasterSocket,2);
293 log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
295 /* Have we got a socket and is it nonblocking? */
296 if (MasterSocket != -1)
300 memset(&addr,0,sizeof(addr));
301 addr.sin6_family = AF_FAMILY;
303 addr.sin6_addr = in6addr_any;
306 memset(&addr,0,sizeof(addr));
307 addr.sin_family = AF_FAMILY;
309 addr.sin_addr.s_addr = INADDR_ANY;
312 if (bind(MasterSocket,(sockaddr *)&addr,sizeof(addr)) != 0)
315 log(DEBUG,"Cant bind DNS::MasterSocket");
316 shutdown(MasterSocket,2);
321 if (MasterSocket >= 0)
323 log(DEBUG,"Add master socket %d",MasterSocket);
324 /* Hook the descriptor into the socket engine */
325 if (ServerInstance && ServerInstance->SE)
326 ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS);
331 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
332 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
334 short payloadpos = 0;
335 const char* tempchr, *tempchr2 = name;
336 unsigned short length;
338 /* split name up into labels, create query */
339 while ((tempchr = strchr(tempchr2,'.')) != NULL)
341 length = tempchr - tempchr2;
342 if (payloadpos + length + 1 > 507)
344 payload[payloadpos++] = length;
345 memcpy(&payload[payloadpos],tempchr2,length);
346 payloadpos += length;
347 tempchr2 = &tempchr[1];
349 length = strlen(tempchr2);
352 if (payloadpos + length + 2 > 507)
354 payload[payloadpos++] = length;
355 memcpy(&payload[payloadpos],tempchr2,length);
356 payloadpos += length;
357 payload[payloadpos++] = 0;
359 if (payloadpos > 508)
362 memcpy(&payload[payloadpos],&length,2);
363 length = htons(rr_class);
364 memcpy(&payload[payloadpos + 2],&length,2);
365 return payloadpos + 4;
368 /* Start lookup of an hostname to an IP address */
369 int DNS::GetIP(const char *name)
375 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
378 DNSRequest* req = this->AddQuery(&h, id);
380 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
386 /* Start lookup of an hostname to an IPv6 address */
387 int DNS::GetIP6(const char *name)
393 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
396 DNSRequest* req = this->AddQuery(&h, id);
398 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
404 /* Start lookup of a cname to another name */
405 int DNS::GetCName(const char *alias)
411 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
414 DNSRequest* req = this->AddQuery(&h, id);
416 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
422 /* Start lookup of an IP address to a hostname */
423 int DNS::GetName(const insp_inaddr *ip)
431 DNS::MakeIP6Int(query, (in6_addr*)ip);
433 unsigned char* c = (unsigned char*)&ip->s_addr;
435 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
438 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
441 DNSRequest* req = this->AddQuery(&h, id);
443 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
449 /* Start lookup of an IP address to a hostname */
450 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
456 #ifdef SUPPORT_IP6LINKS
457 if (fp == PROTOCOL_IPV6)
460 if (inet_pton(AF_INET6, ip, &i) > 0)
462 DNS::MakeIP6Int(query, &i);
465 /* Invalid IP address */
472 if (inet_aton(ip, &i))
474 unsigned char* c = (unsigned char*)&i.s_addr;
475 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
478 /* Invalid IP address */
482 log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
484 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
487 DNSRequest* req = this->AddQuery(&h, id);
489 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
495 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
497 #ifdef SUPPORT_IP6LINKS
498 const char* hex = "0123456789abcdef";
499 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
503 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
506 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
507 *query++ = '.'; /* Seperator */
509 strcpy(query,"ip6.arpa"); /* Suffix the string */
515 /* Return the next id which is ready, and the result attached to it */
516 DNSResult DNS::GetResult()
518 /* Fetch dns query response and decide where it belongs */
521 unsigned char buffer[sizeof(DNSHeader)];
523 socklen_t x = sizeof(from);
524 const char* ipaddr_from = "";
525 unsigned short int port_from = 0;
527 int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
530 log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
532 /* Did we get the whole header? */
535 /* Nope - something screwed up. */
536 log(DEBUG,"Whole header not read!");
537 return std::make_pair(-1,"");
540 /* Check wether the reply came from a different DNS
541 * server to the one we sent it to, or the source-port
543 * A user could in theory still spoof dns packets anyway
544 * but this is less trivial than just sending garbage
545 * to the client, which is possible without this check.
547 * -- Thanks jilles for pointing this one out.
550 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
551 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
553 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
554 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
557 /* We cant perform this security check if you're using 4in6.
558 * Tough luck to you, choose one or't other!
562 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, Config->DNSServer)))
564 log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, Config->DNSServer);
565 return std::make_pair(-1,"");
569 /* Put the read header info into a header class */
570 DNS::FillHeader(&header,buffer,length - 12);
572 /* Get the id of this request.
573 * Its a 16 bit value stored in two char's,
574 * so we use logic shifts to create the value.
576 unsigned long this_id = header.id[1] + (header.id[0] << 8);
578 /* Do we have a pending request matching this id? */
579 requestlist_iter n_iter = requests.find(this_id);
580 if (n_iter == requests.end())
582 /* Somehow we got a DNS response for a request we never made... */
583 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
584 return std::make_pair(-1,"");
588 /* Remove the query from the list of pending queries */
589 req = (DNSRequest*)n_iter->second;
590 requests.erase(n_iter);
593 /* Inform the DNSRequest class that it has a result to be read.
594 * When its finished it will return a DNSInfo which is a pair of
595 * unsigned char* resource record data, and an error message.
597 DNSInfo data = req->ResultIsReady(header, length);
598 std::string resultstr;
600 /* Check if we got a result, if we didnt, its an error */
601 if (data.first == NULL)
604 * Mask the ID with the value of ERROR_MASK, so that
605 * the dns_deal_with_classes() function knows that its
606 * an error response and needs to be treated uniquely.
607 * Put the error message in the second field.
610 return std::make_pair(this_id | ERROR_MASK, data.second);
616 /* Forward lookups come back as binary data. We must format them into ascii */
620 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
621 resultstr = formatted;
626 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
627 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
628 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
629 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
630 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
631 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
632 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
633 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
634 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
635 char* c = strstr(formatted,":0:");
638 memmove(c+1,c+2,strlen(c+2) + 1);
640 while (memcmp(c,"0:",2) == 0)
641 memmove(c,c+2,strlen(c+2) + 1);
642 if (memcmp(c,"0",2) == 0)
644 if (memcmp(formatted,"0::",3) == 0)
645 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
647 resultstr = formatted;
649 /* Special case. Sending ::1 around between servers
650 * and to clients is dangerous, because the : on the
651 * start makes the client or server interpret the IP
652 * as the last parameter on the line with a value ":1".
654 if (*formatted == ':')
655 resultstr = "0" + resultstr;
659 case DNS_QUERY_CNAME:
660 /* Identical handling to PTR */
663 /* Reverse lookups just come back as char* */
664 resultstr = std::string((const char*)data.first);
668 log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
673 /* Build the reply with the id and hostname/ip in it */
675 return std::make_pair(this_id,resultstr);
679 /* A result is ready, process it */
680 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
688 if (!(header.flags1 & FLAGS_MASK_QR))
689 return std::make_pair((unsigned char*)NULL,"Not a query result");
691 if (header.flags1 & FLAGS_MASK_OPCODE)
692 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
694 if (header.flags2 & FLAGS_MASK_RCODE)
695 return std::make_pair((unsigned char*)NULL,"Domain name not found");
697 if (header.ancount < 1)
698 return std::make_pair((unsigned char*)NULL,"No resource records returned");
700 /* Subtract the length of the header from the length of the packet */
703 while ((unsigned int)q < header.qdcount && i < length)
705 if (header.payload[i] > 63)
712 if (header.payload[i] == 0)
717 else i += header.payload[i] + 1;
721 while ((unsigned)curanswer < header.ancount)
724 while (q == 0 && i < length)
726 if (header.payload[i] > 63)
733 if (header.payload[i] == 0)
738 else i += header.payload[i] + 1; /* skip length and label */
742 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
744 DNS::FillResourceRecord(&rr,&header.payload[i]);
746 if (rr.type != this->type)
752 if (rr.rr_class != this->rr_class)
760 if ((unsigned int)curanswer == header.ancount)
761 return std::make_pair((unsigned char*)NULL,"No valid answers");
763 if (i + rr.rdlength > (unsigned int)length)
764 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
766 if (rr.rdlength > 1023)
767 return std::make_pair((unsigned char*)NULL,"Resource record too large");
771 case DNS_QUERY_CNAME:
772 /* CNAME and PTR have the same processing code */
776 while (q == 0 && i < length && o + 256 < 1023)
778 if (header.payload[i] > 63)
780 memcpy(&ptr,&header.payload[i],2);
781 i = ntohs(ptr) - 0xC000 - 12;
785 if (header.payload[i] == 0)
794 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
795 o += header.payload[i];
796 i += header.payload[i] + 1;
803 memcpy(res,&header.payload[i],rr.rdlength);
804 res[rr.rdlength] = 0;
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 return std::make_pair(res,"No error");;
818 /* Close the master socket */
821 shutdown(MasterSocket, 2);
825 /* High level abstraction of dns used by application at large */
826 Resolver::Resolver(const std::string &source, QueryType qt) : input(source), querytype(qt)
833 this->myid = ServerInstance->Res->GetIP(source.c_str());
837 if (insp_aton(source.c_str(), &binip) > 0)
839 /* Valid ip address */
840 this->myid = ServerInstance->Res->GetName(&binip);
844 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
845 throw ModuleException("Resolver: Bad IP address");
851 querytype = DNS_QUERY_PTR;
852 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
856 querytype = DNS_QUERY_PTR;
857 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
861 this->myid = ServerInstance->Res->GetIP6(source.c_str());
864 case DNS_QUERY_CNAME:
865 this->myid = ServerInstance->Res->GetCName(source.c_str());
872 if (this->myid == -1)
874 log(DEBUG,"Resolver::Resolver: Could not get an id!");
875 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
876 throw ModuleException("Resolver: Couldnt get an id to make a request");
877 /* We shouldnt get here really */
881 log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
884 void Resolver::OnError(ResolverError e, const std::string &errormessage)
886 /* Nothing in here */
889 Resolver::~Resolver()
891 /* Nothing here (yet) either */
894 /* Get the request id associated with this class */
895 int Resolver::GetId()
900 /* Process a socket read event */
901 void DNS::MarshallReads(int fd)
903 log(DEBUG,"Marshall reads: %d %d",fd,GetMasterSocket());
904 /* We are only intrested in our single fd */
905 if (fd == GetMasterSocket())
907 /* Fetch the id and result of the next available packet */
908 DNSResult res = this->GetResult();
909 /* Is there a usable request id? */
912 /* Its an error reply */
913 if (res.first & ERROR_MASK)
915 /* Mask off the error bit */
916 res.first -= ERROR_MASK;
918 /* Marshall the error to the correct class */
919 log(DEBUG,"Error available, id=%d",res.first);
920 if (Classes[res.first])
922 if (ServerInstance && ServerInstance->stats)
923 ServerInstance->stats->statsDnsBad++;
924 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
925 delete Classes[res.first];
926 Classes[res.first] = NULL;
931 /* It is a non-error result */
932 log(DEBUG,"Result available, id=%d",res.first);
933 /* Marshall the result to the correct class */
934 if (Classes[res.first])
936 if (ServerInstance && ServerInstance->stats)
937 ServerInstance->stats->statsDnsGood++;
938 Classes[res.first]->OnLookupComplete(res.second);
939 delete Classes[res.first];
940 Classes[res.first] = NULL;
944 if (ServerInstance && ServerInstance->stats)
945 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;