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