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