1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2007 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
15 dns.cpp - Nonblocking DNS functions.
16 Very very loosely based on the firedns library,
17 Copyright (C) 2002 Ian Gulliver. This file is no
18 longer anything like firedns, there are many major
19 differences between this code and the original.
20 Please do not assume that firedns works like this,
21 looks like this, walks like this or tastes like this.
24 #include <sys/types.h>
25 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
31 #include "socketengine.h"
32 #include "configreader.h"
35 using irc::sockets::insp_sockaddr;
36 using irc::sockets::insp_inaddr;
37 using irc::sockets::insp_ntoa;
38 using irc::sockets::insp_aton;
40 /** Masks to mask off the responses we get from the DNSRequest methods
44 ERROR_MASK = 0x10000 /* Result is an error */
47 /** Flags which can be ORed into a request or reply for different meanings
51 FLAGS_MASK_RD = 0x01, /* Recursive */
53 FLAGS_MASK_AA = 0x04, /* Authoritative */
54 FLAGS_MASK_OPCODE = 0x78,
56 FLAGS_MASK_RCODE = 0x0F, /* Request */
62 /** Represents a dns resource record (rr)
67 QueryType type; /* Record type */
68 unsigned int rr_class; /* Record class */
69 unsigned long ttl; /* Time to live */
70 unsigned int rdlength; /* Record length */
73 /** Represents a dns request/reply header, and its payload as opaque data.
78 unsigned char id[2]; /* Request id */
79 unsigned int flags1; /* Flags */
80 unsigned int flags2; /* Flags */
82 unsigned int ancount; /* Answer count */
83 unsigned int nscount; /* Nameserver count */
85 unsigned char payload[512]; /* Packet payload */
91 unsigned char id[2]; /* Request id */
92 unsigned char* res; /* Result processing buffer */
93 unsigned int rr_class; /* Request class */
94 QueryType type; /* Request type */
95 insp_inaddr myserver; /* DNS server address*/
96 DNS* dnsobj; /* DNS caller (where we get our FD from) */
98 DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id);
100 DNSInfo ResultIsReady(DNSHeader &h, int length);
101 int SendRequests(const DNSHeader *header, const int length, QueryType qt);
104 class RequestTimeout : public InspTimer
106 InspIRCd* ServerInstance;
110 RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
112 ServerInstance->Log(DEBUG, "New DNS timeout set on %08x", watching);
115 void Tick(time_t TIME)
117 if (ServerInstance->Res->requests[watchid] == watch)
119 /* Still exists, whack it */
120 if (ServerInstance->Res->Classes[watchid])
122 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
123 delete ServerInstance->Res->Classes[watchid];
124 ServerInstance->Res->Classes[watchid] = NULL;
126 ServerInstance->Res->requests[watchid] = NULL;
128 ServerInstance->Log(DEBUG, "DNS timeout on %08x squished pointer", watch);
131 ServerInstance->Log(DEBUG, "DNS timeout on %08x: result already received!", watch);
135 /* Allocate the processing buffer */
136 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id) : dnsobj(dns)
138 res = new unsigned char[512];
140 memcpy(&myserver, &server, sizeof(insp_inaddr));
141 RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);
142 Instance->Timers->AddTimer(RT); /* The timer manager frees this */
145 /* Deallocate the processing buffer */
146 DNSRequest::~DNSRequest()
151 /** Fill a ResourceRecord class based on raw data input */
152 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
154 rr->type = (QueryType)((input[0] << 8) + input[1]);
155 rr->rr_class = (input[2] << 8) + input[3];
156 rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
157 rr->rdlength = (input[8] << 8) + input[9];
160 /** Fill a DNSHeader class based on raw data input of a given length */
161 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
163 header->id[0] = input[0];
164 header->id[1] = input[1];
165 header->flags1 = input[2];
166 header->flags2 = input[3];
167 header->qdcount = (input[4] << 8) + input[5];
168 header->ancount = (input[6] << 8) + input[7];
169 header->nscount = (input[8] << 8) + input[9];
170 header->arcount = (input[10] << 8) + input[11];
171 memcpy(header->payload,&input[12],length);
174 /** Empty a DNSHeader class out into raw data, ready for transmission */
175 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
177 output[0] = header->id[0];
178 output[1] = header->id[1];
179 output[2] = header->flags1;
180 output[3] = header->flags2;
181 output[4] = header->qdcount >> 8;
182 output[5] = header->qdcount & 0xFF;
183 output[6] = header->ancount >> 8;
184 output[7] = header->ancount & 0xFF;
185 output[8] = header->nscount >> 8;
186 output[9] = header->nscount & 0xFF;
187 output[10] = header->arcount >> 8;
188 output[11] = header->arcount & 0xFF;
189 memcpy(&output[12],header->payload,length);
192 /** Send requests we have previously built down the UDP socket */
193 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
196 unsigned char payload[sizeof(DNSHeader)];
201 DNS::EmptyHeader(payload,header,length);
203 memset(&addr,0,sizeof(addr));
205 memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
206 addr.sin6_family = AF_FAMILY;
207 addr.sin6_port = htons(DNS::QUERY_PORT);
209 memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
210 addr.sin_family = AF_FAMILY;
211 addr.sin_port = htons(DNS::QUERY_PORT);
213 if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
219 /** Add a query with a predefined header, and allocate an ID for it. */
220 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
222 /* Is the DNS connection down? */
223 if (this->GetFd() == -1)
227 id = this->PRNG() & DNS::MAX_REQUEST_ID;
229 /* If this id is already 'in flight', pick another. */
231 id = this->PRNG() & DNS::MAX_REQUEST_ID;
233 DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id);
235 header->id[0] = req->id[0] = id >> 8;
236 header->id[1] = req->id[1] = id & 0xFF;
237 header->flags1 = FLAGS_MASK_RD;
244 /* At this point we already know the id doesnt exist,
245 * so there needs to be no second check for the ::end()
249 /* According to the C++ spec, new never returns NULL. */
258 if (this->GetFd() > -1)
260 if (ServerInstance && ServerInstance->SE)
261 ServerInstance->SE->DelFd(this);
262 shutdown(this->GetFd(), 2);
263 close(this->GetFd());
267 if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
269 memcpy(&myserver,&addr,sizeof(insp_inaddr));
270 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) || (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
272 ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
273 ServerInstance->Log(DEFAULT," This should not cause a problem, however it is recommended you migrate");
274 ServerInstance->Log(DEFAULT," to a true IPv6 environment.");
275 this->ip6munge = true;
277 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
281 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
284 /* Initialize mastersocket */
285 this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
286 if (this->GetFd() != -1)
288 /* Did it succeed? */
289 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
291 /* Couldn't make the socket nonblocking */
292 shutdown(this->GetFd(),2);
293 close(this->GetFd());
299 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
302 /* Have we got a socket and is it nonblocking? */
303 if (this->GetFd() != -1)
307 memset(&addr,0,sizeof(addr));
308 addr.sin6_family = AF_FAMILY;
310 addr.sin6_addr = in6addr_any;
313 memset(&addr,0,sizeof(addr));
314 addr.sin_family = AF_FAMILY;
316 addr.sin_addr.s_addr = INADDR_ANY;
319 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
322 ServerInstance->Log(DEBUG,"Cant bind DNS fd");
323 shutdown(this->GetFd(),2);
324 close(this->GetFd());
328 if (this->GetFd() >= 0)
330 ServerInstance->Log(DEBUG,"Add master socket %d",this->GetFd());
331 /* Hook the descriptor into the socket engine */
332 if (ServerInstance && ServerInstance->SE)
334 if (!ServerInstance->SE->AddFd(this))
336 ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
337 shutdown(this->GetFd(),2);
338 close(this->GetFd());
346 /** Initialise the DNS UDP socket so that we can send requests */
347 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
349 ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
351 /* Clear the Resolver class table */
352 memset(Classes,0,sizeof(Classes));
354 /* Clear the requests class table */
355 memset(requests,0,sizeof(requests));
357 /* Set the id of the next request to 0
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 unsigned char* c = (unsigned char*)&ip->s6_addr;
467 if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
468 c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
469 c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
470 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
472 DNS::MakeIP6Int(query, (in6_addr*)ip);
474 unsigned char* c = (unsigned char*)&ip->s_addr;
475 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
478 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
481 DNSRequest* req = this->AddQuery(&h, id);
483 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
489 /** Start lookup of an IP address to a hostname */
490 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
496 #ifdef SUPPORT_IP6LINKS
497 if (fp == PROTOCOL_IPV6)
500 if (inet_pton(AF_INET6, ip, &i) > 0)
502 DNS::MakeIP6Int(query, &i);
505 /* Invalid IP address */
512 if (inet_aton(ip, &i))
514 unsigned char* c = (unsigned char*)&i.s_addr;
515 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
518 /* Invalid IP address */
522 ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
524 if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
527 DNSRequest* req = this->AddQuery(&h, id);
529 if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
535 /** Build an ipv6 reverse domain from an in6_addr
537 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
539 #ifdef SUPPORT_IP6LINKS
540 const char* hex = "0123456789abcdef";
541 for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
545 *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
548 *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
549 *query++ = '.'; /* Seperator */
551 strcpy(query,"ip6.arpa"); /* Suffix the string */
557 /** Return the next id which is ready, and the result attached to it */
558 DNSResult DNS::GetResult()
560 /* Fetch dns query response and decide where it belongs */
563 unsigned char buffer[sizeof(DNSHeader)];
565 socklen_t x = sizeof(from);
566 const char* ipaddr_from = "";
567 unsigned short int port_from = 0;
569 int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
572 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
574 /* Did we get the whole header? */
577 /* Nope - something screwed up. */
578 ServerInstance->Log(DEBUG,"Whole header not read!");
579 return std::make_pair(-1,"");
582 /* Check wether the reply came from a different DNS
583 * server to the one we sent it to, or the source-port
585 * A user could in theory still spoof dns packets anyway
586 * but this is less trivial than just sending garbage
587 * to the client, which is possible without this check.
589 * -- Thanks jilles for pointing this one out.
592 ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
593 port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
595 ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
596 port_from = ntohs(((sockaddr_in*)&from)->sin_port);
599 /* We cant perform this security check if you're using 4in6.
600 * Tough luck to you, choose one or't other!
604 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
606 ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
607 return std::make_pair(-1,"");
611 /* Put the read header info into a header class */
612 DNS::FillHeader(&header,buffer,length - 12);
614 /* Get the id of this request.
615 * Its a 16 bit value stored in two char's,
616 * so we use logic shifts to create the value.
618 unsigned long this_id = header.id[1] + (header.id[0] << 8);
620 /* Do we have a pending request matching this id? */
621 if (!requests[this_id])
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 = requests[this_id];
631 requests[this_id] = NULL;
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 /* Fetch the id and result of the next available packet */
958 DNSResult res = this->GetResult();
959 /* Is there a usable request id? */
962 /* Its an error reply */
963 if (res.first & ERROR_MASK)
965 /* Mask off the error bit */
966 res.first -= ERROR_MASK;
967 /* Marshall the error to the correct class */
968 ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
969 if (Classes[res.first])
971 if (ServerInstance && ServerInstance->stats)
972 ServerInstance->stats->statsDnsBad++;
973 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
974 delete Classes[res.first];
975 Classes[res.first] = NULL;
980 /* It is a non-error result */
981 ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
982 /* Marshall the result to the correct class */
983 if (Classes[res.first])
985 if (ServerInstance && ServerInstance->stats)
986 ServerInstance->stats->statsDnsGood++;
987 Classes[res.first]->OnLookupComplete(res.second);
988 delete Classes[res.first];
989 Classes[res.first] = NULL;
993 if (ServerInstance && ServerInstance->stats)
994 ServerInstance->stats->statsDns++;
998 /** Add a derived Resolver to the working set */
999 bool DNS::AddResolverClass(Resolver* r)
1001 /* Check the pointers validity and the id's validity */
1002 if ((r) && (r->GetId() > -1))
1004 /* Check the slot isnt already occupied -
1005 * This should NEVER happen unless we have
1006 * a severely broken DNS server somewhere
1008 if (!Classes[r->GetId()])
1010 /* Set up the pointer to the class */
1011 Classes[r->GetId()] = r;
1020 /* Pointer or id not valid.
1021 * Free the item and return
1030 void DNS::CleanResolvers(Module* module)
1032 for (int i = 0; i < MAX_REQUEST_ID; i++)
1036 if (Classes[i]->GetCreator() == module)
1038 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1046 /** Generate pseudo-random number */
1047 unsigned long DNS::PRNG()
1049 unsigned long val = 0;
1051 serverstats* s = ServerInstance->stats;
1052 gettimeofday(&n,NULL);
1053 val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1054 val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1055 val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;