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