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)
67 QueryType type; /* Record type */
68 unsigned int rr_class; /* Record class */
69 unsigned long ttl; /* Time to live */
70 unsigned int rdlength; /* Record length */
73 /** Represents a dns request/reply header, and its payload as opaque data.
78 unsigned char id[2]; /* Request id */
79 unsigned int flags1; /* Flags */
80 unsigned int flags2; /* Flags */
82 unsigned int ancount; /* Answer count */
83 unsigned int nscount; /* Nameserver count */
85 unsigned char payload[512]; /* Packet payload */
91 unsigned char id[2]; /* Request id */
92 unsigned char* res; /* Result processing buffer */
93 unsigned int rr_class; /* Request class */
94 QueryType type; /* Request type */
95 insp_inaddr myserver; /* DNS server address*/
96 DNS* dnsobj; /* DNS caller (where we get our FD from) */
97 unsigned long ttl; /* Time to live */
98 std::string orig; /* Original requested name/ip */
100 DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, const std::string &original);
102 DNSInfo ResultIsReady(DNSHeader &h, int length);
103 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
106 class CacheTimer : public InspTimer
109 InspIRCd* ServerInstance;
112 CacheTimer(InspIRCd* Instance, DNS* thisdns)
113 : InspTimer(3600, Instance->Time(), true), ServerInstance(Instance), dns(thisdns) { }
115 virtual void Tick(time_t TIME)
121 class RequestTimeout : public InspTimer
123 InspIRCd* ServerInstance;
127 RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
131 void Tick(time_t TIME)
133 if (ServerInstance->Res->requests[watchid] == watch)
135 /* Still exists, whack it */
136 if (ServerInstance->Res->Classes[watchid])
138 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
139 delete ServerInstance->Res->Classes[watchid];
140 ServerInstance->Res->Classes[watchid] = NULL;
142 ServerInstance->Res->requests[watchid] = NULL;
149 /* Allocate the processing buffer */
150 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, const std::string &original) : dnsobj(dns)
152 res = new unsigned char[512];
154 memcpy(&myserver, &server, sizeof(insp_inaddr));
156 RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);
157 Instance->Timers->AddTimer(RT); /* The timer manager frees this */
160 /* Deallocate the processing buffer */
161 DNSRequest::~DNSRequest()
166 /** Fill a ResourceRecord class based on raw data input */
167 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
169 rr->type = (QueryType)((input[0] << 8) + input[1]);
170 rr->rr_class = (input[2] << 8) + input[3];
171 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
172 rr->rdlength = (input[8] << 8) + input[9];
175 /** Fill a DNSHeader class based on raw data input of a given length */
176 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
178 header->id[0] = input[0];
179 header->id[1] = input[1];
180 header->flags1 = input[2];
181 header->flags2 = input[3];
182 header->qdcount = (input[4] << 8) + input[5];
183 header->ancount = (input[6] << 8) + input[7];
184 header->nscount = (input[8] << 8) + input[9];
185 header->arcount = (input[10] << 8) + input[11];
186 memcpy(header->payload,&input[12],length);
189 /** Empty a DNSHeader class out into raw data, ready for transmission */
190 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
192 output[0] = header->id[0];
193 output[1] = header->id[1];
194 output[2] = header->flags1;
195 output[3] = header->flags2;
196 output[4] = header->qdcount >> 8;
197 output[5] = header->qdcount & 0xFF;
198 output[6] = header->ancount >> 8;
199 output[7] = header->ancount & 0xFF;
200 output[8] = header->nscount >> 8;
201 output[9] = header->nscount & 0xFF;
202 output[10] = header->arcount >> 8;
203 output[11] = header->arcount & 0xFF;
204 memcpy(&output[12],header->payload,length);
207 /** Send requests we have previously built down the UDP socket */
208 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
211 unsigned char payload[sizeof(DNSHeader)];
216 DNS::EmptyHeader(payload,header,length);
218 memset(&addr,0,sizeof(addr));
220 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
221 addr.sin6_family = AF_FAMILY;
222 addr.sin6_port = htons(DNS::QUERY_PORT);
224 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
225 addr.sin_family = AF_FAMILY;
226 addr.sin_port = htons(DNS::QUERY_PORT);
228 if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
234 /** Add a query with a predefined header, and allocate an ID for it. */
235 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
237 /* Is the DNS connection down? */
238 if (this->GetFd() == -1)
242 id = this->PRNG() & DNS::MAX_REQUEST_ID;
244 /* If this id is already 'in flight', pick another. */
246 id = this->PRNG() & DNS::MAX_REQUEST_ID;
248 DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id, original);
250 header->id[0] = req->id[0] = id >> 8;
251 header->id[1] = req->id[1] = id & 0xFF;
252 header->flags1 = FLAGS_MASK_RD;
259 /* At this point we already know the id doesnt exist,
260 * so there needs to be no second check for the ::end()
264 /* According to the C++ spec, new never returns NULL. */
268 int DNS::ClearCache()
270 /* This ensures the buckets are reset to sane levels */
271 int rv = this->cache->size();
273 this->cache = new dnscache();
277 int DNS::PruneCache()
280 dnscache* newcache = new dnscache();
281 for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
282 /* Dont include expired items (theres no point) */
283 if (i->second.CalcTTLRemaining())
284 newcache->insert(*i);
289 this->cache = newcache;
298 if (this->GetFd() > -1)
300 if (ServerInstance && ServerInstance->SE)
301 ServerInstance->SE->DelFd(this);
302 shutdown(this->GetFd(), 2);
303 close(this->GetFd());
306 /* Rehash the cache */
311 /* Create initial dns cache */
312 this->cache = new dnscache();
315 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
317 memcpy(&myserver,&addr,sizeof(insp_inaddr));
318 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
320 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
321 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
322 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
323 this->ip6munge = true;
327 /* Initialize mastersocket */
328 this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
329 if (this->GetFd() != -1)
331 /* Did it succeed? */
332 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
334 /* Couldn't make the socket nonblocking */
335 shutdown(this->GetFd(),2);
336 close(this->GetFd());
341 /* Have we got a socket and is it nonblocking? */
342 if (this->GetFd() != -1)
346 memset(&addr,0,sizeof(addr));
347 addr.sin6_family = AF_FAMILY;
349 addr.sin6_addr = in6addr_any;
352 memset(&addr,0,sizeof(addr));
353 addr.sin_family = AF_FAMILY;
355 addr.sin_addr.s_addr = INADDR_ANY;
358 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
361 shutdown(this->GetFd(),2);
362 close(this->GetFd());
366 if (this->GetFd() >= 0)
368 /* Hook the descriptor into the socket engine */
369 if (ServerInstance && ServerInstance->SE)
371 if (!ServerInstance->SE->AddFd(this))
373 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
374 shutdown(this->GetFd(),2);
375 close(this->GetFd());
383 /** Initialise the DNS UDP socket so that we can send requests */
384 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
386 /* Clear the Resolver class table */
387 memset(Classes,0,sizeof(Classes));
389 /* Clear the requests class table */
390 memset(requests,0,sizeof(requests));
392 /* Set the id of the next request to 0
396 /* DNS::Rehash() sets this to a valid ptr
400 /* Again, DNS::Rehash() sets this to a
405 /* Actually read the settings
409 this->PruneTimer = new CacheTimer(ServerInstance, this);
411 ServerInstance->Timers->AddTimer(this->PruneTimer);
414 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
415 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
417 short payloadpos = 0;
418 const char* tempchr, *tempchr2 = name;
419 unsigned short length;
421 /* split name up into labels, create query */
422 while ((tempchr = strchr(tempchr2,'.')) != NULL)
424 length = tempchr - tempchr2;
425 if (payloadpos + length + 1 > 507)
427 payload[payloadpos++] = length;
428 memcpy(&payload[payloadpos],tempchr2,length);
429 payloadpos += length;
430 tempchr2 = &tempchr[1];
432 length = strlen(tempchr2);
435 if (payloadpos + length + 2 > 507)
437 payload[payloadpos++] = length;
438 memcpy(&payload[payloadpos],tempchr2,length);
439 payloadpos += length;
440 payload[payloadpos++] = 0;
442 if (payloadpos > 508)
445 memcpy(&payload[payloadpos],&length,2);
446 length = htons(rr_class);
447 memcpy(&payload[payloadpos + 2],&length,2);
448 return payloadpos + 4;
451 /** Start lookup of an hostname to an IP address */
452 int DNS::GetIP(const char *name)
458 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
461 DNSRequest* req = this->AddQuery(&h, id, name);
463 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
469 /** Start lookup of an hostname to an IPv6 address */
470 int DNS::GetIP6(const char *name)
476 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
479 DNSRequest* req = this->AddQuery(&h, id, name);
481 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
487 /** Start lookup of a cname to another name */
488 int DNS::GetCName(const char *alias)
494 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
497 DNSRequest* req = this->AddQuery(&h, id, alias);
499 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
505 /** Start lookup of an IP address to a hostname */
506 int DNS::GetName(const insp_inaddr *ip)
514 unsigned char* c = (unsigned char*)&ip->s6_addr;
515 if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
516 c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
517 c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
518 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
520 DNS::MakeIP6Int(query, (in6_addr*)ip);
522 unsigned char* c = (unsigned char*)&ip->s_addr;
523 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
526 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
529 DNSRequest* req = this->AddQuery(&h, id, insp_ntoa(*ip));
531 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
537 /** Start lookup of an IP address to a hostname */
538 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
544 #ifdef SUPPORT_IP6LINKS
545 if (fp == PROTOCOL_IPV6)
548 if (inet_pton(AF_INET6, ip, &i) > 0)
550 DNS::MakeIP6Int(query, &i);
553 /* Invalid IP address */
560 if (inet_aton(ip, &i))
562 unsigned char* c = (unsigned char*)&i.s_addr;
563 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
566 /* Invalid IP address */
570 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
573 DNSRequest* req = this->AddQuery(&h, id, ip);
575 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
581 /** Build an ipv6 reverse domain from an in6_addr
583 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
585 #ifdef SUPPORT_IP6LINKS
586 const char* hex = "0123456789abcdef";
587 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
591 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
594 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
595 *query++ = '.'; /* Seperator */
597 strcpy(query,"ip6.arpa"); /* Suffix the string */
603 /** Return the next id which is ready, and the result attached to it */
604 DNSResult DNS::GetResult()
606 /* Fetch dns query response and decide where it belongs */
609 unsigned char buffer[sizeof(DNSHeader)];
611 socklen_t x = sizeof(from);
612 const char* ipaddr_from = "";
613 unsigned short int port_from = 0;
615 int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
617 /* Did we get the whole header? */
620 /* Nope - something screwed up. */
621 return DNSResult(-1,"",0,"");
624 /* Check wether the reply came from a different DNS
625 * server to the one we sent it to, or the source-port
627 * A user could in theory still spoof dns packets anyway
628 * but this is less trivial than just sending garbage
629 * to the client, which is possible without this check.
631 * -- Thanks jilles for pointing this one out.
634 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
635 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
637 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
638 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
641 /* We cant perform this security check if you're using 4in6.
642 * Tough luck to you, choose one or't other!
646 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
648 return DNSResult(-1,"",0,"");
652 /* Put the read header info into a header class */
653 DNS::FillHeader(&header,buffer,length - 12);
655 /* Get the id of this request.
656 * Its a 16 bit value stored in two char's,
657 * so we use logic shifts to create the value.
659 unsigned long this_id = header.id[1] + (header.id[0] << 8);
661 /* Do we have a pending request matching this id? */
662 if (!requests[this_id])
664 /* Somehow we got a DNS response for a request we never made... */
665 return DNSResult(-1,"",0,"");
669 /* Remove the query from the list of pending queries */
670 req = requests[this_id];
671 requests[this_id] = NULL;
674 /* Inform the DNSRequest class that it has a result to be read.
675 * When its finished it will return a DNSInfo which is a pair of
676 * unsigned char* resource record data, and an error message.
678 DNSInfo data = req->ResultIsReady(header, length);
679 std::string resultstr;
681 /* Check if we got a result, if we didnt, its an error */
682 if (data.first == NULL)
685 * Mask the ID with the value of ERROR_MASK, so that
686 * the dns_deal_with_classes() function knows that its
687 * an error response and needs to be treated uniquely.
688 * Put the error message in the second field.
690 std::string ro = req->orig;
692 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
696 unsigned long ttl = req->ttl;
699 /* Forward lookups come back as binary data. We must format them into ascii */
703 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
704 resultstr = formatted;
709 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
710 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
711 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
712 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
713 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
714 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
715 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
716 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
717 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
718 char* c = strstr(formatted,":0:");
721 memmove(c+1,c+2,strlen(c+2) + 1);
723 while (memcmp(c,"0:",2) == 0)
724 memmove(c,c+2,strlen(c+2) + 1);
725 if (memcmp(c,"0",2) == 0)
727 if (memcmp(formatted,"0::",3) == 0)
728 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
730 resultstr = formatted;
732 /* Special case. Sending ::1 around between servers
733 * and to clients is dangerous, because the : on the
734 * start makes the client or server interpret the IP
735 * as the last parameter on the line with a value ":1".
737 if (*formatted == ':')
738 resultstr = "0" + resultstr;
742 case DNS_QUERY_CNAME:
743 /* Identical handling to PTR */
746 /* Reverse lookups just come back as char* */
747 resultstr = std::string((const char*)data.first);
755 /* Build the reply with the id and hostname/ip in it */
756 std::string ro = req->orig;
758 return DNSResult(this_id,resultstr,ttl,ro);
762 /** A result is ready, process it */
763 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
771 /* This is just to keep _FORTIFY_SOURCE happy */
772 rr.type = DNS_QUERY_NONE;
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 DNS::FillResourceRecord(&rr,&header.payload[i]);
833 if (rr.type != this->type)
839 if (rr.rr_class != this->rr_class)
847 if ((unsigned int)curanswer == header.ancount)
848 return std::make_pair((unsigned char*)NULL,"No valid answers");
850 if (i + rr.rdlength > (unsigned int)length)
851 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
853 if (rr.rdlength > 1023)
854 return std::make_pair((unsigned char*)NULL,"Resource record too large");
860 case DNS_QUERY_CNAME:
861 /* CNAME and PTR have the same processing code */
865 while (q == 0 && i < length && o + 256 < 1023)
867 if (header.payload[i] > 63)
869 memcpy(&ptr,&header.payload[i],2);
870 i = ntohs(ptr) - 0xC000 - 12;
874 if (header.payload[i] == 0)
883 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
884 o += header.payload[i];
885 i += header.payload[i] + 1;
892 memcpy(res,&header.payload[i],rr.rdlength);
893 res[rr.rdlength] = 0;
896 memcpy(res,&header.payload[i],rr.rdlength);
897 res[rr.rdlength] = 0;
900 memcpy(res,&header.payload[i],rr.rdlength);
901 res[rr.rdlength] = 0;
904 return std::make_pair(res,"No error");;
907 /** Close the master socket */
910 shutdown(this->GetFd(), 2);
911 close(this->GetFd());
912 ServerInstance->Timers->DelTimer(this->PruneTimer);
913 delete this->PruneTimer;
916 CachedQuery* DNS::GetCache(const std::string &source)
918 dnscache::iterator x = cache->find(source.c_str());
919 if (x != cache->end())
925 void DNS::DelCache(const std::string &source)
927 cache->erase(source.c_str());
930 void Resolver::TriggerCachedResult()
933 OnLookupComplete(CQ->data, time_left, true);
936 /** High level abstraction of dns used by application at large */
937 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
941 CQ = ServerInstance->Res->GetCache(source);
944 time_left = CQ->CalcTTLRemaining();
947 ServerInstance->Res->DelCache(source);
961 this->myid = ServerInstance->Res->GetIP(source.c_str());
965 if (insp_aton(source.c_str(), &binip) > 0)
967 /* Valid ip address */
968 this->myid = ServerInstance->Res->GetName(&binip);
972 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
973 throw ModuleException("Resolver: Bad IP address");
979 querytype = DNS_QUERY_PTR;
980 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
984 querytype = DNS_QUERY_PTR;
985 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
989 this->myid = ServerInstance->Res->GetIP6(source.c_str());
992 case DNS_QUERY_CNAME:
993 this->myid = ServerInstance->Res->GetCName(source.c_str());
1000 if (this->myid == -1)
1002 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
1003 throw ModuleException("Resolver: Couldnt get an id to make a request");
1004 /* We shouldnt get here really */
1009 /** Called when an error occurs */
1010 void Resolver::OnError(ResolverError e, const std::string &errormessage)
1012 /* Nothing in here */
1015 /** Destroy a resolver */
1016 Resolver::~Resolver()
1018 /* Nothing here (yet) either */
1021 /** Get the request id associated with this class */
1022 int Resolver::GetId()
1027 Module* Resolver::GetCreator()
1029 return this->Creator;
1032 /** Process a socket read event */
1033 void DNS::HandleEvent(EventType et, int errornum)
1035 /* Fetch the id and result of the next available packet */
1036 DNSResult res = this->GetResult();
1037 /* Is there a usable request id? */
1040 /* Its an error reply */
1041 if (res.id & ERROR_MASK)
1043 /* Mask off the error bit */
1044 res.id -= ERROR_MASK;
1045 /* Marshall the error to the correct class */
1046 if (Classes[res.id])
1048 if (ServerInstance && ServerInstance->stats)
1049 ServerInstance->stats->statsDnsBad++;
1050 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1051 delete Classes[res.id];
1052 Classes[res.id] = NULL;
1057 /* It is a non-error result, marshall the result to the correct class */
1058 if (Classes[res.id])
1060 if (ServerInstance && ServerInstance->stats)
1061 ServerInstance->stats->statsDnsGood++;
1063 if (!this->GetCache(res.original.c_str()))
1064 this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1066 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
1067 delete Classes[res.id];
1068 Classes[res.id] = NULL;
1072 if (ServerInstance && ServerInstance->stats)
1073 ServerInstance->stats->statsDns++;
1077 /** Add a derived Resolver to the working set */
1078 bool DNS::AddResolverClass(Resolver* r)
1080 /* Check the pointers validity and the id's validity */
1081 if ((r) && (r->GetId() > -1))
1083 /* Check the slot isnt already occupied -
1084 * This should NEVER happen unless we have
1085 * a severely broken DNS server somewhere
1087 if (!Classes[r->GetId()])
1089 /* Set up the pointer to the class */
1090 Classes[r->GetId()] = r;
1099 /* Pointer or id not valid.
1100 * Free the item and return
1109 void DNS::CleanResolvers(Module* module)
1111 for (int i = 0; i < MAX_REQUEST_ID; i++)
1115 if (Classes[i]->GetCreator() == module)
1117 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1125 /** Generate pseudo-random number */
1126 unsigned long DNS::PRNG()
1128 unsigned long val = 0;
1130 serverstats* s = ServerInstance->stats;
1131 gettimeofday(&n,NULL);
1132 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1133 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1134 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;