]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
Timer changes and TimerManager enhancements
[user/henk/code/inspircd.git] / src / dns.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2012 William Pitcock <nenolod@dereferenced.org>
5  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
6  *   Copyright (C) 2006, 2009 Robin Burchell <robin+git@viroteck.net>
7  *   Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
8  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
9  *   Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc>
10  *
11  * This file is part of InspIRCd.  InspIRCd is free software: you can
12  * redistribute it and/or modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation, version 2.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24
25 /* $Core */
26
27 /*
28 dns.cpp - Nonblocking DNS functions.
29 Very very loosely based on the firedns library,
30 Copyright (C) 2002 Ian Gulliver. This file is no
31 longer anything like firedns, there are many major
32 differences between this code and the original.
33 Please do not assume that firedns works like this,
34 looks like this, walks like this or tastes like this.
35 */
36
37 #ifndef _WIN32
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <errno.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #else
44 #include "inspircd_win32wrapper.h"
45 #endif
46
47 #include "inspircd.h"
48 #include "socketengine.h"
49 #include "configreader.h"
50 #include "socket.h"
51
52 #define DN_COMP_BITMASK 0xC000          /* highest 6 bits in a DN label header */
53
54 /** Masks to mask off the responses we get from the DNSRequest methods
55  */
56 enum QueryInfo
57 {
58         ERROR_MASK      = 0x10000       /* Result is an error */
59 };
60
61 /** Flags which can be ORed into a request or reply for different meanings
62  */
63 enum QueryFlags
64 {
65         FLAGS_MASK_RD           = 0x01, /* Recursive */
66         FLAGS_MASK_TC           = 0x02,
67         FLAGS_MASK_AA           = 0x04, /* Authoritative */
68         FLAGS_MASK_OPCODE       = 0x78,
69         FLAGS_MASK_QR           = 0x80,
70         FLAGS_MASK_RCODE        = 0x0F, /* Request */
71         FLAGS_MASK_Z            = 0x70,
72         FLAGS_MASK_RA           = 0x80
73 };
74
75
76 /** Represents a dns resource record (rr)
77  */
78 struct ResourceRecord
79 {
80         QueryType       type;           /* Record type */
81         unsigned int    rr_class;       /* Record class */
82         unsigned long   ttl;            /* Time to live */
83         unsigned int    rdlength;       /* Record length */
84 };
85
86 /** Represents a dns request/reply header, and its payload as opaque data.
87  */
88 class DNSHeader
89 {
90  public:
91         unsigned char   id[2];          /* Request id */
92         unsigned int    flags1;         /* Flags */
93         unsigned int    flags2;         /* Flags */
94         unsigned int    qdcount;
95         unsigned int    ancount;        /* Answer count */
96         unsigned int    nscount;        /* Nameserver count */
97         unsigned int    arcount;
98         unsigned char   payload[512];   /* Packet payload */
99 };
100
101 class DNSRequest
102 {
103  public:
104         unsigned char   id[2];          /* Request id */
105         unsigned char*  res;            /* Result processing buffer */
106         unsigned int    rr_class;       /* Request class */
107         QueryType       type;           /* Request type */
108         DNS*            dnsobj;         /* DNS caller (where we get our FD from) */
109         unsigned long   ttl;            /* Time to live */
110         std::string     orig;           /* Original requested name/ip */
111
112         DNSRequest(DNS* dns, int id, const std::string &original);
113         ~DNSRequest();
114         DNSInfo ResultIsReady(DNSHeader &h, unsigned length);
115         int SendRequests(const DNSHeader *header, const int length, QueryType qt);
116 };
117
118 class CacheTimer : public Timer
119 {
120  private:
121         DNS* dns;
122  public:
123         CacheTimer(DNS* thisdns)
124                 : Timer(3600, ServerInstance->Time(), true), dns(thisdns) { }
125
126         virtual bool Tick(time_t)
127         {
128                 dns->PruneCache();
129                 return true;
130         }
131 };
132
133 class RequestTimeout : public Timer
134 {
135         DNSRequest* watch;
136         int watchid;
137  public:
138         RequestTimeout(unsigned long n, DNSRequest* watching, int id) : Timer(n, ServerInstance->Time()), watch(watching), watchid(id)
139         {
140         }
141         ~RequestTimeout()
142         {
143                 if (ServerInstance->Res)
144                         Tick(0);
145         }
146
147         bool Tick(time_t)
148         {
149                 if (ServerInstance->Res->requests[watchid] == watch)
150                 {
151                         /* Still exists, whack it */
152                         if (ServerInstance->Res->Classes[watchid])
153                         {
154                                 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
155                                 delete ServerInstance->Res->Classes[watchid];
156                                 ServerInstance->Res->Classes[watchid] = NULL;
157                         }
158                         ServerInstance->Res->requests[watchid] = NULL;
159                         delete watch;
160                 }
161                 return false;
162         }
163 };
164
165 CachedQuery::CachedQuery(const std::string &res, unsigned int ttl) : data(res)
166 {
167         expires = ServerInstance->Time() + ttl;
168 }
169
170 int CachedQuery::CalcTTLRemaining()
171 {
172         int n = expires - ServerInstance->Time();
173         return (n < 0 ? 0 : n);
174 }
175
176 /* Allocate the processing buffer */
177 DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns)
178 {
179         /* hardening against overflow here:  make our work buffer twice the theoretical
180          * maximum size so that hostile input doesn't screw us over.
181          */
182         res = new unsigned char[sizeof(DNSHeader) * 2];
183         *res = 0;
184         orig = original;
185         RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid);
186         ServerInstance->Timers->AddTimer(RT); /* The timer manager frees this */
187 }
188
189 /* Deallocate the processing buffer */
190 DNSRequest::~DNSRequest()
191 {
192         delete[] res;
193 }
194
195 /** Fill a ResourceRecord class based on raw data input */
196 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
197 {
198         rr->type = (QueryType)((input[0] << 8) + input[1]);
199         rr->rr_class = (input[2] << 8) + input[3];
200         rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
201         rr->rdlength = (input[8] << 8) + input[9];
202 }
203
204 /** Fill a DNSHeader class based on raw data input of a given length */
205 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
206 {
207         header->id[0] = input[0];
208         header->id[1] = input[1];
209         header->flags1 = input[2];
210         header->flags2 = input[3];
211         header->qdcount = (input[4] << 8) + input[5];
212         header->ancount = (input[6] << 8) + input[7];
213         header->nscount = (input[8] << 8) + input[9];
214         header->arcount = (input[10] << 8) + input[11];
215         memcpy(header->payload,&input[12],length);
216 }
217
218 /** Empty a DNSHeader class out into raw data, ready for transmission */
219 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
220 {
221         output[0] = header->id[0];
222         output[1] = header->id[1];
223         output[2] = header->flags1;
224         output[3] = header->flags2;
225         output[4] = header->qdcount >> 8;
226         output[5] = header->qdcount & 0xFF;
227         output[6] = header->ancount >> 8;
228         output[7] = header->ancount & 0xFF;
229         output[8] = header->nscount >> 8;
230         output[9] = header->nscount & 0xFF;
231         output[10] = header->arcount >> 8;
232         output[11] = header->arcount & 0xFF;
233         memcpy(&output[12],header->payload,length);
234 }
235
236 /** Send requests we have previously built down the UDP socket */
237 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
238 {
239         ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG,"DNSRequest::SendRequests");
240
241         unsigned char payload[sizeof(DNSHeader)];
242
243         this->rr_class = 1;
244         this->type = qt;
245
246         DNS::EmptyHeader(payload,header,length);
247
248         if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12)
249                 return -1;
250
251         ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Sent OK");
252         return 0;
253 }
254
255 /** Add a query with a predefined header, and allocate an ID for it. */
256 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
257 {
258         /* Is the DNS connection down? */
259         if (this->GetFd() == -1)
260                 return NULL;
261
262         /* Create an id */
263         unsigned int tries = 0;
264         do {
265                 id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
266                 if (++tries == DNS::MAX_REQUEST_ID*5)
267                 {
268                         // If we couldn't find an empty slot this many times, do a sequential scan as a last
269                         // resort. If an empty slot is found that way, go on, otherwise throw an exception
270                         id = -1;
271                         for (int i = 0; i < DNS::MAX_REQUEST_ID; i++)
272                         {
273                                 if (!requests[i])
274                                 {
275                                         id = i;
276                                         break;
277                                 }
278                         }
279
280                         if (id == -1)
281                                 throw ModuleException("DNS: All ids are in use");
282
283                         break;
284                 }
285         } while (requests[id]);
286
287         DNSRequest* req = new DNSRequest(this, id, original);
288
289         header->id[0] = req->id[0] = id >> 8;
290         header->id[1] = req->id[1] = id & 0xFF;
291         header->flags1 = FLAGS_MASK_RD;
292         header->flags2 = 0;
293         header->qdcount = 1;
294         header->ancount = 0;
295         header->nscount = 0;
296         header->arcount = 0;
297
298         /* At this point we already know the id doesnt exist,
299          * so there needs to be no second check for the ::end()
300          */
301         requests[id] = req;
302
303         /* According to the C++ spec, new never returns NULL. */
304         return req;
305 }
306
307 int DNS::ClearCache()
308 {
309         /* This ensures the buckets are reset to sane levels */
310         int rv = this->cache->size();
311         delete this->cache;
312         this->cache = new dnscache();
313         return rv;
314 }
315
316 int DNS::PruneCache()
317 {
318         int n = 0;
319         dnscache* newcache = new dnscache();
320         for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
321                 /* Dont include expired items (theres no point) */
322                 if (i->second.CalcTTLRemaining())
323                         newcache->insert(*i);
324                 else
325                         n++;
326
327         delete this->cache;
328         this->cache = newcache;
329         return n;
330 }
331
332 void DNS::Rehash()
333 {
334         if (this->GetFd() > -1)
335         {
336                 ServerInstance->SE->DelFd(this);
337                 ServerInstance->SE->Shutdown(this, 2);
338                 ServerInstance->SE->Close(this);
339                 this->SetFd(-1);
340
341                 /* Rehash the cache */
342                 this->PruneCache();
343         }
344         else
345         {
346                 /* Create initial dns cache */
347                 this->cache = new dnscache();
348         }
349
350         irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver);
351
352         /* Initialize mastersocket */
353         int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
354         this->SetFd(s);
355
356         /* Have we got a socket and is it nonblocking? */
357         if (this->GetFd() != -1)
358         {
359                 ServerInstance->SE->SetReuse(s);
360                 ServerInstance->SE->NonBlocking(s);
361                 irc::sockets::sockaddrs bindto;
362                 memset(&bindto, 0, sizeof(bindto));
363                 bindto.sa.sa_family = myserver.sa.sa_family;
364                 if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0)
365                 {
366                         /* Failed to bind */
367                         ServerInstance->Logs->Log("RESOLVER",LOG_SPARSE,"Error binding dns socket - hostnames will NOT resolve");
368                         ServerInstance->SE->Shutdown(this, 2);
369                         ServerInstance->SE->Close(this);
370                         this->SetFd(-1);
371                 }
372                 else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
373                 {
374                         ServerInstance->Logs->Log("RESOLVER",LOG_SPARSE,"Internal error starting DNS - hostnames will NOT resolve.");
375                         ServerInstance->SE->Shutdown(this, 2);
376                         ServerInstance->SE->Close(this);
377                         this->SetFd(-1);
378                 }
379         }
380         else
381         {
382                 ServerInstance->Logs->Log("RESOLVER",LOG_SPARSE,"Error creating DNS socket - hostnames will NOT resolve");
383         }
384 }
385
386 /** Initialise the DNS UDP socket so that we can send requests */
387 DNS::DNS()
388 {
389         ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::DNS");
390         /* Clear the Resolver class table */
391         memset(Classes,0,sizeof(Classes));
392
393         /* Clear the requests class table */
394         memset(requests,0,sizeof(requests));
395
396         /* DNS::Rehash() sets this to a valid ptr
397          */
398         this->cache = NULL;
399
400         /* Again, DNS::Rehash() sets this to a
401          * valid value
402          */
403         this->SetFd(-1);
404
405         /* Actually read the settings
406          */
407         this->Rehash();
408
409         this->PruneTimer = new CacheTimer(this);
410
411         ServerInstance->Timers->AddTimer(this->PruneTimer);
412 }
413
414 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
415 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
416 {
417         short payloadpos = 0;
418         const char* tempchr, *tempchr2 = name;
419         unsigned short length;
420
421         /* split name up into labels, create query */
422         while ((tempchr = strchr(tempchr2,'.')) != NULL)
423         {
424                 length = tempchr - tempchr2;
425                 if (payloadpos + length + 1 > 507)
426                         return -1;
427                 payload[payloadpos++] = length;
428                 memcpy(&payload[payloadpos],tempchr2,length);
429                 payloadpos += length;
430                 tempchr2 = &tempchr[1];
431         }
432         length = strlen(tempchr2);
433         if (length)
434         {
435                 if (payloadpos + length + 2 > 507)
436                         return -1;
437                 payload[payloadpos++] = length;
438                 memcpy(&payload[payloadpos],tempchr2,length);
439                 payloadpos += length;
440                 payload[payloadpos++] = 0;
441         }
442         if (payloadpos > 508)
443                 return -1;
444         length = htons(rr);
445         memcpy(&payload[payloadpos],&length,2);
446         length = htons(rr_class);
447         memcpy(&payload[payloadpos + 2],&length,2);
448         return payloadpos + 4;
449 }
450
451 /** Start lookup of an hostname to an IP address */
452 int DNS::GetIP(const char *name)
453 {
454         DNSHeader h;
455         int id;
456         int length;
457
458         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
459                 return -1;
460
461         DNSRequest* req = this->AddQuery(&h, id, name);
462
463         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
464                 return -1;
465
466         return id;
467 }
468
469 /** Start lookup of an hostname to an IPv6 address */
470 int DNS::GetIP6(const char *name)
471 {
472         DNSHeader h;
473         int id;
474         int length;
475
476         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
477                 return -1;
478
479         DNSRequest* req = this->AddQuery(&h, id, name);
480
481         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
482                 return -1;
483
484         return id;
485 }
486
487 /** Start lookup of a cname to another name */
488 int DNS::GetCName(const char *alias)
489 {
490         DNSHeader h;
491         int id;
492         int length;
493
494         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
495                 return -1;
496
497         DNSRequest* req = this->AddQuery(&h, id, alias);
498
499         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
500                 return -1;
501
502         return id;
503 }
504
505 /** Start lookup of an IP address to a hostname */
506 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
507 {
508         char query[128];
509         DNSHeader h;
510         int id;
511         int length;
512
513         if (fp == PROTOCOL_IPV6)
514         {
515                 in6_addr i;
516                 if (inet_pton(AF_INET6, ip, &i) > 0)
517                 {
518                         DNS::MakeIP6Int(query, &i);
519                 }
520                 else
521                 {
522                         ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip);
523                         /* Invalid IP address */
524                         return -1;
525                 }
526         }
527         else
528         {
529                 in_addr i;
530                 if (inet_aton(ip, &i))
531                 {
532                         unsigned char* c = (unsigned char*)&i.s_addr;
533                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
534                 }
535                 else
536                 {
537                         ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip);
538                         /* Invalid IP address */
539                         return -1;
540                 }
541         }
542
543         length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload);
544         if (length == -1)
545         {
546                 ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query);
547                 return -1;
548         }
549
550         DNSRequest* req = this->AddQuery(&h, id, ip);
551
552         if (!req)
553         {
554                 ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce can't add query (resolver down?)");
555                 return -1;
556         }
557
558         if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1)
559         {
560                 ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce can't send (firewall?)");
561                 return -1;
562         }
563
564         return id;
565 }
566
567 /** Build an ipv6 reverse domain from an in6_addr
568  */
569 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
570 {
571         const char* hex = "0123456789abcdef";
572         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
573         {
574                 if (index % 2)
575                         /* low nibble */
576                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
577                 else
578                         /* high nibble */
579                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
580                 *query++ = '.'; /* Seperator */
581         }
582         strcpy(query,"ip6.arpa"); /* Suffix the string */
583 }
584
585 /** Return the next id which is ready, and the result attached to it */
586 DNSResult DNS::GetResult()
587 {
588         /* Fetch dns query response and decide where it belongs */
589         DNSHeader header;
590         DNSRequest *req;
591         unsigned char buffer[sizeof(DNSHeader)];
592         irc::sockets::sockaddrs from;
593         memset(&from, 0, sizeof(from));
594         socklen_t x = sizeof(from);
595
596         int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
597
598         /* Did we get the whole header? */
599         if (length < 12)
600         {
601                 ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"GetResult didn't get a full packet (len=%d)", length);
602                 /* Nope - something screwed up. */
603                 return DNSResult(-1,"",0,"");
604         }
605
606         /* Check wether the reply came from a different DNS
607          * server to the one we sent it to, or the source-port
608          * is not 53.
609          * A user could in theory still spoof dns packets anyway
610          * but this is less trivial than just sending garbage
611          * to the server, which is possible without this check.
612          *
613          * -- Thanks jilles for pointing this one out.
614          */
615         if (from != myserver)
616         {
617                 std::string server1 = from.str();
618                 std::string server2 = myserver.str();
619                 ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
620                         server1.c_str(), server2.c_str());
621                 return DNSResult(-1,"",0,"");
622         }
623
624         /* Put the read header info into a header class */
625         DNS::FillHeader(&header,buffer,length - 12);
626
627         /* Get the id of this request.
628          * Its a 16 bit value stored in two char's,
629          * so we use logic shifts to create the value.
630          */
631         unsigned long this_id = header.id[1] + (header.id[0] << 8);
632
633         /* Do we have a pending request matching this id? */
634         if (!requests[this_id])
635         {
636                 /* Somehow we got a DNS response for a request we never made... */
637                 ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id);
638                 return DNSResult(-1,"",0,"");
639         }
640         else
641         {
642                 /* Remove the query from the list of pending queries */
643                 req = requests[this_id];
644                 requests[this_id] = NULL;
645         }
646
647         /* Inform the DNSRequest class that it has a result to be read.
648          * When its finished it will return a DNSInfo which is a pair of
649          * unsigned char* resource record data, and an error message.
650          */
651         DNSInfo data = req->ResultIsReady(header, length);
652         std::string resultstr;
653
654         /* Check if we got a result, if we didnt, its an error */
655         if (data.first == NULL)
656         {
657                 /* An error.
658                  * Mask the ID with the value of ERROR_MASK, so that
659                  * the dns_deal_with_classes() function knows that its
660                  * an error response and needs to be treated uniquely.
661                  * Put the error message in the second field.
662                  */
663                 std::string ro = req->orig;
664                 delete req;
665                 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
666         }
667         else
668         {
669                 unsigned long ttl = req->ttl;
670                 char formatted[128];
671
672                 /* Forward lookups come back as binary data. We must format them into ascii */
673                 switch (req->type)
674                 {
675                         case DNS_QUERY_A:
676                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
677                                 resultstr = formatted;
678                         break;
679
680                         case DNS_QUERY_AAAA:
681                         {
682                                 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
683                                 char* c = strstr(formatted,":0:");
684                                 if (c != NULL)
685                                 {
686                                         memmove(c+1,c+2,strlen(c+2) + 1);
687                                         c += 2;
688                                         while (memcmp(c,"0:",2) == 0)
689                                                 memmove(c,c+2,strlen(c+2) + 1);
690                                         if (memcmp(c,"0",2) == 0)
691                                                 *c = 0;
692                                         if (memcmp(formatted,"0::",3) == 0)
693                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
694                                 }
695                                 resultstr = formatted;
696
697                                 /* Special case. Sending ::1 around between servers
698                                  * and to clients is dangerous, because the : on the
699                                  * start makes the client or server interpret the IP
700                                  * as the last parameter on the line with a value ":1".
701                                  */
702                                 if (*formatted == ':')
703                                         resultstr.insert(0, "0");
704                         }
705                         break;
706
707                         case DNS_QUERY_CNAME:
708                                 /* Identical handling to PTR */
709
710                         case DNS_QUERY_PTR:
711                                 /* Reverse lookups just come back as char* */
712                                 resultstr = std::string((const char*)data.first);
713                         break;
714
715                         default:
716                         break;
717                 }
718
719                 /* Build the reply with the id and hostname/ip in it */
720                 std::string ro = req->orig;
721                 delete req;
722                 return DNSResult(this_id,resultstr,ttl,ro);
723         }
724 }
725
726 /** A result is ready, process it */
727 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
728 {
729         unsigned i = 0, o;
730         int q = 0;
731         int curanswer;
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         rr.ttl = 1;     /* GCC is a whiney bastard -- see the XXX below. */
739         rr.rr_class = 0; /* Same for VC++ */
740
741         if (!(header.flags1 & FLAGS_MASK_QR))
742                 return std::make_pair((unsigned char*)NULL,"Not a query result");
743
744         if (header.flags1 & FLAGS_MASK_OPCODE)
745                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
746
747         if (header.flags2 & FLAGS_MASK_RCODE)
748                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
749
750         if (header.ancount < 1)
751                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
752
753         /* Subtract the length of the header from the length of the packet */
754         length -= 12;
755
756         while ((unsigned int)q < header.qdcount && i < length)
757         {
758                 if (header.payload[i] > 63)
759                 {
760                         i += 6;
761                         q++;
762                 }
763                 else
764                 {
765                         if (header.payload[i] == 0)
766                         {
767                                 q++;
768                                 i += 5;
769                         }
770                         else i += header.payload[i] + 1;
771                 }
772         }
773         curanswer = 0;
774         while ((unsigned)curanswer < header.ancount)
775         {
776                 q = 0;
777                 while (q == 0 && i < length)
778                 {
779                         if (header.payload[i] > 63)
780                         {
781                                 i += 2;
782                                 q = 1;
783                         }
784                         else
785                         {
786                                 if (header.payload[i] == 0)
787                                 {
788                                         i++;
789                                         q = 1;
790                                 }
791                                 else i += header.payload[i] + 1; /* skip length and label */
792                         }
793                 }
794                 if (static_cast<int>(length - i) < 10)
795                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
796
797                 /* XXX: We actually initialise 'rr' here including its ttl field */
798                 DNS::FillResourceRecord(&rr,&header.payload[i]);
799
800                 i += 10;
801                 ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Resolver: rr.type is %d and this.type is %d rr.class %d this.class %d", rr.type, this->type, rr.rr_class, this->rr_class);
802                 if (rr.type != this->type)
803                 {
804                         curanswer++;
805                         i += rr.rdlength;
806                         continue;
807                 }
808                 if (rr.rr_class != this->rr_class)
809                 {
810                         curanswer++;
811                         i += rr.rdlength;
812                         continue;
813                 }
814                 break;
815         }
816         if ((unsigned int)curanswer == header.ancount)
817                 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
818
819         if (i + rr.rdlength > (unsigned int)length)
820                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
821
822         if (rr.rdlength > 1023)
823                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
824
825         this->ttl = rr.ttl;
826
827         switch (rr.type)
828         {
829                 /*
830                  * CNAME and PTR are compressed.  We need to decompress them.
831                  */
832                 case DNS_QUERY_CNAME:
833                 case DNS_QUERY_PTR:
834                 {
835                         unsigned short lowest_pos = length;
836                         o = 0;
837                         q = 0;
838                         while (q == 0 && i < length && o + 256 < 1023)
839                         {
840                                 /* DN label found (byte over 63) */
841                                 if (header.payload[i] > 63)
842                                 {
843                                         memcpy(&ptr,&header.payload[i],2);
844
845                                         i = ntohs(ptr);
846
847                                         /* check that highest two bits are set. if not, we've been had */
848                                         if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK)
849                                                 return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
850
851                                         /* mask away the two highest bits. */
852                                         i &= ~DN_COMP_BITMASK;
853
854                                         /* and decrease length by 12 bytes. */
855                                         i -= 12;
856
857                                         if (i >= lowest_pos)
858                                                 return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer");
859                                         lowest_pos = i;
860                                 }
861                                 else
862                                 {
863                                         if (header.payload[i] == 0)
864                                         {
865                                                 q = 1;
866                                         }
867                                         else
868                                         {
869                                                 res[o] = 0;
870                                                 if (o != 0)
871                                                         res[o++] = '.';
872
873                                                 if (o + header.payload[i] > sizeof(DNSHeader))
874                                                         return std::make_pair((unsigned char *) NULL, "DN label decompression is impossible -- malformed/hostile packet?");
875
876                                                 memcpy(&res[o], &header.payload[i + 1], header.payload[i]);
877                                                 o += header.payload[i];
878                                                 i += header.payload[i] + 1;
879                                         }
880                                 }
881                         }
882                         res[o] = 0;
883                 }
884                 break;
885                 case DNS_QUERY_AAAA:
886                         if (rr.rdlength != sizeof(struct in6_addr))
887                                 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?");
888
889                         memcpy(res,&header.payload[i],rr.rdlength);
890                         res[rr.rdlength] = 0;
891                 break;
892                 case DNS_QUERY_A:
893                         if (rr.rdlength != sizeof(struct in_addr))
894                                 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?");
895
896                         memcpy(res,&header.payload[i],rr.rdlength);
897                         res[rr.rdlength] = 0;
898                 break;
899                 default:
900                         return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting");
901                 break;
902         }
903         return std::make_pair(res,"No error");
904 }
905
906 /** Close the master socket */
907 DNS::~DNS()
908 {
909         ServerInstance->SE->Shutdown(this, 2);
910         ServerInstance->SE->Close(this);
911         ServerInstance->Timers->DelTimer(this->PruneTimer);
912         if (cache)
913                 delete cache;
914 }
915
916 CachedQuery* DNS::GetCache(const std::string &source)
917 {
918         dnscache::iterator x = cache->find(source.c_str());
919         if (x != cache->end())
920                 return &(x->second);
921         else
922                 return NULL;
923 }
924
925 void DNS::DelCache(const std::string &source)
926 {
927         cache->erase(source.c_str());
928 }
929
930 void Resolver::TriggerCachedResult()
931 {
932         if (CQ)
933                 OnLookupComplete(CQ->data, time_left, true);
934 }
935
936 /** High level abstraction of dns used by application at large */
937 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
938 {
939         ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Resolver::Resolver");
940         cached = false;
941
942         CQ = ServerInstance->Res->GetCache(source);
943         if (CQ)
944         {
945                 time_left = CQ->CalcTTLRemaining();
946                 if (!time_left)
947                 {
948                         ServerInstance->Res->DelCache(source);
949                 }
950                 else
951                 {
952                         cached = true;
953                         return;
954                 }
955         }
956
957         switch (querytype)
958         {
959                 case DNS_QUERY_A:
960                         this->myid = ServerInstance->Res->GetIP(source.c_str());
961                 break;
962
963                 case DNS_QUERY_PTR4:
964                         querytype = DNS_QUERY_PTR;
965                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
966                 break;
967
968                 case DNS_QUERY_PTR6:
969                         querytype = DNS_QUERY_PTR;
970                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
971                 break;
972
973                 case DNS_QUERY_AAAA:
974                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
975                 break;
976
977                 case DNS_QUERY_CNAME:
978                         this->myid = ServerInstance->Res->GetCName(source.c_str());
979                 break;
980
981                 default:
982                         ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS request with unknown query type %d", querytype);
983                         this->myid = -1;
984                 break;
985         }
986         if (this->myid == -1)
987         {
988                 throw ModuleException("Resolver: Couldn't get an id to make a request");
989         }
990         else
991         {
992                 ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS request id %d", this->myid);
993         }
994 }
995
996 /** Called when an error occurs */
997 void Resolver::OnError(ResolverError, const std::string&)
998 {
999         /* Nothing in here */
1000 }
1001
1002 /** Destroy a resolver */
1003 Resolver::~Resolver()
1004 {
1005         /* Nothing here (yet) either */
1006 }
1007
1008 /** Get the request id associated with this class */
1009 int Resolver::GetId()
1010 {
1011         return this->myid;
1012 }
1013
1014 Module* Resolver::GetCreator()
1015 {
1016         return this->Creator;
1017 }
1018
1019 /** Process a socket read event */
1020 void DNS::HandleEvent(EventType, int)
1021 {
1022         /* Fetch the id and result of the next available packet */
1023         DNSResult res(0,"",0,"");
1024         res.id = 0;
1025         ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Handle DNS event");
1026
1027         res = this->GetResult();
1028
1029         ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Result id %d", res.id);
1030
1031         /* Is there a usable request id? */
1032         if (res.id != -1)
1033         {
1034                 /* Its an error reply */
1035                 if (res.id & ERROR_MASK)
1036                 {
1037                         /* Mask off the error bit */
1038                         res.id -= ERROR_MASK;
1039                         /* Marshall the error to the correct class */
1040                         if (Classes[res.id])
1041                         {
1042                                 if (ServerInstance && ServerInstance->stats)
1043                                         ServerInstance->stats->statsDnsBad++;
1044                                 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1045                                 delete Classes[res.id];
1046                                 Classes[res.id] = NULL;
1047                         }
1048                         return;
1049                 }
1050                 else
1051                 {
1052                         /* It is a non-error result, marshall the result to the correct class */
1053                         if (Classes[res.id])
1054                         {
1055                                 if (ServerInstance && ServerInstance->stats)
1056                                         ServerInstance->stats->statsDnsGood++;
1057
1058                                 if (!this->GetCache(res.original.c_str()))
1059                                         this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1060
1061                                 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
1062                                 delete Classes[res.id];
1063                                 Classes[res.id] = NULL;
1064                         }
1065                 }
1066
1067                 if (ServerInstance && ServerInstance->stats)
1068                         ServerInstance->stats->statsDns++;
1069         }
1070 }
1071
1072 /** Add a derived Resolver to the working set */
1073 bool DNS::AddResolverClass(Resolver* r)
1074 {
1075         ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
1076         /* Check the pointers validity and the id's validity */
1077         if ((r) && (r->GetId() > -1))
1078         {
1079                 /* Check the slot isnt already occupied -
1080                  * This should NEVER happen unless we have
1081                  * a severely broken DNS server somewhere
1082                  */
1083                 if (!Classes[r->GetId()])
1084                 {
1085                         /* Set up the pointer to the class */
1086                         Classes[r->GetId()] = r;
1087                         return true;
1088                 }
1089         }
1090
1091         /* Pointer or id not valid, or duplicate id.
1092          * Free the item and return
1093          */
1094         delete r;
1095         return false;
1096 }
1097
1098 void DNS::CleanResolvers(Module* module)
1099 {
1100         for (int i = 0; i < MAX_REQUEST_ID; i++)
1101         {
1102                 if (Classes[i])
1103                 {
1104                         if (Classes[i]->GetCreator() == module)
1105                         {
1106                                 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");
1107                                 delete Classes[i];
1108                                 Classes[i] = NULL;
1109                         }
1110                 }
1111         }
1112 }