]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
ce9192785d6cfd438c1e578a70957fa16089b3c6
[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                                         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                 return result;
803         }
804         else
805         {
806                 if (ServerInstance && ServerInstance->stats)
807                         ServerInstance->stats->statsDnsBad++;
808                 if (this->myfd != -1)
809                 {
810                         dns_close(this->myfd);
811                 }
812                 return "";
813         }
814 }
815
816 std::string DNS::GetResultIP()
817 {
818         char r[1024];
819         log(DEBUG,"DNS: GetResultIP()");
820         result = dns_getresult(this->myfd);
821         if (this->myfd != -1)
822         {
823                 dns_close(this->myfd);
824         }
825         if (result)
826         {
827                 if (ServerInstance && ServerInstance->stats)
828                         ServerInstance->stats->statsDnsGood++;
829                 unsigned char a = (unsigned)result[0];
830                 unsigned char b = (unsigned)result[1];
831                 unsigned char c = (unsigned)result[2];
832                 unsigned char d = (unsigned)result[3];
833                 snprintf(r,1024,"%u.%u.%u.%u",a,b,c,d);
834                 return r;
835         }
836         else
837         {
838                 if (ServerInstance && ServerInstance->stats)
839                         ServerInstance->stats->statsDnsBad++;
840                 log(DEBUG,"DANGER WILL ROBINSON! NXDOMAIN for forward lookup, but we got a reverse lookup!");
841                 return "";
842         }
843 }
844
845
846
847 #ifdef THREADED_DNS
848 void* dns_task(void* arg)
849 {
850         userrec* u = (userrec*)arg;
851         log(DEBUG,"DNS thread for user %s",u->nick);
852         DNS dns1;
853         DNS dns2;
854         std::string host;
855         std::string ip;
856         if (dns1.ReverseLookup((char*)inet_ntoa(u->ip4)))
857         {
858                 while (!dns1.HasResult())
859                 {
860                         usleep(100);
861                 }
862                 host = dns1.GetResult();
863                 if (host != "")
864                 {
865                         if (dns2.ForwardLookup(host), false)
866                         {
867                                 while (!dns2.HasResult())
868                                 {
869                                         usleep(100);
870                                 }
871                                 ip = dns2.GetResultIP();
872                                 if (ip == std::string((char*)inet_ntoa(u->ip4)))
873                                 {
874                                         if (host.length() < 160)
875                                         {
876                                                 strcpy(u->host,host.c_str());
877                                                 strcpy(u->dhost,host.c_str());
878                                         }
879                                 }
880                         }
881                 }
882         }
883         u->dns_done = true;
884         return NULL;
885 }
886 #endif
887
888 Resolver::Resolver(const std::string &source, bool forward, const std::string &dnsserver = "") : input(source), fwd(forward), server(dnsserver)
889 {
890         if (this->server != "")
891                 Query.SetNS(this->server);
892         else
893                 Query.SetNS(Config->DNSServer);
894
895         if (forward)
896         {
897                 Query.ForwardLookup(input.c_str(), false);
898                 this->fd = Query.GetFD();
899         }
900         else
901         {
902                 Query.ReverseLookup(input.c_str(), false);
903                 this->fd = Query.GetFD();
904         }
905         if (fd < 0)
906         {
907                 log(DEBUG,"Resolver::Resolver: RESOLVER_NSDOWN");
908                 this->OnError(RESOLVER_NSDOWN);
909                 return;
910         }
911
912         if (ServerInstance && ServerInstance->SE)
913         {
914                 log(DEBUG,"Resolver::Resolver: this->fd=%d",this->fd);
915                 ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_CLASSDNS);
916         }
917         else
918         {
919                 log(DEBUG,"Resolver::Resolver: RESOLVER_NOTREADY");
920                 this->OnError(RESOLVER_NOTREADY);
921         }
922 }
923
924 Resolver::~Resolver()
925 {
926         log(DEBUG,"Resolver::~Resolver");
927         if (ServerInstance && ServerInstance->SE)
928                 ServerInstance->SE->DelFd(this->fd);
929 }
930
931 int Resolver::GetFd()
932 {
933         return this->fd;
934 }
935
936 bool Resolver::ProcessResult()
937 {
938         log(DEBUG,"Resolver::ProcessResult");
939         if (this->fwd)
940                 result = Query.GetResultIP();
941         else
942                 result = Query.GetResult();
943
944         if (result != "")
945         {
946                 log(DEBUG,"Resolver::OnLookupComplete(%s)",result.c_str());
947                 this->OnLookupComplete(result);
948                 return true;
949         }
950         else
951         {
952                 log(DEBUG,"Resolver::OnError(RESOLVER_NXDOMAIN)");
953                 this->OnError(RESOLVER_NXDOMAIN);
954                 return false;
955         }
956 }
957
958 void Resolver::OnLookupComplete(const std::string &result)
959 {
960 }
961
962 void Resolver::OnError(ResolverError e)
963 {
964 }
965
966 void dns_deal_with_classes(int fd)
967 {
968         log(DEBUG,"dns_deal_with_classes(%d)",fd);
969         if ((fd > -1) && (dns_classes[fd]))
970         {
971                 log(DEBUG,"Valid fd %d",fd);
972                 dns_classes[fd]->ProcessResult();
973                 delete dns_classes[fd];
974                 dns_classes[fd] = NULL;
975         }
976 }
977
978 bool dns_add_class(Resolver* r)
979 {
980         log(DEBUG,"dns_add_class");
981         if ((r) && (r->GetFd() > -1))
982         {
983                 if (!dns_classes[r->GetFd()])
984                 {
985                         log(DEBUG,"dns_add_class: added class");
986                         dns_classes[r->GetFd()] = r;
987                         return true;
988                 }
989                 else
990                 {
991                         log(DEBUG,"Space occupied!");
992                         return false;
993                 }
994         }
995         else
996         {
997                 log(DEBUG,"Bad class");
998                 delete r;
999                 return true;
1000         }
1001 }
1002
1003 void init_dns()
1004 {
1005         memset(dns_classes,0,sizeof(dns_classes));
1006 }
1007