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