]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/dns.cpp
Tidyup var names. If i ever meet this person who called all the firedns vars 'l'...
[user/henk/code/inspircd.git] / src / dns.cpp
index bdb7889a56899a381eabe057a3ca10580cd5baa8..69df48cc65acdeba1d9e000b0ab6f9e275624adb 100644 (file)
@@ -3,13 +3,13 @@
  *       +------------------------------------+
  *
  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
- *                       E-mail:
- *                <brain@chatspike.net>
- *                <Craig@chatspike.net>
+ *                    E-mail:
+ *             <brain@chatspike.net>
+ *             <Craig@chatspike.net>
  *     
  * Written by Craig Edwards, Craig McLure, and others.
  * This program is free but copyrighted software; see
- *            the file COPYING for details.
+ *         the file COPYING for details.
  *
  * ---------------------------------------------------
  */
@@ -49,11 +49,14 @@ using namespace std;
 #include "dns.h"
 #include "inspircd.h"
 #include "helperfuncs.h"
+#include "inspircd_config.h"
 #include "socketengine.h"
+#include "configreader.h"
 
 extern InspIRCd* ServerInstance;
 extern ServerConfig* Config;
 extern time_t TIME;
+extern userrec* fd_ref_table[MAX_DESCRIPTORS];
 
 enum QueryType { DNS_QRY_A = 1, DNS_QRY_PTR = 12 };
 enum QueryFlags1 { FLAGS1_MASK_RD = 0x01, FLAGS1_MASK_TC = 0x02, FLAGS1_MASK_AA = 0x04, FLAGS1_MASK_OPCODE = 0x78, FLAGS1_MASK_QR = 0x80 };
@@ -63,23 +66,13 @@ class s_connection;
 
 typedef std::map<int,s_connection*> connlist;
 typedef connlist::iterator connlist_iter;
-connlist connections;
 
-struct in_addr servers4[8];
-int i4;
-int initdone = 0;
-int wantclose = 0;
-int lastcreate = -1;
+DNS* Res = NULL;
 
-class s_connection
-{
- public:
-       unsigned char   id[2];
-       unsigned int    _class;
-       QueryType       type;
-       int             want_list;
-       int             fd;
-};
+connlist connections;
+int master_socket = -1;
+Resolver* dns_classes[65536];
+insp_inaddr myserver;
 
 class s_rr_middle
 {
@@ -103,6 +96,24 @@ class s_header
        unsigned char   payload[512];
 };
 
