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