You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

121 lines
5.2 KiB

  1. /*
  2. * This file is part of PowerDNS or dnsdist.
  3. * Copyright -- PowerDNS.COM B.V. and its contributors
  4. *
  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.
  8. *
  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.
  12. *
  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.
  17. *
  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.
  21. */
  22. #pragma once
  23. #include <atomic>
  24. #include <mutex>
  25. #include <thread>
  26. #include "dnsname.hh"
  27. #include "stable-bloom.hh"
  28. namespace nod {
  29. const float c_fp_rate = 0.01;
  30. const size_t c_num_cells = 67108864;
  31. const uint8_t c_num_dec = 10;
  32. const unsigned int snapshot_interval_default = 600;
  33. const std::string bf_suffix = "bf";
  34. const std::string sbf_prefix = "sbf";
  35. // Theses classes are not designed to be shared between threads
  36. // Use a new instance per-thread, e.g. using thread local storage
  37. // Synchronization (at the class level) is still needed for reading from
  38. // and writing to the cache dir
  39. // Synchronization (at the instance level) is needed when snapshotting
  40. class PersistentSBF {
  41. public:
  42. PersistentSBF() : d_sbf{c_fp_rate, c_num_cells, c_num_dec} {}
  43. PersistentSBF(uint32_t num_cells) : d_sbf{c_fp_rate, num_cells, c_num_dec} {}
  44. bool init(bool ignore_pid=false);
  45. void setPrefix(const std::string& prefix) { d_prefix = prefix; } // Added to filenames in cachedir
  46. void setCacheDir(const std::string& cachedir);
  47. bool snapshotCurrent(std::thread::id tid); // Write the current file out to disk
  48. void add(const std::string& data) {
  49. // The only time this should block is when snapshotting
  50. std::lock_guard<std::mutex> lock(d_sbf_mutex);
  51. d_sbf.add(data);
  52. }
  53. bool test(const std::string& data) { return d_sbf.test(data); }
  54. bool testAndAdd(const std::string& data) {
  55. // The only time this should block is when snapshotting
  56. std::lock_guard<std::mutex> lock(d_sbf_mutex);
  57. return d_sbf.testAndAdd(data);
  58. }
  59. private:
  60. bool d_init{false};
  61. bf::stableBF d_sbf; // Stable Bloom Filter
  62. std::string d_cachedir;
  63. std::string d_prefix = sbf_prefix;
  64. std::mutex d_sbf_mutex; // Per-instance mutex for snapshots
  65. static std::mutex d_cachedir_mutex; // One mutex for all instances of this class
  66. };
  67. class NODDB {
  68. public:
  69. NODDB() : d_psbf{} {}
  70. NODDB(uint32_t num_cells) : d_psbf{num_cells} {}
  71. // Set ignore_pid to true if you don't mind loading files
  72. // created by the current process
  73. bool init(bool ignore_pid=false) {
  74. d_psbf.setPrefix("nod");
  75. return d_psbf.init(ignore_pid);
  76. }
  77. bool isNewDomain(const std::string& domain); // Returns true if newly observed domain
  78. bool isNewDomain(const DNSName& dname); // As above
  79. 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)
  80. bool isNewDomainWithParent(const DNSName& dname, std::string& observed); // As above
  81. void addDomain(const DNSName& dname); // You need to add this to refresh frequently used domains
  82. void addDomain(const std::string& domain); // As above
  83. void setSnapshotInterval(unsigned int secs) { d_snapshot_interval = secs; }
  84. void setCacheDir(const std::string& cachedir) { d_psbf.setCacheDir(cachedir); }
  85. bool snapshotCurrent(std::thread::id tid) { return d_psbf.snapshotCurrent(tid); }
  86. static void startHousekeepingThread(std::shared_ptr<NODDB> noddbp, std::thread::id tid) {
  87. noddbp->housekeepingThread(tid);
  88. }
  89. private:
  90. PersistentSBF d_psbf;
  91. unsigned int d_snapshot_interval{snapshot_interval_default}; // Number seconds between snapshots
  92. void housekeepingThread(std::thread::id tid);
  93. };
  94. class UniqueResponseDB {
  95. public:
  96. UniqueResponseDB() : d_psbf{} {}
  97. UniqueResponseDB(uint32_t num_cells) : d_psbf{num_cells} {}
  98. bool init(bool ignore_pid=false) {
  99. d_psbf.setPrefix("udr");
  100. return d_psbf.init(ignore_pid);
  101. }
  102. bool isUniqueResponse(const std::string& response);
  103. void addResponse(const std::string& response);
  104. void setSnapshotInterval(unsigned int secs) { d_snapshot_interval = secs; }
  105. void setCacheDir(const std::string& cachedir) { d_psbf.setCacheDir(cachedir); }
  106. bool snapshotCurrent(std::thread::id tid) { return d_psbf.snapshotCurrent(tid); }
  107. static void startHousekeepingThread(std::shared_ptr<UniqueResponseDB> udrdbp, std::thread::id tid) {
  108. udrdbp->housekeepingThread(tid);
  109. }
  110. private:
  111. PersistentSBF d_psbf;
  112. unsigned int d_snapshot_interval{snapshot_interval_default}; // Number seconds between snapshots
  113. void housekeepingThread(std::thread::id tid);
  114. };
  115. }