+class s_connection
+{
+ public:
+       unsigned char   id[2];
+       unsigned char   res[512];
+       unsigned int    _class;
+       QueryType       type;
+
+       s_connection()
+       {
+               *res = 0;
+       }
+
+       unsigned char*  result_ready(s_header &h, int length);
+       int             send_requests(const s_header *h, const int l, QueryType qt);
+};
+
+
 
 void *dns_align(void *inp)
 {
@@ -159,98 +170,43 @@ inline void dns_empty_header(unsigned char *output, const s_header *header, cons
        memcpy(&output[12],header->payload,l);
 }
 
-void dns_close(int fd)
-{
-#ifndef THREADED_DNS
-       if (ServerInstance && ServerInstance->SE)
-               ServerInstance->SE->DelFd(fd);
-#endif
-       log(DEBUG,"DNS: dns_close on fd %d",fd);
-       if (fd == lastcreate)
-       {
-               wantclose = 1;
-               return;
-       }
-       shutdown(fd,2);
-       close(fd);
-       return;
-}
 
-void DNS::dns_init()
+int s_connection::send_requests(const s_header *h, const int l, QueryType qt)
 {
-       FILE *f;
-       int i;
-       in_addr addr4;
-       char buf[1024];
-       if (initdone == 1)
-               return;
-       i4 = 0;
-
-       initdone = 1;
-       srand((unsigned int) TIME);
-       memset(servers4,'\0',sizeof(in_addr) * 8);
-       f = fopen("/etc/resolv.conf","r");
-       if (f == NULL)
-               return;
-       while (fgets(buf,1024,f) != NULL) {
-               if (strncmp(buf,"nameserver",10) == 0)
-               {
-                       i = 10;
-                       while (buf[i] == ' ' || buf[i] == '\t')
-                               i++;
-                       if (i4 < 8)
-                       {
-                               if (dns_aton4_s(&buf[i],&addr4) != NULL)
-                                       memcpy(&servers4[i4++],&addr4,sizeof(in_addr));
-                       }
-               }
-       }
-       fclose(f);
-}
-
-void DNS::dns_init_2(const char* dnsserver)
-{
-       in_addr addr4;
-       i4 = 0;
-       srand((unsigned int) TIME);
-       memset(servers4,'\0',sizeof(in_addr) * 8);
-       if (dns_aton4_s(dnsserver,&addr4) != NULL)
-           memcpy(&servers4[i4++],&addr4,sizeof(in_addr));
-}
-
-
-int dns_send_requests(const s_header *h, const s_connection *s, const int l)
-{
-       int i;
-       sockaddr_in addr4;
+       insp_sockaddr addr;
        unsigned char payload[sizeof(s_header)];
 
+       this->_class = 1;
+       this->type = qt;
+               
        dns_empty_header(payload,h,l);
 
-
-       i = 0;
-
-       /* otherwise send via standard ipv4 boringness */
-       memset(&addr4,0,sizeof(addr4));
-       memcpy(&addr4.sin_addr,&servers4[i],sizeof(addr4.sin_addr));
-       addr4.sin_family = AF_INET;
-       addr4.sin_port = htons(53);
-       if (sendto(s->fd, payload, l + 12, 0, (sockaddr *) &addr4, sizeof(addr4)) == -1)
+       memset(&addr,0,sizeof(addr));
+#ifdef IPV6
+       memcpy(&addr.sin6_addr,&myserver,sizeof(addr.sin6_addr));
+       addr.sin6_family = AF_FAMILY;
+       addr.sin6_port = htons(53);
+#else
+       memcpy(&addr.sin_addr.s_addr,&myserver,sizeof(addr.sin_addr));
+       addr.sin_family = AF_FAMILY;
+       addr.sin_port = htons(53);
+#endif
+       if (sendto(master_socket, payload, l + 12, 0, (sockaddr *) &addr, sizeof(addr)) == -1)
        {
+               log(DEBUG,"Error in sendto!");
                return -1;
        }
 
        return 0;
 }
 
-s_connection *dns_add_query(s_header *h)
+s_connection* dns_add_query(s_header *h, int &id)
 {
 
-       s_connection * s = new s_connection;
-       int id = rand() % 65536;
+       id = rand() % 65536;
+       s_connection * s = new s_connection();
 
-       /* set header flags */
-       h->id[0] = s->id[0] = id >> 8; /* verified by dns_getresult_s() */
+       h->id[0] = s->id[0] = id >> 8;
        h->id[1] = s->id[1] = id & 0xFF;
        h->flags1 = 0 | FLAGS1_MASK_RD;
        h->flags2 = 0;
@@ -258,48 +214,63 @@ s_connection *dns_add_query(s_header *h)
        h->ancount = 0;
        h->nscount = 0;
        h->arcount = 0;
-       s->want_list = 0;
-       s->fd = socket(PF_INET, SOCK_DGRAM, 0);
-       if (s->fd != -1)
+
+       if (connections.find(id) == connections.end())
+               connections[id] = s;
+       return s;
+}
+
+void create_socket()
+{
+       log(DEBUG,"---- BEGIN DNS INITIALIZATION, SERVER=%s ---",Config->DNSServer);
+       insp_inaddr addr;
+       srand((unsigned int) TIME);
+       memset(&myserver,0,sizeof(insp_inaddr));
+       if (insp_aton(Config->DNSServer,&addr) > 0)
+               memcpy(&myserver,&addr,sizeof(insp_inaddr));
+
+       master_socket = socket(PF_PROTOCOL, SOCK_DGRAM, 0);
+       if (master_socket != -1)
        {
-               if (fcntl(s->fd, F_SETFL, O_NONBLOCK) != 0)
+               log(DEBUG,"Set query socket nonblock");
+               if (fcntl(master_socket, F_SETFL, O_NONBLOCK) != 0)
                {
-                       shutdown(s->fd,2);
-                       close(s->fd);
-                       s->fd = -1;
+                       shutdown(master_socket,2);
+                       close(master_socket);
+                       master_socket = -1;
                }
        }
-       if (s->fd != -1)
+       if (master_socket != -1)
        {
-               sockaddr_in addr;
+#ifdef IPV6
+               insp_sockaddr addr;
+               memset(&addr,0,sizeof(addr));
+               addr.sin6_family = AF_FAMILY;
+               addr.sin6_port = 0;
+               memset(&addr.sin6_addr,255,sizeof(in6_addr));
+#else
+               insp_sockaddr addr;
                memset(&addr,0,sizeof(addr));
-               addr.sin_family = AF_INET;
+               addr.sin_family = AF_FAMILY;
                addr.sin_port = 0;
                addr.sin_addr.s_addr = INADDR_ANY;
-               if (bind(s->fd,(sockaddr *)&addr,sizeof(addr)) != 0)
+#endif
+               log(DEBUG,"Binding query port");
+               if (bind(master_socket,(sockaddr *)&addr,sizeof(addr)) != 0)
                {
-                       shutdown(s->fd,2);
-                       close(s->fd);
-                       s->fd = -1;
+                       log(DEBUG,"Cant bind with source port = 0");
+                       shutdown(master_socket,2);
+                       close(master_socket);
+                       master_socket = -1;
                }
-       }
-       if (s->fd == -1)
-       {
-               delete s;
-               return NULL;
-       }
-       /* create new connection object, add to linked list */
-       if (connections.find(s->fd) == connections.end())
-               connections[s->fd] = s;
 
-       if (wantclose == 1)
-       {
-               shutdown(lastcreate,2);
-               close(lastcreate);
-               wantclose = 0;
+               if (master_socket >= 0)
+               {
+                       log(DEBUG,"Attach query port to socket engine");
+                       if (ServerInstance && ServerInstance->SE)
+                               ServerInstance->SE->AddFd(master_socket,true,X_ESTAB_DNS);
+               }
        }
-       lastcreate = s->fd;
-       return s;
 }
 
 int dns_build_query_payload(const char * const name, const unsigned short rr, const unsigned short _class, unsigned char * const payload)
@@ -341,182 +312,147 @@ int dns_build_query_payload(const char * const name, const unsigned short rr, co
        return payloadpos + 4;
 }
 
-in_addr* DNS::dns_aton4(const char * const ipstring)
+int DNS::dns_getip4(const char *name)
 {
-       static in_addr ip;
-       return dns_aton4_s(ipstring,&ip);
-}
-
-in_addr* DNS::dns_aton4_r(const char *ipstring) { /* ascii to numeric (reentrant): convert string to new 4part IP addr struct */
-       in_addr* ip;
-       ip = new in_addr;
-       if(dns_aton4_s(ipstring,ip) == NULL)
-       {
-               delete ip;
-               return NULL;
-       }
-       return ip;
-}
-
-in_addr* DNS::dns_aton4_s(const char *ipstring, in_addr *ip) { /* ascii to numeric (buffered): convert string to given 4part IP addr struct */
-       inet_aton(ipstring,ip);
-       return ip;
-}
-
-int DNS::dns_getip4(const char *name) { /* build, add and send A query; retrieve result with dns_getresult() */
+       /* build, add and send A query; retrieve result with dns_getresult() */
        s_header h;
-       s_connection *s;
-       int l;
-
-       dns_init();
+       s_connection* req;
+       int id;
        
-
-       l = dns_build_query_payload(name,DNS_QRY_A,1,(unsigned char *)&h.payload);
-       if (l == -1)
+       int length = dns_build_query_payload(name,DNS_QRY_A,1,(unsigned char*)&h.payload);
+       if (length == -1)
                return -1;
-       s = dns_add_query(&h);
-       if (s == NULL)
+       req = dns_add_query(&h, id);
+       if (req == NULL)
                return -1;
-       s->_class = 1;
-       s->type = DNS_QRY_A;
-       if (dns_send_requests(&h,s,l) == -1)
-               return -1;
-
-       return s->fd;
-}
 
-int DNS::dns_getip4list(const char *name) { /* build, add and send A query; retrieve result with dns_getresult() */
-       s_header h;
-       s_connection *s;
-       int l;
-
-       dns_init();
-       
-       l = dns_build_query_payload(name,DNS_QRY_A,1,(unsigned char *)&h.payload);
-       if (l == -1)
-               return -1;
-       s = dns_add_query(&h);
-       if (s == NULL)
-               return -1;
-       s->_class = 1;
-       s->type = DNS_QRY_A;
-       s->want_list = 1;
-       if (dns_send_requests(&h,s,l) == -1)
+       if (req->send_requests(&h,length,DNS_QRY_A) == -1)
                return -1;
 
-       return s->fd;
+       return id;
 }
 
-int DNS::dns_getname4(const in_addr *ip) { /* build, add and send PTR query; retrieve result with dns_getresult() */
+int DNS::dns_getname4(const insp_inaddr *ip)
+{ /* build, add and send PTR query; retrieve result with dns_getresult() */
+#ifdef IPV6
+       return -1;
+#else
+       log(DEBUG,"DNS::dns_getname4");
        char query[512];
        s_header h;
-       s_connection * s;
+       s_connection* req;
        unsigned char *c;
-       int l;
+       int id;
 
        c = (unsigned char *)&ip->s_addr;
 
        sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
 
-       l = dns_build_query_payload(query,DNS_QRY_PTR,1,(unsigned char *)&h.payload);
-       if (l == -1)
+       int length = dns_build_query_payload(query,DNS_QRY_PTR,1,(unsigned char*)&h.payload);
+       if (length == -1)
                return -1;
-       s = dns_add_query(&h);
-       if (s == NULL)
+       req = dns_add_query(&h, id);
+       if (req == NULL)
                return -1;
-       s->_class = 1;
-       s->type = DNS_QRY_PTR;
-       if (dns_send_requests(&h,s,l) == -1)
+       if (req->send_requests(&h,length,DNS_QRY_PTR) == -1)
                return -1;
 
-       return s->fd;
-}
-
-char* DNS::dns_ntoa4(const in_addr * const ip) { /* numeric to ascii: convert 4part IP addr struct to static string */
-       static char r[256];
-       return dns_ntoa4_s(ip,r);
-}
-
-char* DNS::dns_ntoa4_s(const in_addr *ip, char *r) { /* numeric to ascii (buffered): convert 4part IP addr struct to given string */
-       unsigned char *m;
-       m = (unsigned char *)&ip->s_addr;
-       sprintf(r,"%d.%d.%d.%d",m[0],m[1],m[2],m[3]);
-       return r;
-}
-
-char* DNS::dns_getresult(const int cfd) { /* retrieve result of DNS query */
-       log(DEBUG,"DNS: dns_getresult with cfd=%d",cfd);
-       return dns_getresult_s(cfd,this->localbuf);
+       return id;
+#endif
 }
 
-char* DNS::dns_getresult_s(const int cfd, char *res) { /* retrieve result of DNS query (buffered) */
+/* Return the next id which is ready, and the result attached to it
+ */
+DNSResult DNS::dns_getresult()
+{
+       /* retrieve result of DNS query (buffered) */
        s_header h;
        s_connection *c;
-       int l, i, q, curanswer, o;
-       s_rr_middle rr;
+       int length;
        unsigned char buffer[sizeof(s_header)];
-       unsigned short p;
 
-       if (res)
-               *res = 0;
+       length = recv(master_socket,buffer,sizeof(s_header),0);
+
+       if (length < 12)
+               return std::make_pair(-1,"");
+
+       dns_fill_header(&h,buffer,length - 12);
+
+       // Get the id of this request
+       unsigned long this_id = h.id[1] + (h.id[0] << 8);
+
+       // Do we have a pending request for it?
 
-       /* FireDNS used a linked list for this. How ugly (and slow). */
-       connlist_iter n_iter = connections.find(cfd);
-       if (n_iter == connections.end())
+        connlist_iter n_iter = connections.find(this_id);
+        if (n_iter == connections.end())
+        {
+                log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",master_socket,this_id);
+                return std::make_pair(-1,"");
+        }
+        else
+        {
+                /* Remove the query from the list */
+                c = (s_connection*)n_iter->second;
+                /* We don't delete c here, because its done later when needed */
+                connections.erase(n_iter);
+        }
+       unsigned char* a = c->result_ready(h, length);
+       std::string resultstr;
+
+       if (a == NULL)
        {
-               log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d",cfd);
-               return NULL;
+               resultstr = "";
        }
        else
        {
-               /* Remove the query from the list */
-               c = (s_connection*)n_iter->second;
-               /* We don't delete c here, because its done later when needed */
-               connections.erase(n_iter);
+               if (c->type == DNS_QRY_A)
+               {
+                       char formatted[1024];
+                       snprintf(formatted,1024,"%u.%u.%u.%u",a[0],a[1],a[2],a[3]);
+                       resultstr = std::string(formatted);
+               }
+               else
+               {
+                       resultstr = std::string((const char*)a);
+               }
        }
 
-       l = recv(c->fd,buffer,sizeof(s_header),0);
-       dns_close(c->fd);
-       if (l < 12)
-       {
-               delete c;
-               return NULL;
-       }
-       dns_fill_header(&h,buffer,l - 12);
-       if (c->id[0] != h.id[0] || c->id[1] != h.id[1])
-       {
-               log(DEBUG,"DNS: id mismatch on query");
-               delete c;
-               return NULL; /* ID mismatch */
-       }
+       delete c;
+       return std::make_pair(this_id,resultstr);
+}
+
+/** A result is ready, process it
+ */
+unsigned char* s_connection::result_ready(s_header &h, int length)
+{
+       int i, q, curanswer, o;
+       s_rr_middle rr;
+       unsigned short p;
+                                       
        if ((h.flags1 & FLAGS1_MASK_QR) == 0)
        {
                log(DEBUG,"DNS: didnt get a query result");
-               delete c;
                return NULL;
        }
        if ((h.flags1 & FLAGS1_MASK_OPCODE) != 0)
        {
                log(DEBUG,"DNS: got an OPCODE and didnt want one");
-               delete c;
                return NULL;
        }
        if ((h.flags2 & FLAGS2_MASK_RCODE) != 0)
        {
                log(DEBUG,"DNS lookup failed due to SERVFAIL");
-               delete c;
                return NULL;
        }
        if (h.ancount < 1)
        {
                log(DEBUG,"DNS: no answers!");
-               delete c;
                return NULL;
        }
        i = 0;
        q = 0;
-       l -= 12;
-       while ((unsigned)q < h.qdcount && i < l)
+       length -= 12;
+       while ((unsigned)q < h.qdcount && i < length)
        {
                if (h.payload[i] > 63)
                {
@@ -537,7 +473,7 @@ char* DNS::dns_getresult_s(const int cfd, char *res) { /* retrieve result of DNS
        while ((unsigned)curanswer < h.ancount)
        {
                q = 0;
-               while (q == 0 && i < l)
+               while (q == 0 && i < length)
                {
                        if (h.payload[i] > 63)
                        {
@@ -554,20 +490,19 @@ char* DNS::dns_getresult_s(const int cfd, char *res) { /* retrieve result of DNS
                                else i += h.payload[i] + 1; /* skip length and label */
                        }
                }
-               if (l - i < 10)
+               if (length - i < 10)
                {
-                       delete c;
                        return NULL;
                }
                dns_fill_rr(&rr,&h.payload[i]);
                i += 10;
-               if (rr.type != c->type)
+               if (rr.type != this->type)
                {
                        curanswer++;
                        i += rr.rdlength;
                        continue;
                }
-               if (rr._class != c->_class)
+               if (rr._class != this->_class)
                {
                        curanswer++;
                        i += rr.rdlength;
@@ -575,9 +510,9 @@ char* DNS::dns_getresult_s(const int cfd, char *res) { /* retrieve result of DNS
                }
                break;
        }
-       if ((unsigned)curanswer == h.ancount)
+       if ((unsigned int)curanswer == h.ancount)
                return NULL;
-       if ((unsigned)i + rr.rdlength > (unsigned)l)
+       if (i + rr.rdlength > (unsigned int)length)
                return NULL;
        if (rr.rdlength > 1023)
                return NULL;
@@ -588,10 +523,11 @@ char* DNS::dns_getresult_s(const int cfd, char *res) { /* retrieve result of DNS
                        log(DEBUG,"DNS: got a result of type DNS_QRY_PTR");
                        o = 0;
                        q = 0;
-                       while (q == 0 && i < l && o + 256 < 1023)
+                       while (q == 0 && i < length && o + 256 < 1023)
                        {
                                if (h.payload[i] > 63)
                                {
+                                       log(DEBUG,"DNS: h.payload[i] > 63");
                                        memcpy(&p,&h.payload[i],2);
                                        i = ntohs(p) - 0xC000 - 12;
                                }
@@ -616,56 +552,6 @@ char* DNS::dns_getresult_s(const int cfd, char *res) { /* retrieve result of DNS
                break;
                case DNS_QRY_A:
                        log(DEBUG,"DNS: got a result of type DNS_QRY_A");
-                       if (c->want_list)
-                       {
-                               dns_ip4list *alist = (dns_ip4list *) res; /* we have to trust that this is aligned */
-                               while ((char *)alist - (char *)res < 700)
-                               {
-                                       if (rr.type != DNS_QRY_A)
-                                               break;
-                                       if (rr._class != 1)
-                                               break;
-                                       if (rr.rdlength != 4)
-                                       {
-                                               delete c;
-                                               return NULL;
-                                       }
-                                       memcpy(&alist->ip,&h.payload[i],4);
-                                       if ((unsigned)++curanswer >= h.ancount)
-                                               break;
-                                       i += rr.rdlength;
-                                       q = 0;
-                                       while (q == 0 && i < l)
-                                       {
-                                               if (h.payload[i] > 63)
-                                               {
-                                                       i += 2;
-                                                       q = 1;
-                                               }
-                                               else
-                                               {
-                                                       if (h.payload[i] == 0)
-                                                       {
-                                                               i++;
-                                                               q = 1;
-                                                       }
-                                                       else i += h.payload[i] + 1;
-                                               }
-                                       }
-                                       if (l - i < 10)
-                                       {
-                                               delete c;
-                                               return NULL;
-                                       }
-                                       dns_fill_rr(&rr,&h.payload[i]);
-                                       i += 10;
-                                       alist->next = (dns_ip4list *) dns_align(((char *) alist) + sizeof(dns_ip4list));
-                                       alist = alist->next;
-                                       alist->next = NULL;
-                               }
-                               alist->next = NULL;
-                               break;
-                       }
                        memcpy(res,&h.payload[i],rr.rdlength);
                        res[rr.rdlength] = '\0';
                        break;
@@ -674,204 +560,132 @@ char* DNS::dns_getresult_s(const int cfd, char *res) { /* retrieve result of DNS
                        res[rr.rdlength] = '\0';
                        break;
        }
-       delete c;
        return res;
 }
 
 DNS::DNS()
 {
-       dns_init();
        log(DEBUG,"Create blank DNS");
 }
 
-DNS::DNS(const std::string &dnsserver)
-{
-       dns_init_2(dnsserver.c_str());
-       log(DEBUG,"Create DNS with server '%s'",dnsserver.c_str());
-}
-
-void DNS::SetNS(const std::string &dnsserver)
-{
-       dns_init_2(dnsserver.c_str());
-       log(DEBUG,"Set NS");
-}
-
 DNS::~DNS()
 {
 }
 
-bool DNS::ReverseLookup(const std::string &ip)
+Resolver::Resolver(const std::string &source, bool forward) : input(source), fwd(forward)
 {
-       if (ServerInstance && ServerInstance->stats)
-               ServerInstance->stats->statsDns++;
-       binip = dns_aton4(ip.c_str());
-       if (binip == NULL)
+       if (forward)
        {
-               return false;
+               log(DEBUG,"Resolver: Forward lookup on %s",source.c_str());
+               this->myid = Res->dns_getip4(source.c_str());
        }
-
-       this->myfd = dns_getname4(binip);
-       if (this->myfd == -1)
+       else
        {
-               return false;
+               log(DEBUG,"Resolver: Reverse lookup on %s",source.c_str());
+               insp_inaddr binip;
+               if (insp_aton(source.c_str(), &binip) > 0)
+               {
+                       /* Valid ip address */
+                       this->myid = Res->dns_getname4(&binip);
+               }
        }
-       log(DEBUG,"DNS: ReverseLookup, fd=%d",this->myfd);
-#ifndef THREADED_DNS
-       if (ServerInstance && ServerInstance->SE)
-               ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS);
-#endif
-       return true;
-}
-
-bool DNS::ForwardLookup(const std::string &host)
-{
-       if (ServerInstance && ServerInstance->stats)
-               ServerInstance->stats->statsDns++;
-       this->myfd = dns_getip4(host.c_str());
-       if (this->myfd == -1)
+       if (this->myid == -1)
        {
-               return false;
+               log(DEBUG,"Resolver::Resolver: Could not get an id!");
+               this->OnError(RESOLVER_NSDOWN);
+               throw ModuleException("Resolver: Couldnt get an id to make a request");
+               /* We shouldnt get here really */
+               return;
        }
-       log(DEBUG,"DNS: ForwardLookup, fd=%d",this->myfd);
-#ifndef THREADED_DNS
-       if (ServerInstance && ServerInstance->SE)
-               ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_DNS);
-#endif
-       return true;
+
+       log(DEBUG,"Resolver::Resolver: this->myid=%d",this->myid);
 }
 
-bool DNS::ForwardLookupWithFD(const std::string &host, int &fd)
+void Resolver::OnLookupComplete(const std::string &result)
 {
-       if (ServerInstance && ServerInstance->stats)
-               ServerInstance->stats->statsDns++;
-       this->myfd = dns_getip4(host.c_str());
-       fd = this->myfd;
-       if (this->myfd == -1)
-       {
-               
-       }
-       log(DEBUG,"DNS: ForwardLookupWithFD, fd=%d",this->myfd);
-       if (ServerInstance && ServerInstance->SE)
-               ServerInstance->SE->AddFd(this->myfd,true,X_ESTAB_MODULE);
-       return true;
 }
 
-bool DNS::HasResult(int fd)
+void Resolver::OnError(ResolverError e)
 {
-       return (fd == this->myfd);
 }
 
-/* Only the multithreaded dns uses this poll() based
- * check now. As its in another thread we dont have
- * to worry about its performance that much.
- */
-bool DNS::HasResult()
+Resolver::~Resolver()
 {
-       log(DEBUG,"DNS: HasResult, fd=%d",this->myfd);
-       pollfd polls;
-       polls.fd = this->myfd;
-       polls.events = POLLIN;
-       int ret = poll(&polls,1,1);
-       log(DEBUG,"DNS: Hasresult returning %d",ret);
-       return (ret > 0);
+       log(DEBUG,"Resolver::~Resolver");
 }
 
-int DNS::GetFD()
+int Resolver::GetId()
 {
-       return this->myfd;
+       return this->myid;
 }
 
-std::string DNS::GetResult()
+bool Resolver::ProcessResult(const std::string &result)
 {
-       log(DEBUG,"DNS: GetResult()");
-       result = dns_getresult(this->myfd);
-       if (result)
+       log(DEBUG,"Resolver::ProcessResult");
+
+       if (!result.length())
        {
-               if (ServerInstance && ServerInstance->stats)
-                       ServerInstance->stats->statsDnsGood++;
-               dns_close(this->myfd);
-               return result;
+               log(DEBUG,"Resolver::OnError(RESOLVER_NXDOMAIN)");
+               this->OnError(RESOLVER_NXDOMAIN);
+               return false;
        }
        else
        {
-               if (ServerInstance && ServerInstance->stats)
-                       ServerInstance->stats->statsDnsBad++;
-               if (this->myfd != -1)
-               {
-                       dns_close(this->myfd);
-               }
-               return "";
+
+               log(DEBUG,"Resolver::OnLookupComplete(%s)",result.c_str());
+               this->OnLookupComplete(result);
+               return true;
        }
 }
 
-std::string DNS::GetResultIP()
+void dns_deal_with_classes(int fd)
 {
-       char r[1024];
-       log(DEBUG,"DNS: GetResultIP()");
-       result = dns_getresult(this->myfd);
-       if (this->myfd != -1)
-       {
-               dns_close(this->myfd);
-       }
-       if (result)
-       {
-               if (ServerInstance && ServerInstance->stats)
-                       ServerInstance->stats->statsDnsGood++;
-               unsigned char a = (unsigned)result[0];
-               unsigned char b = (unsigned)result[1];
-               unsigned char c = (unsigned)result[2];
-               unsigned char d = (unsigned)result[3];
-               snprintf(r,1024,"%u.%u.%u.%u",a,b,c,d);
-               return r;
-       }
-       else
+       log(DEBUG,"dns_deal_with_classes(%d)",fd);
+       if (fd == master_socket)
        {
-               if (ServerInstance && ServerInstance->stats)
-                       ServerInstance->stats->statsDnsBad++;
-               log(DEBUG,"DANGER WILL ROBINSON! NXDOMAIN for forward lookup, but we got a reverse lookup!");
-               return "";
+               DNSResult res = Res->dns_getresult();
+               if (res.first != -1)
+               {
+                       log(DEBUG,"Result available, id=%d",res.first);
+                       if (dns_classes[res.first])
+                       {
+                               dns_classes[res.first]->ProcessResult(res.second);
+                               delete dns_classes[res.first];
+                               dns_classes[res.first] = NULL;
+                       }
+               }
        }
 }
 
-
-
-#ifdef THREADED_DNS
-void* dns_task(void* arg)
+bool dns_add_class(Resolver* r)
 {
-       userrec* u = (userrec*)arg;
-       log(DEBUG,"DNS thread for user %s",u->nick);
-       DNS dns1;
-       DNS dns2;
-       std::string host;
-       std::string ip;
-       if (dns1.ReverseLookup((char*)inet_ntoa(u->ip4)))
+       log(DEBUG,"dns_add_class");
+       if ((r) && (r->GetId() > -1))
        {
-               while (!dns1.HasResult())
+               if (!dns_classes[r->GetId()])
                {
-                       usleep(100);
+                       log(DEBUG,"dns_add_class: added class");
+                       dns_classes[r->GetId()] = r;
+                       return true;
                }
-               host = dns1.GetResult();
-               if (host != "")
+               else
                {
-                       if (dns2.ForwardLookup(host))
-                       {
-                               while (!dns2.HasResult())
-                               {
-                                       usleep(100);
-                               }
-                               ip = dns2.GetResultIP();
-                               if (ip == std::string((char*)inet_ntoa(u->ip4)))
-                               {
-                                       if (host.length() < 160)
-                                       {
-                                               strcpy(u->host,host.c_str());
-                                               strcpy(u->dhost,host.c_str());
-                                       }
-                               }
-                       }
+                       log(DEBUG,"Space occupied!");
+                       return false;
                }
        }
-       u->dns_done = true;
-       return NULL;
+       else
+       {
+               log(DEBUG,"Bad class");
+               delete r;
+               return true;
+       }
 }
-#endif
+
+void init_dns()
+{
+       Res = new DNS();
+       memset(dns_classes,0,sizeof(dns_classes));
+       create_socket();
+}
+