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