]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
Get rid of HelpopException, use ModuleException thats had reasons for ages now
[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, requestlist &requests);
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         requestlist &rl;
110  public:
111         RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id, requestlist &requests) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id), rl(requests)
112         {
113                 ServerInstance->Log(DEBUG, "New DNS timeout set on %08x", watching);
114         }
115
116         void Tick(time_t TIME)
117         {
118                 if (rl.find(watchid) != rl.end())
119                 {
120                         /* Still exists, whack it */
121                         if (rl.find(watchid)->second == watch)
122                         {
123                                 if (ServerInstance->Res->Classes[watchid])
124                                 {
125                                         ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
126                                         delete ServerInstance->Res->Classes[watchid];
127                                         ServerInstance->Res->Classes[watchid] = NULL;
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->Config->dns_timeout ? Instance->Config->dns_timeout : 5, 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         unsigned char* c = (unsigned char*)&ip->s6_addr;
466         if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
467             c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
468             c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
469                 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
470         else
471                 DNS::MakeIP6Int(query, (in6_addr*)ip);
472 #else
473         unsigned char* c = (unsigned char*)&ip->s_addr;
474         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
475 #endif
476
477         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
478                 return -1;
479
480         DNSRequest* req = this->AddQuery(&h, id);
481
482         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
483                 return -1;
484
485         return id;
486 }
487
488 /** Start lookup of an IP address to a hostname */
489 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
490 {
491         char query[128];
492         DNSHeader h;
493         int id;
494         int length;
495 #ifdef SUPPORT_IP6LINKS
496         if (fp == PROTOCOL_IPV6)
497         {
498                 in6_addr i;
499                 if (inet_pton(AF_INET6, ip, &i) > 0)
500                 {
501                         DNS::MakeIP6Int(query, &i);
502                 }
503                 else
504                         /* Invalid IP address */
505                         return -1;
506         }
507         else
508 #endif
509         {
510                 in_addr i;
511                 if (inet_aton(ip, &i))
512                 {
513                         unsigned char* c = (unsigned char*)&i.s_addr;
514                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
515                 }
516                 else
517                         /* Invalid IP address */
518                         return -1;
519         }
520
521         ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
522
523         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
524                 return -1;
525
526         DNSRequest* req = this->AddQuery(&h, id);
527
528         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
529                 return -1;
530
531         return id;
532 }
533
534 /** Build an ipv6 reverse domain from an in6_addr
535  */
536 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
537 {
538 #ifdef SUPPORT_IP6LINKS
539         const char* hex = "0123456789abcdef";
540         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
541         {
542                 if (index % 2)
543                         /* low nibble */
544                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
545                 else
546                         /* high nibble */
547                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
548                 *query++ = '.'; /* Seperator */
549         }
550         strcpy(query,"ip6.arpa"); /* Suffix the string */
551 #else
552         *query = 0;
553 #endif
554 }
555
556 /** Return the next id which is ready, and the result attached to it */
557 DNSResult DNS::GetResult()
558 {
559         /* Fetch dns query response and decide where it belongs */
560         DNSHeader header;
561         DNSRequest *req;
562         unsigned char buffer[sizeof(DNSHeader)];
563         sockaddr from;
564         socklen_t x = sizeof(from);
565         const char* ipaddr_from = "";
566         unsigned short int port_from = 0;
567
568         int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
569
570         if (length < 0)
571                 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
572
573         /* Did we get the whole header? */
574         if (length < 12)
575         {
576                 /* Nope - something screwed up. */
577                 ServerInstance->Log(DEBUG,"Whole header not read!");
578                 return std::make_pair(-1,"");
579         }
580
581         /* Check wether the reply came from a different DNS
582          * server to the one we sent it to, or the source-port
583          * is not 53.
584          * A user could in theory still spoof dns packets anyway
585          * but this is less trivial than just sending garbage
586          * to the client, which is possible without this check.
587          *
588          * -- Thanks jilles for pointing this one out.
589          */
590 #ifdef IPV6
591         ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
592         port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
593 #else
594         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
595         port_from = ntohs(((sockaddr_in*)&from)->sin_port);
596 #endif
597
598         /* We cant perform this security check if you're using 4in6.
599          * Tough luck to you, choose one or't other!
600          */
601         if (!ip6munge)
602         {
603                 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
604                 {
605                         ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
606                         return std::make_pair(-1,"");
607                 }
608         }
609
610         /* Put the read header info into a header class */
611         DNS::FillHeader(&header,buffer,length - 12);
612
613         /* Get the id of this request.
614          * Its a 16 bit value stored in two char's,
615          * so we use logic shifts to create the value.
616          */
617         unsigned long this_id = header.id[1] + (header.id[0] << 8);
618
619         /* Do we have a pending request matching this id? */
620         requestlist_iter n_iter = requests.find(this_id);
621         if (n_iter == requests.end())
622         {
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,"");
626         }
627         else
628         {
629                 /* Remove the query from the list of pending queries */
630                 req = (DNSRequest*)n_iter->second;
631                 requests.erase(n_iter);
632         }
633
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.
637          */
638         DNSInfo data = req->ResultIsReady(header, length);
639         std::string resultstr;
640
641         /* Check if we got a result, if we didnt, its an error */
642         if (data.first == NULL)
643         {
644                 /* An error.
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.
649                  */
650                 delete req;
651                 return std::make_pair(this_id | ERROR_MASK, data.second);
652         }
653         else
654         {
655                 char formatted[128];
656
657                 /* Forward lookups come back as binary data. We must format them into ascii */
658                 switch (req->type)
659                 {
660                         case DNS_QUERY_A:
661                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
662                                 resultstr = formatted;
663                         break;
664
665                         case DNS_QUERY_AAAA:
666                         {
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:");
677                                 if (c != NULL)
678                                 {
679                                         memmove(c+1,c+2,strlen(c+2) + 1);
680                                         c += 2;
681                                         while (memcmp(c,"0:",2) == 0)
682                                                 memmove(c,c+2,strlen(c+2) + 1);
683                                         if (memcmp(c,"0",2) == 0)
684                                                 *c = 0;
685                                         if (memcmp(formatted,"0::",3) == 0)
686                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
687                                 }
688                                 resultstr = formatted;
689
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".
694                                  */
695                                 if (*formatted == ':')
696                                         resultstr = "0" + resultstr;
697                         }
698                         break;
699
700                         case DNS_QUERY_CNAME:
701                                 /* Identical handling to PTR */
702
703                         case DNS_QUERY_PTR:
704                                 /* Reverse lookups just come back as char* */
705                                 resultstr = std::string((const char*)data.first);
706                         break;
707
708                         default:
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!");
710                         break;
711                         
712                 }
713
714                 /* Build the reply with the id and hostname/ip in it */
715                 delete req;
716                 return std::make_pair(this_id,resultstr);
717         }
718 }
719
720 /** A result is ready, process it */
721 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
722 {
723         int i = 0;
724         int q = 0;
725         int curanswer, o;
726         ResourceRecord rr;
727         unsigned short ptr;
728
729         /* This is just to keep _FORTIFY_SOURCE happy */
730         rr.type = DNS_QUERY_NONE;
731         rr.rdlength = 0;
732
733         if (!(header.flags1 & FLAGS_MASK_QR))
734                 return std::make_pair((unsigned char*)NULL,"Not a query result");
735
736         if (header.flags1 & FLAGS_MASK_OPCODE)
737                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
738
739         if (header.flags2 & FLAGS_MASK_RCODE)
740                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
741
742         if (header.ancount < 1)
743                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
744
745         /* Subtract the length of the header from the length of the packet */
746         length -= 12;
747
748         while ((unsigned int)q < header.qdcount && i < length)
749         {
750                 if (header.payload[i] > 63)
751                 {
752                         i += 6;
753                         q++;
754                 }
755                 else
756                 {
757                         if (header.payload[i] == 0)
758                         {
759                                 q++;
760                                 i += 5;
761                         }
762                         else i += header.payload[i] + 1;
763                 }
764         }
765         curanswer = 0;
766         while ((unsigned)curanswer < header.ancount)
767         {
768                 q = 0;
769                 while (q == 0 && i < length)
770                 {
771                         if (header.payload[i] > 63)
772                         {
773                                 i += 2;
774                                 q = 1;
775                         }
776                         else
777                         {
778                                 if (header.payload[i] == 0)
779                                 {
780                                         i++;
781                                         q = 1;
782                                 }
783                                 else i += header.payload[i] + 1; /* skip length and label */
784                         }
785                 }
786                 if (length - i < 10)
787                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
788
789                 DNS::FillResourceRecord(&rr,&header.payload[i]);
790                 i += 10;
791                 if (rr.type != this->type)
792                 {
793                         curanswer++;
794                         i += rr.rdlength;
795                         continue;
796                 }
797                 if (rr.rr_class != this->rr_class)
798                 {
799                         curanswer++;
800                         i += rr.rdlength;
801                         continue;
802                 }
803                 break;
804         }
805         if ((unsigned int)curanswer == header.ancount)
806                 return std::make_pair((unsigned char*)NULL,"No valid answers");
807
808         if (i + rr.rdlength > (unsigned int)length)
809                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
810
811         if (rr.rdlength > 1023)
812                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
813
814         switch (rr.type)
815         {
816                 case DNS_QUERY_CNAME:
817                         /* CNAME and PTR have the same processing code */
818                 case DNS_QUERY_PTR:
819                         o = 0;
820                         q = 0;
821                         while (q == 0 && i < length && o + 256 < 1023)
822                         {
823                                 if (header.payload[i] > 63)
824                                 {
825                                         memcpy(&ptr,&header.payload[i],2);
826                                         i = ntohs(ptr) - 0xC000 - 12;
827                                 }
828                                 else
829                                 {
830                                         if (header.payload[i] == 0)
831                                         {
832                                                 q = 1;
833                                         }
834                                         else
835                                         {
836                                                 res[o] = 0;
837                                                 if (o != 0)
838                                                         res[o++] = '.';
839                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
840                                                 o += header.payload[i];
841                                                 i += header.payload[i] + 1;
842                                         }
843                                 }
844                         }
845                         res[o] = 0;
846                 break;
847                 case DNS_QUERY_AAAA:
848                         memcpy(res,&header.payload[i],rr.rdlength);
849                         res[rr.rdlength] = 0;
850                 break;
851                 case DNS_QUERY_A:
852                         memcpy(res,&header.payload[i],rr.rdlength);
853                         res[rr.rdlength] = 0;
854                 break;
855                 default:
856                         memcpy(res,&header.payload[i],rr.rdlength);
857                         res[rr.rdlength] = 0;
858                 break;
859         }
860         return std::make_pair(res,"No error");;
861 }
862
863 /** Close the master socket */
864 DNS::~DNS()
865 {
866         shutdown(this->GetFd(), 2);
867         close(this->GetFd());
868 }
869
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)
872 {
873         ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
874
875         insp_inaddr binip;
876
877         switch (querytype)
878         {
879                 case DNS_QUERY_A:
880                         this->myid = ServerInstance->Res->GetIP(source.c_str());
881                 break;
882
883                 case DNS_QUERY_PTR:
884                         if (insp_aton(source.c_str(), &binip) > 0)
885                         {
886                                 /* Valid ip address */
887                                 this->myid = ServerInstance->Res->GetName(&binip);
888                         }
889                         else
890                         {
891                                 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
892                                 throw ModuleException("Resolver: Bad IP address");
893                                 return;
894                         }
895                 break;
896
897                 case DNS_QUERY_PTR4:
898                         querytype = DNS_QUERY_PTR;
899                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
900                 break;
901
902                 case DNS_QUERY_PTR6:
903                         querytype = DNS_QUERY_PTR;
904                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
905                 break;
906
907                 case DNS_QUERY_AAAA:
908                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
909                 break;
910
911                 case DNS_QUERY_CNAME:
912                         this->myid = ServerInstance->Res->GetCName(source.c_str());
913                 break;
914
915                 default:
916                         this->myid = -1;
917                 break;
918         }
919         if (this->myid == -1)
920         {
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 */
925                 return;
926         }
927
928         ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
929 }
930
931 /** Called when an error occurs */
932 void Resolver::OnError(ResolverError e, const std::string &errormessage)
933 {
934         /* Nothing in here */
935 }
936
937 /** Destroy a resolver */
938 Resolver::~Resolver()
939 {
940         /* Nothing here (yet) either */
941 }
942
943 /** Get the request id associated with this class */
944 int Resolver::GetId()
945 {
946         return this->myid;
947 }
948
949 Module* Resolver::GetCreator()
950 {
951         return this->Creator;
952 }
953
954 /** Process a socket read event */
955 void DNS::HandleEvent(EventType et, int errornum)
956 {
957         ServerInstance->Log(DEBUG,"Marshall reads: %d",this->GetFd());
958         /* Fetch the id and result of the next available packet */
959         DNSResult res = this->GetResult();
960         /* Is there a usable request id? */
961         if (res.first != -1)
962         {
963                 /* Its an error reply */
964                 if (res.first & ERROR_MASK)
965                 {
966                         /* Mask off the error bit */
967                         res.first -= ERROR_MASK;
968                         /* Marshall the error to the correct class */
969                         ServerInstance->Log(DEBUG,"Error available, id=%d",res.first);
970                         if (Classes[res.first])
971                         {
972                                 if (ServerInstance && ServerInstance->stats)
973                                         ServerInstance->stats->statsDnsBad++;
974                                 Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
975                                 delete Classes[res.first];
976                                 Classes[res.first] = NULL;
977                         }
978                 }
979                 else
980                 {
981                         /* It is a non-error result */
982                         ServerInstance->Log(DEBUG,"Result available, id=%d",res.first);
983                         /* Marshall the result to the correct class */
984                         if (Classes[res.first])
985                         {
986                                 if (ServerInstance && ServerInstance->stats)
987                                         ServerInstance->stats->statsDnsGood++;
988                                 Classes[res.first]->OnLookupComplete(res.second);
989                                 delete Classes[res.first];
990                                 Classes[res.first] = NULL;
991                         }
992                 }
993
994                 if (ServerInstance && ServerInstance->stats)
995                         ServerInstance->stats->statsDns++;
996         }
997 }
998
999 /** Add a derived Resolver to the working set */
1000 bool DNS::AddResolverClass(Resolver* r)
1001 {
1002         /* Check the pointers validity and the id's validity */
1003         if ((r) && (r->GetId() > -1))
1004         {
1005                 /* Check the slot isnt already occupied -
1006                  * This should NEVER happen unless we have
1007                  * a severely broken DNS server somewhere
1008                  */
1009                 if (!Classes[r->GetId()])
1010                 {
1011                         /* Set up the pointer to the class */
1012                         Classes[r->GetId()] = r;
1013                         return true;
1014                 }
1015                 else
1016                         /* Duplicate id */
1017                         return false;
1018         }
1019         else
1020         {
1021                 /* Pointer or id not valid.
1022                  * Free the item and return
1023                  */
1024                 if (r)
1025                         delete r;
1026
1027                 return false;
1028         }
1029 }
1030
1031 void DNS::CleanResolvers(Module* module)
1032 {
1033         for (int i = 0; i < MAX_REQUEST_ID; i++)
1034         {
1035                 if (Classes[i])
1036                 {
1037                         if (Classes[i]->GetCreator() == module)
1038                         {
1039                                 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1040                                 delete Classes[i];
1041                                 Classes[i] = NULL;
1042                         }
1043                 }
1044         }
1045 }
1046
1047 /** Generate pseudo-random number */
1048 unsigned long DNS::PRNG()
1049 {
1050         unsigned long val = 0;
1051         timeval n;
1052         serverstats* s = ServerInstance->stats;
1053         gettimeofday(&n,NULL);
1054         val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1055         val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1056         val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;
1057         return val;
1058 }
1059