]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
Change channel name parameter of Module::OnUserPreJoin() and Channel::JoinUser()...
[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, unsigned int ttl) : data(res)
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                 delete req;
720                 return DNSResult(this_id,resultstr,ttl,ro);
721         }
722 }
723
724 /** A result is ready, process it */
725 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
726 {
727         unsigned i = 0, o;
728         int q = 0;
729         int curanswer;
730         ResourceRecord rr;
731         unsigned short ptr;
732
733         /* This is just to keep _FORTIFY_SOURCE happy */
734         rr.type = DNS_QUERY_NONE;
735         rr.rdlength = 0;
736         rr.ttl = 1;     /* GCC is a whiney bastard -- see the XXX below. */
737         rr.rr_class = 0; /* Same for VC++ */
738
739         if (!(header.flags1 & FLAGS_MASK_QR))
740                 return std::make_pair((unsigned char*)NULL,"Not a query result");
741
742         if (header.flags1 & FLAGS_MASK_OPCODE)
743                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
744
745         if (header.flags2 & FLAGS_MASK_RCODE)
746                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
747
748         if (header.ancount < 1)
749                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
750
751         /* Subtract the length of the header from the length of the packet */
752         length -= 12;
753
754         while ((unsigned int)q < header.qdcount && i < length)
755         {
756                 if (header.payload[i] > 63)
757                 {
758                         i += 6;
759                         q++;
760                 }
761                 else
762                 {
763                         if (header.payload[i] == 0)
764                         {
765                                 q++;
766                                 i += 5;
767                         }
768                         else i += header.payload[i] + 1;
769                 }
770         }
771         curanswer = 0;
772         while ((unsigned)curanswer < header.ancount)
773         {
774                 q = 0;
775                 while (q == 0 && i < length)
776                 {
777                         if (header.payload[i] > 63)
778                         {
779                                 i += 2;
780                                 q = 1;
781                         }
782                         else
783                         {
784                                 if (header.payload[i] == 0)
785                                 {
786                                         i++;
787                                         q = 1;
788                                 }
789                                 else i += header.payload[i] + 1; /* skip length and label */
790                         }
791                 }
792                 if (static_cast<int>(length - i) < 10)
793                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
794
795                 /* XXX: We actually initialise 'rr' here including its ttl field */
796                 DNS::FillResourceRecord(&rr,&header.payload[i]);
797
798                 i += 10;
799                 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);
800                 if (rr.type != this->type)
801                 {
802                         curanswer++;
803                         i += rr.rdlength;
804                         continue;
805                 }
806                 if (rr.rr_class != this->rr_class)
807                 {
808                         curanswer++;
809                         i += rr.rdlength;
810                         continue;
811                 }
812                 break;
813         }
814         if ((unsigned int)curanswer == header.ancount)
815                 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
816
817         if (i + rr.rdlength > (unsigned int)length)
818                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
819
820         if (rr.rdlength > 1023)
821                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
822
823         this->ttl = rr.ttl;
824
825         switch (rr.type)
826         {
827                 /*
828                  * CNAME and PTR are compressed.  We need to decompress them.
829                  */
830                 case DNS_QUERY_CNAME:
831                 case DNS_QUERY_PTR:
832                 {
833                         unsigned short lowest_pos = length;
834                         o = 0;
835                         q = 0;
836                         while (q == 0 && i < length && o + 256 < 1023)
837                         {
838                                 /* DN label found (byte over 63) */
839                                 if (header.payload[i] > 63)
840                                 {
841                                         memcpy(&ptr,&header.payload[i],2);
842
843                                         i = ntohs(ptr);
844
845                                         /* check that highest two bits are set. if not, we've been had */
846                                         if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK)
847                                                 return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
848
849                                         /* mask away the two highest bits. */
850                                         i &= ~DN_COMP_BITMASK;
851
852                                         /* and decrease length by 12 bytes. */
853                                         i -= 12;
854
855                                         if (i >= lowest_pos)
856                                                 return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer");
857                                         lowest_pos = i;
858                                 }
859                                 else
860                                 {
861                                         if (header.payload[i] == 0)
862                                         {
863                                                 q = 1;
864                                         }
865                                         else
866                                         {
867                                                 res[o] = 0;
868                                                 if (o != 0)
869                                                         res[o++] = '.';
870
871                                                 if (o + header.payload[i] > sizeof(DNSHeader))
872                                                         return std::make_pair((unsigned char *) NULL, "DN label decompression is impossible -- malformed/hostile packet?");
873
874                                                 memcpy(&res[o], &header.payload[i + 1], header.payload[i]);
875                                                 o += header.payload[i];
876                                                 i += header.payload[i] + 1;
877                                         }
878                                 }
879                         }
880                         res[o] = 0;
881                 }
882                 break;
883                 case DNS_QUERY_AAAA:
884                         if (rr.rdlength != sizeof(struct in6_addr))
885                                 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?");
886
887                         memcpy(res,&header.payload[i],rr.rdlength);
888                         res[rr.rdlength] = 0;
889                 break;
890                 case DNS_QUERY_A:
891                         if (rr.rdlength != sizeof(struct in_addr))
892                                 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?");
893
894                         memcpy(res,&header.payload[i],rr.rdlength);
895                         res[rr.rdlength] = 0;
896                 break;
897                 default:
898                         return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting");
899                 break;
900         }
901         return std::make_pair(res,"No error");
902 }
903
904 /** Close the master socket */
905 DNS::~DNS()
906 {
907         ServerInstance->SE->Shutdown(this, 2);
908         ServerInstance->SE->Close(this);
909         ServerInstance->Timers->DelTimer(this->PruneTimer);
910         if (cache)
911                 delete cache;
912 }
913
914 CachedQuery* DNS::GetCache(const std::string &source)
915 {
916         dnscache::iterator x = cache->find(source.c_str());
917         if (x != cache->end())
918                 return &(x->second);
919         else
920                 return NULL;
921 }
922
923 void DNS::DelCache(const std::string &source)
924 {
925         cache->erase(source.c_str());
926 }
927
928 void Resolver::TriggerCachedResult()
929 {
930         if (CQ)
931                 OnLookupComplete(CQ->data, time_left, true);
932 }
933
934 /** High level abstraction of dns used by application at large */
935 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
936 {
937         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
938         cached = false;
939
940         CQ = ServerInstance->Res->GetCache(source);
941         if (CQ)
942         {
943                 time_left = CQ->CalcTTLRemaining();
944                 if (!time_left)
945                 {
946                         ServerInstance->Res->DelCache(source);
947                 }
948                 else
949                 {
950                         cached = true;
951                         return;
952                 }
953         }
954
955         switch (querytype)
956         {
957                 case DNS_QUERY_A:
958                         this->myid = ServerInstance->Res->GetIP(source.c_str());
959                 break;
960
961                 case DNS_QUERY_PTR4:
962                         querytype = DNS_QUERY_PTR;
963                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
964                 break;
965
966                 case DNS_QUERY_PTR6:
967                         querytype = DNS_QUERY_PTR;
968                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
969                 break;
970
971                 case DNS_QUERY_AAAA:
972                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
973                 break;
974
975                 case DNS_QUERY_CNAME:
976                         this->myid = ServerInstance->Res->GetCName(source.c_str());
977                 break;
978
979                 default:
980                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request with unknown query type %d", querytype);
981                         this->myid = -1;
982                 break;
983         }
984         if (this->myid == -1)
985         {
986                 throw ModuleException("Resolver: Couldn't get an id to make a request");
987         }
988         else
989         {
990                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
991         }
992 }
993
994 /** Called when an error occurs */
995 void Resolver::OnError(ResolverError, const std::string&)
996 {
997         /* Nothing in here */
998 }
999
1000 /** Destroy a resolver */
1001 Resolver::~Resolver()
1002 {
1003         /* Nothing here (yet) either */
1004 }
1005
1006 /** Get the request id associated with this class */
1007 int Resolver::GetId()
1008 {
1009         return this->myid;
1010 }
1011
1012 Module* Resolver::GetCreator()
1013 {
1014         return this->Creator;
1015 }
1016
1017 /** Process a socket read event */
1018 void DNS::HandleEvent(EventType, int)
1019 {
1020         /* Fetch the id and result of the next available packet */
1021         DNSResult res(0,"",0,"");
1022         res.id = 0;
1023         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
1024
1025         res = this->GetResult();
1026
1027         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
1028
1029         /* Is there a usable request id? */
1030         if (res.id != -1)
1031         {
1032                 /* Its an error reply */
1033                 if (res.id & ERROR_MASK)
1034                 {
1035                         /* Mask off the error bit */
1036                         res.id -= ERROR_MASK;
1037                         /* Marshall the error to the correct class */
1038                         if (Classes[res.id])
1039                         {
1040                                 if (ServerInstance && ServerInstance->stats)
1041                                         ServerInstance->stats->statsDnsBad++;
1042                                 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1043                                 delete Classes[res.id];
1044                                 Classes[res.id] = NULL;
1045                         }
1046                         return;
1047                 }
1048                 else
1049                 {
1050                         /* It is a non-error result, marshall the result to the correct class */
1051                         if (Classes[res.id])
1052                         {
1053                                 if (ServerInstance && ServerInstance->stats)
1054                                         ServerInstance->stats->statsDnsGood++;
1055
1056                                 if (!this->GetCache(res.original.c_str()))
1057                                         this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1058
1059                                 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
1060                                 delete Classes[res.id];
1061                                 Classes[res.id] = NULL;
1062                         }
1063                 }
1064
1065                 if (ServerInstance && ServerInstance->stats)
1066                         ServerInstance->stats->statsDns++;
1067         }
1068 }
1069
1070 /** Add a derived Resolver to the working set */
1071 bool DNS::AddResolverClass(Resolver* r)
1072 {
1073         ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
1074         /* Check the pointers validity and the id's validity */
1075         if ((r) && (r->GetId() > -1))
1076         {
1077                 /* Check the slot isnt already occupied -
1078                  * This should NEVER happen unless we have
1079                  * a severely broken DNS server somewhere
1080                  */
1081                 if (!Classes[r->GetId()])
1082                 {
1083                         /* Set up the pointer to the class */
1084                         Classes[r->GetId()] = r;
1085                         return true;
1086                 }
1087         }
1088
1089         /* Pointer or id not valid, or duplicate id.
1090          * Free the item and return
1091          */
1092         delete r;
1093         return false;
1094 }
1095
1096 void DNS::CleanResolvers(Module* module)
1097 {
1098         for (int i = 0; i < MAX_REQUEST_ID; i++)
1099         {
1100                 if (Classes[i])
1101                 {
1102                         if (Classes[i]->GetCreator() == module)
1103                         {
1104                                 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");
1105                                 delete Classes[i];
1106                                 Classes[i] = NULL;
1107                         }
1108                 }
1109         }
1110 }