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