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