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