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