]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
0436095b6bd30afc315837138fd0f7402a4c1891
[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 #ifdef SUPPORT_IP6LINKS
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 #endif
470         {
471                 in_addr i;
472                 if (inet_aton(ip, &i))
473                 {
474                         unsigned char* c = (unsigned char*)&i.s_addr;
475                         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
476                 }
477                 else
478                         /* Invalid IP address */
479                         return -1;
480         }
481
482         log(DEBUG,"DNS::GetNameForce: %s %d",query, fp);
483
484         if ((length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload)) == -1)
485                 return -1;
486
487         DNSRequest* req = this->AddQuery(&h, id);
488
489         if ((!req) || (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1))
490                 return -1;
491
492         return id;
493 }
494
495 void DNS::MakeIP6Int(char* query, const in6_addr *ip)
496 {
497 #ifdef SUPPORT_IP6LINKS
498         const char* hex = "0123456789abcdef";
499         for (int index = 31; index >= 0; index--) /* for() loop steps twice per byte */
500         {
501                 if (index % 2)
502                         /* low nibble */
503                         *query++ = hex[ip->s6_addr[index / 2] & 0x0F];
504                 else
505                         /* high nibble */
506                         *query++ = hex[(ip->s6_addr[index / 2] & 0xF0) >> 4];
507                 *query++ = '.'; /* Seperator */
508         }
509         strcpy(query,"ip6.arpa"); /* Suffix the string */
510 #else
511         *query = 0;
512 #endif
513 }
514
515 /* Return the next id which is ready, and the result attached to it */
516 DNSResult DNS::GetResult()
517 {
518         /* Fetch dns query response and decide where it belongs */
519         DNSHeader header;
520         DNSRequest *req;
521         unsigned char buffer[sizeof(DNSHeader)];
522         sockaddr from;
523         socklen_t x = sizeof(from);
524         const char* ipaddr_from = "";
525         unsigned short int port_from = 0;
526
527         int length = recvfrom(MasterSocket,buffer,sizeof(DNSHeader),0,&from,&x);
528
529         if (length < 0)
530                 log(DEBUG,"Error in recvfrom()! (%s)",strerror(errno));
531
532         /* Did we get the whole header? */
533         if (length < 12)
534         {
535                 /* Nope - something screwed up. */
536                 log(DEBUG,"Whole header not read!");
537                 return std::make_pair(-1,"");
538         }
539
540         /* Check wether the reply came from a different DNS
541          * server to the one we sent it to, or the source-port
542          * is not 53.
543          * A user could in theory still spoof dns packets anyway
544          * but this is less trivial than just sending garbage
545          * to the client, which is possible without this check.
546          *
547          * -- Thanks jilles for pointing this one out.
548          */
549 #ifdef IPV6
550         ipaddr_from = insp_ntoa(((sockaddr_in6*)&from)->sin6_addr);
551         port_from = ntohs(((sockaddr_in6*)&from)->sin6_port);
552 #else
553         ipaddr_from = insp_ntoa(((sockaddr_in*)&from)->sin_addr);
554         port_from = ntohs(((sockaddr_in*)&from)->sin_port);
555 #endif
556
557         /* We cant perform this security check if you're using 4in6.
558          * Tough luck to you, choose one or't other!
559          */
560         if (!ip6munge)
561         {
562                 if ((port_from != DNS::QUERY_PORT) || (strcasecmp(ipaddr_from, Config->DNSServer)))
563                 {
564                         log(DEBUG,"port %d is not 53, or %s is not %s",port_from, ipaddr_from, Config->DNSServer);
565                         return std::make_pair(-1,"");
566                 }
567         }
568
569         /* Put the read header info into a header class */
570         DNS::FillHeader(&header,buffer,length - 12);
571
572         /* Get the id of this request.
573          * Its a 16 bit value stored in two char's,
574          * so we use logic shifts to create the value.
575          */
576         unsigned long this_id = header.id[1] + (header.id[0] << 8);
577
578         /* Do we have a pending request matching this id? */
579         requestlist_iter n_iter = requests.find(this_id);
580         if (n_iter == requests.end())
581         {
582                 /* Somehow we got a DNS response for a request we never made... */
583                 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",MasterSocket,this_id);
584                 return std::make_pair(-1,"");
585         }
586         else
587         {
588                 /* Remove the query from the list of pending queries */
589                 req = (DNSRequest*)n_iter->second;
590                 requests.erase(n_iter);
591         }
592
593         /* Inform the DNSRequest class that it has a result to be read.
594          * When its finished it will return a DNSInfo which is a pair of
595          * unsigned char* resource record data, and an error message.
596          */
597         DNSInfo data = req->ResultIsReady(header, length);
598         std::string resultstr;
599
600         /* Check if we got a result, if we didnt, its an error */
601         if (data.first == NULL)
602         {
603                 /* An error.
604                  * Mask the ID with the value of ERROR_MASK, so that
605                  * the dns_deal_with_classes() function knows that its
606                  * an error response and needs to be treated uniquely.
607                  * Put the error message in the second field.
608                  */
609                 delete req;
610                 return std::make_pair(this_id | ERROR_MASK, data.second);
611         }
612         else
613         {
614                 char formatted[128];
615
616                 /* Forward lookups come back as binary data. We must format them into ascii */
617                 switch (req->type)
618                 {
619                         case DNS_QUERY_A:
620                                 snprintf(formatted,16,"%u.%u.%u.%u",data.first[0],data.first[1],data.first[2],data.first[3]);
621                                 resultstr = formatted;
622                         break;
623
624                         case DNS_QUERY_AAAA:
625                         {
626                                 snprintf(formatted,40,"%x:%x:%x:%x:%x:%x:%x:%x",
627                                                 (ntohs(data.first[0]) + ntohs(data.first[1] << 8)),
628                                                 (ntohs(data.first[2]) + ntohs(data.first[3] << 8)),
629                                                 (ntohs(data.first[4]) + ntohs(data.first[5] << 8)),
630                                                 (ntohs(data.first[6]) + ntohs(data.first[7] << 8)),
631                                                 (ntohs(data.first[8]) + ntohs(data.first[9] << 8)),
632                                                 (ntohs(data.first[10]) + ntohs(data.first[11] << 8)),
633                                                 (ntohs(data.first[12]) + ntohs(data.first[13] << 8)),
634                                                 (ntohs(data.first[14]) + ntohs(data.first[15] << 8)));
635                                 char* c = strstr(formatted,":0:");
636                                 if (c != NULL)
637                                 {
638                                         memmove(c+1,c+2,strlen(c+2) + 1);
639                                         c += 2;
640                                         while (memcmp(c,"0:",2) == 0)
641                                                 memmove(c,c+2,strlen(c+2) + 1);
642                                         if (memcmp(c,"0",2) == 0)
643                                                 *c = 0;
644                                         if (memcmp(formatted,"0::",3) == 0)
645                                                 memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
646                                 }
647                                 resultstr = formatted;
648
649                                 /* Special case. Sending ::1 around between servers
650                                  * and to clients is dangerous, because the : on the
651                                  * start makes the client or server interpret the IP
652                                  * as the last parameter on the line with a value ":1".
653                                  */
654                                 if (*formatted == ':')
655                                         resultstr = "0" + resultstr;
656                         }
657                         break;
658
659                         case DNS_QUERY_CNAME:
660                                 /* Identical handling to PTR */
661
662                         case DNS_QUERY_PTR:
663                                 /* Reverse lookups just come back as char* */
664                                 resultstr = std::string((const char*)data.first);
665                         break;
666
667                         default:
668                                 log(DEBUG,"WARNING: Somehow we made a request for a DNS_QUERY_PTR4 or DNS_QUERY_PTR6, but these arent real rr types!");
669                         break;
670                         
671                 }
672
673                 /* Build the reply with the id and hostname/ip in it */
674                 delete req;
675                 return std::make_pair(this_id,resultstr);
676         }
677 }
678
679 /* A result is ready, process it */
680 DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
681 {
682         int i = 0;
683         int q = 0;
684         int curanswer, o;
685         ResourceRecord rr;
686         unsigned short ptr;
687                         
688         if (!(header.flags1 & FLAGS_MASK_QR))
689                 return std::make_pair((unsigned char*)NULL,"Not a query result");
690
691         if (header.flags1 & FLAGS_MASK_OPCODE)
692                 return std::make_pair((unsigned char*)NULL,"Unexpected value in DNS reply packet");
693
694         if (header.flags2 & FLAGS_MASK_RCODE)
695                 return std::make_pair((unsigned char*)NULL,"Domain name not found");
696
697         if (header.ancount < 1)
698                 return std::make_pair((unsigned char*)NULL,"No resource records returned");
699
700         /* Subtract the length of the header from the length of the packet */
701         length -= 12;
702
703         while ((unsigned int)q < header.qdcount && i < length)
704         {
705                 if (header.payload[i] > 63)
706                 {
707                         i += 6;
708                         q++;
709                 }
710                 else
711                 {
712                         if (header.payload[i] == 0)
713                         {
714                                 q++;
715                                 i += 5;
716                         }
717                         else i += header.payload[i] + 1;
718                 }
719         }
720         curanswer = 0;
721         while ((unsigned)curanswer < header.ancount)
722         {
723                 q = 0;
724                 while (q == 0 && i < length)
725                 {
726                         if (header.payload[i] > 63)
727                         {
728                                 i += 2;
729                                 q = 1;
730                         }
731                         else
732                         {
733                                 if (header.payload[i] == 0)
734                                 {
735                                         i++;
736                                         q = 1;
737                                 }
738                                 else i += header.payload[i] + 1; /* skip length and label */
739                         }
740                 }
741                 if (length - i < 10)
742                         return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
743
744                 DNS::FillResourceRecord(&rr,&header.payload[i]);
745                 i += 10;
746                 if (rr.type != this->type)
747                 {
748                         curanswer++;
749                         i += rr.rdlength;
750                         continue;
751                 }
752                 if (rr.rr_class != this->rr_class)
753                 {
754                         curanswer++;
755                         i += rr.rdlength;
756                         continue;
757                 }
758                 break;
759         }
760         if ((unsigned int)curanswer == header.ancount)
761                 return std::make_pair((unsigned char*)NULL,"No valid answers");
762
763         if (i + rr.rdlength > (unsigned int)length)
764                 return std::make_pair((unsigned char*)NULL,"Resource record larger than stated");
765
766         if (rr.rdlength > 1023)
767                 return std::make_pair((unsigned char*)NULL,"Resource record too large");
768
769         switch (rr.type)
770         {
771                 case DNS_QUERY_CNAME:
772                         /* CNAME and PTR have the same processing code */
773                 case DNS_QUERY_PTR:
774                         o = 0;
775                         q = 0;
776                         while (q == 0 && i < length && o + 256 < 1023)
777                         {
778                                 if (header.payload[i] > 63)
779                                 {
780                                         memcpy(&ptr,&header.payload[i],2);
781                                         i = ntohs(ptr) - 0xC000 - 12;
782                                 }
783                                 else
784                                 {
785                                         if (header.payload[i] == 0)
786                                         {
787                                                 q = 1;
788                                         }
789                                         else
790                                         {
791                                                 res[o] = 0;
792                                                 if (o != 0)
793                                                         res[o++] = '.';
794                                                 memcpy(&res[o],&header.payload[i + 1],header.payload[i]);
795                                                 o += header.payload[i];
796                                                 i += header.payload[i] + 1;
797                                         }
798                                 }
799                         }
800                         res[o] = 0;
801                 break;
802                 case DNS_QUERY_AAAA:
803                         memcpy(res,&header.payload[i],rr.rdlength);
804                         res[rr.rdlength] = 0;
805                 break;
806                 case DNS_QUERY_A:
807                         memcpy(res,&header.payload[i],rr.rdlength);
808                         res[rr.rdlength] = 0;
809                 break;
810                 default:
811                         memcpy(res,&header.payload[i],rr.rdlength);
812                         res[rr.rdlength] = 0;
813                 break;
814         }
815         return std::make_pair(res,"No error");;
816 }
817
818 /* Close the master socket */
819 DNS::~DNS()
820 {
821         shutdown(MasterSocket, 2);
822         close(MasterSocket);
823 }
824
825 /* High level abstraction of dns used by application at large */
826 Resolver::Resolver(const std::string &source, QueryType qt) : input(source), querytype(qt)
827 {
828         insp_inaddr binip;
829
830         switch (querytype)
831         {
832                 case DNS_QUERY_A:
833                         this->myid = ServerInstance->Res->GetIP(source.c_str());
834                 break;
835
836                 case DNS_QUERY_PTR:
837                         if (insp_aton(source.c_str(), &binip) > 0)
838                         {
839                                 /* Valid ip address */
840                                 this->myid = ServerInstance->Res->GetName(&binip);
841                         }
842                         else
843                         {
844                                 this->OnError(RESOLVER_BADIP, "Bad IP address for reverse lookup");
845                                 throw ModuleException("Resolver: Bad IP address");
846                                 return;
847                         }
848                 break;
849
850                 case DNS_QUERY_PTR4:
851                         querytype = DNS_QUERY_PTR;
852                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV4);
853                 break;
854
855                 case DNS_QUERY_PTR6:
856                         querytype = DNS_QUERY_PTR;
857                         this->myid = ServerInstance->Res->GetNameForce(source.c_str(), PROTOCOL_IPV6);
858                 break;
859
860                 case DNS_QUERY_AAAA:
861                         this->myid = ServerInstance->Res->GetIP6(source.c_str());
862                 break;
863
864                 case DNS_QUERY_CNAME:
865                         this->myid = ServerInstance->Res->GetCName(source.c_str());
866                 break;
867
868                 default:
869                         this->myid = -1;
870                 break;
871         }
872         if (this->myid == -1)
873         {
874                 log(DEBUG,"Resolver::Resolver: Could not get an id!");
875                 this->OnError(RESOLVER_NSDOWN, "Nameserver is down");
876                 throw ModuleException("Resolver: Couldnt get an id to make a request");
877                 /* We shouldnt get here really */
878                 return;
879         }
880
881         log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
882 }
883
884 void Resolver::OnError(ResolverError e, const std::string &errormessage)
885 {
886         /* Nothing in here */
887 }
888
889 Resolver::~Resolver()
890 {
891         /* Nothing here (yet) either */
892 }
893
894 /* Get the request id associated with this class */
895 int Resolver::GetId()
896 {
897         return this->myid;
898 }
899
900 /* Process a socket read event */
901 void DNS::MarshallReads(int fd)
902 {
903         log(DEBUG,"Marshall reads: %d %d",fd,GetMasterSocket());
904         /* We are only intrested in our single fd */
905         if (fd == GetMasterSocket())
906         {
907                 /* Fetch the id and result of the next available packet */
908                 DNSResult res = this->GetResult();
909                 /* Is there a usable request id? */
910                 if (res.first != -1)
911                 {
912                         /* Its an error reply */
913                         if (res.first & ERROR_MASK)
914                         {
915                                 /* Mask off the error bit */
916                                 res.first -= ERROR_MASK;
917
918                                 /* Marshall the error to the correct class */
919                                 log(DEBUG,"Error available, id=%d",res.first);
920                                 if (Classes[res.first])
921                                 {
922                                         if (ServerInstance && ServerInstance->stats)
923                                                 ServerInstance->stats->statsDnsBad++;
924                                         Classes[res.first]->OnError(RESOLVER_NXDOMAIN, res.second);
925                                         delete Classes[res.first];
926                                         Classes[res.first] = NULL;
927                                 }
928                         }
929                         else
930                         {
931                                 /* It is a non-error result */
932                                 log(DEBUG,"Result available, id=%d",res.first);
933                                 /* Marshall the result to the correct class */
934                                 if (Classes[res.first])
935                                 {
936                                         if (ServerInstance && ServerInstance->stats)
937                                                 ServerInstance->stats->statsDnsGood++;
938                                         Classes[res.first]->OnLookupComplete(res.second);
939                                         delete Classes[res.first];
940                                         Classes[res.first] = NULL;
941                                 }
942                         }
943
944                         if (ServerInstance && ServerInstance->stats)
945                                 ServerInstance->stats->statsDns++;
946
947                 }
948         }
949 }
950
951 /* Add a derived Resolver to the working set */
952 bool DNS::AddResolverClass(Resolver* r)
953 {
954         /* Check the pointers validity and the id's validity */
955         if ((r) && (r->GetId() > -1))
956         {
957                 /* Check the slot isnt already occupied -
958                  * This should NEVER happen unless we have
959                  * a severely broken DNS server somewhere
960                  */
961                 if (!Classes[r->GetId()])
962                 {
963                         /* Set up the pointer to the class */
964                         Classes[r->GetId()] = r;
965                         return true;
966                 }
967                 else
968                         /* Duplicate id */
969                         return false;
970         }
971         else
972         {
973                 /* Pointer or id not valid.
974                  * Free the item and return
975                  */
976                 if (r)
977                         delete r;
978
979                 return false;
980         }
981 }
982
983 unsigned long DNS::PRNG()
984 {
985         unsigned long val = 0;
986         timeval n;
987         serverstats* s = ServerInstance->stats;
988         gettimeofday(&n,NULL);
989         val = (n.tv_usec ^ getpid() ^ geteuid() ^ (this->currid++)) ^ s->statsAccept + n.tv_sec;
990         val = val + s->statsCollisions ^ s->statsDnsGood - s->statsDnsBad;
991         val += (s->statsConnects ^ (unsigned long)s->statsSent ^ (unsigned long)s->statsRecv) - s->BoundPortCount;
992         return val;
993 }
994