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)
246 id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
247 } while (requests[id]);
249 DNSRequest* req = new DNSRequest(this, id, original);
251 header->id[0] = req->id[0] = id >> 8;
252 header->id[1] = req->id[1] = id & 0xFF;
253 header->flags1 = FLAGS_MASK_RD;
260 /* At this point we already know the id doesnt exist,
261 * so there needs to be no second check for the ::end()
265 /* According to the C++ spec, new never returns NULL. */
269 int DNS::ClearCache()
271 /* This ensures the buckets are reset to sane levels */
272 int rv = this->cache->size();
274 this->cache = new dnscache();
278 int DNS::PruneCache()
281 dnscache* newcache = new dnscache();
282 for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
283 /* Dont include expired items (theres no point) */
284 if (i->second.CalcTTLRemaining())
285 newcache->insert(*i);
290 this->cache = newcache;
296 if (this->GetFd() > -1)
298 ServerInstance->SE->DelFd(this);
299 ServerInstance->SE->Shutdown(this, 2);
300 ServerInstance->SE->Close(this);
303 /* Rehash the cache */
308 /* Create initial dns cache */
309 this->cache = new dnscache();
312 irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver);
314 /* Initialize mastersocket */
315 int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
318 /* Have we got a socket and is it nonblocking? */
319 if (this->GetFd() != -1)
321 ServerInstance->SE->SetReuse(s);
322 ServerInstance->SE->NonBlocking(s);
323 irc::sockets::sockaddrs bindto;
324 memset(&bindto, 0, sizeof(bindto));
325 bindto.sa.sa_family = myserver.sa.sa_family;
326 if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0)
329 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error binding dns socket - hostnames will NOT resolve");
330 ServerInstance->SE->Shutdown(this, 2);
331 ServerInstance->SE->Close(this);
334 else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
336 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Internal error starting DNS - hostnames will NOT resolve.");
337 ServerInstance->SE->Shutdown(this, 2);
338 ServerInstance->SE->Close(this);
344 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error creating DNS socket - hostnames will NOT resolve");
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);
488 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip);
489 /* Invalid IP address */
496 if (inet_aton(ip, &i))
498 unsigned char* c = (unsigned char*)&i.s_addr;
499 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
503 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip);
504 /* Invalid IP address */
509 length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload);
512 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query);
516 DNSRequest* req = this->AddQuery(&h, id, ip);
520 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't add query (resolver down?)");
524 if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1)
526 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't send (firewall?)");
533 /** Build an ipv6 reverse domain from an in6_addr
535 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
537 const char* hex = "0123456789abcdef";
538 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
542 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
545 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
546 *query++ = '.'; /* Seperator */
548 strcpy(query,"ip6.arpa"); /* Suffix the string */
551 /** Return the next id which is ready, and the result attached to it */
552 DNSResult DNS::GetResult()
554 /* Fetch dns query response and decide where it belongs */
557 unsigned char buffer[sizeof(DNSHeader)];
558 irc::sockets::sockaddrs from;
559 memset(&from, 0, sizeof(from));
560 socklen_t x = sizeof(from);
562 int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
564 /* Did we get the whole header? */
567 ServerInstance->Logs->Log("RESOLVER",DEBUG,"GetResult didn't get a full packet (len=%d)", length);
568 /* Nope - something screwed up. */
569 return DNSResult(-1,"",0,"");
572 /* Check wether the reply came from a different DNS
573 * server to the one we sent it to, or the source-port
575 * A user could in theory still spoof dns packets anyway
576 * but this is less trivial than just sending garbage
577 * to the server, which is possible without this check.
579 * -- Thanks jilles for pointing this one out.
581 if (from != myserver)
583 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
584 from.str().c_str(), myserver.str().c_str());
585 return DNSResult(-1,"",0,"");
588 /* Put the read header info into a header class */
589 DNS::FillHeader(&header,buffer,length - 12);
591 /* Get the id of this request.
592 * Its a 16 bit value stored in two char's,
593 * so we use logic shifts to create the value.
595 unsigned long this_id = header.id[1] + (header.id[0] << 8);
597 /* Do we have a pending request matching this id? */
598 if (!requests[this_id])
600 /* Somehow we got a DNS response for a request we never made... */
601 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id);
602 return DNSResult(-1,"",0,"");
606 /* Remove the query from the list of pending queries */
607 req = requests[this_id];
608 requests[this_id] = NULL;
611 /* Inform the DNSRequest class that it has a result to be read.
612 * When its finished it will return a DNSInfo which is a pair of
613 * unsigned char* resource record data, and an error message.
615 DNSInfo data = req->ResultIsReady(header, length);
616 std::string resultstr;
618 /* Check if we got a result, if we didnt, its an error */
619 if (data.first == NULL)
622 * Mask the ID with the value of ERROR_MASK, so that
623 * the dns_deal_with_classes() function knows that its
624 * an error response and needs to be treated uniquely.
625 * Put the error message in the second field.
627 std::string ro = req->orig;
629 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
633 unsigned long ttl = req->ttl;
636 /* Forward lookups come back as binary data. We must format them into ascii */
640 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
641 resultstr = formatted;
646 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
647 char* c = strstr(formatted,":0:");
650 memmove(c+1,c+2,strlen(c+2) + 1);
652 while (memcmp(c,"0:",2) == 0)
653 memmove(c,c+2,strlen(c+2) + 1);
654 if (memcmp(c,"0",2) == 0)
656 if (memcmp(formatted,"0::",3) == 0)
657 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
659 resultstr = formatted;
661 /* Special case. Sending ::1 around between servers
662 * and to clients is dangerous, because the : on the
663 * start makes the client or server interpret the IP
664 * as the last parameter on the line with a value ":1".
666 if (*formatted == ':')
667 resultstr.insert(0, "0");
671 case DNS_QUERY_CNAME:
672 /* Identical handling to PTR */
675 /* Reverse lookups just come back as char* */
676 resultstr = std::string((const char*)data.first);
683 /* Build the reply with the id and hostname/ip in it */
684 std::string ro = req->orig;
686 return DNSResult(this_id,resultstr,ttl,ro);
690 /** A result is ready, process it */
691 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
699 /* This is just to keep _FORTIFY_SOURCE happy */
700 rr.type = DNS_QUERY_NONE;
702 rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
703 rr.rr_class = 0; /* Same for VC++ */
705 if (!(header.flags1 & FLAGS_MASK_QR))
706 return std::make_pair((unsigned char*)NULL,"Not a query result");
708 if (header.flags1 & FLAGS_MASK_OPCODE)
709 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
711 if (header.flags2 & FLAGS_MASK_RCODE)
712 return std::make_pair((unsigned char*)NULL,"Domain name not found");
714 if (header.ancount < 1)
715 return std::make_pair((unsigned char*)NULL,"No resource records returned");
717 /* Subtract the length of the header from the length of the packet */
720 while ((unsigned int)q < header.qdcount && i < length)
722 if (header.payload[i] > 63)
729 if (header.payload[i] == 0)
734 else i += header.payload[i] + 1;
738 while ((unsigned)curanswer < header.ancount)
741 while (q == 0 && i < length)
743 if (header.payload[i] > 63)
750 if (header.payload[i] == 0)
755 else i += header.payload[i] + 1; /* skip length and label */
759 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
761 /* XXX: We actually initialise 'rr' here including its ttl field */
762 DNS::FillResourceRecord(&rr,&header.payload[i]);
765 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);
766 if (rr.type != this->type)
772 if (rr.rr_class != this->rr_class)
780 if ((unsigned int)curanswer == header.ancount)
781 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
783 if (i + rr.rdlength > (unsigned int)length)
784 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
786 if (rr.rdlength > 1023)
787 return std::make_pair((unsigned char*)NULL,"Resource record too large");
793 case DNS_QUERY_CNAME:
794 /* CNAME and PTR have the same processing code */
798 while (q == 0 && i < length && o + 256 < 1023)
800 if (header.payload[i] > 63)
802 memcpy(&ptr,&header.payload[i],2);
803 i = ntohs(ptr) - 0xC000 - 12;
807 if (header.payload[i] == 0)
816 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
817 o += header.payload[i];
818 i += header.payload[i] + 1;
825 memcpy(res,&header.payload[i],rr.rdlength);
826 res[rr.rdlength] = 0;
829 memcpy(res,&header.payload[i],rr.rdlength);
830 res[rr.rdlength] = 0;
833 memcpy(res,&header.payload[i],rr.rdlength);
834 res[rr.rdlength] = 0;
837 return std::make_pair(res,"No error");
840 /** Close the master socket */
843 ServerInstance->SE->Shutdown(this, 2);
844 ServerInstance->SE->Close(this);
845 ServerInstance->Timers->DelTimer(this->PruneTimer);
850 CachedQuery* DNS::GetCache(const std::string &source)
852 dnscache::iterator x = cache->find(source.c_str());
853 if (x != cache->end())
859 void DNS::DelCache(const std::string &source)
861 cache->erase(source.c_str());
864 void Resolver::TriggerCachedResult()
867 OnLookupComplete(CQ->data, time_left, true);
870 /** High level abstraction of dns used by application at large */
871 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
873 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
876 CQ = ServerInstance->Res->GetCache(source);
879 time_left = CQ->CalcTTLRemaining();
882 ServerInstance->Res->DelCache(source);
894 this->myid = ServerInstance->Res->GetIP(source.c_str());
898 querytype = DNS_QUERY_PTR;
899 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
903 querytype = DNS_QUERY_PTR;
904 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
908 this->myid = ServerInstance->Res->GetIP6(source.c_str());
911 case DNS_QUERY_CNAME:
912 this->myid = ServerInstance->Res->GetCName(source.c_str());
916 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request with unknown query type %d", querytype);
920 if (this->myid == -1)
922 throw ModuleException("Resolver: Couldn't get an id to make a request");
926 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
930 /** Called when an error occurs */
931 void Resolver::OnError(ResolverError, const std::string&)
933 /* Nothing in here */
936 /** Destroy a resolver */
937 Resolver::~Resolver()
939 /* Nothing here (yet) either */
942 /** Get the request id associated with this class */
943 int Resolver::GetId()
948 Module* Resolver::GetCreator()
950 return this->Creator;
953 /** Process a socket read event */
954 void DNS::HandleEvent(EventType, int)
956 /* Fetch the id and result of the next available packet */
957 DNSResult res(0,"",0,"");
959 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
961 res = this->GetResult();
963 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
965 /* Is there a usable request id? */
968 /* Its an error reply */
969 if (res.id & ERROR_MASK)
971 /* Mask off the error bit */
972 res.id -= ERROR_MASK;
973 /* Marshall the error to the correct class */
976 if (ServerInstance && ServerInstance->stats)
977 ServerInstance->stats->statsDnsBad++;
978 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
979 delete Classes[res.id];
980 Classes[res.id] = NULL;
986 /* It is a non-error result, marshall the result to the correct class */
989 if (ServerInstance && ServerInstance->stats)
990 ServerInstance->stats->statsDnsGood++;
992 if (!this->GetCache(res.original.c_str()))
993 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
995 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
996 delete Classes[res.id];
997 Classes[res.id] = NULL;
1001 if (ServerInstance && ServerInstance->stats)
1002 ServerInstance->stats->statsDns++;
1006 /** Add a derived Resolver to the working set */
1007 bool DNS::AddResolverClass(Resolver* r)
1009 ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
1010 /* Check the pointers validity and the id's validity */
1011 if ((r) && (r->GetId() > -1))
1013 /* Check the slot isnt already occupied -
1014 * This should NEVER happen unless we have
1015 * a severely broken DNS server somewhere
1017 if (!Classes[r->GetId()])
1019 /* Set up the pointer to the class */
1020 Classes[r->GetId()] = r;
1029 /* Pointer or id not valid.
1030 * Free the item and return
1039 void DNS::CleanResolvers(Module* module)
1041 for (int i = 0; i < MAX_REQUEST_ID; i++)
1045 if (Classes[i]->GetCreator() == module)
1047 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");