X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fdns.cpp;h=461722b29dba2e7539bd864a8b09d73968c69ca8;hb=551d687ec6d7ce44be35fae0dd7345fe73c4f63a;hp=2bfa0be20deb9c9e0b51eeefa72b534f306960ed;hpb=9aa28f3730fb3dd69c1e06f78bb2bbc43d36c684;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/dns.cpp b/src/dns.cpp index 2bfa0be20..461722b29 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 @@ -100,7 +111,7 @@ class DNSRequest 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); }; @@ -223,7 +234,7 @@ inline void DNS::EmptyHeader(unsigned char *output, const DNSHeader *header, con /** Send requests we have previously built down the UDP socket */ int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryType qt) { - ServerInstance->Logs->Log("RESOLVER", DEBUG,"DNSRequest::SendRequests"); + ServerInstance->Logs->Log("RESOLVER", LOG_DEBUG,"DNSRequest::SendRequests"); unsigned char payload[sizeof(DNSHeader)]; @@ -235,7 +246,7 @@ int DNSRequest::SendRequests(const DNSHeader *header, const int length, QueryTyp if (ServerInstance->SE->SendTo(dnsobj, payload, length + 12, 0, &(dnsobj->myserver.sa), sa_size(dnsobj->myserver)) != length+12) return -1; - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Sent OK"); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Sent OK"); return 0; } @@ -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); @@ -331,14 +362,14 @@ void DNS::Rehash() if (ServerInstance->SE->Bind(this->GetFd(), bindto) < 0) { /* Failed to bind */ - ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error binding dns socket - hostnames will NOT resolve"); + ServerInstance->Logs->Log("RESOLVER",LOG_SPARSE,"Error binding dns socket - hostnames will NOT resolve"); ServerInstance->SE->Shutdown(this, 2); ServerInstance->SE->Close(this); this->SetFd(-1); } else if (!ServerInstance->SE->AddFd(this, FD_WANT_POLL_READ | FD_WANT_NO_WRITE)) { - ServerInstance->Logs->Log("RESOLVER",SPARSE,"Internal error starting DNS - hostnames will NOT resolve."); + ServerInstance->Logs->Log("RESOLVER",LOG_SPARSE,"Internal error starting DNS - hostnames will NOT resolve."); ServerInstance->SE->Shutdown(this, 2); ServerInstance->SE->Close(this); this->SetFd(-1); @@ -346,24 +377,20 @@ void DNS::Rehash() } else { - ServerInstance->Logs->Log("RESOLVER",SPARSE,"Error creating DNS socket - hostnames will NOT resolve"); + ServerInstance->Logs->Log("RESOLVER",LOG_SPARSE,"Error creating DNS socket - hostnames will NOT resolve"); } } /** Initialise the DNS UDP socket so that we can send requests */ DNS::DNS() { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::DNS"); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::DNS"); /* 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; - /* DNS::Rehash() sets this to a valid ptr */ this->cache = NULL; @@ -490,7 +517,7 @@ int DNS::GetNameForce(const char *ip, ForceProtocol fp) } else { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce IPv6 bad format for '%s'", ip); /* Invalid IP address */ return -1; } @@ -505,7 +532,7 @@ int DNS::GetNameForce(const char *ip, ForceProtocol fp) } else { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce IPv4 bad format for '%s'", ip); /* Invalid IP address */ return -1; } @@ -514,7 +541,7 @@ int DNS::GetNameForce(const char *ip, ForceProtocol fp) length = this->MakePayload(query, DNS_QUERY_PTR, 1, (unsigned char*)&h.payload); if (length == -1) { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce can't query '%s' using '%s' because it's too long", ip, query); return -1; } @@ -522,13 +549,13 @@ int DNS::GetNameForce(const char *ip, ForceProtocol fp) if (!req) { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't add query (resolver down?)"); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce can't add query (resolver down?)"); return -1; } if (req->SendRequests(&h, length, DNS_QUERY_PTR) == -1) { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS::GetNameForce can't send (firewall?)"); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS::GetNameForce can't send (firewall?)"); return -1; } @@ -569,7 +596,7 @@ DNSResult DNS::GetResult() /* Did we get the whole header? */ if (length < 12) { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"GetResult didn't get a full packet (len=%d)", length); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"GetResult didn't get a full packet (len=%d)", length); /* Nope - something screwed up. */ return DNSResult(-1,"",0,""); } @@ -585,8 +612,10 @@ DNSResult DNS::GetResult() */ if (from != myserver) { - 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()); + std::string server1 = from.str(); + std::string server2 = myserver.str(); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Got a result from the wrong server! Bad NAT or DNS forging attempt? '%s' != '%s'", + server1.c_str(), server2.c_str()); return DNSResult(-1,"",0,""); } @@ -603,7 +632,7 @@ DNSResult DNS::GetResult() if (!requests[this_id]) { /* Somehow we got a DNS response for a request we never made... */ - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Hmm, got a result that we didn't ask for (id=%lx). Ignoring.", this_id); return DNSResult(-1,"",0,""); } else @@ -693,7 +722,7 @@ DNSResult DNS::GetResult() } /** 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; @@ -722,7 +751,7 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) /* 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) { @@ -743,7 +772,7 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) while ((unsigned)curanswer < header.ancount) { q = 0; - while (q == 0 && i < (unsigned) length) + while (q == 0 && i < length) { if (header.payload[i] > 63) { @@ -760,14 +789,14 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) else i += header.payload[i] + 1; /* skip length and label */ } } - if ((unsigned) length - i < 10) + if (static_cast(length - i) < 10) return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply"); /* XXX: We actually initialise 'rr' here including its ttl field */ DNS::FillResourceRecord(&rr,&header.payload[i]); i += 10; - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver: rr.type is %d and this.type is %d rr.class %d this.class %d", rr.type, this->type, rr.rr_class, this->rr_class); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Resolver: rr.type is %d and this.type is %d rr.class %d this.class %d", rr.type, this->type, rr.rr_class, this->rr_class); if (rr.type != this->type) { curanswer++; @@ -800,9 +829,11 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) */ 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) @@ -812,14 +843,18 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int 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,18 +878,24 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) } } 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"); @@ -893,7 +934,7 @@ void Resolver::TriggerCachedResult() /** High level abstraction of dns used by application at large */ Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module* creator) : Creator(creator), input(source), querytype(qt) { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Resolver::Resolver"); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Resolver::Resolver"); cached = false; CQ = ServerInstance->Res->GetCache(source); @@ -936,7 +977,7 @@ Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module break; default: - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request with unknown query type %d", querytype); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS request with unknown query type %d", querytype); this->myid = -1; break; } @@ -946,7 +987,7 @@ Resolver::Resolver(const std::string &source, QueryType qt, bool &cached, Module } else { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"DNS request id %d", this->myid); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"DNS request id %d", this->myid); } } @@ -979,11 +1020,11 @@ void DNS::HandleEvent(EventType, int) /* Fetch the id and result of the next available packet */ DNSResult res(0,"",0,""); res.id = 0; - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Handle DNS event"); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Handle DNS event"); res = this->GetResult(); - ServerInstance->Logs->Log("RESOLVER",DEBUG,"Result id %d", res.id); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"Result id %d", res.id); /* Is there a usable request id? */ if (res.id != -1) @@ -1029,7 +1070,7 @@ void DNS::HandleEvent(EventType, int) /** Add a derived Resolver to the working set */ bool DNS::AddResolverClass(Resolver* r) { - ServerInstance->Logs->Log("RESOLVER",DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r); + ServerInstance->Logs->Log("RESOLVER",LOG_DEBUG,"AddResolverClass 0x%08lx", (unsigned long)r); /* Check the pointers validity and the id's validity */ if ((r) && (r->GetId() > -1)) { @@ -1043,20 +1084,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)