]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/nod.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "pdnsexception.hh"
30 #include "threadname.hh"
32 #include <boost/filesystem.hpp>
37 using namespace boost::filesystem
;
39 // PersistentSBF Implementation
41 std::mutex
PersistentSBF::d_cachedir_mutex
;
43 // This looks for an old (per-thread) snapshot. The first one it finds,
44 // it restores from that. Then immediately snapshots with the current thread id,// before removing the old snapshot
45 // In this way, we can have per-thread SBFs, but still snapshot and restore.
46 // The mutex has to be static because we can't have multiple (i.e. per-thread)
47 // instances iterating and writing to the cache dir at the same time
48 bool PersistentSBF::init(bool ignore_pid
) {
52 std::lock_guard
<std::mutex
> lock(d_cachedir_mutex
);
53 if (d_cachedir
.length()) {
56 if (exists(p
) && is_directory(p
)) {
58 std::time_t newest_time
=time(nullptr);
59 Regex
file_regex(d_prefix
+ ".*\\." + bf_suffix
+ "$");
60 for (directory_iterator
i(p
); i
!=directory_iterator(); ++i
) {
61 if (is_regular_file(i
->path()) &&
62 file_regex
.match(i
->path().filename().string())) {
64 (i
->path().filename().string().find(std::to_string(getpid())) == std::string::npos
)) {
65 // look for the newest file matching the regex
66 if ((last_write_time(i
->path()) < newest_time
) ||
67 newest_file
.empty()) {
68 newest_time
= last_write_time(i
->path());
69 newest_file
= i
->path();
74 if (exists(newest_file
)) {
75 std::string filename
= newest_file
.string();
78 infile
.open(filename
, std::ios::in
| std::ios::binary
);
79 g_log
<< Logger::Warning
<< "Found SBF file " << filename
<< endl
;
80 // read the file into the sbf
81 d_sbf
.restore(infile
);
83 // now dump it out again with new thread id & process id
84 snapshotCurrent(std::this_thread::get_id());
85 // Remove the old file we just read to stop proliferation
88 catch (const std::runtime_error
& e
) {
89 g_log
<<Logger::Warning
<<"NODDB init: Cannot parse file: " << filename
<< endl
;
94 catch (const filesystem_error
& e
) {
95 g_log
<<Logger::Warning
<<"NODDB init failed:: " << e
.what() << endl
;
103 void PersistentSBF::setCacheDir(const std::string
& cachedir
)
108 throw PDNSException("NODDB setCacheDir specified non-existent directory: " + cachedir
);
109 else if (!is_directory(p
))
110 throw PDNSException("NODDB setCacheDir specified a file not a directory: " + cachedir
);
111 d_cachedir
= cachedir
;
115 // Dump the SBF to a file
116 // To spend the least amount of time inside the mutex, we dump to an
117 // intermediate stringstream, otherwise the lock would be waiting for
118 // file IO to complete
119 bool PersistentSBF::snapshotCurrent(std::thread::id tid
)
121 if (d_cachedir
.length()) {
124 std::stringstream ss
;
125 ss
<< d_prefix
<< "_" << tid
;
126 f
/= ss
.str() + "_" + std::to_string(getpid()) + "." + bf_suffix
;
127 if (exists(p
) && is_directory(p
)) {
130 std::stringstream iss
;
131 ofile
.open(f
.string(), std::ios::out
| std::ios::binary
);
133 // only lock while dumping to a stringstream
134 std::lock_guard
<std::mutex
> lock(d_sbf_mutex
);
137 // Now write it out to the file
141 throw std::runtime_error("Failed to write to file:" + f
.string());
144 catch (const std::runtime_error
& e
) {
145 g_log
<<Logger::Warning
<<"NODDB snapshot: Cannot write file: " << e
.what() << endl
;
149 g_log
<<Logger::Warning
<<"NODDB snapshot: Cannot write file: " << f
.string() << endl
;
155 // NODDB Implementation
157 void NODDB::housekeepingThread(std::thread::id tid
)
159 setThreadName("pdns-r/NOD-hk");
161 sleep(d_snapshot_interval
);
163 snapshotCurrent(tid
);
168 bool NODDB::isNewDomain(const std::string
& domain
)
170 DNSName
dname(domain
);
171 return isNewDomain(dname
);
174 bool NODDB::isNewDomain(const DNSName
& dname
)
176 std::string dname_lc
= dname
.toDNSStringLC();
177 // The only time this should block is when snapshotting from the
178 // housekeeping thread
179 // the result is always the inverse of what is returned by the SBF
180 return !d_psbf
.testAndAdd(dname_lc
);
183 bool NODDB::isNewDomainWithParent(const std::string
& domain
, std::string
& observed
)
185 DNSName
dname(domain
);
186 return isNewDomainWithParent(dname
, observed
);
189 bool NODDB::isNewDomainWithParent(const DNSName
& dname
, std::string
& observed
)
191 bool ret
= isNewDomain(dname
);
193 DNSName mdname
= dname
;
194 while (mdname
.chopOff()) {
195 if (!isNewDomain(mdname
)) {
196 observed
= mdname
.toString();
204 void NODDB::addDomain(const DNSName
& dname
)
206 std::string native_domain
= dname
.toDNSStringLC();
207 d_psbf
.add(native_domain
);
210 void NODDB::addDomain(const std::string
& domain
)
212 DNSName
dname(domain
);
216 // UniqueResponseDB Implementation
217 bool UniqueResponseDB::isUniqueResponse(const std::string
& response
)
219 return !d_psbf
.testAndAdd(response
);
222 void UniqueResponseDB::addResponse(const std::string
& response
)
224 d_psbf
.add(response
);
227 void UniqueResponseDB::housekeepingThread(std::thread::id tid
)
229 setThreadName("pdns-r/UDR-hk");
231 sleep(d_snapshot_interval
);
233 snapshotCurrent(tid
);