]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/dns.cpp
One goto is now no gotos.
[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                 defaultcase:
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(std::string dnsserver)
688 {
689         dns_init_2(dnsserver.c_str());
690         log(DEBUG,"Create DNS");
691 }
692
693 void DNS::SetNS(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(std::string ip)
704 {
705         ServerInstance->stats->statsDns++;
706         binip = dns_aton4(ip.c_str());
707         if (binip == NULL)
708         {
709                 return false;
710         }
711
712         this->myfd = dns_getname4(binip);
713         if (this->myfd == -1)
714         {
715                 return false;
716         }
717         log(DEBUG,"DNS: ReverseLookup, fd=%d",this->myfd);
718 #ifndef THREADED_DNS
719         ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS);
720 #endif
721         return true;
722 }
723
724 bool DNS::ForwardLookup(std::string host)
725 {
726         ServerInstance->stats->statsDns++;
727         this->myfd = dns_getip4(host.c_str());
728         if (this->myfd == -1)
729         {
730                 return false;
731         }
732         log(DEBUG,"DNS: ForwardLookup, fd=%d",this->myfd);
733 #ifndef THREADED_DNS
734         ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS);
735 #endif
736         return true;
737 }
738
739 bool DNS::HasResult(int fd)
740 {
741         return (fd == this->myfd);
742 }
743
744 /* Only the multithreaded dns uses this poll() based
745  * check now. As its in another thread we dont have
746  * to worry about its performance that much.
747  */
748 bool DNS::HasResult()
749 {
750         log(DEBUG,"DNS: HasResult, fd=%d",this->myfd);
751         pollfd polls;
752         polls.fd = this->myfd;
753         polls.events = POLLIN;
754         int ret = poll(&polls,1,1);
755         log(DEBUG,"DNS: Hasresult returning %d",ret);
756         return (ret > 0);
757 }
758
759 int DNS::GetFD()
760 {
761         return this->myfd;
762 }
763
764 std::string DNS::GetResult()
765 {
766         log(DEBUG,"DNS: GetResult()");
767         result = dns_getresult(this->myfd);
768         if (result)
769         {
770                 ServerInstance->stats->statsDnsGood++;
771                 dns_close(this->myfd);
772                 return result;
773         }
774         else
775         {
776                 ServerInstance->stats->statsDnsBad++;
777                 if (this->myfd != -1)
778                 {
779                         dns_close(this->myfd);
780                 }
781                 return "";
782         }
783 }
784
785 std::string DNS::GetResultIP()
786 {
787         char r[1024];
788         log(DEBUG,"DNS: GetResultIP()");
789         result = dns_getresult(this->myfd);
790         if (this->myfd != -1)
791         {
792                 dns_close(this->myfd);
793         }
794         if (result)
795         {
796                 ServerInstance->stats->statsDnsGood++;
797                 unsigned char a = (unsigned)result[0];
798                 unsigned char b = (unsigned)result[1];
799                 unsigned char c = (unsigned)result[2];
800                 unsigned char d = (unsigned)result[3];
801                 snprintf(r,1024,"%u.%u.%u.%u",a,b,c,d);
802                 return r;
803         }
804         else
805         {
806                 ServerInstance->stats->statsDnsBad++;
807                 log(DEBUG,"DANGER WILL ROBINSON! NXDOMAIN for forward lookup, but we got a reverse lookup!");
808                 return "";
809         }
810 }
811
812
813
814 #ifdef THREADED_DNS
815 void* dns_task(void* arg)
816 {
817         userrec* u = (userrec*)arg;
818         log(DEBUG,"DNS thread for user %s",u->nick);
819         DNS dns1;
820         DNS dns2;
821         std::string host;
822         std::string ip;
823         if (dns1.ReverseLookup(u->ip))
824         {
825                 while (!dns1.HasResult())
826                 {
827                         usleep(100);
828                 }
829                 host = dns1.GetResult();
830                 if (host != "")
831                 {
832                         if (dns2.ForwardLookup(host))
833                         {
834                                 while (!dns2.HasResult())
835                                 {
836                                         usleep(100);
837                                 }
838                                 ip = dns2.GetResultIP();
839                                 if (ip == std::string(u->ip))
840                                 {
841                                         if (host.length() < 160)
842                                         {
843                                                 strcpy(u->host,host.c_str());
844                                                 strcpy(u->dhost,host.c_str());
845                                         }
846                                 }
847                         }
848                 }
849         }
850         u->dns_done = true;
851         return NULL;
852 }
853 #endif