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