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 = irc::sockets::OpenTCPSocket(ServerInstance->Config->DNSServer, SOCK_DGRAM);
311 ServerInstance->SE->NonBlocking(this->GetFd());
313 /* Have we got a socket and is it nonblocking? */
314 if (this->GetFd() != -1)
316 /* Bind the port - port 0 INADDR_ANY */
317 if (!ServerInstance->BindSocket(this->GetFd(), portpass, "", false))
320 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Error binding dns socket");
321 ServerInstance->SE->Shutdown(this, 2);
322 ServerInstance->SE->Close(this);
326 if (this->GetFd() >= 0)
328 /* Hook the descriptor into the socket engine */
329 if (ServerInstance && ServerInstance->SE)
331 if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
333 ServerInstance->Logs->Log("RESOLVER",DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
334 ServerInstance->SE->Shutdown(this, 2);
335 ServerInstance->SE->Close(this);
343 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Error creating dns socket");
347 /** Initialise the DNS UDP socket so that we can send requests */
350 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
351 /* Clear the Resolver class table */
352 memset(Classes,0,sizeof(Classes));
354 /* Clear the requests class table */
355 memset(requests,0,sizeof(requests));
357 /* Set the id of the next request to 0
361 /* DNS::Rehash() sets this to a valid ptr
365 /* Again, DNS::Rehash() sets this to a
370 /* Actually read the settings
374 this->PruneTimer = new CacheTimer(this);
376 ServerInstance->Timers->AddTimer(this->PruneTimer);
379 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
380 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
382 short payloadpos = 0;
383 const char* tempchr, *tempchr2 = name;
384 unsigned short length;
386 /* split name up into labels, create query */
387 while ((tempchr = strchr(tempchr2,'.')) != NULL)
389 length = tempchr - tempchr2;
390 if (payloadpos + length + 1 > 507)
392 payload[payloadpos++] = length;
393 memcpy(&payload[payloadpos],tempchr2,length);
394 payloadpos += length;
395 tempchr2 = &tempchr[1];
397 length = strlen(tempchr2);
400 if (payloadpos + length + 2 > 507)
402 payload[payloadpos++] = length;
403 memcpy(&payload[payloadpos],tempchr2,length);
404 payloadpos += length;
405 payload[payloadpos++] = 0;
407 if (payloadpos > 508)
410 memcpy(&payload[payloadpos],&length,2);
411 length = htons(rr_class);
412 memcpy(&payload[payloadpos + 2],&length,2);
413 return payloadpos + 4;
416 /** Start lookup of an hostname to an IP address */
417 int DNS::GetIP(const char *name)
423 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
426 DNSRequest* req = this->AddQuery(&h, id, name);
428 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
434 /** Start lookup of an hostname to an IPv6 address */
435 int DNS::GetIP6(const char *name)
441 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
444 DNSRequest* req = this->AddQuery(&h, id, name);
446 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
452 /** Start lookup of a cname to another name */
453 int DNS::GetCName(const char *alias)
459 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
462 DNSRequest* req = this->AddQuery(&h, id, alias);
464 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
470 /** Start lookup of an IP address to a hostname */
471 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
478 if (fp == PROTOCOL_IPV6)
481 if (inet_pton(AF_INET6, ip, &i) > 0)
483 DNS::MakeIP6Int(query, &i);
486 /* Invalid IP address */
492 if (inet_aton(ip, &i))
494 unsigned char* c = (unsigned char*)&i.s_addr;
495 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
498 /* Invalid IP address */
502 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
505 DNSRequest* req = this->AddQuery(&h, id, ip);
507 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
513 /** Build an ipv6 reverse domain from an in6_addr
515 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
517 const char* hex = "0123456789abcdef";
518 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
522 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
525 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
526 *query++ = '.'; /* Seperator */
528 strcpy(query,"ip6.arpa"); /* Suffix the string */
531 /** Return the next id which is ready, and the result attached to it */
532 DNSResult DNS::GetResult()
534 /* Fetch dns query response and decide where it belongs */
537 unsigned char buffer[sizeof(DNSHeader)];
538 irc::sockets::sockaddrs from;
539 memset(&from, 0, sizeof(from));
540 socklen_t x = sizeof(from);
542 int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
544 /* Did we get the whole header? */
547 /* Nope - something screwed up. */
548 return DNSResult(-1,"",0,"");
551 /* Check wether the reply came from a different DNS
552 * server to the one we sent it to, or the source-port
554 * A user could in theory still spoof dns packets anyway
555 * but this is less trivial than just sending garbage
556 * to the server, which is possible without this check.
558 * -- Thanks jilles for pointing this one out.
560 if (memcmp(&from, &myserver, sizeof(irc::sockets::sockaddrs)))
562 return DNSResult(-1,"",0,"");
565 /* Put the read header info into a header class */
566 DNS::FillHeader(&header,buffer,length - 12);
568 /* Get the id of this request.
569 * Its a 16 bit value stored in two char's,
570 * so we use logic shifts to create the value.
572 unsigned long this_id = header.id[1] + (header.id[0] << 8);
574 /* Do we have a pending request matching this id? */
575 if (!requests[this_id])
577 /* Somehow we got a DNS response for a request we never made... */
578 return DNSResult(-1,"",0,"");
582 /* Remove the query from the list of pending queries */
583 req = requests[this_id];
584 requests[this_id] = NULL;
587 /* Inform the DNSRequest class that it has a result to be read.
588 * When its finished it will return a DNSInfo which is a pair of
589 * unsigned char* resource record data, and an error message.
591 DNSInfo data = req->ResultIsReady(header, length);
592 std::string resultstr;
594 /* Check if we got a result, if we didnt, its an error */
595 if (data.first == NULL)
598 * Mask the ID with the value of ERROR_MASK, so that
599 * the dns_deal_with_classes() function knows that its
600 * an error response and needs to be treated uniquely.
601 * Put the error message in the second field.
603 std::string ro = req->orig;
605 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
609 unsigned long ttl = req->ttl;
612 /* Forward lookups come back as binary data. We must format them into ascii */
616 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
617 resultstr = formatted;
622 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
623 char* c = strstr(formatted,":0:");
626 memmove(c+1,c+2,strlen(c+2) + 1);
628 while (memcmp(c,"0:",2) == 0)
629 memmove(c,c+2,strlen(c+2) + 1);
630 if (memcmp(c,"0",2) == 0)
632 if (memcmp(formatted,"0::",3) == 0)
633 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
635 resultstr = formatted;
637 /* Special case. Sending ::1 around between servers
638 * and to clients is dangerous, because the : on the
639 * start makes the client or server interpret the IP
640 * as the last parameter on the line with a value ":1".
642 if (*formatted == ':')
643 resultstr.insert(0, "0");
647 case DNS_QUERY_CNAME:
648 /* Identical handling to PTR */
651 /* Reverse lookups just come back as char* */
652 resultstr = std::string((const char*)data.first);
659 /* Build the reply with the id and hostname/ip in it */
660 std::string ro = req->orig;
662 return DNSResult(this_id,resultstr,ttl,ro);
666 /** A result is ready, process it */
667 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
675 /* This is just to keep _FORTIFY_SOURCE happy */
676 rr.type = DNS_QUERY_NONE;
678 rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
679 rr.rr_class = 0; /* Same for VC++ */
681 if (!(header.flags1 & FLAGS_MASK_QR))
682 return std::make_pair((unsigned char*)NULL,"Not a query result");
684 if (header.flags1 & FLAGS_MASK_OPCODE)
685 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
687 if (header.flags2 & FLAGS_MASK_RCODE)
688 return std::make_pair((unsigned char*)NULL,"Domain name not found");
690 if (header.ancount < 1)
691 return std::make_pair((unsigned char*)NULL,"No resource records returned");
693 /* Subtract the length of the header from the length of the packet */
696 while ((unsigned int)q < header.qdcount && i < length)
698 if (header.payload[i] > 63)
705 if (header.payload[i] == 0)
710 else i += header.payload[i] + 1;
714 while ((unsigned)curanswer < header.ancount)
717 while (q == 0 && i < length)
719 if (header.payload[i] > 63)
726 if (header.payload[i] == 0)
731 else i += header.payload[i] + 1; /* skip length and label */
735 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
737 /* XXX: We actually initialise 'rr' here including its ttl field */
738 DNS::FillResourceRecord(&rr,&header.payload[i]);
741 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);
742 if (rr.type != this->type)
748 if (rr.rr_class != this->rr_class)
756 if ((unsigned int)curanswer == header.ancount)
757 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
759 if (i + rr.rdlength > (unsigned int)length)
760 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
762 if (rr.rdlength > 1023)
763 return std::make_pair((unsigned char*)NULL,"Resource record too large");
769 case DNS_QUERY_CNAME:
770 /* CNAME and PTR have the same processing code */
774 while (q == 0 && i < length && o + 256 < 1023)
776 if (header.payload[i] > 63)
778 memcpy(&ptr,&header.payload[i],2);
779 i = ntohs(ptr) - 0xC000 - 12;
783 if (header.payload[i] == 0)
792 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
793 o += header.payload[i];
794 i += header.payload[i] + 1;
801 memcpy(res,&header.payload[i],rr.rdlength);
802 res[rr.rdlength] = 0;
805 memcpy(res,&header.payload[i],rr.rdlength);
806 res[rr.rdlength] = 0;
809 memcpy(res,&header.payload[i],rr.rdlength);
810 res[rr.rdlength] = 0;
813 return std::make_pair(res,"No error");
816 /** Close the master socket */
819 ServerInstance->SE->Shutdown(this, 2);
820 ServerInstance->SE->Close(this);
821 ServerInstance->Timers->DelTimer(this->PruneTimer);
826 CachedQuery* DNS::GetCache(const std::string &source)
828 dnscache::iterator x = cache->find(source.c_str());
829 if (x != cache->end())
835 void DNS::DelCache(const std::string &source)
837 cache->erase(source.c_str());
840 void Resolver::TriggerCachedResult()
843 OnLookupComplete(CQ->data, time_left, true);
846 /** High level abstraction of dns used by application at large */
847 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
849 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
852 CQ = ServerInstance->Res->GetCache(source);
855 time_left = CQ->CalcTTLRemaining();
858 ServerInstance->Res->DelCache(source);
870 this->myid = ServerInstance->Res->GetIP(source.c_str());
874 querytype = DNS_QUERY_PTR;
875 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
879 querytype = DNS_QUERY_PTR;
880 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
884 this->myid = ServerInstance->Res->GetIP6(source.c_str());
887 case DNS_QUERY_CNAME:
888 this->myid = ServerInstance->Res->GetCName(source.c_str());
895 if (this->myid == -1)
897 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
898 throw ModuleException("Resolver: Couldnt get an id to make a request");
899 /* We shouldnt get here really */
904 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
908 /** Called when an error occurs */
909 void Resolver::OnError(ResolverError, const std::string&)
911 /* Nothing in here */
914 /** Destroy a resolver */
915 Resolver::~Resolver()
917 /* Nothing here (yet) either */
920 /** Get the request id associated with this class */
921 int Resolver::GetId()
926 Module* Resolver::GetCreator()
928 return this->Creator;
931 /** Process a socket read event */
932 void DNS::HandleEvent(EventType, int)
934 /* Fetch the id and result of the next available packet */
935 DNSResult res(0,"",0,"");
937 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
939 res = this->GetResult();
941 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
943 /* Is there a usable request id? */
946 /* Its an error reply */
947 if (res.id & ERROR_MASK)
949 /* Mask off the error bit */
950 res.id -= ERROR_MASK;
951 /* Marshall the error to the correct class */
954 if (ServerInstance && ServerInstance->stats)
955 ServerInstance->stats->statsDnsBad++;
956 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
957 delete Classes[res.id];
958 Classes[res.id] = NULL;
964 /* It is a non-error result, marshall the result to the correct class */
967 if (ServerInstance && ServerInstance->stats)
968 ServerInstance->stats->statsDnsGood++;
970 if (!this->GetCache(res.original.c_str()))
971 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
973 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
974 delete Classes[res.id];
975 Classes[res.id] = NULL;
979 if (ServerInstance && ServerInstance->stats)
980 ServerInstance->stats->statsDns++;
984 /** Add a derived Resolver to the working set */
985 bool DNS::AddResolverClass(Resolver* r)
987 ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
988 /* Check the pointers validity and the id's validity */
989 if ((r) && (r->GetId() > -1))
991 /* Check the slot isnt already occupied -
992 * This should NEVER happen unless we have
993 * a severely broken DNS server somewhere
995 if (!Classes[r->GetId()])
997 /* Set up the pointer to the class */
998 Classes[r->GetId()] = r;
1007 /* Pointer or id not valid.
1008 * Free the item and return
1017 void DNS::CleanResolvers(Module* module)
1019 for (int i = 0; i < MAX_REQUEST_ID; i++)
1023 if (Classes[i]->GetCreator() == module)
1025 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");
1033 /** Generate pseudo-random number */
1034 unsigned long DNS::PRNG()
1036 unsigned long val = 0;
1038 serverstats* s = ServerInstance->stats;
1039 gettimeofday(&n,NULL);
1040 val = (n.tv_usec ^ (getpid() ^ geteuid()) ^ ((this->currid++)) ^ s->statsAccept) + n.tv_sec;
1041 val = val + (s->statsCollisions ^ s->statsDnsGood) - s->statsDnsBad;
1042 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - ServerInstance->ports.size();