typedef std::unordered_map<std::string, boost::variant<bool, int, std::string, std::vector<std::pair<int,int> > > > localbind_t;
-static void parseLocalBindVars(boost::optional<localbind_t> vars, bool& doTCP, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus)
+static void parseLocalBindVars(boost::optional<localbind_t> vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus)
{
if (vars) {
- if (vars->count("doTCP")) {
- doTCP = boost::get<bool>((*vars)["doTCP"]);
- }
if (vars->count("reusePort")) {
reusePort = boost::get<bool>((*vars)["reusePort"]);
}
}
}
-#ifdef HAVE_DNS_OVER_TLS
-static bool loadTLSCertificateAndKeys(shared_ptr<TLSFrontend>& frontend, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)
+#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
+static bool loadTLSCertificateAndKeys(const std::string& context, std::vector<std::pair<std::string, std::string>>& pairs, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)
{
if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) {
auto certFile = boost::get<std::string>(certFiles);
auto keyFile = boost::get<std::string>(keyFiles);
- frontend->d_certKeyPairs.clear();
- frontend->d_certKeyPairs.push_back({certFile, keyFile});
+ pairs.clear();
+ pairs.push_back({certFile, keyFile});
}
else if (certFiles.type() == typeid(std::vector<std::pair<int,std::string>>) && keyFiles.type() == typeid(std::vector<std::pair<int,std::string>>))
{
auto certFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(certFiles);
auto keyFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(keyFiles);
if (certFilesVect.size() == keyFilesVect.size()) {
- frontend->d_certKeyPairs.clear();
+ pairs.clear();
for (size_t idx = 0; idx < certFilesVect.size(); idx++) {
- frontend->d_certKeyPairs.push_back({certFilesVect.at(idx).second, keyFilesVect.at(idx).second});
+ pairs.push_back({certFilesVect.at(idx).second, keyFilesVect.at(idx).second});
}
}
else {
- errlog("Error, mismatching number of certificates and keys in call to addTLSLocal()!");
- g_outputBuffer="Error, mismatching number of certificates and keys in call to addTLSLocal()!";
+ errlog("Error, mismatching number of certificates and keys in call to %s()!", context);
+ g_outputBuffer="Error, mismatching number of certificates and keys in call to " + context + "()!";
return false;
}
}
else {
- errlog("Error, mismatching number of certificates and keys in call to addTLSLocal()!");
- g_outputBuffer="Error, mismatching number of certificates and keys in call to addTLSLocal()!";
+ errlog("Error, mismatching number of certificates and keys in call to %s()!", context);
+ g_outputBuffer="Error, mismatching number of certificates and keys in call to " + context + "()!";
return false;
}
return true;
}
-#endif /* HAVE_DNS_OVER_TLS */
+#endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
void setupLuaConfig(bool client)
{
g_outputBuffer="setLocal cannot be used at runtime!\n";
return;
}
- bool doTCP = true;
bool reusePort = false;
int tcpFastOpenQueueSize = 0;
std::string interface;
std::set<int> cpus;
- parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
try {
ComboAddress loc(addr, 53);
- g_locals.clear();
- g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus)); /// only works pre-startup, so no sync necessary
+ for (auto it = g_frontends.begin(); it != g_frontends.end(); ) {
+ /* TLS and DNSCrypt frontends are separate */
+ if ((*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) {
+ it = g_frontends.erase(it);
+ }
+ else {
+ ++it;
+ }
+ }
+
+ // only works pre-startup, so no sync necessary
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
}
- catch(std::exception& e) {
+ catch(const std::exception& e) {
g_outputBuffer="Error: "+string(e.what())+"\n";
}
});
g_outputBuffer="addLocal cannot be used at runtime!\n";
return;
}
- bool doTCP = true;
bool reusePort = false;
int tcpFastOpenQueueSize = 0;
std::string interface;
std::set<int> cpus;
- parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
try {
ComboAddress loc(addr, 53);
- g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus)); /// only works pre-startup, so no sync necessary
+ // only works pre-startup, so no sync necessary
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+ g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
}
catch(std::exception& e) {
- g_outputBuffer="Error: "+string(e.what())+"\n";
+ g_outputBuffer="Error: "+string(e.what())+"\n";
+ errlog("Error while trying to listen on %s: %s\n", addr, string(e.what()));
}
});
return;
}
#ifdef HAVE_DNSCRYPT
- bool doTCP = true;
bool reusePort = false;
int tcpFastOpenQueueSize = 0;
std::string interface;
std::set<int> cpus;
- parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
try {
auto ctx = std::make_shared<DNSCryptContext>(providerName, certFile, keyFile);
- g_dnsCryptLocals.push_back(std::make_tuple(ComboAddress(addr, 443), ctx, reusePort, tcpFastOpenQueueSize, interface, cpus));
+
+ /* UDP */
+ auto cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus));
+ cs->dnscryptCtx = ctx;
+ g_dnsCryptLocals.push_back(ctx);
+ g_frontends.push_back(std::move(cs));
+
+ /* TCP */
+ cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+ cs->dnscryptCtx = ctx;
+ g_frontends.push_back(std::move(cs));
}
catch(std::exception& e) {
errlog(e.what());
ret << (fmt % "#" % "Address" % "Provider Name") << endl;
size_t idx = 0;
- for (const auto& local : g_dnsCryptLocals) {
- const std::shared_ptr<DNSCryptContext> ctx = std::get<1>(local);
- ret<< (fmt % idx % std::get<0>(local).toStringWithPort() % ctx->getProviderName()) << endl;
+ for (const auto& frontend : g_frontends) {
+ const std::shared_ptr<DNSCryptContext> ctx = frontend->dnscryptCtx;
+ ret<< (fmt % idx % frontend->local.toStringWithPort() % ctx->getProviderName()) << endl;
idx++;
}
#ifdef HAVE_DNSCRYPT
std::shared_ptr<DNSCryptContext> ret = nullptr;
if (idx < g_dnsCryptLocals.size()) {
- ret = std::get<1>(g_dnsCryptLocals.at(idx));
+ ret = g_dnsCryptLocals.at(idx);
}
return ret;
#else
setLuaNoSideEffect();
ClientState* ret = nullptr;
if(num < g_frontends.size()) {
- ret=g_frontends[num];
+ ret=g_frontends[num].get();
}
return ret;
});
g_servFailOnNoPolicy = servfail;
});
+ g_lua.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) {
+ setLuaSideEffect();
+ g_roundrobinFailOnNoServer = fail;
+ });
+
g_lua.writeFunction("setRingBuffersSize", [](size_t capacity, boost::optional<size_t> numberOfShards) {
setLuaSideEffect();
if (g_configurationDone) {
setSyslogFacility(facility);
});
+ g_lua.writeFunction("addDOHLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<boost::variant<std::string, vector<pair<int, std::string> > > > urls, boost::optional<localbind_t> vars) {
+#ifdef HAVE_DNS_OVER_HTTPS
+ if (client) {
+ return;
+ }
+ setLuaSideEffect();
+ if (g_configurationDone) {
+ g_outputBuffer="addDOHLocal cannot be used at runtime!\n";
+ return;
+ }
+ auto frontend = std::make_shared<DOHFrontend>();
+
+ if (!loadTLSCertificateAndKeys("addDOHLocal", frontend->d_certKeyPairs, certFiles, keyFiles)) {
+ return;
+ }
+
+ frontend->d_local = ComboAddress(addr, 443);
+ if (urls) {
+ if (urls->type() == typeid(std::string)) {
+ frontend->d_urls.push_back(boost::get<std::string>(*urls));
+ }
+ else if (urls->type() == typeid(std::vector<std::pair<int,std::string>>)) {
+ auto urlsVect = boost::get<std::vector<std::pair<int,std::string>>>(*urls);
+ for(const auto& p : urlsVect) {
+ frontend->d_urls.push_back(p.second);
+ }
+ }
+ }
+ else {
+ frontend->d_urls = {"/"};
+ }
+
+ bool reusePort = false;
+ int tcpFastOpenQueueSize = 0;
+ std::string interface;
+ std::set<int> cpus;
+
+ if(vars) {
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
+
+ if (vars->count("idleTimeout")) {
+ frontend->d_idleTimeout = boost::get<int>((*vars)["idleTimeout"]);
+ }
+ if (vars->count("ciphers")) {
+ frontend->d_ciphers = boost::get<const string>((*vars)["ciphers"]);
+ }
+ if (vars->count("ciphersTLS13")) {
+ frontend->d_ciphers13 = boost::get<const string>((*vars)["ciphersTLS13"]);
+ }
+ if (vars->count("serverTokens")) {
+ frontend->d_serverTokens = boost::get<const string>((*vars)["serverTokens"]);
+ }
+ }
+ g_dohlocals.push_back(frontend);
+ auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_local, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+ cs->dohFrontend = frontend;
+ g_frontends.push_back(std::move(cs));
+#else
+ throw std::runtime_error("addDOHLocal() called but DNS over HTTPS support is not present!");
+#endif
+ });
+
+ g_lua.writeFunction("showDOHFrontends", []() {
+#ifdef HAVE_DNS_OVER_HTTPS
+ setLuaNoSideEffect();
+ try {
+ ostringstream ret;
+ boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d");
+ ret << (fmt % "#" % "Address" % "HTTP" % "HTTP/1" % "HTTP/2" % "TLS 1.0" % "TLS 1.1" % "TLS 1.2" % "TLS 1.3" % "TLS other" % "GET" % "POST" % "Bad" % "Errors" % "Valid") << endl;
+ size_t counter = 0;
+ for (const auto& ctx : g_dohlocals) {
+ ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1queries % ctx->d_http2queries % ctx->d_tls10queries % ctx->d_tls11queries % ctx->d_tls12queries % ctx->d_tls13queries % ctx->d_tlsUnknownqueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_validresponses) << endl;
+ counter++;
+ }
+ g_outputBuffer = ret.str();
+ }
+ catch(const std::exception& e) {
+ g_outputBuffer = e.what();
+ throw;
+ }
+#else
+ g_outputBuffer="DNS over HTTPS support is not present!\n";
+#endif
+ });
+
+ g_lua.writeFunction("getDOHFrontend", [](size_t index) {
+ std::shared_ptr<DOHFrontend> result = nullptr;
+#ifdef HAVE_DNS_OVER_HTTPS
+ setLuaNoSideEffect();
+ try {
+ if (index < g_dohlocals.size()) {
+ result = g_dohlocals.at(index);
+ }
+ else {
+ errlog("Error: trying to get DOH frontend with index %zu but we only have %zu frontend(s)\n", index, g_dohlocals.size());
+ g_outputBuffer="Error: trying to get DOH frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_dohlocals.size()) + " frontend(s)\n";
+ }
+ }
+ catch(const std::exception& e) {
+ g_outputBuffer="Error while trying to get DOH frontend with index " + std::to_string(index) + ": "+string(e.what())+"\n";
+ errlog("Error while trying to get DOH frontend with index %zu: %s\n", index, string(e.what()));
+ }
+#else
+ g_outputBuffer="DNS over HTTPS support is not present!\n";
+#endif
+ return result;
+ });
+
+ g_lua.registerFunction<void(std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<DOHFrontend> frontend) {
+ if (frontend != nullptr) {
+ frontend->reloadCertificates();
+ }
+ });
+
g_lua.writeFunction("addTLSLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<localbind_t> vars) {
+#ifdef HAVE_DNS_OVER_TLS
if (client)
return;
-#ifdef HAVE_DNS_OVER_TLS
setLuaSideEffect();
if (g_configurationDone) {
g_outputBuffer="addTLSLocal cannot be used at runtime!\n";
}
shared_ptr<TLSFrontend> frontend = std::make_shared<TLSFrontend>();
- if (!loadTLSCertificateAndKeys(frontend, certFiles, keyFiles)) {
+ if (!loadTLSCertificateAndKeys("addTLSLocal", frontend->d_certKeyPairs, certFiles, keyFiles)) {
return;
}
+ bool reusePort = false;
+ int tcpFastOpenQueueSize = 0;
+ std::string interface;
+ std::set<int> cpus;
+
if (vars) {
- bool doTCP = true;
- parseLocalBindVars(vars, doTCP, frontend->d_reusePort, frontend->d_tcpFastOpenQueueSize, frontend->d_interface, frontend->d_cpus);
+ parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
if (vars->count("provider")) {
frontend->d_provider = boost::get<const string>((*vars)["provider"]);
frontend->d_ciphers = boost::get<const string>((*vars)["ciphers"]);
}
+ if (vars->count("ciphersTLS13")) {
+ frontend->d_ciphers13 = boost::get<const string>((*vars)["ciphersTLS13"]);
+ }
+
if (vars->count("ticketKeyFile")) {
frontend->d_ticketKeyFile = boost::get<const string>((*vars)["ticketKeyFile"]);
}
try {
frontend->d_addr = ComboAddress(addr, 853);
vinfolog("Loading TLS provider %s", frontend->d_provider);
- g_tlslocals.push_back(frontend); /// only works pre-startup, so no sync necessary
+ // only works pre-startup, so no sync necessary
+ auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+ cs->tlsFrontend = frontend;
+ g_tlslocals.push_back(cs->tlsFrontend);
+ g_frontends.push_back(std::move(cs));
}
catch(const std::exception& e) {
g_outputBuffer="Error: "+string(e.what())+"\n";
}
#else
- g_outputBuffer="DNS over TLS support is not present!\n";
+ throw std::runtime_error("addTLSLocal() called but DNS over TLS support is not present!");
#endif
});
result = g_tlslocals.at(index)->getContext();
}
else {
- errlog("Error: trying to get TLS context with index %zu but we only have %zu\n", index, g_tlslocals.size());
- g_outputBuffer="Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + "\n";
+ errlog("Error: trying to get TLS context with index %zu but we only have %zu context(s)\n", index, g_tlslocals.size());
+ g_outputBuffer="Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " context(s)\n";
}
}
catch(const std::exception& e) {
- g_outputBuffer="Error: "+string(e.what())+"\n";
- errlog("Error: %s\n", string(e.what()));
+ g_outputBuffer="Error while trying to get TLS context with index " + std::to_string(index) + ": "+string(e.what())+"\n";
+ errlog("Error while trying to get TLS context with index %zu: %s\n", index, string(e.what()));
}
#else
g_outputBuffer="DNS over TLS support is not present!\n";
result = g_tlslocals.at(index);
}
else {
- errlog("Error: trying to get TLS frontend with index %zu but we only have %zu\n", index, g_tlslocals.size());
- g_outputBuffer="Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + "\n";
+ errlog("Error: trying to get TLS frontend with index %zu but we only have %zu frontends\n", index, g_tlslocals.size());
+ g_outputBuffer="Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " frontend(s)\n";
}
}
catch(const std::exception& e) {
- g_outputBuffer="Error: "+string(e.what())+"\n";
- errlog("Error: %s\n", string(e.what()));
+ g_outputBuffer="Error while trying to get TLS frontend with index " + std::to_string(index) + ": "+string(e.what())+"\n";
+ errlog("Error while trying to get TLS frontend with index %zu: %s\n", index, string(e.what()));
}
#else
g_outputBuffer="DNS over TLS support is not present!\n";
g_lua.registerFunction<void(std::shared_ptr<TLSFrontend>::*)(boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)>("loadNewCertificatesAndKeys", [](std::shared_ptr<TLSFrontend>& frontend, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles) {
#ifdef HAVE_DNS_OVER_TLS
- if (loadTLSCertificateAndKeys(frontend, certFiles, keyFiles)) {
+ if (loadTLSCertificateAndKeys("loadNewCertificatesAndKeys", frontend->d_certKeyPairs, certFiles, keyFiles)) {
frontend->setupTLS();
}
#endif
});
- g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
+ g_lua.writeFunction("reloadAllCertificates", []() {
+ for (auto& frontend : g_frontends) {
+ if (!frontend) {
+ continue;
+ }
+ try {
+#ifdef HAVE_DNSCRYPT
+ if (frontend->dnscryptCtx) {
+ frontend->dnscryptCtx->reloadCertificate();
+ }
+#endif /* HAVE_DNSCRYPT */
+#ifdef HAVE_DNS_OVER_TLS
+ if (frontend->tlsFrontend) {
+ frontend->tlsFrontend->setupTLS();
+ }
+#endif /* HAVE_DNS_OVER_TLS */
+#ifdef HAVE_DNS_OVER_HTTPS
+ if (frontend->dohFrontend) {
+ frontend->dohFrontend->reloadCertificates();
+ }
+#endif /* HAVE_DNS_OVER_HTTPS */
+ }
+ catch(const std::exception& e) {
+ errlog("Error reloading certificates for frontend %s: %s", frontend->local.toStringWithPort(), e.what());
+ }
+ }
+ });
+
+ g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
}
vector<std::function<void(void)>> setupLua(bool client, const std::string& config)