1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
7 * <brain@chatspike.net>
8 * <Craig@chatspike.net>
10 * Written by Craig Edwards, Craig McLure, and others.
11 * This program is free but copyrighted software; see
12 * the file COPYING for details.
14 * ---------------------------------------------------
18 dns.cpp - Nonblocking DNS functions.
19 Very very loosely based on the firedns library,
20 Copyright (C) 2002 Ian Gulliver. This file is no
21 longer anything like firedns, there are many major
22 differences between this code and the original.
23 Please do not assume that firedns works like this,
24 looks like this, walks like this or tastes like this.
29 #include <sys/types.h>
30 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
36 #include "socketengine.h"
37 #include "configreader.h"
41 using irc::sockets::insp_sockaddr;
42 using irc::sockets::insp_inaddr;
43 using irc::sockets::insp_ntoa;
44 using irc::sockets::insp_aton;
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)
73 QueryType type; /* Record type */
74 unsigned int rr_class; /* Record class */
75 unsigned long ttl; /* Time to live */
76 unsigned int rdlength; /* Record length */
79 /** Represents a dns request/reply header, and its payload as opaque data.
84 unsigned char id[2]; /* Request id */
85 unsigned int flags1; /* Flags */
86 unsigned int flags2; /* Flags */
88 unsigned int ancount; /* Answer count */
89 unsigned int nscount; /* Nameserver count */
91 unsigned char payload[512]; /* Packet payload */
97 unsigned char id[2]; /* Request id */
98 unsigned char* res; /* Result processing buffer */
99 unsigned int rr_class; /* Request class */
100 QueryType type; /* Request type */
101 insp_inaddr myserver; /* DNS server address*/
102 DNS* dnsobj; /* DNS caller (where we get our FD from) */
104 DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, requestlist &requests);
106 DNSInfo ResultIsReady(DNSHeader &h, int length);
107 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
110 class RequestTimeout : public InspTimer
112 InspIRCd* ServerInstance;
117 RequestTimeout(InspIRCd* SI, DNSRequest* watching, int id, requestlist &requests) : InspTimer(2, time(NULL)), ServerInstance(SI), watch(watching), watchid(id), rl(requests)
119 ServerInstance->Log(DEBUG, "New DNS timeout set on %08x", watching);
122 void Tick(time_t TIME)
124 if (rl.find(watchid) != rl.end())
126 /* Still exists, whack it */
127 if (rl.find(watchid)->second == watch)
129 watch->OnError(RESOLVER_TIMEOUT, "Request timed out");
130 rl.erase(rl.find(watchid));
132 ServerInstance->Log(DEBUG, "DNS timeout on %08x squished pointer", watch);
136 ServerInstance->Log(DEBUG, "DNS timeout on %08x: result already received!", watch);
140 /* Allocate the processing buffer */
141 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, requestlist &requests) : dnsobj(dns)
143 res = new unsigned char[512];
145 memcpy(&myserver, &server, sizeof(insp_inaddr));
146 RequestTimeout* RT = new RequestTimeout(Instance, this, id, requests);
147 Instance->Timers->AddTimer(RT); /* The timer manager frees this */
150 /* Deallocate the processing buffer */
151 DNSRequest::~DNSRequest()
156 /** Fill a ResourceRecord class based on raw data input */
157 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
159 rr->type = (QueryType)((input[0] << 8) + input[1]);
160 rr->rr_class = (input[2] << 8) + input[3];
161 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
162 rr->rdlength = (input[8] << 8) + input[9];
165 /** Fill a DNSHeader class based on raw data input of a given length */
166 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
168 header->id[0] = input[0];
169 header->id[1] = input[1];
170 header->flags1 = input[2];
171 header->flags2 = input[3];
172 header->qdcount = (input[4] << 8) + input[5];
173 header->ancount = (input[6] << 8) + input[7];
174 header->nscount = (input[8] << 8) + input[9];
175 header->arcount = (input[10] << 8) + input[11];
176 memcpy(header->payload,&input[12],length);
179 /** Empty a DNSHeader class out into raw data, ready for transmission */
180 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
182 output[0] = header->id[0];
183 output[1] = header->id[1];
184 output[2] = header->flags1;
185 output[3] = header->flags2;
186 output[4] = header->qdcount >> 8;
187 output[5] = header->qdcount & 0xFF;
188 output[6] = header->ancount >> 8;
189 output[7] = header->ancount & 0xFF;
190 output[8] = header->nscount >> 8;
191 output[9] = header->nscount & 0xFF;
192 output[10] = header->arcount >> 8;
193 output[11] = header->arcount & 0xFF;
194 memcpy(&output[12],header->payload,length);
197 /** Send requests we have previously built down the UDP socket */
198 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
201 unsigned char payload[sizeof(DNSHeader)];
206 DNS::EmptyHeader(payload,header,length);
208 memset(&addr,0,sizeof(addr));
210 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
211 addr.sin6_family = AF_FAMILY;
212 addr.sin6_port = htons(DNS::QUERY_PORT);
214 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
215 addr.sin_family = AF_FAMILY;
216 addr.sin_port = htons(DNS::QUERY_PORT);
218 if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
224 /** Add a query with a predefined header, and allocate an ID for it. */
225 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
227 /* Is the DNS connection down? */
228 if (this->GetFd() == -1)
231 /* Are there already the max number of requests on the go? */
232 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
236 id = this->PRNG() & DNS::MAX_REQUEST_ID;
238 /* If this id is already 'in flight', pick another. */
239 while (requests.find(id) != requests.end())
240 id = this->PRNG() & DNS::MAX_REQUEST_ID;
242 DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id, requests);
244 header->id[0] = req->id[0] = id >> 8;
245 header->id[1] = req->id[1] = id & 0xFF;
246 header->flags1 = FLAGS_MASK_RD;
253 /* At this point we already know the id doesnt exist,
254 * so there needs to be no second check for the ::end()
258 /* According to the C++ spec, new never returns NULL. */
262 /** Initialise the DNS UDP socket so that we can send requests */
263 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
265 ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
269 /* Clear the Resolver class table */
270 memset(Classes,0,sizeof(Classes));
272 /* Set the id of the next request to 0
276 /* By default we're not munging ip's
280 /* Clear the namesever address */
281 memset(&myserver,0,sizeof(insp_inaddr));
283 /* Convert the nameserver address into an insp_inaddr */
284 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
286 memcpy(&myserver,&addr,sizeof(insp_inaddr));
287 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
289 /* These dont come back looking like they did when they went in.
290 * We're forced to turn some checks off.
291 * If anyone knows how to fix this, let me know. --Brain
293 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
294 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
295 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
296 this->ip6munge = true;
298 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
302 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
305 /* Initialize mastersocket */
306 this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
307 if (this->GetFd() != -1)
309 /* Did it succeed? */
310 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
312 /* Couldn't make the socket nonblocking */
313 shutdown(this->GetFd(),2);
314 close(this->GetFd());
320 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
322 /* Have we got a socket and is it nonblocking? */
323 if (this->GetFd() != -1)
327 memset(&addr,0,sizeof(addr));
328 addr.sin6_family = AF_FAMILY;
330 addr.sin6_addr = in6addr_any;
333 memset(&addr,0,sizeof(addr));
334 addr.sin_family = AF_FAMILY;
336 addr.sin_addr.s_addr = INADDR_ANY;
339 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
342 ServerInstance->Log(DEBUG,"Cant bind DNS fd");
343 shutdown(this->GetFd(),2);
344 close(this->GetFd());
348 if (this->GetFd() >= 0)
350 ServerInstance->Log(DEBUG,"Add master socket %d",this->GetFd());
351 /* Hook the descriptor into the socket engine */
352 if (ServerInstance && ServerInstance->SE)
354 if (!ServerInstance->SE->AddFd(this))
356 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
357 shutdown(this->GetFd(),2);
358 close(this->GetFd());
366 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
367 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
369 short payloadpos = 0;
370 const char* tempchr, *tempchr2 = name;
371 unsigned short length;
373 /* split name up into labels, create query */
374 while ((tempchr = strchr(tempchr2,'.')) != NULL)
376 length = tempchr - tempchr2;
377 if (payloadpos + length + 1 > 507)
379 payload[payloadpos++] = length;
380 memcpy(&payload[payloadpos],tempchr2,length);
381 payloadpos += length;
382 tempchr2 = &tempchr[1];
384 length = strlen(tempchr2);
387 if (payloadpos + length + 2 > 507)
389 payload[payloadpos++] = length;
390 memcpy(&payload[payloadpos],tempchr2,length);
391 payloadpos += length;
392 payload[payloadpos++] = 0;
394 if (payloadpos > 508)
397 memcpy(&payload[payloadpos],&length,2);
398 length = htons(rr_class);
399 memcpy(&payload[payloadpos + 2],&length,2);
400 return payloadpos + 4;
403 /** Start lookup of an hostname to an IP address */
404 int DNS::GetIP(const char *name)
410 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
413 DNSRequest* req = this->AddQuery(&h, id);
415 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
421 /** Start lookup of an hostname to an IPv6 address */
422 int DNS::GetIP6(const char *name)
428 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
431 DNSRequest* req = this->AddQuery(&h, id);
433 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
439 /** Start lookup of a cname to another name */
440 int DNS::GetCName(const char *alias)
446 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
449 DNSRequest* req = this->AddQuery(&h, id);
451 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
457 /** Start lookup of an IP address to a hostname */
458 int DNS::GetName(const insp_inaddr *ip)
466 DNS::MakeIP6Int(query, (in6_addr*)ip);
468 unsigned char* c = (unsigned char*)&ip->s_addr;
470 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
473 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
476 DNSRequest* req = this->AddQuery(&h, id);
478 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
484 /** Start lookup of an IP address to a hostname */
485 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
491 #ifdef SUPPORT_IP6LINKS
492 if (fp == PROTOCOL_IPV6)
495 if (inet_pton(AF_INET6, ip, &i) > 0)
497 DNS::MakeIP6Int(query, &i);
500 /* Invalid IP address */
507 if (inet_aton(ip, &i))
509 unsigned char* c = (unsigned char*)&i.s_addr;
510 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
513 /* Invalid IP address */
517 ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
519 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
522 DNSRequest* req = this->AddQuery(&h, id);
524 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
530 /** Build an ipv6 reverse domain from an in6_addr
532 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
534 #ifdef SUPPORT_IP6LINKS
535 const char* hex = "0123456789abcdef";
536 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
540 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
543 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
544 *query++ = '.'; /* Seperator */
546 strcpy(query,"ip6.arpa"); /* Suffix the string */
552 /** Return the next id which is ready, and the result attached to it */
553 DNSResult DNS::GetResult()
555 /* Fetch dns query response and decide where it belongs */
558 unsigned char buffer[sizeof(DNSHeader)];
560 socklen_t x = sizeof(from);
561 const char* ipaddr_from = "";
562 unsigned short int port_from = 0;
564 int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
567 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
569 /* Did we get the whole header? */
572 /* Nope - something screwed up. */
573 ServerInstance->Log(DEBUG,"Whole header not read!");
574 return std::make_pair(-1,"");
577 /* Check wether the reply came from a different DNS
578 * server to the one we sent it to, or the source-port
580 * A user could in theory still spoof dns packets anyway
581 * but this is less trivial than just sending garbage
582 * to the client, which is possible without this check.
584 * -- Thanks jilles for pointing this one out.
587 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
588 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
590 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
591 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
594 /* We cant perform this security check if you're using 4in6.
595 * Tough luck to you, choose one or't other!
599 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
601 ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
602 return std::make_pair(-1,"");
606 /* Put the read header info into a header class */
607 DNS::FillHeader(&header,buffer,length - 12);
609 /* Get the id of this request.
610 * Its a 16 bit value stored in two char's,
611 * so we use logic shifts to create the value.
613 unsigned long this_id = header.id[1] + (header.id[0] << 8);
615 /* Do we have a pending request matching this id? */
616 requestlist_iter n_iter = requests.find(this_id);
617 if (n_iter == requests.end())
619 /* Somehow we got a DNS response for a request we never made... */
620 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
621 return std::make_pair(-1,"");
625 /* Remove the query from the list of pending queries */
626 req = (DNSRequest*)n_iter->second;
627 requests.erase(n_iter);
630 /* Inform the DNSRequest class that it has a result to be read.
631 * When its finished it will return a DNSInfo which is a pair of
632 * unsigned char* resource record data, and an error message.
634 DNSInfo data = req->ResultIsReady(header, length);
635 std::string resultstr;
637 /* Check if we got a result, if we didnt, its an error */
638 if (data.first == NULL)
641 * Mask the ID with the value of ERROR_MASK, so that
642 * the dns_deal_with_classes() function knows that its
643 * an error response and needs to be treated uniquely.
644 * Put the error message in the second field.
647 return std::make_pair(this_id | ERROR_MASK, data.second);
653 /* Forward lookups come back as binary data. We must format them into ascii */
657 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
658 resultstr = formatted;
663 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
664 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
665 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
666 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
667 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
668 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
669 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
670 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
671 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
672 char* c = strstr(formatted,":0:");
675 memmove(c+1,c+2,strlen(c+2) + 1);
677 while (memcmp(c,"0:",2) == 0)
678 memmove(c,c+2,strlen(c+2) + 1);
679 if (memcmp(c,"0",2) == 0)
681 if (memcmp(formatted,"0::",3) == 0)
682 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
684 resultstr = formatted;
686 /* Special case. Sending ::1 around between servers
687 * and to clients is dangerous, because the : on the
688 * start makes the client or server interpret the IP
689 * as the last parameter on the line with a value ":1".
691 if (*formatted == ':')
692 resultstr = "0" + resultstr;
696 case DNS_QUERY_CNAME:
697 /* Identical handling to PTR */
700 /* Reverse lookups just come back as char* */
701 resultstr = std::string((const char*)data.first);
705 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
710 /* Build the reply with the id and hostname/ip in it */
712 return std::make_pair(this_id,resultstr);
716 /** A result is ready, process it */
717 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
725 if (!(header.flags1 & FLAGS_MASK_QR))
726 return std::make_pair((unsigned char*)NULL,"Not a query result");
728 if (header.flags1 & FLAGS_MASK_OPCODE)
729 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
731 if (header.flags2 & FLAGS_MASK_RCODE)
732 return std::make_pair((unsigned char*)NULL,"Domain name not found");
734 if (header.ancount < 1)
735 return std::make_pair((unsigned char*)NULL,"No resource records returned");
737 /* Subtract the length of the header from the length of the packet */
740 while ((unsigned int)q < header.qdcount && i < length)
742 if (header.payload[i] > 63)
749 if (header.payload[i] == 0)
754 else i += header.payload[i] + 1;
758 while ((unsigned)curanswer < header.ancount)
761 while (q == 0 && i < length)
763 if (header.payload[i] > 63)
770 if (header.payload[i] == 0)
775 else i += header.payload[i] + 1; /* skip length and label */
779 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
781 DNS::FillResourceRecord(&rr,&header.payload[i]);
783 if (rr.type != this->type)
789 if (rr.rr_class != this->rr_class)
797 if ((unsigned int)curanswer == header.ancount)
798 return std::make_pair((unsigned char*)NULL,"No valid answers");
800 if (i + rr.rdlength > (unsigned int)length)
801 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
803 if (rr.rdlength > 1023)
804 return std::make_pair((unsigned char*)NULL,"Resource record too large");
808 case DNS_QUERY_CNAME:
809 /* CNAME and PTR have the same processing code */
813 while (q == 0 && i < length && o + 256 < 1023)
815 if (header.payload[i] > 63)
817 memcpy(&ptr,&header.payload[i],2);
818 i = ntohs(ptr) - 0xC000 - 12;
822 if (header.payload[i] == 0)
831 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
832 o += header.payload[i];
833 i += header.payload[i] + 1;
840 memcpy(res,&header.payload[i],rr.rdlength);
841 res[rr.rdlength] = 0;
844 memcpy(res,&header.payload[i],rr.rdlength);
845 res[rr.rdlength] = 0;
848 memcpy(res,&header.payload[i],rr.rdlength);
849 res[rr.rdlength] = 0;
852 return std::make_pair(res,"No error");;
855 /** Close the master socket */
858 shutdown(this->GetFd(), 2);
859 close(this->GetFd());
862 /** High level abstraction of dns used by application at large */
863 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
865 ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
872 this->myid = ServerInstance->Res->GetIP(source.c_str());
876 if (insp_aton(source.c_str(), &binip) > 0)
878 /* Valid ip address */
879 this->myid = ServerInstance->Res->GetName(&binip);
883 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
884 throw ModuleException("Resolver: Bad IP address");
890 querytype = DNS_QUERY_PTR;
891 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
895 querytype = DNS_QUERY_PTR;
896 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
900 this->myid = ServerInstance->Res->GetIP6(source.c_str());
903 case DNS_QUERY_CNAME:
904 this->myid = ServerInstance->Res->GetCName(source.c_str());
911 if (this->myid == -1)
913 ServerInstance->Log(DEBUG,"Resolver::Resolver: Could not get an id!");
914 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
915 throw ModuleException("Resolver: Couldnt get an id to make a request");
916 /* We shouldnt get here really */
920 ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
923 /** Called when an error occurs */
924 void Resolver::OnError(ResolverError e, const std::string &errormessage)
926 /* Nothing in here */
929 /** Destroy a resolver */
930 Resolver::~Resolver()
932 /* Nothing here (yet) either */
935 /** Get the request id associated with this class */
936 int Resolver::GetId()
941 /** Process a socket read event */
942 void DNS::HandleEvent(EventType et)
944 ServerInstance->Log(DEBUG,"Marshall reads: %d",this->GetFd());
945 /* Fetch the id and result of the next available packet */
946 DNSResult res = this->GetResult();
947 /* Is there a usable request id? */
950 /* Its an error reply */
951 if (res.first & ERROR_MASK)
953 /* Mask off the error bit */
954 res.first -= ERROR_MASK;
955 /* Marshall the error to the correct class */
956 ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
957 if (Classes[res.first])
959 if (ServerInstance && ServerInstance->stats)
960 ServerInstance->stats->statsDnsBad++;
961 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
962 delete Classes[res.first];
963 Classes[res.first] = NULL;
968 /* It is a non-error result */
969 ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
970 /* Marshall the result to the correct class */
971 if (Classes[res.first])
973 if (ServerInstance && ServerInstance->stats)
974 ServerInstance->stats->statsDnsGood++;
975 Classes[res.first]->OnLookupComplete(res.second);
976 delete Classes[res.first];
977 Classes[res.first] = NULL;
981 if (ServerInstance && ServerInstance->stats)
982 ServerInstance->stats->statsDns++;
986 /** Add a derived Resolver to the working set */
987 bool DNS::AddResolverClass(Resolver* r)
989 /* Check the pointers validity and the id's validity */
990 if ((r) && (r->GetId() > -1))
992 /* Check the slot isnt already occupied -
993 * This should NEVER happen unless we have
994 * a severely broken DNS server somewhere
996 if (!Classes[r->GetId()])
998 /* Set up the pointer to the class */
999 Classes[r->GetId()] = r;
1008 /* Pointer or id not valid.
1009 * Free the item and return
1018 /** Generate pseudo-random number */
1019 unsigned long DNS::PRNG()
1021 unsigned long val = 0;
1023 serverstats* s = ServerInstance->stats;
1024 gettimeofday(&n,NULL);
1025 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1026 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1027 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;