]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
Do not use the result of the dns cache when the query type of the result is different...
[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 void Tick(time_t)
127         {
128                 dns->PruneCache();
129         }
130 };
131
132 class RequestTimeout : public Timer
133 {
134         DNSRequest* watch;
135         int watchid;
136  public:
137         RequestTimeout(unsigned long n, DNSRequest* watching, int id) : Timer(n, ServerInstance->Time()), watch(watching), watchid(id)
138         {
139         }
140         ~RequestTimeout()
141         {
142                 if (ServerInstance->Res)
143                         Tick(0);
144         }
145
146         void Tick(time_t)
147         {
148                 if (ServerInstance->Res->requests[watchid] == watch)
149                 {
150                         /* Still exists, whack it */
151                         if (ServerInstance->Res->Classes[watchid])
152                         {
153                                 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
154                                 delete ServerInstance->Res->Classes[watchid];
155                                 ServerInstance->Res->Classes[watchid] = NULL;
156                         }
157                         ServerInstance->Res->requests[watchid] = NULL;
158                         delete watch;
159                 }
160         }
161 };
162
163 CachedQuery::CachedQuery(const std::string &res, QueryType qt, unsigned int ttl) : data(res), type(qt)
164 {
165         expires = ServerInstance->Time() + ttl;
166 }
167
168 int CachedQuery::CalcTTLRemaining()
169 {
170         int n = expires - ServerInstance->Time();
171         return (n < 0 ? 0 : n);
172 }
173
174 /* Allocate the processing buffer */
175 DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns)
176 {
177         /* hardening against overflow here:  make our work buffer twice the theoretical
178          * maximum size so that hostile input doesn't screw us over.
179          */
180         res = new unsigned char[sizeof(DNSHeader) * 2];
181         *res = 0;
182         orig = original;
183         RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid);
184         ServerInstance->Timers->AddTimer(RT); /* The timer manager frees this */
185 }
186
187 /* Deallocate the processing buffer */
188 DNSRequest::~DNSRequest()
189 {
190         delete[] res;
191 }
192
193 /** Fill a ResourceRecord class based on raw data input */
194 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
195 {
196         rr->type = (QueryType)((input[0] << 8) + input[1]);
197         rr->rr_class = (input[2] << 8) + input[3];
198         rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
199         rr->rdlength = (input[8] << 8) + input[9];
200 }
201
202 /** Fill a DNSHeader class based on raw data input of a given length */
203 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
204 {
205         header->id[0] = input[0];
206         header->id[1] = input[1];
207         header->flags1 = input[2];
208         header->flags2 = input[3];
209         header->qdcount = (input[4] << 8) + input[5];
210         header->ancount = (input[6] << 8) + input[7];
211         header->nscount = (input[8] << 8) + input[9];
212         header->arcount = (input[10] << 8) + input[11];
213         memcpy(header->payload,&input[12],length);
214 }
215
216 /** Empty a DNSHeader class out into raw data, ready for transmission */
217 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
218 {
219         output[0] = header->id[0];
220         output[1] = header->id[1];
221         output[2] = header->flags1;
222         output[3] = header->flags2;
223         output[4] = header->qdcount >> 8;
224         output[5] = header->qdcount & 0xFF;
225         output[6] = header->ancount >> 8;
226         output[7] = header->ancount & 0xFF;
227         output[8] = header->nscount >> 8;
228         output[9] = header->nscount & 0xFF;
229         output[10] = header->arcount >> 8;
230         output[11] = header->arcount & 0xFF;
231         memcpy(&output[12],header->payload,length);
232 }
233
234 /** Send requests we have previously built down the UDP socket */
235 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
236 {
237         ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests");
238
239         unsigned char payload[sizeof(DNSHeader)];
240
241         this->rr_class = 1;
242         this->type = qt;
243
244         DNS::EmptyHeader(payload,header,length);
245
246         if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12)
247                 return -1;
248
249         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK");
250         return 0;
251 }
252
253 /** Add a query with a predefined header, and allocate an ID for it. */
254 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
255 {
256         /* Is the DNS connection down? */
257         if (this->GetFd() == -1)
258                 return NULL;
259
260         /* Create an id */
261         unsigned int tries = 0;
262         do {
263                 id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
264                 if (++tries == DNS::MAX_REQUEST_ID*5)
265                 {
266                         // If we couldn't find an empty slot this many times, do a sequential scan as a last
267                         // resort. If an empty slot is found that way, go on, otherwise throw an exception
268                         id = -1;
269                         for (int i = 0; i < DNS::MAX_REQUEST_ID; i++)
270                         {
271                                 if (!requests[i])
272                                 {
273                                         id = i;
274                                         break;
275                                 }
276                         }
277
278                         if (id == -1)
279                                 throw ModuleException("DNS: All ids are in use");
280
281                         break;
282                 }
283         } while (requests[id]);
284
285         DNSRequest* req = new DNSRequest(this, id, original);
286
287         header->id[0] = req->id[0] = id >> 8;
288         header->id[1] = req->id[1] = id & 0xFF;
289         header->flags1 = FLAGS_MASK_RD;
290         header->flags2 = 0;
291         header->qdcount = 1;
292         header->ancount = 0;
293         header->nscount = 0;
294         header->arcount = 0;
295
296         /* At this point we already know the id doesnt exist,
297          * so there needs to be no second check for the ::end()
298          */
299         requests[id] = req;
300
301         /* According to the C++ spec, new never returns NULL. */
302         return req;
303 }
304
305 int DNS::ClearCache()
306 {
307         /* This ensures the buckets are reset to sane levels */
308         int rv = this->cache->size();
309         delete this->cache;
310         this->cache = new dnscache();
311         return rv;
312 }
313
314 int DNS::PruneCache()
315 {
316         int n = 0;
317         dnscache* newcache = new dnscache();
318         for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
319                 /* Dont include expired items (theres no point) */
320                 if (i->second.CalcTTLRemaining())
321                         newcache->insert(*i);
322                 else
323                         n++;
324
325         delete this->cache;
326         this->cache = newcache;
327         return n;
328 }
329
330 void DNS::Rehash()
331 {
332         if (this->GetFd() > -1)
333         {
334                 ServerInstance->SE->DelFd(this);
335                 ServerInstance->SE->Shutdown(this, 2);
336                 ServerInstance->SE->Close(this);
337                 this->SetFd(-1);
338
339                 /* Rehash the cache */
340                 this->PruneCache();
341         }
342         else
343         {
344                 /* Create initial dns cache */
345                 this->cache = new dnscache();
346         }
347
348         irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver);
349
350         /* Initialize mastersocket */
351         int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
352         this->SetFd(s);
353
354         /* Have we got a socket and is it nonblocking? */
355         if (this->GetFd() != -1)
356         {
357                 ServerInstance->SE->SetReuse(s);
358                 ServerInstance->SE->NonBlocking(s);
359                 irc::sockets::sockaddrs bindto;
360                 memset(&bindto, 0, sizeof(bindto));
361                 bindto.sa.sa_family = myserver.sa.sa_family;
362                 if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0)
363                 {
364                         /* Failed to bind */
365                         ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error binding dns socket - hostnames will NOT resolve");
366                         ServerInstance->SE->Shutdown(this, 2);
367                         ServerInstance->SE->Close(this);
368                         this->SetFd(-1);
369                 }
370                 else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
371                 {
372                         ServerInstance->Logs->Log("RESOLVER",SPARSE,"Internal error starting DNS - hostnames will NOT resolve.");
373                         ServerInstance->SE->Shutdown(this, 2);
374                         ServerInstance->SE->Close(this);
375                         this->SetFd(-1);
376                 }
377         }
378         else
379         {
380                 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error creating DNS socket - hostnames will NOT resolve");
381         }
382 }
383
384 /** Initialise the DNS UDP socket so that we can send requests */
385 DNS::DNS()
386 {
387         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
388         /* Clear the Resolver class table */
389         memset(Classes,0,sizeof(Classes));
390
391         /* Clear the requests class table */
392         memset(requests,0,sizeof(requests));
393
394         /* DNS::Rehash() sets this to a valid ptr
395          */
396         this->cache = NULL;
397
398         /* Again, DNS::Rehash() sets this to a
399          * valid value
400          */
401         this->SetFd(-1);
402
403         /* Actually read the settings
404          */
405         this->Rehash();
406
407         this->PruneTimer = new CacheTimer(this);
408
409         ServerInstance->Timers->AddTimer(this->PruneTimer);
410 }
411
412 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
413 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
414 {
415         short payloadpos = 0;
416         const char* tempchr, *tempchr2 = name;
417         unsigned short length;
418
419         /* split name up into labels, create query */
420         while ((tempchr = strchr(tempchr2,'.')) != NULL)
421         {
422                 length = tempchr - tempchr2;
423                 if (payloadpos + length + 1 > 507)
424                         return -1;
425                 payload[payloadpos++] = length;
426                 memcpy(&payload[payloadpos],tempchr2,length);
427                 payloadpos += length;
428                 tempchr2 = &tempchr[1];
429         }
430         length = strlen(tempchr2);
431         if (length)
432         {
433                 if (payloadpos + length + 2 > 507)
434                         return -1;
435                 payload[payloadpos++] = length;
436                 memcpy(&payload[payloadpos],tempchr2,length);
437                 payloadpos += length;
438                 payload[payloadpos++] = 0;
439         }
440         if (payloadpos > 508)
441                 return -1;
442         length = htons(rr);
443         memcpy(&payload[payloadpos],&length,2);
444         length = htons(rr_class);
445         memcpy(&payload[payloadpos + 2],&length,2);
446         return payloadpos + 4;
447 }
448
449 /** Start lookup of an hostname to an IP address */
450 int DNS::GetIP(const char *name)
451 {
452         DNSHeader h;
453         int id;
454         int length;
455
456         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
457                 return -1;
458
459         DNSRequest* req = this->AddQuery(&h, id, name);
460
461         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
462                 return -1;
463
464         return id;
465 }
466
467 /** Start lookup of an hostname to an IPv6 address */
468 int DNS::GetIP6(const char *name)
469 {
470         DNSHeader h;
471         int id;
472         int length;
473
474         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
475                 return -1;
476
477         DNSRequest* req = this->AddQuery(&h, id, name);
478
479         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
480                 return -1;
481
482         return id;
483 }
484
485 /** Start lookup of a cname to another name */
486 int DNS::GetCName(const char *alias)
487 {
488         DNSHeader h;
489         int id;
490         int length;
491
492         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
493                 return -1;
494
495         DNSRequest* req = this->AddQuery(&h, id, alias);
496
497         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
498                 return -1;
499
500         return id;
501 }
502
503 /** Start lookup of an IP address to a hostname */
504 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
505 {
506         char query[128];
507         DNSHeader h;
508         int id;
509         int length;
510
511         if (fp == PROTOCOL_IPV6)
512         {
513                 in6_addr i;
514                 if (inet_pton(AF_INET6, ip, &i) > 0)
515                 {
516                         DNS::MakeIP6Int(query, &i);
517                 }
518                 else
519                 {
520                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip);
521                         /* Invalid IP address */
522                         return -1;
523                 }
524         }
525         else
526         {
527                 in_addr i;
528                 if (inet_aton(ip, &i))
529                 {
530                         unsigned char* c = (unsigned char*)&i.s_addr;
531                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
532                 }
533                 else
534                 {
535                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip);
536                         /* Invalid IP address */
537                         return -1;
538                 }
539         }
540
541         length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload);
542         if (length == -1)
543         {
544                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query);
545                 return -1;
546         }
547
548         DNSRequest* req = this->AddQuery(&h, id, ip);
549
550         if (!req)
551         {
552                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't add query (resolver down?)");
553                 return -1;
554         }
555
556         if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1)
557         {
558                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't send (firewall?)");
559                 return -1;
560         }
561
562         return id;
563 }
564
565 /** Build an ipv6 reverse domain from an in6_addr
566  */
567 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
568 {
569         const char* hex = "0123456789abcdef";
570         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
571         {
572                 if (index % 2)
573                         /* low nibble */
574                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
575                 else
576                         /* high nibble */
577                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
578                 *query++ = '.'; /* Seperator */
579         }
580         strcpy(query,"ip6.arpa"); /* Suffix the string */
581 }
582
583 /** Return the next id which is ready, and the result attached to it */
584 DNSResult DNS::GetResult()
585 {
586         /* Fetch dns query response and decide where it belongs */
587         DNSHeader header;
588         DNSRequest *req;
589         unsigned char buffer[sizeof(DNSHeader)];
590         irc::sockets::sockaddrs from;
591         memset(&from, 0, sizeof(from));
592         socklen_t x = sizeof(from);
593
594         int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
595
596         /* Did we get the whole header? */
597         if (length < 12)
598         {
599                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"GetResult didn't get a full packet (len=%d)", length);
600                 /* Nope - something screwed up. */
601                 return DNSResult(-1,"",0,"");
602         }
603
604         /* Check wether the reply came from a different DNS
605          * server to the one we sent it to, or the source-port
606          * is not 53.
607          * A user could in theory still spoof dns packets anyway
608          * but this is less trivial than just sending garbage
609          * to the server, which is possible without this check.
610          *
611          * -- Thanks jilles for pointing this one out.
612          */
613         if (from != myserver)
614         {
615                 std::string server1 = from.str();
616                 std::string server2 = myserver.str();
617                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
618                         server1.c_str(), server2.c_str());
619                 return DNSResult(-1,"",0,"");
620         }
621
622         /* Put the read header info into a header class */
623         DNS::FillHeader(&header,buffer,length - 12);
624
625         /* Get the id of this request.
626          * Its a 16 bit value stored in two char's,
627          * so we use logic shifts to create the value.
628          */
629         unsigned long this_id = header.id[1] + (header.id[0] << 8);
630
631         /* Do we have a pending request matching this id? */
632         if (!requests[this_id])
633         {
634                 /* Somehow we got a DNS response for a request we never made... */
635                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id);
636                 return DNSResult(-1,"",0,"");
637         }
638         else
639         {
640                 /* Remove the query from the list of pending queries */
641                 req = requests[this_id];
642                 requests[this_id] = NULL;
643         }
644
645         /* Inform the DNSRequest class that it has a result to be read.
646          * When its finished it will return a DNSInfo which is a pair of
647          * unsigned char* resource record data, and an error message.
648          */
649         DNSInfo data = req->ResultIsReady(header, length);
650         std::string resultstr;
651
652         /* Check if we got a result, if we didnt, its an error */
653         if (data.first == NULL)
654         {
655                 /* An error.
656                  * Mask the ID with the value of ERROR_MASK, so that
657                  * the dns_deal_with_classes() function knows that its
658                  * an error response and needs to be treated uniquely.
659                  * Put the error message in the second field.
660                  */
661                 std::string ro = req->orig;
662                 delete req;
663                 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
664         }
665         else
666         {
667                 unsigned long ttl = req->ttl;
668                 char formatted[128];
669
670                 /* Forward lookups come back as binary data. We must format them into ascii */
671                 switch (req->type)
672                 {
673                         case DNS_QUERY_A:
674                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
675                                 resultstr = formatted;
676                         break;
677
678                         case DNS_QUERY_AAAA:
679                         {
680                                 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
681                                 char* c = strstr(formatted,":0:");
682                                 if (c != NULL)
683                                 {
684                                         memmove(c+1,c+2,strlen(c+2) + 1);
685                                         c += 2;
686                                         while (memcmp(c,"0:",2) == 0)
687                                                 memmove(c,c+2,strlen(c+2) + 1);
688                                         if (memcmp(c,"0",2) == 0)
689                                                 *c = 0;
690                                         if (memcmp(formatted,"0::",3) == 0)
691                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
692                                 }
693                                 resultstr = formatted;
694
695                                 /* Special case. Sending ::1 around between servers
696                                  * and to clients is dangerous, because the : on the
697                                  * start makes the client or server interpret the IP
698                                  * as the last parameter on the line with a value ":1".
699                                  */
700                                 if (*formatted == ':')
701                                         resultstr.insert(0, "0");
702                         }
703                         break;
704
705                         case DNS_QUERY_CNAME:
706                                 /* Identical handling to PTR */
707
708                         case DNS_QUERY_PTR:
709                                 /* Reverse lookups just come back as char* */
710                                 resultstr = std::string((const char*)data.first);
711                         break;
712
713                         default:
714                         break;
715                 }
716
717                 /* Build the reply with the id and hostname/ip in it */
718                 std::string ro = req->orig;
719                 DNSResult result = DNSResult(this_id,resultstr,ttl,ro,req->type);
720                 delete req;
721                 return result;
722         }
723 }
724
725 /** A result is ready, process it */
726 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
727 {
728         unsigned i = 0, o;
729         int q = 0;
730         int curanswer;
731         ResourceRecord rr;
732         unsigned short ptr;
733
734         /* This is just to keep _FORTIFY_SOURCE happy */
735         rr.type = DNS_QUERY_NONE;
736         rr.rdlength = 0;
737         rr.ttl = 1;     /* GCC is a whiney bastard -- see the XXX below. */
738         rr.rr_class = 0; /* Same for VC++ */
739
740         if (!(header.flags1 & FLAGS_MASK_QR))
741                 return std::make_pair((unsigned char*)NULL,"Not a query result");
742
743         if (header.flags1 & FLAGS_MASK_OPCODE)
744                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
745
746         if (header.flags2 & FLAGS_MASK_RCODE)
747                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
748
749         if (header.ancount < 1)
750                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
751
752         /* Subtract the length of the header from the length of the packet */
753         length -= 12;
754
755         while ((unsigned int)q < header.qdcount && i < length)
756         {
757                 if (header.payload[i] > 63)
758                 {
759                         i += 6;
760                         q++;
761                 }
762                 else
763                 {
764                         if (header.payload[i] == 0)
765                         {
766                                 q++;
767                                 i += 5;
768                         }
769                         else i += header.payload[i] + 1;
770                 }
771         }
772         curanswer = 0;
773         while ((unsigned)curanswer < header.ancount)
774         {
775                 q = 0;
776                 while (q == 0 && i < length)
777                 {
778                         if (header.payload[i] > 63)
779                         {
780                                 i += 2;
781                                 q = 1;
782                         }
783                         else
784                         {
785                                 if (header.payload[i] == 0)
786                                 {
787                                         i++;
788                                         q = 1;
789                                 }
790                                 else i += header.payload[i] + 1; /* skip length and label */
791                         }
792                 }
793                 if (static_cast<int>(length - i) < 10)
794                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
795
796                 /* XXX: We actually initialise 'rr' here including its ttl field */
797                 DNS::FillResourceRecord(&rr,&header.payload[i]);
798
799                 i += 10;
800                 ServerInstance->Logs->Log("RESOLVER",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);
801                 if (rr.type != this->type)
802                 {
803                         curanswer++;
804                         i += rr.rdlength;
805                         continue;
806                 }
807                 if (rr.rr_class != this->rr_class)
808                 {
809                         curanswer++;
810                         i += rr.rdlength;
811                         continue;
812                 }
813                 break;
814         }
815         if ((unsigned int)curanswer == header.ancount)
816                 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
817
818         if (i + rr.rdlength > (unsigned int)length)
819                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
820
821         if (rr.rdlength > 1023)
822                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
823
824         this->ttl = rr.ttl;
825
826         switch (rr.type)
827         {
828                 /*
829                  * CNAME and PTR are compressed.  We need to decompress them.
830                  */
831                 case DNS_QUERY_CNAME:
832                 case DNS_QUERY_PTR:
833                 {
834                         unsigned short lowest_pos = length;
835                         o = 0;
836                         q = 0;
837                         while (q == 0 && i < length && o + 256 < 1023)
838                         {
839                                 /* DN label found (byte over 63) */
840                                 if (header.payload[i] > 63)
841                                 {
842                                         memcpy(&ptr,&header.payload[i],2);
843
844                                         i = ntohs(ptr);
845
846                                         /* check that highest two bits are set. if not, we've been had */
847                                         if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK)
848                                                 return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
849
850                                         /* mask away the two highest bits. */
851                                         i &= ~DN_COMP_BITMASK;
852
853                                         /* and decrease length by 12 bytes. */
854                                         i -= 12;
855
856                                         if (i >= lowest_pos)
857                                                 return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer");
858                                         lowest_pos = i;
859                                 }
860                                 else
861                                 {
862                                         if (header.payload[i] == 0)
863                                         {
864                                                 q = 1;
865                                         }
866                                         else
867                                         {
868                                                 res[o] = 0;
869                                                 if (o != 0)
870                                                         res[o++] = '.';
871
872                                                 if (o + header.payload[i] > sizeof(DNSHeader))
873                                                         return std::make_pair((unsigned char *) NULL, "DN label decompression is impossible -- malformed/hostile packet?");
874
875                                                 memcpy(&res[o], &header.payload[i + 1], header.payload[i]);
876                                                 o += header.payload[i];
877                                                 i += header.payload[i] + 1;
878                                         }
879                                 }
880                         }
881                         res[o] = 0;
882                 }
883                 break;
884                 case DNS_QUERY_AAAA:
885                         if (rr.rdlength != sizeof(struct in6_addr))
886                                 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?");
887
888                         memcpy(res,&header.payload[i],rr.rdlength);
889                         res[rr.rdlength] = 0;
890                 break;
891                 case DNS_QUERY_A:
892                         if (rr.rdlength != sizeof(struct in_addr))
893                                 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?");
894
895                         memcpy(res,&header.payload[i],rr.rdlength);
896                         res[rr.rdlength] = 0;
897                 break;
898                 default:
899                         return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting");
900                 break;
901         }
902         return std::make_pair(res,"No error");
903 }
904
905 /** Close the master socket */
906 DNS::~DNS()
907 {
908         ServerInstance->SE->Shutdown(this, 2);
909         ServerInstance->SE->Close(this);
910         ServerInstance->Timers->DelTimer(this->PruneTimer);
911         if (cache)
912                 delete cache;
913 }
914
915 CachedQuery* DNS::GetCache(const std::string &source)
916 {
917         dnscache::iterator x = cache->find(source.c_str());
918         if (x != cache->end())
919                 return &(x->second);
920         else
921                 return NULL;
922 }
923
924 void DNS::DelCache(const std::string &source)
925 {
926         cache->erase(source.c_str());
927 }
928
929 void Resolver::TriggerCachedResult()
930 {
931         if (CQ)
932                 OnLookupComplete(CQ->data, time_left, true);
933 }
934
935 /** High level abstraction of dns used by application at large */
936 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
937 {
938         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
939         cached = false;
940
941         CQ = ServerInstance->Res->GetCache(source);
942         if (CQ)
943         {
944                 time_left = CQ->CalcTTLRemaining();
945                 if (!time_left)
946                 {
947                         ServerInstance->Res->DelCache(source);
948                 }
949                 else if (CQ->type == qt)
950                 {
951                         cached = true;
952                         return;
953                 }
954                 CQ = NULL;
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",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",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",DEBUG,"Handle DNS event");
1026
1027         res = this->GetResult();
1028
1029         ServerInstance->Logs->Log("RESOLVER",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.type, 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",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 }