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 rl.erase(rl.find(watchid));
131 ServerInstance->Log(DEBUG,"DNS timeout on %08x squished pointer", watch);
135 ServerInstance->Log(DEBUG,"DNS timeout on %08x: result already received!", watch);
139 /* Allocate the processing buffer */
140 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, requestlist &requests) : dnsobj(dns)
142 res = new unsigned char[512];
144 memcpy(&myserver, &server, sizeof(insp_inaddr));
145 RequestTimeout* RT = new RequestTimeout(Instance, this, id, requests);
146 Instance->Timers->AddTimer(RT); /* The timer manager frees this */
149 /* Deallocate the processing buffer */
150 DNSRequest::~DNSRequest()
155 /** Fill a ResourceRecord class based on raw data input */
156 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
158 rr->type = (QueryType)((input[0] << 8) + input[1]);
159 rr->rr_class = (input[2] << 8) + input[3];
160 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
161 rr->rdlength = (input[8] << 8) + input[9];
164 /** Fill a DNSHeader class based on raw data input of a given length */
165 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
167 header->id[0] = input[0];
168 header->id[1] = input[1];
169 header->flags1 = input[2];
170 header->flags2 = input[3];
171 header->qdcount = (input[4] << 8) + input[5];
172 header->ancount = (input[6] << 8) + input[7];
173 header->nscount = (input[8] << 8) + input[9];
174 header->arcount = (input[10] << 8) + input[11];
175 memcpy(header->payload,&input[12],length);
178 /** Empty a DNSHeader class out into raw data, ready for transmission */
179 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
181 output[0] = header->id[0];
182 output[1] = header->id[1];
183 output[2] = header->flags1;
184 output[3] = header->flags2;
185 output[4] = header->qdcount >> 8;
186 output[5] = header->qdcount & 0xFF;
187 output[6] = header->ancount >> 8;
188 output[7] = header->ancount & 0xFF;
189 output[8] = header->nscount >> 8;
190 output[9] = header->nscount & 0xFF;
191 output[10] = header->arcount >> 8;
192 output[11] = header->arcount & 0xFF;
193 memcpy(&output[12],header->payload,length);
196 /** Send requests we have previously built down the UDP socket */
197 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
200 unsigned char payload[sizeof(DNSHeader)];
205 DNS::EmptyHeader(payload,header,length);
207 memset(&addr,0,sizeof(addr));
209 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
210 addr.sin6_family = AF_FAMILY;
211 addr.sin6_port = htons(DNS::QUERY_PORT);
213 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
214 addr.sin_family = AF_FAMILY;
215 addr.sin_port = htons(DNS::QUERY_PORT);
217 if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
223 /** Add a query with a predefined header, and allocate an ID for it. */
224 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
226 /* Is the DNS connection down? */
227 if (this->GetFd() == -1)
230 /* Are there already the max number of requests on the go? */
231 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
235 id = this->PRNG() & DNS::MAX_REQUEST_ID;
237 /* If this id is already 'in flight', pick another. */
238 while (requests.find(id) != requests.end())
239 id = this->PRNG() & DNS::MAX_REQUEST_ID;
241 DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id, requests);
243 header->id[0] = req->id[0] = id >> 8;
244 header->id[1] = req->id[1] = id & 0xFF;
245 header->flags1 = FLAGS_MASK_RD;
252 /* At this point we already know the id doesnt exist,
253 * so there needs to be no second check for the ::end()
257 /* According to the C++ spec, new never returns NULL. */
261 /** Initialise the DNS UDP socket so that we can send requests */
262 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
264 ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
268 /* Clear the Resolver class table */
269 memset(Classes,0,sizeof(Classes));
271 /* Set the id of the next request to 0
275 /* By default we're not munging ip's
279 /* Clear the namesever address */
280 memset(&myserver,0,sizeof(insp_inaddr));
282 /* Convert the nameserver address into an insp_inaddr */
283 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
285 memcpy(&myserver,&addr,sizeof(insp_inaddr));
286 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
288 /* These dont come back looking like they did when they went in.
289 * We're forced to turn some checks off.
290 * If anyone knows how to fix this, let me know. --Brain
292 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
293 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
294 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
295 this->ip6munge = true;
297 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
301 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
304 /* Initialize mastersocket */
305 this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
306 if (this->GetFd() != -1)
308 /* Did it succeed? */
309 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
311 /* Couldn't make the socket nonblocking */
312 shutdown(this->GetFd(),2);
313 close(this->GetFd());
319 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
321 /* Have we got a socket and is it nonblocking? */
322 if (this->GetFd() != -1)
326 memset(&addr,0,sizeof(addr));
327 addr.sin6_family = AF_FAMILY;
329 addr.sin6_addr = in6addr_any;
332 memset(&addr,0,sizeof(addr));
333 addr.sin_family = AF_FAMILY;
335 addr.sin_addr.s_addr = INADDR_ANY;
338 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
341 ServerInstance->Log(DEBUG,"Cant bind DNS fd");
342 shutdown(this->GetFd(),2);
343 close(this->GetFd());
347 if (this->GetFd() >= 0)
349 ServerInstance->Log(DEBUG,"Add master socket %d",this->GetFd());
350 /* Hook the descriptor into the socket engine */
351 if (ServerInstance && ServerInstance->SE)
353 if (!ServerInstance->SE->AddFd(this))
355 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
356 shutdown(this->GetFd(),2);
357 close(this->GetFd());
365 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
366 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
368 short payloadpos = 0;
369 const char* tempchr, *tempchr2 = name;
370 unsigned short length;
372 /* split name up into labels, create query */
373 while ((tempchr = strchr(tempchr2,'.')) != NULL)
375 length = tempchr - tempchr2;
376 if (payloadpos + length + 1 > 507)
378 payload[payloadpos++] = length;
379 memcpy(&payload[payloadpos],tempchr2,length);
380 payloadpos += length;
381 tempchr2 = &tempchr[1];
383 length = strlen(tempchr2);
386 if (payloadpos + length + 2 > 507)
388 payload[payloadpos++] = length;
389 memcpy(&payload[payloadpos],tempchr2,length);
390 payloadpos += length;
391 payload[payloadpos++] = 0;
393 if (payloadpos > 508)
396 memcpy(&payload[payloadpos],&length,2);
397 length = htons(rr_class);
398 memcpy(&payload[payloadpos + 2],&length,2);
399 return payloadpos + 4;
402 /** Start lookup of an hostname to an IP address */
403 int DNS::GetIP(const char *name)
409 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
412 DNSRequest* req = this->AddQuery(&h, id);
414 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
420 /** Start lookup of an hostname to an IPv6 address */
421 int DNS::GetIP6(const char *name)
427 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
430 DNSRequest* req = this->AddQuery(&h, id);
432 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
438 /** Start lookup of a cname to another name */
439 int DNS::GetCName(const char *alias)
445 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
448 DNSRequest* req = this->AddQuery(&h, id);
450 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
456 /** Start lookup of an IP address to a hostname */
457 int DNS::GetName(const insp_inaddr *ip)
465 DNS::MakeIP6Int(query, (in6_addr*)ip);
467 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 requestlist_iter n_iter = requests.find(this_id);
616 if (n_iter == requests.end())
618 /* Somehow we got a DNS response for a request we never made... */
619 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
620 return std::make_pair(-1,"");
624 /* Remove the query from the list of pending queries */
625 req = (DNSRequest*)n_iter->second;
626 requests.erase(n_iter);
629 /* Inform the DNSRequest class that it has a result to be read.
630 * When its finished it will return a DNSInfo which is a pair of
631 * unsigned char* resource record data, and an error message.
633 DNSInfo data = req->ResultIsReady(header, length);
634 std::string resultstr;
636 /* Check if we got a result, if we didnt, its an error */
637 if (data.first == NULL)
640 * Mask the ID with the value of ERROR_MASK, so that
641 * the dns_deal_with_classes() function knows that its
642 * an error response and needs to be treated uniquely.
643 * Put the error message in the second field.
646 return std::make_pair(this_id | ERROR_MASK, data.second);
652 /* Forward lookups come back as binary data. We must format them into ascii */
656 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
657 resultstr = formatted;
662 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
663 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
664 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
665 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
666 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
667 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
668 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
669 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
670 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
671 char* c = strstr(formatted,":0:");
674 memmove(c+1,c+2,strlen(c+2) + 1);
676 while (memcmp(c,"0:",2) == 0)
677 memmove(c,c+2,strlen(c+2) + 1);
678 if (memcmp(c,"0",2) == 0)
680 if (memcmp(formatted,"0::",3) == 0)
681 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
683 resultstr = formatted;
685 /* Special case. Sending ::1 around between servers
686 * and to clients is dangerous, because the : on the
687 * start makes the client or server interpret the IP
688 * as the last parameter on the line with a value ":1".
690 if (*formatted == ':')
691 resultstr = "0" + resultstr;
695 case DNS_QUERY_CNAME:
696 /* Identical handling to PTR */
699 /* Reverse lookups just come back as char* */
700 resultstr = std::string((const char*)data.first);
704 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
709 /* Build the reply with the id and hostname/ip in it */
711 return std::make_pair(this_id,resultstr);
715 /** A result is ready, process it */
716 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
724 if (!(header.flags1 & FLAGS_MASK_QR))
725 return std::make_pair((unsigned char*)NULL,"Not a query result");
727 if (header.flags1 & FLAGS_MASK_OPCODE)
728 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
730 if (header.flags2 & FLAGS_MASK_RCODE)
731 return std::make_pair((unsigned char*)NULL,"Domain name not found");
733 if (header.ancount < 1)
734 return std::make_pair((unsigned char*)NULL,"No resource records returned");
736 /* Subtract the length of the header from the length of the packet */
739 while ((unsigned int)q < header.qdcount && i < length)
741 if (header.payload[i] > 63)
748 if (header.payload[i] == 0)
753 else i += header.payload[i] + 1;
757 while ((unsigned)curanswer < header.ancount)
760 while (q == 0 && i < length)
762 if (header.payload[i] > 63)
769 if (header.payload[i] == 0)
774 else i += header.payload[i] + 1; /* skip length and label */
778 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
780 DNS::FillResourceRecord(&rr,&header.payload[i]);
782 if (rr.type != this->type)
788 if (rr.rr_class != this->rr_class)
796 if ((unsigned int)curanswer == header.ancount)
797 return std::make_pair((unsigned char*)NULL,"No valid answers");
799 if (i + rr.rdlength > (unsigned int)length)
800 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
802 if (rr.rdlength > 1023)
803 return std::make_pair((unsigned char*)NULL,"Resource record too large");
807 case DNS_QUERY_CNAME:
808 /* CNAME and PTR have the same processing code */
812 while (q == 0 && i < length && o + 256 < 1023)
814 if (header.payload[i] > 63)
816 memcpy(&ptr,&header.payload[i],2);
817 i = ntohs(ptr) - 0xC000 - 12;
821 if (header.payload[i] == 0)
830 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
831 o += header.payload[i];
832 i += header.payload[i] + 1;
839 memcpy(res,&header.payload[i],rr.rdlength);
840 res[rr.rdlength] = 0;
843 memcpy(res,&header.payload[i],rr.rdlength);
844 res[rr.rdlength] = 0;
847 memcpy(res,&header.payload[i],rr.rdlength);
848 res[rr.rdlength] = 0;
851 return std::make_pair(res,"No error");;
854 /** Close the master socket */
857 shutdown(this->GetFd(), 2);
858 close(this->GetFd());
861 /** High level abstraction of dns used by application at large */
862 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
864 ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
871 this->myid = ServerInstance->Res->GetIP(source.c_str());
875 if (insp_aton(source.c_str(), &binip) > 0)
877 /* Valid ip address */
878 this->myid = ServerInstance->Res->GetName(&binip);
882 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
883 throw ModuleException("Resolver: Bad IP address");
889 querytype = DNS_QUERY_PTR;
890 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
894 querytype = DNS_QUERY_PTR;
895 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
899 this->myid = ServerInstance->Res->GetIP6(source.c_str());
902 case DNS_QUERY_CNAME:
903 this->myid = ServerInstance->Res->GetCName(source.c_str());
910 if (this->myid == -1)
912 ServerInstance->Log(DEBUG,"Resolver::Resolver: Could not get an id!");
913 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
914 throw ModuleException("Resolver: Couldnt get an id to make a request");
915 /* We shouldnt get here really */
919 ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
922 /** Called when an error occurs */
923 void Resolver::OnError(ResolverError e, const std::string &errormessage)
925 /* Nothing in here */
928 /** Destroy a resolver */
929 Resolver::~Resolver()
931 /* Nothing here (yet) either */
934 /** Get the request id associated with this class */
935 int Resolver::GetId()
940 /** Process a socket read event */
941 void DNS::HandleEvent(EventType et)
943 ServerInstance->Log(DEBUG,"Marshall reads: %d",this->GetFd());
944 /* Fetch the id and result of the next available packet */
945 DNSResult res = this->GetResult();
946 /* Is there a usable request id? */
949 /* Its an error reply */
950 if (res.first & ERROR_MASK)
952 /* Mask off the error bit */
953 res.first -= ERROR_MASK;
954 /* Marshall the error to the correct class */
955 ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
956 if (Classes[res.first])
958 if (ServerInstance && ServerInstance->stats)
959 ServerInstance->stats->statsDnsBad++;
960 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
961 delete Classes[res.first];
962 Classes[res.first] = NULL;
967 /* It is a non-error result */
968 ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
969 /* Marshall the result to the correct class */
970 if (Classes[res.first])
972 if (ServerInstance && ServerInstance->stats)
973 ServerInstance->stats->statsDnsGood++;
974 Classes[res.first]->OnLookupComplete(res.second);
975 delete Classes[res.first];
976 Classes[res.first] = NULL;
980 if (ServerInstance && ServerInstance->stats)
981 ServerInstance->stats->statsDns++;
985 /** Add a derived Resolver to the working set */
986 bool DNS::AddResolverClass(Resolver* r)
988 /* Check the pointers validity and the id's validity */
989 if ((r) && (r->GetId() > -1))
991 /* Check the slot isnt already occupied -
992 * This should NEVER happen unless we have
993 * a severely broken DNS server somewhere
995 if (!Classes[r->GetId()])
997 /* Set up the pointer to the class */
998 Classes[r->GetId()] = r;
1007 /* Pointer or id not valid.
1008 * Free the item and return
1017 /** Generate pseudo-random number */
1018 unsigned long DNS::PRNG()
1020 unsigned long val = 0;
1022 serverstats* s = ServerInstance->stats;
1023 gettimeofday(&n,NULL);
1024 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1025 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1026 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;