1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "secpoll-recursor.hh"
#include "syncres.hh"
#include "logger.hh"
#include "arguments.hh"
#include "version.hh"
#include "validate-recursor.hh"
#include "secpoll.hh"
#include <cstdint>
#ifndef PACKAGEVERSION
#define PACKAGEVERSION getPDNSVersion()
#endif
pdns::stat_t g_security_status;
void doSecPoll(time_t* last_secpoll, Logr::log_t log)
{
if (::arg()["security-poll-suffix"].empty()) {
return;
}
string pkgv(PACKAGEVERSION);
struct timeval now{};
Utility::gettimeofday(&now);
/* update last_secpoll right now, even if it fails
we don't want to retry right away and hammer the server */
*last_secpoll = now.tv_sec;
SyncRes resolver(now);
if (g_dnssecmode != DNSSECMode::Off) {
resolver.setDoDNSSEC(true);
resolver.setDNSSECValidationRequested(true);
}
resolver.setId("SecPoll");
vector<DNSRecord> ret;
string version = "recursor-" + pkgv;
string qstring(version.substr(0, 63) + ".security-status." + ::arg()["security-poll-suffix"]);
if (*qstring.rbegin() != '.') {
qstring += '.';
}
std::replace(qstring.begin(), qstring.end(), '+', '_');
std::replace(qstring.begin(), qstring.end(), '~', '_');
vState state = vState::Indeterminate;
DNSName query(qstring);
int res = resolver.beginResolve(query, QType(QType::TXT), 1, ret);
if (g_dnssecmode != DNSSECMode::Off && res != 0) {
state = resolver.getValidationState();
}
auto vlog = log->withValues("version", Logging::Loggable(pkgv), "query", Logging::Loggable(query));
if (vStateIsBogus(state)) {
SLOG(g_log << Logger::Error << "Failed to retrieve security status update for '" + pkgv + "' on '" << query << "', DNSSEC validation result was Bogus!" << endl,
vlog->info(Logr::Error, "Failed to retrieve security status update", "validationResult", Logging::Loggable(vStateToString(state))));
if (g_security_status == 1) { // If we were OK, go to unknown
g_security_status = 0;
}
return;
}
if (res == RCode::NXDomain && !isReleaseVersion(pkgv)) {
SLOG(g_log << Logger::Warning << "Not validating response for security status update, this is a non-release version" << endl,
vlog->info(Logr::Warning, "Not validating response for security status update, this is a non-release version"));
return;
}
string security_message;
int security_status = static_cast<int>(g_security_status);
try {
processSecPoll(res, ret, security_status, security_message);
}
catch (const PDNSException& pe) {
g_security_status = security_status;
SLOG(g_log << Logger::Warning << "Failed to retrieve security status update for '" << pkgv << "' on '" << query << "': " << pe.reason << endl,
vlog->error(Logr::Warning, pe.reason, "Failed to retrieve security status update"));
return;
}
auto rlog = vlog->withValues("securitymessage", Logging::Loggable(security_message), "status", Logging::Loggable(security_status));
if (g_security_status != 1 && security_status == 1) {
SLOG(g_log << Logger::Warning << "Polled security status of version " << pkgv << ", no known issues reported: " << security_message << endl,
rlog->info(Logr::Notice, "Polled security status of version, no known issues reported"));
}
if (security_status == 2) {
SLOG(g_log << Logger::Error << "PowerDNS Security Update Recommended: " << security_message << endl,
rlog->info(Logr::Error, "PowerDNS Security Update Recommended"));
}
if (security_status == 3) {
SLOG(g_log << Logger::Error << "PowerDNS Security Update Mandatory: " << security_message << endl,
rlog->info(Logr::Error, "PowerDNS Security Update Mandatory"));
}
g_security_status = security_status;
}
|