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 #define DN_COMP_BITMASK 0xC000 /* highest 6 bits in a DN label header */
43 /** Masks to mask off the responses we get from the DNSRequest methods
47 ERROR_MASK = 0x10000 /* Result is an error */
50 /** Flags which can be ORed into a request or reply for different meanings
54 FLAGS_MASK_RD = 0x01, /* Recursive */
56 FLAGS_MASK_AA = 0x04, /* Authoritative */
57 FLAGS_MASK_OPCODE = 0x78,
59 FLAGS_MASK_RCODE = 0x0F, /* Request */
65 /** Represents a dns resource record (rr)
69 QueryType type; /* Record type */
70 unsigned int rr_class; /* Record class */
71 unsigned long ttl; /* Time to live */
72 unsigned int rdlength; /* Record length */
75 /** Represents a dns request/reply header, and its payload as opaque data.
80 unsigned char id[2]; /* Request id */
81 unsigned int flags1; /* Flags */
82 unsigned int flags2; /* Flags */
84 unsigned int ancount; /* Answer count */
85 unsigned int nscount; /* Nameserver count */
87 unsigned char payload[512]; /* Packet payload */
93 unsigned char id[2]; /* Request id */
94 unsigned char* res; /* Result processing buffer */
95 unsigned int rr_class; /* Request class */
96 QueryType type; /* Request type */
97 DNS* dnsobj; /* DNS caller (where we get our FD from) */
98 unsigned long ttl; /* Time to live */
99 std::string orig; /* Original requested name/ip */
101 DNSRequest(DNS* dns, int id, const std::string &original);
103 DNSInfo ResultIsReady(DNSHeader &h, unsigned length);
104 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
107 class CacheTimer : public Timer
112 CacheTimer(DNS* thisdns)
113 : Timer(3600, ServerInstance->Time(), true), dns(thisdns) { }
115 virtual void Tick(time_t)
121 class RequestTimeout : public Timer
126 RequestTimeout(unsigned long n, DNSRequest* watching, int id) : Timer(n, ServerInstance->Time()), watch(watching), watchid(id)
131 if (ServerInstance->Res)
137 if (ServerInstance->Res->requests[watchid] == watch)
139 /* Still exists, whack it */
140 if (ServerInstance->Res->Classes[watchid])
142 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
143 delete ServerInstance->Res->Classes[watchid];
144 ServerInstance->Res->Classes[watchid] = NULL;
146 ServerInstance->Res->requests[watchid] = NULL;
152 CachedQuery::CachedQuery(const std::string &res, unsigned int ttl) : data(res)
154 expires = ServerInstance->Time() + ttl;
157 int CachedQuery::CalcTTLRemaining()
159 int n = expires - ServerInstance->Time();
160 return (n < 0 ? 0 : n);
163 /* Allocate the processing buffer */
164 DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns)
166 /* hardening against overflow here: make our work buffer twice the theoretical
167 * maximum size so that hostile input doesn't screw us over.
169 res = new unsigned char[sizeof(DNSHeader) * 2];
172 RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid);
173 ServerInstance->Timers->AddTimer(RT); /* The timer manager frees this */
176 /* Deallocate the processing buffer */
177 DNSRequest::~DNSRequest()
182 /** Fill a ResourceRecord class based on raw data input */
183 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
185 rr->type = (QueryType)((input[0] << 8) + input[1]);
186 rr->rr_class = (input[2] << 8) + input[3];
187 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
188 rr->rdlength = (input[8] << 8) + input[9];
191 /** Fill a DNSHeader class based on raw data input of a given length */
192 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
194 header->id[0] = input[0];
195 header->id[1] = input[1];
196 header->flags1 = input[2];
197 header->flags2 = input[3];
198 header->qdcount = (input[4] << 8) + input[5];
199 header->ancount = (input[6] << 8) + input[7];
200 header->nscount = (input[8] << 8) + input[9];
201 header->arcount = (input[10] << 8) + input[11];
202 memcpy(header->payload,&input[12],length);
205 /** Empty a DNSHeader class out into raw data, ready for transmission */
206 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
208 output[0] = header->id[0];
209 output[1] = header->id[1];
210 output[2] = header->flags1;
211 output[3] = header->flags2;
212 output[4] = header->qdcount >> 8;
213 output[5] = header->qdcount & 0xFF;
214 output[6] = header->ancount >> 8;
215 output[7] = header->ancount & 0xFF;
216 output[8] = header->nscount >> 8;
217 output[9] = header->nscount & 0xFF;
218 output[10] = header->arcount >> 8;
219 output[11] = header->arcount & 0xFF;
220 memcpy(&output[12],header->payload,length);
223 /** Send requests we have previously built down the UDP socket */
224 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
226 ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests");
228 unsigned char payload[sizeof(DNSHeader)];
233 DNS::EmptyHeader(payload,header,length);
235 if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12)
238 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK");
242 /** Add a query with a predefined header, and allocate an ID for it. */
243 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
245 /* Is the DNS connection down? */
246 if (this->GetFd() == -1)
251 id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
252 } while (requests[id]);
254 DNSRequest* req = new DNSRequest(this, id, original);
256 header->id[0] = req->id[0] = id >> 8;
257 header->id[1] = req->id[1] = id & 0xFF;
258 header->flags1 = FLAGS_MASK_RD;
265 /* At this point we already know the id doesnt exist,
266 * so there needs to be no second check for the ::end()
270 /* According to the C++ spec, new never returns NULL. */
274 int DNS::ClearCache()
276 /* This ensures the buckets are reset to sane levels */
277 int rv = this->cache->size();
279 this->cache = new dnscache();
283 int DNS::PruneCache()
286 dnscache* newcache = new dnscache();
287 for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
288 /* Dont include expired items (theres no point) */
289 if (i->second.CalcTTLRemaining())
290 newcache->insert(*i);
295 this->cache = newcache;
301 if (this->GetFd() > -1)
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 irc::sockets::sockaddrs bindto;
329 memset(&bindto, 0, sizeof(bindto));
330 bindto.sa.sa_family = myserver.sa.sa_family;
331 if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0)
334 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error binding dns socket - hostnames will NOT resolve");
335 ServerInstance->SE->Shutdown(this, 2);
336 ServerInstance->SE->Close(this);
339 else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
341 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Internal error starting DNS - hostnames will NOT resolve.");
342 ServerInstance->SE->Shutdown(this, 2);
343 ServerInstance->SE->Close(this);
349 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error creating DNS socket - hostnames will NOT resolve");
353 /** Initialise the DNS UDP socket so that we can send requests */
356 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
357 /* Clear the Resolver class table */
358 memset(Classes,0,sizeof(Classes));
360 /* Clear the requests class table */
361 memset(requests,0,sizeof(requests));
363 /* Set the id of the next request to 0
367 /* DNS::Rehash() sets this to a valid ptr
371 /* Again, DNS::Rehash() sets this to a
376 /* Actually read the settings
380 this->PruneTimer = new CacheTimer(this);
382 ServerInstance->Timers->AddTimer(this->PruneTimer);
385 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
386 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
388 short payloadpos = 0;
389 const char* tempchr, *tempchr2 = name;
390 unsigned short length;
392 /* split name up into labels, create query */
393 while ((tempchr = strchr(tempchr2,'.')) != NULL)
395 length = tempchr - tempchr2;
396 if (payloadpos + length + 1 > 507)
398 payload[payloadpos++] = length;
399 memcpy(&payload[payloadpos],tempchr2,length);
400 payloadpos += length;
401 tempchr2 = &tempchr[1];
403 length = strlen(tempchr2);
406 if (payloadpos + length + 2 > 507)
408 payload[payloadpos++] = length;
409 memcpy(&payload[payloadpos],tempchr2,length);
410 payloadpos += length;
411 payload[payloadpos++] = 0;
413 if (payloadpos > 508)
416 memcpy(&payload[payloadpos],&length,2);
417 length = htons(rr_class);
418 memcpy(&payload[payloadpos + 2],&length,2);
419 return payloadpos + 4;
422 /** Start lookup of an hostname to an IP address */
423 int DNS::GetIP(const char *name)
429 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
432 DNSRequest* req = this->AddQuery(&h, id, name);
434 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
440 /** Start lookup of an hostname to an IPv6 address */
441 int DNS::GetIP6(const char *name)
447 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
450 DNSRequest* req = this->AddQuery(&h, id, name);
452 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
458 /** Start lookup of a cname to another name */
459 int DNS::GetCName(const char *alias)
465 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
468 DNSRequest* req = this->AddQuery(&h, id, alias);
470 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
476 /** Start lookup of an IP address to a hostname */
477 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
484 if (fp == PROTOCOL_IPV6)
487 if (inet_pton(AF_INET6, ip, &i) > 0)
489 DNS::MakeIP6Int(query, &i);
493 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip);
494 /* Invalid IP address */
501 if (inet_aton(ip, &i))
503 unsigned char* c = (unsigned char*)&i.s_addr;
504 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
508 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip);
509 /* Invalid IP address */
514 length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload);
517 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query);
521 DNSRequest* req = this->AddQuery(&h, id, ip);
525 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't add query (resolver down?)");
529 if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1)
531 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't send (firewall?)");
538 /** Build an ipv6 reverse domain from an in6_addr
540 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
542 const char* hex = "0123456789abcdef";
543 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
547 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
550 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
551 *query++ = '.'; /* Seperator */
553 strcpy(query,"ip6.arpa"); /* Suffix the string */
556 /** Return the next id which is ready, and the result attached to it */
557 DNSResult DNS::GetResult()
559 /* Fetch dns query response and decide where it belongs */
562 unsigned char buffer[sizeof(DNSHeader)];
563 irc::sockets::sockaddrs from;
564 memset(&from, 0, sizeof(from));
565 socklen_t x = sizeof(from);
567 int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
569 /* Did we get the whole header? */
572 ServerInstance->Logs->Log("RESOLVER",DEBUG,"GetResult didn't get a full packet (len=%d)", length);
573 /* Nope - something screwed up. */
574 return DNSResult(-1,"",0,"");
577 /* Check wether the reply came from a different DNS
578 * server to the one we sent it to, or the source-port
580 * A user could in theory still spoof dns packets anyway
581 * but this is less trivial than just sending garbage
582 * to the server, which is possible without this check.
584 * -- Thanks jilles for pointing this one out.
586 if (from != myserver)
588 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
589 from.str().c_str(), myserver.str().c_str());
590 return DNSResult(-1,"",0,"");
593 /* Put the read header info into a header class */
594 DNS::FillHeader(&header,buffer,length - 12);
596 /* Get the id of this request.
597 * Its a 16 bit value stored in two char's,
598 * so we use logic shifts to create the value.
600 unsigned long this_id = header.id[1] + (header.id[0] << 8);
602 /* Do we have a pending request matching this id? */
603 if (!requests[this_id])
605 /* Somehow we got a DNS response for a request we never made... */
606 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id);
607 return DNSResult(-1,"",0,"");
611 /* Remove the query from the list of pending queries */
612 req = requests[this_id];
613 requests[this_id] = NULL;
616 /* Inform the DNSRequest class that it has a result to be read.
617 * When its finished it will return a DNSInfo which is a pair of
618 * unsigned char* resource record data, and an error message.
620 DNSInfo data = req->ResultIsReady(header, length);
621 std::string resultstr;
623 /* Check if we got a result, if we didnt, its an error */
624 if (data.first == NULL)
627 * Mask the ID with the value of ERROR_MASK, so that
628 * the dns_deal_with_classes() function knows that its
629 * an error response and needs to be treated uniquely.
630 * Put the error message in the second field.
632 std::string ro = req->orig;
634 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
638 unsigned long ttl = req->ttl;
641 /* Forward lookups come back as binary data. We must format them into ascii */
645 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
646 resultstr = formatted;
651 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
652 char* c = strstr(formatted,":0:");
655 memmove(c+1,c+2,strlen(c+2) + 1);
657 while (memcmp(c,"0:",2) == 0)
658 memmove(c,c+2,strlen(c+2) + 1);
659 if (memcmp(c,"0",2) == 0)
661 if (memcmp(formatted,"0::",3) == 0)
662 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
664 resultstr = formatted;
666 /* Special case. Sending ::1 around between servers
667 * and to clients is dangerous, because the : on the
668 * start makes the client or server interpret the IP
669 * as the last parameter on the line with a value ":1".
671 if (*formatted == ':')
672 resultstr.insert(0, "0");
676 case DNS_QUERY_CNAME:
677 /* Identical handling to PTR */
680 /* Reverse lookups just come back as char* */
681 resultstr = std::string((const char*)data.first);
688 /* Build the reply with the id and hostname/ip in it */
689 std::string ro = req->orig;
691 return DNSResult(this_id,resultstr,ttl,ro);
695 /** A result is ready, process it */
696 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
704 /* This is just to keep _FORTIFY_SOURCE happy */
705 rr.type = DNS_QUERY_NONE;
707 rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
708 rr.rr_class = 0; /* Same for VC++ */
710 if (!(header.flags1 & FLAGS_MASK_QR))
711 return std::make_pair((unsigned char*)NULL,"Not a query result");
713 if (header.flags1 & FLAGS_MASK_OPCODE)
714 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
716 if (header.flags2 & FLAGS_MASK_RCODE)
717 return std::make_pair((unsigned char*)NULL,"Domain name not found");
719 if (header.ancount < 1)
720 return std::make_pair((unsigned char*)NULL,"No resource records returned");
722 /* Subtract the length of the header from the length of the packet */
725 while ((unsigned int)q < header.qdcount && i < length)
727 if (header.payload[i] > 63)
734 if (header.payload[i] == 0)
739 else i += header.payload[i] + 1;
743 while ((unsigned)curanswer < header.ancount)
746 while (q == 0 && i < length)
748 if (header.payload[i] > 63)
755 if (header.payload[i] == 0)
760 else i += header.payload[i] + 1; /* skip length and label */
764 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
766 /* XXX: We actually initialise 'rr' here including its ttl field */
767 DNS::FillResourceRecord(&rr,&header.payload[i]);
770 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);
771 if (rr.type != this->type)
777 if (rr.rr_class != this->rr_class)
785 if ((unsigned int)curanswer == header.ancount)
786 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
788 if (i + rr.rdlength > (unsigned int)length)
789 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
791 if (rr.rdlength > 1023)
792 return std::make_pair((unsigned char*)NULL,"Resource record too large");
799 * CNAME and PTR are compressed. We need to decompress them.
801 case DNS_QUERY_CNAME:
805 while (q == 0 && i < length && o + 256 < 1023)
807 /* DN label found (byte over 63) */
808 if (header.payload[i] > 63)
810 memcpy(&ptr,&header.payload[i],2);
814 /* check that highest two bits are set. if not, we've been had */
815 if (!(i & DN_COMP_BITMASK))
816 return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
818 /* mask away the two highest bits. */
819 i &= ~DN_COMP_BITMASK;
821 /* and decrease length by 12 bytes. */
826 if (header.payload[i] == 0)
836 if (o + header.payload[i] > sizeof(DNSHeader))
837 return std::make_pair((unsigned char *) NULL, "DN label decompression is impossible -- malformed/hostile packet?");
839 memcpy(&res[o], &header.payload[i + 1], header.payload[i]);
840 o += header.payload[i];
841 i += header.payload[i] + 1;
848 if (rr.rdlength != sizeof(struct in6_addr))
849 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?");
851 memcpy(res,&header.payload[i],rr.rdlength);
852 res[rr.rdlength] = 0;
855 if (rr.rdlength != sizeof(struct in_addr))
856 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?");
858 memcpy(res,&header.payload[i],rr.rdlength);
859 res[rr.rdlength] = 0;
862 return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting");
865 return std::make_pair(res,"No error");
868 /** Close the master socket */
871 ServerInstance->SE->Shutdown(this, 2);
872 ServerInstance->SE->Close(this);
873 ServerInstance->Timers->DelTimer(this->PruneTimer);
878 CachedQuery* DNS::GetCache(const std::string &source)
880 dnscache::iterator x = cache->find(source.c_str());
881 if (x != cache->end())
887 void DNS::DelCache(const std::string &source)
889 cache->erase(source.c_str());
892 void Resolver::TriggerCachedResult()
895 OnLookupComplete(CQ->data, time_left, true);
898 /** High level abstraction of dns used by application at large */
899 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
901 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
904 CQ = ServerInstance->Res->GetCache(source);
907 time_left = CQ->CalcTTLRemaining();
910 ServerInstance->Res->DelCache(source);
922 this->myid = ServerInstance->Res->GetIP(source.c_str());
926 querytype = DNS_QUERY_PTR;
927 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
931 querytype = DNS_QUERY_PTR;
932 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
936 this->myid = ServerInstance->Res->GetIP6(source.c_str());
939 case DNS_QUERY_CNAME:
940 this->myid = ServerInstance->Res->GetCName(source.c_str());
944 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request with unknown query type %d", querytype);
948 if (this->myid == -1)
950 throw ModuleException("Resolver: Couldn't get an id to make a request");
954 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
958 /** Called when an error occurs */
959 void Resolver::OnError(ResolverError, const std::string&)
961 /* Nothing in here */
964 /** Destroy a resolver */
965 Resolver::~Resolver()
967 /* Nothing here (yet) either */
970 /** Get the request id associated with this class */
971 int Resolver::GetId()
976 Module* Resolver::GetCreator()
978 return this->Creator;
981 /** Process a socket read event */
982 void DNS::HandleEvent(EventType, int)
984 /* Fetch the id and result of the next available packet */
985 DNSResult res(0,"",0,"");
987 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
989 res = this->GetResult();
991 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
993 /* Is there a usable request id? */
996 /* Its an error reply */
997 if (res.id & ERROR_MASK)
999 /* Mask off the error bit */
1000 res.id -= ERROR_MASK;
1001 /* Marshall the error to the correct class */
1002 if (Classes[res.id])
1004 if (ServerInstance && ServerInstance->stats)
1005 ServerInstance->stats->statsDnsBad++;
1006 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1007 delete Classes[res.id];
1008 Classes[res.id] = NULL;
1014 /* It is a non-error result, marshall the result to the correct class */
1015 if (Classes[res.id])
1017 if (ServerInstance && ServerInstance->stats)
1018 ServerInstance->stats->statsDnsGood++;
1020 if (!this->GetCache(res.original.c_str()))
1021 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1023 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
1024 delete Classes[res.id];
1025 Classes[res.id] = NULL;
1029 if (ServerInstance && ServerInstance->stats)
1030 ServerInstance->stats->statsDns++;
1034 /** Add a derived Resolver to the working set */
1035 bool DNS::AddResolverClass(Resolver* r)
1037 ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
1038 /* Check the pointers validity and the id's validity */
1039 if ((r) && (r->GetId() > -1))
1041 /* Check the slot isnt already occupied -
1042 * This should NEVER happen unless we have
1043 * a severely broken DNS server somewhere
1045 if (!Classes[r->GetId()])
1047 /* Set up the pointer to the class */
1048 Classes[r->GetId()] = r;
1057 /* Pointer or id not valid.
1058 * Free the item and return
1067 void DNS::CleanResolvers(Module* module)
1069 for (int i = 0; i < MAX_REQUEST_ID; i++)
1073 if (Classes[i]->GetCreator() == module)
1075 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");