]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
66c0d8085ed7e7a0708c680f6073035414e61ee7
[user/henk/code/inspircd.git] / src / dns.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /*
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.
22 */
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <errno.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include "dns.h"
30 #include "inspircd.h"
31 #include "socketengine.h"
32 #include "configreader.h"
33 #include "socket.h"
34
35 using irc::sockets::insp_sockaddr;
36 using irc::sockets::insp_inaddr;
37 using irc::sockets::insp_ntoa;
38 using irc::sockets::insp_aton;
39
40 /** Masks to mask off the responses we get from the DNSRequest methods
41  */
42 enum QueryInfo
43 {
44         ERROR_MASK      = 0x10000       /* Result is an error */
45 };
46
47 /** Flags which can be ORed into a request or reply for different meanings
48  */
49 enum QueryFlags
50 {
51         FLAGS_MASK_RD           = 0x01, /* Recursive */
52         FLAGS_MASK_TC           = 0x02,
53         FLAGS_MASK_AA           = 0x04, /* Authoritative */
54         FLAGS_MASK_OPCODE       = 0x78,
55         FLAGS_MASK_QR           = 0x80,
56         FLAGS_MASK_RCODE        = 0x0F, /* Request */
57         FLAGS_MASK_Z            = 0x70,
58         FLAGS_MASK_RA           = 0x80
59 };
60
61
62 /** Represents a dns resource record (rr)
63  */
64 class ResourceRecord
65 {
66  public:
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 */
71 };
72
73 /** Represents a dns request/reply header, and its payload as opaque data.
74  */
75 class DNSHeader
76 {
77  public:
78         unsigned char   id[2];          /* Request id */
79         unsigned int    flags1;         /* Flags */
80         unsigned int    flags2;         /* Flags */
81         unsigned int    qdcount;
82         unsigned int    ancount;        /* Answer count */
83         unsigned int    nscount;        /* Nameserver count */
84         unsigned int    arcount;
85         unsigned char   payload[512];   /* Packet payload */
86 };
87
88 class DNSRequest
89 {
90  public:
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) */
97
98         DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id);
99         ~DNSRequest();
100         DNSInfo ResultIsReady(DNSHeader &h, int length);
101         int SendRequests(const DNSHeader *header, const int length, QueryType qt);
102 };
103
104 class RequestTimeout : public InspTimer
105 {
106         InspIRCd* ServerInstance;
107         DNSRequest* watch;
108         int watchid;
109  public:
110         RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
111         {
112                 ServerInstance->Log(DEBUG, "New DNS timeout set on %08x", watching);
113         }
114
115         void Tick(time_t TIME)
116         {
117                 if (ServerInstance->Res->requests[watchid] == watch)
118                 {
119                         /* Still exists, whack it */
120                         if (ServerInstance->Res->Classes[watchid])
121                         {
122                                 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
123                                 delete ServerInstance->Res->Classes[watchid];
124                                 ServerInstance->Res->Classes[watchid] = NULL;
125                         }
126                         ServerInstance->Res->requests[watchid] = NULL;
127                         delete watch;
128                         ServerInstance->Log(DEBUG, "DNS timeout on %08x squished pointer", watch);
129                         return;
130                 }
131                 ServerInstance->Log(DEBUG, "DNS timeout on %08x: result already received!", watch);
132         }
133 };
134
135 /* Allocate the processing buffer */
136 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id) : dnsobj(dns)
137 {
138         res = new unsigned char[512];
139         *res = 0;
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 */
143 }
144
145 /* Deallocate the processing buffer */
146 DNSRequest::~DNSRequest()
147 {
148         delete[] res;
149 }
150
151 /** Fill a ResourceRecord class based on raw data input */
152 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
153 {
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];
158 }
159
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)
162 {
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);
172 }
173
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)
176 {
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);
190 }
191
192 /** Send requests we have previously built down the UDP socket */
193 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
194 {
195         insp_sockaddr addr;
196         unsigned char payload[sizeof(DNSHeader)];
197
198         this->rr_class = 1;
199         this->type = qt;
200                 
201         DNS::EmptyHeader(payload,header,length);
202
203         memset(&addr,0,sizeof(addr));
204 #ifdef IPV6
205         memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
206         addr.sin6_family = AF_FAMILY;
207         addr.sin6_port = htons(DNS::QUERY_PORT);
208 #else
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);
212 #endif
213         if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
214                 return -1;
215
216         return 0;
217 }
218
219 /** Add a query with a predefined header, and allocate an ID for it. */
220 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
221 {
222         /* Is the DNS connection down? */
223         if (this->GetFd() == -1)
224                 return NULL;
225         
226         /* Create an id */
227         id = this->PRNG() & DNS::MAX_REQUEST_ID;
228
229         /* If this id is already 'in flight', pick another. */
230         while (requests[id])
231                 id = this->PRNG() & DNS::MAX_REQUEST_ID;
232
233         DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id);
234
235         header->id[0] = req->id[0] = id >> 8;
236         header->id[1] = req->id[1] = id & 0xFF;
237         header->flags1 = FLAGS_MASK_RD;
238         header->flags2 = 0;
239         header->qdcount = 1;
240         header->ancount = 0;
241         header->nscount = 0;
242         header->arcount = 0;
243
244         /* At this point we already know the id doesnt exist,
245          * so there needs to be no second check for the ::end()
246          */
247         requests[id] = req;
248
249         /* According to the C++ spec, new never returns NULL. */
250         return req;
251 }
252
253 void DNS::Rehash()
254 {
255         insp_inaddr addr;
256         ip6munge = false;
257
258         if (this->GetFd() > -1)
259         {
260                 shutdown(this->GetFd(), 2);
261                 close(this->GetFd());
262                 this->SetFd(-1);
263         }
264
265         if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
266         {
267                 memcpy(&myserver,&addr,sizeof(insp_inaddr));
268                 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) ||  (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
269                 {
270                         ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
271                         ServerInstance->Log(DEFAULT,"         This should not cause a problem, however it is recommended you migrate");
272                         ServerInstance->Log(DEFAULT,"         to a true IPv6 environment.");
273                         this->ip6munge = true;
274                 }
275                 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
276         }
277         else
278         {
279                 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
280         }
281
282         /* Initialize mastersocket */
283         this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
284         if (this->GetFd() != -1)
285         {
286                 /* Did it succeed? */
287                 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
288                 {
289                         /* Couldn't make the socket nonblocking */
290                         shutdown(this->GetFd(),2);
291                         close(this->GetFd());
292                         this->SetFd(-1);
293                 }
294         }
295         else
296         {
297                 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
298         }
299
300         /* Have we got a socket and is it nonblocking? */
301         if (this->GetFd() != -1)
302         {
303 #ifdef IPV6
304                 insp_sockaddr addr;
305                 memset(&addr,0,sizeof(addr));
306                 addr.sin6_family = AF_FAMILY;
307                 addr.sin6_port = 0;
308                 addr.sin6_addr = in6addr_any;
309 #else
310                 insp_sockaddr addr;
311                 memset(&addr,0,sizeof(addr));
312                 addr.sin_family = AF_FAMILY;
313                 addr.sin_port = 0;
314                 addr.sin_addr.s_addr = INADDR_ANY;
315 #endif
316                 /* Bind the port */
317                 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
318                 {
319                         /* Failed to bind */
320                         ServerInstance->Log(DEBUG,"Cant bind DNS fd");
321                         shutdown(this->GetFd(),2);
322                         close(this->GetFd());
323                         this->SetFd(-1);
324                 }
325
326                 if (this->GetFd() >= 0)
327                 {
328                         ServerInstance->Log(DEBUG,"Add master socket %d",this->GetFd());
329                         /* Hook the descriptor into the socket engine */
330                         if (ServerInstance && ServerInstance->SE)
331                         {
332                                 if (!ServerInstance->SE->AddFd(this))
333                                 {
334                                         ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
335                                         shutdown(this->GetFd(),2);
336                                         close(this->GetFd());
337                                         this->SetFd(-1);
338                                 }
339                         }
340                 }
341         }
342 }
343
344 /** Initialise the DNS UDP socket so that we can send requests */
345 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
346 {
347         ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
348
349         /* Clear the Resolver class table */
350         memset(Classes,0,sizeof(Classes));
351
352         /* Clear the requests class table */
353         memset(requests,0,sizeof(requests));
354
355         /* Set the id of the next request to 0
356          */
357         currid = 0;
358         
359         this->SetFd(-1);
360
361         this->Rehash();
362 }
363
364 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
365 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
366 {
367         short payloadpos = 0;
368         const char* tempchr, *tempchr2 = name;
369         unsigned short length;
370
371         /* split name up into labels, create query */
372         while ((tempchr = strchr(tempchr2,'.')) != NULL)
373         {
374                 length = tempchr - tempchr2;
375                 if (payloadpos + length + 1 > 507)
376                         return -1;
377                 payload[payloadpos++] = length;
378                 memcpy(&payload[payloadpos],tempchr2,length);
379                 payloadpos += length;
380                 tempchr2 = &tempchr[1];
381         }
382         length = strlen(tempchr2);
383         if (length)
384         {
385                 if (payloadpos + length + 2 > 507)
386                         return -1;
387                 payload[payloadpos++] = length;
388                 memcpy(&payload[payloadpos],tempchr2,length);
389                 payloadpos += length;
390                 payload[payloadpos++] = 0;
391         }
392         if (payloadpos > 508)
393                 return -1;
394         length = htons(rr);
395         memcpy(&payload[payloadpos],&length,2);
396         length = htons(rr_class);
397         memcpy(&payload[payloadpos + 2],&length,2);
398         return payloadpos + 4;
399 }
400
401 /** Start lookup of an hostname to an IP address */
402 int DNS::GetIP(const char *name)
403 {
404         DNSHeader h;
405         int id;
406         int length;
407         
408         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
409                 return -1;
410
411         DNSRequest* req = this->AddQuery(&h, id);
412
413         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
414                 return -1;
415
416         return id;
417 }
418
419 /** Start lookup of an hostname to an IPv6 address */
420 int DNS::GetIP6(const char *name)
421 {
422         DNSHeader h;
423         int id;
424         int length;
425
426         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
427                 return -1;
428
429         DNSRequest* req = this->AddQuery(&h, id);
430
431         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
432                 return -1;
433
434         return id;
435 }
436
437 /** Start lookup of a cname to another name */
438 int DNS::GetCName(const char *alias)
439 {
440         DNSHeader h;
441         int id;
442         int length;
443
444         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
445                 return -1;
446
447         DNSRequest* req = this->AddQuery(&h, id);
448
449         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
450                 return -1;
451
452         return id;
453 }
454
455 /** Start lookup of an IP address to a hostname */
456 int DNS::GetName(const insp_inaddr *ip)
457 {
458         char query[128];
459         DNSHeader h;
460         int id;
461         int length;
462
463 #ifdef IPV6
464         unsigned char* c = (unsigned char*)&ip->s6_addr;
465         if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
466             c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
467             c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
468                 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
469         else
470                 DNS::MakeIP6Int(query, (in6_addr*)ip);
471 #else
472         unsigned char* c = (unsigned char*)&ip->s_addr;
473         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
474 #endif
475
476         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
477                 return -1;
478
479         DNSRequest* req = this->AddQuery(&h, id);
480
481         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
482                 return -1;
483
484         return id;
485 }
486
487 /** Start lookup of an IP address to a hostname */
488 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
489 {
490         char query[128];
491         DNSHeader h;
492         int id;
493         int length;
494 #ifdef SUPPORT_IP6LINKS
495         if (fp == PROTOCOL_IPV6)
496         {
497                 in6_addr i;
498                 if (inet_pton(AF_INET6, ip, &i) > 0)
499                 {
500                         DNS::MakeIP6Int(query, &i);
501                 }
502                 else
503                         /* Invalid IP address */
504                         return -1;
505         }
506         else
507 #endif
508         {
509                 in_addr i;
510                 if (inet_aton(ip, &i))
511                 {
512                         unsigned char* c = (unsigned char*)&i.s_addr;
513                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
514                 }
515                 else
516                         /* Invalid IP address */
517                         return -1;
518         }
519
520         ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
521
522         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
523                 return -1;
524
525         DNSRequest* req = this->AddQuery(&h, id);
526
527         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
528                 return -1;
529
530         return id;
531 }
532
533 /** Build an ipv6 reverse domain from an in6_addr
534  */
535 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
536 {
537 #ifdef SUPPORT_IP6LINKS
538         const char* hex = "0123456789abcdef";
539         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
540         {
541                 if (index % 2)
542                         /* low nibble */
543                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
544                 else
545                         /* high nibble */
546                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
547                 *query++ = '.'; /* Seperator */
548         }
549         strcpy(query,"ip6.arpa"); /* Suffix the string */
550 #else
551         *query = 0;
552 #endif
553 }
554
555 /** Return the next id which is ready, and the result attached to it */
556 DNSResult DNS::GetResult()
557 {
558         /* Fetch dns query response and decide where it belongs */
559         DNSHeader header;
560         DNSRequest *req;
561         unsigned char buffer[sizeof(DNSHeader)];
562         sockaddr from;
563         socklen_t x = sizeof(from);
564         const char* ipaddr_from = "";
565         unsigned short int port_from = 0;
566
567         int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
568
569         if (length < 0)
570                 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
571
572         /* Did we get the whole header? */
573         if (length < 12)
574         {
575                 /* Nope - something screwed up. */
576                 ServerInstance->Log(DEBUG,"Whole header not read!");
577                 return std::make_pair(-1,"");
578         }
579
580         /* Check wether the reply came from a different DNS
581          * server to the one we sent it to, or the source-port
582          * is not 53.
583          * A user could in theory still spoof dns packets anyway
584          * but this is less trivial than just sending garbage
585          * to the client, which is possible without this check.
586          *
587          * -- Thanks jilles for pointing this one out.
588          */
589 #ifdef IPV6
590         ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
591         port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
592 #else
593         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
594         port_from = ntohs(((sockaddr_in*)&from)->sin_port);
595 #endif
596
597         /* We cant perform this security check if you're using 4in6.
598          * Tough luck to you, choose one or't other!
599          */
600         if (!ip6munge)
601         {
602                 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
603                 {
604                         ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
605                         return std::make_pair(-1,"");
606                 }
607         }
608
609         /* Put the read header info into a header class */
610         DNS::FillHeader(&header,buffer,length - 12);
611
612         /* Get the id of this request.
613          * Its a 16 bit value stored in two char's,
614          * so we use logic shifts to create the value.
615          */
616         unsigned long this_id = header.id[1] + (header.id[0] << 8);
617
618         /* Do we have a pending request matching this id? */
619         if (!requests[this_id])
620         {
621                 /* Somehow we got a DNS response for a request we never made... */
622                 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
623                 return std::make_pair(-1,"");
624         }
625         else
626         {
627                 /* Remove the query from the list of pending queries */
628                 req = requests[this_id];
629                 requests[this_id] = NULL;
630         }
631
632         /* Inform the DNSRequest class that it has a result to be read.
633          * When its finished it will return a DNSInfo which is a pair of
634          * unsigned char* resource record data, and an error message.
635          */
636         DNSInfo data = req->ResultIsReady(header, length);
637         std::string resultstr;
638
639         /* Check if we got a result, if we didnt, its an error */
640         if (data.first == NULL)
641         {
642                 /* An error.
643                  * Mask the ID with the value of ERROR_MASK, so that
644                  * the dns_deal_with_classes() function knows that its
645                  * an error response and needs to be treated uniquely.
646                  * Put the error message in the second field.
647                  */
648                 delete req;
649                 return std::make_pair(this_id | ERROR_MASK, data.second);
650         }
651         else
652         {
653                 char formatted[128];
654
655                 /* Forward lookups come back as binary data. We must format them into ascii */
656                 switch (req->type)
657                 {
658                         case DNS_QUERY_A:
659                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
660                                 resultstr = formatted;
661                         break;
662
663                         case DNS_QUERY_AAAA:
664                         {
665                                 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
666                                                 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
667                                                 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
668                                                 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
669                                                 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
670                                                 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
671                                                 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
672                                                 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
673                                                 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
674                                 char* c = strstr(formatted,":0:");
675                                 if (c != NULL)
676                                 {
677                                         memmove(c+1,c+2,strlen(c+2) + 1);
678                                         c += 2;
679                                         while (memcmp(c,"0:",2) == 0)
680                                                 memmove(c,c+2,strlen(c+2) + 1);
681                                         if (memcmp(c,"0",2) == 0)
682                                                 *c = 0;
683                                         if (memcmp(formatted,"0::",3) == 0)
684                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
685                                 }
686                                 resultstr = formatted;
687
688                                 /* Special case. Sending ::1 around between servers
689                                  * and to clients is dangerous, because the : on the
690                                  * start makes the client or server interpret the IP
691                                  * as the last parameter on the line with a value ":1".
692                                  */
693                                 if (*formatted == ':')
694                                         resultstr = "0" + resultstr;
695                         }
696                         break;
697
698                         case DNS_QUERY_CNAME:
699                                 /* Identical handling to PTR */
700
701                         case DNS_QUERY_PTR:
702                                 /* Reverse lookups just come back as char* */
703                                 resultstr = std::string((const char*)data.first);
704                         break;
705
706                         default:
707                                 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
708                         break;
709                         
710                 }
711
712                 /* Build the reply with the id and hostname/ip in it */
713                 delete req;
714                 return std::make_pair(this_id,resultstr);
715         }
716 }
717
718 /** A result is ready, process it */
719 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
720 {
721         int i = 0;
722         int q = 0;
723         int curanswer, o;
724         ResourceRecord rr;
725         unsigned short ptr;
726
727         /* This is just to keep _FORTIFY_SOURCE happy */
728         rr.type = DNS_QUERY_NONE;
729         rr.rdlength = 0;
730
731         if (!(header.flags1 & FLAGS_MASK_QR))
732                 return std::make_pair((unsigned char*)NULL,"Not a query result");
733
734         if (header.flags1 & FLAGS_MASK_OPCODE)
735                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
736
737         if (header.flags2 & FLAGS_MASK_RCODE)
738                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
739
740         if (header.ancount < 1)
741                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
742
743         /* Subtract the length of the header from the length of the packet */
744         length -= 12;
745
746         while ((unsigned int)q < header.qdcount && i < length)
747         {
748                 if (header.payload[i] > 63)
749                 {
750                         i += 6;
751                         q++;
752                 }
753                 else
754                 {
755                         if (header.payload[i] == 0)
756                         {
757                                 q++;
758                                 i += 5;
759                         }
760                         else i += header.payload[i] + 1;
761                 }
762         }
763         curanswer = 0;
764         while ((unsigned)curanswer < header.ancount)
765         {
766                 q = 0;
767                 while (q == 0 && i < length)
768                 {
769                         if (header.payload[i] > 63)
770                         {
771                                 i += 2;
772                                 q = 1;
773                         }
774                         else
775                         {
776                                 if (header.payload[i] == 0)
777                                 {
778                                         i++;
779                                         q = 1;
780                                 }
781                                 else i += header.payload[i] + 1; /* skip length and label */
782                         }
783                 }
784                 if (length - i < 10)
785                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
786
787                 DNS::FillResourceRecord(&rr,&header.payload[i]);
788                 i += 10;
789                 if (rr.type != this->type)
790                 {
791                         curanswer++;
792                         i += rr.rdlength;
793                         continue;
794                 }
795                 if (rr.rr_class != this->rr_class)
796                 {
797                         curanswer++;
798                         i += rr.rdlength;
799                         continue;
800                 }
801                 break;
802         }
803         if ((unsigned int)curanswer == header.ancount)
804                 return std::make_pair((unsigned char*)NULL,"No valid answers");
805
806         if (i + rr.rdlength > (unsigned int)length)
807                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
808
809         if (rr.rdlength > 1023)
810                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
811
812         switch (rr.type)
813         {
814                 case DNS_QUERY_CNAME:
815                         /* CNAME and PTR have the same processing code */
816                 case DNS_QUERY_PTR:
817                         o = 0;
818                         q = 0;
819                         while (q == 0 && i < length && o + 256 < 1023)
820                         {
821                                 if (header.payload[i] > 63)
822                                 {
823                                         memcpy(&ptr,&header.payload[i],2);
824                                         i = ntohs(ptr) - 0xC000 - 12;
825                                 }
826                                 else
827                                 {
828                                         if (header.payload[i] == 0)
829                                         {
830                                                 q = 1;
831                                         }
832                                         else
833                                         {
834                                                 res[o] = 0;
835                                                 if (o != 0)
836                                                         res[o++] = '.';
837                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
838                                                 o += header.payload[i];
839                                                 i += header.payload[i] + 1;
840                                         }
841                                 }
842                         }
843                         res[o] = 0;
844                 break;
845                 case DNS_QUERY_AAAA:
846                         memcpy(res,&header.payload[i],rr.rdlength);
847                         res[rr.rdlength] = 0;
848                 break;
849                 case DNS_QUERY_A:
850                         memcpy(res,&header.payload[i],rr.rdlength);
851                         res[rr.rdlength] = 0;
852                 break;
853                 default:
854                         memcpy(res,&header.payload[i],rr.rdlength);
855                         res[rr.rdlength] = 0;
856                 break;
857         }
858         return std::make_pair(res,"No error");;
859 }
860
861 /** Close the master socket */
862 DNS::~DNS()
863 {
864         shutdown(this->GetFd(), 2);
865         close(this->GetFd());
866 }
867
868 /** High level abstraction of dns used by application at large */
869 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
870 {
871         ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
872
873         insp_inaddr binip;
874
875         switch (querytype)
876         {
877                 case DNS_QUERY_A:
878                         this->myid = ServerInstance->Res->GetIP(source.c_str());
879                 break;
880
881                 case DNS_QUERY_PTR:
882                         if (insp_aton(source.c_str(), &binip) > 0)
883                         {
884                                 /* Valid ip address */
885                                 this->myid = ServerInstance->Res->GetName(&binip);
886                         }
887                         else
888                         {
889                                 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
890                                 throw ModuleException("Resolver: Bad IP address");
891                                 return;
892                         }
893                 break;
894
895                 case DNS_QUERY_PTR4:
896                         querytype = DNS_QUERY_PTR;
897                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
898                 break;
899
900                 case DNS_QUERY_PTR6:
901                         querytype = DNS_QUERY_PTR;
902                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
903                 break;
904
905                 case DNS_QUERY_AAAA:
906                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
907                 break;
908
909                 case DNS_QUERY_CNAME:
910                         this->myid = ServerInstance->Res->GetCName(source.c_str());
911                 break;
912
913                 default:
914                         this->myid = -1;
915                 break;
916         }
917         if (this->myid == -1)
918         {
919                 ServerInstance->Log(DEBUG,"Resolver::Resolver: Could not get an id!");
920                 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
921                 throw ModuleException("Resolver: Couldnt get an id to make a request");
922                 /* We shouldnt get here really */
923                 return;
924         }
925
926         ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
927 }
928
929 /** Called when an error occurs */
930 void Resolver::OnError(ResolverError e, const std::string &errormessage)
931 {
932         /* Nothing in here */
933 }
934
935 /** Destroy a resolver */
936 Resolver::~Resolver()
937 {
938         /* Nothing here (yet) either */
939 }
940
941 /** Get the request id associated with this class */
942 int Resolver::GetId()
943 {
944         return this->myid;
945 }
946
947 Module* Resolver::GetCreator()
948 {
949         return this->Creator;
950 }
951
952 /** Process a socket read event */
953 void DNS::HandleEvent(EventType et, int errornum)
954 {
955         /* Fetch the id and result of the next available packet */
956         DNSResult res = this->GetResult();
957         /* Is there a usable request id? */
958         if (res.first != -1)
959         {
960                 /* Its an error reply */
961                 if (res.first & ERROR_MASK)
962                 {
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])
968                         {
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;
974                         }
975                 }
976                 else
977                 {
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])
982                         {
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;
988                         }
989                 }
990
991                 if (ServerInstance && ServerInstance->stats)
992                         ServerInstance->stats->statsDns++;
993         }
994 }
995
996 /** Add a derived Resolver to the working set */
997 bool DNS::AddResolverClass(Resolver* r)
998 {
999         /* Check the pointers validity and the id's validity */
1000         if ((r) && (r->GetId() > -1))
1001         {
1002                 /* Check the slot isnt already occupied -
1003                  * This should NEVER happen unless we have
1004                  * a severely broken DNS server somewhere
1005                  */
1006                 if (!Classes[r->GetId()])
1007                 {
1008                         /* Set up the pointer to the class */
1009                         Classes[r->GetId()] = r;
1010                         return true;
1011                 }
1012                 else
1013                         /* Duplicate id */
1014                         return false;
1015         }
1016         else
1017         {
1018                 /* Pointer or id not valid.
1019                  * Free the item and return
1020                  */
1021                 if (r)
1022                         delete r;
1023
1024                 return false;
1025         }
1026 }
1027
1028 void DNS::CleanResolvers(Module* module)
1029 {
1030         for (int i = 0; i < MAX_REQUEST_ID; i++)
1031         {
1032                 if (Classes[i])
1033                 {
1034                         if (Classes[i]->GetCreator() == module)
1035                         {
1036                                 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1037                                 delete Classes[i];
1038                                 Classes[i] = NULL;
1039                         }
1040                 }
1041         }
1042 }
1043
1044 /** Generate pseudo-random number */
1045 unsigned long DNS::PRNG()
1046 {
1047         unsigned long val = 0;
1048         timeval n;
1049         serverstats* s = ServerInstance->stats;
1050         gettimeofday(&n,NULL);
1051         val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1052         val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1053         val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;
1054         return val;
1055 }
1056