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) */
98 DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id);
100 DNSInfo ResultIsReady(DNSHeader &h, int length);
101 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
104 class RequestTimeout : public InspTimer
106 InspIRCd* ServerInstance;
110 RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
112 ServerInstance->Log(DEBUG, "New DNS timeout set on %08x", watching);
115 void Tick(time_t TIME)
117 if (ServerInstance->Res->requests[watchid] == watch)
119 /* Still exists, whack it */
120 if (ServerInstance->Res->Classes[watchid])
122 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
123 delete ServerInstance->Res->Classes[watchid];
124 ServerInstance->Res->Classes[watchid] = NULL;
126 ServerInstance->Res->requests[watchid] = NULL;
128 ServerInstance->Log(DEBUG, "DNS timeout on %08x squished pointer", watch);
131 ServerInstance->Log(DEBUG, "DNS timeout on %08x: result already received!", watch);
135 /* Allocate the processing buffer */
136 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id) : dnsobj(dns)
138 res = new unsigned char[512];
140 memcpy(&myserver, &server, sizeof(insp_inaddr));
141 RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);
142 Instance->Timers->AddTimer(RT); /* The timer manager frees this */
145 /* Deallocate the processing buffer */
146 DNSRequest::~DNSRequest()
151 /** Fill a ResourceRecord class based on raw data input */
152 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
154 rr->type = (QueryType)((input[0] << 8) + input[1]);
155 rr->rr_class = (input[2] << 8) + input[3];
156 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
157 rr->rdlength = (input[8] << 8) + input[9];
160 /** Fill a DNSHeader class based on raw data input of a given length */
161 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
163 header->id[0] = input[0];
164 header->id[1] = input[1];
165 header->flags1 = input[2];
166 header->flags2 = input[3];
167 header->qdcount = (input[4] << 8) + input[5];
168 header->ancount = (input[6] << 8) + input[7];
169 header->nscount = (input[8] << 8) + input[9];
170 header->arcount = (input[10] << 8) + input[11];
171 memcpy(header->payload,&input[12],length);
174 /** Empty a DNSHeader class out into raw data, ready for transmission */
175 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
177 output[0] = header->id[0];
178 output[1] = header->id[1];
179 output[2] = header->flags1;
180 output[3] = header->flags2;
181 output[4] = header->qdcount >> 8;
182 output[5] = header->qdcount & 0xFF;
183 output[6] = header->ancount >> 8;
184 output[7] = header->ancount & 0xFF;
185 output[8] = header->nscount >> 8;
186 output[9] = header->nscount & 0xFF;
187 output[10] = header->arcount >> 8;
188 output[11] = header->arcount & 0xFF;
189 memcpy(&output[12],header->payload,length);
192 /** Send requests we have previously built down the UDP socket */
193 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
196 unsigned char payload[sizeof(DNSHeader)];
201 DNS::EmptyHeader(payload,header,length);
203 memset(&addr,0,sizeof(addr));
205 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
206 addr.sin6_family = AF_FAMILY;
207 addr.sin6_port = htons(DNS::QUERY_PORT);
209 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
210 addr.sin_family = AF_FAMILY;
211 addr.sin_port = htons(DNS::QUERY_PORT);
213 if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
219 /** Add a query with a predefined header, and allocate an ID for it. */
220 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
222 /* Is the DNS connection down? */
223 if (this->GetFd() == -1)
227 id = this->PRNG() & DNS::MAX_REQUEST_ID;
229 /* If this id is already 'in flight', pick another. */
231 id = this->PRNG() & DNS::MAX_REQUEST_ID;
233 DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id);
235 header->id[0] = req->id[0] = id >> 8;
236 header->id[1] = req->id[1] = id & 0xFF;
237 header->flags1 = FLAGS_MASK_RD;
244 /* At this point we already know the id doesnt exist,
245 * so there needs to be no second check for the ::end()
249 /* According to the C++ spec, new never returns NULL. */
253 /** Initialise the DNS UDP socket so that we can send requests */
254 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
256 ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
260 /* Clear the Resolver class table */
261 memset(Classes,0,sizeof(Classes));
263 /* Clear the requests class table */
264 memset(requests,0,sizeof(requests));
266 /* Set the id of the next request to 0
270 /* By default we're not munging ip's
274 /* Clear the namesever address */
275 memset(&myserver,0,sizeof(insp_inaddr));
277 /* Convert the nameserver address into an insp_inaddr */
278 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
280 memcpy(&myserver,&addr,sizeof(insp_inaddr));
281 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
283 /* These dont come back looking like they did when they went in.
284 * We're forced to turn some checks off.
285 * If anyone knows how to fix this, let me know. --Brain
287 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
288 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
289 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
290 this->ip6munge = true;
292 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
296 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
299 /* Initialize mastersocket */
300 this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
301 if (this->GetFd() != -1)
303 /* Did it succeed? */
304 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
306 /* Couldn't make the socket nonblocking */
307 shutdown(this->GetFd(),2);
308 close(this->GetFd());
314 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
316 /* Have we got a socket and is it nonblocking? */
317 if (this->GetFd() != -1)
321 memset(&addr,0,sizeof(addr));
322 addr.sin6_family = AF_FAMILY;
324 addr.sin6_addr = in6addr_any;
327 memset(&addr,0,sizeof(addr));
328 addr.sin_family = AF_FAMILY;
330 addr.sin_addr.s_addr = INADDR_ANY;
333 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
336 ServerInstance->Log(DEBUG,"Cant bind DNS fd");
337 shutdown(this->GetFd(),2);
338 close(this->GetFd());
342 if (this->GetFd() >= 0)
344 ServerInstance->Log(DEBUG,"Add master socket %d",this->GetFd());
345 /* Hook the descriptor into the socket engine */
346 if (ServerInstance && ServerInstance->SE)
348 if (!ServerInstance->SE->AddFd(this))
350 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
351 shutdown(this->GetFd(),2);
352 close(this->GetFd());
360 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
361 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
363 short payloadpos = 0;
364 const char* tempchr, *tempchr2 = name;
365 unsigned short length;
367 /* split name up into labels, create query */
368 while ((tempchr = strchr(tempchr2,'.')) != NULL)
370 length = tempchr - tempchr2;
371 if (payloadpos + length + 1 > 507)
373 payload[payloadpos++] = length;
374 memcpy(&payload[payloadpos],tempchr2,length);
375 payloadpos += length;
376 tempchr2 = &tempchr[1];
378 length = strlen(tempchr2);
381 if (payloadpos + length + 2 > 507)
383 payload[payloadpos++] = length;
384 memcpy(&payload[payloadpos],tempchr2,length);
385 payloadpos += length;
386 payload[payloadpos++] = 0;
388 if (payloadpos > 508)
391 memcpy(&payload[payloadpos],&length,2);
392 length = htons(rr_class);
393 memcpy(&payload[payloadpos + 2],&length,2);
394 return payloadpos + 4;
397 /** Start lookup of an hostname to an IP address */
398 int DNS::GetIP(const char *name)
404 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
407 DNSRequest* req = this->AddQuery(&h, id);
409 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
415 /** Start lookup of an hostname to an IPv6 address */
416 int DNS::GetIP6(const char *name)
422 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
425 DNSRequest* req = this->AddQuery(&h, id);
427 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
433 /** Start lookup of a cname to another name */
434 int DNS::GetCName(const char *alias)
440 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
443 DNSRequest* req = this->AddQuery(&h, id);
445 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
451 /** Start lookup of an IP address to a hostname */
452 int DNS::GetName(const insp_inaddr *ip)
460 unsigned char* c = (unsigned char*)&ip->s6_addr;
461 if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
462 c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
463 c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
464 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
466 DNS::MakeIP6Int(query, (in6_addr*)ip);
468 unsigned char* c = (unsigned char*)&ip->s_addr;
469 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
472 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
475 DNSRequest* req = this->AddQuery(&h, id);
477 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
483 /** Start lookup of an IP address to a hostname */
484 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
490 #ifdef SUPPORT_IP6LINKS
491 if (fp == PROTOCOL_IPV6)
494 if (inet_pton(AF_INET6, ip, &i) > 0)
496 DNS::MakeIP6Int(query, &i);
499 /* Invalid IP address */
506 if (inet_aton(ip, &i))
508 unsigned char* c = (unsigned char*)&i.s_addr;
509 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
512 /* Invalid IP address */
516 ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
518 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
521 DNSRequest* req = this->AddQuery(&h, id);
523 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
529 /** Build an ipv6 reverse domain from an in6_addr
531 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
533 #ifdef SUPPORT_IP6LINKS
534 const char* hex = "0123456789abcdef";
535 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
539 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
542 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
543 *query++ = '.'; /* Seperator */
545 strcpy(query,"ip6.arpa"); /* Suffix the string */
551 /** Return the next id which is ready, and the result attached to it */
552 DNSResult DNS::GetResult()
554 /* Fetch dns query response and decide where it belongs */
557 unsigned char buffer[sizeof(DNSHeader)];
559 socklen_t x = sizeof(from);
560 const char* ipaddr_from = "";
561 unsigned short int port_from = 0;
563 int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
566 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
568 /* Did we get the whole header? */
571 /* Nope - something screwed up. */
572 ServerInstance->Log(DEBUG,"Whole header not read!");
573 return std::make_pair(-1,"");
576 /* Check wether the reply came from a different DNS
577 * server to the one we sent it to, or the source-port
579 * A user could in theory still spoof dns packets anyway
580 * but this is less trivial than just sending garbage
581 * to the client, which is possible without this check.
583 * -- Thanks jilles for pointing this one out.
586 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
587 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
589 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
590 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
593 /* We cant perform this security check if you're using 4in6.
594 * Tough luck to you, choose one or't other!
598 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
600 ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
601 return std::make_pair(-1,"");
605 /* Put the read header info into a header class */
606 DNS::FillHeader(&header,buffer,length - 12);
608 /* Get the id of this request.
609 * Its a 16 bit value stored in two char's,
610 * so we use logic shifts to create the value.
612 unsigned long this_id = header.id[1] + (header.id[0] << 8);
614 /* Do we have a pending request matching this id? */
615 if (!requests[this_id])
617 /* Somehow we got a DNS response for a request we never made... */
618 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
619 return std::make_pair(-1,"");
623 /* Remove the query from the list of pending queries */
624 req = requests[this_id];
625 requests[this_id] = NULL;
628 /* Inform the DNSRequest class that it has a result to be read.
629 * When its finished it will return a DNSInfo which is a pair of
630 * unsigned char* resource record data, and an error message.
632 DNSInfo data = req->ResultIsReady(header, length);
633 std::string resultstr;
635 /* Check if we got a result, if we didnt, its an error */
636 if (data.first == NULL)
639 * Mask the ID with the value of ERROR_MASK, so that
640 * the dns_deal_with_classes() function knows that its
641 * an error response and needs to be treated uniquely.
642 * Put the error message in the second field.
645 return std::make_pair(this_id | ERROR_MASK, data.second);
651 /* Forward lookups come back as binary data. We must format them into ascii */
655 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
656 resultstr = formatted;
661 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
662 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
663 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
664 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
665 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
666 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
667 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
668 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
669 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
670 char* c = strstr(formatted,":0:");
673 memmove(c+1,c+2,strlen(c+2) + 1);
675 while (memcmp(c,"0:",2) == 0)
676 memmove(c,c+2,strlen(c+2) + 1);
677 if (memcmp(c,"0",2) == 0)
679 if (memcmp(formatted,"0::",3) == 0)
680 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
682 resultstr = formatted;
684 /* Special case. Sending ::1 around between servers
685 * and to clients is dangerous, because the : on the
686 * start makes the client or server interpret the IP
687 * as the last parameter on the line with a value ":1".
689 if (*formatted == ':')
690 resultstr = "0" + resultstr;
694 case DNS_QUERY_CNAME:
695 /* Identical handling to PTR */
698 /* Reverse lookups just come back as char* */
699 resultstr = std::string((const char*)data.first);
703 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
708 /* Build the reply with the id and hostname/ip in it */
710 return std::make_pair(this_id,resultstr);
714 /** A result is ready, process it */
715 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
723 /* This is just to keep _FORTIFY_SOURCE happy */
724 rr.type = DNS_QUERY_NONE;
727 if (!(header.flags1 & FLAGS_MASK_QR))
728 return std::make_pair((unsigned char*)NULL,"Not a query result");
730 if (header.flags1 & FLAGS_MASK_OPCODE)
731 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
733 if (header.flags2 & FLAGS_MASK_RCODE)
734 return std::make_pair((unsigned char*)NULL,"Domain name not found");
736 if (header.ancount < 1)
737 return std::make_pair((unsigned char*)NULL,"No resource records returned");
739 /* Subtract the length of the header from the length of the packet */
742 while ((unsigned int)q < header.qdcount && i < length)
744 if (header.payload[i] > 63)
751 if (header.payload[i] == 0)
756 else i += header.payload[i] + 1;
760 while ((unsigned)curanswer < header.ancount)
763 while (q == 0 && i < length)
765 if (header.payload[i] > 63)
772 if (header.payload[i] == 0)
777 else i += header.payload[i] + 1; /* skip length and label */
781 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
783 DNS::FillResourceRecord(&rr,&header.payload[i]);
785 if (rr.type != this->type)
791 if (rr.rr_class != this->rr_class)
799 if ((unsigned int)curanswer == header.ancount)
800 return std::make_pair((unsigned char*)NULL,"No valid answers");
802 if (i + rr.rdlength > (unsigned int)length)
803 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
805 if (rr.rdlength > 1023)
806 return std::make_pair((unsigned char*)NULL,"Resource record too large");
810 case DNS_QUERY_CNAME:
811 /* CNAME and PTR have the same processing code */
815 while (q == 0 && i < length && o + 256 < 1023)
817 if (header.payload[i] > 63)
819 memcpy(&ptr,&header.payload[i],2);
820 i = ntohs(ptr) - 0xC000 - 12;
824 if (header.payload[i] == 0)
833 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
834 o += header.payload[i];
835 i += header.payload[i] + 1;
842 memcpy(res,&header.payload[i],rr.rdlength);
843 res[rr.rdlength] = 0;
846 memcpy(res,&header.payload[i],rr.rdlength);
847 res[rr.rdlength] = 0;
850 memcpy(res,&header.payload[i],rr.rdlength);
851 res[rr.rdlength] = 0;
854 return std::make_pair(res,"No error");;
857 /** Close the master socket */
860 shutdown(this->GetFd(), 2);
861 close(this->GetFd());
864 /** High level abstraction of dns used by application at large */
865 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
867 ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
874 this->myid = ServerInstance->Res->GetIP(source.c_str());
878 if (insp_aton(source.c_str(), &binip) > 0)
880 /* Valid ip address */
881 this->myid = ServerInstance->Res->GetName(&binip);
885 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
886 throw ModuleException("Resolver: Bad IP address");
892 querytype = DNS_QUERY_PTR;
893 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
897 querytype = DNS_QUERY_PTR;
898 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
902 this->myid = ServerInstance->Res->GetIP6(source.c_str());
905 case DNS_QUERY_CNAME:
906 this->myid = ServerInstance->Res->GetCName(source.c_str());
913 if (this->myid == -1)
915 ServerInstance->Log(DEBUG,"Resolver::Resolver: Could not get an id!");
916 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
917 throw ModuleException("Resolver: Couldnt get an id to make a request");
918 /* We shouldnt get here really */
922 ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
925 /** Called when an error occurs */
926 void Resolver::OnError(ResolverError e, const std::string &errormessage)
928 /* Nothing in here */
931 /** Destroy a resolver */
932 Resolver::~Resolver()
934 /* Nothing here (yet) either */
937 /** Get the request id associated with this class */
938 int Resolver::GetId()
943 Module* Resolver::GetCreator()
945 return this->Creator;
948 /** Process a socket read event */
949 void DNS::HandleEvent(EventType et, int errornum)
951 /* Fetch the id and result of the next available packet */
952 DNSResult res = this->GetResult();
953 /* Is there a usable request id? */
956 /* Its an error reply */
957 if (res.first & ERROR_MASK)
959 /* Mask off the error bit */
960 res.first -= ERROR_MASK;
961 /* Marshall the error to the correct class */
962 ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
963 if (Classes[res.first])
965 if (ServerInstance && ServerInstance->stats)
966 ServerInstance->stats->statsDnsBad++;
967 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
968 delete Classes[res.first];
969 Classes[res.first] = NULL;
974 /* It is a non-error result */
975 ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
976 /* Marshall the result to the correct class */
977 if (Classes[res.first])
979 if (ServerInstance && ServerInstance->stats)
980 ServerInstance->stats->statsDnsGood++;
981 Classes[res.first]->OnLookupComplete(res.second);
982 delete Classes[res.first];
983 Classes[res.first] = NULL;
987 if (ServerInstance && ServerInstance->stats)
988 ServerInstance->stats->statsDns++;
992 /** Add a derived Resolver to the working set */
993 bool DNS::AddResolverClass(Resolver* r)
995 /* Check the pointers validity and the id's validity */
996 if ((r) && (r->GetId() > -1))
998 /* Check the slot isnt already occupied -
999 * This should NEVER happen unless we have
1000 * a severely broken DNS server somewhere
1002 if (!Classes[r->GetId()])
1004 /* Set up the pointer to the class */
1005 Classes[r->GetId()] = r;
1014 /* Pointer or id not valid.
1015 * Free the item and return
1024 void DNS::CleanResolvers(Module* module)
1026 for (int i = 0; i < MAX_REQUEST_ID; i++)
1030 if (Classes[i]->GetCreator() == module)
1032 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1040 /** Generate pseudo-random number */
1041 unsigned long DNS::PRNG()
1043 unsigned long val = 0;
1045 serverstats* s = ServerInstance->stats;
1046 gettimeofday(&n,NULL);
1047 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1048 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1049 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;