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