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