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