-/* +------------------------------------+
- * | Inspire Internet Relay Chat Daemon |
- * +------------------------------------+
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2012 William Pitcock <nenolod@dereferenced.org>
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2006, 2009 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ * Copyright (C) 2005-2007 Craig Edwards <craigedwards@brainbox.cc>
*
- * InspIRCd: (C) 2002-2010 InspIRCd Development Team
- * See: http://wiki.inspircd.org/Credits
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
*
- * This program is free but copyrighted software; see
- * the file COPYING for details.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
*
- * ---------------------------------------------------
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
/* $Core */
/*
looks like this, walks like this or tastes like this.
*/
-#ifndef WIN32
+#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
DNSRequest(DNS* dns, int id, const std::string &original);
~DNSRequest();
- DNSInfo ResultIsReady(DNSHeader &h, int length);
+ DNSInfo ResultIsReady(DNSHeader &h, unsigned length);
int SendRequests(const DNSHeader *header, const int length, QueryType qt);
};
DNS* dns;
public:
CacheTimer(DNS* thisdns)
- : Timer(3600, ServerInstance->Time(), true), dns(thisdns) { }
+ : Timer(5*60, ServerInstance->Time(), true), dns(thisdns) { }
virtual void Tick(time_t)
{
}
};
-CachedQuery::CachedQuery(const std::string &res, unsigned int ttl) : data(res)
+CachedQuery::CachedQuery(const std::string &res, QueryType qt, unsigned int ttl) : data(res), type(qt)
{
+ if (ttl > 5*60)
+ ttl = 5*60;
expires = ServerInstance->Time() + ttl;
}
return NULL;
/* Create an id */
+ unsigned int tries = 0;
do {
id = ServerInstance->GenRandomInt(DNS::MAX_REQUEST_ID);
+ if (++tries == DNS::MAX_REQUEST_ID*5)
+ {
+ // If we couldn't find an empty slot this many times, do a sequential scan as a last
+ // resort. If an empty slot is found that way, go on, otherwise throw an exception
+ id = -1;
+ for (int i = 0; i < DNS::MAX_REQUEST_ID; i++)
+ {
+ if (!requests[i])
+ {
+ id = i;
+ break;
+ }
+ }
+
+ if (id == -1)
+ throw ModuleException("DNS: All ids are in use");
+
+ break;
+ }
} while (requests[id]);
DNSRequest* req = new DNSRequest(this, id, original);
/* Clear the requests class table */
memset(requests,0,sizeof(requests));
- /* Set the id of the next request to 0
- */
- currid = 0;
-
/* DNS::Rehash() sets this to a valid ptr
*/
this->cache = NULL;
*/
if (from != myserver)
{
+ std::string server1 = from.str();
+ std::string server2 = myserver.str();
ServerInstance->Logs->Log("RESOLVER",DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'",
- from.str().c_str(), myserver.str().c_str());
+ server1.c_str(), server2.c_str());
return DNSResult(-1,"",0,"");
}
case DNS_QUERY_AAAA:
{
- inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted));
- char* c = strstr(formatted,":0:");
- if (c != NULL)
+ if (!inet_ntop(AF_INET6, data.first, formatted, sizeof(formatted)))
{
- memmove(c+1,c+2,strlen(c+2) + 1);
- c += 2;
- while (memcmp(c,"0:",2) == 0)
- memmove(c,c+2,strlen(c+2) + 1);
- if (memcmp(c,"0",2) == 0)
- *c = 0;
- if (memcmp(formatted,"0::",3) == 0)
- memmove(formatted,formatted + 1, strlen(formatted + 1) + 1);
+ std::string ro = req->orig;
+ delete req;
+ return DNSResult(this_id | ERROR_MASK, "inet_ntop() failed", 0, ro);
}
+
resultstr = formatted;
/* Special case. Sending ::1 around between servers
/* Identical handling to PTR */
case DNS_QUERY_PTR:
+ {
/* Reverse lookups just come back as char* */
resultstr = std::string((const char*)data.first);
+ if (resultstr.find_first_not_of("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-") != std::string::npos)
+ {
+ std::string ro = req->orig;
+ delete req;
+ return DNSResult(this_id | ERROR_MASK, "Invalid char(s) in reply", 0, ro);
+ }
+ }
break;
default:
/* Build the reply with the id and hostname/ip in it */
std::string ro = req->orig;
+ DNSResult result = DNSResult(this_id,resultstr,ttl,ro,req->type);
delete req;
- return DNSResult(this_id,resultstr,ttl,ro);
+ return result;
}
}
/** A result is ready, process it */
-DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length)
+DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length)
{
unsigned i = 0, o;
int q = 0;
/* Subtract the length of the header from the length of the packet */
length -= 12;
- while ((unsigned int)q < header.qdcount && i < (unsigned) length)
+ while ((unsigned int)q < header.qdcount && i < length)
{
if (header.payload[i] > 63)
{
while ((unsigned)curanswer < header.ancount)
{
q = 0;
- while (q == 0 && i < (unsigned) length)
+ while (q == 0 && i < length)
{
if (header.payload[i] > 63)
{
else i += header.payload[i] + 1; /* skip length and label */
}
}
- if ((unsigned) length - i < 10)
+ if (static_cast<int>(length - i) < 10)
return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply");
/* XXX: We actually initialise 'rr' here including its ttl field */
*/
case DNS_QUERY_CNAME:
case DNS_QUERY_PTR:
+ {
+ unsigned short lowest_pos = length;
o = 0;
q = 0;
- while (q == 0 && i < (unsigned) length && o + 256 < 1023)
+ while (q == 0 && i < length && o + 256 < 1023)
{
/* DN label found (byte over 63) */
if (header.payload[i] > 63)
i = ntohs(ptr);
/* check that highest two bits are set. if not, we've been had */
- if (!(i & DN_COMP_BITMASK))
+ if ((i & DN_COMP_BITMASK) != DN_COMP_BITMASK)
return std::make_pair((unsigned char *) NULL, "DN label decompression header is bogus");
/* mask away the two highest bits. */
i &= ~DN_COMP_BITMASK;
/* and decrease length by 12 bytes. */
- i =- 12;
+ i -= 12;
+
+ if (i >= lowest_pos)
+ return std::make_pair((unsigned char *) NULL, "Invalid decompression pointer");
+ lowest_pos = i;
}
else
{
}
}
res[o] = 0;
+ }
break;
case DNS_QUERY_AAAA:
+ if (rr.rdlength != sizeof(struct in6_addr))
+ return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 16 bytes for an ipv6 entry -- malformed/hostile packet?");
+
memcpy(res,&header.payload[i],rr.rdlength);
res[rr.rdlength] = 0;
break;
case DNS_QUERY_A:
+ if (rr.rdlength != sizeof(struct in_addr))
+ return std::make_pair((unsigned char *) NULL, "rr.rdlength is larger than 4 bytes for an ipv4 entry -- malformed/hostile packet?");
+
memcpy(res,&header.payload[i],rr.rdlength);
res[rr.rdlength] = 0;
break;
default:
- memcpy(res,&header.payload[i],rr.rdlength);
- res[rr.rdlength] = 0;
+ return std::make_pair((unsigned char *) NULL, "don't know how to handle undefined type (" + ConvToStr(rr.type) + ") -- rejecting");
break;
}
return std::make_pair(res,"No error");
{
ServerInstance->Res->DelCache(source);
}
- else
+ else if (CQ->type == qt)
{
cached = true;
return;
}
+ CQ = NULL;
}
switch (querytype)
ServerInstance->stats->statsDnsGood++;
if (!this->GetCache(res.original.c_str()))
- this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl)));
+ {
+ if (cache->size() >= MAX_CACHE_SIZE)
+ cache->clear();
+ this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.type, res.ttl)));
+ }
Classes[res.id]->OnLookupComplete(res.result, res.ttl, false);
delete Classes[res.id];
Classes[r->GetId()] = r;
return true;
}
- else
- /* Duplicate id */
- return false;
}
- else
- {
- /* Pointer or id not valid.
- * Free the item and return
- */
- if (r)
- delete r;
- return false;
- }
+ /* Pointer or id not valid, or duplicate id.
+ * Free the item and return
+ */
+ delete r;
+ return false;
}
void DNS::CleanResolvers(Module* module)