]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
06cff075755b17bbc19a8acd1fd557916651a2a5
[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)
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 (ServerInstance && ServerInstance->SE)
724                 ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS);
725 #endif
726         return true;
727 }
728
729 bool DNS::ForwardLookup(const std::string &host)
730 {
731         if (ServerInstance && ServerInstance->stats)
732                 ServerInstance->stats->statsDns++;
733         this->myfd = dns_getip4(host.c_str());
734         if (this->myfd == -1)
735         {
736                 return false;
737         }
738         log(DEBUG,"DNS: ForwardLookup, fd=%d",this->myfd);
739 #ifndef THREADED_DNS
740         if (ServerInstance && ServerInstance->SE)
741                 ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS);
742 #endif
743         return true;
744 }
745
746 bool DNS::ForwardLookupWithFD(const std::string &host, int &fd)
747 {
748         if (ServerInstance && ServerInstance->stats)
749                 ServerInstance->stats->statsDns++;
750         this->myfd = dns_getip4(host.c_str());
751         fd = this->myfd;
752         if (this->myfd == -1)
753         {
754                 return false;
755         }
756         log(DEBUG,"DNS: ForwardLookupWithFD, fd=%d",this->myfd);
757         if (ServerInstance && ServerInstance->SE)
758                 ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_MODULE);
759         return true;
760 }
761
762 bool DNS::HasResult(int fd)
763 {
764         return (fd == this->myfd);
765 }
766
767 /* Only the multithreaded dns uses this poll() based
768  * check now. As its in another thread we dont have
769  * to worry about its performance that much.
770  */
771 bool DNS::HasResult()
772 {
773         log(DEBUG,"DNS: HasResult, fd=%d",this->myfd);
774         pollfd polls;
775         polls.fd = this->myfd;
776         polls.events = POLLIN;
777         int ret = poll(&polls,1,1);
778         log(DEBUG,"DNS: Hasresult returning %d",ret);
779         return (ret > 0);
780 }
781
782 int DNS::GetFD()
783 {
784         return this->myfd;
785 }
786
787 std::string DNS::GetResult()
788 {
789         log(DEBUG,"DNS: GetResult()");
790         result = dns_getresult(this->myfd);
791         if (result)
792         {
793                 if (ServerInstance && ServerInstance->stats)
794                         ServerInstance->stats->statsDnsGood++;
795                 dns_close(this->myfd);
796                 return result;
797         }
798         else
799         {
800                 if (ServerInstance && ServerInstance->stats)
801                         ServerInstance->stats->statsDnsBad++;
802                 if (this->myfd != -1)
803                 {
804                         dns_close(this->myfd);
805                 }
806                 return "";
807         }
808 }
809
810 std::string DNS::GetResultIP()
811 {
812         char r[1024];
813         log(DEBUG,"DNS: GetResultIP()");
814         result = dns_getresult(this->myfd);
815         if (this->myfd != -1)
816         {
817                 dns_close(this->myfd);
818         }
819         if (result)
820         {
821                 if (ServerInstance && ServerInstance->stats)
822                         ServerInstance->stats->statsDnsGood++;
823                 unsigned char a = (unsigned)result[0];
824                 unsigned char b = (unsigned)result[1];
825                 unsigned char c = (unsigned)result[2];
826                 unsigned char d = (unsigned)result[3];
827                 snprintf(r,1024,"%u.%u.%u.%u",a,b,c,d);
828                 return r;
829         }
830         else
831         {
832                 if (ServerInstance && ServerInstance->stats)
833                         ServerInstance->stats->statsDnsBad++;
834                 log(DEBUG,"DANGER WILL ROBINSON! NXDOMAIN for forward lookup, but we got a reverse lookup!");
835                 return "";
836         }
837 }
838
839
840
841 #ifdef THREADED_DNS
842 void* dns_task(void* arg)
843 {
844         userrec* u = (userrec*)arg;
845         log(DEBUG,"DNS thread for user %s",u->nick);
846         DNS dns1;
847         DNS dns2;
848         std::string host;
849         std::string ip;
850         if (dns1.ReverseLookup((char*)inet_ntoa(u->ip4)))
851         {
852                 while (!dns1.HasResult())
853                 {
854                         usleep(100);
855                 }
856                 host = dns1.GetResult();
857                 if (host != "")
858                 {
859                         if (dns2.ForwardLookup(host))
860                         {
861                                 while (!dns2.HasResult())
862                                 {
863                                         usleep(100);
864                                 }
865                                 ip = dns2.GetResultIP();
866                                 if (ip == std::string((char*)inet_ntoa(u->ip4)))
867                                 {
868                                         if (host.length() < 160)
869                                         {
870                                                 strcpy(u->host,host.c_str());
871                                                 strcpy(u->dhost,host.c_str());
872                                         }
873                                 }
874                         }
875                 }
876         }
877         u->dns_done = true;
878         return NULL;
879 }
880 #endif
881
882 Resolver::Resolver(const std::string &source, bool forward, const std::string &dnsserver = "") : input(source), fwd(forward), server(dnsserver)
883 {
884         if (this->server != "")
885                 Query.SetNS(this->server);
886         else
887                 Query.SetNS(Config->DNSServer);
888
889         if (forward)
890                 this->fd = Query.ForwardLookup(input.c_str());
891         else
892                 this->fd = Query.ReverseLookup(input.c_str());
893         if (fd < 0)
894                 this->OnError(RESOLVER_NSDOWN);
895
896         if (ServerInstance && ServerInstance->SE)
897                 ServerInstance->SE->AddFd(this->fd,true,X_ESTAB_CLASSDNS);
898         else
899                 this->OnError(RESOLVER_NOTREADY);
900 }
901
902 Resolver::~Resolver()
903 {
904         if (ServerInstance && ServerInstance->SE)
905                 ServerInstance->SE->DelFd(this->fd);
906 }
907
908 int Resolver::GetFd()
909 {
910         return this->fd;
911 }
912
913 bool Resolver::ProcessResult()
914 {
915         if (this->fwd)
916                 result = Query.GetResultIP();
917         else
918                 result = Query.GetResult();
919
920         if (result != "")
921         {
922                 this->OnLookupComplete(result);
923                 return true;
924         }
925         else
926         {
927                 this->OnError(RESOLVER_NXDOMAIN);
928                 return false;
929         }
930 }
931
932 void Resolver::OnLookupComplete(const std::string &result)
933 {
934 }
935
936 void Resolver::OnError(ResolverError e)
937 {
938 }
939
940 void dns_deal_with_classes(int fd)
941 {
942         if ((fd > -1) && (dns_classes[fd]))
943         {
944                 dns_classes[fd]->ProcessResult();
945                 delete dns_classes[fd];
946                 dns_classes[fd] = NULL;
947         }
948 }
949
950 bool dns_add_class(Resolver* r)
951 {
952         if ((r) && (r->GetFd() > -1))
953         {
954                 if (!dns_classes[r->GetFd()])
955                 {
956                         dns_classes[r->GetFd()] = r;
957                         return true;
958                 }
959                 else
960                 {
961                         return false;
962                 }
963         }
964         else
965         {
966                 delete r;
967                 return true;
968         }
969 }
970
971 void init_dns()
972 {
973         memset(dns_classes,0,sizeof(dns_classes));
974 }
975