#include "threadname.hh"
GlobalStateHolder<vector<CarbonConfig> > 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<<namespace_name<<"."<<hostname<<"."<<instance_name<<"."<<e.first<<' ';
- if(const auto& val = boost::get<DNSDistStats::stat_t*>(&e.second))
- str<<(*val)->load();
- else if (const auto& dval = boost::get<double*>(&e.second))
- str<<**dval;
- else
- str<<(*boost::get<DNSDistStats::statfunction_t>(&e.second))(e.first);
- str<<' '<<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<<base<<"queries" << ' ' << state->queries.load() << " " << now << "\r\n";
- str<<base<<"responses" << ' ' << state->responses.load() << " " << now << "\r\n";
- str<<base<<"drops" << ' ' << state->reuseds.load() << " " << now << "\r\n";
- str<<base<<"latency" << ' ' << (state->availability != DownstreamState::Availability::Down ? state->latencyUsec/1000.0 : 0) << " " << now << "\r\n";
- str<<base<<"senderrors" << ' ' << state->sendErrors.load() << " " << now << "\r\n";
- str<<base<<"outstanding" << ' ' << state->outstanding.load() << " " << now << "\r\n";
- str<<base<<"tcpdiedsendingquery" << ' '<< state->tcpDiedSendingQuery.load() << " " << now << "\r\n";
- str<<base<<"tcpdiedreaddingresponse" << ' '<< state->tcpDiedReadingResponse.load() << " " << now << "\r\n";
- str<<base<<"tcpgaveup" << ' '<< state->tcpGaveUp.load() << " " << now << "\r\n";
- str<<base<<"tcpreadimeouts" << ' '<< state->tcpReadTimeouts.load() << " " << now << "\r\n";
- str<<base<<"tcpwritetimeouts" << ' '<< state->tcpWriteTimeouts.load() << " " << now << "\r\n";
- str<<base<<"tcpcurrentconnections" << ' '<< state->tcpCurrentConnections.load() << " " << now << "\r\n";
- str<<base<<"tcpavgqueriesperconnection" << ' '<< state->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n";
- str<<base<<"tcpavgconnectionduration" << ' '<< state->tcpAvgConnectionDuration.load() << " " << now << "\r\n";
- }
-
- std::map<std::string,uint64_t> 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<<base<<"queries" << ' ' << front->queries.load() << " " << now << "\r\n";
- str<<base<<"responses" << ' ' << front->responses.load() << " " << now << "\r\n";
- str<<base<<"tcpdiedreadingquery" << ' '<< front->tcpDiedReadingQuery.load() << " " << now << "\r\n";
- str<<base<<"tcpdiedsendingresponse" << ' '<< front->tcpDiedSendingResponse.load() << " " << now << "\r\n";
- str<<base<<"tcpgaveup" << ' '<< front->tcpGaveUp.load() << " " << now << "\r\n";
- str<<base<<"tcpclientimeouts" << ' '<< front->tcpClientTimeouts.load() << " " << now << "\r\n";
- str<<base<<"tcpdownstreamtimeouts" << ' '<< front->tcpDownstreamTimeouts.load() << " " << now << "\r\n";
- str<<base<<"tcpcurrentconnections" << ' '<< front->tcpCurrentConnections.load() << " " << now << "\r\n";
- str<<base<<"tcpavgqueriesperconnection" << ' '<< front->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n";
- str<<base<<"tcpavgconnectionduration" << ' '<< front->tcpAvgConnectionDuration.load() << " " << now << "\r\n";
- str<<base<<"tls10-queries" << ' ' << front->tls10queries.load() << " " << now << "\r\n";
- str<<base<<"tls11-queries" << ' ' << front->tls11queries.load() << " " << now << "\r\n";
- str<<base<<"tls12-queries" << ' ' << front->tls12queries.load() << " " << now << "\r\n";
- str<<base<<"tls13-queries" << ' ' << front->tls13queries.load() << " " << now << "\r\n";
- str<<base<<"tls-unknown-queries" << ' ' << front->tlsUnknownqueries.load() << " " << now << "\r\n";
- str<<base<<"tlsnewsessions" << ' ' << front->tlsNewSessions.load() << " " << now << "\r\n";
- str<<base<<"tlsresumptions" << ' ' << front->tlsResumptions.load() << " " << now << "\r\n";
- str<<base<<"tlsunknownticketkeys" << ' ' << front->tlsUnknownTicketKey.load() << " " << now << "\r\n";
- str<<base<<"tlsinactiveticketkeys" << ' ' << front->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<<base<<"tlsdhkeytoosmall" << ' ' << errorCounters->d_dhKeyTooSmall << " " << now << "\r\n";
- str<<base<<"tlsinappropriatefallback" << ' ' << errorCounters->d_inappropriateFallBack << " " << now << "\r\n";
- str<<base<<"tlsnosharedcipher" << ' ' << errorCounters->d_noSharedCipher << " " << now << "\r\n";
- str<<base<<"tlsunknownciphertype" << ' ' << errorCounters->d_unknownCipherType << " " << now << "\r\n";
- str<<base<<"tlsunknownkeyexchangetype" << ' ' << errorCounters->d_unknownKeyExchangeType << " " << now << "\r\n";
- str<<base<<"tlsunknownprotocol" << ' ' << errorCounters->d_unknownProtocol << " " << now << "\r\n";
- str<<base<<"tlsunsupportedec" << ' ' << errorCounters->d_unsupportedEC << " " << now << "\r\n";
- str<<base<<"tlsunsupportedprotocol" << ' ' << errorCounters->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<<namespace_name<<"."<<hostname<<"."<<instance_name<<"."<<e.first<<' ';
+ if(const auto& val = boost::get<DNSDistStats::stat_t*>(&e.second))
+ str<<(*val)->load();
+ else if (const auto& dval = boost::get<double*>(&e.second))
+ str<<**dval;
+ else
+ str<<(*boost::get<DNSDistStats::statfunction_t>(&e.second))(e.first);
+ str<<' '<<now<<"\r\n";
}
- const string base = namespace_name + "." + hostname + "." + instance_name + ".pools." + poolName + ".";
- const std::shared_ptr<ServerPool> pool = entry.second;
- str<<base<<"servers" << " " << pool->countServers(false) << " " << now << "\r\n";
- str<<base<<"servers-up" << " " << pool->countServers(true) << " " << now << "\r\n";
- if (pool->packetCache != nullptr) {
- const auto& cache = pool->packetCache;
- str<<base<<"cache-size" << " " << cache->getMaxEntries() << " " << now << "\r\n";
- str<<base<<"cache-entries" << " " << cache->getEntriesCount() << " " << now << "\r\n";
- str<<base<<"cache-hits" << " " << cache->getHits() << " " << now << "\r\n";
- str<<base<<"cache-misses" << " " << cache->getMisses() << " " << now << "\r\n";
- str<<base<<"cache-deferred-inserts" << " " << cache->getDeferredInserts() << " " << now << "\r\n";
- str<<base<<"cache-deferred-lookups" << " " << cache->getDeferredLookups() << " " << now << "\r\n";
- str<<base<<"cache-lookup-collisions" << " " << cache->getLookupCollisions() << " " << now << "\r\n";
- str<<base<<"cache-insert-collisions" << " " << cache->getInsertCollisions() << " " << now << "\r\n";
- str<<base<<"cache-ttl-too-shorts" << " " << cache->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<<base<<"queries" << ' ' << state->queries.load() << " " << now << "\r\n";
+ str<<base<<"responses" << ' ' << state->responses.load() << " " << now << "\r\n";
+ str<<base<<"drops" << ' ' << state->reuseds.load() << " " << now << "\r\n";
+ str<<base<<"latency" << ' ' << (state->availability != DownstreamState::Availability::Down ? state->latencyUsec/1000.0 : 0) << " " << now << "\r\n";
+ str<<base<<"senderrors" << ' ' << state->sendErrors.load() << " " << now << "\r\n";
+ str<<base<<"outstanding" << ' ' << state->outstanding.load() << " " << now << "\r\n";
+ str<<base<<"tcpdiedsendingquery" << ' '<< state->tcpDiedSendingQuery.load() << " " << now << "\r\n";
+ str<<base<<"tcpdiedreaddingresponse" << ' '<< state->tcpDiedReadingResponse.load() << " " << now << "\r\n";
+ str<<base<<"tcpgaveup" << ' '<< state->tcpGaveUp.load() << " " << now << "\r\n";
+ str<<base<<"tcpreadimeouts" << ' '<< state->tcpReadTimeouts.load() << " " << now << "\r\n";
+ str<<base<<"tcpwritetimeouts" << ' '<< state->tcpWriteTimeouts.load() << " " << now << "\r\n";
+ str<<base<<"tcpcurrentconnections" << ' '<< state->tcpCurrentConnections.load() << " " << now << "\r\n";
+ str<<base<<"tcpavgqueriesperconnection" << ' '<< state->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n";
+ str<<base<<"tcpavgconnectionduration" << ' '<< state->tcpAvgConnectionDuration.load() << " " << now << "\r\n";
}
- }
-#ifdef HAVE_DNS_OVER_HTTPS
- {
- std::map<std::string,uint64_t> 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<std::string,uint64_t> 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<pair<const char*, const std::atomic<uint64_t>&>> 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<<base<<"queries" << ' ' << front->queries.load() << " " << now << "\r\n";
+ str<<base<<"responses" << ' ' << front->responses.load() << " " << now << "\r\n";
+ str<<base<<"tcpdiedreadingquery" << ' '<< front->tcpDiedReadingQuery.load() << " " << now << "\r\n";
+ str<<base<<"tcpdiedsendingresponse" << ' '<< front->tcpDiedSendingResponse.load() << " " << now << "\r\n";
+ str<<base<<"tcpgaveup" << ' '<< front->tcpGaveUp.load() << " " << now << "\r\n";
+ str<<base<<"tcpclientimeouts" << ' '<< front->tcpClientTimeouts.load() << " " << now << "\r\n";
+ str<<base<<"tcpdownstreamtimeouts" << ' '<< front->tcpDownstreamTimeouts.load() << " " << now << "\r\n";
+ str<<base<<"tcpcurrentconnections" << ' '<< front->tcpCurrentConnections.load() << " " << now << "\r\n";
+ str<<base<<"tcpavgqueriesperconnection" << ' '<< front->tcpAvgQueriesPerConnection.load() << " " << now << "\r\n";
+ str<<base<<"tcpavgconnectionduration" << ' '<< front->tcpAvgConnectionDuration.load() << " " << now << "\r\n";
+ str<<base<<"tls10-queries" << ' ' << front->tls10queries.load() << " " << now << "\r\n";
+ str<<base<<"tls11-queries" << ' ' << front->tls11queries.load() << " " << now << "\r\n";
+ str<<base<<"tls12-queries" << ' ' << front->tls12queries.load() << " " << now << "\r\n";
+ str<<base<<"tls13-queries" << ' ' << front->tls13queries.load() << " " << now << "\r\n";
+ str<<base<<"tls-unknown-queries" << ' ' << front->tlsUnknownqueries.load() << " " << now << "\r\n";
+ str<<base<<"tlsnewsessions" << ' ' << front->tlsNewSessions.load() << " " << now << "\r\n";
+ str<<base<<"tlsresumptions" << ' ' << front->tlsResumptions.load() << " " << now << "\r\n";
+ str<<base<<"tlsunknownticketkeys" << ' ' << front->tlsUnknownTicketKey.load() << " " << now << "\r\n";
+ str<<base<<"tlsinactiveticketkeys" << ' ' << front->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<<base<<"tlsdhkeytoosmall" << ' ' << errorCounters->d_dhKeyTooSmall << " " << now << "\r\n";
+ str<<base<<"tlsinappropriatefallback" << ' ' << errorCounters->d_inappropriateFallBack << " " << now << "\r\n";
+ str<<base<<"tlsnosharedcipher" << ' ' << errorCounters->d_noSharedCipher << " " << now << "\r\n";
+ str<<base<<"tlsunknownciphertype" << ' ' << errorCounters->d_unknownCipherType << " " << now << "\r\n";
+ str<<base<<"tlsunknownkeyexchangetype" << ' ' << errorCounters->d_unknownKeyExchangeType << " " << now << "\r\n";
+ str<<base<<"tlsunknownprotocol" << ' ' << errorCounters->d_unknownProtocol << " " << now << "\r\n";
+ str<<base<<"tlsunsupportedec" << ' ' << errorCounters->d_unsupportedEC << " " << now << "\r\n";
+ str<<base<<"tlsunsupportedprotocol" << ' ' << errorCounters->d_unsupportedProtocol << " " << now << "\r\n";
+ }
+ }
- for(const auto& item : v) {
- str<<base<<name<<"."<<item.first << " " << item.second << " " << now <<"\r\n";
+ auto localPools = g_pools.getLocal();
+ for (const auto& entry : *localPools) {
+ string poolName = entry.first;
+ boost::replace_all(poolName, ".", "_");
+ if (poolName.empty()) {
+ poolName = "_default_";
+ }
+ const string base = namespace_name + "." + hostname + "." + instance_name + ".pools." + poolName + ".";
+ const std::shared_ptr<ServerPool> pool = entry.second;
+ str<<base<<"servers" << " " << pool->countServers(false) << " " << now << "\r\n";
+ str<<base<<"servers-up" << " " << pool->countServers(true) << " " << now << "\r\n";
+ if (pool->packetCache != nullptr) {
+ const auto& cache = pool->packetCache;
+ str<<base<<"cache-size" << " " << cache->getMaxEntries() << " " << now << "\r\n";
+ str<<base<<"cache-entries" << " " << cache->getEntriesCount() << " " << now << "\r\n";
+ str<<base<<"cache-hits" << " " << cache->getHits() << " " << now << "\r\n";
+ str<<base<<"cache-misses" << " " << cache->getMisses() << " " << now << "\r\n";
+ str<<base<<"cache-deferred-inserts" << " " << cache->getDeferredInserts() << " " << now << "\r\n";
+ str<<base<<"cache-deferred-lookups" << " " << cache->getDeferredLookups() << " " << now << "\r\n";
+ str<<base<<"cache-lookup-collisions" << " " << cache->getLookupCollisions() << " " << now << "\r\n";
+ str<<base<<"cache-insert-collisions" << " " << cache->getInsertCollisions() << " " << now << "\r\n";
+ str<<base<<"cache-ttl-too-shorts" << " " << cache->getTTLTooShorts() << " " << now << "\r\n";
+ }
+ }
+
+#ifdef HAVE_DNS_OVER_HTTPS
+ {
+ std::map<std::string,uint64_t> 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<pair<const char*, const std::atomic<uint64_t>&>> 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<<base<<name<<"."<<item.first << " " << item.second << " " << now <<"\r\n";
+ }
}
}
- }
#endif /* HAVE_DNS_OVER_HTTPS */
- {
- WriteLock wl(&g_qcount.queryLock);
- std::string qname;
- for(auto &record: g_qcount.records) {
- qname = record.first;
- boost::replace_all(qname, ".", "_");
- str<<"dnsdist.querycount." << qname << ".queries " << record.second << " " << now << "\r\n";
+ {
+ WriteLock wl(&g_qcount.queryLock);
+ std::string qname;
+ for(auto &record: g_qcount.records) {
+ qname = record.first;
+ boost::replace_all(qname, ".", "_");
+ str<<"dnsdist.querycount." << qname << ".queries " << record.second << " " << now << "\r\n";
+ }
+ g_qcount.records.clear();
}
- g_qcount.records.clear();
- }
- const string msg = str.str();
+ const string msg = str.str();
- int ret = waitForRWData(s.getHandle(), false, 1 , 0);
- if(ret <= 0 ) {
- vinfolog("Unable to write data to carbon server on %s: %s", server.toStringWithPort(), (ret<0 ? stringerror() : "Timeout"));
- continue;
+ int ret = waitForRWData(s.getHandle(), false, 1 , 0);
+ if(ret <= 0 ) {
+ vinfolog("Unable to write data to carbon server on %s: %s", server.toStringWithPort(), (ret<0 ? stringerror() : "Timeout"));
+ continue;
+ }
+ s.setBlocking();
+ writen2(s.getHandle(), msg.c_str(), msg.size());
+ }
+ catch(const std::exception& e) {
+ warnlog("Problem sending carbon data: %s", e.what());
}
- s.setBlocking();
- writen2(s.getHandle(), msg.c_str(), msg.size());
- }
- catch(std::exception& e) {
- warnlog("Problem sending carbon data: %s", e.what());
}
}
}
-}
-catch(std::exception& e)
-{
- errlog("Carbon thread died: %s", e.what());
-}
-catch(PDNSException& e)
-{
- errlog("Carbon thread died, PDNSException: %s", e.reason);
-}
-catch(...)
-{
- errlog("Carbon thread died");
+ catch(const std::exception& e)
+ {
+ errlog("Carbon thread died: %s", e.what());
+ }
+ catch(const PDNSException& e)
+ {
+ errlog("Carbon thread died, PDNSException: %s", e.reason);
+ }
+ catch(...)
+ {
+ errlog("Carbon thread died");
+ }
}
}
static bool getMsgLen32(int fd, uint32_t* len)
-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)
+ 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)
}
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<char> msg(new char[len]);
- readn2(fd, msg.get(), len);
+ boost::scoped_array<char> 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: "<<line<<endl;
- string response;
- try {
- bool withReturn=true;
- retry:;
+ line = sodDecryptSym(line, g_consoleKey, readingNonce);
+ // cerr<<"Have decrypted line: "<<line<<endl;
+ string response;
try {
- std::lock_guard<std::mutex> lock(g_luamutex);
+ bool withReturn=true;
+ retry:;
+ try {
+ std::lock_guard<std::mutex> lock(g_luamutex);
- g_outputBuffer.clear();
- resetLuaSideEffect();
- auto ret=g_lua.executeCode<
- boost::optional<
- boost::variant<
- string,
- shared_ptr<DownstreamState>,
- ClientState*,
- std::unordered_map<string, double>
+ g_outputBuffer.clear();
+ resetLuaSideEffect();
+ auto ret=g_lua.executeCode<
+ boost::optional<
+ boost::variant<
+ string,
+ shared_ptr<DownstreamState>,
+ ClientState*,
+ std::unordered_map<string, double>
+ >
>
- >
- >(withReturn ? ("return "+line) : line);
-
- if(ret) {
- if (const auto dsValue = boost::get<shared_ptr<DownstreamState>>(&*ret)) {
- if (*dsValue) {
- response=(*dsValue)->getName()+"\n";
- } else {
- response="";
+ >(withReturn ? ("return "+line) : line);
+
+ if(ret) {
+ if (const auto dsValue = boost::get<shared_ptr<DownstreamState>>(&*ret)) {
+ if (*dsValue) {
+ response=(*dsValue)->getName()+"\n";
+ } else {
+ response="";
+ }
+ }
+ else if (const auto csValue = boost::get<ClientState*>(&*ret)) {
+ if (*csValue) {
+ response=(*csValue)->local.toStringWithPort()+"\n";
+ } else {
+ response="";
+ }
+ }
+ else if (const auto strValue = boost::get<string>(&*ret)) {
+ response=*strValue+"\n";
+ }
+ else if(const auto um = boost::get<std::unordered_map<string, double> >(&*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<ClientState*>(&*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<string>(&*ret)) {
- response=*strValue+"\n";
- }
- else if(const auto um = boost::get<std::unordered_map<string, double> >(&*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()
// 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;
}
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"<<endl;
- exit(EXIT_FAILURE);
- }
- g_hashperturb=randombytes_uniform(0xffffffff);
- srandom(randombytes_uniform(0xffffffff));
+ if (sodium_init() == -1) {
+ cerr<<"Unable to initialize crypto library"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ g_hashperturb=randombytes_uniform(0xffffffff);
+ srandom(randombytes_uniform(0xffffffff));
#else
- {
- struct timeval tv;
- gettimeofday(&tv, 0);
- srandom(tv.tv_sec ^ tv.tv_usec ^ getpid());
- g_hashperturb=random();
- }
+ {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ srandom(tv.tv_sec ^ tv.tv_usec ^ getpid());
+ g_hashperturb=random();
+ }
#endif
- ComboAddress clientAddress = ComboAddress();
- g_cmdLine.config=SYSCONFDIR "/dnsdist.conf";
- struct option longopts[]={
- {"acl", required_argument, 0, 'a'},
- {"check-config", no_argument, 0, 1},
- {"client", no_argument, 0, 'c'},
- {"config", required_argument, 0, 'C'},
- {"disable-syslog", no_argument, 0, 2},
- {"execute", required_argument, 0, 'e'},
- {"gid", required_argument, 0, 'g'},
- {"help", no_argument, 0, 'h'},
- {"local", required_argument, 0, 'l'},
- {"setkey", required_argument, 0, 'k'},
- {"supervised", no_argument, 0, 3},
- {"uid", required_argument, 0, 'u'},
- {"verbose", no_argument, 0, 'v'},
- {"version", no_argument, 0, 'V'},
- {0,0,0,0}
- };
- int longindex=0;
- string optstring;
- for(;;) {
- int c=getopt_long(argc, argv, "a:cC:e:g:hk:l:u:vV", longopts, &longindex);
- if(c==-1)
- break;
- switch(c) {
- case 1:
- g_cmdLine.checkConfig=true;
- break;
- case 2:
- g_syslog=false;
- break;
- case 3:
- g_cmdLine.beSupervised=true;
- break;
- case 'C':
- g_cmdLine.config=optarg;
- break;
- case 'c':
- g_cmdLine.beClient=true;
- break;
- case 'e':
- g_cmdLine.command=optarg;
- break;
- case 'g':
- g_cmdLine.gid=optarg;
- break;
- case 'h':
- cout<<"dnsdist "<<VERSION<<endl;
- usage();
- cout<<"\n";
- exit(EXIT_SUCCESS);
- break;
- case 'a':
- optstring=optarg;
- g_ACL.modify([optstring](NetmaskGroup& nmg) { nmg.addMask(optstring); });
- break;
- case 'k':
+ ComboAddress clientAddress = ComboAddress();
+ g_cmdLine.config=SYSCONFDIR "/dnsdist.conf";
+ struct option longopts[]={
+ {"acl", required_argument, 0, 'a'},
+ {"check-config", no_argument, 0, 1},
+ {"client", no_argument, 0, 'c'},
+ {"config", required_argument, 0, 'C'},
+ {"disable-syslog", no_argument, 0, 2},
+ {"execute", required_argument, 0, 'e'},
+ {"gid", required_argument, 0, 'g'},
+ {"help", no_argument, 0, 'h'},
+ {"local", required_argument, 0, 'l'},
+ {"setkey", required_argument, 0, 'k'},
+ {"supervised", no_argument, 0, 3},
+ {"uid", required_argument, 0, 'u'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {0,0,0,0}
+ };
+ int longindex=0;
+ string optstring;
+ for(;;) {
+ int c=getopt_long(argc, argv, "a:cC:e:g:hk:l:u:vV", longopts, &longindex);
+ if(c==-1)
+ break;
+ switch(c) {
+ case 1:
+ g_cmdLine.checkConfig=true;
+ break;
+ case 2:
+ g_syslog=false;
+ break;
+ case 3:
+ g_cmdLine.beSupervised=true;
+ break;
+ case 'C':
+ g_cmdLine.config=optarg;
+ break;
+ case 'c':
+ g_cmdLine.beClient=true;
+ break;
+ case 'e':
+ g_cmdLine.command=optarg;
+ break;
+ case 'g':
+ g_cmdLine.gid=optarg;
+ break;
+ case 'h':
+ cout<<"dnsdist "<<VERSION<<endl;
+ usage();
+ cout<<"\n";
+ exit(EXIT_SUCCESS);
+ break;
+ case 'a':
+ optstring=optarg;
+ g_ACL.modify([optstring](NetmaskGroup& nmg) { nmg.addMask(optstring); });
+ break;
+ case 'k':
#ifdef HAVE_LIBSODIUM
- if (B64Decode(string(optarg), g_consoleKey) < 0) {
- cerr<<"Unable to decode key '"<<optarg<<"'."<<endl;
- exit(EXIT_FAILURE);
- }
+ if (B64Decode(string(optarg), g_consoleKey) < 0) {
+ cerr<<"Unable to decode key '"<<optarg<<"'."<<endl;
+ exit(EXIT_FAILURE);
+ }
#else
- cerr<<"dnsdist has been built without libsodium, -k/--setkey is unsupported."<<endl;
- exit(EXIT_FAILURE);
+ cerr<<"dnsdist has been built without libsodium, -k/--setkey is unsupported."<<endl;
+ exit(EXIT_FAILURE);
#endif
- break;
- case 'l':
- g_cmdLine.locals.push_back(boost::trim_copy(string(optarg)));
- break;
- case 'u':
- g_cmdLine.uid=optarg;
- break;
- case 'v':
- g_verbose=true;
- break;
- case 'V':
+ break;
+ case 'l':
+ g_cmdLine.locals.push_back(boost::trim_copy(string(optarg)));
+ break;
+ case 'u':
+ g_cmdLine.uid=optarg;
+ break;
+ case 'v':
+ g_verbose=true;
+ break;
+ case 'V':
#ifdef LUAJIT_VERSION
- cout<<"dnsdist "<<VERSION<<" ("<<LUA_RELEASE<<" ["<<LUAJIT_VERSION<<"])"<<endl;
+ cout<<"dnsdist "<<VERSION<<" ("<<LUA_RELEASE<<" ["<<LUAJIT_VERSION<<"])"<<endl;
#else
- cout<<"dnsdist "<<VERSION<<" ("<<LUA_RELEASE<<")"<<endl;
+ cout<<"dnsdist "<<VERSION<<" ("<<LUA_RELEASE<<")"<<endl;
#endif
- cout<<"Enabled features: ";
+ cout<<"Enabled features: ";
#ifdef HAVE_CDB
- cout<<"cdb ";
+ cout<<"cdb ";
#endif
#ifdef HAVE_DNS_OVER_TLS
- cout<<"dns-over-tls(";
+ cout<<"dns-over-tls(";
#ifdef HAVE_GNUTLS
- cout<<"gnutls";
- #ifdef HAVE_LIBSSL
- cout<<" ";
- #endif
+ cout<<"gnutls";
+#ifdef HAVE_LIBSSL
+ cout<<" ";
+#endif
#endif
#ifdef HAVE_LIBSSL
- cout<<"openssl";
+ cout<<"openssl";
#endif
- cout<<") ";
+ cout<<") ";
#endif
#ifdef HAVE_DNS_OVER_HTTPS
- cout<<"dns-over-https(DOH) ";
+ cout<<"dns-over-https(DOH) ";
#endif
#ifdef HAVE_DNSCRYPT
- cout<<"dnscrypt ";
+ cout<<"dnscrypt ";
#endif
#ifdef HAVE_EBPF
- cout<<"ebpf ";
+ cout<<"ebpf ";
#endif
#ifdef HAVE_FSTRM
- cout<<"fstrm ";
+ cout<<"fstrm ";
#endif
#ifdef HAVE_LIBCRYPTO
- cout<<"ipcipher ";
+ cout<<"ipcipher ";
#endif
#ifdef HAVE_LIBSODIUM
- cout<<"libsodium ";
+ cout<<"libsodium ";
#endif
#ifdef HAVE_LMDB
- cout<<"lmdb ";
+ cout<<"lmdb ";
#endif
- cout<<"protobuf ";
+ cout<<"protobuf ";
#ifdef HAVE_RE2
- cout<<"re2 ";
+ cout<<"re2 ";
#endif
#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
- cout<<"recvmmsg/sendmmsg ";
+ cout<<"recvmmsg/sendmmsg ";
#endif
#ifdef HAVE_NET_SNMP
- cout<<"snmp ";
+ cout<<"snmp ";
#endif
#ifdef HAVE_SYSTEMD
- cout<<"systemd";
+ cout<<"systemd";
#endif
- cout<<endl;
- exit(EXIT_SUCCESS);
- break;
- case '?':
- //getopt_long printed an error message.
- usage();
- exit(EXIT_FAILURE);
- break;
+ cout<<endl;
+ exit(EXIT_SUCCESS);
+ break;
+ case '?':
+ //getopt_long printed an error message.
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ }
}
- }
- argc-=optind;
- argv+=optind;
- for(auto p = argv; *p; ++p) {
- if(g_cmdLine.beClient) {
- clientAddress = ComboAddress(*p, 5199);
- } else {
- g_cmdLine.remotes.push_back(*p);
+ argc-=optind;
+ argv+=optind;
+ for(auto p = argv; *p; ++p) {
+ if(g_cmdLine.beClient) {
+ clientAddress = ComboAddress(*p, 5199);
+ } else {
+ g_cmdLine.remotes.push_back(*p);
+ }
}
- }
- ServerPolicy leastOutstandingPol{"leastOutstanding", leastOutstanding, false};
+ ServerPolicy leastOutstandingPol{"leastOutstanding", leastOutstanding, false};
- g_policy.setState(leastOutstandingPol);
- if(g_cmdLine.beClient || !g_cmdLine.command.empty()) {
- setupLua(g_lua, true, false, g_cmdLine.config);
- if (clientAddress != ComboAddress())
- g_serverControl = clientAddress;
- doClient(g_serverControl, g_cmdLine.command);
- _exit(EXIT_SUCCESS);
- }
+ g_policy.setState(leastOutstandingPol);
+ if(g_cmdLine.beClient || !g_cmdLine.command.empty()) {
+ setupLua(g_lua, true, false, g_cmdLine.config);
+ if (clientAddress != ComboAddress())
+ g_serverControl = clientAddress;
+ doClient(g_serverControl, g_cmdLine.command);
+ _exit(EXIT_SUCCESS);
+ }
- auto acl = g_ACL.getCopy();
- if(acl.empty()) {
- for(auto& addr : {"127.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "169.254.0.0/16", "192.168.0.0/16", "172.16.0.0/12", "::1/128", "fc00::/7", "fe80::/10"})
- acl.addMask(addr);
- g_ACL.setState(acl);
- }
+ auto acl = g_ACL.getCopy();
+ if(acl.empty()) {
+ for(auto& addr : {"127.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "169.254.0.0/16", "192.168.0.0/16", "172.16.0.0/12", "::1/128", "fc00::/7", "fe80::/10"})
+ acl.addMask(addr);
+ g_ACL.setState(acl);
+ }
- auto consoleACL = g_consoleACL.getCopy();
- for (const auto& mask : { "127.0.0.1/8", "::1/128" }) {
- consoleACL.addMask(mask);
- }
- g_consoleACL.setState(consoleACL);
- registerBuiltInWebHandlers();
+ auto consoleACL = g_consoleACL.getCopy();
+ for (const auto& mask : { "127.0.0.1/8", "::1/128" }) {
+ consoleACL.addMask(mask);
+ }
+ g_consoleACL.setState(consoleACL);
+ registerBuiltInWebHandlers();
- if (g_cmdLine.checkConfig) {
- setupLua(g_lua, false, true, g_cmdLine.config);
- // No exception was thrown
- infolog("Configuration '%s' OK!", g_cmdLine.config);
- _exit(EXIT_SUCCESS);
- }
+ if (g_cmdLine.checkConfig) {
+ setupLua(g_lua, false, true, g_cmdLine.config);
+ // No exception was thrown
+ infolog("Configuration '%s' OK!", g_cmdLine.config);
+ _exit(EXIT_SUCCESS);
+ }
- auto todo = setupLua(g_lua, false, false, g_cmdLine.config);
+ auto todo = setupLua(g_lua, false, false, g_cmdLine.config);
- 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 ;
+ 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<ClientState>(new ClientState(ComboAddress(loc, 53), false, false, 0, "", {})));
+ /* TCP */
+ g_frontends.push_back(std::unique_ptr<ClientState>(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<ClientState>(new ClientState(ComboAddress(loc, 53), false, false, 0, "", {})));
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress("127.0.0.1", 53), false, false, 0, "", {})));
/* TCP */
- g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress(loc, 53), true, false, 0, "", {})));
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress("127.0.0.1", 53), true, false, 0, "", {})));
}
- }
- if (g_frontends.empty()) {
- /* UDP */
- g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(ComboAddress("127.0.0.1", 53), false, false, 0, "", {})));
- /* TCP */
- g_frontends.push_back(std::unique_ptr<ClientState>(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<string> 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<string> 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<DelayedPacket>();
+ /* this need to be done _after_ dropping privileges */
+ g_delay = new DelayPipe<DelayedPacket>();
- if (g_snmpAgent) {
- g_snmpAgent->run();
- }
+ if (g_snmpAgent) {
+ g_snmpAgent->run();
+ }
- g_tcpclientthreads = std::unique_ptr<TCPClientCollection>(new TCPClientCollection(g_maxTCPClientThreads, g_useTCPSinglePipe));
+ g_tcpclientthreads = std::unique_ptr<TCPClientCollection>(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<DownstreamState>(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<DownstreamState>(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>(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>(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&)
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<struct sockaddr*>(&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<struct sockaddr*>(&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<struct sockaddr*>(&local));
- DOHServerConfig* dsc = reinterpret_cast<DOHServerConfig*>(req->conn->ctx->storage.entries[0].data);
+ h2o_socket_getsockname(sock, reinterpret_cast<struct sockaddr*>(&local));
+ DOHServerConfig* dsc = reinterpret_cast<DOHServerConfig*>(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)
// this is the entrypoint from dnsdist.cc
void dohThread(ClientState* cs)
-try
{
- std::shared_ptr<DOHFrontend>& 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<DOHFrontend>& 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 */
}
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) {
++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<std::mutex> 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<std::mutex> 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()