]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
abdd0a54cff586f20f81cf5acbc20af30019b48f
[user/henk/code/inspircd.git] / src / dns.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core */
15
16 /*
17 dns.cpp - Nonblocking DNS functions.
18 Very very loosely based on the firedns library,
19 Copyright (C) 2002 Ian Gulliver. This file is no
20 longer anything like firedns, there are many major
21 differences between this code and the original.
22 Please do not assume that firedns works like this,
23 looks like this, walks like this or tastes like this.
24 */
25
26 #ifndef WIN32
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <errno.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #else
33 #include "inspircd_win32wrapper.h"
34 #endif
35
36 #include "inspircd.h"
37 #include "socketengine.h"
38 #include "configreader.h"
39 #include "socket.h"
40
41 /** Masks to mask off the responses we get from the DNSRequest methods
42  */
43 enum QueryInfo
44 {
45         ERROR_MASK      = 0x10000       /* Result is an error */
46 };
47
48 /** Flags which can be ORed into a request or reply for different meanings
49  */
50 enum QueryFlags
51 {
52         FLAGS_MASK_RD           = 0x01, /* Recursive */
53         FLAGS_MASK_TC           = 0x02,
54         FLAGS_MASK_AA           = 0x04, /* Authoritative */
55         FLAGS_MASK_OPCODE       = 0x78,
56         FLAGS_MASK_QR           = 0x80,
57         FLAGS_MASK_RCODE        = 0x0F, /* Request */
58         FLAGS_MASK_Z            = 0x70,
59         FLAGS_MASK_RA           = 0x80
60 };
61
62
63 /** Represents a dns resource record (rr)
64  */
65 struct ResourceRecord
66 {
67         QueryType       type;           /* Record type */
68         unsigned int    rr_class;       /* Record class */
69         unsigned long   ttl;            /* Time to live */
70         unsigned int    rdlength;       /* Record length */
71 };
72
73 /** Represents a dns request/reply header, and its payload as opaque data.
74  */
75 class DNSHeader
76 {
77  public:
78         unsigned char   id[2];          /* Request id */
79         unsigned int    flags1;         /* Flags */
80         unsigned int    flags2;         /* Flags */
81         unsigned int    qdcount;
82         unsigned int    ancount;        /* Answer count */
83         unsigned int    nscount;        /* Nameserver count */
84         unsigned int    arcount;
85         unsigned char   payload[512];   /* Packet payload */
86 };
87
88 class DNSRequest
89 {
90  public:
91         unsigned char   id[2];          /* Request id */
92         unsigned char*  res;            /* Result processing buffer */
93         unsigned int    rr_class;       /* Request class */
94         QueryType       type;           /* Request type */
95         DNS*            dnsobj;         /* DNS caller (where we get our FD from) */
96         unsigned long   ttl;            /* Time to live */
97         std::string     orig;           /* Original requested name/ip */
98
99         DNSRequest(DNS* dns, int id, const std::string &original);
100         ~DNSRequest();
101         DNSInfo ResultIsReady(DNSHeader &h, int length);
102         int SendRequests(const DNSHeader *header, const int length, QueryType qt);
103 };
104
105 class CacheTimer : public Timer
106 {
107  private:
108         DNS* dns;
109  public:
110         CacheTimer(DNS* thisdns)
111                 : Timer(3600, ServerInstance->Time(), true), dns(thisdns) { }
112
113         virtual void Tick(time_t)
114         {
115                 dns->PruneCache();
116         }
117 };
118
119 class RequestTimeout : public Timer
120 {
121         DNSRequest* watch;
122         int watchid;
123  public:
124         RequestTimeout(unsigned long n, DNSRequest* watching, int id) : Timer(n, ServerInstance->Time()), watch(watching), watchid(id)
125         {
126         }
127         ~RequestTimeout()
128         {
129                 if (ServerInstance->Res)
130                         Tick(0);
131         }
132
133         void Tick(time_t)
134         {
135                 if (ServerInstance->Res->requests[watchid] == watch)
136                 {
137                         /* Still exists, whack it */
138                         if (ServerInstance->Res->Classes[watchid])
139                         {
140                                 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
141                                 delete ServerInstance->Res->Classes[watchid];
142                                 ServerInstance->Res->Classes[watchid] = NULL;
143                         }
144                         ServerInstance->Res->requests[watchid] = NULL;
145                         delete watch;
146                 }
147         }
148 };
149
150 CachedQuery::CachedQuery(const std::string &res, unsigned int ttl) : data(res)
151 {
152         expires = ServerInstance->Time() + ttl;
153 }
154
155 int CachedQuery::CalcTTLRemaining()
156 {
157         int n = expires - ServerInstance->Time();
158         return (n < 0 ? 0 : n);
159 }
160
161 /* Allocate the processing buffer */
162 DNSRequest::DNSRequest(DNS* dns, int rid, const std::string &original) : dnsobj(dns)
163 {
164         res = new unsigned char[512];
165         *res = 0;
166         orig = original;
167         RequestTimeout* RT = new RequestTimeout(ServerInstance->Config->dns_timeout ? ServerInstance->Config->dns_timeout : 5, this, rid);
168         ServerInstance->Timers->AddTimer(RT); /* The timer manager frees this */
169 }
170
171 /* Deallocate the processing buffer */
172 DNSRequest::~DNSRequest()
173 {
174         delete[] res;
175 }
176
177 /** Fill a ResourceRecord class based on raw data input */
178 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
179 {
180         rr->type = (QueryType)((input[0] << 8) + input[1]);
181         rr->rr_class = (input[2] << 8) + input[3];
182         rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
183         rr->rdlength = (input[8] << 8) + input[9];
184 }
185
186 /** Fill a DNSHeader class based on raw data input of a given length */
187 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
188 {
189         header->id[0] = input[0];
190         header->id[1] = input[1];
191         header->flags1 = input[2];
192         header->flags2 = input[3];
193         header->qdcount = (input[4] << 8) + input[5];
194         header->ancount = (input[6] << 8) + input[7];
195         header->nscount = (input[8] << 8) + input[9];
196         header->arcount = (input[10] << 8) + input[11];
197         memcpy(header->payload,&input[12],length);
198 }
199
200 /** Empty a DNSHeader class out into raw data, ready for transmission */
201 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
202 {
203         output[0] = header->id[0];
204         output[1] = header->id[1];
205         output[2] = header->flags1;
206         output[3] = header->flags2;
207         output[4] = header->qdcount >> 8;
208         output[5] = header->qdcount & 0xFF;
209         output[6] = header->ancount >> 8;
210         output[7] = header->ancount & 0xFF;
211         output[8] = header->nscount >> 8;
212         output[9] = header->nscount & 0xFF;
213         output[10] = header->arcount >> 8;
214         output[11] = header->arcount & 0xFF;
215         memcpy(&output[12],header->payload,length);
216 }
217
218 /** Send requests we have previously built down the UDP socket */
219 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
220 {
221         ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests");
222
223         unsigned char payload[sizeof(DNSHeader)];
224
225         this->rr_class = 1;
226         this->type = qt;
227
228         DNS::EmptyHeader(payload,header,length);
229
230         if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12)
231                 return -1;
232
233         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK");
234         return 0;
235 }
236
237 /** Add a query with a predefined header, and allocate an ID for it. */
238 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
239 {
240         /* Is the DNS connection down? */
241         if (this->GetFd() == -1)
242                 return NULL;
243
244         /* Create an id */
245         do {
246                 id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
247         } while (requests[id]);
248
249         DNSRequest* req = new DNSRequest(this, id, original);
250
251         header->id[0] = req->id[0] = id >> 8;
252         header->id[1] = req->id[1] = id & 0xFF;
253         header->flags1 = FLAGS_MASK_RD;
254         header->flags2 = 0;
255         header->qdcount = 1;
256         header->ancount = 0;
257         header->nscount = 0;
258         header->arcount = 0;
259
260         /* At this point we already know the id doesnt exist,
261          * so there needs to be no second check for the ::end()
262          */
263         requests[id] = req;
264
265         /* According to the C++ spec, new never returns NULL. */
266         return req;
267 }
268
269 int DNS::ClearCache()
270 {
271         /* This ensures the buckets are reset to sane levels */
272         int rv = this->cache->size();
273         delete this->cache;
274         this->cache = new dnscache();
275         return rv;
276 }
277
278 int DNS::PruneCache()
279 {
280         int n = 0;
281         dnscache* newcache = new dnscache();
282         for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
283                 /* Dont include expired items (theres no point) */
284                 if (i->second.CalcTTLRemaining())
285                         newcache->insert(*i);
286                 else
287                         n++;
288
289         delete this->cache;
290         this->cache = newcache;
291         return n;
292 }
293
294 void DNS::Rehash()
295 {
296         if (this->GetFd() > -1)
297         {
298                 ServerInstance->SE->DelFd(this);
299                 ServerInstance->SE->Shutdown(this, 2);
300                 ServerInstance->SE->Close(this);
301                 this->SetFd(-1);
302
303                 /* Rehash the cache */
304                 this->PruneCache();
305         }
306         else
307         {
308                 /* Create initial dns cache */
309                 this->cache = new dnscache();
310         }
311
312         irc::sockets::aptosa(ServerInstance->Config->DNSServer, DNS::QUERY_PORT, myserver);
313
314         /* Initialize mastersocket */
315         int s = socket(myserver.sa.sa_family, SOCK_DGRAM, 0);
316         this->SetFd(s);
317
318         /* Have we got a socket and is it nonblocking? */
319         if (this->GetFd() != -1)
320         {
321                 ServerInstance->SE->SetReuse(s);
322                 ServerInstance->SE->NonBlocking(s);
323                 irc::sockets::sockaddrs bindto;
324                 memset(&bindto, 0, sizeof(bindto));
325                 bindto.sa.sa_family = myserver.sa.sa_family;
326                 if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0)
327                 {
328                         /* Failed to bind */
329                         ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error binding dns socket - hostnames will NOT resolve");
330                         ServerInstance->SE->Shutdown(this, 2);
331                         ServerInstance->SE->Close(this);
332                         this->SetFd(-1);
333                 }
334                 else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE))
335                 {
336                         ServerInstance->Logs->Log("RESOLVER",SPARSE,"Internal error starting DNS - hostnames will NOT resolve.");
337                         ServerInstance->SE->Shutdown(this, 2);
338                         ServerInstance->SE->Close(this);
339                         this->SetFd(-1);
340                 }
341         }
342         else
343         {
344                 ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error creating DNS socket - hostnames will NOT resolve");
345         }
346 }
347
348 /** Initialise the DNS UDP socket so that we can send requests */
349 DNS::DNS()
350 {
351         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS");
352         /* Clear the Resolver class table */
353         memset(Classes,0,sizeof(Classes));
354
355         /* Clear the requests class table */
356         memset(requests,0,sizeof(requests));
357
358         /* Set the id of the next request to 0
359          */
360         currid = 0;
361
362         /* DNS::Rehash() sets this to a valid ptr
363          */
364         this->cache = NULL;
365
366         /* Again, DNS::Rehash() sets this to a
367          * valid value
368          */
369         this->SetFd(-1);
370
371         /* Actually read the settings
372          */
373         this->Rehash();
374
375         this->PruneTimer = new CacheTimer(this);
376
377         ServerInstance->Timers->AddTimer(this->PruneTimer);
378 }
379
380 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
381 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
382 {
383         short payloadpos = 0;
384         const char* tempchr, *tempchr2 = name;
385         unsigned short length;
386
387         /* split name up into labels, create query */
388         while ((tempchr = strchr(tempchr2,'.')) != NULL)
389         {
390                 length = tempchr - tempchr2;
391                 if (payloadpos + length + 1 > 507)
392                         return -1;
393                 payload[payloadpos++] = length;
394                 memcpy(&payload[payloadpos],tempchr2,length);
395                 payloadpos += length;
396                 tempchr2 = &tempchr[1];
397         }
398         length = strlen(tempchr2);
399         if (length)
400         {
401                 if (payloadpos + length + 2 > 507)
402                         return -1;
403                 payload[payloadpos++] = length;
404                 memcpy(&payload[payloadpos],tempchr2,length);
405                 payloadpos += length;
406                 payload[payloadpos++] = 0;
407         }
408         if (payloadpos > 508)
409                 return -1;
410         length = htons(rr);
411         memcpy(&payload[payloadpos],&length,2);
412         length = htons(rr_class);
413         memcpy(&payload[payloadpos + 2],&length,2);
414         return payloadpos + 4;
415 }
416
417 /** Start lookup of an hostname to an IP address */
418 int DNS::GetIP(const char *name)
419 {
420         DNSHeader h;
421         int id;
422         int length;
423
424         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
425                 return -1;
426
427         DNSRequest* req = this->AddQuery(&h, id, name);
428
429         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
430                 return -1;
431
432         return id;
433 }
434
435 /** Start lookup of an hostname to an IPv6 address */
436 int DNS::GetIP6(const char *name)
437 {
438         DNSHeader h;
439         int id;
440         int length;
441
442         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
443                 return -1;
444
445         DNSRequest* req = this->AddQuery(&h, id, name);
446
447         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
448                 return -1;
449
450         return id;
451 }
452
453 /** Start lookup of a cname to another name */
454 int DNS::GetCName(const char *alias)
455 {
456         DNSHeader h;
457         int id;
458         int length;
459
460         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
461                 return -1;
462
463         DNSRequest* req = this->AddQuery(&h, id, alias);
464
465         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
466                 return -1;
467
468         return id;
469 }
470
471 /** Start lookup of an IP address to a hostname */
472 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
473 {
474         char query[128];
475         DNSHeader h;
476         int id;
477         int length;
478
479         if (fp == PROTOCOL_IPV6)
480         {
481                 in6_addr i;
482                 if (inet_pton(AF_INET6, ip, &i) > 0)
483                 {
484                         DNS::MakeIP6Int(query, &i);
485                 }
486                 else
487                 {
488                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip);
489                         /* Invalid IP address */
490                         return -1;
491                 }
492         }
493         else
494         {
495                 in_addr i;
496                 if (inet_aton(ip, &i))
497                 {
498                         unsigned char* c = (unsigned char*)&i.s_addr;
499                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
500                 }
501                 else
502                 {
503                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip);
504                         /* Invalid IP address */
505                         return -1;
506                 }
507         }
508
509         length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload);
510         if (length == -1)
511         {
512                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query);
513                 return -1;
514         }
515
516         DNSRequest* req = this->AddQuery(&h, id, ip);
517
518         if (!req)
519         {
520                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't add query (resolver down?)");
521                 return -1;
522         }
523
524         if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1)
525         {
526                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't send (firewall?)");
527                 return -1;
528         }
529
530         return id;
531 }
532
533 /** Build an ipv6 reverse domain from an in6_addr
534  */
535 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
536 {
537         const char* hex = "0123456789abcdef";
538         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
539         {
540                 if (index % 2)
541                         /* low nibble */
542                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
543                 else
544                         /* high nibble */
545                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
546                 *query++ = '.'; /* Seperator */
547         }
548         strcpy(query,"ip6.arpa"); /* Suffix the string */
549 }
550
551 /** Return the next id which is ready, and the result attached to it */
552 DNSResult DNS::GetResult()
553 {
554         /* Fetch dns query response and decide where it belongs */
555         DNSHeader header;
556         DNSRequest *req;
557         unsigned char buffer[sizeof(DNSHeader)];
558         irc::sockets::sockaddrs from;
559         memset(&from, 0, sizeof(from));
560         socklen_t x = sizeof(from);
561
562         int length = ServerInstance->SE->RecvFrom(this, (char*)buffer, sizeof(DNSHeader), 0, &from.sa, &x);
563
564         /* Did we get the whole header? */
565         if (length < 12)
566         {
567                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"GetResult didn't get a full packet (len=%d)", length);
568                 /* Nope - something screwed up. */
569                 return DNSResult(-1,"",0,"");
570         }
571
572         /* Check wether the reply came from a different DNS
573          * server to the one we sent it to, or the source-port
574          * is not 53.
575          * A user could in theory still spoof dns packets anyway
576          * but this is less trivial than just sending garbage
577          * to the server, which is possible without this check.
578          *
579          * -- Thanks jilles for pointing this one out.
580          */
581         if (from != myserver)
582         {
583                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
584                         from.str().c_str(), myserver.str().c_str());
585                 return DNSResult(-1,"",0,"");
586         }
587
588         /* Put the read header info into a header class */
589         DNS::FillHeader(&header,buffer,length - 12);
590
591         /* Get the id of this request.
592          * Its a 16 bit value stored in two char's,
593          * so we use logic shifts to create the value.
594          */
595         unsigned long this_id = header.id[1] + (header.id[0] << 8);
596
597         /* Do we have a pending request matching this id? */
598         if (!requests[this_id])
599         {
600                 /* Somehow we got a DNS response for a request we never made... */
601                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id);
602                 return DNSResult(-1,"",0,"");
603         }
604         else
605         {
606                 /* Remove the query from the list of pending queries */
607                 req = requests[this_id];
608                 requests[this_id] = NULL;
609         }
610
611         /* Inform the DNSRequest class that it has a result to be read.
612          * When its finished it will return a DNSInfo which is a pair of
613          * unsigned char* resource record data, and an error message.
614          */
615         DNSInfo data = req->ResultIsReady(header, length);
616         std::string resultstr;
617
618         /* Check if we got a result, if we didnt, its an error */
619         if (data.first == NULL)
620         {
621                 /* An error.
622                  * Mask the ID with the value of ERROR_MASK, so that
623                  * the dns_deal_with_classes() function knows that its
624                  * an error response and needs to be treated uniquely.
625                  * Put the error message in the second field.
626                  */
627                 std::string ro = req->orig;
628                 delete req;
629                 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
630         }
631         else
632         {
633                 unsigned long ttl = req->ttl;
634                 char formatted[128];
635
636                 /* Forward lookups come back as binary data. We must format them into ascii */
637                 switch (req->type)
638                 {
639                         case DNS_QUERY_A:
640                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
641                                 resultstr = formatted;
642                         break;
643
644                         case DNS_QUERY_AAAA:
645                         {
646                                 inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
647                                 char* c = strstr(formatted,":0:");
648                                 if (c != NULL)
649                                 {
650                                         memmove(c+1,c+2,strlen(c+2) + 1);
651                                         c += 2;
652                                         while (memcmp(c,"0:",2) == 0)
653                                                 memmove(c,c+2,strlen(c+2) + 1);
654                                         if (memcmp(c,"0",2) == 0)
655                                                 *c = 0;
656                                         if (memcmp(formatted,"0::",3) == 0)
657                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
658                                 }
659                                 resultstr = formatted;
660
661                                 /* Special case. Sending ::1 around between servers
662                                  * and to clients is dangerous, because the : on the
663                                  * start makes the client or server interpret the IP
664                                  * as the last parameter on the line with a value ":1".
665                                  */
666                                 if (*formatted == ':')
667                                         resultstr.insert(0, "0");
668                         }
669                         break;
670
671                         case DNS_QUERY_CNAME:
672                                 /* Identical handling to PTR */
673
674                         case DNS_QUERY_PTR:
675                                 /* Reverse lookups just come back as char* */
676                                 resultstr = std::string((const char*)data.first);
677                         break;
678
679                         default:
680                         break;
681                 }
682
683                 /* Build the reply with the id and hostname/ip in it */
684                 std::string ro = req->orig;
685                 delete req;
686                 return DNSResult(this_id,resultstr,ttl,ro);
687         }
688 }
689
690 /** A result is ready, process it */
691 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
692 {
693         unsigned i = 0;
694         int q = 0;
695         int curanswer, o;
696         ResourceRecord rr;
697         unsigned short ptr;
698
699         /* This is just to keep _FORTIFY_SOURCE happy */
700         rr.type = DNS_QUERY_NONE;
701         rr.rdlength = 0;
702         rr.ttl = 1;     /* GCC is a whiney bastard -- see the XXX below. */
703         rr.rr_class = 0; /* Same for VC++ */
704
705         if (!(header.flags1 & FLAGS_MASK_QR))
706                 return std::make_pair((unsigned char*)NULL,"Not a query result");
707
708         if (header.flags1 & FLAGS_MASK_OPCODE)
709                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
710
711         if (header.flags2 & FLAGS_MASK_RCODE)
712                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
713
714         if (header.ancount < 1)
715                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
716
717         /* Subtract the length of the header from the length of the packet */
718         length -= 12;
719
720         while ((unsigned int)q < header.qdcount && i < length)
721         {
722                 if (header.payload[i] > 63)
723                 {
724                         i += 6;
725                         q++;
726                 }
727                 else
728                 {
729                         if (header.payload[i] == 0)
730                         {
731                                 q++;
732                                 i += 5;
733                         }
734                         else i += header.payload[i] + 1;
735                 }
736         }
737         curanswer = 0;
738         while ((unsigned)curanswer < header.ancount)
739         {
740                 q = 0;
741                 while (q == 0 && i < length)
742                 {
743                         if (header.payload[i] > 63)
744                         {
745                                 i += 2;
746                                 q = 1;
747                         }
748                         else
749                         {
750                                 if (header.payload[i] == 0)
751                                 {
752                                         i++;
753                                         q = 1;
754                                 }
755                                 else i += header.payload[i] + 1; /* skip length and label */
756                         }
757                 }
758                 if (length - i < 10)
759                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
760
761                 /* XXX: We actually initialise 'rr' here including its ttl field */
762                 DNS::FillResourceRecord(&rr,&header.payload[i]);
763
764                 i += 10;
765                 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);
766                 if (rr.type != this->type)
767                 {
768                         curanswer++;
769                         i += rr.rdlength;
770                         continue;
771                 }
772                 if (rr.rr_class != this->rr_class)
773                 {
774                         curanswer++;
775                         i += rr.rdlength;
776                         continue;
777                 }
778                 break;
779         }
780         if ((unsigned int)curanswer == header.ancount)
781                 return std::make_pair((unsigned char*)NULL,"No A, AAAA or PTR type answers (" + ConvToStr(header.ancount) + " answers)");
782
783         if (i + rr.rdlength > (unsigned int)length)
784                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
785
786         if (rr.rdlength > 1023)
787                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
788
789         this->ttl = rr.ttl;
790
791         switch (rr.type)
792         {
793                 case DNS_QUERY_CNAME:
794                         /* CNAME and PTR have the same processing code */
795                 case DNS_QUERY_PTR:
796                         o = 0;
797                         q = 0;
798                         while (q == 0 && i < length && o + 256 < 1023)
799                         {
800                                 if (header.payload[i] > 63)
801                                 {
802                                         memcpy(&ptr,&header.payload[i],2);
803                                         i = ntohs(ptr) - 0xC000 - 12;
804                                 }
805                                 else
806                                 {
807                                         if (header.payload[i] == 0)
808                                         {
809                                                 q = 1;
810                                         }
811                                         else
812                                         {
813                                                 res[o] = 0;
814                                                 if (o != 0)
815                                                         res[o++] = '.';
816                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
817                                                 o += header.payload[i];
818                                                 i += header.payload[i] + 1;
819                                         }
820                                 }
821                         }
822                         res[o] = 0;
823                 break;
824                 case DNS_QUERY_AAAA:
825                         memcpy(res,&header.payload[i],rr.rdlength);
826                         res[rr.rdlength] = 0;
827                 break;
828                 case DNS_QUERY_A:
829                         memcpy(res,&header.payload[i],rr.rdlength);
830                         res[rr.rdlength] = 0;
831                 break;
832                 default:
833                         memcpy(res,&header.payload[i],rr.rdlength);
834                         res[rr.rdlength] = 0;
835                 break;
836         }
837         return std::make_pair(res,"No error");
838 }
839
840 /** Close the master socket */
841 DNS::~DNS()
842 {
843         ServerInstance->SE->Shutdown(this, 2);
844         ServerInstance->SE->Close(this);
845         ServerInstance->Timers->DelTimer(this->PruneTimer);
846         if (cache)
847                 delete cache;
848 }
849
850 CachedQuery* DNS::GetCache(const std::string &source)
851 {
852         dnscache::iterator x = cache->find(source.c_str());
853         if (x != cache->end())
854                 return &(x->second);
855         else
856                 return NULL;
857 }
858
859 void DNS::DelCache(const std::string &source)
860 {
861         cache->erase(source.c_str());
862 }
863
864 void Resolver::TriggerCachedResult()
865 {
866         if (CQ)
867                 OnLookupComplete(CQ->data, time_left, true);
868 }
869
870 /** High level abstraction of dns used by application at large */
871 Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt)
872 {
873         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver");
874         cached = false;
875
876         CQ = ServerInstance->Res->GetCache(source);
877         if (CQ)
878         {
879                 time_left = CQ->CalcTTLRemaining();
880                 if (!time_left)
881                 {
882                         ServerInstance->Res->DelCache(source);
883                 }
884                 else
885                 {
886                         cached = true;
887                         return;
888                 }
889         }
890
891         switch (querytype)
892         {
893                 case DNS_QUERY_A:
894                         this->myid = ServerInstance->Res->GetIP(source.c_str());
895                 break;
896
897                 case DNS_QUERY_PTR4:
898                         querytype = DNS_QUERY_PTR;
899                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
900                 break;
901
902                 case DNS_QUERY_PTR6:
903                         querytype = DNS_QUERY_PTR;
904                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
905                 break;
906
907                 case DNS_QUERY_AAAA:
908                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
909                 break;
910
911                 case DNS_QUERY_CNAME:
912                         this->myid = ServerInstance->Res->GetCName(source.c_str());
913                 break;
914
915                 default:
916                         ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request with unknown query type %d", querytype);
917                         this->myid = -1;
918                 break;
919         }
920         if (this->myid == -1)
921         {
922                 throw ModuleException("Resolver: Couldn't get an id to make a request");
923         }
924         else
925         {
926                 ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid);
927         }
928 }
929
930 /** Called when an error occurs */
931 void Resolver::OnError(ResolverError, const std::string&)
932 {
933         /* Nothing in here */
934 }
935
936 /** Destroy a resolver */
937 Resolver::~Resolver()
938 {
939         /* Nothing here (yet) either */
940 }
941
942 /** Get the request id associated with this class */
943 int Resolver::GetId()
944 {
945         return this->myid;
946 }
947
948 Module* Resolver::GetCreator()
949 {
950         return this->Creator;
951 }
952
953 /** Process a socket read event */
954 void DNS::HandleEvent(EventType, int)
955 {
956         /* Fetch the id and result of the next available packet */
957         DNSResult res(0,"",0,"");
958         res.id = 0;
959         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event");
960
961         res = this->GetResult();
962
963         ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id);
964
965         /* Is there a usable request id? */
966         if (res.id != -1)
967         {
968                 /* Its an error reply */
969                 if (res.id & ERROR_MASK)
970                 {
971                         /* Mask off the error bit */
972                         res.id -= ERROR_MASK;
973                         /* Marshall the error to the correct class */
974                         if (Classes[res.id])
975                         {
976                                 if (ServerInstance && ServerInstance->stats)
977                                         ServerInstance->stats->statsDnsBad++;
978                                 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
979                                 delete Classes[res.id];
980                                 Classes[res.id] = NULL;
981                         }
982                         return;
983                 }
984                 else
985                 {
986                         /* It is a non-error result, marshall the result to the correct class */
987                         if (Classes[res.id])
988                         {
989                                 if (ServerInstance && ServerInstance->stats)
990                                         ServerInstance->stats->statsDnsGood++;
991
992                                 if (!this->GetCache(res.original.c_str()))
993                                         this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
994
995                                 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
996                                 delete Classes[res.id];
997                                 Classes[res.id] = NULL;
998                         }
999                 }
1000
1001                 if (ServerInstance && ServerInstance->stats)
1002                         ServerInstance->stats->statsDns++;
1003         }
1004 }
1005
1006 /** Add a derived Resolver to the working set */
1007 bool DNS::AddResolverClass(Resolver* r)
1008 {
1009         ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r);
1010         /* Check the pointers validity and the id's validity */
1011         if ((r) && (r->GetId() > -1))
1012         {
1013                 /* Check the slot isnt already occupied -
1014                  * This should NEVER happen unless we have
1015                  * a severely broken DNS server somewhere
1016                  */
1017                 if (!Classes[r->GetId()])
1018                 {
1019                         /* Set up the pointer to the class */
1020                         Classes[r->GetId()] = r;
1021                         return true;
1022                 }
1023                 else
1024                         /* Duplicate id */
1025                         return false;
1026         }
1027         else
1028         {
1029                 /* Pointer or id not valid.
1030                  * Free the item and return
1031                  */
1032                 if (r)
1033                         delete r;
1034
1035                 return false;
1036         }
1037 }
1038
1039 void DNS::CleanResolvers(Module* module)
1040 {
1041         for (int i = 0; i < MAX_REQUEST_ID; i++)
1042         {
1043                 if (Classes[i])
1044                 {
1045                         if (Classes[i]->GetCreator() == module)
1046                         {
1047                                 Classes[i]->OnError(RESOLVER_FORCEUNLOAD, "Parent module is unloading");
1048                                 delete Classes[i];
1049                                 Classes[i] = NULL;
1050                         }
1051                 }
1052         }
1053 }