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, requestlist &requests);
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;
111 RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id, requestlist &requests) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id), rl(requests)
113 ServerInstance->Log(DEBUG, "New DNS timeout set on %08x", watching);
116 void Tick(time_t TIME)
118 if (rl.find(watchid) != rl.end())
120 /* Still exists, whack it */
121 if (rl.find(watchid)->second == watch)
123 if (ServerInstance->Res->Classes[watchid])
125 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
126 delete ServerInstance->Res->Classes[watchid];
127 ServerInstance->Res->Classes[watchid] = NULL;
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->Config->dns_timeout ? Instance->Config->dns_timeout : 5, 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 unsigned char* c = (unsigned char*)&ip->s6_addr;
466 if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
467 c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
468 c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
469 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
471 DNS::MakeIP6Int(query, (in6_addr*)ip);
473 unsigned char* c = (unsigned char*)&ip->s_addr;
474 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
477 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
480 DNSRequest* req = this->AddQuery(&h, id);
482 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
488 /** Start lookup of an IP address to a hostname */
489 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
495 #ifdef SUPPORT_IP6LINKS
496 if (fp == PROTOCOL_IPV6)
499 if (inet_pton(AF_INET6, ip, &i) > 0)
501 DNS::MakeIP6Int(query, &i);
504 /* Invalid IP address */
511 if (inet_aton(ip, &i))
513 unsigned char* c = (unsigned char*)&i.s_addr;
514 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
517 /* Invalid IP address */
521 ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
523 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
526 DNSRequest* req = this->AddQuery(&h, id);
528 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
534 /** Build an ipv6 reverse domain from an in6_addr
536 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
538 #ifdef SUPPORT_IP6LINKS
539 const char* hex = "0123456789abcdef";
540 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
544 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
547 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
548 *query++ = '.'; /* Seperator */
550 strcpy(query,"ip6.arpa"); /* Suffix the string */
556 /** Return the next id which is ready, and the result attached to it */
557 DNSResult DNS::GetResult()
559 /* Fetch dns query response and decide where it belongs */
562 unsigned char buffer[sizeof(DNSHeader)];
564 socklen_t x = sizeof(from);
565 const char* ipaddr_from = "";
566 unsigned short int port_from = 0;
568 int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
571 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
573 /* Did we get the whole header? */
576 /* Nope - something screwed up. */
577 ServerInstance->Log(DEBUG,"Whole header not read!");
578 return std::make_pair(-1,"");
581 /* Check wether the reply came from a different DNS
582 * server to the one we sent it to, or the source-port
584 * A user could in theory still spoof dns packets anyway
585 * but this is less trivial than just sending garbage
586 * to the client, which is possible without this check.
588 * -- Thanks jilles for pointing this one out.
591 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
592 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
594 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
595 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
598 /* We cant perform this security check if you're using 4in6.
599 * Tough luck to you, choose one or't other!
603 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
605 ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
606 return std::make_pair(-1,"");
610 /* Put the read header info into a header class */
611 DNS::FillHeader(&header,buffer,length - 12);
613 /* Get the id of this request.
614 * Its a 16 bit value stored in two char's,
615 * so we use logic shifts to create the value.
617 unsigned long this_id = header.id[1] + (header.id[0] << 8);
619 /* Do we have a pending request matching this id? */
620 requestlist_iter n_iter = requests.find(this_id);
621 if (n_iter == requests.end())
623 /* Somehow we got a DNS response for a request we never made... */
624 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
625 return std::make_pair(-1,"");
629 /* Remove the query from the list of pending queries */
630 req = (DNSRequest*)n_iter->second;
631 requests.erase(n_iter);
634 /* Inform the DNSRequest class that it has a result to be read.
635 * When its finished it will return a DNSInfo which is a pair of
636 * unsigned char* resource record data, and an error message.
638 DNSInfo data = req->ResultIsReady(header, length);
639 std::string resultstr;
641 /* Check if we got a result, if we didnt, its an error */
642 if (data.first == NULL)
645 * Mask the ID with the value of ERROR_MASK, so that
646 * the dns_deal_with_classes() function knows that its
647 * an error response and needs to be treated uniquely.
648 * Put the error message in the second field.
651 return std::make_pair(this_id | ERROR_MASK, data.second);
657 /* Forward lookups come back as binary data. We must format them into ascii */
661 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
662 resultstr = formatted;
667 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
668 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
669 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
670 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
671 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
672 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
673 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
674 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
675 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
676 char* c = strstr(formatted,":0:");
679 memmove(c+1,c+2,strlen(c+2) + 1);
681 while (memcmp(c,"0:",2) == 0)
682 memmove(c,c+2,strlen(c+2) + 1);
683 if (memcmp(c,"0",2) == 0)
685 if (memcmp(formatted,"0::",3) == 0)
686 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
688 resultstr = formatted;
690 /* Special case. Sending ::1 around between servers
691 * and to clients is dangerous, because the : on the
692 * start makes the client or server interpret the IP
693 * as the last parameter on the line with a value ":1".
695 if (*formatted == ':')
696 resultstr = "0" + resultstr;
700 case DNS_QUERY_CNAME:
701 /* Identical handling to PTR */
704 /* Reverse lookups just come back as char* */
705 resultstr = std::string((const char*)data.first);
709 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
714 /* Build the reply with the id and hostname/ip in it */
716 return std::make_pair(this_id,resultstr);
720 /** A result is ready, process it */
721 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
729 /* This is just to keep _FORTIFY_SOURCE happy */
730 rr.type = DNS_QUERY_NONE;
733 if (!(header.flags1 & FLAGS_MASK_QR))
734 return std::make_pair((unsigned char*)NULL,"Not a query result");
736 if (header.flags1 & FLAGS_MASK_OPCODE)
737 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
739 if (header.flags2 & FLAGS_MASK_RCODE)
740 return std::make_pair((unsigned char*)NULL,"Domain name not found");
742 if (header.ancount < 1)
743 return std::make_pair((unsigned char*)NULL,"No resource records returned");
745 /* Subtract the length of the header from the length of the packet */
748 while ((unsigned int)q < header.qdcount && i < length)
750 if (header.payload[i] > 63)
757 if (header.payload[i] == 0)
762 else i += header.payload[i] + 1;
766 while ((unsigned)curanswer < header.ancount)
769 while (q == 0 && i < length)
771 if (header.payload[i] > 63)
778 if (header.payload[i] == 0)
783 else i += header.payload[i] + 1; /* skip length and label */
787 return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
789 DNS::FillResourceRecord(&rr,&header.payload[i]);
791 if (rr.type != this->type)
797 if (rr.rr_class != this->rr_class)
805 if ((unsigned int)curanswer == header.ancount)
806 return std::make_pair((unsigned char*)NULL,"No valid answers");
808 if (i + rr.rdlength > (unsigned int)length)
809 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
811 if (rr.rdlength > 1023)
812 return std::make_pair((unsigned char*)NULL,"Resource record too large");
816 case DNS_QUERY_CNAME:
817 /* CNAME and PTR have the same processing code */
821 while (q == 0 && i < length && o + 256 < 1023)
823 if (header.payload[i] > 63)
825 memcpy(&ptr,&header.payload[i],2);
826 i = ntohs(ptr) - 0xC000 - 12;
830 if (header.payload[i] == 0)
839 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
840 o += header.payload[i];
841 i += header.payload[i] + 1;
848 memcpy(res,&header.payload[i],rr.rdlength);
849 res[rr.rdlength] = 0;
852 memcpy(res,&header.payload[i],rr.rdlength);
853 res[rr.rdlength] = 0;
856 memcpy(res,&header.payload[i],rr.rdlength);
857 res[rr.rdlength] = 0;
860 return std::make_pair(res,"No error");;
863 /** Close the master socket */
866 shutdown(this->GetFd(), 2);
867 close(this->GetFd());
870 /** High level abstraction of dns used by application at large */
871 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
873 ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
880 this->myid = ServerInstance->Res->GetIP(source.c_str());
884 if (insp_aton(source.c_str(), &binip) > 0)
886 /* Valid ip address */
887 this->myid = ServerInstance->Res->GetName(&binip);
891 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
892 throw ModuleException("Resolver: Bad IP address");
898 querytype = DNS_QUERY_PTR;
899 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
903 querytype = DNS_QUERY_PTR;
904 this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
908 this->myid = ServerInstance->Res->GetIP6(source.c_str());
911 case DNS_QUERY_CNAME:
912 this->myid = ServerInstance->Res->GetCName(source.c_str());
919 if (this->myid == -1)
921 ServerInstance->Log(DEBUG,"Resolver::Resolver: Could not get an id!");
922 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
923 throw ModuleException("Resolver: Couldnt get an id to make a request");
924 /* We shouldnt get here really */
928 ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
931 /** Called when an error occurs */
932 void Resolver::OnError(ResolverError e, const std::string &errormessage)
934 /* Nothing in here */
937 /** Destroy a resolver */
938 Resolver::~Resolver()
940 /* Nothing here (yet) either */
943 /** Get the request id associated with this class */
944 int Resolver::GetId()
949 Module* Resolver::GetCreator()
951 return this->Creator;
954 /** Process a socket read event */
955 void DNS::HandleEvent(EventType et, int errornum)
957 ServerInstance->Log(DEBUG,"Marshall reads: %d",this->GetFd());
958 /* Fetch the id and result of the next available packet */
959 DNSResult res = this->GetResult();
960 /* Is there a usable request id? */
963 /* Its an error reply */
964 if (res.first & ERROR_MASK)
966 /* Mask off the error bit */
967 res.first -= ERROR_MASK;
968 /* Marshall the error to the correct class */
969 ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
970 if (Classes[res.first])
972 if (ServerInstance && ServerInstance->stats)
973 ServerInstance->stats->statsDnsBad++;
974 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
975 delete Classes[res.first];
976 Classes[res.first] = NULL;
981 /* It is a non-error result */
982 ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
983 /* Marshall the result to the correct class */
984 if (Classes[res.first])
986 if (ServerInstance && ServerInstance->stats)
987 ServerInstance->stats->statsDnsGood++;
988 Classes[res.first]->OnLookupComplete(res.second);
989 delete Classes[res.first];
990 Classes[res.first] = NULL;
994 if (ServerInstance && ServerInstance->stats)
995 ServerInstance->stats->statsDns++;
999 /** Add a derived Resolver to the working set */
1000 bool DNS::AddResolverClass(Resolver* r)
1002 /* Check the pointers validity and the id's validity */
1003 if ((r) && (r->GetId() > -1))
1005 /* Check the slot isnt already occupied -
1006 * This should NEVER happen unless we have
1007 * a severely broken DNS server somewhere
1009 if (!Classes[r->GetId()])
1011 /* Set up the pointer to the class */
1012 Classes[r->GetId()] = r;
1021 /* Pointer or id not valid.
1022 * Free the item and return
1031 void DNS::CleanResolvers(Module* module)
1033 for (int i = 0; i < MAX_REQUEST_ID; i++)
1037 if (Classes[i]->GetCreator() == module)
1039 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1047 /** Generate pseudo-random number */
1048 unsigned long DNS::PRNG()
1050 unsigned long val = 0;
1052 serverstats* s = ServerInstance->stats;
1053 gettimeofday(&n,NULL);
1054 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1055 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1056 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;