]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
Add alias:matchcase config setting (per-alias, determines wether to match case on...
[user/henk/code/inspircd.git] / src / dns.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /*
15 dns.cpp - Nonblocking DNS functions.
16 Very very loosely based on the firedns library,
17 Copyright (C) 2002 Ian Gulliver. This file is no
18 longer anything like firedns, there are many major
19 differences between this code and the original.
20 Please do not assume that firedns works like this,
21 looks like this, walks like this or tastes like this.
22 */
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <errno.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include "dns.h"
30 #include "inspircd.h"
31 #include "socketengine.h"
32 #include "configreader.h"
33 #include "socket.h"
34
35 using irc::sockets::insp_sockaddr;
36 using irc::sockets::insp_inaddr;
37 using irc::sockets::insp_ntoa;
38 using irc::sockets::insp_aton;
39
40 /** Masks to mask off the responses we get from the DNSRequest methods
41  */
42 enum QueryInfo
43 {
44         ERROR_MASK      = 0x10000       /* Result is an error */
45 };
46
47 /** Flags which can be ORed into a request or reply for different meanings
48  */
49 enum QueryFlags
50 {
51         FLAGS_MASK_RD           = 0x01, /* Recursive */
52         FLAGS_MASK_TC           = 0x02,
53         FLAGS_MASK_AA           = 0x04, /* Authoritative */
54         FLAGS_MASK_OPCODE       = 0x78,
55         FLAGS_MASK_QR           = 0x80,
56         FLAGS_MASK_RCODE        = 0x0F, /* Request */
57         FLAGS_MASK_Z            = 0x70,
58         FLAGS_MASK_RA           = 0x80
59 };
60
61
62 /** Represents a dns resource record (rr)
63  */
64 class ResourceRecord
65 {
66  public:
67         QueryType       type;           /* Record type */
68         unsigned int    rr_class;       /* Record class */
69         unsigned long   ttl;            /* Time to live */
70         unsigned int    rdlength;       /* Record length */
71 };
72
73 /** Represents a dns request/reply header, and its payload as opaque data.
74  */
75 class DNSHeader
76 {
77  public:
78         unsigned char   id[2];          /* Request id */
79         unsigned int    flags1;         /* Flags */
80         unsigned int    flags2;         /* Flags */
81         unsigned int    qdcount;
82         unsigned int    ancount;        /* Answer count */
83         unsigned int    nscount;        /* Nameserver count */
84         unsigned int    arcount;
85         unsigned char   payload[512];   /* Packet payload */
86 };
87
88 class DNSRequest
89 {
90  public:
91         unsigned char   id[2];          /* Request id */
92         unsigned char*  res;            /* Result processing buffer */
93         unsigned int    rr_class;       /* Request class */
94         QueryType       type;           /* Request type */
95         insp_inaddr     myserver;       /* DNS server address*/
96         DNS*            dnsobj;         /* DNS caller (where we get our FD from) */
97         unsigned long   ttl;            /* Time to live */
98         std::string     orig;           /* Original requested name/ip */
99
100         DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, const std::string &original);
101         ~DNSRequest();
102         DNSInfo ResultIsReady(DNSHeader &h, int length);
103         int SendRequests(const DNSHeader *header, const int length, QueryType qt);
104 };
105
106 class CacheTimer : public InspTimer
107 {
108  private:
109         InspIRCd* ServerInstance;
110         DNS* dns;
111  public:
112         CacheTimer(InspIRCd* Instance, DNS* thisdns)
113                 : InspTimer(3600, Instance->Time(), true), ServerInstance(Instance), dns(thisdns) { }
114
115         virtual void Tick(time_t TIME)
116         {
117                 dns->PruneCache();
118         }
119 };
120
121 class RequestTimeout : public InspTimer
122 {
123         InspIRCd* ServerInstance;
124         DNSRequest* watch;
125         int watchid;
126  public:
127         RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
128         {
129                 ServerInstance->Log(DEBUG, "New DNS timeout set on %08x", watching);
130         }
131
132         void Tick(time_t TIME)
133         {
134                 if (ServerInstance->Res->requests[watchid] == watch)
135                 {
136                         /* Still exists, whack it */
137                         if (ServerInstance->Res->Classes[watchid])
138                         {
139                                 ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
140                                 delete ServerInstance->Res->Classes[watchid];
141                                 ServerInstance->Res->Classes[watchid] = NULL;
142                         }
143                         ServerInstance->Res->requests[watchid] = NULL;
144                         delete watch;
145                         ServerInstance->Log(DEBUG, "DNS timeout on %08x squished pointer", watch);
146                         return;
147                 }
148                 ServerInstance->Log(DEBUG, "DNS timeout on %08x: result already received!", watch);
149         }
150 };
151
152 /* Allocate the processing buffer */
153 DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id, const std::string &original) : dnsobj(dns)
154 {
155         res = new unsigned char[512];
156         *res = 0;
157         memcpy(&myserver, &server, sizeof(insp_inaddr));
158         orig = original;
159         RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);
160         Instance->Timers->AddTimer(RT); /* The timer manager frees this */
161 }
162
163 /* Deallocate the processing buffer */
164 DNSRequest::~DNSRequest()
165 {
166         delete[] res;
167 }
168
169 /** Fill a ResourceRecord class based on raw data input */
170 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
171 {
172         rr->type = (QueryType)((input[0] << 8) + input[1]);
173         rr->rr_class = (input[2] << 8) + input[3];
174         rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
175         rr->rdlength = (input[8] << 8) + input[9];
176 }
177
178 /** Fill a DNSHeader class based on raw data input of a given length */
179 inline void DNS::FillHeader(DNSHeader *header, const unsigned char *input, const int length)
180 {
181         header->id[0] = input[0];
182         header->id[1] = input[1];
183         header->flags1 = input[2];
184         header->flags2 = input[3];
185         header->qdcount = (input[4] << 8) + input[5];
186         header->ancount = (input[6] << 8) + input[7];
187         header->nscount = (input[8] << 8) + input[9];
188         header->arcount = (input[10] << 8) + input[11];
189         memcpy(header->payload,&input[12],length);
190 }
191
192 /** Empty a DNSHeader class out into raw data, ready for transmission */
193 inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, const int length)
194 {
195         output[0] = header->id[0];
196         output[1] = header->id[1];
197         output[2] = header->flags1;
198         output[3] = header->flags2;
199         output[4] = header->qdcount >> 8;
200         output[5] = header->qdcount & 0xFF;
201         output[6] = header->ancount >> 8;
202         output[7] = header->ancount & 0xFF;
203         output[8] = header->nscount >> 8;
204         output[9] = header->nscount & 0xFF;
205         output[10] = header->arcount >> 8;
206         output[11] = header->arcount & 0xFF;
207         memcpy(&output[12],header->payload,length);
208 }
209
210 /** Send requests we have previously built down the UDP socket */
211 int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt)
212 {
213         insp_sockaddr addr;
214         unsigned char payload[sizeof(DNSHeader)];
215
216         this->rr_class = 1;
217         this->type = qt;
218                 
219         DNS::EmptyHeader(payload,header,length);
220
221         memset(&addr,0,sizeof(addr));
222 #ifdef IPV6
223         memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
224         addr.sin6_family = AF_FAMILY;
225         addr.sin6_port = htons(DNS::QUERY_PORT);
226 #else
227         memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
228         addr.sin_family = AF_FAMILY;
229         addr.sin_port = htons(DNS::QUERY_PORT);
230 #endif
231         if (sendto(dnsobj->GetFd(), payload, length + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
232                 return -1;
233
234         return 0;
235 }
236
237 /** Add a query with a predefined header, and allocate an ID for it. */
238 DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original)
239 {
240         /* Is the DNS connection down? */
241         if (this->GetFd() == -1)
242                 return NULL;
243         
244         /* Create an id */
245         id = this->PRNG() & DNS::MAX_REQUEST_ID;
246
247         /* If this id is already 'in flight', pick another. */
248         while (requests[id])
249                 id = this->PRNG() & DNS::MAX_REQUEST_ID;
250
251         DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id, original);
252
253         header->id[0] = req->id[0] = id >> 8;
254         header->id[1] = req->id[1] = id & 0xFF;
255         header->flags1 = FLAGS_MASK_RD;
256         header->flags2 = 0;
257         header->qdcount = 1;
258         header->ancount = 0;
259         header->nscount = 0;
260         header->arcount = 0;
261
262         /* At this point we already know the id doesnt exist,
263          * so there needs to be no second check for the ::end()
264          */
265         requests[id] = req;
266
267         /* According to the C++ spec, new never returns NULL. */
268         return req;
269 }
270
271 int DNS::ClearCache()
272 {
273         /* This ensures the buckets are reset to sane levels */
274         int rv = this->cache->size();
275         delete this->cache;
276         this->cache = new dnscache();
277         return rv;
278 }
279
280 int DNS::PruneCache()
281 {
282         int n = 0;
283         dnscache* newcache = new dnscache();
284         for (dnscache::iterator i = this->cache->begin(); i != this->cache->end(); i++)
285                 /* Dont include expired items (theres no point) */
286                 if (i->second.CalcTTLRemaining())
287                         newcache->insert(*i);
288                 else
289                         n++;
290
291         delete this->cache;
292         this->cache = newcache;
293         ServerInstance->Log(DEBUG,"Prune %d expired cache items", n);
294         return n;
295 }
296
297 void DNS::Rehash()
298 {
299         insp_inaddr addr;
300         ip6munge = false;
301
302         if (this->GetFd() > -1)
303         {
304                 if (ServerInstance && ServerInstance->SE)
305                         ServerInstance->SE->DelFd(this);
306                 shutdown(this->GetFd(), 2);
307                 close(this->GetFd());
308                 this->SetFd(-1);
309
310                 /* Rehash the cache */
311                 this->PruneCache();
312         }
313         else
314         {
315                 /* Create initial dns cache */
316                 this->cache = new dnscache();
317         }
318
319         if (insp_aton(ServerInstance->Config->DNSServer,&addr) > 0)
320         {
321                 memcpy(&myserver,&addr,sizeof(insp_inaddr));
322                 if ((strstr(ServerInstance->Config->DNSServer,"::ffff:") == (char*)&ServerInstance->Config->DNSServer) ||  (strstr(ServerInstance->Config->DNSServer,"::FFFF:") == (char*)&ServerInstance->Config->DNSServer))
323                 {
324                         ServerInstance->Log(DEFAULT,"WARNING: Using IPv4 addresses over IPv6 forces some DNS checks to be disabled.");
325                         ServerInstance->Log(DEFAULT,"         This should not cause a problem, however it is recommended you migrate");
326                         ServerInstance->Log(DEFAULT,"         to a true IPv6 environment.");
327                         this->ip6munge = true;
328                 }
329                 ServerInstance->Log(DEBUG,"Added nameserver '%s'",ServerInstance->Config->DNSServer);
330         }
331         else
332         {
333                 ServerInstance->Log(DEBUG,"GACK! insp_aton says the nameserver '%s' is invalid!",ServerInstance->Config->DNSServer);
334         }
335
336         /* Initialize mastersocket */
337         this->SetFd(socket(PF_PROTOCOL, SOCK_DGRAM, 0));
338         if (this->GetFd() != -1)
339         {
340                 /* Did it succeed? */
341                 if (fcntl(this->GetFd(), F_SETFL, O_NONBLOCK) != 0)
342                 {
343                         /* Couldn't make the socket nonblocking */
344                         shutdown(this->GetFd(),2);
345                         close(this->GetFd());
346                         this->SetFd(-1);
347                 }
348         }
349         else
350         {
351                 ServerInstance->Log(DEBUG,"I cant socket() this socket! (%s)",strerror(errno));
352         }
353
354         /* Have we got a socket and is it nonblocking? */
355         if (this->GetFd() != -1)
356         {
357 #ifdef IPV6
358                 insp_sockaddr addr;
359                 memset(&addr,0,sizeof(addr));
360                 addr.sin6_family = AF_FAMILY;
361                 addr.sin6_port = 0;
362                 addr.sin6_addr = in6addr_any;
363 #else
364                 insp_sockaddr addr;
365                 memset(&addr,0,sizeof(addr));
366                 addr.sin_family = AF_FAMILY;
367                 addr.sin_port = 0;
368                 addr.sin_addr.s_addr = INADDR_ANY;
369 #endif
370                 /* Bind the port */
371                 if (bind(this->GetFd(),(sockaddr *)&addr,sizeof(addr)) != 0)
372                 {
373                         /* Failed to bind */
374                         ServerInstance->Log(DEBUG,"Cant bind DNS fd");
375                         shutdown(this->GetFd(),2);
376                         close(this->GetFd());
377                         this->SetFd(-1);
378                 }
379
380                 if (this->GetFd() >= 0)
381                 {
382                         ServerInstance->Log(DEBUG,"Add master socket %d",this->GetFd());
383                         /* Hook the descriptor into the socket engine */
384                         if (ServerInstance && ServerInstance->SE)
385                         {
386                                 if (!ServerInstance->SE->AddFd(this))
387                                 {
388                                         ServerInstance->Log(DEFAULT,"Internal error starting DNS - hostnames will NOT resolve.");
389                                         shutdown(this->GetFd(),2);
390                                         close(this->GetFd());
391                                         this->SetFd(-1);
392                                 }
393                         }
394                 }
395         }
396 }
397
398 /** Initialise the DNS UDP socket so that we can send requests */
399 DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
400 {
401         ServerInstance->Log(DEBUG,"DNS::DNS: Instance = %08x",Instance);
402
403         /* Clear the Resolver class table */
404         memset(Classes,0,sizeof(Classes));
405
406         /* Clear the requests class table */
407         memset(requests,0,sizeof(requests));
408
409         /* Set the id of the next request to 0
410          */
411         currid = 0;
412
413         /* DNS::Rehash() sets this to a valid ptr
414          */
415         this->cache = NULL;
416         
417         /* Again, DNS::Rehash() sets this to a
418          * valid value
419          */
420         this->SetFd(-1);
421
422         /* Actually read the settings
423          */
424         this->Rehash();
425
426         this->PruneTimer = new CacheTimer(ServerInstance, this);
427
428         ServerInstance->Timers->AddTimer(this->PruneTimer);
429 }
430
431 /** Build a payload to be placed after the header, based upon input data, a resource type, a class and a pointer to a buffer */
432 int DNS::MakePayload(const char * const name, const QueryType rr, const unsigned short rr_class, unsigned char * const payload)
433 {
434         short payloadpos = 0;
435         const char* tempchr, *tempchr2 = name;
436         unsigned short length;
437
438         /* split name up into labels, create query */
439         while ((tempchr = strchr(tempchr2,'.')) != NULL)
440         {
441                 length = tempchr - tempchr2;
442                 if (payloadpos + length + 1 > 507)
443                         return -1;
444                 payload[payloadpos++] = length;
445                 memcpy(&payload[payloadpos],tempchr2,length);
446                 payloadpos += length;
447                 tempchr2 = &tempchr[1];
448         }
449         length = strlen(tempchr2);
450         if (length)
451         {
452                 if (payloadpos + length + 2 > 507)
453                         return -1;
454                 payload[payloadpos++] = length;
455                 memcpy(&payload[payloadpos],tempchr2,length);
456                 payloadpos += length;
457                 payload[payloadpos++] = 0;
458         }
459         if (payloadpos > 508)
460                 return -1;
461         length = htons(rr);
462         memcpy(&payload[payloadpos],&length,2);
463         length = htons(rr_class);
464         memcpy(&payload[payloadpos + 2],&length,2);
465         return payloadpos + 4;
466 }
467
468 /** Start lookup of an hostname to an IP address */
469 int DNS::GetIP(const char *name)
470 {
471         DNSHeader h;
472         int id;
473         int length;
474         
475         if ((length = this->MakePayload(name, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1)
476                 return -1;
477
478         DNSRequest* req = this->AddQuery(&h, id, name);
479
480         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_A) == -1))
481                 return -1;
482
483         return id;
484 }
485
486 /** Start lookup of an hostname to an IPv6 address */
487 int DNS::GetIP6(const char *name)
488 {
489         DNSHeader h;
490         int id;
491         int length;
492
493         if ((length = this->MakePayload(name, DNS_QUERY_AAAA, 1, (unsigned char*)&h.payload)) == -1)
494                 return -1;
495
496         DNSRequest* req = this->AddQuery(&h, id, name);
497
498         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_AAAA) == -1))
499                 return -1;
500
501         return id;
502 }
503
504 /** Start lookup of a cname to another name */
505 int DNS::GetCName(const char *alias)
506 {
507         DNSHeader h;
508         int id;
509         int length;
510
511         if ((length = this->MakePayload(alias, DNS_QUERY_CNAME, 1, (unsigned char*)&h.payload)) == -1)
512                 return -1;
513
514         DNSRequest* req = this->AddQuery(&h, id, alias);
515
516         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_CNAME) == -1))
517                 return -1;
518
519         return id;
520 }
521
522 /** Start lookup of an IP address to a hostname */
523 int DNS::GetName(const insp_inaddr *ip)
524 {
525         char query[128];
526         DNSHeader h;
527         int id;
528         int length;
529
530 #ifdef IPV6
531         unsigned char* c = (unsigned char*)&ip->s6_addr;
532         if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
533             c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
534             c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
535                 sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
536         else
537                 DNS::MakeIP6Int(query, (in6_addr*)ip);
538 #else
539         unsigned char* c = (unsigned char*)&ip->s_addr;
540         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
541 #endif
542
543         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
544                 return -1;
545
546         DNSRequest* req = this->AddQuery(&h, id, insp_ntoa(*ip));
547
548         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
549                 return -1;
550
551         return id;
552 }
553
554 /** Start lookup of an IP address to a hostname */
555 int DNS::GetNameForce(const char *ip, ForceProtocol fp)
556 {
557         char query[128];
558         DNSHeader h;
559         int id;
560         int length;
561 #ifdef SUPPORT_IP6LINKS
562         if (fp == PROTOCOL_IPV6)
563         {
564                 in6_addr i;
565                 if (inet_pton(AF_INET6, ip, &i) > 0)
566                 {
567                         DNS::MakeIP6Int(query, &i);
568                 }
569                 else
570                         /* Invalid IP address */
571                         return -1;
572         }
573         else
574 #endif
575         {
576                 in_addr i;
577                 if (inet_aton(ip, &i))
578                 {
579                         unsigned char* c = (unsigned char*)&i.s_addr;
580                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
581                 }
582                 else
583                         /* Invalid IP address */
584                         return -1;
585         }
586
587         ServerInstance->Log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
588
589         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
590                 return -1;
591
592         DNSRequest* req = this->AddQuery(&h, id, ip);
593
594         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
595                 return -1;
596
597         return id;
598 }
599
600 /** Build an ipv6 reverse domain from an in6_addr
601  */
602 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
603 {
604 #ifdef SUPPORT_IP6LINKS
605         const char* hex = "0123456789abcdef";
606         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
607         {
608                 if (index % 2)
609                         /* low nibble */
610                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
611                 else
612                         /* high nibble */
613                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
614                 *query++ = '.'; /* Seperator */
615         }
616         strcpy(query,"ip6.arpa"); /* Suffix the string */
617 #else
618         *query = 0;
619 #endif
620 }
621
622 /** Return the next id which is ready, and the result attached to it */
623 DNSResult DNS::GetResult()
624 {
625         /* Fetch dns query response and decide where it belongs */
626         DNSHeader header;
627         DNSRequest *req;
628         unsigned char buffer[sizeof(DNSHeader)];
629         sockaddr from;
630         socklen_t x = sizeof(from);
631         const char* ipaddr_from = "";
632         unsigned short int port_from = 0;
633
634         int length = recvfrom(this->GetFd(),buffer,sizeof(DNSHeader),0,&from,&x);
635
636         if (length < 0)
637                 ServerInstance->Log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
638
639         /* Did we get the whole header? */
640         if (length < 12)
641         {
642                 /* Nope - something screwed up. */
643                 ServerInstance->Log(DEBUG,"Whole header not read!");
644                 return DNSResult(-1,"",0,"");
645         }
646
647         /* Check wether the reply came from a different DNS
648          * server to the one we sent it to, or the source-port
649          * is not 53.
650          * A user could in theory still spoof dns packets anyway
651          * but this is less trivial than just sending garbage
652          * to the client, which is possible without this check.
653          *
654          * -- Thanks jilles for pointing this one out.
655          */
656 #ifdef IPV6
657         ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
658         port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
659 #else
660         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
661         port_from = ntohs(((sockaddr_in*)&from)->sin_port);
662 #endif
663
664         /* We cant perform this security check if you're using 4in6.
665          * Tough luck to you, choose one or't other!
666          */
667         if (!ip6munge)
668         {
669                 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, ServerInstance->Config->DNSServer)))
670                 {
671                         ServerInstance->Log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, ServerInstance->Config->DNSServer);
672                         return DNSResult(-1,"",0,"");
673                 }
674         }
675
676         /* Put the read header info into a header class */
677         DNS::FillHeader(&header,buffer,length - 12);
678
679         /* Get the id of this request.
680          * Its a 16 bit value stored in two char's,
681          * so we use logic shifts to create the value.
682          */
683         unsigned long this_id = header.id[1] + (header.id[0] << 8);
684
685         /* Do we have a pending request matching this id? */
686         if (!requests[this_id])
687         {
688                 /* Somehow we got a DNS response for a request we never made... */
689                 ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
690                 return DNSResult(-1,"",0,"");
691         }
692         else
693         {
694                 /* Remove the query from the list of pending queries */
695                 req = requests[this_id];
696                 requests[this_id] = NULL;
697         }
698
699         /* Inform the DNSRequest class that it has a result to be read.
700          * When its finished it will return a DNSInfo which is a pair of
701          * unsigned char* resource record data, and an error message.
702          */
703         DNSInfo data = req->ResultIsReady(header, length);
704         std::string resultstr;
705
706         /* Check if we got a result, if we didnt, its an error */
707         if (data.first == NULL)
708         {
709                 /* An error.
710                  * Mask the ID with the value of ERROR_MASK, so that
711                  * the dns_deal_with_classes() function knows that its
712                  * an error response and needs to be treated uniquely.
713                  * Put the error message in the second field.
714                  */
715                 std::string ro = req->orig;
716                 delete req;
717                 return DNSResult(this_id | ERROR_MASK, data.second, 0, ro);
718         }
719         else
720         {
721                 unsigned long ttl = req->ttl;
722                 char formatted[128];
723
724                 /* Forward lookups come back as binary data. We must format them into ascii */
725                 switch (req->type)
726                 {
727                         case DNS_QUERY_A:
728                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
729                                 resultstr = formatted;
730                         break;
731
732                         case DNS_QUERY_AAAA:
733                         {
734                                 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
735                                                 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
736                                                 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
737                                                 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
738                                                 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
739                                                 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
740                                                 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
741                                                 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
742                                                 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
743                                 char* c = strstr(formatted,":0:");
744                                 if (c != NULL)
745                                 {
746                                         memmove(c+1,c+2,strlen(c+2) + 1);
747                                         c += 2;
748                                         while (memcmp(c,"0:",2) == 0)
749                                                 memmove(c,c+2,strlen(c+2) + 1);
750                                         if (memcmp(c,"0",2) == 0)
751                                                 *c = 0;
752                                         if (memcmp(formatted,"0::",3) == 0)
753                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
754                                 }
755                                 resultstr = formatted;
756
757                                 /* Special case. Sending ::1 around between servers
758                                  * and to clients is dangerous, because the : on the
759                                  * start makes the client or server interpret the IP
760                                  * as the last parameter on the line with a value ":1".
761                                  */
762                                 if (*formatted == ':')
763                                         resultstr = "0" + resultstr;
764                         }
765                         break;
766
767                         case DNS_QUERY_CNAME:
768                                 /* Identical handling to PTR */
769
770                         case DNS_QUERY_PTR:
771                                 /* Reverse lookups just come back as char* */
772                                 resultstr = std::string((const char*)data.first);
773                         break;
774
775                         default:
776                                 ServerInstance->Log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
777                         break;
778                         
779                 }
780
781                 /* Build the reply with the id and hostname/ip in it */
782                 std::string ro = req->orig;
783                 delete req;
784                 return DNSResult(this_id,resultstr,ttl,ro);
785         }
786 }
787
788 /** A result is ready, process it */
789 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
790 {
791         int i = 0;
792         int q = 0;
793         int curanswer, o;
794         ResourceRecord rr;
795         unsigned short ptr;
796
797         /* This is just to keep _FORTIFY_SOURCE happy */
798         rr.type = DNS_QUERY_NONE;
799         rr.rdlength = 0;
800
801         if (!(header.flags1 & FLAGS_MASK_QR))
802                 return std::make_pair((unsigned char*)NULL,"Not a query result");
803
804         if (header.flags1 & FLAGS_MASK_OPCODE)
805                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
806
807         if (header.flags2 & FLAGS_MASK_RCODE)
808                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
809
810         if (header.ancount < 1)
811                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
812
813         /* Subtract the length of the header from the length of the packet */
814         length -= 12;
815
816         while ((unsigned int)q < header.qdcount && i < length)
817         {
818                 if (header.payload[i] > 63)
819                 {
820                         i += 6;
821                         q++;
822                 }
823                 else
824                 {
825                         if (header.payload[i] == 0)
826                         {
827                                 q++;
828                                 i += 5;
829                         }
830                         else i += header.payload[i] + 1;
831                 }
832         }
833         curanswer = 0;
834         while ((unsigned)curanswer < header.ancount)
835         {
836                 q = 0;
837                 while (q == 0 && i < length)
838                 {
839                         if (header.payload[i] > 63)
840                         {
841                                 i += 2;
842                                 q = 1;
843                         }
844                         else
845                         {
846                                 if (header.payload[i] == 0)
847                                 {
848                                         i++;
849                                         q = 1;
850                                 }
851                                 else i += header.payload[i] + 1; /* skip length and label */
852                         }
853                 }
854                 if (length - i < 10)
855                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
856
857                 DNS::FillResourceRecord(&rr,&header.payload[i]);
858                 i += 10;
859                 if (rr.type != this->type)
860                 {
861                         curanswer++;
862                         i += rr.rdlength;
863                         continue;
864                 }
865                 if (rr.rr_class != this->rr_class)
866                 {
867                         curanswer++;
868                         i += rr.rdlength;
869                         continue;
870                 }
871                 break;
872         }
873         if ((unsigned int)curanswer == header.ancount)
874                 return std::make_pair((unsigned char*)NULL,"No valid answers");
875
876         if (i + rr.rdlength > (unsigned int)length)
877                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
878
879         if (rr.rdlength > 1023)
880                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
881
882         this->ttl = rr.ttl;
883
884         switch (rr.type)
885         {
886                 case DNS_QUERY_CNAME:
887                         /* CNAME and PTR have the same processing code */
888                 case DNS_QUERY_PTR:
889                         o = 0;
890                         q = 0;
891                         while (q == 0 && i < length && o + 256 < 1023)
892                         {
893                                 if (header.payload[i] > 63)
894                                 {
895                                         memcpy(&ptr,&header.payload[i],2);
896                                         i = ntohs(ptr) - 0xC000 - 12;
897                                 }
898                                 else
899                                 {
900                                         if (header.payload[i] == 0)
901                                         {
902                                                 q = 1;
903                                         }
904                                         else
905                                         {
906                                                 res[o] = 0;
907                                                 if (o != 0)
908                                                         res[o++] = '.';
909                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
910                                                 o += header.payload[i];
911                                                 i += header.payload[i] + 1;
912                                         }
913                                 }
914                         }
915                         res[o] = 0;
916                 break;
917                 case DNS_QUERY_AAAA:
918                         memcpy(res,&header.payload[i],rr.rdlength);
919                         res[rr.rdlength] = 0;
920                 break;
921                 case DNS_QUERY_A:
922                         memcpy(res,&header.payload[i],rr.rdlength);
923                         res[rr.rdlength] = 0;
924                 break;
925                 default:
926                         memcpy(res,&header.payload[i],rr.rdlength);
927                         res[rr.rdlength] = 0;
928                 break;
929         }
930         return std::make_pair(res,"No error");;
931 }
932
933 /** Close the master socket */
934 DNS::~DNS()
935 {
936         shutdown(this->GetFd(), 2);
937         close(this->GetFd());
938         ServerInstance->Timers->DelTimer(this->PruneTimer);
939         delete this->PruneTimer;
940 }
941
942 CachedQuery* DNS::GetCache(const std::string &source)
943 {
944         dnscache::iterator x = cache->find(source.c_str());
945         if (x != cache->end())
946                 return &(x->second);
947         else
948                 return NULL;
949 }
950                 
951 void DNS::DelCache(const std::string &source)
952 {
953         cache->erase(source.c_str());
954 }
955
956 void Resolver::TriggerCachedResult()
957 {
958         if (CQ)
959                 OnLookupComplete(CQ->data, time_left, true);
960 }
961
962 /** High level abstraction of dns used by application at large */
963 Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, bool &cached, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
964 {
965         ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
966
967         cached = false;
968
969         CQ = ServerInstance->Res->GetCache(source);
970         if (CQ)
971         {
972                 time_left = CQ->CalcTTLRemaining();
973                 if (!time_left)
974                 {
975                         ServerInstance->Log(DEBUG,"Cached but EXPIRED result: %s", CQ->data.c_str());
976                         ServerInstance->Res->DelCache(source);
977                 }
978                 else
979                 {
980                         cached = true;
981                         ServerInstance->Log(DEBUG,"Cached result: %s", CQ->data.c_str());
982                         return;
983                 }
984         }
985
986         insp_inaddr binip;
987
988         switch (querytype)
989         {
990                 case DNS_QUERY_A:
991                         this->myid = ServerInstance->Res->GetIP(source.c_str());
992                 break;
993
994                 case DNS_QUERY_PTR:
995                         if (insp_aton(source.c_str(), &binip) > 0)
996                         {
997                                 /* Valid ip address */
998                                 this->myid = ServerInstance->Res->GetName(&binip);
999                         }
1000                         else
1001                         {
1002                                 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
1003                                 throw ModuleException("Resolver: Bad IP address");
1004                                 return;
1005                         }
1006                 break;
1007
1008                 case DNS_QUERY_PTR4:
1009                         querytype = DNS_QUERY_PTR;
1010                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
1011                 break;
1012
1013                 case DNS_QUERY_PTR6:
1014                         querytype = DNS_QUERY_PTR;
1015                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
1016                 break;
1017
1018                 case DNS_QUERY_AAAA:
1019                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
1020                 break;
1021
1022                 case DNS_QUERY_CNAME:
1023                         this->myid = ServerInstance->Res->GetCName(source.c_str());
1024                 break;
1025
1026                 default:
1027                         this->myid = -1;
1028                 break;
1029         }
1030         if (this->myid == -1)
1031         {
1032                 ServerInstance->Log(DEBUG,"Resolver::Resolver: Could not get an id!");
1033                 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
1034                 throw ModuleException("Resolver: Couldnt get an id to make a request");
1035                 /* We shouldnt get here really */
1036                 return;
1037         }
1038
1039         ServerInstance->Log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
1040 }
1041
1042 /** Called when an error occurs */
1043 void Resolver::OnError(ResolverError e, const std::string &errormessage)
1044 {
1045         /* Nothing in here */
1046 }
1047
1048 /** Destroy a resolver */
1049 Resolver::~Resolver()
1050 {
1051         /* Nothing here (yet) either */
1052 }
1053
1054 /** Get the request id associated with this class */
1055 int Resolver::GetId()
1056 {
1057         return this->myid;
1058 }
1059
1060 Module* Resolver::GetCreator()
1061 {
1062         return this->Creator;
1063 }
1064
1065 /** Process a socket read event */
1066 void DNS::HandleEvent(EventType et, int errornum)
1067 {
1068         /* Fetch the id and result of the next available packet */
1069         DNSResult res = this->GetResult();
1070         /* Is there a usable request id? */
1071         if (res.id != -1)
1072         {
1073                 /* Its an error reply */
1074                 if (res.id & ERROR_MASK)
1075                 {
1076                         /* Mask off the error bit */
1077                         res.id -= ERROR_MASK;
1078                         /* Marshall the error to the correct class */
1079                         ServerInstance->Log(DEBUG,"Error available, id=%d",res.id);
1080                         if (Classes[res.id])
1081                         {
1082                                 if (ServerInstance && ServerInstance->stats)
1083                                         ServerInstance->stats->statsDnsBad++;
1084                                 Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result);
1085                                 delete Classes[res.id];
1086                                 Classes[res.id] = NULL;
1087                         }
1088                 }
1089                 else
1090                 {
1091                         /* It is a non-error result */
1092                         ServerInstance->Log(DEBUG,"Result available, id=%d",res.id);
1093                         /* Marshall the result to the correct class */
1094                         if (Classes[res.id])
1095                         {
1096                                 if (ServerInstance && ServerInstance->stats)
1097                                         ServerInstance->stats->statsDnsGood++;
1098
1099                                 if (!this->GetCache(res.original.c_str()))
1100                                 {
1101                                         ServerInstance->Log(DEBUG,"Caching result: %s->%s for %lu secs", res.original.c_str(), res.result.c_str(), res.ttl);
1102                                         this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
1103                                 }
1104
1105                                 Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
1106                                 delete Classes[res.id];
1107                                 Classes[res.id] = NULL;
1108                         }
1109                 }
1110
1111                 if (ServerInstance && ServerInstance->stats)
1112                         ServerInstance->stats->statsDns++;
1113         }
1114 }
1115
1116 /** Add a derived Resolver to the working set */
1117 bool DNS::AddResolverClass(Resolver* r)
1118 {
1119         /* Check the pointers validity and the id's validity */
1120         if ((r) && (r->GetId() > -1))
1121         {
1122                 /* Check the slot isnt already occupied -
1123                  * This should NEVER happen unless we have
1124                  * a severely broken DNS server somewhere
1125                  */
1126                 if (!Classes[r->GetId()])
1127                 {
1128                         /* Set up the pointer to the class */
1129                         Classes[r->GetId()] = r;
1130                         return true;
1131                 }
1132                 else
1133                         /* Duplicate id */
1134                         return false;
1135         }
1136         else
1137         {
1138                 /* Pointer or id not valid.
1139                  * Free the item and return
1140                  */
1141                 if (r)
1142                         delete r;
1143
1144                 return false;
1145         }
1146 }
1147
1148 void DNS::CleanResolvers(Module* module)
1149 {
1150         for (int i = 0; i < MAX_REQUEST_ID; i++)
1151         {
1152                 if (Classes[i])
1153                 {
1154                         if (Classes[i]->GetCreator() == module)
1155                         {
1156                                 Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
1157                                 delete Classes[i];
1158                                 Classes[i] = NULL;
1159                         }
1160                 }
1161         }
1162 }
1163
1164 /** Generate pseudo-random number */
1165 unsigned long DNS::PRNG()
1166 {
1167         unsigned long val = 0;
1168         timeval n;
1169         serverstats* s = ServerInstance->stats;
1170         gettimeofday(&n,NULL);
1171         val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
1172         val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
1173         val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;
1174         return val;
1175 }
1176