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