1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2007 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
14 /* $Core: libIRCDasyncdns */
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"
34 #include "inspircd_se_config.h"
39 #include "socketengine.h"
40 #include "configreader.h"
43 using irc::sockets::insp_inaddr;
44 using irc::sockets::insp_ntoa;
45 using irc::sockets::insp_aton;
46 using irc::sockets::OpenTCPSocket;
48 /** Masks to mask off the responses we get from the DNSRequest methods
52 ERROR_MASK = 0x10000 /* Result is an error */
55 /** Flags which can be ORed into a request or reply for different meanings
59 FLAGS_MASK_RD = 0x01, /* Recursive */
61 FLAGS_MASK_AA = 0x04, /* Authoritative */
62 FLAGS_MASK_OPCODE = 0x78,
64 FLAGS_MASK_RCODE = 0x0F, /* Request */
70 /** Represents a dns resource record (rr)
74 QueryType type; /* Record type */
75 unsigned int rr_class; /* Record class */
76 unsigned long ttl; /* Time to live */
77 unsigned int rdlength; /* Record length */
80 /** Represents a dns request/reply header, and its payload as opaque data.
85 unsigned char id[2]; /* Request id */
86 unsigned int flags1; /* Flags */
87 unsigned int flags2; /* Flags */
89 unsigned int ancount; /* Answer count */
90 unsigned int nscount; /* Nameserver count */
92 unsigned char payload[512]; /* Packet payload */
98 unsigned char id[2]; /* Request id */
99 unsigned char* res; /* Result processing buffer */
100 unsigned int rr_class; /* Request class */
101 QueryType type; /* Request type */
102 DNS* dnsobj; /* DNS caller (where we get our FD from) */
103 unsigned long ttl; /* Time to live */
104 std::string orig; /* Original requested name/ip */
105 InspIRCd* ServerInstance;
107 DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original);
109 DNSInfo ResultIsReady(DNSHeader &h, int length, int result_we_want);
110 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
113 class CacheTimer : public Timer
116 InspIRCd* ServerInstance;
119 CacheTimer(InspIRCd* Instance, DNS* thisdns)
120 : Timer(3600, Instance->Time(), true), ServerInstance(Instance), dns(thisdns) { }
122 virtual void Tick(time_t)
128 class RequestTimeout : public Timer
130 InspIRCd* ServerInstance;
134 RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : Timer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
140 if (ServerInstance->Res->requests[watchid] == watch)
142 /* Still exists, whack it */
143 if (ServerInstance->Res->Classes[watchid])
145 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
146 delete ServerInstance->Res->Classes[watchid];
147 ServerInstance->Res->Classes[watchid] = NULL;
149 ServerInstance->Res->requests[watchid] = NULL;
156 /* Allocate the processing buffer */
157 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original) : dnsobj(dns), ServerInstance(Instance)
159 res = new unsigned char[512];
162 RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);
163 Instance->Timers->AddTimer(RT); /* The timer manager frees this */
166 /* Deallocate the processing buffer */
167 DNSRequest::~DNSRequest()
172 /** Fill a ResourceRecord class based on raw data input */
173 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
175 rr->type = (QueryType)((input[0] << 8) + input[1]);
176 rr->rr_class = (input[2] << 8) + input[3];
177 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
178 rr->rdlength = (input[8] << 8) + input[9];
181 /** Fill a DNSHeader class based on raw data input of a given length */
182 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
184 header->id[0] = input[0];
185 header->id[1] = input[1];
186 header->flags1 = input[2];
187 header->flags2 = input[3];
188 header->qdcount = (input[4] << 8) + input[5];
189 header->ancount = (input[6] << 8) + input[7];
190 header->nscount = (input[8] << 8) + input[9];
191 header->arcount = (input[10] << 8) + input[11];
192 memcpy(header->payload,&input[12],length);
195 /** Empty a DNSHeader class out into raw data, ready for transmission */
196 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
198 output[0] = header->id[0];
199 output[1] = header->id[1];
200 output[2] = header->flags1;
201 output[3] = header->flags2;
202 output[4] = header->qdcount >> 8;
203 output[5] = header->qdcount & 0xFF;
204 output[6] = header->ancount >> 8;
205 output[7] = header->ancount & 0xFF;
206 output[8] = header->nscount >> 8;
207 output[9] = header->nscount & 0xFF;
208 output[10] = header->arcount >> 8;
209 output[11] = header->arcount & 0xFF;
210 memcpy(&output[12],header->payload,length);
213 /** Send requests we have previously built down the UDP socket */
214 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
216 unsigned char payload[sizeof(DNSHeader)];
221 DNS::EmptyHeader(payload,header,length);
224 if (this->dnsobj->socketfamily == AF_INET6)
227 memset(&addr,0,sizeof(addr));
228 memcpy(&addr.sin6_addr,&dnsobj->myserver6,sizeof(addr.sin6_addr));
229 addr.sin6_family = AF_INET6;
230 addr.sin6_port = htons(DNS::QUERY_PORT);
231 if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)
238 memset(&addr,0,sizeof(addr));
239 memcpy(&addr.sin_addr.s_addr,&dnsobj->myserver4,sizeof(addr.sin_addr));
240 addr.sin_family = AF_INET;
241 addr.sin_port = htons(DNS::QUERY_PORT);
242 if (ServerInstance->SE->SendTo(dnsobj, (const char*)payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)
248 /** Add a query with a predefined header, and allocate an ID for it. */
249 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
251 /* Is the DNS connection down? */
252 if (this->GetFd() == -1)
256 id = this->PRNG() & DNS::MAX_REQUEST_ID;
258 /* If this id is already 'in flight', pick another. */
260 id = this->PRNG() & DNS::MAX_REQUEST_ID;
262 DNSRequest* req = new DNSRequest(ServerInstance, this, id, original);
264 header->id[0] = req->id[0] = id >> 8;
265 header->id[1] = req->id[1] = id & 0xFF;
266 header->flags1 = FLAGS_MASK_RD;
273 /* At this point we already know the id doesnt exist,
274 * so there needs to be no second check for the ::end()
278 /* According to the C++ spec, new never returns NULL. */
282 int DNS::ClearCache()
284 /* This ensures the buckets are reset to sane levels */
285 int rv = this->cache->size();
287 this->cache = new dnscache();
291 int DNS::PruneCache()
294 dnscache* newcache = new dnscache();
295 for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
296 /* Dont include expired items (theres no point) */
297 if (i->second.CalcTTLRemaining())
298 newcache->insert(*i);
303 this->cache = newcache;
312 if (this->GetFd() > -1)
314 if (ServerInstance && ServerInstance->SE)
315 ServerInstance->SE->DelFd(this);
316 ServerInstance->SE->Shutdown(this, 2);
317 ServerInstance->SE->Close(this);
320 /* Rehash the cache */
325 /* Create initial dns cache */
326 this->cache = new dnscache();
329 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
331 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
332 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
333 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
334 this->ip6munge = true;
337 this->socketfamily = AF_INET;
339 if (strchr(ServerInstance->Config->DNSServer,':'))
341 this->socketfamily = AF_INET6;
342 inet_pton(AF_INET6, ServerInstance->Config->DNSServer, &this->myserver6);
346 inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);
350 inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);
353 /* Initialize mastersocket */
354 int s = OpenTCPSocket(ServerInstance->Config->DNSServer, SOCK_DGRAM);
356 ServerInstance->SE->NonBlocking(this->GetFd());
358 /* Have we got a socket and is it nonblocking? */
359 if (this->GetFd() != -1)
361 /* Bind the port - port 0 INADDR_ANY */
362 if (!ServerInstance->BindSocket(this->GetFd(), portpass, "", false))
365 ServerInstance->SE->Shutdown(this, 2);
366 ServerInstance->SE->Close(this);
370 if (this->GetFd() >= 0)
372 /* Hook the descriptor into the socket engine */
373 if (ServerInstance && ServerInstance->SE)
375 if (!ServerInstance->SE->AddFd(this))
377 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
378 ServerInstance->SE->Shutdown(this, 2);
379 ServerInstance->SE->Close(this);
387 /** Initialise the DNS UDP socket so that we can send requests */
388 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
390 /* Clear the Resolver class table */
391 memset(Classes,0,sizeof(Classes));
393 /* Clear the requests class table */
394 memset(requests,0,sizeof(requests));
396 /* Set the id of the next request to 0
400 /* DNS::Rehash() sets this to a valid ptr
404 /* Again, DNS::Rehash() sets this to a
409 /* Actually read the settings
413 this->PruneTimer = new CacheTimer(ServerInstance, this);
415 ServerInstance->Timers->AddTimer(this->PruneTimer);
418 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
419 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
421 short payloadpos = 0;
422 const char* tempchr, *tempchr2 = name;
423 unsigned short length;
425 /* split name up into labels, create query */
426 while ((tempchr = strchr(tempchr2,'.')) != NULL)
428 length = tempchr - tempchr2;
429 if (payloadpos + length + 1 > 507)
431 payload[payloadpos++] = length;
432 memcpy(&payload[payloadpos],tempchr2,length);
433 payloadpos += length;
434 tempchr2 = &tempchr[1];
436 length = strlen(tempchr2);
439 if (payloadpos + length + 2 > 507)
441 payload[payloadpos++] = length;
442 memcpy(&payload[payloadpos],tempchr2,length);
443 payloadpos += length;
444 payload[payloadpos++] = 0;
446 if (payloadpos > 508)
449 memcpy(&payload[payloadpos],&length,2);
450 length = htons(rr_class);
451 memcpy(&payload[payloadpos + 2],&length,2);
452 return payloadpos + 4;
455 /** Start lookup of an hostname to an IP address */
456 int DNS::GetIP(const char *name)
462 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
465 DNSRequest* req = this->AddQuery(&h, id, name);
467 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
473 /** Start lookup of an hostname to an IPv6 address */
474 int DNS::GetIP6(const char *name)
480 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
483 DNSRequest* req = this->AddQuery(&h, id, name);
485 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
491 /** Start lookup of a cname to another name */
492 int DNS::GetCName(const char *alias)
498 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
501 DNSRequest* req = this->AddQuery(&h, id, alias);
503 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
509 /** Start lookup of an IP address to a hostname */
510 int DNS::GetName(const insp_inaddr *ip)
518 unsigned char* c = (unsigned char*)&ip->s6_addr;
519 if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
520 c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
521 c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
522 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
524 DNS::MakeIP6Int(query, (in6_addr*)ip);
526 unsigned char* c = (unsigned char*)&ip->s_addr;
527 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
530 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
533 DNSRequest* req = this->AddQuery(&h, id, insp_ntoa(*ip));
535 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
541 /** Start lookup of an IP address to a hostname */
542 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
548 #ifdef SUPPORT_IP6LINKS
549 if (fp == PROTOCOL_IPV6)
552 if (inet_pton(AF_INET6, ip, &i) > 0)
554 DNS::MakeIP6Int(query, &i);
557 /* Invalid IP address */
564 if (inet_aton(ip, &i))
566 unsigned char* c = (unsigned char*)&i.s_addr;
567 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
570 /* Invalid IP address */
574 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
577 DNSRequest* req = this->AddQuery(&h, id, ip);
579 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
585 /** Build an ipv6 reverse domain from an in6_addr
587 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
589 #ifdef SUPPORT_IP6LINKS
590 const char* hex = "0123456789abcdef";
591 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
595 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
598 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
599 *query++ = '.'; /* Seperator */
601 strcpy(query,"ip6.arpa"); /* Suffix the string */
607 /** Return the next id which is ready, and the result attached to it */
608 DNSResult DNS::GetResult(int resultnum)
610 /* Fetch dns query response and decide where it belongs */
613 unsigned char buffer[sizeof(DNSHeader)];
614 sockaddr* from = new sockaddr[2];
616 socklen_t x = this->socketfamily == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
618 socklen_t x = sizeof(sockaddr_in);
620 const char* ipaddr_from;
621 unsigned short int port_from = 0;
623 int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, from, &x);
625 /* Did we get the whole header? */
628 /* Nope - something screwed up. */
630 return DNSResult(-1,"",0,"");
633 /* Check wether the reply came from a different DNS
634 * server to the one we sent it to, or the source-port
636 * A user could in theory still spoof dns packets anyway
637 * but this is less trivial than just sending garbage
638 * to the client, which is possible without this check.
640 * -- Thanks jilles for pointing this one out.
644 if (this->socketfamily == AF_INET6)
646 ipaddr_from = inet_ntop(AF_INET6, &((sockaddr_in6*)from)->sin6_addr, nbuf, sizeof(nbuf));
647 port_from = ntohs(((sockaddr_in6*)from)->sin6_port);
652 ipaddr_from = inet_ntoa(((sockaddr_in*)from)->sin_addr);
653 port_from = ntohs(((sockaddr_in*)from)->sin_port);
658 /* We cant perform this security check if you're using 4in6.
659 * Tough luck to you, choose one or't other!
663 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
665 return DNSResult(-1,"",0,"");
669 /* Put the read header info into a header class */
670 DNS::FillHeader(&header,buffer,length - 12);
672 /* Get the id of this request.
673 * Its a 16 bit value stored in two char's,
674 * so we use logic shifts to create the value.
676 unsigned long this_id = header.id[1] + (header.id[0] << 8);
678 /* Do we have a pending request matching this id? */
679 if (!requests[this_id])
681 /* Somehow we got a DNS response for a request we never made... */
682 return DNSResult(-1,"",0,"");
686 /* Remove the query from the list of pending queries */
687 req = requests[this_id];
688 requests[this_id] = NULL;
691 /* Inform the DNSRequest class that it has a result to be read.
692 * When its finished it will return a DNSInfo which is a pair of
693 * unsigned char* resource record data, and an error message.
695 DNSInfo data = req->ResultIsReady(header, length, resultnum);
696 std::string resultstr;
698 /* Check if we got a result, if we didnt, its an error */
699 if (data.first == NULL)
702 * Mask the ID with the value of ERROR_MASK, so that
703 * the dns_deal_with_classes() function knows that its
704 * an error response and needs to be treated uniquely.
705 * Put the error message in the second field.
707 std::string ro = req->orig;
709 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
713 unsigned long ttl = req->ttl;
716 /* Forward lookups come back as binary data. We must format them into ascii */
720 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
721 resultstr = formatted;
726 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
727 char* c = strstr(formatted,":0:");
730 memmove(c+1,c+2,strlen(c+2) + 1);
732 while (memcmp(c,"0:",2) == 0)
733 memmove(c,c+2,strlen(c+2) + 1);
734 if (memcmp(c,"0",2) == 0)
736 if (memcmp(formatted,"0::",3) == 0)
737 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
739 resultstr = formatted;
741 /* Special case. Sending ::1 around between servers
742 * and to clients is dangerous, because the : on the
743 * start makes the client or server interpret the IP
744 * as the last parameter on the line with a value ":1".
746 if (*formatted == ':')
747 resultstr.insert(0, "0");
751 case DNS_QUERY_CNAME:
752 /* Identical handling to PTR */
755 /* Reverse lookups just come back as char* */
756 resultstr = std::string((const char*)data.first);
764 /* Build the reply with the id and hostname/ip in it */
765 std::string ro = req->orig;
767 return DNSResult(this_id,resultstr,ttl,ro);
771 /** A result is ready, process it */
772 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length, int result_we_want)
780 /* This is just to keep _FORTIFY_SOURCE happy */
781 rr.type = DNS_QUERY_NONE;
783 rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
785 if (!(header.flags1 & FLAGS_MASK_QR))
786 return std::make_pair((unsigned char*)NULL,"Not a query result");
788 if (header.flags1 & FLAGS_MASK_OPCODE)
789 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
791 if (header.flags2 & FLAGS_MASK_RCODE)
792 return std::make_pair((unsigned char*)NULL,"Domain name not found");
794 if (header.ancount < 1)
795 return std::make_pair((unsigned char*)NULL,"No resource records returned");
797 /* Subtract the length of the header from the length of the packet */
800 while ((unsigned int)q < header.qdcount && i < length)
802 if (header.payload[i] > 63)
809 if (header.payload[i] == 0)
814 else i += header.payload[i] + 1;
818 while ((unsigned)curanswer < header.ancount)
821 while (q == 0 && i < length)
823 if (header.payload[i] > 63)
830 if (header.payload[i] == 0)
835 else i += header.payload[i] + 1; /* skip length and label */
839 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
841 /* XXX: We actually initialise 'rr' here including its ttl field */
842 if (curanswer == result_we_want)
843 DNS::FillResourceRecord(&rr,&header.payload[i]);
846 if (rr.type != this->type)
852 if (rr.rr_class != this->rr_class)
860 if ((unsigned int)curanswer == header.ancount)
861 return std::make_pair((unsigned char*)NULL,"No more records");
863 if (i + rr.rdlength > (unsigned int)length)
864 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
866 if (rr.rdlength > 1023)
867 return std::make_pair((unsigned char*)NULL,"Resource record too large");
873 case DNS_QUERY_CNAME:
874 /* CNAME and PTR have the same processing code */
878 while (q == 0 && i < length && o + 256 < 1023)
880 if (header.payload[i] > 63)
882 memcpy(&ptr,&header.payload[i],2);
883 i = ntohs(ptr) - 0xC000 - 12;
887 if (header.payload[i] == 0)
896 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
897 o += header.payload[i];
898 i += header.payload[i] + 1;
905 memcpy(res,&header.payload[i],rr.rdlength);
906 res[rr.rdlength] = 0;
909 memcpy(res,&header.payload[i],rr.rdlength);
910 res[rr.rdlength] = 0;
913 memcpy(res,&header.payload[i],rr.rdlength);
914 res[rr.rdlength] = 0;
917 return std::make_pair(res,"No error");
920 /** Close the master socket */
923 ServerInstance->SE->Shutdown(this, 2);
924 ServerInstance->SE->Close(this);
925 ServerInstance->Timers->DelTimer(this->PruneTimer);
926 delete this->PruneTimer;
929 CachedQuery* DNS::GetCache(const std::string &source)
931 dnscache::iterator x = cache->find(source.c_str());
932 if (x != cache->end())
938 void DNS::DelCache(const std::string &source)
940 cache->erase(source.c_str());
943 void Resolver::TriggerCachedResult()
946 OnLookupComplete(CQ->data, time_left, true, 0);
949 /** High level abstraction of dns used by application at large */
950 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
954 CQ = ServerInstance->Res->GetCache(source);
957 time_left = CQ->CalcTTLRemaining();
960 ServerInstance->Res->DelCache(source);
974 this->myid = ServerInstance->Res->GetIP(source.c_str());
978 if (insp_aton(source.c_str(), &binip) > 0)
980 /* Valid ip address */
981 this->myid = ServerInstance->Res->GetName(&binip);
985 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
986 throw ModuleException("Resolver: Bad IP address");
992 querytype = DNS_QUERY_PTR;
993 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
997 querytype = DNS_QUERY_PTR;
998 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
1001 case DNS_QUERY_AAAA:
1002 this->myid = ServerInstance->Res->GetIP6(source.c_str());
1005 case DNS_QUERY_CNAME:
1006 this->myid = ServerInstance->Res->GetCName(source.c_str());
1013 if (this->myid == -1)
1015 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
1016 throw ModuleException("Resolver: Couldnt get an id to make a request");
1017 /* We shouldnt get here really */
1022 /** Called when an error occurs */
1023 void Resolver::OnError(ResolverError, const std::string&)
1025 /* Nothing in here */
1028 /** Destroy a resolver */
1029 Resolver::~Resolver()
1031 /* Nothing here (yet) either */
1034 /** Get the request id associated with this class */
1035 int Resolver::GetId()
1040 Module* Resolver::GetCreator()
1042 return this->Creator;
1045 /** Process a socket read event */
1046 void DNS::HandleEvent(EventType, int)
1048 /* Fetch the id and result of the next available packet */
1050 DNSResult res(0,"",0,"");
1052 ServerInstance->Log(DEBUG,"Handle DNS event");
1053 while ((res.id & ERROR_MASK) == 0)
1055 res = this->GetResult(resultnum);
1057 ServerInstance->Log(DEBUG,"Result %d id %d", resultnum, res.id);
1059 /* Is there a usable request id? */
1062 /* Its an error reply */
1063 if (res.id & ERROR_MASK)
1065 /* Mask off the error bit */
1066 res.id -= ERROR_MASK;
1067 /* Marshall the error to the correct class */
1068 if (Classes[res.id])
1070 if (ServerInstance && ServerInstance->stats)
1071 ServerInstance->stats->statsDnsBad++;
1072 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1073 delete Classes[res.id];
1074 Classes[res.id] = NULL;
1080 /* It is a non-error result, marshall the result to the correct class */
1081 if (Classes[res.id])
1083 if (ServerInstance && ServerInstance->stats)
1084 ServerInstance->stats->statsDnsGood++;
1086 if (!this->GetCache(res.original.c_str()))
1087 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1089 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false, resultnum);
1090 delete Classes[res.id];
1091 Classes[res.id] = NULL;
1095 if (ServerInstance && ServerInstance->stats)
1096 ServerInstance->stats->statsDns++;
1103 /** Add a derived Resolver to the working set */
1104 bool DNS::AddResolverClass(Resolver* r)
1106 /* Check the pointers validity and the id's validity */
1107 if ((r) && (r->GetId() > -1))
1109 /* Check the slot isnt already occupied -
1110 * This should NEVER happen unless we have
1111 * a severely broken DNS server somewhere
1113 if (!Classes[r->GetId()])
1115 /* Set up the pointer to the class */
1116 Classes[r->GetId()] = r;
1125 /* Pointer or id not valid.
1126 * Free the item and return
1135 void DNS::CleanResolvers(Module* module)
1137 for (int i = 0; i < MAX_REQUEST_ID; i++)
1141 if (Classes[i]->GetCreator() == module)
1143 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1151 /** Generate pseudo-random number */
1152 unsigned long DNS::PRNG()
1154 unsigned long val = 0;
1156 serverstats* s = ServerInstance->stats;
1157 gettimeofday(&n,NULL);
1158 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1159 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1160 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - ServerInstance->Config->ports.size();