1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2010 InspIRCd Development Team
6 * See: http://wiki.inspircd.org/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
17 dns.cpp - Nonblocking DNS functions.
18 Very very loosely based on the firedns library,
19 Copyright (C) 2002 Ian Gulliver. This file is no
20 longer anything like firedns, there are many major
21 differences between this code and the original.
22 Please do not assume that firedns works like this,
23 looks like this, walks like this or tastes like this.
27 #include <sys/types.h>
28 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
33 #include "inspircd_win32wrapper.h"
37 #include "socketengine.h"
38 #include "configreader.h"
41 /** Masks to mask off the responses we get from the DNSRequest methods
45 ERROR_MASK = 0x10000 /* Result is an error */
48 /** Flags which can be ORed into a request or reply for different meanings
52 FLAGS_MASK_RD = 0x01, /* Recursive */
54 FLAGS_MASK_AA = 0x04, /* Authoritative */
55 FLAGS_MASK_OPCODE = 0x78,
57 FLAGS_MASK_RCODE = 0x0F, /* Request */
63 /** Represents a dns resource record (rr)
67 QueryType type; /* Record type */
68 unsigned int rr_class; /* Record class */
69 unsigned long ttl; /* Time to live */
70 unsigned int rdlength; /* Record length */
73 /** Represents a dns request/reply header, and its payload as opaque data.
78 unsigned char id[2]; /* Request id */
79 unsigned int flags1; /* Flags */
80 unsigned int flags2; /* Flags */
82 unsigned int ancount; /* Answer count */
83 unsigned int nscount; /* Nameserver count */
85 unsigned char payload[512]; /* Packet payload */
91 unsigned char id[2]; /* Request id */
92 unsigned char* res; /* Result processing buffer */
93 unsigned int rr_class; /* Request class */
94 QueryType type; /* Request type */
95 DNS* dnsobj; /* DNS caller (where we get our FD from) */
96 unsigned long ttl; /* Time to live */
97 std::string orig; /* Original requested name/ip */
99 DNSRequest(DNS* dns, int id, const std::string &original);
101 DNSInfo ResultIsReady(DNSHeader &h, int length);
102 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
105 class CacheTimer : public Timer
110 CacheTimer(DNS* thisdns)
111 : Timer(3600, ServerInstance->Time(), true), dns(thisdns) { }
113 virtual void Tick(time_t)
119 class RequestTimeout : public Timer
124 RequestTimeout(unsigned long n, DNSRequest* watching, int id) : Timer(n, ServerInstance->Time()), watch(watching), watchid(id)
129 if (ServerInstance->Res)
135 if (ServerInstance->Res->requests[watchid] == watch)
137 /* Still exists, whack it */
138 if (ServerInstance->Res->Classes[watchid])
140 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
141 delete ServerInstance->Res->Classes[watchid];
142 ServerInstance->Res->Classes[watchid] = NULL;
144 ServerInstance->Res->requests[watchid] = NULL;
150 CachedQuery::CachedQuery(const std::string &res, unsigned int ttl) : data(res)
152 expires = ServerInstance->Time() + ttl;
155 int CachedQuery::CalcTTLRemaining()
157 int n = expires - ServerInstance->Time();
158 return (n < 0 ? 0 : n);
161 /* Allocate the processing buffer */
162 DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns)
164 res = new unsigned char[512];
167 RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid);
168 ServerInstance->Timers->AddTimer(RT); /* The timer manager frees this */
171 /* Deallocate the processing buffer */
172 DNSRequest::~DNSRequest()
177 /** Fill a ResourceRecord class based on raw data input */
178 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
180 rr->type = (QueryType)((input[0] << 8) + input[1]);
181 rr->rr_class = (input[2] << 8) + input[3];
182 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
183 rr->rdlength = (input[8] << 8) + input[9];
186 /** Fill a DNSHeader class based on raw data input of a given length */
187 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
189 header->id[0] = input[0];
190 header->id[1] = input[1];
191 header->flags1 = input[2];
192 header->flags2 = input[3];
193 header->qdcount = (input[4] << 8) + input[5];
194 header->ancount = (input[6] << 8) + input[7];
195 header->nscount = (input[8] << 8) + input[9];
196 header->arcount = (input[10] << 8) + input[11];
197 memcpy(header->payload,&input[12],length);
200 /** Empty a DNSHeader class out into raw data, ready for transmission */
201 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
203 output[0] = header->id[0];
204 output[1] = header->id[1];
205 output[2] = header->flags1;
206 output[3] = header->flags2;
207 output[4] = header->qdcount >> 8;
208 output[5] = header->qdcount & 0xFF;
209 output[6] = header->ancount >> 8;
210 output[7] = header->ancount & 0xFF;
211 output[8] = header->nscount >> 8;
212 output[9] = header->nscount & 0xFF;
213 output[10] = header->arcount >> 8;
214 output[11] = header->arcount & 0xFF;
215 memcpy(&output[12],header->payload,length);
218 /** Send requests we have previously built down the UDP socket */
219 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
221 ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests");
223 unsigned char payload[sizeof(DNSHeader)];
228 DNS::EmptyHeader(payload,header,length);
230 if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12)
233 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK");
237 /** Add a query with a predefined header, and allocate an ID for it. */
238 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
240 /* Is the DNS connection down? */
241 if (this->GetFd() == -1)
245 id = this->PRNG() & DNS::MAX_REQUEST_ID;
247 /* If this id is already 'in flight', pick another. */
249 id = this->PRNG() & DNS::MAX_REQUEST_ID;
251 DNSRequest* req = new DNSRequest(this, id, original);
253 header->id[0] = req->id[0] = id >> 8;
254 header->id[1] = req->id[1] = id & 0xFF;
255 header->flags1 = FLAGS_MASK_RD;
262 /* At this point we already know the id doesnt exist,
263 * so there needs to be no second check for the ::end()
267 /* According to the C++ spec, new never returns NULL. */
271 int DNS::ClearCache()
273 /* This ensures the buckets are reset to sane levels */
274 int rv = this->cache->size();
276 this->cache = new dnscache();
280 int DNS::PruneCache()
283 dnscache* newcache = new dnscache();
284 for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
285 /* Dont include expired items (theres no point) */
286 if (i->second.CalcTTLRemaining())
287 newcache->insert(*i);
292 this->cache = newcache;
300 if (this->GetFd() > -1)
302 if (ServerInstance && ServerInstance->SE)
303 ServerInstance->SE->DelFd(this);
304 ServerInstance->SE->Shutdown(this, 2);
305 ServerInstance->SE->Close(this);
308 /* Rehash the cache */
313 /* Create initial dns cache */
314 this->cache = new dnscache();
317 irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver);
319 /* Initialize mastersocket */
320 int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
323 /* Have we got a socket and is it nonblocking? */
324 if (this->GetFd() != -1)
326 ServerInstance->SE->SetReuse(s);
327 ServerInstance->SE->NonBlocking(s);
328 /* Bind the port - port 0 INADDR_ANY */
329 if (!ServerInstance->BindSocket(this->GetFd(), portpass, "", false))
332 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Error binding dns socket");
333 ServerInstance->SE->Shutdown(this, 2);
334 ServerInstance->SE->Close(this);
338 if (this->GetFd() >= 0)
340 /* Hook the descriptor into the socket engine */
341 if (ServerInstance && ServerInstance->SE)
343 if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
345 ServerInstance->Logs->Log("RESOLVER",DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
346 ServerInstance->SE->Shutdown(this, 2);
347 ServerInstance->SE->Close(this);
355 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Error creating dns socket");
359 /** Initialise the DNS UDP socket so that we can send requests */
362 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
363 /* Clear the Resolver class table */
364 memset(Classes,0,sizeof(Classes));
366 /* Clear the requests class table */
367 memset(requests,0,sizeof(requests));
369 /* Set the id of the next request to 0
373 /* DNS::Rehash() sets this to a valid ptr
377 /* Again, DNS::Rehash() sets this to a
382 /* Actually read the settings
386 this->PruneTimer = new CacheTimer(this);
388 ServerInstance->Timers->AddTimer(this->PruneTimer);
391 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
392 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
394 short payloadpos = 0;
395 const char* tempchr, *tempchr2 = name;
396 unsigned short length;
398 /* split name up into labels, create query */
399 while ((tempchr = strchr(tempchr2,'.')) != NULL)
401 length = tempchr - tempchr2;
402 if (payloadpos + length + 1 > 507)
404 payload[payloadpos++] = length;
405 memcpy(&payload[payloadpos],tempchr2,length);
406 payloadpos += length;
407 tempchr2 = &tempchr[1];
409 length = strlen(tempchr2);
412 if (payloadpos + length + 2 > 507)
414 payload[payloadpos++] = length;
415 memcpy(&payload[payloadpos],tempchr2,length);
416 payloadpos += length;
417 payload[payloadpos++] = 0;
419 if (payloadpos > 508)
422 memcpy(&payload[payloadpos],&length,2);
423 length = htons(rr_class);
424 memcpy(&payload[payloadpos + 2],&length,2);
425 return payloadpos + 4;
428 /** Start lookup of an hostname to an IP address */
429 int DNS::GetIP(const char *name)
435 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
438 DNSRequest* req = this->AddQuery(&h, id, name);
440 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
446 /** Start lookup of an hostname to an IPv6 address */
447 int DNS::GetIP6(const char *name)
453 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
456 DNSRequest* req = this->AddQuery(&h, id, name);
458 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
464 /** Start lookup of a cname to another name */
465 int DNS::GetCName(const char *alias)
471 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
474 DNSRequest* req = this->AddQuery(&h, id, alias);
476 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
482 /** Start lookup of an IP address to a hostname */
483 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
490 if (fp == PROTOCOL_IPV6)
493 if (inet_pton(AF_INET6, ip, &i) > 0)
495 DNS::MakeIP6Int(query, &i);
498 /* Invalid IP address */
504 if (inet_aton(ip, &i))
506 unsigned char* c = (unsigned char*)&i.s_addr;
507 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
510 /* Invalid IP address */
514 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
517 DNSRequest* req = this->AddQuery(&h, id, ip);
519 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
525 /** Build an ipv6 reverse domain from an in6_addr
527 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
529 const char* hex = "0123456789abcdef";
530 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
534 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
537 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
538 *query++ = '.'; /* Seperator */
540 strcpy(query,"ip6.arpa"); /* Suffix the string */
543 /** Return the next id which is ready, and the result attached to it */
544 DNSResult DNS::GetResult()
546 /* Fetch dns query response and decide where it belongs */
549 unsigned char buffer[sizeof(DNSHeader)];
550 irc::sockets::sockaddrs from;
551 memset(&from, 0, sizeof(from));
552 socklen_t x = sizeof(from);
554 int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
556 /* Did we get the whole header? */
559 /* Nope - something screwed up. */
560 return DNSResult(-1,"",0,"");
563 /* Check wether the reply came from a different DNS
564 * server to the one we sent it to, or the source-port
566 * A user could in theory still spoof dns packets anyway
567 * but this is less trivial than just sending garbage
568 * to the server, which is possible without this check.
570 * -- Thanks jilles for pointing this one out.
572 if (memcmp(&from, &myserver, sizeof(irc::sockets::sockaddrs)))
574 return DNSResult(-1,"",0,"");
577 /* Put the read header info into a header class */
578 DNS::FillHeader(&header,buffer,length - 12);
580 /* Get the id of this request.
581 * Its a 16 bit value stored in two char's,
582 * so we use logic shifts to create the value.
584 unsigned long this_id = header.id[1] + (header.id[0] << 8);
586 /* Do we have a pending request matching this id? */
587 if (!requests[this_id])
589 /* Somehow we got a DNS response for a request we never made... */
590 return DNSResult(-1,"",0,"");
594 /* Remove the query from the list of pending queries */
595 req = requests[this_id];
596 requests[this_id] = NULL;
599 /* Inform the DNSRequest class that it has a result to be read.
600 * When its finished it will return a DNSInfo which is a pair of
601 * unsigned char* resource record data, and an error message.
603 DNSInfo data = req->ResultIsReady(header, length);
604 std::string resultstr;
606 /* Check if we got a result, if we didnt, its an error */
607 if (data.first == NULL)
610 * Mask the ID with the value of ERROR_MASK, so that
611 * the dns_deal_with_classes() function knows that its
612 * an error response and needs to be treated uniquely.
613 * Put the error message in the second field.
615 std::string ro = req->orig;
617 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
621 unsigned long ttl = req->ttl;
624 /* Forward lookups come back as binary data. We must format them into ascii */
628 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
629 resultstr = formatted;
634 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
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.insert(0, "0");
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);
671 /* Build the reply with the id and hostname/ip in it */
672 std::string ro = req->orig;
674 return DNSResult(this_id,resultstr,ttl,ro);
678 /** A result is ready, process it */
679 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
687 /* This is just to keep _FORTIFY_SOURCE happy */
688 rr.type = DNS_QUERY_NONE;
690 rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
691 rr.rr_class = 0; /* Same for VC++ */
693 if (!(header.flags1 & FLAGS_MASK_QR))
694 return std::make_pair((unsigned char*)NULL,"Not a query result");
696 if (header.flags1 & FLAGS_MASK_OPCODE)
697 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
699 if (header.flags2 & FLAGS_MASK_RCODE)
700 return std::make_pair((unsigned char*)NULL,"Domain name not found");
702 if (header.ancount < 1)
703 return std::make_pair((unsigned char*)NULL,"No resource records returned");
705 /* Subtract the length of the header from the length of the packet */
708 while ((unsigned int)q < header.qdcount && i < length)
710 if (header.payload[i] > 63)
717 if (header.payload[i] == 0)
722 else i += header.payload[i] + 1;
726 while ((unsigned)curanswer < header.ancount)
729 while (q == 0 && i < length)
731 if (header.payload[i] > 63)
738 if (header.payload[i] == 0)
743 else i += header.payload[i] + 1; /* skip length and label */
747 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
749 /* XXX: We actually initialise 'rr' here including its ttl field */
750 DNS::FillResourceRecord(&rr,&header.payload[i]);
753 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver: rr.type is %d and this.type is %d rr.class %d this.class %d", rr.type, this->type, rr.rr_class, this->rr_class);
754 if (rr.type != this->type)
760 if (rr.rr_class != this->rr_class)
768 if ((unsigned int)curanswer == header.ancount)
769 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
771 if (i + rr.rdlength > (unsigned int)length)
772 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
774 if (rr.rdlength > 1023)
775 return std::make_pair((unsigned char*)NULL,"Resource record too large");
781 case DNS_QUERY_CNAME:
782 /* CNAME and PTR have the same processing code */
786 while (q == 0 && i < length && o + 256 < 1023)
788 if (header.payload[i] > 63)
790 memcpy(&ptr,&header.payload[i],2);
791 i = ntohs(ptr) - 0xC000 - 12;
795 if (header.payload[i] == 0)
804 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
805 o += header.payload[i];
806 i += header.payload[i] + 1;
813 memcpy(res,&header.payload[i],rr.rdlength);
814 res[rr.rdlength] = 0;
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 return std::make_pair(res,"No error");
828 /** Close the master socket */
831 ServerInstance->SE->Shutdown(this, 2);
832 ServerInstance->SE->Close(this);
833 ServerInstance->Timers->DelTimer(this->PruneTimer);
838 CachedQuery* DNS::GetCache(const std::string &source)
840 dnscache::iterator x = cache->find(source.c_str());
841 if (x != cache->end())
847 void DNS::DelCache(const std::string &source)
849 cache->erase(source.c_str());
852 void Resolver::TriggerCachedResult()
855 OnLookupComplete(CQ->data, time_left, true);
858 /** High level abstraction of dns used by application at large */
859 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
861 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
864 CQ = ServerInstance->Res->GetCache(source);
867 time_left = CQ->CalcTTLRemaining();
870 ServerInstance->Res->DelCache(source);
882 this->myid = ServerInstance->Res->GetIP(source.c_str());
886 querytype = DNS_QUERY_PTR;
887 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
891 querytype = DNS_QUERY_PTR;
892 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
896 this->myid = ServerInstance->Res->GetIP6(source.c_str());
899 case DNS_QUERY_CNAME:
900 this->myid = ServerInstance->Res->GetCName(source.c_str());
907 if (this->myid == -1)
909 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
910 throw ModuleException("Resolver: Couldnt get an id to make a request");
911 /* We shouldnt get here really */
916 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
920 /** Called when an error occurs */
921 void Resolver::OnError(ResolverError, const std::string&)
923 /* Nothing in here */
926 /** Destroy a resolver */
927 Resolver::~Resolver()
929 /* Nothing here (yet) either */
932 /** Get the request id associated with this class */
933 int Resolver::GetId()
938 Module* Resolver::GetCreator()
940 return this->Creator;
943 /** Process a socket read event */
944 void DNS::HandleEvent(EventType, int)
946 /* Fetch the id and result of the next available packet */
947 DNSResult res(0,"",0,"");
949 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
951 res = this->GetResult();
953 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
955 /* Is there a usable request id? */
958 /* Its an error reply */
959 if (res.id & ERROR_MASK)
961 /* Mask off the error bit */
962 res.id -= ERROR_MASK;
963 /* Marshall the error to the correct class */
966 if (ServerInstance && ServerInstance->stats)
967 ServerInstance->stats->statsDnsBad++;
968 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
969 delete Classes[res.id];
970 Classes[res.id] = NULL;
976 /* It is a non-error result, marshall the result to the correct class */
979 if (ServerInstance && ServerInstance->stats)
980 ServerInstance->stats->statsDnsGood++;
982 if (!this->GetCache(res.original.c_str()))
983 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
985 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
986 delete Classes[res.id];
987 Classes[res.id] = NULL;
991 if (ServerInstance && ServerInstance->stats)
992 ServerInstance->stats->statsDns++;
996 /** Add a derived Resolver to the working set */
997 bool DNS::AddResolverClass(Resolver* r)
999 ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
1000 /* Check the pointers validity and the id's validity */
1001 if ((r) && (r->GetId() > -1))
1003 /* Check the slot isnt already occupied -
1004 * This should NEVER happen unless we have
1005 * a severely broken DNS server somewhere
1007 if (!Classes[r->GetId()])
1009 /* Set up the pointer to the class */
1010 Classes[r->GetId()] = r;
1019 /* Pointer or id not valid.
1020 * Free the item and return
1029 void DNS::CleanResolvers(Module* module)
1031 for (int i = 0; i < MAX_REQUEST_ID; i++)
1035 if (Classes[i]->GetCreator() == module)
1037 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");
1045 /** Generate pseudo-random number */
1046 unsigned long DNS::PRNG()
1048 unsigned long val = 0;
1049 serverstats* s = ServerInstance->stats;
1050 val = (rand() ^ this->currid++ ^ s->statsAccept) + ServerInstance->Time_ns();
1051 val += (s->statsCollisions ^ s->statsDnsGood) * s->statsDnsBad;
1052 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv);