From: Otto Moerbeek Date: Mon, 8 May 2023 07:51:19 +0000 (+0200) Subject: Split serviceMain() to reduce cognitive complexity X-Git-Tag: rec-4.9.0-beta1~19^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=63189aaf3421a79cb1507a49f12d36944be1b08f;p=thirdparty%2Fpdns.git Split serviceMain() to reduce cognitive complexity --- diff --git a/pdns/recursordist/rec-main.cc b/pdns/recursordist/rec-main.cc index b288a7cf47..dff35ea1a5 100644 --- a/pdns/recursordist/rec-main.cc +++ b/pdns/recursordist/rec-main.cc @@ -1362,27 +1362,8 @@ template ThreadTimes broadcastAccFunction(const std::function& f template ProxyMappingStats_t broadcastAccFunction(const std::function& fun); template RemoteLoggerStats_t broadcastAccFunction(const std::function& fun); -static int serviceMain(Logr::log_t log) +static int initNet(Logr::log_t log) { - g_log.setName(g_programname); - g_log.disableSyslog(::arg().mustDo("disable-syslog")); - g_log.setTimestamps(::arg().mustDo("log-timestamp")); - g_regressionTestMode = ::arg().mustDo("devonly-regression-test-mode"); - - if (!::arg()["logging-facility"].empty()) { - int val = logFacilityToLOG(::arg().asNum("logging-facility")); - if (val >= 0) { - g_log.setFacility(val); - } else { - SLOG(g_log << Logger::Error << "Unknown logging facility " << ::arg().asNum("logging-facility") << endl, - log->info(Logr::Error, "Unknown logging facility", "facility", Logging::Loggable(::arg().asNum("logging-facility")))); - } - } - - showProductVersion(); - - g_disthashseed = dns_random(0xffffffff); - checkLinuxIPv6Limits(log); try { pdns::parseQueryLocalAddress(::arg()["query-local-address"]); @@ -1418,8 +1399,11 @@ static int serviceMain(Logr::log_t log) log->info(Logr::Error, "No outgoing addresses configured! Can not continue")); return 99; } + return 0; +} - // keep this ABOVE loadRecursorLuaConfig! +static int initDNSSEC(Logr::log_t log) +{ if (::arg()["dnssec"] == "off") { g_dnssecmode = DNSSECMode::Off; } else if (::arg()["dnssec"] == "process-no-validate") { @@ -1445,25 +1429,11 @@ static int serviceMain(Logr::log_t log) g_dnssecLogBogus = ::arg().mustDo("dnssec-log-bogus"); g_maxNSEC3Iterations = ::arg().asNum("nsec3-max-iterations"); + return 0; +} - g_maxCacheEntries = ::arg().asNum("max-cache-entries"); - - luaConfigDelayedThreads delayedLuaThreads; - try { - ProxyMapping proxyMapping; - loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads, proxyMapping); - // Initial proxy mapping - g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique(proxyMapping); - } - catch (PDNSException& e) { - SLOG(g_log << Logger::Error << "Cannot load Lua configuration: " << e.reason << endl, - log->error(Logr::Error, e.reason, "Cannot load Lua configuration")); - return 1; - } - - parseACLs(); - initPublicSuffixList(::arg()["public-suffix-list-file"]); - +static void initDontQuery(Logr::log_t log) +{ if (!::arg()["dont-query"].empty()) { vector ips; stringtok(ips, ::arg()["dont-query"], ", "); @@ -1487,30 +1457,10 @@ static int serviceMain(Logr::log_t log) log->info(Logr::Notice, "Will not send queries to", "addresses", Logging::IterLoggable(ips.begin(), ips.end())); } } +} - /* this needs to be done before parseACLs(), which call broadcastFunction() */ - RecThreadInfo::setWeDistributeQueries(::arg().mustDo("pdns-distributes-queries")); - if (RecThreadInfo::weDistributeQueries()) { - SLOG(g_log << Logger::Warning << "PowerDNS Recursor itself will distribute queries over threads" << endl, - log->info(Logr::Notice, "PowerDNS Recursor itself will distribute queries over threads")); - } - - g_outgoingEDNSBufsize = ::arg().asNum("edns-outgoing-bufsize"); - - if (::arg()["trace"] == "fail") { - SyncRes::setDefaultLogMode(SyncRes::Store); - } - else if (::arg().mustDo("trace")) { - SyncRes::setDefaultLogMode(SyncRes::Log); - ::arg().set("quiet") = "no"; - g_quiet = false; - } - auto myHostname = getHostname(); - if (!myHostname.has_value()) { - SLOG(g_log << Logger::Warning << "Unable to get the hostname, NSID and id.server values will be empty" << endl, - log->info(Logr::Warning, "Unable to get the hostname, NSID and id.server values will be empty")); - } - +static int initSyncRes(Logr::log_t log, const std::optional& myHostname) +{ SyncRes::s_minimumTTL = ::arg().asNum("minimum-ttl-override"); SyncRes::s_minimumECSTTL = ::arg().asNum("ecs-minimum-ttl-override"); SyncRes::s_maxnegttl = ::arg().asNum("max-negative-ttl"); @@ -1624,160 +1574,11 @@ static int serviceMain(Logr::log_t log) SyncRes::parseEDNSSubnetAllowlist(::arg()["edns-subnet-allow-list"]); SyncRes::parseEDNSSubnetAddFor(::arg()["ecs-add-for"]); g_useIncomingECS = ::arg().mustDo("use-incoming-edns-subnet"); + return 0; +} - g_proxyProtocolACL.toMasks(::arg()["proxy-protocol-from"]); - g_proxyProtocolMaximumSize = ::arg().asNum("proxy-protocol-maximum-size"); - - if (!::arg()["dns64-prefix"].empty()) { - try { - auto dns64Prefix = Netmask(::arg()["dns64-prefix"]); - if (dns64Prefix.getBits() != 96) { - SLOG(g_log << Logger::Error << "Invalid prefix for 'dns64-prefix', the current implementation only supports /96 prefixes: " << ::arg()["dns64-prefix"] << endl, - log->info(Logr::Error, "Invalid prefix for 'dns64-prefix', the current implementation only supports /96 prefixes", "prefix", Logging::Loggable(::arg()["dns64-prefix"]))); - return 1; - } - g_dns64Prefix = dns64Prefix.getNetwork(); - g_dns64PrefixReverse = reverseNameFromIP(*g_dns64Prefix); - /* /96 is 24 nibbles + 2 for "ip6.arpa." */ - while (g_dns64PrefixReverse.countLabels() > 26) { - g_dns64PrefixReverse.chopOff(); - } - } - catch (const NetmaskException& ne) { - SLOG(g_log << Logger::Error << "Invalid prefix '" << ::arg()["dns64-prefix"] << "' for 'dns64-prefix': " << ne.reason << endl, - log->info(Logr::Error, "Invalid prefix", "dns64-prefix", Logging::Loggable(::arg()["dns64-prefix"]))); - return 1; - } - } - - g_networkTimeoutMsec = ::arg().asNum("network-timeout"); - - std::tie(g_initialDomainMap, g_initialAllowNotifyFor) = parseZoneConfiguration(); - - g_latencyStatSize = ::arg().asNum("latency-statistic-size"); - - g_logCommonErrors = ::arg().mustDo("log-common-errors"); - g_logRPZChanges = ::arg().mustDo("log-rpz-changes"); - - g_anyToTcp = ::arg().mustDo("any-to-tcp"); - g_udpTruncationThreshold = ::arg().asNum("udp-truncation-threshold"); - - g_lowercaseOutgoing = ::arg().mustDo("lowercase-outgoing"); - - g_paddingFrom.toMasks(::arg()["edns-padding-from"]); - if (::arg()["edns-padding-mode"] == "always") { - g_paddingMode = PaddingMode::Always; - } - else if (::arg()["edns-padding-mode"] == "padded-queries-only") { - g_paddingMode = PaddingMode::PaddedQueries; - } - else { - SLOG(g_log << Logger::Error << "Unknown edns-padding-mode: " << ::arg()["edns-padding-mode"] << endl, - log->info(Logr::Error, "Unknown edns-padding-mode", "edns-padding-mode", Logging::Loggable(::arg()["edns-padding-mode"]))); - return 1; - } - g_paddingTag = ::arg().asNum("edns-padding-tag"); - g_paddingOutgoing = ::arg().mustDo("edns-padding-out"); - - RecThreadInfo::setNumDistributorThreads(::arg().asNum("distributor-threads")); - RecThreadInfo::setNumWorkerThreads(::arg().asNum("threads")); - if (RecThreadInfo::numWorkers() < 1) { - SLOG(g_log << Logger::Warning << "Asked to run with 0 threads, raising to 1 instead" << endl, - log->info(Logr::Warning, "Asked to run with 0 threads, raising to 1 instead")); - RecThreadInfo::setNumWorkerThreads(1); - } - - g_maxMThreads = ::arg().asNum("max-mthreads"); - - int64_t maxInFlight = ::arg().asNum("max-concurrent-requests-per-tcp-connection"); - if (maxInFlight < 1 || maxInFlight > USHRT_MAX || maxInFlight >= g_maxMThreads) { - SLOG(g_log << Logger::Warning << "Asked to run with illegal max-concurrent-requests-per-tcp-connection, setting to default (10)" << endl, - log->info(Logr::Warning, "Asked to run with illegal max-concurrent-requests-per-tcp-connection, setting to default (10)")); - TCPConnection::s_maxInFlight = 10; - } - else { - TCPConnection::s_maxInFlight = maxInFlight; - } - - int64_t millis = ::arg().asNum("tcp-out-max-idle-ms"); - TCPOutConnectionManager::s_maxIdleTime = timeval{millis / 1000, (static_cast(millis) % 1000) * 1000}; - TCPOutConnectionManager::s_maxIdlePerAuth = ::arg().asNum("tcp-out-max-idle-per-auth"); - TCPOutConnectionManager::s_maxQueries = ::arg().asNum("tcp-out-max-queries"); - TCPOutConnectionManager::s_maxIdlePerThread = ::arg().asNum("tcp-out-max-idle-per-thread"); - - g_gettagNeedsEDNSOptions = ::arg().mustDo("gettag-needs-edns-options"); - - s_statisticsInterval = ::arg().asNum("statistics-interval"); - - SyncRes::s_addExtendedResolutionDNSErrors = ::arg().mustDo("extended-resolution-errors"); - - if (::arg().asNum("aggressive-nsec-cache-size") > 0) { - if (g_dnssecmode == DNSSECMode::ValidateAll || g_dnssecmode == DNSSECMode::ValidateForLog || g_dnssecmode == DNSSECMode::Process) { - g_aggressiveNSECCache = make_unique(::arg().asNum("aggressive-nsec-cache-size")); - } - else { - SLOG(g_log << Logger::Warning << "Aggressive NSEC/NSEC3 caching is enabled but DNSSEC validation is not set to 'validate', 'log-fail' or 'process', ignoring" << endl, - log->info(Logr::Warning, "Aggressive NSEC/NSEC3 caching is enabled but DNSSEC validation is not set to 'validate', 'log-fail' or 'process', ignoring")); - } - } - - AggressiveNSECCache::s_maxNSEC3CommonPrefix = static_cast(std::round(std::log2(::arg().asNum("aggressive-cache-min-nsec3-hit-ratio")))); - SLOG(g_log << Logger::Debug << "NSEC3 aggressive cache tuning: aggressive-cache-min-nsec3-hit-ratio: " << ::arg().asNum("aggressive-cache-min-nsec3-hit-ratio") << " max common prefix bits: " << std::to_string(AggressiveNSECCache::s_maxNSEC3CommonPrefix) << endl, - log->info(Logr::Debug, "NSEC3 aggressive cache tuning", "aggressive-cache-min-nsec3-hit-ratio", Logging::Loggable(::arg().asNum("aggressive-cache-min-nsec3-hit-ratio")), "maxCommonPrefixBits", Logging::Loggable(AggressiveNSECCache::s_maxNSEC3CommonPrefix))); - - { - SuffixMatchNode dontThrottleNames; - vector parts; - stringtok(parts, ::arg()["dont-throttle-names"], " ,"); - for (const auto& part : parts) { - dontThrottleNames.add(DNSName(part)); - } - g_dontThrottleNames.setState(std::move(dontThrottleNames)); - - parts.clear(); - NetmaskGroup dontThrottleNetmasks; - stringtok(parts, ::arg()["dont-throttle-netmasks"], " ,"); - for (const auto& part : parts) { - dontThrottleNetmasks.addMask(Netmask(part)); - } - g_dontThrottleNetmasks.setState(std::move(dontThrottleNetmasks)); - } - - { - SuffixMatchNode xdnssecNames; - vector parts; - stringtok(parts, ::arg()["x-dnssec-names"], " ,"); - for (const auto& part : parts) { - xdnssecNames.add(DNSName(part)); - } - g_xdnssec.setState(std::move(xdnssecNames)); - } - - { - SuffixMatchNode dotauthNames; - vector parts; - stringtok(parts, ::arg()["dot-to-auth-names"], " ,"); -#ifndef HAVE_DNS_OVER_TLS - if (parts.size()) { - SLOG(g_log << Logger::Error << "dot-to-auth-names setting contains names, but Recursor was built without DNS over TLS support. Setting will be ignored." << endl, - log->info(Logr::Error, "dot-to-auth-names setting contains names, but Recursor was built without DNS over TLS support. Setting will be ignored")); - } -#endif - for (const auto& part : parts) { - dotauthNames.add(DNSName(part)); - } - g_DoTToAuthNames.setState(std::move(dotauthNames)); - } - - { - CarbonConfig config; - stringtok(config.servers, arg()["carbon-server"], ", "); - config.hostname = arg()["carbon-ourname"]; - config.instance_name = arg()["carbon-instance"]; - config.namespace_name = arg()["carbon-namespace"]; - g_carbonConfig.setState(std::move(config)); - } - +static void initDistribution(Logr::log_t log) +{ g_balancingFactor = ::arg().asDouble("distribution-load-factor"); if (g_balancingFactor != 0.0 && g_balancingFactor < 1.0) { g_balancingFactor = 0.0; @@ -1835,16 +1636,15 @@ static int serviceMain(Logr::log_t log) } } } +} -#ifdef NOD_ENABLED - // Setup newly observed domain globals - setupNODGlobal(); -#endif /* NOD_ENABLED */ - +static int initForks(Logr::log_t log) +{ int forks = 0; for (; forks < ::arg().asNum("processes") - 1; ++forks) { - if (fork() == 0) // we are child + if (fork() == 0) { // we are child break; + } } if (::arg().mustDo("daemon")) { @@ -1853,6 +1653,7 @@ static int serviceMain(Logr::log_t log) g_log.toConsole(Logger::Critical); daemonize(log); } + if (Utility::getpid() == 1) { /* We are running as pid 1, register sigterm and sigint handler @@ -1874,37 +1675,59 @@ static int serviceMain(Logr::log_t log) signal(SIGUSR1, usr1Handler); signal(SIGUSR2, usr2Handler); signal(SIGPIPE, SIG_IGN); // NOLINT: Posix API + return forks; +} - checkOrFixFDS(log); - -#ifdef HAVE_LIBSODIUM - if (sodium_init() == -1) { - SLOG(g_log << Logger::Error << "Unable to initialize sodium crypto library" << endl, - log->info(Logr::Error, "Unable to initialize sodium crypto library")); - return 99; +static int initPorts(Logr::log_t log) +{ + int port = ::arg().asNum("udp-source-port-min"); + if (port < 1024 || port > 65535) { + SLOG(g_log << Logger::Error << "Unable to launch, udp-source-port-min is not a valid port number" << endl, + log->info(Logr::Error, "Unable to launch, udp-source-port-min is not a valid port number")); + return 99; // this isn't going to fix itself either } -#endif - - openssl_thread_setup(); - openssl_seed(); - /* setup rng before chroot */ - dns_random_init(); - - if (::arg()["server-id"].empty()) { - ::arg().set("server-id") = myHostname.has_value() ? *myHostname : ""; + g_minUdpSourcePort = port; + port = ::arg().asNum("udp-source-port-max"); + if (port < 1024 || port > 65535 || port < g_minUdpSourcePort) { + SLOG(g_log << Logger::Error << "Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min" << endl, + log->info(Logr::Error, "Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min")); + return 99; // this isn't going to fix itself either } - - gid_t newgid = 0; - if (!::arg()["setgid"].empty()) { - newgid = strToGID(::arg()["setgid"]); - } - uid_t newuid = 0; - if (!::arg()["setuid"].empty()) { - newuid = strToUID(::arg()["setuid"]); + g_maxUdpSourcePort = port; + std::vector parts{}; + stringtok(parts, ::arg()["udp-source-port-avoid"], ", "); + for (const auto& part : parts) { + port = std::stoi(part); + if (port < 1024 || port > 65535) { + SLOG(g_log << Logger::Error << "Unable to launch, udp-source-port-avoid contains an invalid port number: " << part << endl, + log->info(Logr::Error, "Unable to launch, udp-source-port-avoid contains an invalid port number", "port", Logging::Loggable(part))); + return 99; // this isn't going to fix itself either + } + g_avoidUdpSourcePorts.insert(port); } + return 0; +} - Utility::dropGroupPrivs(newuid, newgid); +static void initSNMP([[maybe_unused]] Logr::log_t log) +{ + if (::arg().mustDo("snmp-agent")) { +#ifdef HAVE_NET_SNMP + string setting = ::arg()["snmp-daemon-socket"]; + if (setting.empty()) { + setting = ::arg()["snmp-master-socket"]; + } + g_snmpAgent = std::make_shared("recursor", setting); + g_snmpAgent->run(); +#else + const std::string msg = "snmp-agent set but SNMP support not compiled in"; + SLOG(g_log << Logger::Error << msg << endl, + log->info(Logr::Error, msg)); +#endif // HAVE_NET_SNMP + } +} +static int initControl(Logr::log_t log, uid_t newuid, int forks) // NOLINT(bugprone-easily-swappable-parameter*) +{ if (!::arg()["chroot"].empty()) { #ifdef HAVE_SYSTEMD char* ns; @@ -1947,6 +1770,297 @@ static int serviceMain(Logr::log_t log) SLOG(g_log << Logger::Warning << e.what() << endl, log->error(Logr::Warning, e.what(), "Could not drop capabilities")); } + return 0; +} + +static void initSuffixMatchNodes() +{ + { + SuffixMatchNode dontThrottleNames; + vector parts; + stringtok(parts, ::arg()["dont-throttle-names"], " ,"); + for (const auto& part : parts) { + dontThrottleNames.add(DNSName(part)); + } + g_dontThrottleNames.setState(std::move(dontThrottleNames)); + + parts.clear(); + NetmaskGroup dontThrottleNetmasks; + stringtok(parts, ::arg()["dont-throttle-netmasks"], " ,"); + for (const auto& part : parts) { + dontThrottleNetmasks.addMask(Netmask(part)); + } + g_dontThrottleNetmasks.setState(std::move(dontThrottleNetmasks)); + } + + { + SuffixMatchNode xdnssecNames; + vector parts; + stringtok(parts, ::arg()["x-dnssec-names"], " ,"); + for (const auto& part : parts) { + xdnssecNames.add(DNSName(part)); + } + g_xdnssec.setState(std::move(xdnssecNames)); + } + + { + SuffixMatchNode dotauthNames; + vector parts; + stringtok(parts, ::arg()["dot-to-auth-names"], " ,"); +#ifndef HAVE_DNS_OVER_TLS + if (parts.size()) { + SLOG(g_log << Logger::Error << "dot-to-auth-names setting contains names, but Recursor was built without DNS over TLS support. Setting will be ignored." << endl, + log->info(Logr::Error, "dot-to-auth-names setting contains names, but Recursor was built without DNS over TLS support. Setting will be ignored")); + } +#endif + for (const auto& part : parts) { + dotauthNames.add(DNSName(part)); + } + g_DoTToAuthNames.setState(std::move(dotauthNames)); + } +} + +static void initCarbon() +{ + CarbonConfig config; + stringtok(config.servers, arg()["carbon-server"], ", "); + config.hostname = arg()["carbon-ourname"]; + config.instance_name = arg()["carbon-instance"]; + config.namespace_name = arg()["carbon-namespace"]; + g_carbonConfig.setState(std::move(config)); +} + +static int initDNS64(Logr::log_t log) +{ + if (!::arg()["dns64-prefix"].empty()) { + try { + auto dns64Prefix = Netmask(::arg()["dns64-prefix"]); + if (dns64Prefix.getBits() != 96) { + SLOG(g_log << Logger::Error << "Invalid prefix for 'dns64-prefix', the current implementation only supports /96 prefixes: " << ::arg()["dns64-prefix"] << endl, + log->info(Logr::Error, "Invalid prefix for 'dns64-prefix', the current implementation only supports /96 prefixes", "prefix", Logging::Loggable(::arg()["dns64-prefix"]))); + return 1; + } + g_dns64Prefix = dns64Prefix.getNetwork(); + g_dns64PrefixReverse = reverseNameFromIP(*g_dns64Prefix); + /* /96 is 24 nibbles + 2 for "ip6.arpa." */ + while (g_dns64PrefixReverse.countLabels() > 26) { + g_dns64PrefixReverse.chopOff(); + } + } + catch (const NetmaskException& ne) { + SLOG(g_log << Logger::Error << "Invalid prefix '" << ::arg()["dns64-prefix"] << "' for 'dns64-prefix': " << ne.reason << endl, + log->info(Logr::Error, "Invalid prefix", "dns64-prefix", Logging::Loggable(::arg()["dns64-prefix"]))); + return 1; + } + } + return 0; +} + +static int serviceMain(Logr::log_t log) +{ + g_log.setName(g_programname); + g_log.disableSyslog(::arg().mustDo("disable-syslog")); + g_log.setTimestamps(::arg().mustDo("log-timestamp")); + g_regressionTestMode = ::arg().mustDo("devonly-regression-test-mode"); + + if (!::arg()["logging-facility"].empty()) { + int val = logFacilityToLOG(::arg().asNum("logging-facility")); + if (val >= 0) { + g_log.setFacility(val); + } else { + SLOG(g_log << Logger::Error << "Unknown logging facility " << ::arg().asNum("logging-facility") << endl, + log->info(Logr::Error, "Unknown logging facility", "facility", Logging::Loggable(::arg().asNum("logging-facility")))); + } + } + + showProductVersion(); + + g_disthashseed = dns_random(0xffffffff); + + int ret = initNet(log); + if (ret != 0) { + return ret; + } + // keep this ABOVE loadRecursorLuaConfig! + ret = initDNSSEC(log); + if (ret != 0) { + return ret; + } + g_maxCacheEntries = ::arg().asNum("max-cache-entries"); + + luaConfigDelayedThreads delayedLuaThreads; + try { + ProxyMapping proxyMapping; + loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads, proxyMapping); + // Initial proxy mapping + g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique(proxyMapping); + } + catch (PDNSException& e) { + SLOG(g_log << Logger::Error << "Cannot load Lua configuration: " << e.reason << endl, + log->error(Logr::Error, e.reason, "Cannot load Lua configuration")); + return 1; + } + + parseACLs(); + initPublicSuffixList(::arg()["public-suffix-list-file"]); + + initDontQuery(log); + + /* this needs to be done before parseACLs(), which call broadcastFunction() */ + RecThreadInfo::setWeDistributeQueries(::arg().mustDo("pdns-distributes-queries")); + if (RecThreadInfo::weDistributeQueries()) { + SLOG(g_log << Logger::Warning << "PowerDNS Recursor itself will distribute queries over threads" << endl, + log->info(Logr::Notice, "PowerDNS Recursor itself will distribute queries over threads")); + } + + g_outgoingEDNSBufsize = ::arg().asNum("edns-outgoing-bufsize"); + + if (::arg()["trace"] == "fail") { + SyncRes::setDefaultLogMode(SyncRes::Store); + } + else if (::arg().mustDo("trace")) { + SyncRes::setDefaultLogMode(SyncRes::Log); + ::arg().set("quiet") = "no"; + g_quiet = false; + } + auto myHostname = getHostname(); + if (!myHostname.has_value()) { + SLOG(g_log << Logger::Warning << "Unable to get the hostname, NSID and id.server values will be empty" << endl, + log->info(Logr::Warning, "Unable to get the hostname, NSID and id.server values will be empty")); + } + + ret = initSyncRes(log, myHostname); + if (ret != 0) { + return ret; + } + + g_proxyProtocolACL.toMasks(::arg()["proxy-protocol-from"]); + g_proxyProtocolMaximumSize = ::arg().asNum("proxy-protocol-maximum-size"); + + ret = initDNS64(log); + if (ret != 0) { + return ret; + } + g_networkTimeoutMsec = ::arg().asNum("network-timeout"); + + std::tie(g_initialDomainMap, g_initialAllowNotifyFor) = parseZoneConfiguration(); + + g_latencyStatSize = ::arg().asNum("latency-statistic-size"); + + g_logCommonErrors = ::arg().mustDo("log-common-errors"); + g_logRPZChanges = ::arg().mustDo("log-rpz-changes"); + + g_anyToTcp = ::arg().mustDo("any-to-tcp"); + g_udpTruncationThreshold = ::arg().asNum("udp-truncation-threshold"); + + g_lowercaseOutgoing = ::arg().mustDo("lowercase-outgoing"); + + g_paddingFrom.toMasks(::arg()["edns-padding-from"]); + if (::arg()["edns-padding-mode"] == "always") { + g_paddingMode = PaddingMode::Always; + } + else if (::arg()["edns-padding-mode"] == "padded-queries-only") { + g_paddingMode = PaddingMode::PaddedQueries; + } + else { + SLOG(g_log << Logger::Error << "Unknown edns-padding-mode: " << ::arg()["edns-padding-mode"] << endl, + log->info(Logr::Error, "Unknown edns-padding-mode", "edns-padding-mode", Logging::Loggable(::arg()["edns-padding-mode"]))); + return 1; + } + g_paddingTag = ::arg().asNum("edns-padding-tag"); + g_paddingOutgoing = ::arg().mustDo("edns-padding-out"); + + RecThreadInfo::setNumDistributorThreads(::arg().asNum("distributor-threads")); + RecThreadInfo::setNumWorkerThreads(::arg().asNum("threads")); + if (RecThreadInfo::numWorkers() < 1) { + SLOG(g_log << Logger::Warning << "Asked to run with 0 threads, raising to 1 instead" << endl, + log->info(Logr::Warning, "Asked to run with 0 threads, raising to 1 instead")); + RecThreadInfo::setNumWorkerThreads(1); + } + + g_maxMThreads = ::arg().asNum("max-mthreads"); + + int64_t maxInFlight = ::arg().asNum("max-concurrent-requests-per-tcp-connection"); + if (maxInFlight < 1 || maxInFlight > USHRT_MAX || maxInFlight >= g_maxMThreads) { + SLOG(g_log << Logger::Warning << "Asked to run with illegal max-concurrent-requests-per-tcp-connection, setting to default (10)" << endl, + log->info(Logr::Warning, "Asked to run with illegal max-concurrent-requests-per-tcp-connection, setting to default (10)")); + TCPConnection::s_maxInFlight = 10; + } + else { + TCPConnection::s_maxInFlight = maxInFlight; + } + + int64_t millis = ::arg().asNum("tcp-out-max-idle-ms"); + TCPOutConnectionManager::s_maxIdleTime = timeval{millis / 1000, (static_cast(millis) % 1000) * 1000}; + TCPOutConnectionManager::s_maxIdlePerAuth = ::arg().asNum("tcp-out-max-idle-per-auth"); + TCPOutConnectionManager::s_maxQueries = ::arg().asNum("tcp-out-max-queries"); + TCPOutConnectionManager::s_maxIdlePerThread = ::arg().asNum("tcp-out-max-idle-per-thread"); + + g_gettagNeedsEDNSOptions = ::arg().mustDo("gettag-needs-edns-options"); + + s_statisticsInterval = ::arg().asNum("statistics-interval"); + + SyncRes::s_addExtendedResolutionDNSErrors = ::arg().mustDo("extended-resolution-errors"); + + if (::arg().asNum("aggressive-nsec-cache-size") > 0) { + if (g_dnssecmode == DNSSECMode::ValidateAll || g_dnssecmode == DNSSECMode::ValidateForLog || g_dnssecmode == DNSSECMode::Process) { + g_aggressiveNSECCache = make_unique(::arg().asNum("aggressive-nsec-cache-size")); + } + else { + SLOG(g_log << Logger::Warning << "Aggressive NSEC/NSEC3 caching is enabled but DNSSEC validation is not set to 'validate', 'log-fail' or 'process', ignoring" << endl, + log->info(Logr::Warning, "Aggressive NSEC/NSEC3 caching is enabled but DNSSEC validation is not set to 'validate', 'log-fail' or 'process', ignoring")); + } + } + + AggressiveNSECCache::s_maxNSEC3CommonPrefix = static_cast(std::round(std::log2(::arg().asNum("aggressive-cache-min-nsec3-hit-ratio")))); + SLOG(g_log << Logger::Debug << "NSEC3 aggressive cache tuning: aggressive-cache-min-nsec3-hit-ratio: " << ::arg().asNum("aggressive-cache-min-nsec3-hit-ratio") << " max common prefix bits: " << std::to_string(AggressiveNSECCache::s_maxNSEC3CommonPrefix) << endl, + log->info(Logr::Debug, "NSEC3 aggressive cache tuning", "aggressive-cache-min-nsec3-hit-ratio", Logging::Loggable(::arg().asNum("aggressive-cache-min-nsec3-hit-ratio")), "maxCommonPrefixBits", Logging::Loggable(AggressiveNSECCache::s_maxNSEC3CommonPrefix))); + + initSuffixMatchNodes(); + initCarbon(); + initDistribution(log); + +#ifdef NOD_ENABLED + // Setup newly observed domain globals + setupNODGlobal(); +#endif /* NOD_ENABLED */ + + auto forks = initForks(log); + + checkOrFixFDS(log); + +#ifdef HAVE_LIBSODIUM + if (sodium_init() == -1) { + SLOG(g_log << Logger::Error << "Unable to initialize sodium crypto library" << endl, + log->info(Logr::Error, "Unable to initialize sodium crypto library")); + return 99; + } +#endif + + openssl_thread_setup(); + openssl_seed(); + /* setup rng before chroot */ + dns_random_init(); + + if (::arg()["server-id"].empty()) { + ::arg().set("server-id") = myHostname.has_value() ? *myHostname : ""; + } + + gid_t newgid = 0; + if (!::arg()["setgid"].empty()) { + newgid = strToGID(::arg()["setgid"]); + } + uid_t newuid = 0; + if (!::arg()["setuid"].empty()) { + newuid = strToUID(::arg()["setuid"]); + } + + Utility::dropGroupPrivs(newuid, newgid); + + ret = initControl(log, newuid, forks); + if (ret != 0) { + return ret; + } startLuaConfigDelayedThreads(delayedLuaThreads, g_luaconfs.getCopy().generation); delayedLuaThreads.rpzPrimaryThreads.clear(); // no longer needed @@ -1973,45 +2087,11 @@ static int serviceMain(Logr::log_t log) // Run before any thread doing stats related things registerAllStats(); - if (::arg().mustDo("snmp-agent")) { -#ifdef HAVE_NET_SNMP - string setting = ::arg()["snmp-daemon-socket"]; - if (setting.empty()) { - setting = ::arg()["snmp-master-socket"]; - } - g_snmpAgent = std::make_shared("recursor", setting); - g_snmpAgent->run(); -#else - const std::string msg = "snmp-agent set but SNMP support not compiled in"; - SLOG(g_log << Logger::Error << msg << endl, - log->info(Logr::Error, msg)); -#endif // HAVE_NET_SNMP - } + initSNMP(log); - int port = ::arg().asNum("udp-source-port-min"); - if (port < 1024 || port > 65535) { - SLOG(g_log << Logger::Error << "Unable to launch, udp-source-port-min is not a valid port number" << endl, - log->info(Logr::Error, "Unable to launch, udp-source-port-min is not a valid port number")); - return 99; // this isn't going to fix itself either - } - g_minUdpSourcePort = port; - port = ::arg().asNum("udp-source-port-max"); - if (port < 1024 || port > 65535 || port < g_minUdpSourcePort) { - SLOG(g_log << Logger::Error << "Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min" << endl, - log->info(Logr::Error, "Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min")); - return 99; // this isn't going to fix itself either - } - g_maxUdpSourcePort = port; - std::vector parts{}; - stringtok(parts, ::arg()["udp-source-port-avoid"], ", "); - for (const auto& part : parts) { - port = std::stoi(part); - if (port < 1024 || port > 65535) { - SLOG(g_log << Logger::Error << "Unable to launch, udp-source-port-avoid contains an invalid port number: " << part << endl, - log->info(Logr::Error, "Unable to launch, udp-source-port-avoid contains an invalid port number", "port", Logging::Loggable(part))); - return 99; // this isn't going to fix itself either - } - g_avoidUdpSourcePorts.insert(port); + ret = initPorts(log); + if (ret != 0) { + return ret; } return RecThreadInfo::runThreads(log);