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