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