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(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id, requestlist &requests) : InspTimer(n, 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 if (ServerInstance->Res->Classes[watchid])
131 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
132 delete ServerInstance->Res->Classes[watchid];
133 ServerInstance->Res->Classes[watchid] = NULL;
135 rl.erase(rl.find(watchid));
137 ServerInstance->Log(DEBUG, "DNS timeout on %08x squished pointer", watch);
141 ServerInstance->Log(DEBUG, "DNS timeout on %08x: result already received!", watch);
145 /* Allocate the processing buffer */
146 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, requestlist &requests) : dnsobj(dns)
148 res = new unsigned char[512];
150 memcpy(&myserver, &server, sizeof(insp_inaddr));
151 RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id, requests);
152 Instance->Timers->AddTimer(RT); /* The timer manager frees this */
155 /* Deallocate the processing buffer */
156 DNSRequest::~DNSRequest()
161 /** Fill a ResourceRecord class based on raw data input */
162 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
164 rr->type = (QueryType)((input[0] << 8) + input[1]);
165 rr->rr_class = (input[2] << 8) + input[3];
166 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
167 rr->rdlength = (input[8] << 8) + input[9];
170 /** Fill a DNSHeader class based on raw data input of a given length */
171 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
173 header->id[0] = input[0];
174 header->id[1] = input[1];
175 header->flags1 = input[2];
176 header->flags2 = input[3];
177 header->qdcount = (input[4] << 8) + input[5];
178 header->ancount = (input[6] << 8) + input[7];
179 header->nscount = (input[8] << 8) + input[9];
180 header->arcount = (input[10] << 8) + input[11];
181 memcpy(header->payload,&input[12],length);
184 /** Empty a DNSHeader class out into raw data, ready for transmission */
185 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
187 output[0] = header->id[0];
188 output[1] = header->id[1];
189 output[2] = header->flags1;
190 output[3] = header->flags2;
191 output[4] = header->qdcount >> 8;
192 output[5] = header->qdcount & 0xFF;
193 output[6] = header->ancount >> 8;
194 output[7] = header->ancount & 0xFF;
195 output[8] = header->nscount >> 8;
196 output[9] = header->nscount & 0xFF;
197 output[10] = header->arcount >> 8;
198 output[11] = header->arcount & 0xFF;
199 memcpy(&output[12],header->payload,length);
202 /** Send requests we have previously built down the UDP socket */
203 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
206 unsigned char payload[sizeof(DNSHeader)];
211 DNS::EmptyHeader(payload,header,length);
213 memset(&addr,0,sizeof(addr));
215 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
216 addr.sin6_family = AF_FAMILY;
217 addr.sin6_port = htons(DNS::QUERY_PORT);
219 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
220 addr.sin_family = AF_FAMILY;
221 addr.sin_port = htons(DNS::QUERY_PORT);
223 if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
229 /** Add a query with a predefined header, and allocate an ID for it. */
230 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
232 /* Is the DNS connection down? */
233 if (this->GetFd() == -1)
236 /* Are there already the max number of requests on the go? */
237 if (requests.size() == DNS::MAX_REQUEST_ID + 1)
241 id = this->PRNG() & DNS::MAX_REQUEST_ID;
243 /* If this id is already 'in flight', pick another. */
244 while (requests.find(id) != requests.end())
245 id = this->PRNG() & DNS::MAX_REQUEST_ID;
247 DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id, requests);
249 header->id[0] = req->id[0] = id >> 8;
250 header->id[1] = req->id[1] = id & 0xFF;
251 header->flags1 = FLAGS_MASK_RD;
258 /* At this point we already know the id doesnt exist,
259 * so there needs to be no second check for the ::end()
263 /* According to the C++ spec, new never returns NULL. */
267 /** Initialise the DNS UDP socket so that we can send requests */
268 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
270 ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
274 /* Clear the Resolver class table */
275 memset(Classes,0,sizeof(Classes));
277 /* Set the id of the next request to 0
281 /* By default we're not munging ip's
285 /* Clear the namesever address */
286 memset(&myserver,0,sizeof(insp_inaddr));
288 /* Convert the nameserver address into an insp_inaddr */
289 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
291 memcpy(&myserver,&addr,sizeof(insp_inaddr));
292 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
294 /* These dont come back looking like they did when they went in.
295 * We're forced to turn some checks off.
296 * If anyone knows how to fix this, let me know. --Brain
298 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
299 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
300 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
301 this->ip6munge = true;
303 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
307 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
310 /* Initialize mastersocket */
311 this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
312 if (this->GetFd() != -1)
314 /* Did it succeed? */
315 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
317 /* Couldn't make the socket nonblocking */
318 shutdown(this->GetFd(),2);
319 close(this->GetFd());
325 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
327 /* Have we got a socket and is it nonblocking? */
328 if (this->GetFd() != -1)
332 memset(&addr,0,sizeof(addr));
333 addr.sin6_family = AF_FAMILY;
335 addr.sin6_addr = in6addr_any;
338 memset(&addr,0,sizeof(addr));
339 addr.sin_family = AF_FAMILY;
341 addr.sin_addr.s_addr = INADDR_ANY;
344 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
347 ServerInstance->Log(DEBUG,"Cant bind DNS fd");
348 shutdown(this->GetFd(),2);
349 close(this->GetFd());
353 if (this->GetFd() >= 0)
355 ServerInstance->Log(DEBUG,"Add master socket %d",this->GetFd());
356 /* Hook the descriptor into the socket engine */
357 if (ServerInstance && ServerInstance->SE)
359 if (!ServerInstance->SE->AddFd(this))
361 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
362 shutdown(this->GetFd(),2);
363 close(this->GetFd());
371 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
372 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
374 short payloadpos = 0;
375 const char* tempchr, *tempchr2 = name;
376 unsigned short length;
378 /* split name up into labels, create query */
379 while ((tempchr = strchr(tempchr2,'.')) != NULL)
381 length = tempchr - tempchr2;
382 if (payloadpos + length + 1 > 507)
384 payload[payloadpos++] = length;
385 memcpy(&payload[payloadpos],tempchr2,length);
386 payloadpos += length;
387 tempchr2 = &tempchr[1];
389 length = strlen(tempchr2);
392 if (payloadpos + length + 2 > 507)
394 payload[payloadpos++] = length;
395 memcpy(&payload[payloadpos],tempchr2,length);
396 payloadpos += length;
397 payload[payloadpos++] = 0;
399 if (payloadpos > 508)
402 memcpy(&payload[payloadpos],&length,2);
403 length = htons(rr_class);
404 memcpy(&payload[payloadpos + 2],&length,2);
405 return payloadpos + 4;
408 /** Start lookup of an hostname to an IP address */
409 int DNS::GetIP(const char *name)
415 if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
418 DNSRequest* req = this->AddQuery(&h, id);
420 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
426 /** Start lookup of an hostname to an IPv6 address */
427 int DNS::GetIP6(const char *name)
433 if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
436 DNSRequest* req = this->AddQuery(&h, id);
438 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
444 /** Start lookup of a cname to another name */
445 int DNS::GetCName(const char *alias)
451 if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
454 DNSRequest* req = this->AddQuery(&h, id);
456 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
462 /** Start lookup of an IP address to a hostname */
463 int DNS::GetName(const insp_inaddr *ip)
471 unsigned char* c = (unsigned char*)&ip->s6_addr;
472 if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
473 c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
474 c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
475 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
477 DNS::MakeIP6Int(query, (in6_addr*)ip);
479 unsigned char* c = (unsigned char*)&ip->s_addr;
480 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
483 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
486 DNSRequest* req = this->AddQuery(&h, id);
488 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
494 /** Start lookup of an IP address to a hostname */
495 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
501 #ifdef SUPPORT_IP6LINKS
502 if (fp == PROTOCOL_IPV6)
505 if (inet_pton(AF_INET6, ip, &i) > 0)
507 DNS::MakeIP6Int(query, &i);
510 /* Invalid IP address */
517 if (inet_aton(ip, &i))
519 unsigned char* c = (unsigned char*)&i.s_addr;
520 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
523 /* Invalid IP address */
527 ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
529 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
532 DNSRequest* req = this->AddQuery(&h, id);
534 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
540 /** Build an ipv6 reverse domain from an in6_addr
542 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
544 #ifdef SUPPORT_IP6LINKS
545 const char* hex = "0123456789abcdef";
546 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
550 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
553 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
554 *query++ = '.'; /* Seperator */
556 strcpy(query,"ip6.arpa"); /* Suffix the string */
562 /** Return the next id which is ready, and the result attached to it */
563 DNSResult DNS::GetResult()
565 /* Fetch dns query response and decide where it belongs */
568 unsigned char buffer[sizeof(DNSHeader)];
570 socklen_t x = sizeof(from);
571 const char* ipaddr_from = "";
572 unsigned short int port_from = 0;
574 int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
577 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
579 /* Did we get the whole header? */
582 /* Nope - something screwed up. */
583 ServerInstance->Log(DEBUG,"Whole header not read!");
584 return std::make_pair(-1,"");
587 /* Check wether the reply came from a different DNS
588 * server to the one we sent it to, or the source-port
590 * A user could in theory still spoof dns packets anyway
591 * but this is less trivial than just sending garbage
592 * to the client, which is possible without this check.
594 * -- Thanks jilles for pointing this one out.
597 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
598 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
600 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
601 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
604 /* We cant perform this security check if you're using 4in6.
605 * Tough luck to you, choose one or't other!
609 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
611 ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
612 return std::make_pair(-1,"");
616 /* Put the read header info into a header class */
617 DNS::FillHeader(&header,buffer,length - 12);
619 /* Get the id of this request.
620 * Its a 16 bit value stored in two char's,
621 * so we use logic shifts to create the value.
623 unsigned long this_id = header.id[1] + (header.id[0] << 8);
625 /* Do we have a pending request matching this id? */
626 requestlist_iter n_iter = requests.find(this_id);
627 if (n_iter == requests.end())
629 /* Somehow we got a DNS response for a request we never made... */
630 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
631 return std::make_pair(-1,"");
635 /* Remove the query from the list of pending queries */
636 req = (DNSRequest*)n_iter->second;
637 requests.erase(n_iter);
640 /* Inform the DNSRequest class that it has a result to be read.
641 * When its finished it will return a DNSInfo which is a pair of
642 * unsigned char* resource record data, and an error message.
644 DNSInfo data = req->ResultIsReady(header, length);
645 std::string resultstr;
647 /* Check if we got a result, if we didnt, its an error */
648 if (data.first == NULL)
651 * Mask the ID with the value of ERROR_MASK, so that
652 * the dns_deal_with_classes() function knows that its
653 * an error response and needs to be treated uniquely.
654 * Put the error message in the second field.
657 return std::make_pair(this_id | ERROR_MASK, data.second);
663 /* Forward lookups come back as binary data. We must format them into ascii */
667 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
668 resultstr = formatted;
673 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
674 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
675 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
676 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
677 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
678 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
679 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
680 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
681 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
682 char* c = strstr(formatted,":0:");
685 memmove(c+1,c+2,strlen(c+2) + 1);
687 while (memcmp(c,"0:",2) == 0)
688 memmove(c,c+2,strlen(c+2) + 1);
689 if (memcmp(c,"0",2) == 0)
691 if (memcmp(formatted,"0::",3) == 0)
692 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
694 resultstr = formatted;
696 /* Special case. Sending ::1 around between servers
697 * and to clients is dangerous, because the : on the
698 * start makes the client or server interpret the IP
699 * as the last parameter on the line with a value ":1".
701 if (*formatted == ':')
702 resultstr = "0" + resultstr;
706 case DNS_QUERY_CNAME:
707 /* Identical handling to PTR */
710 /* Reverse lookups just come back as char* */
711 resultstr = std::string((const char*)data.first);
715 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
720 /* Build the reply with the id and hostname/ip in it */
722 return std::make_pair(this_id,resultstr);
726 /** A result is ready, process it */
727 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
735 if (!(header.flags1 & FLAGS_MASK_QR))
736 return std::make_pair((unsigned char*)NULL,"Not a query result");
738 if (header.flags1 & FLAGS_MASK_OPCODE)
739 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
741 if (header.flags2 & FLAGS_MASK_RCODE)
742 return std::make_pair((unsigned char*)NULL,"Domain name not found");
744 if (header.ancount < 1)
745 return std::make_pair((unsigned char*)NULL,"No resource records returned");
747 /* Subtract the length of the header from the length of the packet */
750 while ((unsigned int)q < header.qdcount && i < length)
752 if (header.payload[i] > 63)
759 if (header.payload[i] == 0)
764 else i += header.payload[i] + 1;
768 while ((unsigned)curanswer < header.ancount)
771 while (q == 0 && i < length)
773 if (header.payload[i] > 63)
780 if (header.payload[i] == 0)
785 else i += header.payload[i] + 1; /* skip length and label */
789 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
791 DNS::FillResourceRecord(&rr,&header.payload[i]);
793 if (rr.type != this->type)
799 if (rr.rr_class != this->rr_class)
807 if ((unsigned int)curanswer == header.ancount)
808 return std::make_pair((unsigned char*)NULL,"No valid answers");
810 if (i + rr.rdlength > (unsigned int)length)
811 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
813 if (rr.rdlength > 1023)
814 return std::make_pair((unsigned char*)NULL,"Resource record too large");
818 case DNS_QUERY_CNAME:
819 /* CNAME and PTR have the same processing code */
823 while (q == 0 && i < length && o + 256 < 1023)
825 if (header.payload[i] > 63)
827 memcpy(&ptr,&header.payload[i],2);
828 i = ntohs(ptr) - 0xC000 - 12;
832 if (header.payload[i] == 0)
841 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
842 o += header.payload[i];
843 i += header.payload[i] + 1;
850 memcpy(res,&header.payload[i],rr.rdlength);
851 res[rr.rdlength] = 0;
854 memcpy(res,&header.payload[i],rr.rdlength);
855 res[rr.rdlength] = 0;
858 memcpy(res,&header.payload[i],rr.rdlength);
859 res[rr.rdlength] = 0;
862 return std::make_pair(res,"No error");;
865 /** Close the master socket */
868 shutdown(this->GetFd(), 2);
869 close(this->GetFd());
872 /** High level abstraction of dns used by application at large */
873 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
875 ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
882 this->myid = ServerInstance->Res->GetIP(source.c_str());
886 if (insp_aton(source.c_str(), &binip) > 0)
888 /* Valid ip address */
889 this->myid = ServerInstance->Res->GetName(&binip);
893 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
894 throw ModuleException("Resolver: Bad IP address");
900 querytype = DNS_QUERY_PTR;
901 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
905 querytype = DNS_QUERY_PTR;
906 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
910 this->myid = ServerInstance->Res->GetIP6(source.c_str());
913 case DNS_QUERY_CNAME:
914 this->myid = ServerInstance->Res->GetCName(source.c_str());
921 if (this->myid == -1)
923 ServerInstance->Log(DEBUG,"Resolver::Resolver: Could not get an id!");
924 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
925 throw ModuleException("Resolver: Couldnt get an id to make a request");
926 /* We shouldnt get here really */
930 ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
933 /** Called when an error occurs */
934 void Resolver::OnError(ResolverError e, const std::string &errormessage)
936 /* Nothing in here */
939 /** Destroy a resolver */
940 Resolver::~Resolver()
942 /* Nothing here (yet) either */
945 /** Get the request id associated with this class */
946 int Resolver::GetId()
951 /** Process a socket read event */
952 void DNS::HandleEvent(EventType et, int errornum)
954 ServerInstance->Log(DEBUG,"Marshall reads: %d",this->GetFd());
955 /* Fetch the id and result of the next available packet */
956 DNSResult res = this->GetResult();
957 /* Is there a usable request id? */
960 /* Its an error reply */
961 if (res.first & ERROR_MASK)
963 /* Mask off the error bit */
964 res.first -= ERROR_MASK;
965 /* Marshall the error to the correct class */
966 ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
967 if (Classes[res.first])
969 if (ServerInstance && ServerInstance->stats)
970 ServerInstance->stats->statsDnsBad++;
971 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
972 delete Classes[res.first];
973 Classes[res.first] = NULL;
978 /* It is a non-error result */
979 ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
980 /* Marshall the result to the correct class */
981 if (Classes[res.first])
983 if (ServerInstance && ServerInstance->stats)
984 ServerInstance->stats->statsDnsGood++;
985 Classes[res.first]->OnLookupComplete(res.second);
986 delete Classes[res.first];
987 Classes[res.first] = NULL;
991 if (ServerInstance && ServerInstance->stats)
992 ServerInstance->stats->statsDns++;
996 /** Add a derived Resolver to the working set */
997 bool DNS::AddResolverClass(Resolver* r)
999 /* Check the pointers validity and the id's validity */
1000 if ((r) && (r->GetId() > -1))
1002 /* Check the slot isnt already occupied -
1003 * This should NEVER happen unless we have
1004 * a severely broken DNS server somewhere
1006 if (!Classes[r->GetId()])
1008 /* Set up the pointer to the class */
1009 Classes[r->GetId()] = r;
1018 /* Pointer or id not valid.
1019 * Free the item and return
1028 /** Generate pseudo-random number */
1029 unsigned long DNS::PRNG()
1031 unsigned long val = 0;
1033 serverstats* s = ServerInstance->stats;
1034 gettimeofday(&n,NULL);
1035 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1036 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1037 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;