]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/dns.cpp
Removed a pointless check in ./configure --clean that made it only work with one...
[user/henk/code/inspircd.git] / src / dns.cpp
index e5c1388f6ecb662c9cbcf82e2ad5347d555deffb..756c2d5dc12c6cfdc442f1fd585e8881d7171d38 100644 (file)
@@ -2,14 +2,11 @@
  *       | Inspire Internet Relay Chat Daemon |
  *       +------------------------------------+
  *
- *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
- *                    E-mail:
- *             <brain@chatspike.net>
- *             <Craig@chatspike.net>
- *     
- * Written by Craig Edwards, Craig McLure, and others.
+ *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
  * This program is free but copyrighted software; see
- *         the file COPYING for details.
+ *            the file COPYING for details.
  *
  * ---------------------------------------------------
  */
@@ -24,8 +21,6 @@ Please do not assume that firedns works like this,
 looks like this, walks like this or tastes like this.
 */
 
-using namespace std;
-
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <errno.h>
@@ -37,7 +32,6 @@ using namespace std;
 #include "configreader.h"
 #include "socket.h"
 
-using namespace std;
 using irc::sockets::insp_sockaddr;
 using irc::sockets::insp_inaddr;
 using irc::sockets::insp_ntoa;
@@ -91,39 +85,68 @@ class DNSHeader
        unsigned char   payload[512];   /* Packet payload */
 };
 
-/** Represents a request 'on the wire' with routing information relating to
- * where to call when we get a result
- */
 class DNSRequest
 {
  public:
        unsigned char   id[2];          /* Request id */
-       unsigned char*  res;            /* Result processing buffer */
-       unsigned int    rr_class;       /* Request class */
+       unsigned char*  res;            /* Result processing buffer */
+       unsigned int    rr_class;       /* Request class */
        QueryType       type;           /* Request type */
-       insp_inaddr     myserver;       /* DNS server address*/
-       DNS*            dnsobj;         /* DNS caller (where we get our FD from) */
+       insp_inaddr     myserver;       /* DNS server address*/
+       DNS*            dnsobj;         /* DNS caller (where we get our FD from) */
 
-       /* Allocate the processing buffer */
-       DNSRequest(DNS* dns, insp_inaddr server) : dnsobj(dns)
+       DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id);
+       ~DNSRequest();
+       DNSInfo ResultIsReady(DNSHeader &h, int length);
+       int SendRequests(const DNSHeader *header, const int length, QueryType qt);
+};
+
+class RequestTimeout : public InspTimer
+{
+       InspIRCd* ServerInstance;
+       DNSRequest* watch;
+       int watchid;
+ public:
+       RequestTimeout(unsigned long n, InspIRCd* SI, DNSRequest* watching, int id) : InspTimer(n, time(NULL)), ServerInstance(SI), watch(watching), watchid(id)
        {
-               res = new unsigned char[512];
-               *res = 0;
-               memcpy(&myserver, &server, sizeof(insp_inaddr));
+               ServerInstance->Log(DEBUG, "New DNS timeout set on %08x", watching);
        }
 
-       /* Deallocate the processing buffer */
-       ~DNSRequest()
+       void Tick(time_t TIME)
        {
-               delete[] res;
+               if (ServerInstance->Res->requests[watchid] == watch)
+               {
+                       /* Still exists, whack it */
+                       if (ServerInstance->Res->Classes[watchid])
+                       {
+                               ServerInstance->Res->Classes[watchid]->OnError(RESOLVER_TIMEOUT, "Request timed out");
+                               delete ServerInstance->Res->Classes[watchid];
+                               ServerInstance->Res->Classes[watchid] = NULL;
+                       }
+                       ServerInstance->Res->requests[watchid] = NULL;
+                       delete watch;
+                       ServerInstance->Log(DEBUG, "DNS timeout on %08x squished pointer", watch);
+                       return;
+               }
+               ServerInstance->Log(DEBUG, "DNS timeout on %08x: result already received!", watch);
        }
+};
 
-       /* Called when a result is ready to be processed which matches this id */
-       DNSInfo ResultIsReady(DNSHeader &h, int length);
+/* Allocate the processing buffer */
+DNSRequest::DNSRequest(InspIRCd* Instance, DNS* dns, insp_inaddr server, int id) : dnsobj(dns)
+{
+       res = new unsigned char[512];
+       *res = 0;
+       memcpy(&myserver, &server, sizeof(insp_inaddr));
+       RequestTimeout* RT = new RequestTimeout(Instance->Config->dns_timeout ? Instance->Config->dns_timeout : 5, Instance, this, id);
+       Instance->Timers->AddTimer(RT); /* The timer manager frees this */
+}
 
-       /* Called when there are requests to be sent out */
-       int SendRequests(const DNSHeader *header, const int length, QueryType qt);
-};
+/* Deallocate the processing buffer */
+DNSRequest::~DNSRequest()
+{
+       delete[] res;
+}
 
 /** Fill a ResourceRecord class based on raw data input */
 inline void DNS::FillResourceRecord(ResourceRecord* rr, const unsigned char *input)
