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