]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
6d624c1811a6b697eba13027a482a6a7cba10501
[user/henk/code/inspircd.git] / src / dns.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                     E-mail:
7  *              <brain@chatspike.net>
8  *              <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *          the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 /*
18 dns.cpp - Nonblocking DNS functions.
19 Very very loosely based on the firedns library,
20 Copyright (C) 2002 Ian Gulliver. This file is no
21 longer anything like firedns, there are many major
22 differences between this code and the original.
23 Please do not assume that firedns works like this,
24 looks like this, walks like this or tastes like this.
25 */
26
27 using namespace std;
28
29 #include <string>
30 #include <time.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <map>
39 #include "dns.h"
40 #include "inspircd.h"
41 #include "helperfuncs.h"
42 #include "inspircd_config.h"
43 #include "socketengine.h"
44 #include "configreader.h"
45
46 /* We need these */
47 extern InspIRCd* ServerInstance;
48 extern ServerConfig* Config;
49
50 /* Master file descriptor */
51 int DNS::MasterSocket;
52
53 /* Masks to mask off the responses we get from the DNSRequest methods */
54 enum QueryInfo
55 {
56         ERROR_MASK      = 0x10000       /* Result is an error */
57 };
58
59 /* Flags which can be ORed into a request or reply for different meanings */
60 enum QueryFlags
61 {
62         FLAGS_MASK_RD           = 0x01, /* Recursive */
63         FLAGS_MASK_TC           = 0x02,
64         FLAGS_MASK_AA           = 0x04, /* Authoritative */
65         FLAGS_MASK_OPCODE       = 0x78,
66         FLAGS_MASK_QR           = 0x80,
67         FLAGS_MASK_RCODE        = 0x0F, /* Request */
68         FLAGS_MASK_Z            = 0x70,
69         FLAGS_MASK_RA           = 0x80
70 };
71
72
73 /* Represents a dns resource record (rr) */
74 class ResourceRecord
75 {
76  public:
77         QueryType       type;           /* Record type */
78         unsigned int    rr_class;       /* Record class */
79         unsigned long   ttl;            /* Time to live */
80         unsigned int    rdlength;       /* Record length */
81 };
82
83 /* Represents a dns request/reply header, and its payload as opaque data.
84  */
85 class DNSHeader
86 {
87  public:
88         unsigned char   id[2];          /* Request id */
89         unsigned int    flags1;         /* Flags */
90         unsigned int    flags2;         /* Flags */
91         unsigned int    qdcount;
92         unsigned int    ancount;        /* Answer count */
93         unsigned int    nscount;        /* Nameserver count */
94         unsigned int    arcount;
95         unsigned char   payload[512];   /* Packet payload */
96 };
97
98 /* Represents a request 'on the wire' with routing information relating to
99  * where to call when we get a result
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         insp_inaddr     myserver;       /* DNS server address*/
109
110         /* Allocate the processing buffer */
111         DNSRequest(insp_inaddr server)
112         {
113                 res = new unsigned char[512];
114                 *res = 0;
115                 memcpy(&myserver, &server, sizeof(insp_inaddr));
116         }
117
118         /* Deallocate the processing buffer */
119         ~DNSRequest()
120         {
121                 delete[] res;
122         }
123
124         /* Called when a result is ready to be processed which matches this id */
125         DNSInfo ResultIsReady(DNSHeader &h, int length);
126
127         /* Called when there are requests to be sent out */
128         int SendRequests(const DNSHeader *header, const int length, QueryType qt);
129 };
130
131 /* Fill a ResourceRecord class based on raw data input */
132 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
133 {
134         rr->type = (QueryType)((input[0] << 8) + input[1]);
135         rr->rr_class = (input[2] << 8) + input[3];
136         rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
137         rr->rdlength = (input[8] << 8) + input[9];
138 }
139
140 /* Fill a DNSHeader class based on raw data input of a given length */
141 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
142 {
143         header->id[0] = input[0];
144         header->id[1] = input[1];
145         header->flags1 = input[2];
146         header->flags2 = input[3];
147         header->qdcount = (input[4] << 8) + input[5];
148         header->ancount = (input[6] << 8) + input[7];
149         header->nscount = (input[8] << 8) + input[9];
150         header->arcount = (input[10] << 8) + input[11];
151         memcpy(header->payload,&input[12],length);
152 }
153
154 /* Empty a DNSHeader class out into raw data, ready for transmission */
155 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
156 {
157         output[0] = header->id[0];
158         output[1] = header->id[1];
159         output[2] = header->flags1;
160         output[3] = header->flags2;
161         output[4] = header->qdcount >> 8;
162         output[5] = header->qdcount & 0xFF;
163         output[6] = header->ancount >> 8;
164         output[7] = header->ancount & 0xFF;
165         output[8] = header->nscount >> 8;
166         output[9] = header->nscount & 0xFF;
167         output[10] = header->arcount >> 8;
168         output[11] = header->arcount & 0xFF;
169         memcpy(&output[12],header->payload,length);
170 }
171
172 /* Send requests we have previously built down the UDP socket */
173 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
174 {
175         insp_sockaddr addr;
176         unsigned char payload[sizeof(DNSHeader)];
177
178         this->rr_class = 1;
179         this->type = qt;
180                 
181         DNS::EmptyHeader(payload,header,length);
182
183         memset(&addr,0,sizeof(addr));
184 #ifdef IPV6
185         memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
186         addr.sin6_family = AF_FAMILY;
187         addr.sin6_port = htons(DNS::QUERY_PORT);
188 #else
189         memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
190         addr.sin_family = AF_FAMILY;
191         addr.sin_port = htons(DNS::QUERY_PORT);
192 #endif
193         if (sendto(DNS::GetMasterSocket(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
194         {
195                 log(DEBUG,"Error in sendto! (%s)",strerror(errno));
196                 return -1;
197         }
198
199         return 0;
200 }
201
202 /* Add a query with a predefined header, and allocate an ID for it. */
203 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
204 {
205         /* Are there already the max number of requests on the go? */
206         if (requests.size() == DNS::MAX_REQUEST_ID + 1)
207                 return NULL;
208         
209         /* Create an id */
210         id = this->PRNG() & DNS::MAX_REQUEST_ID;
211
212         /* If this id is already 'in flight', pick another. */
213         while (requests.find(id) != requests.end())
214                 id = this->PRNG() & DNS::MAX_REQUEST_ID;
215
216         DNSRequest* req = new DNSRequest(this->myserver);
217
218         header->id[0] = req->id[0] = id >> 8;
219         header->id[1] = req->id[1] = id & 0xFF;
220         header->flags1 = FLAGS_MASK_RD;
221         header->flags2 = 0;
222         header->qdcount = 1;
223         header->ancount = 0;
224         header->nscount = 0;
225         header->arcount = 0;
226
227         /* At this point we already know the id doesnt exist,
228          * so there needs to be no second check for the ::end()
229          */
230         requests[id] = req;
231
232         /* According to the C++ spec, new never returns NULL. */
233         return req;
234 }
235
236 int DNS::GetMasterSocket()
237 {
238         return MasterSocket;
239 }
240
241 /* Initialise the DNS UDP socket so that we can send requests */
242 DNS::DNS()
243 {
244         insp_inaddr addr;
245
246         /* Clear the Resolver class table */
247         memset(Classes,0,sizeof(Classes));
248
249         /* Set the id of the next request to 0
250          */
251         currid = 0;
252
253         /* Clear the namesever address */
254         memset(&myserver,0,sizeof(insp_inaddr));
255
256         /* Convert the nameserver address into an insp_inaddr */
257         if (insp_aton(Config->DNSServer,&addr) > 0)
258         {
259                 memcpy(&myserver,&addr,sizeof(insp_inaddr));
260                 log(DEBUG,"Added nameserver '%s'",Config->DNSServer);
261         }
262         else
263         {
264                 log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",Config->DNSServer);
265         }
266
267         /* Initialize mastersocket */
268         MasterSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
269         if (MasterSocket != -1)
270         {
271                 /* Did it succeed? */
272                 if (fcntl(MasterSocket, F_SETFL, O_NONBLOCK) != 0)
273                 {
274                         /* Couldn't make the socket nonblocking */
275                         shutdown(MasterSocket,2);
276                         close(MasterSocket);
277                         MasterSocket = -1;
278                 }
279         }
280         else
281         {
282                 log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
283         }
284         /* Have we got a socket and is it nonblocking? */
285         if (MasterSocket != -1)
286         {
287 #ifdef IPV6
288                 insp_sockaddr addr;
289                 memset(&addr,0,sizeof(addr));
290                 addr.sin6_family = AF_FAMILY;
291                 addr.sin6_port = 0;
292                 addr.sin6_addr = in6addr_any;
293 #else
294                 insp_sockaddr addr;
295                 memset(&addr,0,sizeof(addr));
296                 addr.sin_family = AF_FAMILY;
297                 addr.sin_port = 0;
298                 addr.sin_addr.s_addr = INADDR_ANY;
299 #endif
300                 /* Bind the port */
301                 if (bind(MasterSocket,(sockaddr *)&addr,sizeof(addr)) != 0)
302                 {
303                         /* Failed to bind */
304                         log(DEBUG,"Cant bind DNS::MasterSocket");
305                         shutdown(MasterSocket,2);
306                         close(MasterSocket);
307                         MasterSocket = -1;
308                 }
309
310                 if (MasterSocket >= 0)
311                 {
312                         log(DEBUG,"Add master socket %d",MasterSocket);
313                         /* Hook the descriptor into the socket engine */
314                         if (ServerInstance && ServerInstance->SE)
315                                 ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS);
316                 }
317         }
318 }
319
320 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
321 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
322 {
323         short payloadpos = 0;
324         const char* tempchr, *tempchr2 = name;
325         unsigned short length;
326
327         /* split name up into labels, create query */
328         while ((tempchr = strchr(tempchr2,'.')) != NULL)
329         {
330                 length = tempchr - tempchr2;
331                 if (payloadpos + length + 1 > 507)
332                         return -1;
333                 payload[payloadpos++] = length;
334                 memcpy(&payload[payloadpos],tempchr2,length);
335                 payloadpos += length;
336                 tempchr2 = &tempchr[1];
337         }
338         length = strlen(tempchr2);
339         if (length)
340         {
341                 if (payloadpos + length + 2 > 507)
342                         return -1;
343                 payload[payloadpos++] = length;
344                 memcpy(&payload[payloadpos],tempchr2,length);
345                 payloadpos += length;
346                 payload[payloadpos++] = 0;
347         }
348         if (payloadpos > 508)
349                 return -1;
350         length = htons(rr);
351         memcpy(&payload[payloadpos],&length,2);
352         length = htons(rr_class);
353         memcpy(&payload[payloadpos + 2],&length,2);
354         return payloadpos + 4;
355 }
356
357 /* Start lookup of an hostname to an IP address */
358 int DNS::GetIP(const char *name)
359 {
360         DNSHeader h;
361         int id;
362         int length;
363         
364         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
365                 return -1;
366
367         DNSRequest* req = this->AddQuery(&h, id);
368
369         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
370                 return -1;
371
372         return id;
373 }
374
375 /* Start lookup of an hostname to an IPv6 address */
376 int DNS::GetIP6(const char *name)
377 {
378         DNSHeader h;
379         int id;
380         int length;
381
382         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
383                 return -1;
384
385         DNSRequest* req = this->AddQuery(&h, id);
386
387         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
388                 return -1;
389
390         return id;
391 }
392
393 /* Start lookup of a cname to another name */
394 int DNS::GetCName(const char *alias)
395 {
396         DNSHeader h;
397         int id;
398         int length;
399
400         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
401                 return -1;
402
403         DNSRequest* req = this->AddQuery(&h, id);
404
405         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
406                 return -1;
407
408         return id;
409 }
410
411 /* Start lookup of an IP address to a hostname */
412 int DNS::GetName(const insp_inaddr *ip)
413 {
414         char query[128];
415         DNSHeader h;
416         int id;
417         int length;
418
419 #ifdef IPV6
420         DNS::MakeIP6Int(query, (in6_addr*)ip);
421 #else
422         unsigned char* c = (unsigned char*)&ip->s_addr;
423
424         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
425 #endif
426
427         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
428                 return -1;
429
430         DNSRequest* req = this->AddQuery(&h, id);
431
432         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
433                 return -1;
434
435         return id;
436 }
437
438 /* Start lookup of an IP address to a hostname */
439 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
440 {
441         char query[128];
442         DNSHeader h;
443         int id;
444         int length;
445
446         if (fp == PROTOCOL_IPV6)
447         {
448                 in6_addr i;
449                 if (inet_pton(AF_INET6, ip, &i) > 0)
450                 {
451                         DNS::MakeIP6Int(query, &i);
452                 }
453                 else
454                         /* Invalid IP address */
455                         return -1;
456         }
457         else
458         {
459                 in_addr i;
460                 if (inet_aton(ip, &i))
461                 {
462                         unsigned char* c = (unsigned char*)&i.s_addr;
463                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
464                 }
465                 else
466                         /* Invalid IP address */
467                         return -1;
468         }
469
470         log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
471
472         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
473                 return -1;
474
475         DNSRequest* req = this->AddQuery(&h, id);
476
477         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
478                 return -1;
479
480         return id;
481 }
482
483 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
484 {
485         const char* hex = "0123456789abcdef";
486         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
487         {
488                 if (index % 2)
489                         /* low nibble */
490                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
491                 else
492                         /* high nibble */
493                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
494                 *query++ = '.'; /* Seperator */
495         }
496         strcpy(query,"ip6.arpa"); /* Suffix the string */
497 }
498
499 /* Return the next id which is ready, and the result attached to it */
500 DNSResult DNS::GetResult()
501 {
502         /* Fetch dns query response and decide where it belongs */
503         DNSHeader header;
504         DNSRequest *req;
505         unsigned char buffer[sizeof(DNSHeader)];
506         sockaddr from;
507         socklen_t x = sizeof(from);
508         const char* ipaddr_from = "";
509         unsigned short int port_from = 0;
510
511         int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
512
513         if (length < 0)
514                 log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
515
516         /* Did we get the whole header? */
517         if (length < 12)
518         {
519                 /* Nope - something screwed up. */
520                 log(DEBUG,"Whole header not read!");
521                 return std::make_pair(-1,"");
522         }
523
524         /* Check wether the reply came from a different DNS
525          * server to the one we sent it to, or the source-port
526          * is not 53.
527          * A user could in theory still spoof dns packets anyway
528          * but this is less trivial than just sending garbage
529          * to the client, which is possible without this check.
530          *
531          * -- Thanks jilles for pointing this one out.
532          */
533 #ifdef IPV6
534         ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
535         port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
536 #else
537         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
538         port_from = ntohs(((sockaddr_in*)&from)->sin_port);
539 #endif
540
541         if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, Config->DNSServer)))
542         {
543                 log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, Config->DNSServer);
544                 return std::make_pair(-1,"");
545         }
546
547         /* Put the read header info into a header class */
548         DNS::FillHeader(&header,buffer,length - 12);
549
550         /* Get the id of this request.
551          * Its a 16 bit value stored in two char's,
552          * so we use logic shifts to create the value.
553          */
554         unsigned long this_id = header.id[1] + (header.id[0] << 8);
555
556         /* Do we have a pending request matching this id? */
557         requestlist_iter n_iter = requests.find(this_id);
558         if (n_iter == requests.end())
559         {
560                 /* Somehow we got a DNS response for a request we never made... */
561                 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
562                 return std::make_pair(-1,"");
563         }
564         else
565         {
566                 /* Remove the query from the list of pending queries */
567                 req = (DNSRequest*)n_iter->second;
568                 requests.erase(n_iter);
569         }
570
571         /* Inform the DNSRequest class that it has a result to be read.
572          * When its finished it will return a DNSInfo which is a pair of
573          * unsigned char* resource record data, and an error message.
574          */
575         DNSInfo data = req->ResultIsReady(header, length);
576         std::string resultstr;
577
578         /* Check if we got a result, if we didnt, its an error */
579         if (data.first == NULL)
580         {
581                 /* An error.
582                  * Mask the ID with the value of ERROR_MASK, so that
583                  * the dns_deal_with_classes() function knows that its
584                  * an error response and needs to be treated uniquely.
585                  * Put the error message in the second field.
586                  */
587                 delete req;
588                 return std::make_pair(this_id | ERROR_MASK, data.second);
589         }
590         else
591         {
592                 char formatted[128];
593
594                 /* Forward lookups come back as binary data. We must format them into ascii */
595                 switch (req->type)
596                 {
597                         case DNS_QUERY_A:
598                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
599                                 resultstr = formatted;
600                         break;
601
602                         case DNS_QUERY_AAAA:
603                         {
604                                 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
605                                                 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
606                                                 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
607                                                 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
608                                                 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
609                                                 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
610                                                 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
611                                                 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
612                                                 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
613                                 char* c = strstr(formatted,":0:");
614                                 if (c != NULL)
615                                 {
616                                         memmove(c+1,c+2,strlen(c+2) + 1);
617                                         c += 2;
618                                         while (memcmp(c,"0:",2) == 0)
619                                                 memmove(c,c+2,strlen(c+2) + 1);
620                                         if (memcmp(c,"0",2) == 0)
621                                                 *c = 0;
622                                         if (memcmp(formatted,"0::",3) == 0)
623                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
624                                 }
625                                 resultstr = formatted;
626                         }
627                         break;
628
629                         case DNS_QUERY_CNAME:
630                                 /* Identical handling to PTR */
631
632                         case DNS_QUERY_PTR:
633                                 /* Reverse lookups just come back as char* */
634                                 resultstr = std::string((const char*)data.first);
635                         break;
636
637                         default:
638                                 log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
639                         break;
640                         
641                 }
642
643                 /* Build the reply with the id and hostname/ip in it */
644                 delete req;
645                 return std::make_pair(this_id,resultstr);
646         }
647 }
648
649 /* A result is ready, process it */
650 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
651 {
652         int i = 0;
653         int q = 0;
654         int curanswer, o;
655         ResourceRecord rr;
656         unsigned short ptr;
657                         
658         if (!(header.flags1 & FLAGS_MASK_QR))
659                 return std::make_pair((unsigned char*)NULL,"Not a query result");
660
661         if (header.flags1 & FLAGS_MASK_OPCODE)
662                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
663
664         if (header.flags2 & FLAGS_MASK_RCODE)
665                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
666
667         if (header.ancount < 1)
668                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
669
670         /* Subtract the length of the header from the length of the packet */
671         length -= 12;
672
673         while ((unsigned int)q < header.qdcount && i < length)
674         {
675                 if (header.payload[i] > 63)
676                 {
677                         i += 6;
678                         q++;
679                 }
680                 else
681                 {
682                         if (header.payload[i] == 0)
683                         {
684                                 q++;
685                                 i += 5;
686                         }
687                         else i += header.payload[i] + 1;
688                 }
689         }
690         curanswer = 0;
691         while ((unsigned)curanswer < header.ancount)
692         {
693                 q = 0;
694                 while (q == 0 && i < length)
695                 {
696                         if (header.payload[i] > 63)
697                         {
698                                 i += 2;
699                                 q = 1;
700                         }
701                         else
702                         {
703                                 if (header.payload[i] == 0)
704                                 {
705                                         i++;
706                                         q = 1;
707                                 }
708                                 else i += header.payload[i] + 1; /* skip length and label */
709                         }
710                 }
711                 if (length - i < 10)
712                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
713
714                 DNS::FillResourceRecord(&rr,&header.payload[i]);
715                 i += 10;
716                 if (rr.type != this->type)
717                 {
718                         curanswer++;
719                         i += rr.rdlength;
720                         continue;
721                 }
722                 if (rr.rr_class != this->rr_class)
723                 {
724                         curanswer++;
725                         i += rr.rdlength;
726                         continue;
727                 }
728                 break;
729         }
730         if ((unsigned int)curanswer == header.ancount)
731                 return std::make_pair((unsigned char*)NULL,"No valid answers");
732
733         if (i + rr.rdlength > (unsigned int)length)
734                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
735
736         if (rr.rdlength > 1023)
737                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
738
739         switch (rr.type)
740         {
741                 case DNS_QUERY_CNAME:
742                         /* CNAME and PTR have the same processing code */
743                 case DNS_QUERY_PTR:
744                         o = 0;
745                         q = 0;
746                         while (q == 0 && i < length && o + 256 < 1023)
747                         {
748                                 if (header.payload[i] > 63)
749                                 {
750                                         memcpy(&ptr,&header.payload[i],2);
751                                         i = ntohs(ptr) - 0xC000 - 12;
752                                 }
753                                 else
754                                 {
755                                         if (header.payload[i] == 0)
756                                         {
757                                                 q = 1;
758                                         }
759                                         else
760                                         {
761                                                 res[o] = 0;
762                                                 if (o != 0)
763                                                         res[o++] = '.';
764                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
765                                                 o += header.payload[i];
766                                                 i += header.payload[i] + 1;
767                                         }
768                                 }
769                         }
770                         res[o] = 0;
771                 break;
772                 case DNS_QUERY_AAAA:
773                         memcpy(res,&header.payload[i],rr.rdlength);
774                         res[rr.rdlength] = 0;
775                 break;
776                 case DNS_QUERY_A:
777                         memcpy(res,&header.payload[i],rr.rdlength);
778                         res[rr.rdlength] = 0;
779                 break;
780                 default:
781                         memcpy(res,&header.payload[i],rr.rdlength);
782                         res[rr.rdlength] = 0;
783                 break;
784         }
785         return std::make_pair(res,"No error");;
786 }
787
788 /* Close the master socket */
789 DNS::~DNS()
790 {
791         shutdown(MasterSocket, 2);
792         close(MasterSocket);
793 }
794
795 /* High level abstraction of dns used by application at large */
796 Resolver::Resolver(const std::string &source, QueryType qt) : input(source), querytype(qt)
797 {
798         insp_inaddr binip;
799
800         switch (querytype)
801         {
802                 case DNS_QUERY_A:
803                         this->myid = ServerInstance->Res->GetIP(source.c_str());
804                 break;
805
806                 case DNS_QUERY_PTR:
807                         if (insp_aton(source.c_str(), &binip) > 0)
808                         {
809                                 /* Valid ip address */
810                                 this->myid = ServerInstance->Res->GetName(&binip);
811                         }
812                         else
813                         {
814                                 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
815                                 throw ModuleException("Resolver: Bad IP address");
816                                 return;
817                         }
818                 break;
819
820                 case DNS_QUERY_PTR4:
821                         querytype = DNS_QUERY_PTR;
822                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
823                 break;
824
825                 case DNS_QUERY_PTR6:
826                         querytype = DNS_QUERY_PTR;
827                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
828                 break;
829
830                 case DNS_QUERY_AAAA:
831                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
832                 break;
833
834                 case DNS_QUERY_CNAME:
835                         this->myid = ServerInstance->Res->GetCName(source.c_str());
836                 break;
837
838                 default:
839                         this->myid = -1;
840                 break;
841         }
842         if (this->myid == -1)
843         {
844                 log(DEBUG,"Resolver::Resolver: Could not get an id!");
845                 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
846                 throw ModuleException("Resolver: Couldnt get an id to make a request");
847                 /* We shouldnt get here really */
848                 return;
849         }
850
851         log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
852 }
853
854 void Resolver::OnError(ResolverError e, const std::string &errormessage)
855 {
856         /* Nothing in here */
857 }
858
859 Resolver::~Resolver()
860 {
861         /* Nothing here (yet) either */
862 }
863
864 /* Get the request id associated with this class */
865 int Resolver::GetId()
866 {
867         return this->myid;
868 }
869
870 /* Process a socket read event */
871 void DNS::MarshallReads(int fd)
872 {
873         log(DEBUG,"Marshall reads: %d %d",fd,GetMasterSocket());
874         /* We are only intrested in our single fd */
875         if (fd == GetMasterSocket())
876         {
877                 /* Fetch the id and result of the next available packet */
878                 DNSResult res = this->GetResult();
879                 /* Is there a usable request id? */
880                 if (res.first != -1)
881                 {
882                         /* Its an error reply */
883                         if (res.first & ERROR_MASK)
884                         {
885                                 /* Mask off the error bit */
886                                 res.first -= ERROR_MASK;
887
888                                 /* Marshall the error to the correct class */
889                                 log(DEBUG,"Error available, id=%d",res.first);
890                                 if (Classes[res.first])
891                                 {
892                                         if (ServerInstance && ServerInstance->stats)
893                                                 ServerInstance->stats->statsDnsBad++;
894                                         Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
895                                         delete Classes[res.first];
896                                         Classes[res.first] = NULL;
897                                 }
898                         }
899                         else
900                         {
901                                 /* It is a non-error result */
902                                 log(DEBUG,"Result available, id=%d",res.first);
903                                 /* Marshall the result to the correct class */
904                                 if (Classes[res.first])
905                                 {
906                                         if (ServerInstance && ServerInstance->stats)
907                                                 ServerInstance->stats->statsDnsGood++;
908                                         Classes[res.first]->OnLookupComplete(res.second);
909                                         delete Classes[res.first];
910                                         Classes[res.first] = NULL;
911                                 }
912                         }
913
914                         if (ServerInstance && ServerInstance->stats)
915                                 ServerInstance->stats->statsDns++;
916
917                 }
918         }
919 }
920
921 /* Add a derived Resolver to the working set */
922 bool DNS::AddResolverClass(Resolver* r)
923 {
924         /* Check the pointers validity and the id's validity */
925         if ((r) && (r->GetId() > -1))
926         {
927                 /* Check the slot isnt already occupied -
928                  * This should NEVER happen unless we have
929                  * a severely broken DNS server somewhere
930                  */
931                 if (!Classes[r->GetId()])
932                 {
933                         /* Set up the pointer to the class */
934                         Classes[r->GetId()] = r;
935                         return true;
936                 }
937                 else
938                         /* Duplicate id */
939                         return false;
940         }
941         else
942         {
943                 /* Pointer or id not valid.
944                  * Free the item and return
945                  */
946                 if (r)
947                         delete r;
948
949                 return false;
950         }
951 }
952
953 unsigned long DNS::PRNG()
954 {
955         unsigned long val = 0;
956         timeval n;
957         serverstats* s = ServerInstance->stats;
958         gettimeofday(&n,NULL);
959         val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
960         val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
961         val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;
962         return val;
963 }
964