@@ -199,19 +222,15 @@ DNSRequest* DNS::AddQuery(DNSHeader *header, int &id)
        /* Is the DNS connection down? */
        if (this->GetFd() == -1)
                return NULL;
-
-       /* Are there already the max number of requests on the go? */
-       if (requests.size() == DNS::MAX_REQUEST_ID + 1)
-               return NULL;
        
        /* Create an id */
        id = this->PRNG() & DNS::MAX_REQUEST_ID;
 
        /* If this id is already 'in flight', pick another. */
-       while (requests.find(id) != requests.end())
+       while (requests[id])
                id = this->PRNG() & DNS::MAX_REQUEST_ID;
 
-       DNSRequest* req = new DNSRequest(this, this->myserver);
+       DNSRequest* req = new DNSRequest(ServerInstance, this, this->myserver, id);
 
        header->id[0] = req->id[0] = id >> 8;
        header->id[1] = req->id[1] = id & 0xFF;
@@ -241,6 +260,9 @@ DNS::DNS(InspIRCd* Instance) : ServerInstance(Instance)
        /* Clear the Resolver class table */
        memset(Classes,0,sizeof(Classes));
 
+       /* Clear the requests class table */
+       memset(requests,0,sizeof(requests));
+
        /* Set the id of the next request to 0
         */
        currid = 0;
@@ -435,10 +457,15 @@ int DNS::GetName(const insp_inaddr *ip)
        int length;
 
 #ifdef IPV6
-       DNS::MakeIP6Int(query, (in6_addr*)ip);
+       unsigned char* c = (unsigned char*)&ip->s6_addr;
+       if (c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0 &&
+           c[4] == 0 && c[5] == 0 && c[6] == 0 && c[7] == 0 &&
+           c[8] == 0 && c[9] == 0 && c[10] == 0xFF && c[11] == 0xFF)
+               sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[15],c[14],c[13],c[12]);
+       else
+               DNS::MakeIP6Int(query, (in6_addr*)ip);
 #else
        unsigned char* c = (unsigned char*)&ip->s_addr;
-
        sprintf(query,"%d.%d.%d.%d.in-addr.arpa",c[3],c[2],c[1],c[0]);
 #endif
 
@@ -585,8 +612,7 @@ DNSResult DNS::GetResult()
        unsigned long this_id = header.id[1] + (header.id[0] << 8);
 
        /* Do we have a pending request matching this id? */
-       requestlist_iter n_iter = requests.find(this_id);
-       if (n_iter == requests.end())
+       if (!requests[this_id])
        {
                /* Somehow we got a DNS response for a request we never made... */
                ServerInstance->Log(DEBUG,"DNS: got a response for a query we didnt send with fd=%d queryid=%d",this->GetFd(),this_id);
@@ -595,8 +621,8 @@ DNSResult DNS::GetResult()
        else
        {
                /* Remove the query from the list of pending queries */
-               req = (DNSRequest*)n_iter->second;
-               requests.erase(n_iter);
+               req = requests[this_id];
+               requests[this_id] = NULL;
        }
 
        /* Inform the DNSRequest class that it has a result to be read.
@@ -693,7 +719,11 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
        int curanswer, o;
        ResourceRecord rr;
        unsigned short ptr;
-                       
+
+       /* This is just to keep _FORTIFY_SOURCE happy */
+       rr.type = DNS_QUERY_NONE;
+       rr.rdlength = 0;
+
        if (!(header.flags1 & FLAGS_MASK_QR))
                return std::make_pair((unsigned char*)NULL,"Not a query result");
 
@@ -832,7 +862,7 @@ DNS::~DNS()
 }
 
 /** High level abstraction of dns used by application at large */
-Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt) : ServerInstance(Instance), input(source), querytype(qt)
+Resolver::Resolver(InspIRCd* Instance, const std::string &source, QueryType qt, Module* creator) : ServerInstance(Instance), Creator(creator), input(source), querytype(qt)
 {
        ServerInstance->Log(DEBUG,"Instance: %08x %08x",Instance, ServerInstance);
 
@@ -910,10 +940,14 @@ int Resolver::GetId()
        return this->myid;
 }
 
+Module* Resolver::GetCreator()
+{
+       return this->Creator;
+}
+
 /** Process a socket read event */
-void DNS::HandleEvent(EventType et)
+void DNS::HandleEvent(EventType et, int errornum)
 {
-       ServerInstance->Log(DEBUG,"Marshall reads: %d",this->GetFd());
        /* Fetch the id and result of the next available packet */
        DNSResult res = this->GetResult();
        /* Is there a usable request id? */
@@ -987,6 +1021,22 @@ bool DNS::AddResolverClass(Resolver* r)
        }
 }
 
+void DNS::CleanResolvers(Module* module)
+{
+       for (int i = 0; i < MAX_REQUEST_ID; i++)
+       {
+               if (Classes[i])
+               {
+                       if (Classes[i]->GetCreator() == module)
+                       {
+                               Classes[i]->OnError(RESLOVER_FORCEUNLOAD, "Parent module is unloading");
+                               delete Classes[i];
+                               Classes[i] = NULL;
+                       }
+               }
+       }
+}
+
 /** Generate pseudo-random number */
 unsigned long DNS::PRNG()
 {