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