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