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