1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 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 /* Allocate the processing buffer */
151 DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns)
153 res = new unsigned char[512];
156 RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid);
157 ServerInstance->Timers->AddTimer(RT); /* The timer manager frees this */
160 /* Deallocate the processing buffer */
161 DNSRequest::~DNSRequest()
166 /** Fill a ResourceRecord class based on raw data input */
167 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
169 rr->type = (QueryType)((input[0] << 8) + input[1]);
170 rr->rr_class = (input[2] << 8) + input[3];
171 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
172 rr->rdlength = (input[8] << 8) + input[9];
175 /** Fill a DNSHeader class based on raw data input of a given length */
176 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
178 header->id[0] = input[0];
179 header->id[1] = input[1];
180 header->flags1 = input[2];
181 header->flags2 = input[3];
182 header->qdcount = (input[4] << 8) + input[5];
183 header->ancount = (input[6] << 8) + input[7];
184 header->nscount = (input[8] << 8) + input[9];
185 header->arcount = (input[10] << 8) + input[11];
186 memcpy(header->payload,&input[12],length);
189 /** Empty a DNSHeader class out into raw data, ready for transmission */
190 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
192 output[0] = header->id[0];
193 output[1] = header->id[1];
194 output[2] = header->flags1;
195 output[3] = header->flags2;
196 output[4] = header->qdcount >> 8;
197 output[5] = header->qdcount & 0xFF;
198 output[6] = header->ancount >> 8;
199 output[7] = header->ancount & 0xFF;
200 output[8] = header->nscount >> 8;
201 output[9] = header->nscount & 0xFF;
202 output[10] = header->arcount >> 8;
203 output[11] = header->arcount & 0xFF;
204 memcpy(&output[12],header->payload,length);
207 /** Send requests we have previously built down the UDP socket */
208 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
210 ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests");
212 unsigned char payload[sizeof(DNSHeader)];
217 DNS::EmptyHeader(payload,header,length);
219 if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12)
222 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK");
226 /** Add a query with a predefined header, and allocate an ID for it. */
227 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
229 /* Is the DNS connection down? */
230 if (this->GetFd() == -1)
234 id = this->PRNG() & DNS::MAX_REQUEST_ID;
236 /* If this id is already 'in flight', pick another. */
238 id = this->PRNG() & DNS::MAX_REQUEST_ID;
240 DNSRequest* req = new DNSRequest(this, id, original);
242 header->id[0] = req->id[0] = id >> 8;
243 header->id[1] = req->id[1] = id & 0xFF;
244 header->flags1 = FLAGS_MASK_RD;
251 /* At this point we already know the id doesnt exist,
252 * so there needs to be no second check for the ::end()
256 /* According to the C++ spec, new never returns NULL. */
260 int DNS::ClearCache()
262 /* This ensures the buckets are reset to sane levels */
263 int rv = this->cache->size();
265 this->cache = new dnscache();
269 int DNS::PruneCache()
272 dnscache* newcache = new dnscache();
273 for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
274 /* Dont include expired items (theres no point) */
275 if (i->second.CalcTTLRemaining())
276 newcache->insert(*i);
281 this->cache = newcache;
289 if (this->GetFd() > -1)
291 if (ServerInstance && ServerInstance->SE)
292 ServerInstance->SE->DelFd(this);
293 ServerInstance->SE->Shutdown(this, 2);
294 ServerInstance->SE->Close(this);
297 /* Rehash the cache */
302 /* Create initial dns cache */
303 this->cache = new dnscache();
306 irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver);
308 /* Initialize mastersocket */
309 int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
312 /* Have we got a socket and is it nonblocking? */
313 if (this->GetFd() != -1)
315 ServerInstance->SE->SetReuse(s);
316 ServerInstance->SE->NonBlocking(s);
317 /* Bind the port - port 0 INADDR_ANY */
318 if (!ServerInstance->BindSocket(this->GetFd(), portpass, "", false))
321 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Error binding dns socket");
322 ServerInstance->SE->Shutdown(this, 2);
323 ServerInstance->SE->Close(this);
327 if (this->GetFd() >= 0)
329 /* Hook the descriptor into the socket engine */
330 if (ServerInstance && ServerInstance->SE)
332 if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
334 ServerInstance->Logs->Log("RESOLVER",DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
335 ServerInstance->SE->Shutdown(this, 2);
336 ServerInstance->SE->Close(this);
344 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Error creating dns socket");
348 /** Initialise the DNS UDP socket so that we can send requests */
351 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
352 /* Clear the Resolver class table */
353 memset(Classes,0,sizeof(Classes));
355 /* Clear the requests class table */
356 memset(requests,0,sizeof(requests));
358 /* Set the id of the next request to 0
362 /* DNS::Rehash() sets this to a valid ptr
366 /* Again, DNS::Rehash() sets this to a
371 /* Actually read the settings
375 this->PruneTimer = new CacheTimer(this);
377 ServerInstance->Timers->AddTimer(this->PruneTimer);
380 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
381 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
383 short payloadpos = 0;
384 const char* tempchr, *tempchr2 = name;
385 unsigned short length;
387 /* split name up into labels, create query */
388 while ((tempchr = strchr(tempchr2,'.')) != NULL)
390 length = tempchr - tempchr2;
391 if (payloadpos + length + 1 > 507)
393 payload[payloadpos++] = length;
394 memcpy(&payload[payloadpos],tempchr2,length);
395 payloadpos += length;
396 tempchr2 = &tempchr[1];
398 length = strlen(tempchr2);
401 if (payloadpos + length + 2 > 507)
403 payload[payloadpos++] = length;
404 memcpy(&payload[payloadpos],tempchr2,length);
405 payloadpos += length;
406 payload[payloadpos++] = 0;
408 if (payloadpos > 508)
411 memcpy(&payload[payloadpos],&length,2);
412 length = htons(rr_class);
413 memcpy(&payload[payloadpos + 2],&length,2);
414 return payloadpos + 4;
417 /** Start lookup of an hostname to an IP address */
418 int DNS::GetIP(const char *name)
424 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
427 DNSRequest* req = this->AddQuery(&h, id, name);
429 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
435 /** Start lookup of an hostname to an IPv6 address */
436 int DNS::GetIP6(const char *name)
442 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
445 DNSRequest* req = this->AddQuery(&h, id, name);
447 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
453 /** Start lookup of a cname to another name */
454 int DNS::GetCName(const char *alias)
460 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
463 DNSRequest* req = this->AddQuery(&h, id, alias);
465 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
471 /** Start lookup of an IP address to a hostname */
472 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
479 if (fp == PROTOCOL_IPV6)
482 if (inet_pton(AF_INET6, ip, &i) > 0)
484 DNS::MakeIP6Int(query, &i);
487 /* Invalid IP address */
493 if (inet_aton(ip, &i))
495 unsigned char* c = (unsigned char*)&i.s_addr;
496 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
499 /* Invalid IP address */
503 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
506 DNSRequest* req = this->AddQuery(&h, id, ip);
508 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
514 /** Build an ipv6 reverse domain from an in6_addr
516 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
518 const char* hex = "0123456789abcdef";
519 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
523 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
526 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
527 *query++ = '.'; /* Seperator */
529 strcpy(query,"ip6.arpa"); /* Suffix the string */
532 /** Return the next id which is ready, and the result attached to it */
533 DNSResult DNS::GetResult()
535 /* Fetch dns query response and decide where it belongs */
538 unsigned char buffer[sizeof(DNSHeader)];
539 irc::sockets::sockaddrs from;
540 memset(&from, 0, sizeof(from));
541 socklen_t x = sizeof(from);
543 int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
545 /* Did we get the whole header? */
548 /* Nope - something screwed up. */
549 return DNSResult(-1,"",0,"");
552 /* Check wether the reply came from a different DNS
553 * server to the one we sent it to, or the source-port
555 * A user could in theory still spoof dns packets anyway
556 * but this is less trivial than just sending garbage
557 * to the server, which is possible without this check.
559 * -- Thanks jilles for pointing this one out.
561 if (memcmp(&from, &myserver, sizeof(irc::sockets::sockaddrs)))
563 return DNSResult(-1,"",0,"");
566 /* Put the read header info into a header class */
567 DNS::FillHeader(&header,buffer,length - 12);
569 /* Get the id of this request.
570 * Its a 16 bit value stored in two char's,
571 * so we use logic shifts to create the value.
573 unsigned long this_id = header.id[1] + (header.id[0] << 8);
575 /* Do we have a pending request matching this id? */
576 if (!requests[this_id])
578 /* Somehow we got a DNS response for a request we never made... */
579 return DNSResult(-1,"",0,"");
583 /* Remove the query from the list of pending queries */
584 req = requests[this_id];
585 requests[this_id] = NULL;
588 /* Inform the DNSRequest class that it has a result to be read.
589 * When its finished it will return a DNSInfo which is a pair of
590 * unsigned char* resource record data, and an error message.
592 DNSInfo data = req->ResultIsReady(header, length);
593 std::string resultstr;
595 /* Check if we got a result, if we didnt, its an error */
596 if (data.first == NULL)
599 * Mask the ID with the value of ERROR_MASK, so that
600 * the dns_deal_with_classes() function knows that its
601 * an error response and needs to be treated uniquely.
602 * Put the error message in the second field.
604 std::string ro = req->orig;
606 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
610 unsigned long ttl = req->ttl;
613 /* Forward lookups come back as binary data. We must format them into ascii */
617 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
618 resultstr = formatted;
623 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
624 char* c = strstr(formatted,":0:");
627 memmove(c+1,c+2,strlen(c+2) + 1);
629 while (memcmp(c,"0:",2) == 0)
630 memmove(c,c+2,strlen(c+2) + 1);
631 if (memcmp(c,"0",2) == 0)
633 if (memcmp(formatted,"0::",3) == 0)
634 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
636 resultstr = formatted;
638 /* Special case. Sending ::1 around between servers
639 * and to clients is dangerous, because the : on the
640 * start makes the client or server interpret the IP
641 * as the last parameter on the line with a value ":1".
643 if (*formatted == ':')
644 resultstr.insert(0, "0");
648 case DNS_QUERY_CNAME:
649 /* Identical handling to PTR */
652 /* Reverse lookups just come back as char* */
653 resultstr = std::string((const char*)data.first);
660 /* Build the reply with the id and hostname/ip in it */
661 std::string ro = req->orig;
663 return DNSResult(this_id,resultstr,ttl,ro);
667 /** A result is ready, process it */
668 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
676 /* This is just to keep _FORTIFY_SOURCE happy */
677 rr.type = DNS_QUERY_NONE;
679 rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
680 rr.rr_class = 0; /* Same for VC++ */
682 if (!(header.flags1 & FLAGS_MASK_QR))
683 return std::make_pair((unsigned char*)NULL,"Not a query result");
685 if (header.flags1 & FLAGS_MASK_OPCODE)
686 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
688 if (header.flags2 & FLAGS_MASK_RCODE)
689 return std::make_pair((unsigned char*)NULL,"Domain name not found");
691 if (header.ancount < 1)
692 return std::make_pair((unsigned char*)NULL,"No resource records returned");
694 /* Subtract the length of the header from the length of the packet */
697 while ((unsigned int)q < header.qdcount && i < length)
699 if (header.payload[i] > 63)
706 if (header.payload[i] == 0)
711 else i += header.payload[i] + 1;
715 while ((unsigned)curanswer < header.ancount)
718 while (q == 0 && i < length)
720 if (header.payload[i] > 63)
727 if (header.payload[i] == 0)
732 else i += header.payload[i] + 1; /* skip length and label */
736 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
738 /* XXX: We actually initialise 'rr' here including its ttl field */
739 DNS::FillResourceRecord(&rr,&header.payload[i]);
742 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);
743 if (rr.type != this->type)
749 if (rr.rr_class != this->rr_class)
757 if ((unsigned int)curanswer == header.ancount)
758 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
760 if (i + rr.rdlength > (unsigned int)length)
761 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
763 if (rr.rdlength > 1023)
764 return std::make_pair((unsigned char*)NULL,"Resource record too large");
770 case DNS_QUERY_CNAME:
771 /* CNAME and PTR have the same processing code */
775 while (q == 0 && i < length && o + 256 < 1023)
777 if (header.payload[i] > 63)
779 memcpy(&ptr,&header.payload[i],2);
780 i = ntohs(ptr) - 0xC000 - 12;
784 if (header.payload[i] == 0)
793 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
794 o += header.payload[i];
795 i += header.payload[i] + 1;
802 memcpy(res,&header.payload[i],rr.rdlength);
803 res[rr.rdlength] = 0;
806 memcpy(res,&header.payload[i],rr.rdlength);
807 res[rr.rdlength] = 0;
810 memcpy(res,&header.payload[i],rr.rdlength);
811 res[rr.rdlength] = 0;
814 return std::make_pair(res,"No error");
817 /** Close the master socket */
820 ServerInstance->SE->Shutdown(this, 2);
821 ServerInstance->SE->Close(this);
822 ServerInstance->Timers->DelTimer(this->PruneTimer);
827 CachedQuery* DNS::GetCache(const std::string &source)
829 dnscache::iterator x = cache->find(source.c_str());
830 if (x != cache->end())
836 void DNS::DelCache(const std::string &source)
838 cache->erase(source.c_str());
841 void Resolver::TriggerCachedResult()
844 OnLookupComplete(CQ->data, time_left, true);
847 /** High level abstraction of dns used by application at large */
848 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
850 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
853 CQ = ServerInstance->Res->GetCache(source);
856 time_left = CQ->CalcTTLRemaining();
859 ServerInstance->Res->DelCache(source);
871 this->myid = ServerInstance->Res->GetIP(source.c_str());
875 querytype = DNS_QUERY_PTR;
876 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
880 querytype = DNS_QUERY_PTR;
881 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
885 this->myid = ServerInstance->Res->GetIP6(source.c_str());
888 case DNS_QUERY_CNAME:
889 this->myid = ServerInstance->Res->GetCName(source.c_str());
896 if (this->myid == -1)
898 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
899 throw ModuleException("Resolver: Couldnt get an id to make a request");
900 /* We shouldnt get here really */
905 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
909 /** Called when an error occurs */
910 void Resolver::OnError(ResolverError, const std::string&)
912 /* Nothing in here */
915 /** Destroy a resolver */
916 Resolver::~Resolver()
918 /* Nothing here (yet) either */
921 /** Get the request id associated with this class */
922 int Resolver::GetId()
927 Module* Resolver::GetCreator()
929 return this->Creator;
932 /** Process a socket read event */
933 void DNS::HandleEvent(EventType, int)
935 /* Fetch the id and result of the next available packet */
936 DNSResult res(0,"",0,"");
938 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
940 res = this->GetResult();
942 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
944 /* Is there a usable request id? */
947 /* Its an error reply */
948 if (res.id & ERROR_MASK)
950 /* Mask off the error bit */
951 res.id -= ERROR_MASK;
952 /* Marshall the error to the correct class */
955 if (ServerInstance && ServerInstance->stats)
956 ServerInstance->stats->statsDnsBad++;
957 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
958 delete Classes[res.id];
959 Classes[res.id] = NULL;
965 /* It is a non-error result, marshall the result to the correct class */
968 if (ServerInstance && ServerInstance->stats)
969 ServerInstance->stats->statsDnsGood++;
971 if (!this->GetCache(res.original.c_str()))
972 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
974 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
975 delete Classes[res.id];
976 Classes[res.id] = NULL;
980 if (ServerInstance && ServerInstance->stats)
981 ServerInstance->stats->statsDns++;
985 /** Add a derived Resolver to the working set */
986 bool DNS::AddResolverClass(Resolver* r)
988 ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
989 /* Check the pointers validity and the id's validity */
990 if ((r) && (r->GetId() > -1))
992 /* Check the slot isnt already occupied -
993 * This should NEVER happen unless we have
994 * a severely broken DNS server somewhere
996 if (!Classes[r->GetId()])
998 /* Set up the pointer to the class */
999 Classes[r->GetId()] = r;
1008 /* Pointer or id not valid.
1009 * Free the item and return
1018 void DNS::CleanResolvers(Module* module)
1020 for (int i = 0; i < MAX_REQUEST_ID; i++)
1024 if (Classes[i]->GetCreator() == module)
1026 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");
1034 /** Generate pseudo-random number */
1035 unsigned long DNS::PRNG()
1037 unsigned long val = 0;
1039 serverstats* s = ServerInstance->stats;
1040 gettimeofday(&n,NULL);
1041 val = (n.tv_usec ^ (getpid() ^ geteuid()) ^ ((this->currid++)) ^ s->statsAccept) + n.tv_sec;
1042 val = val + (s->statsCollisions ^ s->statsDnsGood) - s->statsDnsBad;
1043 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - ServerInstance->ports.size();