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 * ---------------------------------------------------
15 dns.cpp - Nonblocking DNS functions.
16 Very very loosely based on the firedns library,
17 Copyright (C) 2002 Ian Gulliver. This file is no
18 longer anything like firedns, there are many major
19 differences between this code and the original.
20 Please do not assume that firedns works like this,
21 looks like this, walks like this or tastes like this.
25 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
31 #include "inspircd_win32wrapper.h"
32 #include "inspircd_se_config.h"
37 #include "socketengine.h"
38 #include "configreader.h"
41 using irc::sockets::insp_inaddr;
42 using irc::sockets::insp_ntoa;
43 using irc::sockets::insp_aton;
44 using irc::sockets::OpenTCPSocket;
46 /** Masks to mask off the responses we get from the DNSRequest methods
50 ERROR_MASK = 0x10000 /* Result is an error */
53 /** Flags which can be ORed into a request or reply for different meanings
57 FLAGS_MASK_RD = 0x01, /* Recursive */
59 FLAGS_MASK_AA = 0x04, /* Authoritative */
60 FLAGS_MASK_OPCODE = 0x78,
62 FLAGS_MASK_RCODE = 0x0F, /* Request */
68 /** Represents a dns resource record (rr)
72 QueryType type; /* Record type */
73 unsigned int rr_class; /* Record class */
74 unsigned long ttl; /* Time to live */
75 unsigned int rdlength; /* Record length */
78 /** Represents a dns request/reply header, and its payload as opaque data.
83 unsigned char id[2]; /* Request id */
84 unsigned int flags1; /* Flags */
85 unsigned int flags2; /* Flags */
87 unsigned int ancount; /* Answer count */
88 unsigned int nscount; /* Nameserver count */
90 unsigned char payload[512]; /* Packet payload */
96 unsigned char id[2]; /* Request id */
97 unsigned char* res; /* Result processing buffer */
98 unsigned int rr_class; /* Request class */
99 QueryType type; /* Request type */
100 DNS* dnsobj; /* DNS caller (where we get our FD from) */
101 unsigned long ttl; /* Time to live */
102 std::string orig; /* Original requested name/ip */
103 InspIRCd* ServerInstance;
105 DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original);
107 DNSInfo ResultIsReady(DNSHeader &h, int length, int result_we_want);
108 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
111 class CacheTimer : public Timer
114 InspIRCd* ServerInstance;
117 CacheTimer(InspIRCd* Instance, DNS* thisdns)
118 : Timer(3600, Instance->Time(), true), ServerInstance(Instance), dns(thisdns) { }
120 virtual void Tick(time_t TIME)
126 class RequestTimeout : public Timer
128 InspIRCd* ServerInstance;
132 RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : Timer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
136 void Tick(time_t TIME)
138 if (ServerInstance->Res->requests[watchid] == watch)
140 /* Still exists, whack it */
141 if (ServerInstance->Res->Classes[watchid])
143 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
144 delete ServerInstance->Res->Classes[watchid];
145 ServerInstance->Res->Classes[watchid] = NULL;
147 ServerInstance->Res->requests[watchid] = NULL;
154 /* Allocate the processing buffer */
155 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original) : dnsobj(dns), ServerInstance(Instance)
157 res = new unsigned char[512];
160 RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);
161 Instance->Timers->AddTimer(RT); /* The timer manager frees this */
164 /* Deallocate the processing buffer */
165 DNSRequest::~DNSRequest()
170 /** Fill a ResourceRecord class based on raw data input */
171 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
173 rr->type = (QueryType)((input[0] << 8) + input[1]);
174 rr->rr_class = (input[2] << 8) + input[3];
175 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
176 rr->rdlength = (input[8] << 8) + input[9];
179 /** Fill a DNSHeader class based on raw data input of a given length */
180 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
182 header->id[0] = input[0];
183 header->id[1] = input[1];
184 header->flags1 = input[2];
185 header->flags2 = input[3];
186 header->qdcount = (input[4] << 8) + input[5];
187 header->ancount = (input[6] << 8) + input[7];
188 header->nscount = (input[8] << 8) + input[9];
189 header->arcount = (input[10] << 8) + input[11];
190 memcpy(header->payload,&input[12],length);
193 /** Empty a DNSHeader class out into raw data, ready for transmission */
194 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
196 output[0] = header->id[0];
197 output[1] = header->id[1];
198 output[2] = header->flags1;
199 output[3] = header->flags2;
200 output[4] = header->qdcount >> 8;
201 output[5] = header->qdcount & 0xFF;
202 output[6] = header->ancount >> 8;
203 output[7] = header->ancount & 0xFF;
204 output[8] = header->nscount >> 8;
205 output[9] = header->nscount & 0xFF;
206 output[10] = header->arcount >> 8;
207 output[11] = header->arcount & 0xFF;
208 memcpy(&output[12],header->payload,length);
211 /** Send requests we have previously built down the UDP socket */
212 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
214 unsigned char payload[sizeof(DNSHeader)];
219 DNS::EmptyHeader(payload,header,length);
222 if (this->dnsobj->socketfamily == AF_INET6)
225 memset(&addr,0,sizeof(addr));
226 memcpy(&addr.sin6_addr,&dnsobj->myserver6,sizeof(addr.sin6_addr));
227 addr.sin6_family = AF_INET6;
228 addr.sin6_port = htons(DNS::QUERY_PORT);
229 if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)
236 memset(&addr,0,sizeof(addr));
237 memcpy(&addr.sin_addr.s_addr,&dnsobj->myserver4,sizeof(addr.sin_addr));
238 addr.sin_family = AF_INET;
239 addr.sin_port = htons(DNS::QUERY_PORT);
240 if (ServerInstance->SE->SendTo(dnsobj, (const char*)payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) != length+12)
246 /** Add a query with a predefined header, and allocate an ID for it. */
247 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
249 /* Is the DNS connection down? */
250 if (this->GetFd() == -1)
254 id = this->PRNG() & DNS::MAX_REQUEST_ID;
256 /* If this id is already 'in flight', pick another. */
258 id = this->PRNG() & DNS::MAX_REQUEST_ID;
260 DNSRequest* req = new DNSRequest(ServerInstance, this, id, original);
262 header->id[0] = req->id[0] = id >> 8;
263 header->id[1] = req->id[1] = id & 0xFF;
264 header->flags1 = FLAGS_MASK_RD;
271 /* At this point we already know the id doesnt exist,
272 * so there needs to be no second check for the ::end()
276 /* According to the C++ spec, new never returns NULL. */
280 int DNS::ClearCache()
282 /* This ensures the buckets are reset to sane levels */
283 int rv = this->cache->size();
285 this->cache = new dnscache();
289 int DNS::PruneCache()
292 dnscache* newcache = new dnscache();
293 for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
294 /* Dont include expired items (theres no point) */
295 if (i->second.CalcTTLRemaining())
296 newcache->insert(*i);
301 this->cache = newcache;
310 if (this->GetFd() > -1)
312 if (ServerInstance && ServerInstance->SE)
313 ServerInstance->SE->DelFd(this);
314 ServerInstance->SE->Shutdown(this, 2);
315 ServerInstance->SE->Close(this);
318 /* Rehash the cache */
323 /* Create initial dns cache */
324 this->cache = new dnscache();
327 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
329 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
330 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
331 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
332 this->ip6munge = true;
335 this->socketfamily = AF_INET;
337 if (strchr(ServerInstance->Config->DNSServer,':'))
339 this->socketfamily = AF_INET6;
340 inet_pton(AF_INET6, ServerInstance->Config->DNSServer, &this->myserver6);
344 inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);
348 inet_aton(ServerInstance->Config->DNSServer, &this->myserver4);
351 /* Initialize mastersocket */
352 int s = OpenTCPSocket(ServerInstance->Config->DNSServer, SOCK_DGRAM);
354 ServerInstance->SE->NonBlocking(this->GetFd());
356 /* Have we got a socket and is it nonblocking? */
357 if (this->GetFd() != -1)
359 /* Bind the port - port 0 INADDR_ANY */
360 if (!ServerInstance->BindSocket(this->GetFd(), portpass, "", false))
363 ServerInstance->SE->Shutdown(this, 2);
364 ServerInstance->SE->Close(this);
368 if (this->GetFd() >= 0)
370 /* Hook the descriptor into the socket engine */
371 if (ServerInstance && ServerInstance->SE)
373 if (!ServerInstance->SE->AddFd(this))
375 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
376 ServerInstance->SE->Shutdown(this, 2);
377 ServerInstance->SE->Close(this);
385 /** Initialise the DNS UDP socket so that we can send requests */
386 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
388 /* Clear the Resolver class table */
389 memset(Classes,0,sizeof(Classes));
391 /* Clear the requests class table */
392 memset(requests,0,sizeof(requests));
394 /* Set the id of the next request to 0
398 /* DNS::Rehash() sets this to a valid ptr
402 /* Again, DNS::Rehash() sets this to a
407 /* Actually read the settings
411 this->PruneTimer = new CacheTimer(ServerInstance, this);
413 ServerInstance->Timers->AddTimer(this->PruneTimer);
416 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
417 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
419 short payloadpos = 0;
420 const char* tempchr, *tempchr2 = name;
421 unsigned short length;
423 /* split name up into labels, create query */
424 while ((tempchr = strchr(tempchr2,'.')) != NULL)
426 length = tempchr - tempchr2;
427 if (payloadpos + length + 1 > 507)
429 payload[payloadpos++] = length;
430 memcpy(&payload[payloadpos],tempchr2,length);
431 payloadpos += length;
432 tempchr2 = &tempchr[1];
434 length = strlen(tempchr2);
437 if (payloadpos + length + 2 > 507)
439 payload[payloadpos++] = length;
440 memcpy(&payload[payloadpos],tempchr2,length);
441 payloadpos += length;
442 payload[payloadpos++] = 0;
444 if (payloadpos > 508)
447 memcpy(&payload[payloadpos],&length,2);
448 length = htons(rr_class);
449 memcpy(&payload[payloadpos + 2],&length,2);
450 return payloadpos + 4;
453 /** Start lookup of an hostname to an IP address */
454 int DNS::GetIP(const char *name)
460 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
463 DNSRequest* req = this->AddQuery(&h, id, name);
465 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
471 /** Start lookup of an hostname to an IPv6 address */
472 int DNS::GetIP6(const char *name)
478 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
481 DNSRequest* req = this->AddQuery(&h, id, name);
483 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
489 /** Start lookup of a cname to another name */
490 int DNS::GetCName(const char *alias)
496 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
499 DNSRequest* req = this->AddQuery(&h, id, alias);
501 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
507 /** Start lookup of an IP address to a hostname */
508 int DNS::GetName(const insp_inaddr *ip)
516 unsigned char* c = (unsigned char*)&ip->s6_addr;
517 if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
518 c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
519 c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
520 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
522 DNS::MakeIP6Int(query, (in6_addr*)ip);
524 unsigned char* c = (unsigned char*)&ip->s_addr;
525 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
528 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
531 DNSRequest* req = this->AddQuery(&h, id, insp_ntoa(*ip));
533 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
539 /** Start lookup of an IP address to a hostname */
540 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
546 #ifdef SUPPORT_IP6LINKS
547 if (fp == PROTOCOL_IPV6)
550 if (inet_pton(AF_INET6, ip, &i) > 0)
552 DNS::MakeIP6Int(query, &i);
555 /* Invalid IP address */
562 if (inet_aton(ip, &i))
564 unsigned char* c = (unsigned char*)&i.s_addr;
565 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
568 /* Invalid IP address */
572 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
575 DNSRequest* req = this->AddQuery(&h, id, ip);
577 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
583 /** Build an ipv6 reverse domain from an in6_addr
585 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
587 #ifdef SUPPORT_IP6LINKS
588 const char* hex = "0123456789abcdef";
589 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
593 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
596 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
597 *query++ = '.'; /* Seperator */
599 strcpy(query,"ip6.arpa"); /* Suffix the string */
605 /** Return the next id which is ready, and the result attached to it */
606 DNSResult DNS::GetResult(int resultnum)
608 /* Fetch dns query response and decide where it belongs */
611 unsigned char buffer[sizeof(DNSHeader)];
612 sockaddr* from = new sockaddr[2];
614 socklen_t x = this->socketfamily == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
616 socklen_t x = sizeof(sockaddr_in);
618 const char* ipaddr_from;
619 unsigned short int port_from = 0;
621 int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, from, &x);
623 /* Did we get the whole header? */
626 /* Nope - something screwed up. */
628 return DNSResult(-1,"",0,"");
631 /* Check wether the reply came from a different DNS
632 * server to the one we sent it to, or the source-port
634 * A user could in theory still spoof dns packets anyway
635 * but this is less trivial than just sending garbage
636 * to the client, which is possible without this check.
638 * -- Thanks jilles for pointing this one out.
642 if (this->socketfamily == AF_INET6)
644 ipaddr_from = inet_ntop(AF_INET6, &((sockaddr_in6*)from)->sin6_addr, nbuf, sizeof(nbuf));
645 port_from = ntohs(((sockaddr_in6*)from)->sin6_port);
650 ipaddr_from = inet_ntoa(((sockaddr_in*)from)->sin_addr);
651 port_from = ntohs(((sockaddr_in*)from)->sin_port);
656 /* We cant perform this security check if you're using 4in6.
657 * Tough luck to you, choose one or't other!
661 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
663 return DNSResult(-1,"",0,"");
667 /* Put the read header info into a header class */
668 DNS::FillHeader(&header,buffer,length - 12);
670 /* Get the id of this request.
671 * Its a 16 bit value stored in two char's,
672 * so we use logic shifts to create the value.
674 unsigned long this_id = header.id[1] + (header.id[0] << 8);
676 /* Do we have a pending request matching this id? */
677 if (!requests[this_id])
679 /* Somehow we got a DNS response for a request we never made... */
680 return DNSResult(-1,"",0,"");
684 /* Remove the query from the list of pending queries */
685 req = requests[this_id];
686 requests[this_id] = NULL;
689 /* Inform the DNSRequest class that it has a result to be read.
690 * When its finished it will return a DNSInfo which is a pair of
691 * unsigned char* resource record data, and an error message.
693 DNSInfo data = req->ResultIsReady(header, length, resultnum);
694 std::string resultstr;
696 /* Check if we got a result, if we didnt, its an error */
697 if (data.first == NULL)
700 * Mask the ID with the value of ERROR_MASK, so that
701 * the dns_deal_with_classes() function knows that its
702 * an error response and needs to be treated uniquely.
703 * Put the error message in the second field.
705 std::string ro = req->orig;
707 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
711 unsigned long ttl = req->ttl;
714 /* Forward lookups come back as binary data. We must format them into ascii */
718 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
719 resultstr = formatted;
724 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
725 char* c = strstr(formatted,":0:");
728 memmove(c+1,c+2,strlen(c+2) + 1);
730 while (memcmp(c,"0:",2) == 0)
731 memmove(c,c+2,strlen(c+2) + 1);
732 if (memcmp(c,"0",2) == 0)
734 if (memcmp(formatted,"0::",3) == 0)
735 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
737 resultstr = formatted;
739 /* Special case. Sending ::1 around between servers
740 * and to clients is dangerous, because the : on the
741 * start makes the client or server interpret the IP
742 * as the last parameter on the line with a value ":1".
744 if (*formatted == ':')
745 resultstr.insert(0, "0");
749 case DNS_QUERY_CNAME:
750 /* Identical handling to PTR */
753 /* Reverse lookups just come back as char* */
754 resultstr = std::string((const char*)data.first);
762 /* Build the reply with the id and hostname/ip in it */
763 std::string ro = req->orig;
765 return DNSResult(this_id,resultstr,ttl,ro);
769 /** A result is ready, process it */
770 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length, int result_we_want)
778 /* This is just to keep _FORTIFY_SOURCE happy */
779 rr.type = DNS_QUERY_NONE;
781 rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
783 if (!(header.flags1 & FLAGS_MASK_QR))
784 return std::make_pair((unsigned char*)NULL,"Not a query result");
786 if (header.flags1 & FLAGS_MASK_OPCODE)
787 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
789 if (header.flags2 & FLAGS_MASK_RCODE)
790 return std::make_pair((unsigned char*)NULL,"Domain name not found");
792 if (header.ancount < 1)
793 return std::make_pair((unsigned char*)NULL,"No resource records returned");
795 /* Subtract the length of the header from the length of the packet */
798 while ((unsigned int)q < header.qdcount && i < length)
800 if (header.payload[i] > 63)
807 if (header.payload[i] == 0)
812 else i += header.payload[i] + 1;
816 while ((unsigned)curanswer < header.ancount)
819 while (q == 0 && i < length)
821 if (header.payload[i] > 63)
828 if (header.payload[i] == 0)
833 else i += header.payload[i] + 1; /* skip length and label */
837 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
839 /* XXX: We actually initialise 'rr' here including its ttl field */
840 if (curanswer == result_we_want)
841 DNS::FillResourceRecord(&rr,&header.payload[i]);
844 if (rr.type != this->type)
850 if (rr.rr_class != this->rr_class)
858 if ((unsigned int)curanswer == header.ancount)
859 return std::make_pair((unsigned char*)NULL,"No more records");
861 if (i + rr.rdlength > (unsigned int)length)
862 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
864 if (rr.rdlength > 1023)
865 return std::make_pair((unsigned char*)NULL,"Resource record too large");
871 case DNS_QUERY_CNAME:
872 /* CNAME and PTR have the same processing code */
876 while (q == 0 && i < length && o + 256 < 1023)
878 if (header.payload[i] > 63)
880 memcpy(&ptr,&header.payload[i],2);
881 i = ntohs(ptr) - 0xC000 - 12;
885 if (header.payload[i] == 0)
894 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
895 o += header.payload[i];
896 i += header.payload[i] + 1;
903 memcpy(res,&header.payload[i],rr.rdlength);
904 res[rr.rdlength] = 0;
907 memcpy(res,&header.payload[i],rr.rdlength);
908 res[rr.rdlength] = 0;
911 memcpy(res,&header.payload[i],rr.rdlength);
912 res[rr.rdlength] = 0;
915 return std::make_pair(res,"No error");
918 /** Close the master socket */
921 ServerInstance->SE->Shutdown(this, 2);
922 ServerInstance->SE->Close(this);
923 ServerInstance->Timers->DelTimer(this->PruneTimer);
924 delete this->PruneTimer;
927 CachedQuery* DNS::GetCache(const std::string &source)
929 dnscache::iterator x = cache->find(source.c_str());
930 if (x != cache->end())
936 void DNS::DelCache(const std::string &source)
938 cache->erase(source.c_str());
941 void Resolver::TriggerCachedResult()
944 OnLookupComplete(CQ->data, time_left, true, 0);
947 /** High level abstraction of dns used by application at large */
948 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
952 CQ = ServerInstance->Res->GetCache(source);
955 time_left = CQ->CalcTTLRemaining();
958 ServerInstance->Res->DelCache(source);
972 this->myid = ServerInstance->Res->GetIP(source.c_str());
976 if (insp_aton(source.c_str(), &binip) > 0)
978 /* Valid ip address */
979 this->myid = ServerInstance->Res->GetName(&binip);
983 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
984 throw ModuleException("Resolver: Bad IP address");
990 querytype = DNS_QUERY_PTR;
991 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
995 querytype = DNS_QUERY_PTR;
996 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
1000 this->myid = ServerInstance->Res->GetIP6(source.c_str());
1003 case DNS_QUERY_CNAME:
1004 this->myid = ServerInstance->Res->GetCName(source.c_str());
1011 if (this->myid == -1)
1013 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
1014 throw ModuleException("Resolver: Couldnt get an id to make a request");
1015 /* We shouldnt get here really */
1020 /** Called when an error occurs */
1021 void Resolver::OnError(ResolverError e, const std::string &errormessage)
1023 /* Nothing in here */
1026 /** Destroy a resolver */
1027 Resolver::~Resolver()
1029 /* Nothing here (yet) either */
1032 /** Get the request id associated with this class */
1033 int Resolver::GetId()
1038 Module* Resolver::GetCreator()
1040 return this->Creator;
1043 /** Process a socket read event */
1044 void DNS::HandleEvent(EventType et, int errornum)
1046 /* Fetch the id and result of the next available packet */
1048 DNSResult res(0,"",0,"");
1050 ServerInstance->Log(DEBUG,"Handle DNS event");
1051 while ((res.id & ERROR_MASK) == 0)
1053 res = this->GetResult(resultnum);
1055 ServerInstance->Log(DEBUG,"Result %d id %d", resultnum, res.id);
1057 /* Is there a usable request id? */
1060 /* Its an error reply */
1061 if (res.id & ERROR_MASK)
1063 /* Mask off the error bit */
1064 res.id -= ERROR_MASK;
1065 /* Marshall the error to the correct class */
1066 if (Classes[res.id])
1068 if (ServerInstance && ServerInstance->stats)
1069 ServerInstance->stats->statsDnsBad++;
1070 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1071 delete Classes[res.id];
1072 Classes[res.id] = NULL;
1078 /* It is a non-error result, marshall the result to the correct class */
1079 if (Classes[res.id])
1081 if (ServerInstance && ServerInstance->stats)
1082 ServerInstance->stats->statsDnsGood++;
1084 if (!this->GetCache(res.original.c_str()))
1085 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1087 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false, resultnum);
1088 delete Classes[res.id];
1089 Classes[res.id] = NULL;
1093 if (ServerInstance && ServerInstance->stats)
1094 ServerInstance->stats->statsDns++;
1101 /** Add a derived Resolver to the working set */
1102 bool DNS::AddResolverClass(Resolver* r)
1104 /* Check the pointers validity and the id's validity */
1105 if ((r) && (r->GetId() > -1))
1107 /* Check the slot isnt already occupied -
1108 * This should NEVER happen unless we have
1109 * a severely broken DNS server somewhere
1111 if (!Classes[r->GetId()])
1113 /* Set up the pointer to the class */
1114 Classes[r->GetId()] = r;
1123 /* Pointer or id not valid.
1124 * Free the item and return
1133 void DNS::CleanResolvers(Module* module)
1135 for (int i = 0; i < MAX_REQUEST_ID; i++)
1139 if (Classes[i]->GetCreator() == module)
1141 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1149 /** Generate pseudo-random number */
1150 unsigned long DNS::PRNG()
1152 unsigned long val = 0;
1154 serverstats* s = ServerInstance->stats;
1155 gettimeofday(&n,NULL);
1156 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1157 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1158 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - ServerInstance->Config->ports.size();