2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2012 William Pitcock <nenolod@dereferenced.org>
5 * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
6 * Copyright (C) 2006, 2009 Robin Burchell <robin+git@viroteck.net>
7 * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
8 * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
9 * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc>
11 * This file is part of InspIRCd. InspIRCd is free software: you can
12 * redistribute it and/or modify it under the terms of the GNU General Public
13 * License as published by the Free Software Foundation, version 2.
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 dns.cpp - Nonblocking DNS functions.
29 Very very loosely based on the firedns library,
30 Copyright (C) 2002 Ian Gulliver. This file is no
31 longer anything like firedns, there are many major
32 differences between this code and the original.
33 Please do not assume that firedns works like this,
34 looks like this, walks like this or tastes like this.
38 #include <sys/types.h>
39 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
44 #include "inspircd_win32wrapper.h"
48 #include "socketengine.h"
49 #include "configreader.h"
52 #define DN_COMP_BITMASK 0xC000 /* highest 6 bits in a DN label header */
54 /** Masks to mask off the responses we get from the DNSRequest methods
58 ERROR_MASK = 0x10000 /* Result is an error */
61 /** Flags which can be ORed into a request or reply for different meanings
65 FLAGS_MASK_RD = 0x01, /* Recursive */
67 FLAGS_MASK_AA = 0x04, /* Authoritative */
68 FLAGS_MASK_OPCODE = 0x78,
70 FLAGS_MASK_RCODE = 0x0F, /* Request */
76 /** Represents a dns resource record (rr)
80 QueryType type; /* Record type */
81 unsigned int rr_class; /* Record class */
82 unsigned long ttl; /* Time to live */
83 unsigned int rdlength; /* Record length */
86 /** Represents a dns request/reply header, and its payload as opaque data.
91 unsigned char id[2]; /* Request id */
92 unsigned int flags1; /* Flags */
93 unsigned int flags2; /* Flags */
95 unsigned int ancount; /* Answer count */
96 unsigned int nscount; /* Nameserver count */
98 unsigned char payload[512]; /* Packet payload */
104 unsigned char id[2]; /* Request id */
105 unsigned char* res; /* Result processing buffer */
106 unsigned int rr_class; /* Request class */
107 QueryType type; /* Request type */
108 DNS* dnsobj; /* DNS caller (where we get our FD from) */
109 unsigned long ttl; /* Time to live */
110 std::string orig; /* Original requested name/ip */
112 DNSRequest(DNS* dns, int id, const std::string &original);
114 DNSInfo ResultIsReady(DNSHeader &h, unsigned length);
115 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
118 class CacheTimer : public Timer
123 CacheTimer(DNS* thisdns)
124 : Timer(3600, ServerInstance->Time(), true), dns(thisdns) { }
126 virtual void Tick(time_t)
132 class RequestTimeout : public Timer
137 RequestTimeout(unsigned long n, DNSRequest* watching, int id) : Timer(n, ServerInstance->Time()), watch(watching), watchid(id)
142 if (ServerInstance->Res)
148 if (ServerInstance->Res->requests[watchid] == watch)
150 /* Still exists, whack it */
151 if (ServerInstance->Res->Classes[watchid])
153 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
154 delete ServerInstance->Res->Classes[watchid];
155 ServerInstance->Res->Classes[watchid] = NULL;
157 ServerInstance->Res->requests[watchid] = NULL;
163 CachedQuery::CachedQuery(const std::string &res, unsigned int ttl) : data(res)
165 expires = ServerInstance->Time() + ttl;
168 int CachedQuery::CalcTTLRemaining()
170 int n = expires - ServerInstance->Time();
171 return (n < 0 ? 0 : n);
174 /* Allocate the processing buffer */
175 DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns)
177 /* hardening against overflow here: make our work buffer twice the theoretical
178 * maximum size so that hostile input doesn't screw us over.
180 res = new unsigned char[sizeof(DNSHeader) * 2];
183 RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid);
184 ServerInstance->Timers->AddTimer(RT); /* The timer manager frees this */
187 /* Deallocate the processing buffer */
188 DNSRequest::~DNSRequest()
193 /** Fill a ResourceRecord class based on raw data input */
194 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
196 rr->type = (QueryType)((input[0] << 8) + input[1]);
197 rr->rr_class = (input[2] << 8) + input[3];
198 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
199 rr->rdlength = (input[8] << 8) + input[9];
202 /** Fill a DNSHeader class based on raw data input of a given length */
203 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
205 header->id[0] = input[0];
206 header->id[1] = input[1];
207 header->flags1 = input[2];
208 header->flags2 = input[3];
209 header->qdcount = (input[4] << 8) + input[5];
210 header->ancount = (input[6] << 8) + input[7];
211 header->nscount = (input[8] << 8) + input[9];
212 header->arcount = (input[10] << 8) + input[11];
213 memcpy(header->payload,&input[12],length);
216 /** Empty a DNSHeader class out into raw data, ready for transmission */
217 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
219 output[0] = header->id[0];
220 output[1] = header->id[1];
221 output[2] = header->flags1;
222 output[3] = header->flags2;
223 output[4] = header->qdcount >> 8;
224 output[5] = header->qdcount & 0xFF;
225 output[6] = header->ancount >> 8;
226 output[7] = header->ancount & 0xFF;
227 output[8] = header->nscount >> 8;
228 output[9] = header->nscount & 0xFF;
229 output[10] = header->arcount >> 8;
230 output[11] = header->arcount & 0xFF;
231 memcpy(&output[12],header->payload,length);
234 /** Send requests we have previously built down the UDP socket */
235 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
237 ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests");
239 unsigned char payload[sizeof(DNSHeader)];
244 DNS::EmptyHeader(payload,header,length);
246 if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12)
249 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK");
253 /** Add a query with a predefined header, and allocate an ID for it. */
254 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
256 /* Is the DNS connection down? */
257 if (this->GetFd() == -1)
262 id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
263 } while (requests[id]);
265 DNSRequest* req = new DNSRequest(this, id, original);
267 header->id[0] = req->id[0] = id >> 8;
268 header->id[1] = req->id[1] = id & 0xFF;
269 header->flags1 = FLAGS_MASK_RD;
276 /* At this point we already know the id doesnt exist,
277 * so there needs to be no second check for the ::end()
281 /* According to the C++ spec, new never returns NULL. */
285 int DNS::ClearCache()
287 /* This ensures the buckets are reset to sane levels */
288 int rv = this->cache->size();
290 this->cache = new dnscache();
294 int DNS::PruneCache()
297 dnscache* newcache = new dnscache();
298 for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
299 /* Dont include expired items (theres no point) */
300 if (i->second.CalcTTLRemaining())
301 newcache->insert(*i);
306 this->cache = newcache;
312 if (this->GetFd() > -1)
314 ServerInstance->SE->DelFd(this);
315 ServerInstance->SE->Shutdown(this, 2);
316 ServerInstance->SE->Close(this);
319 /* Rehash the cache */
324 /* Create initial dns cache */
325 this->cache = new dnscache();
328 irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver);
330 /* Initialize mastersocket */
331 int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
334 /* Have we got a socket and is it nonblocking? */
335 if (this->GetFd() != -1)
337 ServerInstance->SE->SetReuse(s);
338 ServerInstance->SE->NonBlocking(s);
339 irc::sockets::sockaddrs bindto;
340 memset(&bindto, 0, sizeof(bindto));
341 bindto.sa.sa_family = myserver.sa.sa_family;
342 if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0)
345 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error binding dns socket - hostnames will NOT resolve");
346 ServerInstance->SE->Shutdown(this, 2);
347 ServerInstance->SE->Close(this);
350 else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
352 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Internal error starting DNS - hostnames will NOT resolve.");
353 ServerInstance->SE->Shutdown(this, 2);
354 ServerInstance->SE->Close(this);
360 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error creating DNS socket - hostnames will NOT resolve");
364 /** Initialise the DNS UDP socket so that we can send requests */
367 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
368 /* Clear the Resolver class table */
369 memset(Classes,0,sizeof(Classes));
371 /* Clear the requests class table */
372 memset(requests,0,sizeof(requests));
374 /* Set the id of the next request to 0
378 /* DNS::Rehash() sets this to a valid ptr
382 /* Again, DNS::Rehash() sets this to a
387 /* Actually read the settings
391 this->PruneTimer = new CacheTimer(this);
393 ServerInstance->Timers->AddTimer(this->PruneTimer);
396 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
397 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
399 short payloadpos = 0;
400 const char* tempchr, *tempchr2 = name;
401 unsigned short length;
403 /* split name up into labels, create query */
404 while ((tempchr = strchr(tempchr2,'.')) != NULL)
406 length = tempchr - tempchr2;
407 if (payloadpos + length + 1 > 507)
409 payload[payloadpos++] = length;
410 memcpy(&payload[payloadpos],tempchr2,length);
411 payloadpos += length;
412 tempchr2 = &tempchr[1];
414 length = strlen(tempchr2);
417 if (payloadpos + length + 2 > 507)
419 payload[payloadpos++] = length;
420 memcpy(&payload[payloadpos],tempchr2,length);
421 payloadpos += length;
422 payload[payloadpos++] = 0;
424 if (payloadpos > 508)
427 memcpy(&payload[payloadpos],&length,2);
428 length = htons(rr_class);
429 memcpy(&payload[payloadpos + 2],&length,2);
430 return payloadpos + 4;
433 /** Start lookup of an hostname to an IP address */
434 int DNS::GetIP(const char *name)
440 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
443 DNSRequest* req = this->AddQuery(&h, id, name);
445 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
451 /** Start lookup of an hostname to an IPv6 address */
452 int DNS::GetIP6(const char *name)
458 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
461 DNSRequest* req = this->AddQuery(&h, id, name);
463 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
469 /** Start lookup of a cname to another name */
470 int DNS::GetCName(const char *alias)
476 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
479 DNSRequest* req = this->AddQuery(&h, id, alias);
481 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
487 /** Start lookup of an IP address to a hostname */
488 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
495 if (fp == PROTOCOL_IPV6)
498 if (inet_pton(AF_INET6, ip, &i) > 0)
500 DNS::MakeIP6Int(query, &i);
504 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip);
505 /* Invalid IP address */
512 if (inet_aton(ip, &i))
514 unsigned char* c = (unsigned char*)&i.s_addr;
515 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
519 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip);
520 /* Invalid IP address */
525 length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload);
528 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query);
532 DNSRequest* req = this->AddQuery(&h, id, ip);
536 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't add query (resolver down?)");
540 if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1)
542 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't send (firewall?)");
549 /** Build an ipv6 reverse domain from an in6_addr
551 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
553 const char* hex = "0123456789abcdef";
554 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
558 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
561 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
562 *query++ = '.'; /* Seperator */
564 strcpy(query,"ip6.arpa"); /* Suffix the string */
567 /** Return the next id which is ready, and the result attached to it */
568 DNSResult DNS::GetResult()
570 /* Fetch dns query response and decide where it belongs */
573 unsigned char buffer[sizeof(DNSHeader)];
574 irc::sockets::sockaddrs from;
575 memset(&from, 0, sizeof(from));
576 socklen_t x = sizeof(from);
578 int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
580 /* Did we get the whole header? */
583 ServerInstance->Logs->Log("RESOLVER",DEBUG,"GetResult didn't get a full packet (len=%d)", length);
584 /* Nope - something screwed up. */
585 return DNSResult(-1,"",0,"");
588 /* Check wether the reply came from a different DNS
589 * server to the one we sent it to, or the source-port
591 * A user could in theory still spoof dns packets anyway
592 * but this is less trivial than just sending garbage
593 * to the server, which is possible without this check.
595 * -- Thanks jilles for pointing this one out.
597 if (from != myserver)
599 std::string server1 = from.str();
600 std::string server2 = myserver.str();
601 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
602 server1.c_str(), server2.c_str());
603 return DNSResult(-1,"",0,"");
606 /* Put the read header info into a header class */
607 DNS::FillHeader(&header,buffer,length - 12);
609 /* Get the id of this request.
610 * Its a 16 bit value stored in two char's,
611 * so we use logic shifts to create the value.
613 unsigned long this_id = header.id[1] + (header.id[0] << 8);
615 /* Do we have a pending request matching this id? */
616 if (!requests[this_id])
618 /* Somehow we got a DNS response for a request we never made... */
619 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id);
620 return DNSResult(-1,"",0,"");
624 /* Remove the query from the list of pending queries */
625 req = requests[this_id];
626 requests[this_id] = NULL;
629 /* Inform the DNSRequest class that it has a result to be read.
630 * When its finished it will return a DNSInfo which is a pair of
631 * unsigned char* resource record data, and an error message.
633 DNSInfo data = req->ResultIsReady(header, length);
634 std::string resultstr;
636 /* Check if we got a result, if we didnt, its an error */
637 if (data.first == NULL)
640 * Mask the ID with the value of ERROR_MASK, so that
641 * the dns_deal_with_classes() function knows that its
642 * an error response and needs to be treated uniquely.
643 * Put the error message in the second field.
645 std::string ro = req->orig;
647 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
651 unsigned long ttl = req->ttl;
654 /* Forward lookups come back as binary data. We must format them into ascii */
658 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
659 resultstr = formatted;
664 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
665 char* c = strstr(formatted,":0:");
668 memmove(c+1,c+2,strlen(c+2) + 1);
670 while (memcmp(c,"0:",2) == 0)
671 memmove(c,c+2,strlen(c+2) + 1);
672 if (memcmp(c,"0",2) == 0)
674 if (memcmp(formatted,"0::",3) == 0)
675 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
677 resultstr = formatted;
679 /* Special case. Sending ::1 around between servers
680 * and to clients is dangerous, because the : on the
681 * start makes the client or server interpret the IP
682 * as the last parameter on the line with a value ":1".
684 if (*formatted == ':')
685 resultstr.insert(0, "0");
689 case DNS_QUERY_CNAME:
690 /* Identical handling to PTR */
693 /* Reverse lookups just come back as char* */
694 resultstr = std::string((const char*)data.first);
701 /* Build the reply with the id and hostname/ip in it */
702 std::string ro = req->orig;
704 return DNSResult(this_id,resultstr,ttl,ro);
708 /** A result is ready, process it */
709 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
717 /* This is just to keep _FORTIFY_SOURCE happy */
718 rr.type = DNS_QUERY_NONE;
720 rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
721 rr.rr_class = 0; /* Same for VC++ */
723 if (!(header.flags1 & FLAGS_MASK_QR))
724 return std::make_pair((unsigned char*)NULL,"Not a query result");
726 if (header.flags1 & FLAGS_MASK_OPCODE)
727 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
729 if (header.flags2 & FLAGS_MASK_RCODE)
730 return std::make_pair((unsigned char*)NULL,"Domain name not found");
732 if (header.ancount < 1)
733 return std::make_pair((unsigned char*)NULL,"No resource records returned");
735 /* Subtract the length of the header from the length of the packet */
738 while ((unsigned int)q < header.qdcount && i < length)
740 if (header.payload[i] > 63)
747 if (header.payload[i] == 0)
752 else i += header.payload[i] + 1;
756 while ((unsigned)curanswer < header.ancount)
759 while (q == 0 && i < length)
761 if (header.payload[i] > 63)
768 if (header.payload[i] == 0)
773 else i += header.payload[i] + 1; /* skip length and label */
776 if (static_cast<int>(length - i) < 10)
777 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
779 /* XXX: We actually initialise 'rr' here including its ttl field */
780 DNS::FillResourceRecord(&rr,&header.payload[i]);
783 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);
784 if (rr.type != this->type)
790 if (rr.rr_class != this->rr_class)
798 if ((unsigned int)curanswer == header.ancount)
799 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
801 if (i + rr.rdlength > (unsigned int)length)
802 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
804 if (rr.rdlength > 1023)
805 return std::make_pair((unsigned char*)NULL,"Resource record too large");
812 * CNAME and PTR are compressed. We need to decompress them.
814 case DNS_QUERY_CNAME:
817 unsigned short lowest_pos = length;
820 while (q == 0 && i < length && o + 256 < 1023)
822 /* DN label found (byte over 63) */
823 if (header.payload[i] > 63)
825 memcpy(&ptr,&header.payload[i],2);
829 /* check that highest two bits are set. if not, we've been had */
830 if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK)
831 return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
833 /* mask away the two highest bits. */
834 i &= ~DN_COMP_BITMASK;
836 /* and decrease length by 12 bytes. */
840 return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer");
845 if (header.payload[i] == 0)
855 if (o + header.payload[i] > sizeof(DNSHeader))
856 return std::make_pair((unsigned char *) NULL, "DN label decompression is impossible -- malformed/hostile packet?");
858 memcpy(&res[o], &header.payload[i + 1], header.payload[i]);
859 o += header.payload[i];
860 i += header.payload[i] + 1;
868 if (rr.rdlength != sizeof(struct in6_addr))
869 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?");
871 memcpy(res,&header.payload[i],rr.rdlength);
872 res[rr.rdlength] = 0;
875 if (rr.rdlength != sizeof(struct in_addr))
876 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?");
878 memcpy(res,&header.payload[i],rr.rdlength);
879 res[rr.rdlength] = 0;
882 return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting");
885 return std::make_pair(res,"No error");
888 /** Close the master socket */
891 ServerInstance->SE->Shutdown(this, 2);
892 ServerInstance->SE->Close(this);
893 ServerInstance->Timers->DelTimer(this->PruneTimer);
898 CachedQuery* DNS::GetCache(const std::string &source)
900 dnscache::iterator x = cache->find(source.c_str());
901 if (x != cache->end())
907 void DNS::DelCache(const std::string &source)
909 cache->erase(source.c_str());
912 void Resolver::TriggerCachedResult()
915 OnLookupComplete(CQ->data, time_left, true);
918 /** High level abstraction of dns used by application at large */
919 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
921 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
924 CQ = ServerInstance->Res->GetCache(source);
927 time_left = CQ->CalcTTLRemaining();
930 ServerInstance->Res->DelCache(source);
942 this->myid = ServerInstance->Res->GetIP(source.c_str());
946 querytype = DNS_QUERY_PTR;
947 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
951 querytype = DNS_QUERY_PTR;
952 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
956 this->myid = ServerInstance->Res->GetIP6(source.c_str());
959 case DNS_QUERY_CNAME:
960 this->myid = ServerInstance->Res->GetCName(source.c_str());
964 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request with unknown query type %d", querytype);
968 if (this->myid == -1)
970 throw ModuleException("Resolver: Couldn't get an id to make a request");
974 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
978 /** Called when an error occurs */
979 void Resolver::OnError(ResolverError, const std::string&)
981 /* Nothing in here */
984 /** Destroy a resolver */
985 Resolver::~Resolver()
987 /* Nothing here (yet) either */
990 /** Get the request id associated with this class */
991 int Resolver::GetId()
996 Module* Resolver::GetCreator()
998 return this->Creator;
1001 /** Process a socket read event */
1002 void DNS::HandleEvent(EventType, int)
1004 /* Fetch the id and result of the next available packet */
1005 DNSResult res(0,"",0,"");
1007 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
1009 res = this->GetResult();
1011 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
1013 /* Is there a usable request id? */
1016 /* Its an error reply */
1017 if (res.id & ERROR_MASK)
1019 /* Mask off the error bit */
1020 res.id -= ERROR_MASK;
1021 /* Marshall the error to the correct class */
1022 if (Classes[res.id])
1024 if (ServerInstance && ServerInstance->stats)
1025 ServerInstance->stats->statsDnsBad++;
1026 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1027 delete Classes[res.id];
1028 Classes[res.id] = NULL;
1034 /* It is a non-error result, marshall the result to the correct class */
1035 if (Classes[res.id])
1037 if (ServerInstance && ServerInstance->stats)
1038 ServerInstance->stats->statsDnsGood++;
1040 if (!this->GetCache(res.original.c_str()))
1041 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1043 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
1044 delete Classes[res.id];
1045 Classes[res.id] = NULL;
1049 if (ServerInstance && ServerInstance->stats)
1050 ServerInstance->stats->statsDns++;
1054 /** Add a derived Resolver to the working set */
1055 bool DNS::AddResolverClass(Resolver* r)
1057 ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
1058 /* Check the pointers validity and the id's validity */
1059 if ((r) && (r->GetId() > -1))
1061 /* Check the slot isnt already occupied -
1062 * This should NEVER happen unless we have
1063 * a severely broken DNS server somewhere
1065 if (!Classes[r->GetId()])
1067 /* Set up the pointer to the class */
1068 Classes[r->GetId()] = r;
1077 /* Pointer or id not valid.
1078 * Free the item and return
1087 void DNS::CleanResolvers(Module* module)
1089 for (int i = 0; i < MAX_REQUEST_ID; i++)
1093 if (Classes[i]->GetCreator() == module)
1095 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");