]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
bede73a6fada8736bc5fa94f01de32cf27789e8a
[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         do {
262                 id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
263         } while (requests[id]);
264
265         DNSRequest* req = new DNSRequest(this, id, original);
266
267         header->id[0] = req->id[0] = id >> 8;
268         header->id[1] = req->id[1] = id & 0xFF;
269         header->flags1 = FLAGS_MASK_RD;
270         header->flags2 = 0;
271         header->qdcount = 1;
272         header->ancount = 0;
273         header->nscount = 0;
274         header->arcount = 0;
275
276         /* At this point we already know the id doesnt exist,
277          * so there needs to be no second check for the ::end()
278          */
279         requests[id] = req;
280
281         /* According to the C++ spec, new never returns NULL. */
282         return req;
283 }
284
285 int DNS::ClearCache()
286 {
287         /* This ensures the buckets are reset to sane levels */
288         int rv = this->cache->size();
289         delete this->cache;
290         this->cache = new dnscache();
291         return rv;
292 }
293
294 int DNS::PruneCache()
295 {
296         int n = 0;
297         dnscache* newcache = new dnscache();
298         for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
299                 /* Dont include expired items (theres no point) */
300                 if (i->second.CalcTTLRemaining())
301                         newcache->insert(*i);
302                 else
303                         n++;
304
305         delete this->cache;
306         this->cache = newcache;
307         return n;
308 }
309
310 void DNS::Rehash()
311 {
312         if (this->GetFd() > -1)
313         {
314                 ServerInstance->SE->DelFd(this);
315                 ServerInstance->SE->Shutdown(this, 2);
316                 ServerInstance->SE->Close(this);
317                 this->SetFd(-1);
318
319                 /* Rehash the cache */
320                 this->PruneCache();
321         }
322         else
323         {
324                 /* Create initial dns cache */
325                 this->cache = new dnscache();
326         }
327
328         irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver);
329
330         /* Initialize mastersocket */
331         int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
332         this->SetFd(s);
333
334         /* Have we got a socket and is it nonblocking? */
335         if (this->GetFd() != -1)
336         {
337                 ServerInstance->SE->SetReuse(s);
338                 ServerInstance->SE->NonBlocking(s);
339                 irc::sockets::sockaddrs bindto;
340                 memset(&bindto, 0, sizeof(bindto));
341                 bindto.sa.sa_family = myserver.sa.sa_family;
342                 if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0)
343                 {
344                         /* Failed to bind */
345                         ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error binding dns socket - hostnames will NOT resolve");
346                         ServerInstance->SE->Shutdown(this, 2);
347                         ServerInstance->SE->Close(this);
348                         this->SetFd(-1);
349                 }
350                 else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
351                 {
352                         ServerInstance->Logs->Log("RESOLVER",SPARSE,"Internal error starting DNS - hostnames will NOT resolve.");
353                         ServerInstance->SE->Shutdown(this, 2);
354                         ServerInstance->SE->Close(this);
355                         this->SetFd(-1);
356                 }
357         }
358         else
359         {
360                 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error creating DNS socket - hostnames will NOT resolve");
361         }
362 }
363
364 /** Initialise the DNS UDP socket so that we can send requests */
365 DNS::DNS()
366 {
367         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
368         /* Clear the Resolver class table */
369         memset(Classes,0,sizeof(Classes));
370
371         /* Clear the requests class table */
372         memset(requests,0,sizeof(requests));
373
374         /* DNS::Rehash() sets this to a valid ptr
375          */
376         this->cache = NULL;
377
378         /* Again, DNS::Rehash() sets this to a
379          * valid value
380          */
381         this->SetFd(-1);
382
383         /* Actually read the settings
384          */
385         this->Rehash();
386
387         this->PruneTimer = new CacheTimer(this);
388
389         ServerInstance->Timers->AddTimer(this->PruneTimer);
390 }
391
392 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
393 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
394 {
395         short payloadpos = 0;
396         const char* tempchr, *tempchr2 = name;
397         unsigned short length;
398
399         /* split name up into labels, create query */
400         while ((tempchr = strchr(tempchr2,'.')) != NULL)
401         {
402                 length = tempchr - tempchr2;
403                 if (payloadpos + length + 1 > 507)
404                         return -1;
405                 payload[payloadpos++] = length;
406                 memcpy(&payload[payloadpos],tempchr2,length);
407                 payloadpos += length;
408                 tempchr2 = &tempchr[1];
409         }
410         length = strlen(tempchr2);
411         if (length)
412         {
413                 if (payloadpos + length + 2 > 507)
414                         return -1;
415                 payload[payloadpos++] = length;
416                 memcpy(&payload[payloadpos],tempchr2,length);
417                 payloadpos += length;
418                 payload[payloadpos++] = 0;
419         }
420         if (payloadpos > 508)
421                 return -1;
422         length = htons(rr);
423         memcpy(&payload[payloadpos],&length,2);
424         length = htons(rr_class);
425         memcpy(&payload[payloadpos + 2],&length,2);
426         return payloadpos + 4;
427 }
428
429 /** Start lookup of an hostname to an IP address */
430 int DNS::GetIP(const char *name)
431 {
432         DNSHeader h;
433         int id;
434         int length;
435
436         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
437                 return -1;
438
439         DNSRequest* req = this->AddQuery(&h, id, name);
440
441         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
442                 return -1;
443
444         return id;
445 }
446
447 /** Start lookup of an hostname to an IPv6 address */
448 int DNS::GetIP6(const char *name)
449 {
450         DNSHeader h;
451         int id;
452         int length;
453
454         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
455                 return -1;
456
457         DNSRequest* req = this->AddQuery(&h, id, name);
458
459         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
460                 return -1;
461
462         return id;
463 }
464
465 /** Start lookup of a cname to another name */
466 int DNS::GetCName(const char *alias)
467 {
468         DNSHeader h;
469         int id;
470         int length;
471
472         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
473                 return -1;
474
475         DNSRequest* req = this->AddQuery(&h, id, alias);
476
477         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
478                 return -1;
479
480         return id;
481 }
482
483 /** Start lookup of an IP address to a hostname */
484 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
485 {
486         char query[128];
487         DNSHeader h;
488         int id;
489         int length;
490
491         if (fp == PROTOCOL_IPV6)
492         {
493                 in6_addr i;
494                 if (inet_pton(AF_INET6, ip, &i) > 0)
495                 {
496                         DNS::MakeIP6Int(query, &i);
497                 }
498                 else
499                 {
500                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip);
501                         /* Invalid IP address */
502                         return -1;
503                 }
504         }
505         else
506         {
507                 in_addr i;
508                 if (inet_aton(ip, &i))
509                 {
510                         unsigned char* c = (unsigned char*)&i.s_addr;
511                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
512                 }
513                 else
514                 {
515                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip);
516                         /* Invalid IP address */
517                         return -1;
518                 }
519         }
520
521         length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload);
522         if (length == -1)
523         {
524                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query);
525                 return -1;
526         }
527
528         DNSRequest* req = this->AddQuery(&h, id, ip);
529
530         if (!req)
531         {
532                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't add query (resolver down?)");
533                 return -1;
534         }
535
536         if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1)
537         {
538                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't send (firewall?)");
539                 return -1;
540         }
541
542         return id;
543 }
544
545 /** Build an ipv6 reverse domain from an in6_addr
546  */
547 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
548 {
549         const char* hex = "0123456789abcdef";
550         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
551         {
552                 if (index % 2)
553                         /* low nibble */
554                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
555                 else
556                         /* high nibble */
557                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
558                 *query++ = '.'; /* Seperator */
559         }
560         strcpy(query,"ip6.arpa"); /* Suffix the string */
561 }
562
563 /** Return the next id which is ready, and the result attached to it */
564 DNSResult DNS::GetResult()
565 {
566         /* Fetch dns query response and decide where it belongs */
567         DNSHeader header;
568         DNSRequest *req;
569         unsigned char buffer[sizeof(DNSHeader)];
570         irc::sockets::sockaddrs from;
571         memset(&from, 0, sizeof(from));
572         socklen_t x = sizeof(from);
573
574         int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
575
576         /* Did we get the whole header? */
577         if (length < 12)
578         {
579                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"GetResult didn't get a full packet (len=%d)", length);
580                 /* Nope - something screwed up. */
581                 return DNSResult(-1,"",0,"");
582         }
583
584         /* Check wether the reply came from a different DNS
585          * server to the one we sent it to, or the source-port
586          * is not 53.
587          * A user could in theory still spoof dns packets anyway
588          * but this is less trivial than just sending garbage
589          * to the server, which is possible without this check.
590          *
591          * -- Thanks jilles for pointing this one out.
592          */
593         if (from != myserver)
594         {
595                 std::string server1 = from.str();
596                 std::string server2 = myserver.str();
597                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
598                         server1.c_str(), server2.c_str());
599                 return DNSResult(-1,"",0,"");
600         }
601
602         /* Put the read header info into a header class */
603         DNS::FillHeader(&header,buffer,length - 12);
604
605         /* Get the id of this request.
606          * Its a 16 bit value stored in two char's,
607          * so we use logic shifts to create the value.
608          */
609         unsigned long this_id = header.id[1] + (header.id[0] << 8);
610
611         /* Do we have a pending request matching this id? */
612         if (!requests[this_id])
613         {
614                 /* Somehow we got a DNS response for a request we never made... */
615                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id);
616                 return DNSResult(-1,"",0,"");
617         }
618         else
619         {
620                 /* Remove the query from the list of pending queries */
621                 req = requests[this_id];
622                 requests[this_id] = NULL;
623         }
624
625         /* Inform the DNSRequest class that it has a result to be read.
626          * When its finished it will return a DNSInfo which is a pair of
627          * unsigned char* resource record data, and an error message.
628          */
629         DNSInfo data = req->ResultIsReady(header, length);
630         std::string resultstr;
631
632         /* Check if we got a result, if we didnt, its an error */
633         if (data.first == NULL)
634         {
635                 /* An error.
636                  * Mask the ID with the value of ERROR_MASK, so that
637                  * the dns_deal_with_classes() function knows that its
638                  * an error response and needs to be treated uniquely.
639                  * Put the error message in the second field.
640                  */
641                 std::string ro = req->orig;
642                 delete req;
643                 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
644         }
645         else
646         {
647                 unsigned long ttl = req->ttl;
648                 char formatted[128];
649
650                 /* Forward lookups come back as binary data. We must format them into ascii */
651                 switch (req->type)
652                 {
653                         case DNS_QUERY_A:
654                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
655                                 resultstr = formatted;
656                         break;
657
658                         case DNS_QUERY_AAAA:
659                         {
660                                 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
661                                 char* c = strstr(formatted,":0:");
662                                 if (c != NULL)
663                                 {
664                                         memmove(c+1,c+2,strlen(c+2) + 1);
665                                         c += 2;
666                                         while (memcmp(c,"0:",2) == 0)
667                                                 memmove(c,c+2,strlen(c+2) + 1);
668                                         if (memcmp(c,"0",2) == 0)
669                                                 *c = 0;
670                                         if (memcmp(formatted,"0::",3) == 0)
671                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
672                                 }
673                                 resultstr = formatted;
674
675                                 /* Special case. Sending ::1 around between servers
676                                  * and to clients is dangerous, because the : on the
677                                  * start makes the client or server interpret the IP
678                                  * as the last parameter on the line with a value ":1".
679                                  */
680                                 if (*formatted == ':')
681                                         resultstr.insert(0, "0");
682                         }
683                         break;
684
685                         case DNS_QUERY_CNAME:
686                                 /* Identical handling to PTR */
687
688                         case DNS_QUERY_PTR:
689                                 /* Reverse lookups just come back as char* */
690                                 resultstr = std::string((const char*)data.first);
691                         break;
692
693                         default:
694                         break;
695                 }
696
697                 /* Build the reply with the id and hostname/ip in it */
698                 std::string ro = req->orig;
699                 delete req;
700                 return DNSResult(this_id,resultstr,ttl,ro);
701         }
702 }
703
704 /** A result is ready, process it */
705 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
706 {
707         unsigned i = 0, o;
708         int q = 0;
709         int curanswer;
710         ResourceRecord rr;
711         unsigned short ptr;
712
713         /* This is just to keep _FORTIFY_SOURCE happy */
714         rr.type = DNS_QUERY_NONE;
715         rr.rdlength = 0;
716         rr.ttl = 1;     /* GCC is a whiney bastard -- see the XXX below. */
717         rr.rr_class = 0; /* Same for VC++ */
718
719         if (!(header.flags1 & FLAGS_MASK_QR))
720                 return std::make_pair((unsigned char*)NULL,"Not a query result");
721
722         if (header.flags1 & FLAGS_MASK_OPCODE)
723                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
724
725         if (header.flags2 & FLAGS_MASK_RCODE)
726                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
727
728         if (header.ancount < 1)
729                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
730
731         /* Subtract the length of the header from the length of the packet */
732         length -= 12;
733
734         while ((unsigned int)q < header.qdcount && i < length)
735         {
736                 if (header.payload[i] > 63)
737                 {
738                         i += 6;
739                         q++;
740                 }
741                 else
742                 {
743                         if (header.payload[i] == 0)
744                         {
745                                 q++;
746                                 i += 5;
747                         }
748                         else i += header.payload[i] + 1;
749                 }
750         }
751         curanswer = 0;
752         while ((unsigned)curanswer < header.ancount)
753         {
754                 q = 0;
755                 while (q == 0 && i < length)
756                 {
757                         if (header.payload[i] > 63)
758                         {
759                                 i += 2;
760                                 q = 1;
761                         }
762                         else
763                         {
764                                 if (header.payload[i] == 0)
765                                 {
766                                         i++;
767                                         q = 1;
768                                 }
769                                 else i += header.payload[i] + 1; /* skip length and label */
770                         }
771                 }
772                 if (static_cast<int>(length - i) < 10)
773                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
774
775                 /* XXX: We actually initialise 'rr' here including its ttl field */
776                 DNS::FillResourceRecord(&rr,&header.payload[i]);
777
778                 i += 10;
779                 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);
780                 if (rr.type != this->type)
781                 {
782                         curanswer++;
783                         i += rr.rdlength;
784                         continue;
785                 }
786                 if (rr.rr_class != this->rr_class)
787                 {
788                         curanswer++;
789                         i += rr.rdlength;
790                         continue;
791                 }
792                 break;
793         }
794         if ((unsigned int)curanswer == header.ancount)
795                 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
796
797         if (i + rr.rdlength > (unsigned int)length)
798                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
799
800         if (rr.rdlength > 1023)
801                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
802
803         this->ttl = rr.ttl;
804
805         switch (rr.type)
806         {
807                 /*
808                  * CNAME and PTR are compressed.  We need to decompress them.
809                  */
810                 case DNS_QUERY_CNAME:
811                 case DNS_QUERY_PTR:
812                 {
813                         unsigned short lowest_pos = length;
814                         o = 0;
815                         q = 0;
816                         while (q == 0 && i < length && o + 256 < 1023)
817                         {
818                                 /* DN label found (byte over 63) */
819                                 if (header.payload[i] > 63)
820                                 {
821                                         memcpy(&ptr,&header.payload[i],2);
822
823                                         i = ntohs(ptr);
824
825                                         /* check that highest two bits are set. if not, we've been had */
826                                         if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK)
827                                                 return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
828
829                                         /* mask away the two highest bits. */
830                                         i &= ~DN_COMP_BITMASK;
831
832                                         /* and decrease length by 12 bytes. */
833                                         i -= 12;
834
835                                         if (i >= lowest_pos)
836                                                 return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer");
837                                         lowest_pos = i;
838                                 }
839                                 else
840                                 {
841                                         if (header.payload[i] == 0)
842                                         {
843                                                 q = 1;
844                                         }
845                                         else
846                                         {
847                                                 res[o] = 0;
848                                                 if (o != 0)
849                                                         res[o++] = '.';
850
851                                                 if (o + header.payload[i] > sizeof(DNSHeader))
852                                                         return std::make_pair((unsigned char *) NULL, "DN label decompression is impossible -- malformed/hostile packet?");
853
854                                                 memcpy(&res[o], &header.payload[i + 1], header.payload[i]);
855                                                 o += header.payload[i];
856                                                 i += header.payload[i] + 1;
857                                         }
858                                 }
859                         }
860                         res[o] = 0;
861                 }
862                 break;
863                 case DNS_QUERY_AAAA:
864                         if (rr.rdlength != sizeof(struct in6_addr))
865                                 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?");
866
867                         memcpy(res,&header.payload[i],rr.rdlength);
868                         res[rr.rdlength] = 0;
869                 break;
870                 case DNS_QUERY_A:
871                         if (rr.rdlength != sizeof(struct in_addr))
872                                 return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?");
873
874                         memcpy(res,&header.payload[i],rr.rdlength);
875                         res[rr.rdlength] = 0;
876                 break;
877                 default:
878                         return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting");
879                 break;
880         }
881         return std::make_pair(res,"No error");
882 }
883
884 /** Close the master socket */
885 DNS::~DNS()
886 {
887         ServerInstance->SE->Shutdown(this, 2);
888         ServerInstance->SE->Close(this);
889         ServerInstance->Timers->DelTimer(this->PruneTimer);
890         if (cache)
891                 delete cache;
892 }
893
894 CachedQuery* DNS::GetCache(const std::string &source)
895 {
896         dnscache::iterator x = cache->find(source.c_str());
897         if (x != cache->end())
898                 return &(x->second);
899         else
900                 return NULL;
901 }
902
903 void DNS::DelCache(const std::string &source)
904 {
905         cache->erase(source.c_str());
906 }
907
908 void Resolver::TriggerCachedResult()
909 {
910         if (CQ)
911                 OnLookupComplete(CQ->data, time_left, true);
912 }
913
914 /** High level abstraction of dns used by application at large */
915 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
916 {
917         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
918         cached = false;
919
920         CQ = ServerInstance->Res->GetCache(source);
921         if (CQ)
922         {
923                 time_left = CQ->CalcTTLRemaining();
924                 if (!time_left)
925                 {
926                         ServerInstance->Res->DelCache(source);
927                 }
928                 else
929                 {
930                         cached = true;
931                         return;
932                 }
933         }
934
935         switch (querytype)
936         {
937                 case DNS_QUERY_A:
938                         this->myid = ServerInstance->Res->GetIP(source.c_str());
939                 break;
940
941                 case DNS_QUERY_PTR4:
942                         querytype = DNS_QUERY_PTR;
943                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
944                 break;
945
946                 case DNS_QUERY_PTR6:
947                         querytype = DNS_QUERY_PTR;
948                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
949                 break;
950
951                 case DNS_QUERY_AAAA:
952                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
953                 break;
954
955                 case DNS_QUERY_CNAME:
956                         this->myid = ServerInstance->Res->GetCName(source.c_str());
957                 break;
958
959                 default:
960                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request with unknown query type %d", querytype);
961                         this->myid = -1;
962                 break;
963         }
964         if (this->myid == -1)
965         {
966                 throw ModuleException("Resolver: Couldn't get an id to make a request");
967         }
968         else
969         {
970                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
971         }
972 }
973
974 /** Called when an error occurs */
975 void Resolver::OnError(ResolverError, const std::string&)
976 {
977         /* Nothing in here */
978 }
979
980 /** Destroy a resolver */
981 Resolver::~Resolver()
982 {
983         /* Nothing here (yet) either */
984 }
985
986 /** Get the request id associated with this class */
987 int Resolver::GetId()
988 {
989         return this->myid;
990 }
991
992 Module* Resolver::GetCreator()
993 {
994         return this->Creator;
995 }
996
997 /** Process a socket read event */
998 void DNS::HandleEvent(EventType, int)
999 {
1000         /* Fetch the id and result of the next available packet */
1001         DNSResult res(0,"",0,"");
1002         res.id = 0;
1003         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
1004
1005         res = this->GetResult();
1006
1007         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
1008
1009         /* Is there a usable request id? */
1010         if (res.id != -1)
1011         {
1012                 /* Its an error reply */
1013                 if (res.id & ERROR_MASK)
1014                 {
1015                         /* Mask off the error bit */
1016                         res.id -= ERROR_MASK;
1017                         /* Marshall the error to the correct class */
1018                         if (Classes[res.id])
1019                         {
1020                                 if (ServerInstance && ServerInstance->stats)
1021                                         ServerInstance->stats->statsDnsBad++;
1022                                 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1023                                 delete Classes[res.id];
1024                                 Classes[res.id] = NULL;
1025                         }
1026                         return;
1027                 }
1028                 else
1029                 {
1030                         /* It is a non-error result, marshall the result to the correct class */
1031                         if (Classes[res.id])
1032                         {
1033                                 if (ServerInstance && ServerInstance->stats)
1034                                         ServerInstance->stats->statsDnsGood++;
1035
1036                                 if (!this->GetCache(res.original.c_str()))
1037                                         this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1038
1039                                 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
1040                                 delete Classes[res.id];
1041                                 Classes[res.id] = NULL;
1042                         }
1043                 }
1044
1045                 if (ServerInstance && ServerInstance->stats)
1046                         ServerInstance->stats->statsDns++;
1047         }
1048 }
1049
1050 /** Add a derived Resolver to the working set */
1051 bool DNS::AddResolverClass(Resolver* r)
1052 {
1053         ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
1054         /* Check the pointers validity and the id's validity */
1055         if ((r) && (r->GetId() > -1))
1056         {
1057                 /* Check the slot isnt already occupied -
1058                  * This should NEVER happen unless we have
1059                  * a severely broken DNS server somewhere
1060                  */
1061                 if (!Classes[r->GetId()])
1062                 {
1063                         /* Set up the pointer to the class */
1064                         Classes[r->GetId()] = r;
1065                         return true;
1066                 }
1067         }
1068
1069         /* Pointer or id not valid, or duplicate id.
1070          * Free the item and return
1071          */
1072         delete r;
1073         return false;
1074 }
1075
1076 void DNS::CleanResolvers(Module* module)
1077 {
1078         for (int i = 0; i < MAX_REQUEST_ID; i++)
1079         {
1080                 if (Classes[i])
1081                 {
1082                         if (Classes[i]->GetCreator() == module)
1083                         {
1084                                 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");
1085                                 delete Classes[i];
1086                                 Classes[i] = NULL;
1087                         }
1088                 }
1089         }
1090 }