]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
e3a32a7458a5caf3c687630e60525277a218432c
[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 loosely based on the firedns library,
20 Copyright (C) 2002 Ian Gulliver.
21
22 There have been so many modifications to this file
23 to make it fit into InspIRCd and make it object
24 orientated that you should not take this code as
25 being what firedns really looks like. It used to
26 look very different to this! :-P
27 */
28
29 using namespace std;
30
31 #include <string>
32 #include <stdlib.h>
33 #include <time.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <stdio.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <poll.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <map>
48 #include <algorithm>
49 #include "dns.h"
50 #include "inspircd.h"
51 #include "helperfuncs.h"
52 #include "socketengine.h"
53 #include "configreader.h"
54
55 extern InspIRCd* ServerInstance;
56 extern ServerConfig* Config;
57 extern time_t TIME;
58
59 enum QueryType { DNS_QRY_A = 1, DNS_QRY_PTR = 12 };
60 enum QueryFlags1 { FLAGS1_MASK_RD = 0x01, FLAGS1_MASK_TC = 0x02, FLAGS1_MASK_AA = 0x04, FLAGS1_MASK_OPCODE = 0x78, FLAGS1_MASK_QR = 0x80 };
61 enum QueryFlags2 { FLAGS2_MASK_RCODE = 0x0F, FLAGS2_MASK_Z = 0x70, FLAGS2_MASK_RA = 0x80 };
62
63 class s_connection;
64
65 typedef std::map<int,s_connection*> connlist;
66 typedef connlist::iterator connlist_iter;
67 connlist connections;
68
69 Resolver* dns_classes[MAX_DESCRIPTORS];
70
71 struct in_addr servers4[8];
72 int i4;
73 int initdone = 0;
74 int wantclose = 0;
75 int lastcreate = -1;
76
77 class s_connection
78 {
79  public:
80         unsigned char   id[2];
81         unsigned int    _class;
82         QueryType       type;
83         int             want_list;
84         int             fd;
85 };
86
87 class s_rr_middle
88 {
89  public:
90         QueryType       type;
91         unsigned int    _class;
92         unsigned long   ttl;
93         unsigned int    rdlength;
94 };
95
96 class s_header
97 {
98  public:
99         unsigned char   id[2];
100         unsigned int    flags1;
101         unsigned int    flags2;
102         unsigned int    qdcount;
103         unsigned int    ancount;
104         unsigned int    nscount;
105         unsigned int    arcount;
106         unsigned char   payload[512];
107 };
108
109
110 void *dns_align(void *inp)
111 {
112         char *p = (char*)inp;
113         int offby = ((char *)p - (char *)0) % (sizeof(void *) > sizeof(long) ? sizeof(void *) : sizeof(long));
114         if (offby != 0)
115                 return p + ((sizeof(void *) > sizeof(long) ? sizeof(void *) : sizeof(long)) - offby);
116         else
117                 return p;
118 }
119
120 /*
121  * Optimized by brain, these were using integer division and modulus.
122  * We can use logic shifts and logic AND to replace these even divisions
123  * and multiplications, it should be a bit faster (probably not noticably,
124  * but of course, more impressive). Also made these inline.
125  */
126
127 inline void dns_fill_rr(s_rr_middle* rr, const unsigned char *input)
128 {
129         rr->type = (QueryType)((input[0] << 8) + input[1]);
130         rr->_class = (input[2] << 8) + input[3];
131         rr->ttl = (input[4] << 24) + (input[5] << 16) + (input[6] << 8) + input[7];
132         rr->rdlength = (input[8] << 8) + input[9];
133 }
134
135 inline void dns_fill_header(s_header *header, const unsigned char *input, const int l)
136 {
137         header->id[0] = input[0];
138         header->id[1] = input[1];
139         header->flags1 = input[2];
140         header->flags2 = input[3];
141         header->qdcount = (input[4] << 8) + input[5];
142         header->ancount = (input[6] << 8) + input[7];
143         header->nscount = (input[8] << 8) + input[9];
144         header->arcount = (input[10] << 8) + input[11];
145         memcpy(header->payload,&input[12],l);
146 }
147
148 inline void dns_empty_header(unsigned char *output, const s_header *header, const int l)
149 {
150         output[0] = header->id[0];
151         output[1] = header->id[1];
152         output[2] = header->flags1;
153         output[3] = header->flags2;
154         output[4] = header->qdcount >> 8;
155         output[5] = header->qdcount & 0xFF;
156         output[6] = header->ancount >> 8;
157         output[7] = header->ancount & 0xFF;
158         output[8] = header->nscount >> 8;
159         output[9] = header->nscount & 0xFF;
160         output[10] = header->arcount >> 8;
161         output[11] = header->arcount & 0xFF;
162         memcpy(&output[12],header->payload,l);
163 }
164
165 void dns_close(int fd)
166 {
167 #ifndef THREADED_DNS
168         if (ServerInstance && ServerInstance->SE)
169                 ServerInstance->SE->DelFd(fd);
170 #endif
171         log(DEBUG,"DNS: dns_close on fd %d",fd);
172         if (fd == lastcreate)
173         {
174                 wantclose = 1;
175                 return;
176         }
177         shutdown(fd,2);
178         close(fd);
179         return;
180 }
181
182 void DNS::dns_init()
183 {
184         FILE *f;
185         int i;
186         in_addr addr4;
187         char buf[1024];
188         if (initdone == 1)
189                 return;
190         i4 = 0;
191
192         initdone = 1;
193         srand((unsigned int) TIME);
194         memset(servers4,'\0',sizeof(in_addr) * 8);
195         f = fopen("/etc/resolv.conf","r");
196         if (f == NULL)
197                 return;
198         while (fgets(buf,1024,f) != NULL) {
199                 if (strncmp(buf,"nameserver",10) == 0)
200                 {
201                         i = 10;
202                         while (buf[i] == ' ' || buf[i] == '\t')
203                                 i++;
204                         if (i4 < 8)
205                         {
206                                 if (dns_aton4_s(&buf[i],&addr4) != NULL)
207                                         memcpy(&servers4[i4++],&addr4,sizeof(in_addr));
208                         }
209                 }
210         }
211         fclose(f);
212 }
213
214 void DNS::dns_init_2(const char* dnsserver)
215 {
216         in_addr addr4;
217         i4 = 0;
218         srand((unsigned int) TIME);
219         memset(servers4,'\0',sizeof(in_addr) * 8);
220         if (dns_aton4_s(dnsserver,&addr4) != NULL)
221             memcpy(&servers4[i4++],&addr4,sizeof(in_addr));
222 }
223
224
225 int dns_send_requests(const s_header *h, const s_connection *s, const int l)
226 {
227         int i;
228         sockaddr_in addr4;
229         unsigned char payload[sizeof(s_header)];
230
231         dns_empty_header(payload,h,l);
232
233
234         i = 0;
235
236         /* otherwise send via standard ipv4 boringness */
237         memset(&addr4,0,sizeof(addr4));
238         memcpy(&addr4.sin_addr,&servers4[i],sizeof(addr4.sin_addr));
239         addr4.sin_family = AF_INET;
240         addr4.sin_port = htons(53);
241         if (sendto(s->fd, payload, l + 12, 0, (sockaddr *) &addr4, sizeof(addr4)) == -1)
242         {
243                 return -1;
244         }
245
246         return 0;
247 }
248
249 s_connection *dns_add_query(s_header *h)
250 {
251
252         s_connection * s = new s_connection;
253         int id = rand() % 65536;
254
255         /* set header flags */
256         h->id[0] = s->id[0] = id >> 8; /* verified by dns_getresult_s() */
257         h->id[1] = s->id[1] = id & 0xFF;
258         h->flags1 = 0 | FLAGS1_MASK_RD;
259         h->flags2 = 0;
260         h->qdcount = 1;
261         h->ancount = 0;
262         h->nscount = 0;
263         h->arcount = 0;
264         s->want_list = 0;
265         s->fd = socket(PF_INET, SOCK_DGRAM, 0);
266         if (s->fd != -1)
267         {
268                 if (fcntl(s->fd, F_SETFL, O_NONBLOCK) != 0)
269                 {
270                         shutdown(s->fd,2);
271                         close(s->fd);
272                         s->fd = -1;
273                 }
274         }
275         if (s->fd != -1)
276         {
277                 sockaddr_in addr;
278                 memset(&addr,0,sizeof(addr));
279                 addr.sin_family = AF_INET;
280                 addr.sin_port = 0;
281                 addr.sin_addr.s_addr = INADDR_ANY;
282                 if (bind(s->fd,(sockaddr *)&addr,sizeof(addr)) != 0)
283                 {
284                         shutdown(s->fd,2);
285                         close(s->fd);
286                         s->fd = -1;
287                 }
288         }
289         if (s->fd == -1)
290         {
291                 DELETE(s);
292                 return NULL;
293         }
294         /* create new connection object, add to linked list */
295         if (connections.find(s->fd) == connections.end())
296                 connections[s->fd] = s;
297
298         if (wantclose == 1)
299         {
300                 shutdown(lastcreate,2);
301                 close(lastcreate);
302                 wantclose = 0;
303         }
304         lastcreate = s->fd;
305         return s;
306 }
307
308 int dns_build_query_payload(const char * const name, const unsigned short rr, const unsigned short _class, unsigned char * const payload)
309 {
310         short payloadpos;
311         const char * tempchr, * tempchr2;
312         unsigned short l;
313
314         payloadpos = 0;
315         tempchr2 = name;
316
317         /* split name up into labels, create query */
318         while ((tempchr = strchr(tempchr2,'.')) != NULL)
319         {
320                 l = tempchr - tempchr2;
321                 if (payloadpos + l + 1 > 507)
322                         return -1;
323                 payload[payloadpos++] = l;
324                 memcpy(&payload[payloadpos],tempchr2,l);
325                 payloadpos += l;
326                 tempchr2 = &tempchr[1];
327         }
328         l = strlen(tempchr2);
329         if (l)
330         {
331                 if (payloadpos + l + 2 > 507)
332                         return -1;
333                 payload[payloadpos++] = l;
334                 memcpy(&payload[payloadpos],tempchr2,l);
335                 payloadpos += l;
336                 payload[payloadpos++] = '\0';
337         }
338         if (payloadpos > 508)
339                 return -1;
340         l = htons(rr);
341         memcpy(&payload[payloadpos],&l,2);
342         l = htons(_class);
343         memcpy(&payload[payloadpos + 2],&l,2);
344         return payloadpos + 4;
345 }
346
347 in_addr* DNS::dns_aton4(const char * const ipstring)
348 {
349         static in_addr ip;
350         return dns_aton4_s(ipstring,&ip);
351 }
352
353 in_addr* DNS::dns_aton4_r(const char *ipstring) { /* ascii to numeric (reentrant): convert string to new 4part IP addr struct */
354         in_addr* ip;
355         ip = new in_addr;
356         if(dns_aton4_s(ipstring,ip) == NULL)
357         {
358                 DELETE(ip);
359                 return NULL;
360         }
361         return ip;
362 }
363
364 in_addr* DNS::dns_aton4_s(const char *ipstring, in_addr *ip) { /* ascii to numeric (buffered): convert string to given 4part IP addr struct */
365         inet_aton(ipstring,ip);
366         return ip;
367 }
368
369 int DNS::dns_getip4(const char *name) { /* build, add and send A query; retrieve result with dns_getresult() */
370         s_header h;
371         s_connection *s;
372         int l;
373
374         dns_init();
375         
376
377         l = dns_build_query_payload(name,DNS_QRY_A,1,(unsigned char *)&h.payload);
378         if (l == -1)
379                 return -1;
380         s = dns_add_query(&h);
381         if (s == NULL)
382                 return -1;
383         s->_class = 1;
384         s->type = DNS_QRY_A;
385         if (dns_send_requests(&h,s,l) == -1)
386                 return -1;
387
388         return s->fd;
389 }
390
391 int DNS::dns_getip4list(const char *name) { /* build, add and send A query; retrieve result with dns_getresult() */
392         s_header h;
393         s_connection *s;
394         int l;
395
396         dns_init();
397         
398         l = dns_build_query_payload(name,DNS_QRY_A,1,(unsigned char *)&h.payload);
399         if (l == -1)
400                 return -1;
401         s = dns_add_query(&h);
402         if (s == NULL)
403                 return -1;
404         s->_class = 1;
405         s->type = DNS_QRY_A;
406         s->want_list = 1;
407         if (dns_send_requests(&h,s,l) == -1)
408                 return -1;
409
410         return s->fd;
411 }
412
413 int DNS::dns_getname4(const in_addr *ip) { /* build, add and send PTR query; retrieve result with dns_getresult() */
414         char query[512];
415         s_header h;
416         s_connection * s;
417         unsigned char *c;
418         int l;
419
420         c = (unsigned char *)&ip->s_addr;
421
422         sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
423
424         l = dns_build_query_payload(query,DNS_QRY_PTR,1,(unsigned char *)&h.payload);
425         if (l == -1)
426                 return -1;
427         s = dns_add_query(&h);
428         if (s == NULL)
429                 return -1;
430         s->_class = 1;
431         s->type = DNS_QRY_PTR;
432         if (dns_send_requests(&h,s,l) == -1)
433                 return -1;
434
435         return s->fd;
436 }
437
438 char* DNS::dns_ntoa4(const in_addr * const ip) { /* numeric to ascii: convert 4part IP addr struct to static string */
439         static char r[256];
440         return dns_ntoa4_s(ip,r);
441 }
442
443 char* DNS::dns_ntoa4_s(const in_addr *ip, char *r) { /* numeric to ascii (buffered): convert 4part IP addr struct to given string */
444         unsigned char *m;
445         m = (unsigned char *)&ip->s_addr;
446         sprintf(r,"%d.%d.%d.%d",m[0],m[1],m[2],m[3]);
447         return r;
448 }
449
450 char* DNS::dns_getresult(const int cfd) { /* retrieve result of DNS query */
451         log(DEBUG,"DNS: dns_getresult with cfd=%d",cfd);
452         return dns_getresult_s(cfd,this->localbuf);
453 }
454
455 char* DNS::dns_getresult_s(const int cfd, char *res) { /* retrieve result of DNS query (buffered) */
456         s_header h;
457         s_connection *c;
458         int l, i, q, curanswer, o;
459         s_rr_middle rr;
460         unsigned char buffer[sizeof(s_header)];
461         unsigned short p;
462
463         if (res)
464                 *res = 0;
465
466         /* FireDNS used a linked list for this. How ugly (and slow). */
467         connlist_iter n_iter = connections.find(cfd);
468         if (n_iter == connections.end())
469         {
470                 log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d",cfd);
471                 return NULL;
472         }
473         else
474         {
475                 /* Remove the query from the list */
476                 c = (s_connection*)n_iter->second;
477                 /* We don't delete c here, because its done later when needed */
478                 connections.erase(n_iter);
479         }
480
481         l = recv(c->fd,buffer,sizeof(s_header),0);
482         dns_close(c->fd);
483         if (l < 12)
484         {
485                 DELETE(c);
486                 return NULL;
487         }
488         dns_fill_header(&h,buffer,l - 12);
489         if (c->id[0] != h.id[0] || c->id[1] != h.id[1])
490         {
491                 log(DEBUG,"DNS: id mismatch on query");
492                 DELETE(c);
493                 return NULL; /* ID mismatch */
494         }
495         if ((h.flags1 & FLAGS1_MASK_QR) == 0)
496         {
497                 log(DEBUG,"DNS: didnt get a query result");
498                 DELETE(c);
499                 return NULL;
500         }
501         if ((h.flags1 & FLAGS1_MASK_OPCODE) != 0)
502         {
503                 log(DEBUG,"DNS: got an OPCODE and didnt want one");
504                 DELETE(c);
505                 return NULL;
506         }
507         if ((h.flags2 & FLAGS2_MASK_RCODE) != 0)
508         {
509                 log(DEBUG,"DNS lookup failed due to SERVFAIL");
510                 DELETE(c);
511                 return NULL;
512         }
513         if (h.ancount < 1)
514         {
515                 log(DEBUG,"DNS: no answers!");
516                 DELETE(c);
517                 return NULL;
518         }
519         i = 0;
520         q = 0;
521         l -= 12;
522         while ((unsigned)q < h.qdcount && i < l)
523         {
524                 if (h.payload[i] > 63)
525                 {
526                         i += 6;
527                         q++;
528                 }
529                 else
530                 {
531                         if (h.payload[i] == 0)
532                         {
533                                 q++;
534                                 i += 5;
535                         }
536                         else i += h.payload[i] + 1;
537                 }
538         }
539         curanswer = 0;
540         while ((unsigned)curanswer < h.ancount)
541         {
542                 q = 0;
543                 while (q == 0 && i < l)
544                 {
545                         if (h.payload[i] > 63)
546                         {
547                                 i += 2;
548                                 q = 1;
549                         }
550                         else
551                         {
552                                 if (h.payload[i] == 0)
553                                 {
554                                         i++;
555                                         q = 1;
556                                 }
557                                 else i += h.payload[i] + 1; /* skip length and label */
558                         }
559                 }
560                 if (l - i < 10)
561                 {
562                         DELETE(c);
563                         return NULL;
564                 }
565                 dns_fill_rr(&rr,&h.payload[i]);
566                 i += 10;
567                 if (rr.type != c->type)
568                 {
569                         curanswer++;
570                         i += rr.rdlength;
571                         continue;
572                 }
573                 if (rr._class != c->_class)
574                 {
575                         curanswer++;
576                         i += rr.rdlength;
577                         continue;
578                 }
579                 break;
580         }
581         if ((unsigned)curanswer == h.ancount)
582                 return NULL;
583         if ((unsigned)i + rr.rdlength > (unsigned)l)
584                 return NULL;
585         if (rr.rdlength > 1023)
586                 return NULL;
587
588         switch (rr.type)
589         {
590                 case DNS_QRY_PTR:
591                         log(DEBUG,"DNS: got a result of type DNS_QRY_PTR");
592                         o = 0;
593                         q = 0;
594                         while (q == 0 && i < l && o + 256 < 1023)
595                         {
596                                 if (h.payload[i] > 63)
597                                 {
598                                         log(DEBUG,"DNS: h.payload[i] > 63");
599                                         memcpy(&p,&h.payload[i],2);
600                                         i = ntohs(p) - 0xC000 - 12;
601                                 }
602                                 else
603                                 {
604                                         if (h.payload[i] == 0)
605                                         {
606                                                 q = 1;
607                                         }
608                                         else
609                                         {
610                                                 res[o] = '\0';
611                                                 if (o != 0)
612                                                         res[o++] = '.';
613                                                 memcpy(&res[o],&h.payload[i + 1],h.payload[i]);
614                                                 o += h.payload[i];
615                                                 i += h.payload[i] + 1;
616                                         }
617                                 }
618                         }
619                         res[o] = '\0';
620                 break;
621                 case DNS_QRY_A:
622                         log(DEBUG,"DNS: got a result of type DNS_QRY_A");
623                         if (c->want_list)
624                         {
625                                 dns_ip4list *alist = (dns_ip4list *) res; /* we have to trust that this is aligned */
626                                 while ((char *)alist - (char *)res < 700)
627                                 {
628                                         if (rr.type != DNS_QRY_A)
629                                                 break;
630                                         if (rr._class != 1)
631                                                 break;
632                                         if (rr.rdlength != 4)
633                                         {
634                                                 DELETE(c);
635                                                 return NULL;
636                                         }
637                                         memcpy(&alist->ip,&h.payload[i],4);
638                                         if ((unsigned)++curanswer >= h.ancount)
639                                                 break;
640                                         i += rr.rdlength;
641                                         q = 0;
642                                         while (q == 0 && i < l)
643                                         {
644                                                 if (h.payload[i] > 63)
645                                                 {
646                                                         i += 2;
647                                                         q = 1;
648                                                 }
649                                                 else
650                                                 {
651                                                         if (h.payload[i] == 0)
652                                                         {
653                                                                 i++;
654                                                                 q = 1;
655                                                         }
656                                                         else i += h.payload[i] + 1;
657                                                 }
658                                         }
659                                         if (l - i < 10)
660                                         {
661                                                 DELETE(c);
662                                                 return NULL;
663                                         }
664                                         dns_fill_rr(&rr,&h.payload[i]);
665                                         i += 10;
666                                         alist->next = (dns_ip4list *) dns_align(((char *) alist) + sizeof(dns_ip4list));
667                                         alist = alist->next;
668                                         alist->next = NULL;
669                                 }
670                                 alist->next = NULL;
671                                 break;
672                         }
673                         memcpy(res,&h.payload[i],rr.rdlength);
674                         res[rr.rdlength] = '\0';
675                         break;
676                 default:
677                         memcpy(res,&h.payload[i],rr.rdlength);
678                         res[rr.rdlength] = '\0';
679                         break;
680         }
681         DELETE(c);
682         return res;
683 }
684
685 DNS::DNS()
686 {
687         dns_init();
688         log(DEBUG,"Create blank DNS");
689 }
690
691 DNS::DNS(const std::string &dnsserver)
692 {
693         dns_init_2(dnsserver.c_str());
694         log(DEBUG,"Create DNS with server '%s'",dnsserver.c_str());
695 }
696
697 void DNS::SetNS(const std::string &dnsserver)
698 {
699         dns_init_2(dnsserver.c_str());
700         log(DEBUG,"Set NS");
701 }
702
703 DNS::~DNS()
704 {
705         if (this->myfd > -1)
706         {
707                 log(DEBUG,"HA! An FD tried to sneak by unnoticed - freed it.");
708                 dns_close(this->myfd);
709         }
710 }
711
712 bool DNS::ReverseLookup(const std::string &ip, bool ins)
713 {
714         if (ServerInstance && ServerInstance->stats)
715                 ServerInstance->stats->statsDns++;
716         binip = dns_aton4(ip.c_str());
717         if (binip == NULL)
718         {
719                 return false;
720         }
721
722         this->myfd = dns_getname4(binip);
723         if (this->myfd == -1)
724         {
725                 return false;
726         }
727         log(DEBUG,"DNS: ReverseLookup, fd=%d",this->myfd);
728 #ifndef THREADED_DNS
729         if (ins)
730         {
731                 if (ServerInstance && ServerInstance->SE)
732                         ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS);
733         }
734 #endif
735         return true;
736 }
737
738 bool DNS::ForwardLookup(const std::string &host, bool ins)
739 {
740         if (ServerInstance && ServerInstance->stats)
741                 ServerInstance->stats->statsDns++;
742         this->myfd = dns_getip4(host.c_str());
743         if (this->myfd == -1)
744         {
745                 return false;
746         }
747         log(DEBUG,"DNS: ForwardLookup, fd=%d",this->myfd);
748 #ifndef THREADED_DNS
749         if (ins)
750         {
751                 if (ServerInstance && ServerInstance->SE)
752                         ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS);
753         }
754 #endif
755         return true;
756 }
757
758 bool DNS::ForwardLookupWithFD(const std::string &host, int &fd)
759 {
760         if (ServerInstance && ServerInstance->stats)
761                 ServerInstance->stats->statsDns++;
762         this->myfd = dns_getip4(host.c_str());
763         fd = this->myfd;
764         if (this->myfd == -1)
765         {
766                 return false;
767         }
768         log(DEBUG,"DNS: ForwardLookupWithFD, fd=%d",this->myfd);
769         if (ServerInstance && ServerInstance->SE)
770                 ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_MODULE);
771         return true;
772 }
773
774 bool DNS::HasResult(int fd)
775 {
776         return (fd == this->myfd);
777 }
778
779 /* Only the multithreaded dns uses this poll() based
780  * check now. As its in another thread we dont have
781  * to worry about its performance that much.
782  */
783 bool DNS::HasResult()
784 {
785         log(DEBUG,"DNS: HasResult, fd=%d",this->myfd);
786         pollfd polls;
787         polls.fd = this->myfd;
788         polls.events = POLLIN;
789         int ret = poll(&polls,1,1);
790         log(DEBUG,"DNS: Hasresult returning %d",ret);
791         return (ret > 0);
792 }
793
794 int DNS::GetFD()
795 {
796         return this->myfd;
797 }
798
799 std::string DNS::GetResult()
800 {
801         log(DEBUG,"DNS: GetResult()");
802         result = dns_getresult(this->myfd);
803         if (result)
804         {
805                 if (ServerInstance && ServerInstance->stats)
806                         ServerInstance->stats->statsDnsGood++;
807                 dns_close(this->myfd);
808                 return result;
809         }
810         else
811         {
812                 if (ServerInstance && ServerInstance->stats)
813                         ServerInstance->stats->statsDnsBad++;
814                 if (this->myfd != -1)
815                 {
816                         dns_close(this->myfd);
817                 }
818                 return "";
819         }
820 }
821
822 std::string DNS::GetResultIP()
823 {
824         char r[1024];
825         log(DEBUG,"DNS: GetResultIP()");
826         result = dns_getresult(this->myfd);
827         if (this->myfd != -1)
828         {
829                 dns_close(this->myfd);
830         }
831         if (result)
832         {
833                 if (ServerInstance && ServerInstance->stats)
834                         ServerInstance->stats->statsDnsGood++;
835                 unsigned char a = (unsigned)result[0];
836                 unsigned char b = (unsigned)result[1];
837                 unsigned char c = (unsigned)result[2];
838                 unsigned char d = (unsigned)result[3];
839                 snprintf(r,1024,"%u.%u.%u.%u",a,b,c,d);
840                 return r;
841         }
842         else
843         {
844                 if (ServerInstance && ServerInstance->stats)
845                         ServerInstance->stats->statsDnsBad++;
846                 log(DEBUG,"DANGER WILL ROBINSON! NXDOMAIN for forward lookup, but we got a reverse lookup!");
847                 return "";
848         }
849 }
850
851
852
853 #ifdef THREADED_DNS
854 void* dns_task(void* arg)
855 {
856         userrec* u = (userrec*)arg;
857         log(DEBUG,"DNS thread for user %s",u->nick);
858         DNS dns1;
859         DNS dns2;
860         std::string host;
861         std::string ip;
862         if (dns1.ReverseLookup((char*)inet_ntoa(u->ip4)))
863         {
864                 while (!dns1.HasResult())
865                 {
866                         usleep(100);
867                 }
868                 host = dns1.GetResult();
869                 if (host != "")
870                 {
871                         if (dns2.ForwardLookup(host), false)
872                         {
873                                 while (!dns2.HasResult())
874                                 {
875                                         usleep(100);
876                                 }
877                                 ip = dns2.GetResultIP();
878                                 if (ip == std::string((char*)inet_ntoa(u->ip4)))
879                                 {
880                                         if (host.length() < 160)
881                                         {
882                                                 strcpy(u->host,host.c_str());
883                                                 strcpy(u->dhost,host.c_str());
884                                         }
885                                 }
886                         }
887                 }
888         }
889         u->dns_done = true;
890         return NULL;
891 }
892 #endif
893
894 Resolver::Resolver(const std::string &source, bool forward, const std::string &dnsserver = "") : input(source), fwd(forward), server(dnsserver)
895 {
896         if (this->server != "")
897                 Query.SetNS(this->server);
898         else
899                 Query.SetNS(Config->DNSServer);
900
901         if (forward)
902         {
903                 Query.ForwardLookup(input.c_str(), false);
904                 this->fd = Query.GetFD();
905         }
906         else
907         {
908                 Query.ReverseLookup(input.c_str(), false);
909                 this->fd = Query.GetFD();
910         }
911         if (fd < 0)
912         {
913                 log(DEBUG,"Resolver::Resolver: RESOLVER_NSDOWN");
914                 this->OnError(RESOLVER_NSDOWN);
915                 ModuleException e("Resolver: Nameserver is down");
916                 throw e;
917                 /* We shouldnt get here really */
918                 return;
919         }
920
921         if (ServerInstance && ServerInstance->SE)
922         {
923                 log(DEBUG,"Resolver::Resolver: this->fd=%d",this->fd);
924                 ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_CLASSDNS);
925         }
926         else
927         {
928                 log(DEBUG,"Resolver::Resolver: RESOLVER_NOTREADY");
929                 this->OnError(RESOLVER_NOTREADY);
930                 ModuleException e("Resolver: Core not initialized yet");
931                 throw e;
932                 /* We shouldnt get here really */
933                 return;
934         }
935 }
936
937 Resolver::~Resolver()
938 {
939         log(DEBUG,"Resolver::~Resolver");
940         if (ServerInstance && ServerInstance->SE)
941                 ServerInstance->SE->DelFd(this->fd);
942 }
943
944 int Resolver::GetFd()
945 {
946         return this->fd;
947 }
948
949 bool Resolver::ProcessResult()
950 {
951         log(DEBUG,"Resolver::ProcessResult");
952         if (this->fwd)
953                 result = Query.GetResultIP();
954         else
955                 result = Query.GetResult();
956
957         if (result != "")
958         {
959                 log(DEBUG,"Resolver::OnLookupComplete(%s)",result.c_str());
960                 this->OnLookupComplete(result);
961                 return true;
962         }
963         else
964         {
965                 log(DEBUG,"Resolver::OnError(RESOLVER_NXDOMAIN)");
966                 this->OnError(RESOLVER_NXDOMAIN);
967                 return false;
968         }
969 }
970
971 void Resolver::OnLookupComplete(const std::string &result)
972 {
973 }
974
975 void Resolver::OnError(ResolverError e)
976 {
977 }
978
979 void dns_deal_with_classes(int fd)
980 {
981         log(DEBUG,"dns_deal_with_classes(%d)",fd);
982         if ((fd > -1) && (dns_classes[fd]))
983         {
984                 log(DEBUG,"Valid fd %d",fd);
985                 dns_classes[fd]->ProcessResult();
986                 delete dns_classes[fd];
987                 dns_classes[fd] = NULL;
988         }
989 }
990
991 bool dns_add_class(Resolver* r)
992 {
993         log(DEBUG,"dns_add_class");
994         if ((r) && (r->GetFd() > -1))
995         {
996                 if (!dns_classes[r->GetFd()])
997                 {
998                         log(DEBUG,"dns_add_class: added class");
999                         dns_classes[r->GetFd()] = r;
1000                         return true;
1001                 }
1002                 else
1003                 {
1004                         log(DEBUG,"Space occupied!");
1005                         return false;
1006                 }
1007         }
1008         else
1009         {
1010                 log(DEBUG,"Bad class");
1011                 delete r;
1012                 return true;
1013         }
1014 }
1015
1016 void init_dns()
1017 {
1018         memset(dns_classes,0,sizeof(dns_classes));
1019 }
1020