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