if (time(nullptr) - d_lastcheck < d_checkinterval)
return true;
- if (d_filename.empty())
- return true;
-
- return (getCtime() == d_ctime);
+ d_lastcheck = time(nullptr);
+ for (const auto& fileinfo : d_fileinfo) {
+ if (getCtime(fileinfo.first) != fileinfo.second) {
+ return false;
+ }
+ }
+ return true;
}
-time_t BB2DomainInfo::getCtime()
+time_t BB2DomainInfo::getCtime(const std::string& filename)
{
struct stat buf;
- if (d_filename.empty() || stat(d_filename.c_str(), &buf) < 0)
+ if (filename.empty() || stat(filename.c_str(), &buf) < 0)
return 0;
- d_lastcheck = time(nullptr);
return buf.st_ctime;
}
-void BB2DomainInfo::setCtime()
+void BB2DomainInfo::updateCtime()
{
struct stat buf;
- if (stat(d_filename.c_str(), &buf) < 0)
- return;
- d_ctime = buf.st_ctime;
+
+ for (auto& fileinfo : d_fileinfo) {
+ if (stat(fileinfo.first.c_str(), &buf) < 0) {
+ buf.st_ctime = 0;
+ }
+ fileinfo.second = buf.st_ctime;
+ }
}
// NOLINTNEXTLINE(readability-identifier-length)
d_transaction_qname = qname;
BB2DomainInfo bbd;
if (safeGetBBDomainInfo(domainId, &bbd)) {
- d_transaction_tmpname = bbd.d_filename + "XXXXXX";
+ d_transaction_tmpname = bbd.d_fileinfo.front().first + "XXXXXX";
int fd = mkstemp(&d_transaction_tmpname.at(0));
if (fd == -1) {
throw DBException("Unable to create a unique temporary zonefile '" + d_transaction_tmpname + "': " + stringerror());
BB2DomainInfo bbd;
if (safeGetBBDomainInfo(d_transaction_id, &bbd)) {
- if (rename(d_transaction_tmpname.c_str(), bbd.d_filename.c_str()) < 0)
- throw DBException("Unable to commit (rename to: '" + bbd.d_filename + "') AXFRed zone: " + stringerror());
+ if (rename(d_transaction_tmpname.c_str(), bbd.d_fileinfo.front().first.c_str()) < 0)
+ throw DBException("Unable to commit (rename to: '" + bbd.d_fileinfo.front().first + "') AXFRed zone: " + stringerror());
queueReloadAndStore(bbd.d_id);
}
nsec3zone = getNSEC3PARAMuncached(bbd->d_name, &ns3pr);
auto records = std::make_shared<recordstorage_t>();
- ZoneParserTNG zpt(bbd->d_filename, bbd->d_name, s_binddirectory, d_upgradeContent);
+ ZoneParserTNG zpt(bbd->d_fileinfo.front().first, bbd->d_name, s_binddirectory, d_upgradeContent);
zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
zpt.setMaxIncludes(::arg().asNum("max-include-depth"));
DNSResourceRecord rr;
}
fixupOrderAndAuth(records, bbd->d_name, nsec3zone, ns3pr);
doEmptyNonTerminals(records, bbd->d_name, nsec3zone, ns3pr);
- bbd->setCtime();
+ bbd->d_fileinfo = zpt.getFileset();
bbd->d_loaded = true;
bbd->d_checknow = false;
bbd->d_status = "parsed into memory at " + nowTime();
ret << info.d_name << ": " << std::endl;
ret << "\t Status: " << info.d_status << std::endl;
ret << "\t Internal ID: " << info.d_id << std::endl;
- ret << "\t On-disk file: " << info.d_filename << " (" << info.d_ctime << ")" << std::endl;
+ ret << "\t On-disk file: " << info.d_fileinfo.front().first << " (" << info.d_fileinfo.front().second << ")" << std::endl;
ret << "\t Kind: ";
switch (info.d_kind) {
case DomainInfo::Primary:
return "Unable to load zone " + domainname.toLogString() + " from " + filename + ": " + strerror(errno);
Bind2Backend bb2; // createdomainentry needs access to our configuration
- bbd = bb2.createDomainEntry(domainname, filename);
- bbd.d_filename = filename;
+ bbd = bb2.createDomainEntry(domainname);
+ bbd.d_fileinfo.emplace_back(std::make_pair(filename, buf.st_ctime));
bbd.d_checknow = true;
bbd.d_loaded = true;
bbd.d_lastcheck = 0;
bbd.d_status = "parsing into memory";
- bbd.setCtime();
safePutBBDomainInfo(bbd);
// overwrite what we knew about the domain
bbd.d_name = domain.name;
- bool filenameChanged = (bbd.d_filename != domain.filename);
+ bool filenameChanged = bbd.d_fileinfo.empty() || (bbd.d_fileinfo.front().first != domain.filename);
bool addressesChanged = (bbd.d_primaries != domain.primaries || bbd.d_also_notify != domain.alsoNotify);
- bbd.d_filename = domain.filename;
+ // Preserve existing fileinfo in case we won't reread anything.
+ if (filenameChanged) {
+ bbd.d_fileinfo.clear();
+ bbd.d_fileinfo.emplace_back(std::make_pair(domain.filename, 0));
+ }
bbd.d_primaries = domain.primaries;
bbd.d_also_notify = domain.alsoNotify;
parseZoneFile(&bbnew);
bbnew.d_wasRejectedLastReload = false;
safePutBBDomainInfo(bbnew);
- g_log << Logger::Warning << "Zone '" << bbnew.d_name << "' (" << bbnew.d_filename << ") reloaded" << endl;
+ g_log << Logger::Warning << "Zone '" << bbnew.d_name << "' (" << bbnew.d_fileinfo.front().first << ") reloaded" << endl;
}
catch (PDNSException& ae) {
ostringstream msg;
- msg << " error at " + nowTime() + " parsing '" << bbold.d_name << "' from file '" << bbold.d_filename << "': " << ae.reason;
- g_log << Logger::Warning << "Error parsing '" << bbold.d_name << "' from file '" << bbold.d_filename << "': " << ae.reason << endl;
+ msg << " error at " + nowTime() + " parsing '" << bbold.d_name << "' from file '" << bbold.d_fileinfo.front().first << "': " << ae.reason;
+ g_log << Logger::Warning << "Error parsing '" << bbold.d_name << "' from file '" << bbold.d_fileinfo.front().first << "': " << ae.reason << endl;
bbold.d_status = msg.str();
bbold.d_lastcheck = time(nullptr);
bbold.d_wasRejectedLastReload = true;
}
catch (std::exception& ae) {
ostringstream msg;
- msg << " error at " + nowTime() + " parsing '" << bbold.d_name << "' from file '" << bbold.d_filename << "': " << ae.what();
- g_log << Logger::Warning << "Error parsing '" << bbold.d_name << "' from file '" << bbold.d_filename << "': " << ae.what() << endl;
+ msg << " error at " + nowTime() + " parsing '" << bbold.d_name << "' from file '" << bbold.d_fileinfo.front().first << "': " << ae.what();
+ g_log << Logger::Warning << "Error parsing '" << bbold.d_name << "' from file '" << bbold.d_fileinfo.front().first << "': " << ae.what() << endl;
bbold.d_status = msg.str();
bbold.d_lastcheck = time(nullptr);
bbold.d_wasRejectedLastReload = true;
d_handle.domain = std::move(domain);
if (!bbd.current()) {
- g_log << Logger::Warning << "Zone '" << d_handle.domain << "' (" << bbd.d_filename << ") needs reloading" << endl;
+ g_log << Logger::Warning << "Zone '" << d_handle.domain << "' (" << bbd.d_fileinfo.front().first << ") needs reloading" << endl;
queueReloadAndStore(bbd.d_id);
if (!safeGetBBDomainInfo(d_handle.domain, &bbd))
- throw DBException("Zone '" + bbd.d_name.toLogString() + "' (" + bbd.d_filename + ") gone after reload"); // if we don't throw here, we crash for some reason
+ throw DBException("Zone '" + bbd.d_name.toLogString() + "' (" + bbd.d_fileinfo.front().first + ") gone after reload"); // if we don't throw here, we crash for some reason
}
if (!bbd.d_loaded) {
d_handle.reset();
- throw DBException("Zone for '" + d_handle.domain.toLogString() + "' in '" + bbd.d_filename + "' not loaded (file missing, corrupt or primary dead)"); // fsck
+ throw DBException("Zone for '" + d_handle.domain.toLogString() + "' in '" + bbd.d_fileinfo.front().first + "' not loaded (file missing, corrupt or primary dead)"); // fsck
}
d_handle.d_records = bbd.d_records.get();
return true;
}
-BB2DomainInfo Bind2Backend::createDomainEntry(const ZoneName& domain, const string& filename)
+BB2DomainInfo Bind2Backend::createDomainEntry(const ZoneName& domain)
{
domainid_t newid = 1;
{ // Find a free zone id nr.
bbd.d_records = std::make_shared<recordstorage_t>();
bbd.d_name = domain;
bbd.setCheckInterval(getArgAsNum("check-interval"));
- bbd.d_filename = filename;
return bbd;
}
c_of.close();
}
- BB2DomainInfo bbd = createDomainEntry(domain, filename);
+ BB2DomainInfo bbd = createDomainEntry(domain);
bbd.d_kind = DomainInfo::Secondary;
bbd.d_primaries.emplace_back(ComboAddress(ipAddress, 53));
- bbd.setCtime();
+ bbd.d_fileinfo.emplace_back(std::make_pair(filename, 0));
+ bbd.updateCtime();
safePutBBDomainInfo(bbd);
return true;
{
public:
BB2DomainInfo();
- void setCtime();
+ void updateCtime();
bool current();
//! configure how often this domain should be checked for changes (on disk)
void setCheckInterval(time_t seconds);
ZoneName d_name; //!< actual name of the domain
DomainInfo::DomainKind d_kind{DomainInfo::Native}; //!< the kind of domain
- string d_filename; //!< full absolute filename of the zone on disk
+ std::vector<std::pair<std::string, time_t>> d_fileinfo; //!< list of full absolute filename of the zone on disk, and any included file, with their last verified ctime
string d_status; //!< message describing status of a domain, for human consumption
vector<ComboAddress> d_primaries; //!< IP address of the primary of this domain
set<string> d_also_notify; //!< IP list of hosts to also notify
LookButDontTouch<recordstorage_t> d_records; //!< the actual records belonging to this domain
- time_t d_ctime{0}; //!< last known ctime of the file on disk
- time_t d_lastcheck{0}; //!< last time domain was checked for freshness
+ time_t d_lastcheck{0}; //!< last time files were checked for freshness
uint32_t d_lastnotified{0}; //!< Last serial number we notified our secondaries of
domainid_t d_id{0}; //!< internal id of the domain
mutable bool d_checknow; //!< if this domain has been flagged for a check
NSEC3PARAMRecordContent d_nsec3param;
private:
- time_t getCtime();
+ static time_t getCtime(const std::string&);
time_t d_checkinterval{0};
};
void getUnfreshSecondaryInfos(vector<DomainInfo>* unfreshDomains) override;
void getUpdatedPrimaries(vector<DomainInfo>& changedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
bool getDomainInfo(const ZoneName& domain, DomainInfo& info, bool getSerial = true) override;
- time_t getCtime(const string& fname);
// DNSSEC
bool getBeforeAndAfterNamesAbsolute(domainid_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) override;
void lookup(const QType& qtype, const DNSName& qname, domainid_t zoneId, DNSPacket* p = nullptr) override;
bool d_hybrid;
bool d_upgradeContent;
- BB2DomainInfo createDomainEntry(const ZoneName& domain, const string& filename); //!< does not insert in s_state
+ BB2DomainInfo createDomainEntry(const ZoneName& domain); //!< does not insert in s_state
void queueReloadAndStore(domainid_t id);
static bool findBeforeAndAfterUnhashed(std::shared_ptr<const recordstorage_t>& records, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after);