From: Remi Gacogne Date: Mon, 11 Jan 2021 10:06:42 +0000 (+0100) Subject: dnsdist: Fix "keyword 'try' is not allowed in global scope" warning X-Git-Tag: rec-4.5.0-alpha1~19^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F9616%2Fhead;p=thirdparty%2Fpdns.git dnsdist: Fix "keyword 'try' is not allowed in global scope" warning Reported by cppcheck. Using a proper block function also makes the code easier to read. The diff looks huge but that's mostly indentation changes, getting rid of the changed whitespaces yields a very small diff. --- diff --git a/pdns/dnsdist-carbon.cc b/pdns/dnsdist-carbon.cc index 53475dfa9e..b22e7dc581 100644 --- a/pdns/dnsdist-carbon.cc +++ b/pdns/dnsdist-carbon.cc @@ -31,241 +31,244 @@ #include "threadname.hh" GlobalStateHolder > g_carbon; -static time_t s_start=time(0); +static time_t s_start = time(nullptr); + uint64_t uptimeOfProcess(const std::string& str) { - return time(0) - s_start; + return time(nullptr) - s_start; } void carbonDumpThread() -try { - setThreadName("dnsdist/carbon"); - auto localCarbon = g_carbon.getLocal(); - for(int numloops=0;;++numloops) { - if(localCarbon->empty()) { - sleep(1); - continue; - } - /* this is wrong, we use the interval of the first server - for every single one of them */ - if(numloops) { - const unsigned int interval = localCarbon->at(0).interval; - sleep(interval); - } - - for (const auto& conf : *localCarbon) { - const auto& server = conf.server; - const std::string& namespace_name = conf.namespace_name; - std::string hostname = conf.ourname; - if (hostname.empty()) { - try { - hostname = getCarbonHostName(); - } - catch(const std::exception& e) { - throw std::runtime_error(std::string("The 'ourname' setting in 'carbonServer()' has not been set and we are unable to determine the system's hostname: ") + e.what()); - } + try + { + setThreadName("dnsdist/carbon"); + auto localCarbon = g_carbon.getLocal(); + for(int numloops=0;;++numloops) { + if(localCarbon->empty()) { + sleep(1); + continue; + } + /* this is wrong, we use the interval of the first server + for every single one of them */ + if(numloops) { + const unsigned int interval = localCarbon->at(0).interval; + sleep(interval); } - const std::string& instance_name = conf.instance_name; - - try { - Socket s(server.sin4.sin_family, SOCK_STREAM); - s.setNonBlocking(); - s.connect(server); // we do the connect so the attempt happens while we gather stats - ostringstream str; - time_t now=time(0); - for(const auto& e : g_stats.entries) { - str<(&e.second)) - str<<(*val)->load(); - else if (const auto& dval = boost::get(&e.second)) - str<<**dval; - else - str<<(*boost::get(&e.second))(e.first); - str<<' '<getName().empty() ? state->remote.toStringWithPort() : state->getName(); - boost::replace_all(serverName, ".", "_"); - const string base = namespace_name + "." + hostname + "." + instance_name + ".servers." + serverName + "."; - str<queries.load() << " " << now << "\r\n"; - str<responses.load() << " " << now << "\r\n"; - str<reuseds.load() << " " << now << "\r\n"; - str<availability != DownstreamState::Availability::Down ? state->latencyUsec/1000.0 : 0) << " " << now << "\r\n"; - str<sendErrors.load() << " " << now << "\r\n"; - str<outstanding.load() << " " << now << "\r\n"; - str<tcpDiedSendingQuery.load() << " " << now << "\r\n"; - str<tcpDiedReadingResponse.load() << " " << now << "\r\n"; - str<tcpGaveUp.load() << " " << now << "\r\n"; - str<tcpReadTimeouts.load() << " " << now << "\r\n"; - str<tcpWriteTimeouts.load() << " " << now << "\r\n"; - str<tcpCurrentConnections.load() << " " << now << "\r\n"; - str<tcpAvgQueriesPerConnection.load() << " " << now << "\r\n"; - str<tcpAvgConnectionDuration.load() << " " << now << "\r\n"; - } - - std::map frontendDuplicates; - for(const auto& front : g_frontends) { - if (front->udpFD == -1 && front->tcpFD == -1) - continue; - - string frontName = front->local.toStringWithPort() + (front->udpFD >= 0 ? "_udp" : "_tcp"); - boost::replace_all(frontName, ".", "_"); - auto dupPair = frontendDuplicates.insert({frontName, 1}); - if (!dupPair.second) { - frontName = frontName + "_" + std::to_string(dupPair.first->second); - ++(dupPair.first->second); - } - const string base = namespace_name + "." + hostname + "." + instance_name + ".frontends." + frontName + "."; - str<queries.load() << " " << now << "\r\n"; - str<responses.load() << " " << now << "\r\n"; - str<tcpDiedReadingQuery.load() << " " << now << "\r\n"; - str<tcpDiedSendingResponse.load() << " " << now << "\r\n"; - str<tcpGaveUp.load() << " " << now << "\r\n"; - str<tcpClientTimeouts.load() << " " << now << "\r\n"; - str<tcpDownstreamTimeouts.load() << " " << now << "\r\n"; - str<tcpCurrentConnections.load() << " " << now << "\r\n"; - str<tcpAvgQueriesPerConnection.load() << " " << now << "\r\n"; - str<tcpAvgConnectionDuration.load() << " " << now << "\r\n"; - str<tls10queries.load() << " " << now << "\r\n"; - str<tls11queries.load() << " " << now << "\r\n"; - str<tls12queries.load() << " " << now << "\r\n"; - str<tls13queries.load() << " " << now << "\r\n"; - str<tlsUnknownqueries.load() << " " << now << "\r\n"; - str<tlsNewSessions.load() << " " << now << "\r\n"; - str<tlsResumptions.load() << " " << now << "\r\n"; - str<tlsUnknownTicketKey.load() << " " << now << "\r\n"; - str<tlsInactiveTicketKey.load() << " " << now << "\r\n"; - const TLSErrorCounters* errorCounters = nullptr; - if (front->tlsFrontend != nullptr) { - errorCounters = &front->tlsFrontend->d_tlsCounters; + for (const auto& conf : *localCarbon) { + const auto& server = conf.server; + const std::string& namespace_name = conf.namespace_name; + std::string hostname = conf.ourname; + if (hostname.empty()) { + try { + hostname = getCarbonHostName(); } - else if (front->dohFrontend != nullptr) { - errorCounters = &front->dohFrontend->d_tlsCounters; - } - if (errorCounters != nullptr) { - str<d_dhKeyTooSmall << " " << now << "\r\n"; - str<d_inappropriateFallBack << " " << now << "\r\n"; - str<d_noSharedCipher << " " << now << "\r\n"; - str<d_unknownCipherType << " " << now << "\r\n"; - str<d_unknownKeyExchangeType << " " << now << "\r\n"; - str<d_unknownProtocol << " " << now << "\r\n"; - str<d_unsupportedEC << " " << now << "\r\n"; - str<d_unsupportedProtocol << " " << now << "\r\n"; + catch(const std::exception& e) { + throw std::runtime_error(std::string("The 'ourname' setting in 'carbonServer()' has not been set and we are unable to determine the system's hostname: ") + e.what()); } } + const std::string& instance_name = conf.instance_name; - auto localPools = g_pools.getLocal(); - for (const auto& entry : *localPools) { - string poolName = entry.first; - boost::replace_all(poolName, ".", "_"); - if (poolName.empty()) { - poolName = "_default_"; + try { + Socket s(server.sin4.sin_family, SOCK_STREAM); + s.setNonBlocking(); + s.connect(server); // we do the connect so the attempt happens while we gather stats + ostringstream str; + time_t now=time(0); + for(const auto& e : g_stats.entries) { + str<(&e.second)) + str<<(*val)->load(); + else if (const auto& dval = boost::get(&e.second)) + str<<**dval; + else + str<<(*boost::get(&e.second))(e.first); + str<<' '< pool = entry.second; - str<countServers(false) << " " << now << "\r\n"; - str<countServers(true) << " " << now << "\r\n"; - if (pool->packetCache != nullptr) { - const auto& cache = pool->packetCache; - str<getMaxEntries() << " " << now << "\r\n"; - str<getEntriesCount() << " " << now << "\r\n"; - str<getHits() << " " << now << "\r\n"; - str<getMisses() << " " << now << "\r\n"; - str<getDeferredInserts() << " " << now << "\r\n"; - str<getDeferredLookups() << " " << now << "\r\n"; - str<getLookupCollisions() << " " << now << "\r\n"; - str<getInsertCollisions() << " " << now << "\r\n"; - str<getTTLTooShorts() << " " << now << "\r\n"; + auto states = g_dstates.getLocal(); + for(const auto& state : *states) { + string serverName = state->getName().empty() ? state->remote.toStringWithPort() : state->getName(); + boost::replace_all(serverName, ".", "_"); + const string base = namespace_name + "." + hostname + "." + instance_name + ".servers." + serverName + "."; + str<queries.load() << " " << now << "\r\n"; + str<responses.load() << " " << now << "\r\n"; + str<reuseds.load() << " " << now << "\r\n"; + str<availability != DownstreamState::Availability::Down ? state->latencyUsec/1000.0 : 0) << " " << now << "\r\n"; + str<sendErrors.load() << " " << now << "\r\n"; + str<outstanding.load() << " " << now << "\r\n"; + str<tcpDiedSendingQuery.load() << " " << now << "\r\n"; + str<tcpDiedReadingResponse.load() << " " << now << "\r\n"; + str<tcpGaveUp.load() << " " << now << "\r\n"; + str<tcpReadTimeouts.load() << " " << now << "\r\n"; + str<tcpWriteTimeouts.load() << " " << now << "\r\n"; + str<tcpCurrentConnections.load() << " " << now << "\r\n"; + str<tcpAvgQueriesPerConnection.load() << " " << now << "\r\n"; + str<tcpAvgConnectionDuration.load() << " " << now << "\r\n"; } - } -#ifdef HAVE_DNS_OVER_HTTPS - { - std::map dohFrontendDuplicates; - const string base = "dnsdist." + hostname + ".main.doh."; - for(const auto& doh : g_dohlocals) { - string name = doh->d_local.toStringWithPort(); - boost::replace_all(name, ".", "_"); - boost::replace_all(name, ":", "_"); - boost::replace_all(name, "[", "_"); - boost::replace_all(name, "]", "_"); + std::map frontendDuplicates; + for(const auto& front : g_frontends) { + if (front->udpFD == -1 && front->tcpFD == -1) + continue; - auto dupPair = dohFrontendDuplicates.insert({name, 1}); + string frontName = front->local.toStringWithPort() + (front->udpFD >= 0 ? "_udp" : "_tcp"); + boost::replace_all(frontName, ".", "_"); + auto dupPair = frontendDuplicates.insert({frontName, 1}); if (!dupPair.second) { - name = name + "_" + std::to_string(dupPair.first->second); + frontName = frontName + "_" + std::to_string(dupPair.first->second); ++(dupPair.first->second); } - vector&>> v{ - {"http-connects", doh->d_httpconnects}, - {"http1-queries", doh->d_http1Stats.d_nbQueries}, - {"http2-queries", doh->d_http2Stats.d_nbQueries}, - {"http1-200-responses", doh->d_http1Stats.d_nb200Responses}, - {"http2-200-responses", doh->d_http2Stats.d_nb200Responses}, - {"http1-400-responses", doh->d_http1Stats.d_nb400Responses}, - {"http2-400-responses", doh->d_http2Stats.d_nb400Responses}, - {"http1-403-responses", doh->d_http1Stats.d_nb403Responses}, - {"http2-403-responses", doh->d_http2Stats.d_nb403Responses}, - {"http1-500-responses", doh->d_http1Stats.d_nb500Responses}, - {"http2-500-responses", doh->d_http2Stats.d_nb500Responses}, - {"http1-502-responses", doh->d_http1Stats.d_nb502Responses}, - {"http2-502-responses", doh->d_http2Stats.d_nb502Responses}, - {"http1-other-responses", doh->d_http1Stats.d_nbOtherResponses}, - {"http2-other-responses", doh->d_http2Stats.d_nbOtherResponses}, - {"get-queries", doh->d_getqueries}, - {"post-queries", doh->d_postqueries}, - {"bad-requests", doh->d_badrequests}, - {"error-responses", doh->d_errorresponses}, - {"redirect-responses", doh->d_redirectresponses}, - {"valid-responses", doh->d_validresponses} - }; + const string base = namespace_name + "." + hostname + "." + instance_name + ".frontends." + frontName + "."; + str<queries.load() << " " << now << "\r\n"; + str<responses.load() << " " << now << "\r\n"; + str<tcpDiedReadingQuery.load() << " " << now << "\r\n"; + str<tcpDiedSendingResponse.load() << " " << now << "\r\n"; + str<tcpGaveUp.load() << " " << now << "\r\n"; + str<tcpClientTimeouts.load() << " " << now << "\r\n"; + str<tcpDownstreamTimeouts.load() << " " << now << "\r\n"; + str<tcpCurrentConnections.load() << " " << now << "\r\n"; + str<tcpAvgQueriesPerConnection.load() << " " << now << "\r\n"; + str<tcpAvgConnectionDuration.load() << " " << now << "\r\n"; + str<tls10queries.load() << " " << now << "\r\n"; + str<tls11queries.load() << " " << now << "\r\n"; + str<tls12queries.load() << " " << now << "\r\n"; + str<tls13queries.load() << " " << now << "\r\n"; + str<tlsUnknownqueries.load() << " " << now << "\r\n"; + str<tlsNewSessions.load() << " " << now << "\r\n"; + str<tlsResumptions.load() << " " << now << "\r\n"; + str<tlsUnknownTicketKey.load() << " " << now << "\r\n"; + str<tlsInactiveTicketKey.load() << " " << now << "\r\n"; + const TLSErrorCounters* errorCounters = nullptr; + if (front->tlsFrontend != nullptr) { + errorCounters = &front->tlsFrontend->d_tlsCounters; + } + else if (front->dohFrontend != nullptr) { + errorCounters = &front->dohFrontend->d_tlsCounters; + } + if (errorCounters != nullptr) { + str<d_dhKeyTooSmall << " " << now << "\r\n"; + str<d_inappropriateFallBack << " " << now << "\r\n"; + str<d_noSharedCipher << " " << now << "\r\n"; + str<d_unknownCipherType << " " << now << "\r\n"; + str<d_unknownKeyExchangeType << " " << now << "\r\n"; + str<d_unknownProtocol << " " << now << "\r\n"; + str<d_unsupportedEC << " " << now << "\r\n"; + str<d_unsupportedProtocol << " " << now << "\r\n"; + } + } - for(const auto& item : v) { - str< pool = entry.second; + str<countServers(false) << " " << now << "\r\n"; + str<countServers(true) << " " << now << "\r\n"; + if (pool->packetCache != nullptr) { + const auto& cache = pool->packetCache; + str<getMaxEntries() << " " << now << "\r\n"; + str<getEntriesCount() << " " << now << "\r\n"; + str<getHits() << " " << now << "\r\n"; + str<getMisses() << " " << now << "\r\n"; + str<getDeferredInserts() << " " << now << "\r\n"; + str<getDeferredLookups() << " " << now << "\r\n"; + str<getLookupCollisions() << " " << now << "\r\n"; + str<getInsertCollisions() << " " << now << "\r\n"; + str<getTTLTooShorts() << " " << now << "\r\n"; + } + } + +#ifdef HAVE_DNS_OVER_HTTPS + { + std::map dohFrontendDuplicates; + const string base = "dnsdist." + hostname + ".main.doh."; + for(const auto& doh : g_dohlocals) { + string name = doh->d_local.toStringWithPort(); + boost::replace_all(name, ".", "_"); + boost::replace_all(name, ":", "_"); + boost::replace_all(name, "[", "_"); + boost::replace_all(name, "]", "_"); + + auto dupPair = dohFrontendDuplicates.insert({name, 1}); + if (!dupPair.second) { + name = name + "_" + std::to_string(dupPair.first->second); + ++(dupPair.first->second); + } + + vector&>> v{ + {"http-connects", doh->d_httpconnects}, + {"http1-queries", doh->d_http1Stats.d_nbQueries}, + {"http2-queries", doh->d_http2Stats.d_nbQueries}, + {"http1-200-responses", doh->d_http1Stats.d_nb200Responses}, + {"http2-200-responses", doh->d_http2Stats.d_nb200Responses}, + {"http1-400-responses", doh->d_http1Stats.d_nb400Responses}, + {"http2-400-responses", doh->d_http2Stats.d_nb400Responses}, + {"http1-403-responses", doh->d_http1Stats.d_nb403Responses}, + {"http2-403-responses", doh->d_http2Stats.d_nb403Responses}, + {"http1-500-responses", doh->d_http1Stats.d_nb500Responses}, + {"http2-500-responses", doh->d_http2Stats.d_nb500Responses}, + {"http1-502-responses", doh->d_http1Stats.d_nb502Responses}, + {"http2-502-responses", doh->d_http2Stats.d_nb502Responses}, + {"http1-other-responses", doh->d_http1Stats.d_nbOtherResponses}, + {"http2-other-responses", doh->d_http2Stats.d_nbOtherResponses}, + {"get-queries", doh->d_getqueries}, + {"post-queries", doh->d_postqueries}, + {"bad-requests", doh->d_badrequests}, + {"error-responses", doh->d_errorresponses}, + {"redirect-responses", doh->d_redirectresponses}, + {"valid-responses", doh->d_validresponses} + }; + + for(const auto& item : v) { + str< g_consoleOutputMsgMaxSize) + try + { + uint32_t raw; + size_t ret = readn2(fd, &raw, sizeof raw); + + if (ret != sizeof raw) { + return false; + } + + *len = ntohl(raw); + if (*len > g_consoleOutputMsgMaxSize) { + return false; + } + + return true; + } + catch(...) { return false; - return true; -} -catch(...) { - return false; + } } static bool putMsgLen32(int fd, uint32_t len) -try { - uint32_t raw = htonl(len); - size_t ret = writen2(fd, &raw, sizeof raw); - return ret==sizeof raw; -} -catch(...) { - return false; + try + { + uint32_t raw = htonl(len); + size_t ret = writen2(fd, &raw, sizeof raw); + return ret == sizeof raw; + } + catch(...) { + return false; + } } static bool sendMessageToServer(int fd, const std::string& line, SodiumNonce& readingNonce, SodiumNonce& writingNonce, const bool outputEmptyLine) @@ -673,171 +682,175 @@ char** my_completion( const char * text , int start, int end) } static void controlClientThread(int fd, ComboAddress client) -try { - setThreadName("dnsdist/conscli"); - setTCPNoDelay(fd); - SodiumNonce theirs, ours, readingNonce, writingNonce; - ours.init(); - readn2(fd, (char*)theirs.value, sizeof(theirs.value)); - writen2(fd, (char*)ours.value, sizeof(ours.value)); - readingNonce.merge(ours, theirs); - writingNonce.merge(theirs, ours); - - for(;;) { - uint32_t len; - if(!getMsgLen32(fd, &len)) - break; - - if (len == 0) { - /* just ACK an empty message - with an empty response */ - putMsgLen32(fd, 0); - continue; - } + try + { + setThreadName("dnsdist/conscli"); + setTCPNoDelay(fd); + SodiumNonce theirs, ours, readingNonce, writingNonce; + ours.init(); + readn2(fd, (char*)theirs.value, sizeof(theirs.value)); + writen2(fd, (char*)ours.value, sizeof(ours.value)); + readingNonce.merge(ours, theirs); + writingNonce.merge(theirs, ours); + + for(;;) { + uint32_t len; + if(!getMsgLen32(fd, &len)) + break; + + if (len == 0) { + /* just ACK an empty message + with an empty response */ + putMsgLen32(fd, 0); + continue; + } - boost::scoped_array msg(new char[len]); - readn2(fd, msg.get(), len); + boost::scoped_array msg(new char[len]); + readn2(fd, msg.get(), len); - string line(msg.get(), len); + string line(msg.get(), len); - line = sodDecryptSym(line, g_consoleKey, readingNonce); - // cerr<<"Have decrypted line: "< lock(g_luamutex); + bool withReturn=true; + retry:; + try { + std::lock_guard lock(g_luamutex); - g_outputBuffer.clear(); - resetLuaSideEffect(); - auto ret=g_lua.executeCode< - boost::optional< - boost::variant< - string, - shared_ptr, - ClientState*, - std::unordered_map + g_outputBuffer.clear(); + resetLuaSideEffect(); + auto ret=g_lua.executeCode< + boost::optional< + boost::variant< + string, + shared_ptr, + ClientState*, + std::unordered_map + > > - > - >(withReturn ? ("return "+line) : line); - - if(ret) { - if (const auto dsValue = boost::get>(&*ret)) { - if (*dsValue) { - response=(*dsValue)->getName()+"\n"; - } else { - response=""; + >(withReturn ? ("return "+line) : line); + + if(ret) { + if (const auto dsValue = boost::get>(&*ret)) { + if (*dsValue) { + response=(*dsValue)->getName()+"\n"; + } else { + response=""; + } + } + else if (const auto csValue = boost::get(&*ret)) { + if (*csValue) { + response=(*csValue)->local.toStringWithPort()+"\n"; + } else { + response=""; + } + } + else if (const auto strValue = boost::get(&*ret)) { + response=*strValue+"\n"; + } + else if(const auto um = boost::get >(&*ret)) { + using namespace json11; + Json::object o; + for(const auto& v : *um) + o[v.first]=v.second; + Json out = o; + response=out.dump()+"\n"; + } } + else + response=g_outputBuffer; + if(!getLuaNoSideEffect()) + feedConfigDelta(line); } - else if (const auto csValue = boost::get(&*ret)) { - if (*csValue) { - response=(*csValue)->local.toStringWithPort()+"\n"; - } else { - response=""; + catch(const LuaContext::SyntaxErrorException&) { + if(withReturn) { + withReturn=false; + goto retry; } - } - else if (const auto strValue = boost::get(&*ret)) { - response=*strValue+"\n"; - } - else if(const auto um = boost::get >(&*ret)) { - using namespace json11; - Json::object o; - for(const auto& v : *um) - o[v.first]=v.second; - Json out = o; - response=out.dump()+"\n"; + throw; } } - else - response=g_outputBuffer; - if(!getLuaNoSideEffect()) - feedConfigDelta(line); + catch(const LuaContext::WrongTypeException& e) { + response = "Command returned an object we can't print: " +std::string(e.what()) + "\n"; + // tried to return something we don't understand } - catch(const LuaContext::SyntaxErrorException&) { - if(withReturn) { - withReturn=false; - goto retry; + catch(const LuaContext::ExecutionErrorException& e) { + if(!strcmp(e.what(),"invalid key to 'next'")) + response = "Error: Parsing function parameters, did you forget parameter name?"; + else + response = "Error: " + string(e.what()); + try { + std::rethrow_if_nested(e); + } catch(const std::exception& ne) { + // ne is the exception that was thrown from inside the lambda + response+= ": " + string(ne.what()); + } + catch(const PDNSException& ne) { + // ne is the exception that was thrown from inside the lambda + response += ": " + string(ne.reason); } - throw; - } - } - catch(const LuaContext::WrongTypeException& e) { - response = "Command returned an object we can't print: " +std::string(e.what()) + "\n"; - // tried to return something we don't understand - } - catch(const LuaContext::ExecutionErrorException& e) { - if(!strcmp(e.what(),"invalid key to 'next'")) - response = "Error: Parsing function parameters, did you forget parameter name?"; - else - response = "Error: " + string(e.what()); - try { - std::rethrow_if_nested(e); - } catch(const std::exception& ne) { - // ne is the exception that was thrown from inside the lambda - response+= ": " + string(ne.what()); } - catch(const PDNSException& ne) { - // ne is the exception that was thrown from inside the lambda - response += ": " + string(ne.reason); + catch(const LuaContext::SyntaxErrorException& e) { + response = "Error: " + string(e.what()) + ": "; } + response = sodEncryptSym(response, g_consoleKey, writingNonce); + putMsgLen32(fd, response.length()); + writen2(fd, response.c_str(), response.length()); } - catch(const LuaContext::SyntaxErrorException& e) { - response = "Error: " + string(e.what()) + ": "; + if (g_logConsoleConnections) { + infolog("Closed control connection from %s", client.toStringWithPort()); } - response = sodEncryptSym(response, g_consoleKey, writingNonce); - putMsgLen32(fd, response.length()); - writen2(fd, response.c_str(), response.length()); + close(fd); + fd=-1; } - if (g_logConsoleConnections) { - infolog("Closed control connection from %s", client.toStringWithPort()); + catch (const std::exception& e) + { + errlog("Got an exception in client connection from %s: %s", client.toStringWithPort(), e.what()); + if(fd >= 0) + close(fd); } - close(fd); - fd=-1; -} -catch(std::exception& e) -{ - errlog("Got an exception in client connection from %s: %s", client.toStringWithPort(), e.what()); - if(fd >= 0) - close(fd); } void controlThread(int fd, ComboAddress local) -try { - setThreadName("dnsdist/control"); - ComboAddress client; - int sock; - auto localACL = g_consoleACL.getLocal(); - infolog("Accepting control connections on %s", local.toStringWithPort()); - - while ((sock = SAccept(fd, client)) >= 0) { + try + { + setThreadName("dnsdist/control"); + ComboAddress client; + int sock; + auto localACL = g_consoleACL.getLocal(); + infolog("Accepting control connections on %s", local.toStringWithPort()); + + while ((sock = SAccept(fd, client)) >= 0) { + + if (!sodIsValidKey(g_consoleKey)) { + vinfolog("Control connection from %s dropped because we don't have a valid key configured, please configure one using setKey()", client.toStringWithPort()); + close(sock); + continue; + } - if (!sodIsValidKey(g_consoleKey)) { - vinfolog("Control connection from %s dropped because we don't have a valid key configured, please configure one using setKey()", client.toStringWithPort()); - close(sock); - continue; - } + if (!localACL->match(client)) { + vinfolog("Control connection from %s dropped because of ACL", client.toStringWithPort()); + close(sock); + continue; + } - if (!localACL->match(client)) { - vinfolog("Control connection from %s dropped because of ACL", client.toStringWithPort()); - close(sock); - continue; - } + if (g_logConsoleConnections) { + warnlog("Got control connection from %s", client.toStringWithPort()); + } - if (g_logConsoleConnections) { - warnlog("Got control connection from %s", client.toStringWithPort()); + std::thread t(controlClientThread, sock, client); + t.detach(); } - - std::thread t(controlClientThread, sock, client); - t.detach(); } -} -catch(const std::exception& e) -{ - close(fd); - errlog("Control connection died: %s", e.what()); + catch (const std::exception& e) + { + close(fd); + errlog("Control connection died: %s", e.what()); + } } void clearConsoleHistory() diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 568fd0c2db..b42aaf7f43 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -1498,8 +1498,7 @@ static void MultipleMessagesUDPClientThread(ClientState* cs, LocalHolders& holde // listens to incoming queries, sends out to downstream servers, noting the intended return path static void udpClientThread(ClientState* cs) { - try - { + try { setThreadName("dnsdist/udpClie"); LocalHolders holders; @@ -2000,477 +1999,478 @@ static void usage() } int main(int argc, char** argv) -try { - size_t udpBindsCount = 0; - size_t tcpBindsCount = 0; - rl_attempted_completion_function = my_completion; - rl_completion_append_character = 0; + try { + size_t udpBindsCount = 0; + size_t tcpBindsCount = 0; + rl_attempted_completion_function = my_completion; + rl_completion_append_character = 0; - signal(SIGPIPE, SIG_IGN); - signal(SIGCHLD, SIG_IGN); - openlog("dnsdist", LOG_PID|LOG_NDELAY, LOG_DAEMON); + signal(SIGPIPE, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + openlog("dnsdist", LOG_PID|LOG_NDELAY, LOG_DAEMON); #ifdef HAVE_LIBSODIUM - if (sodium_init() == -1) { - cerr<<"Unable to initialize crypto library"<getName() == "chashed") { - precompute = true; - } else { - for (const auto& entry: localPools) { - if (entry.second->policy != nullptr && entry.second->policy->getName() == "chashed") { - precompute = true; - break ; + auto localPools = g_pools.getCopy(); + { + bool precompute = false; + if (g_policy.getLocal()->getName() == "chashed") { + precompute = true; + } else { + for (const auto& entry: localPools) { + if (entry.second->policy != nullptr && entry.second->policy->getName() == "chashed") { + precompute = true; + break ; + } } } - } - if (precompute) { - vinfolog("Pre-computing hashes for consistent hash load-balancing policy"); - // pre compute hashes - auto backends = g_dstates.getLocal(); - for (auto& backend: *backends) { - if (backend->weight < 100) { - vinfolog("Warning, the backend '%s' has a very low weight (%d), which will not yield a good distribution of queries with the 'chashed' policy. Please consider raising it to at least '100'.", backend->getName(), backend->weight); - } + if (precompute) { + vinfolog("Pre-computing hashes for consistent hash load-balancing policy"); + // pre compute hashes + auto backends = g_dstates.getLocal(); + for (auto& backend: *backends) { + if (backend->weight < 100) { + vinfolog("Warning, the backend '%s' has a very low weight (%d), which will not yield a good distribution of queries with the 'chashed' policy. Please consider raising it to at least '100'.", backend->getName(), backend->weight); + } - backend->hash(); + backend->hash(); + } } } - } - if (!g_cmdLine.locals.empty()) { - for (auto it = g_frontends.begin(); it != g_frontends.end(); ) { - /* DoH, DoT and DNSCrypt frontends are separate */ - if ((*it)->dohFrontend == nullptr && (*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) { - it = g_frontends.erase(it); + if (!g_cmdLine.locals.empty()) { + for (auto it = g_frontends.begin(); it != g_frontends.end(); ) { + /* DoH, DoT and DNSCrypt frontends are separate */ + if ((*it)->dohFrontend == nullptr && (*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) { + it = g_frontends.erase(it); + } + else { + ++it; + } } - else { - ++it; + + for(const auto& loc : g_cmdLine.locals) { + /* UDP */ + g_frontends.push_back(std::unique_ptr(new ClientState(ComboAddress(loc, 53), false, false, 0, "", {}))); + /* TCP */ + g_frontends.push_back(std::unique_ptr(new ClientState(ComboAddress(loc, 53), true, false, 0, "", {}))); } } - for(const auto& loc : g_cmdLine.locals) { + if (g_frontends.empty()) { /* UDP */ - g_frontends.push_back(std::unique_ptr(new ClientState(ComboAddress(loc, 53), false, false, 0, "", {}))); + g_frontends.push_back(std::unique_ptr(new ClientState(ComboAddress("127.0.0.1", 53), false, false, 0, "", {}))); /* TCP */ - g_frontends.push_back(std::unique_ptr(new ClientState(ComboAddress(loc, 53), true, false, 0, "", {}))); + g_frontends.push_back(std::unique_ptr(new ClientState(ComboAddress("127.0.0.1", 53), true, false, 0, "", {}))); } - } - if (g_frontends.empty()) { - /* UDP */ - g_frontends.push_back(std::unique_ptr(new ClientState(ComboAddress("127.0.0.1", 53), false, false, 0, "", {}))); - /* TCP */ - g_frontends.push_back(std::unique_ptr(new ClientState(ComboAddress("127.0.0.1", 53), true, false, 0, "", {}))); - } - - g_configurationDone = true; + g_configurationDone = true; - for(auto& frontend : g_frontends) { - setUpLocalBind(frontend); + for(auto& frontend : g_frontends) { + setUpLocalBind(frontend); - if (frontend->tcp == false) { - ++udpBindsCount; - } - else { - ++tcpBindsCount; + if (frontend->tcp == false) { + ++udpBindsCount; + } + else { + ++tcpBindsCount; + } } - } - warnlog("dnsdist %s comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2", VERSION); + warnlog("dnsdist %s comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2", VERSION); - vector vec; - std::string acls; - g_ACL.getLocal()->toStringVector(&vec); - for(const auto& s : vec) { - if (!acls.empty()) - acls += ", "; - acls += s; - } - infolog("ACL allowing queries from: %s", acls.c_str()); - vec.clear(); - acls.clear(); - g_consoleACL.getLocal()->toStringVector(&vec); - for (const auto& entry : vec) { - if (!acls.empty()) { - acls += ", "; + vector vec; + std::string acls; + g_ACL.getLocal()->toStringVector(&vec); + for(const auto& s : vec) { + if (!acls.empty()) + acls += ", "; + acls += s; } - acls += entry; - } - infolog("Console ACL allowing connections from: %s", acls.c_str()); + infolog("ACL allowing queries from: %s", acls.c_str()); + vec.clear(); + acls.clear(); + g_consoleACL.getLocal()->toStringVector(&vec); + for (const auto& entry : vec) { + if (!acls.empty()) { + acls += ", "; + } + acls += entry; + } + infolog("Console ACL allowing connections from: %s", acls.c_str()); #ifdef HAVE_LIBSODIUM - if (g_consoleEnabled && g_consoleKey.empty()) { - warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set"); - } + if (g_consoleEnabled && g_consoleKey.empty()) { + warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set"); + } #endif - uid_t newgid=getegid(); - gid_t newuid=geteuid(); + uid_t newgid=getegid(); + gid_t newuid=geteuid(); - if(!g_cmdLine.gid.empty()) - newgid = strToGID(g_cmdLine.gid.c_str()); + if(!g_cmdLine.gid.empty()) + newgid = strToGID(g_cmdLine.gid.c_str()); - if(!g_cmdLine.uid.empty()) - newuid = strToUID(g_cmdLine.uid.c_str()); + if(!g_cmdLine.uid.empty()) + newuid = strToUID(g_cmdLine.uid.c_str()); - if (getegid() != newgid) { - if (running_in_service_mgr()) { - errlog("--gid/-g set on command-line, but dnsdist was started as a systemd service. Use the 'Group' setting in the systemd unit file to set the group to run as"); - _exit(EXIT_FAILURE); + if (getegid() != newgid) { + if (running_in_service_mgr()) { + errlog("--gid/-g set on command-line, but dnsdist was started as a systemd service. Use the 'Group' setting in the systemd unit file to set the group to run as"); + _exit(EXIT_FAILURE); + } + dropGroupPrivs(newgid); } - dropGroupPrivs(newgid); - } - if (geteuid() != newuid) { - if (running_in_service_mgr()) { - errlog("--uid/-u set on command-line, but dnsdist was started as a systemd service. Use the 'User' setting in the systemd unit file to set the user to run as"); - _exit(EXIT_FAILURE); + if (geteuid() != newuid) { + if (running_in_service_mgr()) { + errlog("--uid/-u set on command-line, but dnsdist was started as a systemd service. Use the 'User' setting in the systemd unit file to set the user to run as"); + _exit(EXIT_FAILURE); + } + dropUserPrivs(newuid); } - dropUserPrivs(newuid); - } - try { - /* we might still have capabilities remaining, - for example if we have been started as root - without --uid or --gid (please don't do that) - or as an unprivileged user with ambient - capabilities like CAP_NET_BIND_SERVICE. - */ - dropCapabilities(g_capabilitiesToRetain); - } - catch(const std::exception& e) { - warnlog("%s", e.what()); - } + try { + /* we might still have capabilities remaining, + for example if we have been started as root + without --uid or --gid (please don't do that) + or as an unprivileged user with ambient + capabilities like CAP_NET_BIND_SERVICE. + */ + dropCapabilities(g_capabilitiesToRetain); + } + catch (const std::exception& e) { + warnlog("%s", e.what()); + } - /* this need to be done _after_ dropping privileges */ - g_delay = new DelayPipe(); + /* this need to be done _after_ dropping privileges */ + g_delay = new DelayPipe(); - if (g_snmpAgent) { - g_snmpAgent->run(); - } + if (g_snmpAgent) { + g_snmpAgent->run(); + } - g_tcpclientthreads = std::unique_ptr(new TCPClientCollection(g_maxTCPClientThreads, g_useTCPSinglePipe)); + g_tcpclientthreads = std::unique_ptr(new TCPClientCollection(g_maxTCPClientThreads, g_useTCPSinglePipe)); - for(auto& t : todo) - t(); + for(auto& t : todo) + t(); - localPools = g_pools.getCopy(); - /* create the default pool no matter what */ - createPoolIfNotExists(localPools, ""); - if(g_cmdLine.remotes.size()) { - for(const auto& address : g_cmdLine.remotes) { - auto ret=std::make_shared(ComboAddress(address, 53)); - addServerToPool(localPools, "", ret); - if (ret->connected && !ret->threadStarted.test_and_set()) { - ret->tid = thread(responderThread, ret); + localPools = g_pools.getCopy(); + /* create the default pool no matter what */ + createPoolIfNotExists(localPools, ""); + if(g_cmdLine.remotes.size()) { + for(const auto& address : g_cmdLine.remotes) { + auto ret=std::make_shared(ComboAddress(address, 53)); + addServerToPool(localPools, "", ret); + if (ret->connected && !ret->threadStarted.test_and_set()) { + ret->tid = thread(responderThread, ret); + } + g_dstates.modify([ret](servers_t& servers) { servers.push_back(ret); }); } - g_dstates.modify([ret](servers_t& servers) { servers.push_back(ret); }); } - } - g_pools.setState(localPools); + g_pools.setState(localPools); - if(g_dstates.getLocal()->empty()) { - errlog("No downstream servers defined: all packets will get dropped"); - // you might define them later, but you need to know - } + if(g_dstates.getLocal()->empty()) { + errlog("No downstream servers defined: all packets will get dropped"); + // you might define them later, but you need to know + } - checkFileDescriptorsLimits(udpBindsCount, tcpBindsCount); + checkFileDescriptorsLimits(udpBindsCount, tcpBindsCount); - auto mplexer = std::shared_ptr(FDMultiplexer::getMultiplexerSilent()); - for(auto& dss : g_dstates.getCopy()) { // it is a copy, but the internal shared_ptrs are the real deal - if (dss->availability == DownstreamState::Availability::Auto) { - if (!queueHealthCheck(mplexer, dss, true)) { - dss->upStatus = false; - warnlog("Marking downstream %s as 'down'", dss->getNameWithAddr()); + auto mplexer = std::shared_ptr(FDMultiplexer::getMultiplexerSilent()); + for(auto& dss : g_dstates.getCopy()) { // it is a copy, but the internal shared_ptrs are the real deal + if (dss->availability == DownstreamState::Availability::Auto) { + if (!queueHealthCheck(mplexer, dss, true)) { + dss->upStatus = false; + warnlog("Marking downstream %s as 'down'", dss->getNameWithAddr()); + } } } - } - handleQueuedHealthChecks(mplexer, true); + handleQueuedHealthChecks(mplexer, true); - for(auto& cs : g_frontends) { - if (cs->dohFrontend != nullptr) { + for(auto& cs : g_frontends) { + if (cs->dohFrontend != nullptr) { #ifdef HAVE_DNS_OVER_HTTPS - std::thread t1(dohThread, cs.get()); - if (!cs->cpus.empty()) { - mapThreadToCPUList(t1.native_handle(), cs->cpus); - } - t1.detach(); + std::thread t1(dohThread, cs.get()); + if (!cs->cpus.empty()) { + mapThreadToCPUList(t1.native_handle(), cs->cpus); + } + t1.detach(); #endif /* HAVE_DNS_OVER_HTTPS */ - continue; - } - if (cs->udpFD >= 0) { - thread t1(udpClientThread, cs.get()); - if (!cs->cpus.empty()) { - mapThreadToCPUList(t1.native_handle(), cs->cpus); + continue; } - t1.detach(); - } - else if (cs->tcpFD >= 0) { - thread t1(tcpAcceptorThread, cs.get()); - if (!cs->cpus.empty()) { - mapThreadToCPUList(t1.native_handle(), cs->cpus); + if (cs->udpFD >= 0) { + thread t1(udpClientThread, cs.get()); + if (!cs->cpus.empty()) { + mapThreadToCPUList(t1.native_handle(), cs->cpus); + } + t1.detach(); + } + else if (cs->tcpFD >= 0) { + thread t1(tcpAcceptorThread, cs.get()); + if (!cs->cpus.empty()) { + mapThreadToCPUList(t1.native_handle(), cs->cpus); + } + t1.detach(); } - t1.detach(); } - } - thread carbonthread(carbonDumpThread); - carbonthread.detach(); + thread carbonthread(carbonDumpThread); + carbonthread.detach(); - thread stattid(maintThread); - stattid.detach(); + thread stattid(maintThread); + stattid.detach(); - thread healththread(healthChecksThread); + thread healththread(healthChecksThread); - thread dynBlockMaintThread(dynBlockMaintenanceThread); - dynBlockMaintThread.detach(); + thread dynBlockMaintThread(dynBlockMaintenanceThread); + dynBlockMaintThread.detach(); - if (!g_secPollSuffix.empty()) { - thread secpollthread(secPollThread); - secpollthread.detach(); - } + if (!g_secPollSuffix.empty()) { + thread secpollthread(secPollThread); + secpollthread.detach(); + } - if(g_cmdLine.beSupervised) { + if(g_cmdLine.beSupervised) { #ifdef HAVE_SYSTEMD - sd_notify(0, "READY=1"); + sd_notify(0, "READY=1"); #endif - healththread.join(); + healththread.join(); + } + else { + healththread.detach(); + doConsole(); + } + _exit(EXIT_SUCCESS); + } - else { - healththread.detach(); - doConsole(); + catch (const LuaContext::ExecutionErrorException& e) { + try { + errlog("Fatal Lua error: %s", e.what()); + std::rethrow_if_nested(e); + } catch(const std::exception& ne) { + errlog("Details: %s", ne.what()); + } + catch (const PDNSException &ae) + { + errlog("Fatal pdns error: %s", ae.reason); + } + _exit(EXIT_FAILURE); } - _exit(EXIT_SUCCESS); - -} -catch(const LuaContext::ExecutionErrorException& e) { - try { - errlog("Fatal Lua error: %s", e.what()); - std::rethrow_if_nested(e); - } catch(const std::exception& ne) { - errlog("Details: %s", ne.what()); + catch (const std::exception &e) + { + errlog("Fatal error: %s", e.what()); + _exit(EXIT_FAILURE); } - catch(PDNSException &ae) + catch (const PDNSException &ae) { errlog("Fatal pdns error: %s", ae.reason); + _exit(EXIT_FAILURE); } - _exit(EXIT_FAILURE); -} -catch(std::exception &e) -{ - errlog("Fatal error: %s", e.what()); - _exit(EXIT_FAILURE); -} -catch(PDNSException &ae) -{ - errlog("Fatal pdns error: %s", ae.reason); - _exit(EXIT_FAILURE); } uint64_t getLatencyCount(const std::string&) diff --git a/pdns/dnsdistdist/doh.cc b/pdns/dnsdistdist/doh.cc index 60c8487b96..b1a0c4c027 100644 --- a/pdns/dnsdistdist/doh.cc +++ b/pdns/dnsdistdist/doh.cc @@ -775,156 +775,157 @@ static void processForwardedForHeader(const h2o_req_t* req, ComboAddress& remote For POST, the payload is the payload. */ static int doh_handler(h2o_handler_t *self, h2o_req_t *req) -try { - if (!req->conn->ctx->storage.size) { - return 0; // although we might was well crash on this - } - h2o_socket_t* sock = req->conn->callbacks->get_socket(req->conn); - ComboAddress remote; - ComboAddress local; + try { + if (!req->conn->ctx->storage.size) { + return 0; // although we might was well crash on this + } + h2o_socket_t* sock = req->conn->callbacks->get_socket(req->conn); + ComboAddress remote; + ComboAddress local; - if (h2o_socket_getpeername(sock, reinterpret_cast(&remote)) == 0) { - /* getpeername failed, likely because the connection has already been closed, - but anyway that means we can't get the remote address, which could allow an ACL bypass */ - h2o_send_error_500(req, getReasonFromStatusCode(500).c_str(), "Internal Server Error - Unable to get remote address", 0); - return 0; - } + if (h2o_socket_getpeername(sock, reinterpret_cast(&remote)) == 0) { + /* getpeername failed, likely because the connection has already been closed, + but anyway that means we can't get the remote address, which could allow an ACL bypass */ + h2o_send_error_500(req, getReasonFromStatusCode(500).c_str(), "Internal Server Error - Unable to get remote address", 0); + return 0; + } - h2o_socket_getsockname(sock, reinterpret_cast(&local)); - DOHServerConfig* dsc = reinterpret_cast(req->conn->ctx->storage.entries[0].data); + h2o_socket_getsockname(sock, reinterpret_cast(&local)); + DOHServerConfig* dsc = reinterpret_cast(req->conn->ctx->storage.entries[0].data); - if (dsc->df->d_trustForwardedForHeader) { - processForwardedForHeader(req, remote); - } + if (dsc->df->d_trustForwardedForHeader) { + processForwardedForHeader(req, remote); + } - auto& holders = dsc->holders; - if (!holders.acl->match(remote)) { - ++g_stats.aclDrops; - vinfolog("Query from %s (DoH) dropped because of ACL", remote.toStringWithPort()); - h2o_send_error_403(req, "Forbidden", "dns query not allowed because of ACL", 0); - return 0; - } + auto& holders = dsc->holders; + if (!holders.acl->match(remote)) { + ++g_stats.aclDrops; + vinfolog("Query from %s (DoH) dropped because of ACL", remote.toStringWithPort()); + h2o_send_error_403(req, "Forbidden", "dns query not allowed because of ACL", 0); + return 0; + } - if (h2o_socket_get_ssl_session_reused(sock) == 0) { - ++dsc->cs->tlsNewSessions; - } - else { - ++dsc->cs->tlsResumptions; - } + if (h2o_socket_get_ssl_session_reused(sock) == 0) { + ++dsc->cs->tlsNewSessions; + } + else { + ++dsc->cs->tlsResumptions; + } - const int descriptor = h2o_socket_get_fd(sock); - if (descriptor != -1) { - ++t_conns.at(descriptor).d_nbQueries; - } - - if (auto tlsversion = h2o_socket_get_ssl_protocol_version(sock)) { - if(!strcmp(tlsversion, "TLSv1.0")) - ++dsc->cs->tls10queries; - else if(!strcmp(tlsversion, "TLSv1.1")) - ++dsc->cs->tls11queries; - else if(!strcmp(tlsversion, "TLSv1.2")) - ++dsc->cs->tls12queries; - else if(!strcmp(tlsversion, "TLSv1.3")) - ++dsc->cs->tls13queries; - else - ++dsc->cs->tlsUnknownqueries; - } - - // would be nice to be able to use a pdns_string_view there, but we would need heterogeneous lookups - // (having string in the set and compare them to string_view, for example. Note that comparing - // two boost::string_view uses the pointer, not the content). - const std::string pathOnly(req->path_normalized.base, req->path_normalized.len); - if (dsc->paths.count(pathOnly) == 0) { - h2o_send_error_404(req, "Not Found", "there is no endpoint configured for this path", 0); - return 0; - } + const int descriptor = h2o_socket_get_fd(sock); + if (descriptor != -1) { + ++t_conns.at(descriptor).d_nbQueries; + } - // would be nice to be able to use a pdns_string_view there, - // but regex (called by matches() internally) requires a null-terminated string - string path(req->path.base, req->path.len); - for (const auto& entry : dsc->df->d_responsesMap) { - if (entry->matches(path)) { - const auto& customHeaders = entry->getHeaders(); - handleResponse(*dsc->df, req, entry->getStatusCode(), entry->getContent(), customHeaders ? *customHeaders : dsc->df->d_customResponseHeaders, std::string(), false); + if (auto tlsversion = h2o_socket_get_ssl_protocol_version(sock)) { + if(!strcmp(tlsversion, "TLSv1.0")) + ++dsc->cs->tls10queries; + else if(!strcmp(tlsversion, "TLSv1.1")) + ++dsc->cs->tls11queries; + else if(!strcmp(tlsversion, "TLSv1.2")) + ++dsc->cs->tls12queries; + else if(!strcmp(tlsversion, "TLSv1.3")) + ++dsc->cs->tls13queries; + else + ++dsc->cs->tlsUnknownqueries; + } + + // would be nice to be able to use a pdns_string_view there, but we would need heterogeneous lookups + // (having string in the set and compare them to string_view, for example. Note that comparing + // two boost::string_view uses the pointer, not the content). + const std::string pathOnly(req->path_normalized.base, req->path_normalized.len); + if (dsc->paths.count(pathOnly) == 0) { + h2o_send_error_404(req, "Not Found", "there is no endpoint configured for this path", 0); return 0; } - } - if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST"))) { - ++dsc->df->d_postqueries; - if(req->version >= 0x0200) - ++dsc->df->d_http2Stats.d_nbQueries; - else - ++dsc->df->d_http1Stats.d_nbQueries; - - PacketBuffer query; - /* We reserve at least 512 additional bytes to be able to add EDNS, but we also want - at least s_maxPacketCacheEntrySize bytes to be able to fill the answer from the packet cache */ - query.reserve(std::max(req->entity.len + 512, s_maxPacketCacheEntrySize)); - query.resize(req->entity.len); - memcpy(query.data(), req->entity.base, req->entity.len); - doh_dispatch_query(dsc, self, req, std::move(query), local, remote, std::move(path)); - } - else if(req->query_at != SIZE_MAX && (req->path.len - req->query_at > 5)) { - auto pos = path.find("?dns="); - if(pos == string::npos) - pos = path.find("&dns="); - if(pos != string::npos) { - // need to base64url decode this - string sdns(path.substr(pos+5)); - boost::replace_all(sdns,"-", "+"); - boost::replace_all(sdns,"_", "/"); - // re-add padding that may have been missing - switch (sdns.size() % 4) { - case 2: - sdns.append(2, '='); - break; - case 3: - sdns.append(1, '='); - break; + // would be nice to be able to use a pdns_string_view there, + // but regex (called by matches() internally) requires a null-terminated string + string path(req->path.base, req->path.len); + for (const auto& entry : dsc->df->d_responsesMap) { + if (entry->matches(path)) { + const auto& customHeaders = entry->getHeaders(); + handleResponse(*dsc->df, req, entry->getStatusCode(), entry->getContent(), customHeaders ? *customHeaders : dsc->df->d_customResponseHeaders, std::string(), false); + return 0; } + } - PacketBuffer decoded; + if (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST"))) { + ++dsc->df->d_postqueries; + if(req->version >= 0x0200) + ++dsc->df->d_http2Stats.d_nbQueries; + else + ++dsc->df->d_http1Stats.d_nbQueries; - /* rough estimate so we hopefully don't need a new allocation later */ + PacketBuffer query; /* We reserve at least 512 additional bytes to be able to add EDNS, but we also want at least s_maxPacketCacheEntrySize bytes to be able to fill the answer from the packet cache */ - const size_t estimate = ((sdns.size() * 3) / 4); - decoded.reserve(std::max(estimate + 512, s_maxPacketCacheEntrySize)); - if(B64Decode(sdns, decoded) < 0) { - h2o_send_error_400(req, "Bad Request", "Unable to decode BASE64-URL", 0); + query.reserve(std::max(req->entity.len + 512, s_maxPacketCacheEntrySize)); + query.resize(req->entity.len); + memcpy(query.data(), req->entity.base, req->entity.len); + doh_dispatch_query(dsc, self, req, std::move(query), local, remote, std::move(path)); + } + else if(req->query_at != SIZE_MAX && (req->path.len - req->query_at > 5)) { + auto pos = path.find("?dns="); + if(pos == string::npos) + pos = path.find("&dns="); + if(pos != string::npos) { + // need to base64url decode this + string sdns(path.substr(pos+5)); + boost::replace_all(sdns,"-", "+"); + boost::replace_all(sdns,"_", "/"); + // re-add padding that may have been missing + switch (sdns.size() % 4) { + case 2: + sdns.append(2, '='); + break; + case 3: + sdns.append(1, '='); + break; + } + + PacketBuffer decoded; + + /* rough estimate so we hopefully don't need a new allocation later */ + /* We reserve at least 512 additional bytes to be able to add EDNS, but we also want + at least s_maxPacketCacheEntrySize bytes to be able to fill the answer from the packet cache */ + const size_t estimate = ((sdns.size() * 3) / 4); + decoded.reserve(std::max(estimate + 512, s_maxPacketCacheEntrySize)); + if(B64Decode(sdns, decoded) < 0) { + h2o_send_error_400(req, "Bad Request", "Unable to decode BASE64-URL", 0); + ++dsc->df->d_badrequests; + return 0; + } + else { + ++dsc->df->d_getqueries; + if(req->version >= 0x0200) + ++dsc->df->d_http2Stats.d_nbQueries; + else + ++dsc->df->d_http1Stats.d_nbQueries; + + doh_dispatch_query(dsc, self, req, std::move(decoded), local, remote, std::move(path)); + } + } + else + { + vinfolog("HTTP request without DNS parameter: %s", req->path.base); + h2o_send_error_400(req, "Bad Request", "Unable to find the DNS parameter", 0); ++dsc->df->d_badrequests; return 0; } - else { - ++dsc->df->d_getqueries; - if(req->version >= 0x0200) - ++dsc->df->d_http2Stats.d_nbQueries; - else - ++dsc->df->d_http1Stats.d_nbQueries; - - doh_dispatch_query(dsc, self, req, std::move(decoded), local, remote, std::move(path)); - } } - else - { - vinfolog("HTTP request without DNS parameter: %s", req->path.base); - h2o_send_error_400(req, "Bad Request", "Unable to find the DNS parameter", 0); + else { + h2o_send_error_400(req, "Bad Request", "Unable to parse the request", 0); ++dsc->df->d_badrequests; - return 0; } + return 0; } - else { - h2o_send_error_400(req, "Bad Request", "Unable to parse the request", 0); - ++dsc->df->d_badrequests; + catch(const std::exception& e) + { + errlog("DOH Handler function failed with error %s", e.what()); + return 0; } - return 0; -} - catch(const std::exception& e) -{ - errlog("DOH Handler function failed with error %s", e.what()); - return 0; } HTTPHeaderRule::HTTPHeaderRule(const std::string& header, const std::string& regex) @@ -1391,65 +1392,66 @@ static h2o_pathconf_t *register_handler(h2o_hostconf_t *hostconf, const char *pa // this is the entrypoint from dnsdist.cc void dohThread(ClientState* cs) -try { - std::shared_ptr& df = cs->dohFrontend; - auto& dsc = df->d_dsc; - dsc->cs = cs; - dsc->df = cs->dohFrontend; - dsc->h2o_config.server_name = h2o_iovec_init(df->d_serverTokens.c_str(), df->d_serverTokens.size()); + try { + std::shared_ptr& df = cs->dohFrontend; + auto& dsc = df->d_dsc; + dsc->cs = cs; + dsc->df = cs->dohFrontend; + dsc->h2o_config.server_name = h2o_iovec_init(df->d_serverTokens.c_str(), df->d_serverTokens.size()); - std::thread dnsdistThread(dnsdistclient, dsc->dohquerypair[1]); - dnsdistThread.detach(); // gets us better error reporting + std::thread dnsdistThread(dnsdistclient, dsc->dohquerypair[1]); + dnsdistThread.detach(); // gets us better error reporting - setThreadName("dnsdist/doh"); - // I wonder if this registers an IP address.. I think it does - // this may mean we need to actually register a site "name" here and not the IP address - h2o_hostconf_t *hostconf = h2o_config_register_host(&dsc->h2o_config, h2o_iovec_init(df->d_local.toString().c_str(), df->d_local.toString().size()), 65535); + setThreadName("dnsdist/doh"); + // I wonder if this registers an IP address.. I think it does + // this may mean we need to actually register a site "name" here and not the IP address + h2o_hostconf_t *hostconf = h2o_config_register_host(&dsc->h2o_config, h2o_iovec_init(df->d_local.toString().c_str(), df->d_local.toString().size()), 65535); - for(const auto& url : df->d_urls) { - register_handler(hostconf, url.c_str(), doh_handler); - dsc->paths.insert(url); - } + for(const auto& url : df->d_urls) { + register_handler(hostconf, url.c_str(), doh_handler); + dsc->paths.insert(url); + } - h2o_context_init(&dsc->h2o_ctx, h2o_evloop_create(), &dsc->h2o_config); + h2o_context_init(&dsc->h2o_ctx, h2o_evloop_create(), &dsc->h2o_config); - // in this complicated way we insert the DOHServerConfig pointer in there - h2o_vector_reserve(nullptr, &dsc->h2o_ctx.storage, 1); - dsc->h2o_ctx.storage.entries[0].data = dsc.get(); - ++dsc->h2o_ctx.storage.size; + // in this complicated way we insert the DOHServerConfig pointer in there + h2o_vector_reserve(nullptr, &dsc->h2o_ctx.storage, 1); + dsc->h2o_ctx.storage.entries[0].data = dsc.get(); + ++dsc->h2o_ctx.storage.size; - auto sock = h2o_evloop_socket_create(dsc->h2o_ctx.loop, dsc->dohresponsepair[1], H2O_SOCKET_FLAG_DONT_READ); - sock->data = dsc.get(); + auto sock = h2o_evloop_socket_create(dsc->h2o_ctx.loop, dsc->dohresponsepair[1], H2O_SOCKET_FLAG_DONT_READ); + sock->data = dsc.get(); - // this listens to responses from dnsdist to turn into http responses - h2o_socket_read_start(sock, on_dnsdist); + // this listens to responses from dnsdist to turn into http responses + h2o_socket_read_start(sock, on_dnsdist); - setupAcceptContext(*dsc->accept_ctx, *dsc, false); + setupAcceptContext(*dsc->accept_ctx, *dsc, false); - if (create_listener(df->d_local, dsc, cs->tcpFD) != 0) { - throw std::runtime_error("DOH server failed to listen on " + df->d_local.toStringWithPort() + ": " + strerror(errno)); - } + if (create_listener(df->d_local, dsc, cs->tcpFD) != 0) { + throw std::runtime_error("DOH server failed to listen on " + df->d_local.toStringWithPort() + ": " + strerror(errno)); + } - bool stop = false; - do { - int result = h2o_evloop_run(dsc->h2o_ctx.loop, INT32_MAX); - if (result == -1) { - if (errno != EINTR) { - errlog("Error in the DoH event loop: %s", strerror(errno)); - stop = true; + bool stop = false; + do { + int result = h2o_evloop_run(dsc->h2o_ctx.loop, INT32_MAX); + if (result == -1) { + if (errno != EINTR) { + errlog("Error in the DoH event loop: %s", strerror(errno)); + stop = true; + } } } - } - while (stop == false); + while (stop == false); -} -catch(const std::exception& e) { - throw runtime_error("DOH thread failed to launch: " + std::string(e.what())); -} -catch(...) { - throw runtime_error("DOH thread failed to launch"); + } + catch (const std::exception& e) { + throw runtime_error("DOH thread failed to launch: " + std::string(e.what())); + } + catch (...) { + throw runtime_error("DOH thread failed to launch"); + } } #else /* HAVE_DNS_OVER_HTTPS */ diff --git a/pdns/dnsparser.cc b/pdns/dnsparser.cc index f8755b4934..808872761d 100644 --- a/pdns/dnsparser.cc +++ b/pdns/dnsparser.cc @@ -516,23 +516,24 @@ string PacketReader::getUnquotedText(bool lenField) } void PacketReader::xfrBlob(string& blob) -try { - if(d_recordlen && !(d_pos == (d_startrecordpos + d_recordlen))) { - if (d_pos > (d_startrecordpos + d_recordlen)) { - throw std::out_of_range("xfrBlob out of record range"); + try { + if(d_recordlen && !(d_pos == (d_startrecordpos + d_recordlen))) { + if (d_pos > (d_startrecordpos + d_recordlen)) { + throw std::out_of_range("xfrBlob out of record range"); + } + blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1); + } + else { + blob.clear(); } - blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1); + + d_pos = d_startrecordpos + d_recordlen; } - else { - blob.clear(); + catch(...) + { + throw std::out_of_range("xfrBlob out of range"); } - - d_pos = d_startrecordpos + d_recordlen; -} -catch(...) -{ - throw std::out_of_range("xfrBlob out of range"); } void PacketReader::xfrBlobNoSpaces(string& blob, int length) { diff --git a/pdns/remote_logger.cc b/pdns/remote_logger.cc index 0816105238..f5d9e47a4e 100644 --- a/pdns/remote_logger.cc +++ b/pdns/remote_logger.cc @@ -173,62 +173,63 @@ void RemoteLogger::queueData(const std::string& data) ++d_queued; } -void RemoteLogger::maintenanceThread() -try +void RemoteLogger::maintenanceThread() { + try { #ifdef WE_ARE_RECURSOR - string threadName = "pdns-r/remLog"; + string threadName = "pdns-r/remLog"; #else - string threadName = "dnsdist/remLog"; + string threadName = "dnsdist/remLog"; #endif - setThreadName(threadName); + setThreadName(threadName); - for (;;) { - if (d_exiting) { - break; - } + for (;;) { + if (d_exiting) { + break; + } - bool connected = true; - if (d_socket == nullptr) { - // if it was unset, it will remain so, we are the only ones setting it! - connected = reconnect(); - } + bool connected = true; + if (d_socket == nullptr) { + // if it was unset, it will remain so, we are the only ones setting it! + connected = reconnect(); + } - /* we will just go to sleep if the reconnection just failed */ - if (connected) { - try { - /* we don't want to take the lock while trying to reconnect */ - std::lock_guard lock(d_mutex); - if (d_socket) { // check if it is set - /* if flush() returns false, it means that we couldn't flush anything yet - either because there is nothing to flush, or because the outgoing TCP - buffer is full. That's fine by us */ - d_writer.flush(d_socket->getHandle()); + /* we will just go to sleep if the reconnection just failed */ + if (connected) { + try { + /* we don't want to take the lock while trying to reconnect */ + std::lock_guard lock(d_mutex); + if (d_socket) { // check if it is set + /* if flush() returns false, it means that we couldn't flush anything yet + either because there is nothing to flush, or because the outgoing TCP + buffer is full. That's fine by us */ + d_writer.flush(d_socket->getHandle()); + } + else { + connected = false; + } } - else { + catch(const std::exception& e) { + d_socket.reset(); connected = false; } - } - catch(const std::exception& e) { - d_socket.reset(); - connected = false; - } - if (!connected) { - /* let's try to reconnect right away, we are about to sleep anyway */ - reconnect(); + if (!connected) { + /* let's try to reconnect right away, we are about to sleep anyway */ + reconnect(); + } } - } - sleep(d_reconnectWaitTime); + sleep(d_reconnectWaitTime); + } + } + catch (const std::exception& e) + { + cerr << "Remote Logger's maintenance thead died on: " << e.what() << endl; + } + catch (...) { + cerr << "Remote Logger's maintenance thead died on unknown exception" << endl; } -} -catch(const std::exception& e) -{ - cerr << "Remote Logger's maintenance thead died on: " << e.what() << endl; -} -catch(...) { - cerr << "Remote Logger's maintenance thead died on unknown exception" << endl; } RemoteLogger::~RemoteLogger()