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.
24 #include <sys/types.h>
25 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
31 #include "socketengine.h"
32 #include "configreader.h"
35 using irc::sockets::insp_sockaddr;
36 using irc::sockets::insp_inaddr;
37 using irc::sockets::insp_ntoa;
38 using irc::sockets::insp_aton;
40 /** Masks to mask off the responses we get from the DNSRequest methods
44 ERROR_MASK = 0x10000 /* Result is an error */
47 /** Flags which can be ORed into a request or reply for different meanings
51 FLAGS_MASK_RD = 0x01, /* Recursive */
53 FLAGS_MASK_AA = 0x04, /* Authoritative */
54 FLAGS_MASK_OPCODE = 0x78,
56 FLAGS_MASK_RCODE = 0x0F, /* Request */
62 /** Represents a dns resource record (rr)
66 QueryType type; /* Record type */
67 unsigned int rr_class; /* Record class */
68 unsigned long ttl; /* Time to live */
69 unsigned int rdlength; /* Record length */
72 /** Represents a dns request/reply header, and its payload as opaque data.
77 unsigned char id[2]; /* Request id */
78 unsigned int flags1; /* Flags */
79 unsigned int flags2; /* Flags */
81 unsigned int ancount; /* Answer count */
82 unsigned int nscount; /* Nameserver count */
84 unsigned char payload[512]; /* Packet payload */
90 unsigned char id[2]; /* Request id */
91 unsigned char* res; /* Result processing buffer */
92 unsigned int rr_class; /* Request class */
93 QueryType type; /* Request type */
94 insp_inaddr myserver; /* DNS server address*/
95 DNS* dnsobj; /* DNS caller (where we get our FD from) */
96 unsigned long ttl; /* Time to live */
97 std::string orig; /* Original requested name/ip */
99 DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, const std::string &original);
101 DNSInfo ResultIsReady(DNSHeader &h, int length);
102 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
105 class CacheTimer : public InspTimer
108 InspIRCd* ServerInstance;
111 CacheTimer(InspIRCd* Instance, DNS* thisdns)
112 : InspTimer(3600, Instance->Time(), true), ServerInstance(Instance), dns(thisdns) { }
114 virtual void Tick(time_t TIME)
120 class RequestTimeout : public InspTimer
122 InspIRCd* ServerInstance;
126 RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
130 void Tick(time_t TIME)
132 if (ServerInstance->Res->requests[watchid] == watch)
134 /* Still exists, whack it */
135 if (ServerInstance->Res->Classes[watchid])
137 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
138 delete ServerInstance->Res->Classes[watchid];
139 ServerInstance->Res->Classes[watchid] = NULL;
141 ServerInstance->Res->requests[watchid] = NULL;
148 /* Allocate the processing buffer */
149 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, const std::string &original) : dnsobj(dns)
151 res = new unsigned char[512];
153 memcpy(&myserver, &server, sizeof(insp_inaddr));
155 RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);
156 Instance->Timers->AddTimer(RT); /* The timer manager frees this */
159 /* Deallocate the processing buffer */
160 DNSRequest::~DNSRequest()
165 /** Fill a ResourceRecord class based on raw data input */
166 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
168 rr->type = (QueryType)((input[0] << 8) + input[1]);
169 rr->rr_class = (input[2] << 8) + input[3];
170 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
171 rr->rdlength = (input[8] << 8) + input[9];
174 /** Fill a DNSHeader class based on raw data input of a given length */
175 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
177 header->id[0] = input[0];
178 header->id[1] = input[1];
179 header->flags1 = input[2];
180 header->flags2 = input[3];
181 header->qdcount = (input[4] << 8) + input[5];
182 header->ancount = (input[6] << 8) + input[7];
183 header->nscount = (input[8] << 8) + input[9];
184 header->arcount = (input[10] << 8) + input[11];
185 memcpy(header->payload,&input[12],length);
188 /** Empty a DNSHeader class out into raw data, ready for transmission */
189 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
191 output[0] = header->id[0];
192 output[1] = header->id[1];
193 output[2] = header->flags1;
194 output[3] = header->flags2;
195 output[4] = header->qdcount >> 8;
196 output[5] = header->qdcount & 0xFF;
197 output[6] = header->ancount >> 8;
198 output[7] = header->ancount & 0xFF;
199 output[8] = header->nscount >> 8;
200 output[9] = header->nscount & 0xFF;
201 output[10] = header->arcount >> 8;
202 output[11] = header->arcount & 0xFF;
203 memcpy(&output[12],header->payload,length);
206 /** Send requests we have previously built down the UDP socket */
207 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
210 unsigned char payload[sizeof(DNSHeader)];
215 DNS::EmptyHeader(payload,header,length);
217 memset(&addr,0,sizeof(addr));
219 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
220 addr.sin6_family = AF_FAMILY;
221 addr.sin6_port = htons(DNS::QUERY_PORT);
223 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
224 addr.sin_family = AF_FAMILY;
225 addr.sin_port = htons(DNS::QUERY_PORT);
227 if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
233 /** Add a query with a predefined header, and allocate an ID for it. */
234 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
236 /* Is the DNS connection down? */
237 if (this->GetFd() == -1)
241 id = this->PRNG() & DNS::MAX_REQUEST_ID;
243 /* If this id is already 'in flight', pick another. */
245 id = this->PRNG() & DNS::MAX_REQUEST_ID;
247 DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id, original);
249 header->id[0] = req->id[0] = id >> 8;
250 header->id[1] = req->id[1] = id & 0xFF;
251 header->flags1 = FLAGS_MASK_RD;
258 /* At this point we already know the id doesnt exist,
259 * so there needs to be no second check for the ::end()
263 /* According to the C++ spec, new never returns NULL. */
267 int DNS::ClearCache()
269 /* This ensures the buckets are reset to sane levels */
270 int rv = this->cache->size();
272 this->cache = new dnscache();
276 int DNS::PruneCache()
279 dnscache* newcache = new dnscache();
280 for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
281 /* Dont include expired items (theres no point) */
282 if (i->second.CalcTTLRemaining())
283 newcache->insert(*i);
288 this->cache = newcache;
297 if (this->GetFd() > -1)
299 if (ServerInstance && ServerInstance->SE)
300 ServerInstance->SE->DelFd(this);
301 shutdown(this->GetFd(), 2);
302 close(this->GetFd());
305 /* Rehash the cache */
310 /* Create initial dns cache */
311 this->cache = new dnscache();
314 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
316 memcpy(&myserver,&addr,sizeof(insp_inaddr));
317 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
319 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
320 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
321 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
322 this->ip6munge = true;
326 /* Initialize mastersocket */
327 this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
328 if (this->GetFd() != -1)
330 /* Did it succeed? */
331 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
333 /* Couldn't make the socket nonblocking */
334 shutdown(this->GetFd(),2);
335 close(this->GetFd());
340 /* Have we got a socket and is it nonblocking? */
341 if (this->GetFd() != -1)
345 memset(&addr,0,sizeof(addr));
346 addr.sin6_family = AF_FAMILY;
348 addr.sin6_addr = in6addr_any;
351 memset(&addr,0,sizeof(addr));
352 addr.sin_family = AF_FAMILY;
354 addr.sin_addr.s_addr = INADDR_ANY;
357 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
360 shutdown(this->GetFd(),2);
361 close(this->GetFd());
365 if (this->GetFd() >= 0)
367 /* Hook the descriptor into the socket engine */
368 if (ServerInstance && ServerInstance->SE)
370 if (!ServerInstance->SE->AddFd(this))
372 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
373 shutdown(this->GetFd(),2);
374 close(this->GetFd());
382 /** Initialise the DNS UDP socket so that we can send requests */
383 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
385 /* Clear the Resolver class table */
386 memset(Classes,0,sizeof(Classes));
388 /* Clear the requests class table */
389 memset(requests,0,sizeof(requests));
391 /* Set the id of the next request to 0
395 /* DNS::Rehash() sets this to a valid ptr
399 /* Again, DNS::Rehash() sets this to a
404 /* Actually read the settings
408 this->PruneTimer = new CacheTimer(ServerInstance, this);
410 ServerInstance->Timers->AddTimer(this->PruneTimer);
413 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
414 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
416 short payloadpos = 0;
417 const char* tempchr, *tempchr2 = name;
418 unsigned short length;
420 /* split name up into labels, create query */
421 while ((tempchr = strchr(tempchr2,'.')) != NULL)
423 length = tempchr - tempchr2;
424 if (payloadpos + length + 1 > 507)
426 payload[payloadpos++] = length;
427 memcpy(&payload[payloadpos],tempchr2,length);
428 payloadpos += length;
429 tempchr2 = &tempchr[1];
431 length = strlen(tempchr2);
434 if (payloadpos + length + 2 > 507)
436 payload[payloadpos++] = length;
437 memcpy(&payload[payloadpos],tempchr2,length);
438 payloadpos += length;
439 payload[payloadpos++] = 0;
441 if (payloadpos > 508)
444 memcpy(&payload[payloadpos],&length,2);
445 length = htons(rr_class);
446 memcpy(&payload[payloadpos + 2],&length,2);
447 return payloadpos + 4;
450 /** Start lookup of an hostname to an IP address */
451 int DNS::GetIP(const char *name)
457 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
460 DNSRequest* req = this->AddQuery(&h, id, name);
462 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
468 /** Start lookup of an hostname to an IPv6 address */
469 int DNS::GetIP6(const char *name)
475 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
478 DNSRequest* req = this->AddQuery(&h, id, name);
480 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
486 /** Start lookup of a cname to another name */
487 int DNS::GetCName(const char *alias)
493 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
496 DNSRequest* req = this->AddQuery(&h, id, alias);
498 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
504 /** Start lookup of an IP address to a hostname */
505 int DNS::GetName(const insp_inaddr *ip)
513 unsigned char* c = (unsigned char*)&ip->s6_addr;
514 if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
515 c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
516 c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
517 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
519 DNS::MakeIP6Int(query, (in6_addr*)ip);
521 unsigned char* c = (unsigned char*)&ip->s_addr;
522 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
525 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
528 DNSRequest* req = this->AddQuery(&h, id, insp_ntoa(*ip));
530 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
536 /** Start lookup of an IP address to a hostname */
537 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
543 #ifdef SUPPORT_IP6LINKS
544 if (fp == PROTOCOL_IPV6)
547 if (inet_pton(AF_INET6, ip, &i) > 0)
549 DNS::MakeIP6Int(query, &i);
552 /* Invalid IP address */
559 if (inet_aton(ip, &i))
561 unsigned char* c = (unsigned char*)&i.s_addr;
562 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
565 /* Invalid IP address */
569 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
572 DNSRequest* req = this->AddQuery(&h, id, ip);
574 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
580 /** Build an ipv6 reverse domain from an in6_addr
582 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
584 #ifdef SUPPORT_IP6LINKS
585 const char* hex = "0123456789abcdef";
586 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
590 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
593 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
594 *query++ = '.'; /* Seperator */
596 strcpy(query,"ip6.arpa"); /* Suffix the string */
602 /** Return the next id which is ready, and the result attached to it */
603 DNSResult DNS::GetResult()
605 /* Fetch dns query response and decide where it belongs */
608 unsigned char buffer[sizeof(DNSHeader)];
610 socklen_t x = sizeof(from);
611 const char* ipaddr_from = "";
612 unsigned short int port_from = 0;
614 int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
616 /* Did we get the whole header? */
619 /* Nope - something screwed up. */
620 return DNSResult(-1,"",0,"");
623 /* Check wether the reply came from a different DNS
624 * server to the one we sent it to, or the source-port
626 * A user could in theory still spoof dns packets anyway
627 * but this is less trivial than just sending garbage
628 * to the client, which is possible without this check.
630 * -- Thanks jilles for pointing this one out.
633 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
634 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
636 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
637 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
640 /* We cant perform this security check if you're using 4in6.
641 * Tough luck to you, choose one or't other!
645 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
647 return DNSResult(-1,"",0,"");
651 /* Put the read header info into a header class */
652 DNS::FillHeader(&header,buffer,length - 12);
654 /* Get the id of this request.
655 * Its a 16 bit value stored in two char's,
656 * so we use logic shifts to create the value.
658 unsigned long this_id = header.id[1] + (header.id[0] << 8);
660 /* Do we have a pending request matching this id? */
661 if (!requests[this_id])
663 /* Somehow we got a DNS response for a request we never made... */
664 return DNSResult(-1,"",0,"");
668 /* Remove the query from the list of pending queries */
669 req = requests[this_id];
670 requests[this_id] = NULL;
673 /* Inform the DNSRequest class that it has a result to be read.
674 * When its finished it will return a DNSInfo which is a pair of
675 * unsigned char* resource record data, and an error message.
677 DNSInfo data = req->ResultIsReady(header, length);
678 std::string resultstr;
680 /* Check if we got a result, if we didnt, its an error */
681 if (data.first == NULL)
684 * Mask the ID with the value of ERROR_MASK, so that
685 * the dns_deal_with_classes() function knows that its
686 * an error response and needs to be treated uniquely.
687 * Put the error message in the second field.
689 std::string ro = req->orig;
691 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
695 unsigned long ttl = req->ttl;
698 /* Forward lookups come back as binary data. We must format them into ascii */
702 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
703 resultstr = formatted;
708 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
709 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
710 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
711 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
712 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
713 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
714 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
715 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
716 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
717 char* c = strstr(formatted,":0:");
720 memmove(c+1,c+2,strlen(c+2) + 1);
722 while (memcmp(c,"0:",2) == 0)
723 memmove(c,c+2,strlen(c+2) + 1);
724 if (memcmp(c,"0",2) == 0)
726 if (memcmp(formatted,"0::",3) == 0)
727 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
729 resultstr = formatted;
731 /* Special case. Sending ::1 around between servers
732 * and to clients is dangerous, because the : on the
733 * start makes the client or server interpret the IP
734 * as the last parameter on the line with a value ":1".
736 if (*formatted == ':')
737 resultstr = "0" + resultstr;
741 case DNS_QUERY_CNAME:
742 /* Identical handling to PTR */
745 /* Reverse lookups just come back as char* */
746 resultstr = std::string((const char*)data.first);
754 /* Build the reply with the id and hostname/ip in it */
755 std::string ro = req->orig;
757 return DNSResult(this_id,resultstr,ttl,ro);
761 /** A result is ready, process it */
762 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
770 /* This is just to keep _FORTIFY_SOURCE happy */
771 rr.type = DNS_QUERY_NONE;
773 rr.ttl = 1; /* GCC is a whiney bastard -- see the XXX below. */
775 if (!(header.flags1 & FLAGS_MASK_QR))
776 return std::make_pair((unsigned char*)NULL,"Not a query result");
778 if (header.flags1 & FLAGS_MASK_OPCODE)
779 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
781 if (header.flags2 & FLAGS_MASK_RCODE)
782 return std::make_pair((unsigned char*)NULL,"Domain name not found");
784 if (header.ancount < 1)
785 return std::make_pair((unsigned char*)NULL,"No resource records returned");
787 /* Subtract the length of the header from the length of the packet */
790 while ((unsigned int)q < header.qdcount && i < length)
792 if (header.payload[i] > 63)
799 if (header.payload[i] == 0)
804 else i += header.payload[i] + 1;
808 while ((unsigned)curanswer < header.ancount)
811 while (q == 0 && i < length)
813 if (header.payload[i] > 63)
820 if (header.payload[i] == 0)
825 else i += header.payload[i] + 1; /* skip length and label */
829 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
831 /* XXX: We actually initialise 'rr' here including its ttl field */
832 DNS::FillResourceRecord(&rr,&header.payload[i]);
834 if (rr.type != this->type)
840 if (rr.rr_class != this->rr_class)
848 if ((unsigned int)curanswer == header.ancount)
849 return std::make_pair((unsigned char*)NULL,"No valid answers");
851 if (i + rr.rdlength > (unsigned int)length)
852 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
854 if (rr.rdlength > 1023)
855 return std::make_pair((unsigned char*)NULL,"Resource record too large");
861 case DNS_QUERY_CNAME:
862 /* CNAME and PTR have the same processing code */
866 while (q == 0 && i < length && o + 256 < 1023)
868 if (header.payload[i] > 63)
870 memcpy(&ptr,&header.payload[i],2);
871 i = ntohs(ptr) - 0xC000 - 12;
875 if (header.payload[i] == 0)
884 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
885 o += header.payload[i];
886 i += header.payload[i] + 1;
893 memcpy(res,&header.payload[i],rr.rdlength);
894 res[rr.rdlength] = 0;
897 memcpy(res,&header.payload[i],rr.rdlength);
898 res[rr.rdlength] = 0;
901 memcpy(res,&header.payload[i],rr.rdlength);
902 res[rr.rdlength] = 0;
905 return std::make_pair(res,"No error");;
908 /** Close the master socket */
911 shutdown(this->GetFd(), 2);
912 close(this->GetFd());
913 ServerInstance->Timers->DelTimer(this->PruneTimer);
914 delete this->PruneTimer;
917 CachedQuery* DNS::GetCache(const std::string &source)
919 dnscache::iterator x = cache->find(source.c_str());
920 if (x != cache->end())
926 void DNS::DelCache(const std::string &source)
928 cache->erase(source.c_str());
931 void Resolver::TriggerCachedResult()
934 OnLookupComplete(CQ->data, time_left, true);
937 /** High level abstraction of dns used by application at large */
938 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
942 CQ = ServerInstance->Res->GetCache(source);
945 time_left = CQ->CalcTTLRemaining();
948 ServerInstance->Res->DelCache(source);
962 this->myid = ServerInstance->Res->GetIP(source.c_str());
966 if (insp_aton(source.c_str(), &binip) > 0)
968 /* Valid ip address */
969 this->myid = ServerInstance->Res->GetName(&binip);
973 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
974 throw ModuleException("Resolver: Bad IP address");
980 querytype = DNS_QUERY_PTR;
981 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
985 querytype = DNS_QUERY_PTR;
986 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
990 this->myid = ServerInstance->Res->GetIP6(source.c_str());
993 case DNS_QUERY_CNAME:
994 this->myid = ServerInstance->Res->GetCName(source.c_str());
1001 if (this->myid == -1)
1003 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
1004 throw ModuleException("Resolver: Couldnt get an id to make a request");
1005 /* We shouldnt get here really */
1010 /** Called when an error occurs */
1011 void Resolver::OnError(ResolverError e, const std::string &errormessage)
1013 /* Nothing in here */
1016 /** Destroy a resolver */
1017 Resolver::~Resolver()
1019 /* Nothing here (yet) either */
1022 /** Get the request id associated with this class */
1023 int Resolver::GetId()
1028 Module* Resolver::GetCreator()
1030 return this->Creator;
1033 /** Process a socket read event */
1034 void DNS::HandleEvent(EventType et, int errornum)
1036 /* Fetch the id and result of the next available packet */
1037 DNSResult res = this->GetResult();
1038 /* Is there a usable request id? */
1041 /* Its an error reply */
1042 if (res.id & ERROR_MASK)
1044 /* Mask off the error bit */
1045 res.id -= ERROR_MASK;
1046 /* Marshall the error to the correct class */
1047 if (Classes[res.id])
1049 if (ServerInstance && ServerInstance->stats)
1050 ServerInstance->stats->statsDnsBad++;
1051 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1052 delete Classes[res.id];
1053 Classes[res.id] = NULL;
1058 /* It is a non-error result, marshall the result to the correct class */
1059 if (Classes[res.id])
1061 if (ServerInstance && ServerInstance->stats)
1062 ServerInstance->stats->statsDnsGood++;
1064 if (!this->GetCache(res.original.c_str()))
1065 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1067 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
1068 delete Classes[res.id];
1069 Classes[res.id] = NULL;
1073 if (ServerInstance && ServerInstance->stats)
1074 ServerInstance->stats->statsDns++;
1078 /** Add a derived Resolver to the working set */
1079 bool DNS::AddResolverClass(Resolver* r)
1081 /* Check the pointers validity and the id's validity */
1082 if ((r) && (r->GetId() > -1))
1084 /* Check the slot isnt already occupied -
1085 * This should NEVER happen unless we have
1086 * a severely broken DNS server somewhere
1088 if (!Classes[r->GetId()])
1090 /* Set up the pointer to the class */
1091 Classes[r->GetId()] = r;
1100 /* Pointer or id not valid.
1101 * Free the item and return
1110 void DNS::CleanResolvers(Module* module)
1112 for (int i = 0; i < MAX_REQUEST_ID; i++)
1116 if (Classes[i]->GetCreator() == module)
1118 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1126 /** Generate pseudo-random number */
1127 unsigned long DNS::PRNG()
1129 unsigned long val = 0;
1131 serverstats* s = ServerInstance->stats;
1132 gettimeofday(&n,NULL);
1133 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1134 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1135 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;