]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
78025021faff52e72cdcc7cf4a3a0e2e6e83b003
[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                         /* Hook the descriptor into the socket engine */
313                         if (ServerInstance && ServerInstance->SE)
314                                 ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS);
315                 }
316         }
317 }
318
319 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
320 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
321 {
322         short payloadpos = 0;
323         const char* tempchr, *tempchr2 = name;
324         unsigned short length;
325
326         /* split name up into labels, create query */
327         while ((tempchr = strchr(tempchr2,'.')) != NULL)
328         {
329                 length = tempchr - tempchr2;
330                 if (payloadpos + length + 1 > 507)
331                         return -1;
332                 payload[payloadpos++] = length;
333                 memcpy(&payload[payloadpos],tempchr2,length);
334                 payloadpos += length;
335                 tempchr2 = &tempchr[1];
336         }
337         length = strlen(tempchr2);
338         if (length)
339         {
340                 if (payloadpos + length + 2 > 507)
341                         return -1;
342                 payload[payloadpos++] = length;
343                 memcpy(&payload[payloadpos],tempchr2,length);
344                 payloadpos += length;
345                 payload[payloadpos++] = 0;
346         }
347         if (payloadpos > 508)
348                 return -1;
349         length = htons(rr);
350         memcpy(&payload[payloadpos],&length,2);
351         length = htons(rr_class);
352         memcpy(&payload[payloadpos + 2],&length,2);
353         return payloadpos + 4;
354 }
355
356 /* Start lookup of an hostname to an IP address */
357 int DNS::GetIP(const char *name)
358 {
359         DNSHeader h;
360         int id;
361         int length;
362         
363         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
364                 return -1;
365
366         DNSRequest* req = this->AddQuery(&h, id);
367
368         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
369                 return -1;
370
371         return id;
372 }
373
374 /* Start lookup of an hostname to an IPv6 address */
375 int DNS::GetIP6(const char *name)
376 {
377         DNSHeader h;
378         int id;
379         int length;
380
381         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
382                 return -1;
383
384         DNSRequest* req = this->AddQuery(&h, id);
385
386         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
387                 return -1;
388
389         return id;
390 }
391
392 /* Start lookup of a cname to another name */
393 int DNS::GetCName(const char *alias)
394 {
395         DNSHeader h;
396         int id;
397         int length;
398
399         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
400                 return -1;
401
402         DNSRequest* req = this->AddQuery(&h, id);
403
404         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
405                 return -1;
406
407         return id;
408 }
409
410 /* Start lookup of an IP address to a hostname */
411 int DNS::GetName(const insp_inaddr *ip)
412 {
413         char query[128];
414         DNSHeader h;
415         int id;
416         int length;
417
418 #ifdef IPV6
419         DNS::MakeIP6Int(query, (in6_addr*)ip);
420 #else
421         unsigned char* c = (unsigned char*)&ip->s_addr;
422
423         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
424 #endif
425
426         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
427                 return -1;
428
429         DNSRequest* req = this->AddQuery(&h, id);
430
431         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
432                 return -1;
433
434         return id;
435 }
436
437 /* Start lookup of an IP address to a hostname */
438 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
439 {
440         char query[128];
441         DNSHeader h;
442         int id;
443         int length;
444
445         if (fp == PROTOCOL_IPV6)
446         {
447                 in6_addr i;
448                 if (inet_pton(AF_INET6, ip, &i) > 0)
449                 {
450                         DNS::MakeIP6Int(query, &i);
451                 }
452                 else
453                         /* Invalid IP address */
454                         return -1;
455         }
456         else
457         {
458                 in_addr i;
459                 if (inet_aton(ip, &i))
460                 {
461                         unsigned char* c = (unsigned char*)&i.s_addr;
462                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
463                 }
464                 else
465                         /* Invalid IP address */
466                         return -1;
467         }
468
469         log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
470
471         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
472                 return -1;
473
474         DNSRequest* req = this->AddQuery(&h, id);
475
476         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
477                 return -1;
478
479         return id;
480 }
481
482 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
483 {
484         const char* hex = "0123456789abcdef";
485         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
486         {
487                 if (index % 2)
488                         /* low nibble */
489                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
490                 else
491                         /* high nibble */
492                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
493                 *query++ = '.'; /* Seperator */
494         }
495         strcpy(query,"ip6.arpa"); /* Suffix the string */
496 }
497
498 /* Return the next id which is ready, and the result attached to it */
499 DNSResult DNS::GetResult()
500 {
501         /* Fetch dns query response and decide where it belongs */
502         DNSHeader header;
503         DNSRequest *req;
504         unsigned char buffer[sizeof(DNSHeader)];
505         sockaddr from;
506         socklen_t x = sizeof(from);
507         const char* ipaddr_from = "";
508         unsigned short int port_from = 0;
509
510         int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
511
512         if (length < 0)
513                 log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
514
515         /* Did we get the whole header? */
516         if (length < 12)
517                 /* Nope - something screwed up. */
518                 return std::make_pair(-1,"");
519
520         /* Check wether the reply came from a different DNS
521          * server to the one we sent it to, or the source-port
522          * is not 53.
523          * A user could in theory still spoof dns packets anyway
524          * but this is less trivial than just sending garbage
525          * to the client, which is possible without this check.
526          *
527          * -- Thanks jilles for pointing this one out.
528          */
529 #ifdef IPV6
530         ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
531         port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
532 #else
533         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
534         port_from = ntohs(((sockaddr_in*)&from)->sin_port);
535 #endif
536
537         if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, Config->DNSServer)))
538                 return std::make_pair(-1,"");
539
540         /* Put the read header info into a header class */
541         DNS::FillHeader(&header,buffer,length - 12);
542
543         /* Get the id of this request.
544          * Its a 16 bit value stored in two char's,
545          * so we use logic shifts to create the value.
546          */
547         unsigned long this_id = header.id[1] + (header.id[0] << 8);
548
549         /* Do we have a pending request matching this id? */
550         requestlist_iter n_iter = requests.find(this_id);
551         if (n_iter == requests.end())
552         {
553                 /* Somehow we got a DNS response for a request we never made... */
554                 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
555                 return std::make_pair(-1,"");
556         }
557         else
558         {
559                 /* Remove the query from the list of pending queries */
560                 req = (DNSRequest*)n_iter->second;
561                 requests.erase(n_iter);
562         }
563
564         /* Inform the DNSRequest class that it has a result to be read.
565          * When its finished it will return a DNSInfo which is a pair of
566          * unsigned char* resource record data, and an error message.
567          */
568         DNSInfo data = req->ResultIsReady(header, length);
569         std::string resultstr;
570
571         /* Check if we got a result, if we didnt, its an error */
572         if (data.first == NULL)
573         {
574                 /* An error.
575                  * Mask the ID with the value of ERROR_MASK, so that
576                  * the dns_deal_with_classes() function knows that its
577                  * an error response and needs to be treated uniquely.
578                  * Put the error message in the second field.
579                  */
580                 delete req;
581                 return std::make_pair(this_id | ERROR_MASK, data.second);
582         }
583         else
584         {
585                 char formatted[128];
586
587                 /* Forward lookups come back as binary data. We must format them into ascii */
588                 switch (req->type)
589                 {
590                         case DNS_QUERY_A:
591                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
592                                 resultstr = formatted;
593                         break;
594
595                         case DNS_QUERY_AAAA:
596                         {
597                                 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
598                                                 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
599                                                 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
600                                                 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
601                                                 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
602                                                 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
603                                                 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
604                                                 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
605                                                 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
606                                 char* c = strstr(formatted,":0:");
607                                 if (c != NULL)
608                                 {
609                                         memmove(c+1,c+2,strlen(c+2) + 1);
610                                         c += 2;
611                                         while (memcmp(c,"0:",2) == 0)
612                                                 memmove(c,c+2,strlen(c+2) + 1);
613                                         if (memcmp(c,"0",2) == 0)
614                                                 *c = 0;
615                                         if (memcmp(formatted,"0::",3) == 0)
616                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
617                                 }
618                                 resultstr = formatted;
619                         }
620                         break;
621
622                         case DNS_QUERY_CNAME:
623                                 /* Identical handling to PTR */
624
625                         case DNS_QUERY_PTR:
626                                 /* Reverse lookups just come back as char* */
627                                 resultstr = std::string((const char*)data.first);
628                         break;
629
630                         default:
631                                 log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
632                         break;
633                         
634                 }
635
636                 /* Build the reply with the id and hostname/ip in it */
637                 delete req;
638                 return std::make_pair(this_id,resultstr);
639         }
640 }
641
642 /* A result is ready, process it */
643 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
644 {
645         int i = 0;
646         int q = 0;
647         int curanswer, o;
648         ResourceRecord rr;
649         unsigned short ptr;
650                         
651         if (!(header.flags1 & FLAGS_MASK_QR))
652                 return std::make_pair((unsigned char*)NULL,"Not a query result");
653
654         if (header.flags1 & FLAGS_MASK_OPCODE)
655                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
656
657         if (header.flags2 & FLAGS_MASK_RCODE)
658                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
659
660         if (header.ancount < 1)
661                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
662
663         /* Subtract the length of the header from the length of the packet */
664         length -= 12;
665
666         while ((unsigned int)q < header.qdcount && i < length)
667         {
668                 if (header.payload[i] > 63)
669                 {
670                         i += 6;
671                         q++;
672                 }
673                 else
674                 {
675                         if (header.payload[i] == 0)
676                         {
677                                 q++;
678                                 i += 5;
679                         }
680                         else i += header.payload[i] + 1;
681                 }
682         }
683         curanswer = 0;
684         while ((unsigned)curanswer < header.ancount)
685         {
686                 q = 0;
687                 while (q == 0 && i < length)
688                 {
689                         if (header.payload[i] > 63)
690                         {
691                                 i += 2;
692                                 q = 1;
693                         }
694                         else
695                         {
696                                 if (header.payload[i] == 0)
697                                 {
698                                         i++;
699                                         q = 1;
700                                 }
701                                 else i += header.payload[i] + 1; /* skip length and label */
702                         }
703                 }
704                 if (length - i < 10)
705                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
706
707                 DNS::FillResourceRecord(&rr,&header.payload[i]);
708                 i += 10;
709                 if (rr.type != this->type)
710                 {
711                         curanswer++;
712                         i += rr.rdlength;
713                         continue;
714                 }
715                 if (rr.rr_class != this->rr_class)
716                 {
717                         curanswer++;
718                         i += rr.rdlength;
719                         continue;
720                 }
721                 break;
722         }
723         if ((unsigned int)curanswer == header.ancount)
724                 return std::make_pair((unsigned char*)NULL,"No valid answers");
725
726         if (i + rr.rdlength > (unsigned int)length)
727                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
728
729         if (rr.rdlength > 1023)
730                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
731
732         switch (rr.type)
733         {
734                 case DNS_QUERY_CNAME:
735                         /* CNAME and PTR have the same processing code */
736                 case DNS_QUERY_PTR:
737                         o = 0;
738                         q = 0;
739                         while (q == 0 && i < length && o + 256 < 1023)
740                         {
741                                 if (header.payload[i] > 63)
742                                 {
743                                         memcpy(&ptr,&header.payload[i],2);
744                                         i = ntohs(ptr) - 0xC000 - 12;
745                                 }
746                                 else
747                                 {
748                                         if (header.payload[i] == 0)
749                                         {
750                                                 q = 1;
751                                         }
752                                         else
753                                         {
754                                                 res[o] = 0;
755                                                 if (o != 0)
756                                                         res[o++] = '.';
757                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
758                                                 o += header.payload[i];
759                                                 i += header.payload[i] + 1;
760                                         }
761                                 }
762                         }
763                         res[o] = 0;
764                 break;
765                 case DNS_QUERY_AAAA:
766                         memcpy(res,&header.payload[i],rr.rdlength);
767                         res[rr.rdlength] = 0;
768                 break;
769                 case DNS_QUERY_A:
770                         memcpy(res,&header.payload[i],rr.rdlength);
771                         res[rr.rdlength] = 0;
772                 break;
773                 default:
774                         memcpy(res,&header.payload[i],rr.rdlength);
775                         res[rr.rdlength] = 0;
776                 break;
777         }
778         return std::make_pair(res,"No error");;
779 }
780
781 /* Close the master socket */
782 DNS::~DNS()
783 {
784         shutdown(MasterSocket, 2);
785         close(MasterSocket);
786 }
787
788 /* High level abstraction of dns used by application at large */
789 Resolver::Resolver(const std::string &source, QueryType qt) : input(source), querytype(qt)
790 {
791         insp_inaddr binip;
792
793         switch (querytype)
794         {
795                 case DNS_QUERY_A:
796                         this->myid = ServerInstance->Res->GetIP(source.c_str());
797                 break;
798
799                 case DNS_QUERY_PTR:
800                         if (insp_aton(source.c_str(), &binip) > 0)
801                         {
802                                 /* Valid ip address */
803                                 this->myid = ServerInstance->Res->GetName(&binip);
804                         }
805                         else
806                         {
807                                 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
808                                 throw ModuleException("Resolver: Bad IP address");
809                                 return;
810                         }
811                 break;
812
813                 case DNS_QUERY_PTR4:
814                         querytype = DNS_QUERY_PTR;
815                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
816                 break;
817
818                 case DNS_QUERY_PTR6:
819                         querytype = DNS_QUERY_PTR;
820                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
821                 break;
822
823                 case DNS_QUERY_AAAA:
824                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
825                 break;
826
827                 case DNS_QUERY_CNAME:
828                         this->myid = ServerInstance->Res->GetCName(source.c_str());
829                 break;
830
831                 default:
832                         this->myid = -1;
833                 break;
834         }
835         if (this->myid == -1)
836         {
837                 log(DEBUG,"Resolver::Resolver: Could not get an id!");
838                 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
839                 throw ModuleException("Resolver: Couldnt get an id to make a request");
840                 /* We shouldnt get here really */
841                 return;
842         }
843
844         log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
845 }
846
847 void Resolver::OnError(ResolverError e, const std::string &errormessage)
848 {
849         /* Nothing in here */
850 }
851
852 Resolver::~Resolver()
853 {
854         /* Nothing here (yet) either */
855 }
856
857 /* Get the request id associated with this class */
858 int Resolver::GetId()
859 {
860         return this->myid;
861 }
862
863 /* Process a socket read event */
864 void DNS::MarshallReads(int fd)
865 {
866         /* We are only intrested in our single fd */
867         if (fd == GetMasterSocket())
868         {
869                 /* Fetch the id and result of the next available packet */
870                 DNSResult res = this->GetResult();
871                 /* Is there a usable request id? */
872                 if (res.first != -1)
873                 {
874                         /* Its an error reply */
875                         if (res.first & ERROR_MASK)
876                         {
877                                 /* Mask off the error bit */
878                                 res.first -= ERROR_MASK;
879
880                                 /* Marshall the error to the correct class */
881                                 log(DEBUG,"Error available, id=%d",res.first);
882                                 if (Classes[res.first])
883                                 {
884                                         if (ServerInstance && ServerInstance->stats)
885                                                 ServerInstance->stats->statsDnsBad++;
886                                         Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
887                                         delete Classes[res.first];
888                                         Classes[res.first] = NULL;
889                                 }
890                         }
891                         else
892                         {
893                                 /* It is a non-error result */
894                                 log(DEBUG,"Result available, id=%d",res.first);
895                                 /* Marshall the result to the correct class */
896                                 if (Classes[res.first])
897                                 {
898                                         if (ServerInstance && ServerInstance->stats)
899                                                 ServerInstance->stats->statsDnsGood++;
900                                         Classes[res.first]->OnLookupComplete(res.second);
901                                         delete Classes[res.first];
902                                         Classes[res.first] = NULL;
903                                 }
904                         }
905
906                         if (ServerInstance && ServerInstance->stats)
907                                 ServerInstance->stats->statsDns++;
908
909                 }
910         }
911 }
912
913 /* Add a derived Resolver to the working set */
914 bool DNS::AddResolverClass(Resolver* r)
915 {
916         /* Check the pointers validity and the id's validity */
917         if ((r) && (r->GetId() > -1))
918         {
919                 /* Check the slot isnt already occupied -
920                  * This should NEVER happen unless we have
921                  * a severely broken DNS server somewhere
922                  */
923                 if (!Classes[r->GetId()])
924                 {
925                         /* Set up the pointer to the class */
926                         Classes[r->GetId()] = r;
927                         return true;
928                 }
929                 else
930                         /* Duplicate id */
931                         return false;
932         }
933         else
934         {
935                 /* Pointer or id not valid.
936                  * Free the item and return
937                  */
938                 if (r)
939                         delete r;
940
941                 return false;
942         }
943 }
944
945 unsigned long DNS::PRNG()
946 {
947         unsigned long val = 0;
948         timeval n;
949         serverstats* s = ServerInstance->stats;
950         gettimeofday(&n,NULL);
951         val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
952         val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
953         val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;
954         return val;
955 }
956