]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
Fix passing wrong instance to resolver
[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 /* Master file descriptor */
47 int DNS::MasterSocket;
48
49 /* Masks to mask off the responses we get from the DNSRequest methods */
50 enum QueryInfo
51 {
52         ERROR_MASK      = 0x10000       /* Result is an error */
53 };
54
55 /* Flags which can be ORed into a request or reply for different meanings */
56 enum QueryFlags
57 {
58         FLAGS_MASK_RD           = 0x01, /* Recursive */
59         FLAGS_MASK_TC           = 0x02,
60         FLAGS_MASK_AA           = 0x04, /* Authoritative */
61         FLAGS_MASK_OPCODE       = 0x78,
62         FLAGS_MASK_QR           = 0x80,
63         FLAGS_MASK_RCODE        = 0x0F, /* Request */
64         FLAGS_MASK_Z            = 0x70,
65         FLAGS_MASK_RA           = 0x80
66 };
67
68
69 /* Represents a dns resource record (rr) */
70 class ResourceRecord
71 {
72  public:
73         QueryType       type;           /* Record type */
74         unsigned int    rr_class;       /* Record class */
75         unsigned long   ttl;            /* Time to live */
76         unsigned int    rdlength;       /* Record length */
77 };
78
79 /* Represents a dns request/reply header, and its payload as opaque data.
80  */
81 class DNSHeader
82 {
83  public:
84         unsigned char   id[2];          /* Request id */
85         unsigned int    flags1;         /* Flags */
86         unsigned int    flags2;         /* Flags */
87         unsigned int    qdcount;
88         unsigned int    ancount;        /* Answer count */
89         unsigned int    nscount;        /* Nameserver count */
90         unsigned int    arcount;
91         unsigned char   payload[512];   /* Packet payload */
92 };
93
94 /* Represents a request 'on the wire' with routing information relating to
95  * where to call when we get a result
96  */
97 class DNSRequest
98 {
99  public:
100         unsigned char   id[2];          /* Request id */
101         unsigned char*  res;            /* Result processing buffer */
102         unsigned int    rr_class;       /* Request class */
103         QueryType       type;           /* Request type */
104         insp_inaddr     myserver;       /* DNS server address*/
105
106         /* Allocate the processing buffer */
107         DNSRequest(insp_inaddr server)
108         {
109                 res = new unsigned char[512];
110                 *res = 0;
111                 memcpy(&myserver, &server, sizeof(insp_inaddr));
112         }
113
114         /* Deallocate the processing buffer */
115         ~DNSRequest()
116         {
117                 delete[] res;
118         }
119
120         /* Called when a result is ready to be processed which matches this id */
121         DNSInfo ResultIsReady(DNSHeader &h, int length);
122
123         /* Called when there are requests to be sent out */
124         int SendRequests(const DNSHeader *header, const int length, QueryType qt);
125 };
126
127 /* Fill a ResourceRecord class based on raw data input */
128 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
129 {
130         rr->type = (QueryType)((input[0] << 8) + input[1]);
131         rr->rr_class = (input[2] << 8) + input[3];
132         rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
133         rr->rdlength = (input[8] << 8) + input[9];
134 }
135
136 /* Fill a DNSHeader class based on raw data input of a given length */
137 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
138 {
139         header->id[0] = input[0];
140         header->id[1] = input[1];
141         header->flags1 = input[2];
142         header->flags2 = input[3];
143         header->qdcount = (input[4] << 8) + input[5];
144         header->ancount = (input[6] << 8) + input[7];
145         header->nscount = (input[8] << 8) + input[9];
146         header->arcount = (input[10] << 8) + input[11];
147         memcpy(header->payload,&input[12],length);
148 }
149
150 /* Empty a DNSHeader class out into raw data, ready for transmission */
151 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
152 {
153         output[0] = header->id[0];
154         output[1] = header->id[1];
155         output[2] = header->flags1;
156         output[3] = header->flags2;
157         output[4] = header->qdcount >> 8;
158         output[5] = header->qdcount & 0xFF;
159         output[6] = header->ancount >> 8;
160         output[7] = header->ancount & 0xFF;
161         output[8] = header->nscount >> 8;
162         output[9] = header->nscount & 0xFF;
163         output[10] = header->arcount >> 8;
164         output[11] = header->arcount & 0xFF;
165         memcpy(&output[12],header->payload,length);
166 }
167
168 /* Send requests we have previously built down the UDP socket */
169 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
170 {
171         insp_sockaddr addr;
172         unsigned char payload[sizeof(DNSHeader)];
173
174         this->rr_class = 1;
175         this->type = qt;
176                 
177         DNS::EmptyHeader(payload,header,length);
178
179         memset(&addr,0,sizeof(addr));
180 #ifdef IPV6
181         memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
182         addr.sin6_family = AF_FAMILY;
183         addr.sin6_port = htons(DNS::QUERY_PORT);
184 #else
185         memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
186         addr.sin_family = AF_FAMILY;
187         addr.sin_port = htons(DNS::QUERY_PORT);
188 #endif
189         if (sendto(DNS::GetMasterSocket(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
190         {
191                 log(DEBUG,"Error in sendto! (%s)",strerror(errno));
192                 return -1;
193         }
194
195         return 0;
196 }
197
198 /* Add a query with a predefined header, and allocate an ID for it. */
199 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
200 {
201         /* Is the DNS connection down? */
202         if (MasterSocket == -1)
203                 return NULL;
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(InspIRCd* Instance) : ServerInstance(Instance)
243 {
244         log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
245
246         insp_inaddr addr;
247
248         /* Clear the Resolver class table */
249         memset(Classes,0,sizeof(Classes));
250
251         /* Set the id of the next request to 0
252          */
253         currid = 0;
254
255         /* Clear the namesever address */
256         memset(&myserver,0,sizeof(insp_inaddr));
257
258         /* Convert the nameserver address into an insp_inaddr */
259         if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
260         {
261                 memcpy(&myserver,&addr,sizeof(insp_inaddr));
262                 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) ||  (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
263                 {
264                         /* These dont come back looking like they did when they went in.
265                          * We're forced to turn some checks off.
266                          * If anyone knows how to fix this, let me know. --Brain
267                          */
268                         log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
269                         log(DEFAULT,"         This should not cause a problem, however it is recommended you migrate");
270                         log(DEFAULT,"         to a true IPv6 environment.");
271                         this->ip6munge = true;
272                 }
273                 log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
274         }
275         else
276         {
277                 log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
278         }
279
280         /* Initialize mastersocket */
281         MasterSocket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
282         if (MasterSocket != -1)
283         {
284                 /* Did it succeed? */
285                 if (fcntl(MasterSocket, F_SETFL, O_NONBLOCK) != 0)
286                 {
287                         /* Couldn't make the socket nonblocking */
288                         shutdown(MasterSocket,2);
289                         close(MasterSocket);
290                         MasterSocket = -1;
291                 }
292         }
293         else
294         {
295                 log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
296         }
297         /* Have we got a socket and is it nonblocking? */
298         if (MasterSocket != -1)
299         {
300 #ifdef IPV6
301                 insp_sockaddr addr;
302                 memset(&addr,0,sizeof(addr));
303                 addr.sin6_family = AF_FAMILY;
304                 addr.sin6_port = 0;
305                 addr.sin6_addr = in6addr_any;
306 #else
307                 insp_sockaddr addr;
308                 memset(&addr,0,sizeof(addr));
309                 addr.sin_family = AF_FAMILY;
310                 addr.sin_port = 0;
311                 addr.sin_addr.s_addr = INADDR_ANY;
312 #endif
313                 /* Bind the port */
314                 if (bind(MasterSocket,(sockaddr *)&addr,sizeof(addr)) != 0)
315                 {
316                         /* Failed to bind */
317                         log(DEBUG,"Cant bind DNS::MasterSocket");
318                         shutdown(MasterSocket,2);
319                         close(MasterSocket);
320                         MasterSocket = -1;
321                 }
322
323                 if (MasterSocket >= 0)
324                 {
325                         log(DEBUG,"Add master socket %d",MasterSocket);
326                         /* Hook the descriptor into the socket engine */
327                         if (ServerInstance && ServerInstance->SE)
328                         {
329                                 if (!ServerInstance->SE->AddFd(MasterSocket,true,X_ESTAB_DNS))
330                                 {
331                                         log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
332                                         shutdown(MasterSocket,2);
333                                         close(MasterSocket);
334                                         MasterSocket = -1;
335                                 }
336                         }
337                 }
338         }
339 }
340
341 /* Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
342 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
343 {
344         short payloadpos = 0;
345         const char* tempchr, *tempchr2 = name;
346         unsigned short length;
347
348         /* split name up into labels, create query */
349         while ((tempchr = strchr(tempchr2,'.')) != NULL)
350         {
351                 length = tempchr - tempchr2;
352                 if (payloadpos + length + 1 > 507)
353                         return -1;
354                 payload[payloadpos++] = length;
355                 memcpy(&payload[payloadpos],tempchr2,length);
356                 payloadpos += length;
357                 tempchr2 = &tempchr[1];
358         }
359         length = strlen(tempchr2);
360         if (length)
361         {
362                 if (payloadpos + length + 2 > 507)
363                         return -1;
364                 payload[payloadpos++] = length;
365                 memcpy(&payload[payloadpos],tempchr2,length);
366                 payloadpos += length;
367                 payload[payloadpos++] = 0;
368         }
369         if (payloadpos > 508)
370                 return -1;
371         length = htons(rr);
372         memcpy(&payload[payloadpos],&length,2);
373         length = htons(rr_class);
374         memcpy(&payload[payloadpos + 2],&length,2);
375         return payloadpos + 4;
376 }
377
378 /* Start lookup of an hostname to an IP address */
379 int DNS::GetIP(const char *name)
380 {
381         DNSHeader h;
382         int id;
383         int length;
384         
385         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
386                 return -1;
387
388         DNSRequest* req = this->AddQuery(&h, id);
389
390         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
391                 return -1;
392
393         return id;
394 }
395
396 /* Start lookup of an hostname to an IPv6 address */
397 int DNS::GetIP6(const char *name)
398 {
399         DNSHeader h;
400         int id;
401         int length;
402
403         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
404                 return -1;
405
406         DNSRequest* req = this->AddQuery(&h, id);
407
408         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
409                 return -1;
410
411         return id;
412 }
413
414 /* Start lookup of a cname to another name */
415 int DNS::GetCName(const char *alias)
416 {
417         DNSHeader h;
418         int id;
419         int length;
420
421         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 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_CNAME) == -1))
427                 return -1;
428
429         return id;
430 }
431
432 /* Start lookup of an IP address to a hostname */
433 int DNS::GetName(const insp_inaddr *ip)
434 {
435         char query[128];
436         DNSHeader h;
437         int id;
438         int length;
439
440 #ifdef IPV6
441         DNS::MakeIP6Int(query, (in6_addr*)ip);
442 #else
443         unsigned char* c = (unsigned char*)&ip->s_addr;
444
445         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
446 #endif
447
448         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
449                 return -1;
450
451         DNSRequest* req = this->AddQuery(&h, id);
452
453         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
454                 return -1;
455
456         return id;
457 }
458
459 /* Start lookup of an IP address to a hostname */
460 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
461 {
462         char query[128];
463         DNSHeader h;
464         int id;
465         int length;
466 #ifdef SUPPORT_IP6LINKS
467         if (fp == PROTOCOL_IPV6)
468         {
469                 in6_addr i;
470                 if (inet_pton(AF_INET6, ip, &i) > 0)
471                 {
472                         DNS::MakeIP6Int(query, &i);
473                 }
474                 else
475                         /* Invalid IP address */
476                         return -1;
477         }
478         else
479 #endif
480         {
481                 in_addr i;
482                 if (inet_aton(ip, &i))
483                 {
484                         unsigned char* c = (unsigned char*)&i.s_addr;
485                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
486                 }
487                 else
488                         /* Invalid IP address */
489                         return -1;
490         }
491
492         log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
493
494         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
495                 return -1;
496
497         DNSRequest* req = this->AddQuery(&h, id);
498
499         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
500                 return -1;
501
502         return id;
503 }
504
505 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
506 {
507 #ifdef SUPPORT_IP6LINKS
508         const char* hex = "0123456789abcdef";
509         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
510         {
511                 if (index % 2)
512                         /* low nibble */
513                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
514                 else
515                         /* high nibble */
516                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
517                 *query++ = '.'; /* Seperator */
518         }
519         strcpy(query,"ip6.arpa"); /* Suffix the string */
520 #else
521         *query = 0;
522 #endif
523 }
524
525 /* Return the next id which is ready, and the result attached to it */
526 DNSResult DNS::GetResult()
527 {
528         /* Fetch dns query response and decide where it belongs */
529         DNSHeader header;
530         DNSRequest *req;
531         unsigned char buffer[sizeof(DNSHeader)];
532         sockaddr from;
533         socklen_t x = sizeof(from);
534         const char* ipaddr_from = "";
535         unsigned short int port_from = 0;
536
537         int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
538
539         if (length < 0)
540                 log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
541
542         /* Did we get the whole header? */
543         if (length < 12)
544         {
545                 /* Nope - something screwed up. */
546                 log(DEBUG,"Whole header not read!");
547                 return std::make_pair(-1,"");
548         }
549
550         /* Check wether the reply came from a different DNS
551          * server to the one we sent it to, or the source-port
552          * is not 53.
553          * A user could in theory still spoof dns packets anyway
554          * but this is less trivial than just sending garbage
555          * to the client, which is possible without this check.
556          *
557          * -- Thanks jilles for pointing this one out.
558          */
559 #ifdef IPV6
560         ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
561         port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
562 #else
563         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
564         port_from = ntohs(((sockaddr_in*)&from)->sin_port);
565 #endif
566
567         /* We cant perform this security check if you're using 4in6.
568          * Tough luck to you, choose one or't other!
569          */
570         if (!ip6munge)
571         {
572                 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
573                 {
574                         log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
575                         return std::make_pair(-1,"");
576                 }
577         }
578
579         /* Put the read header info into a header class */
580         DNS::FillHeader(&header,buffer,length - 12);
581
582         /* Get the id of this request.
583          * Its a 16 bit value stored in two char's,
584          * so we use logic shifts to create the value.
585          */
586         unsigned long this_id = header.id[1] + (header.id[0] << 8);
587
588         /* Do we have a pending request matching this id? */
589         requestlist_iter n_iter = requests.find(this_id);
590         if (n_iter == requests.end())
591         {
592                 /* Somehow we got a DNS response for a request we never made... */
593                 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
594                 return std::make_pair(-1,"");
595         }
596         else
597         {
598                 /* Remove the query from the list of pending queries */
599                 req = (DNSRequest*)n_iter->second;
600                 requests.erase(n_iter);
601         }
602
603         /* Inform the DNSRequest class that it has a result to be read.
604          * When its finished it will return a DNSInfo which is a pair of
605          * unsigned char* resource record data, and an error message.
606          */
607         DNSInfo data = req->ResultIsReady(header, length);
608         std::string resultstr;
609
610         /* Check if we got a result, if we didnt, its an error */
611         if (data.first == NULL)
612         {
613                 /* An error.
614                  * Mask the ID with the value of ERROR_MASK, so that
615                  * the dns_deal_with_classes() function knows that its
616                  * an error response and needs to be treated uniquely.
617                  * Put the error message in the second field.
618                  */
619                 delete req;
620                 return std::make_pair(this_id | ERROR_MASK, data.second);
621         }
622         else
623         {
624                 char formatted[128];
625
626                 /* Forward lookups come back as binary data. We must format them into ascii */
627                 switch (req->type)
628                 {
629                         case DNS_QUERY_A:
630                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
631                                 resultstr = formatted;
632                         break;
633
634                         case DNS_QUERY_AAAA:
635                         {
636                                 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
637                                                 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
638                                                 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
639                                                 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
640                                                 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
641                                                 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
642                                                 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
643                                                 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
644                                                 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
645                                 char* c = strstr(formatted,":0:");
646                                 if (c != NULL)
647                                 {
648                                         memmove(c+1,c+2,strlen(c+2) + 1);
649                                         c += 2;
650                                         while (memcmp(c,"0:",2) == 0)
651                                                 memmove(c,c+2,strlen(c+2) + 1);
652                                         if (memcmp(c,"0",2) == 0)
653                                                 *c = 0;
654                                         if (memcmp(formatted,"0::",3) == 0)
655                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
656                                 }
657                                 resultstr = formatted;
658
659                                 /* Special case. Sending ::1 around between servers
660                                  * and to clients is dangerous, because the : on the
661                                  * start makes the client or server interpret the IP
662                                  * as the last parameter on the line with a value ":1".
663                                  */
664                                 if (*formatted == ':')
665                                         resultstr = "0" + resultstr;
666                         }
667                         break;
668
669                         case DNS_QUERY_CNAME:
670                                 /* Identical handling to PTR */
671
672                         case DNS_QUERY_PTR:
673                                 /* Reverse lookups just come back as char* */
674                                 resultstr = std::string((const char*)data.first);
675                         break;
676
677                         default:
678                                 log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
679                         break;
680                         
681                 }
682
683                 /* Build the reply with the id and hostname/ip in it */
684                 delete req;
685                 return std::make_pair(this_id,resultstr);
686         }
687 }
688
689 /* A result is ready, process it */
690 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
691 {
692         int i = 0;
693         int q = 0;
694         int curanswer, o;
695         ResourceRecord rr;
696         unsigned short ptr;
697                         
698         if (!(header.flags1 & FLAGS_MASK_QR))
699                 return std::make_pair((unsigned char*)NULL,"Not a query result");
700
701         if (header.flags1 & FLAGS_MASK_OPCODE)
702                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
703
704         if (header.flags2 & FLAGS_MASK_RCODE)
705                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
706
707         if (header.ancount < 1)
708                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
709
710         /* Subtract the length of the header from the length of the packet */
711         length -= 12;
712
713         while ((unsigned int)q < header.qdcount && i < length)
714         {
715                 if (header.payload[i] > 63)
716                 {
717                         i += 6;
718                         q++;
719                 }
720                 else
721                 {
722                         if (header.payload[i] == 0)
723                         {
724                                 q++;
725                                 i += 5;
726                         }
727                         else i += header.payload[i] + 1;
728                 }
729         }
730         curanswer = 0;
731         while ((unsigned)curanswer < header.ancount)
732         {
733                 q = 0;
734                 while (q == 0 && i < length)
735                 {
736                         if (header.payload[i] > 63)
737                         {
738                                 i += 2;
739                                 q = 1;
740                         }
741                         else
742                         {
743                                 if (header.payload[i] == 0)
744                                 {
745                                         i++;
746                                         q = 1;
747                                 }
748                                 else i += header.payload[i] + 1; /* skip length and label */
749                         }
750                 }
751                 if (length - i < 10)
752                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
753
754                 DNS::FillResourceRecord(&rr,&header.payload[i]);
755                 i += 10;
756                 if (rr.type != this->type)
757                 {
758                         curanswer++;
759                         i += rr.rdlength;
760                         continue;
761                 }
762                 if (rr.rr_class != this->rr_class)
763                 {
764                         curanswer++;
765                         i += rr.rdlength;
766                         continue;
767                 }
768                 break;
769         }
770         if ((unsigned int)curanswer == header.ancount)
771                 return std::make_pair((unsigned char*)NULL,"No valid answers");
772
773         if (i + rr.rdlength > (unsigned int)length)
774                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
775
776         if (rr.rdlength > 1023)
777                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
778
779         switch (rr.type)
780         {
781                 case DNS_QUERY_CNAME:
782                         /* CNAME and PTR have the same processing code */
783                 case DNS_QUERY_PTR:
784                         o = 0;
785                         q = 0;
786                         while (q == 0 && i < length && o + 256 < 1023)
787                         {
788                                 if (header.payload[i] > 63)
789                                 {
790                                         memcpy(&ptr,&header.payload[i],2);
791                                         i = ntohs(ptr) - 0xC000 - 12;
792                                 }
793                                 else
794                                 {
795                                         if (header.payload[i] == 0)
796                                         {
797                                                 q = 1;
798                                         }
799                                         else
800                                         {
801                                                 res[o] = 0;
802                                                 if (o != 0)
803                                                         res[o++] = '.';
804                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
805                                                 o += header.payload[i];
806                                                 i += header.payload[i] + 1;
807                                         }
808                                 }
809                         }
810                         res[o] = 0;
811                 break;
812                 case DNS_QUERY_AAAA:
813                         memcpy(res,&header.payload[i],rr.rdlength);
814                         res[rr.rdlength] = 0;
815                 break;
816                 case DNS_QUERY_A:
817                         memcpy(res,&header.payload[i],rr.rdlength);
818                         res[rr.rdlength] = 0;
819                 break;
820                 default:
821                         memcpy(res,&header.payload[i],rr.rdlength);
822                         res[rr.rdlength] = 0;
823                 break;
824         }
825         return std::make_pair(res,"No error");;
826 }
827
828 /* Close the master socket */
829 DNS::~DNS()
830 {
831         shutdown(MasterSocket, 2);
832         close(MasterSocket);
833 }
834
835 /* High level abstraction of dns used by application at large */
836 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
837 {
838         log(DEBUG,"Instance: %08x %08x %08x",Instance, ServerInstance, ServerInstance->Res);
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