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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
/*
* This file is part of PowerDNS or dnsdist.
* Copyright -- PowerDNS.COM B.V. and its contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* In addition, for the avoidance of any doubt, permission is granted to
* link this program with OpenSSL and to (re)distribute the binaries
* produced as the result of such linking.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <atomic>
#include <mutex>
#include <thread>
#include <boost/filesystem.hpp>
#include "dnsname.hh"
#include "lock.hh"
#include "stable-bloom.hh"
namespace nod {
const float c_fp_rate = 0.01;
const size_t c_num_cells = 67108864;
const uint8_t c_num_dec = 10;
const unsigned int snapshot_interval_default = 600;
const std::string bf_suffix = "bf";
const std::string sbf_prefix = "sbf";
// Theses classes are not designed to be shared between threads
// Use a new instance per-thread, e.g. using thread local storage
// Synchronization (at the class level) is still needed for reading from
// and writing to the cache dir
// Synchronization (at the instance level) is needed when snapshotting
class PersistentSBF {
public:
PersistentSBF() : d_sbf(bf::stableBF(c_fp_rate, c_num_cells, c_num_dec)) {}
PersistentSBF(uint32_t num_cells) : d_sbf(bf::stableBF(c_fp_rate, num_cells, c_num_dec)) {}
bool init(bool ignore_pid=false);
void setPrefix(const std::string& prefix) { d_prefix = prefix; } // Added to filenames in cachedir
void setCacheDir(const std::string& cachedir);
bool snapshotCurrent(std::thread::id tid); // Write the current file out to disk
void add(const std::string& data) {
// The only time this should block is when snapshotting
d_sbf.lock()->add(data);
}
bool test(const std::string& data) { return d_sbf.lock()->test(data); }
bool testAndAdd(const std::string& data) {
// The only time this should block is when snapshotting
return d_sbf.lock()->testAndAdd(data);
}
private:
void remove_tmp_files(const boost::filesystem::path&, std::lock_guard<std::mutex>&);
bool d_init{false};
LockGuarded<bf::stableBF> d_sbf; // Stable Bloom Filter
std::string d_cachedir;
std::string d_prefix = sbf_prefix;
static std::mutex d_cachedir_mutex; // One mutex for all instances of this class
};
class NODDB {
public:
NODDB() : d_psbf{} {}
NODDB(uint32_t num_cells) : d_psbf{num_cells} {}
// Set ignore_pid to true if you don't mind loading files
// created by the current process
bool init(bool ignore_pid=false) {
d_psbf.setPrefix("nod");
return d_psbf.init(ignore_pid);
}
bool isNewDomain(const std::string& domain); // Returns true if newly observed domain
bool isNewDomain(const DNSName& dname); // As above
bool isNewDomainWithParent(const std::string& domain, std::string& observed); // Returns true if newly observed domain, in which case "observed" contains the parent domain which *was* observed (or "" if domain is . or no parent domains observed)
bool isNewDomainWithParent(const DNSName& dname, std::string& observed); // As above
void addDomain(const DNSName& dname); // You need to add this to refresh frequently used domains
void addDomain(const std::string& domain); // As above
void setSnapshotInterval(unsigned int secs) { d_snapshot_interval = secs; }
void setCacheDir(const std::string& cachedir) { d_psbf.setCacheDir(cachedir); }
bool snapshotCurrent(std::thread::id tid) { return d_psbf.snapshotCurrent(tid); }
static void startHousekeepingThread(std::shared_ptr<NODDB> noddbp, std::thread::id tid) {
noddbp->housekeepingThread(tid);
}
private:
PersistentSBF d_psbf;
unsigned int d_snapshot_interval{snapshot_interval_default}; // Number seconds between snapshots
void housekeepingThread(std::thread::id tid);
};
class UniqueResponseDB {
public:
UniqueResponseDB() : d_psbf{} {}
UniqueResponseDB(uint32_t num_cells) : d_psbf{num_cells} {}
bool init(bool ignore_pid=false) {
d_psbf.setPrefix("udr");
return d_psbf.init(ignore_pid);
}
bool isUniqueResponse(const std::string& response);
void addResponse(const std::string& response);
void setSnapshotInterval(unsigned int secs) { d_snapshot_interval = secs; }
void setCacheDir(const std::string& cachedir) { d_psbf.setCacheDir(cachedir); }
bool snapshotCurrent(std::thread::id tid) { return d_psbf.snapshotCurrent(tid); }
static void startHousekeepingThread(std::shared_ptr<UniqueResponseDB> udrdbp, std::thread::id tid) {
udrdbp->housekeepingThread(tid);
}
private:
PersistentSBF d_psbf;
unsigned int d_snapshot_interval{snapshot_interval_default}; // Number seconds between snapshots
void housekeepingThread(std::thread::id tid);
};
}
|