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