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