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