X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fdns.cpp;h=14305ccab2f49a2a4e94f94ee67dc543c34e92c2;hb=68211809ee3111bdc9609fbd46dc3c875fbb5ea6;hp=be74e6aa341f5fa3581b29051bcfe874d7df3936;hpb=ed28c1ba666b39581adb860bf51cdde43c84cc89;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/dns.cpp b/src/dns.cpp index be74e6aa3..14305ccab 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -1,16 +1,27 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2012 William Pitcock + * Copyright (C) 2009-2010 Daniel De Graaf + * Copyright (C) 2006, 2009 Robin Burchell + * Copyright (C) 2007, 2009 Dennis Friis + * Copyright (C) 2008 Thomas Stagner + * Copyright (C) 2005-2007 Craig Edwards * - * 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 . */ + /* $Core */ /* @@ -23,7 +34,7 @@ Please do not assume that firedns works like this, looks like this, walks like this or tastes like this. */ -#ifndef WIN32 +#ifndef _WIN32 #include #include #include @@ -149,7 +160,7 @@ class RequestTimeout : public Timer } }; -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) { expires = ServerInstance->Time() + ttl; } @@ -247,8 +258,28 @@ DNSRequest* DNS::AddQuery(DNSHeader *header, int &id, const char* original) 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); @@ -360,10 +391,6 @@ DNS::DNS() /* 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; @@ -585,8 +612,10 @@ DNSResult DNS::GetResult() */ 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,""); } @@ -648,19 +677,13 @@ DNSResult DNS::GetResult() 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 @@ -677,8 +700,16 @@ DNSResult DNS::GetResult() /* 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: @@ -687,8 +718,9 @@ DNSResult DNS::GetResult() /* 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; } } @@ -800,6 +832,8 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) */ case DNS_QUERY_CNAME: case DNS_QUERY_PTR: + { + unsigned short lowest_pos = length; o = 0; q = 0; while (q == 0 && i < length && o + 256 < 1023) @@ -812,14 +846,18 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) 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 { @@ -843,6 +881,7 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, unsigned length) } } res[o] = 0; + } break; case DNS_QUERY_AAAA: if (rr.rdlength != sizeof(struct in6_addr)) @@ -909,11 +948,12 @@ Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module { ServerInstance->Res->DelCache(source); } - else + else if (CQ->type == qt) { cached = true; return; } + CQ = NULL; } switch (querytype) @@ -1018,7 +1058,7 @@ void DNS::HandleEvent(EventType, int) 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))); + 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]; @@ -1048,20 +1088,13 @@ bool DNS::AddResolverClass(Resolver* r) 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)