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 <string> 24 #include <map> 25 #include "dns.hh" 26 #include <boost/version.hpp> 27 #include "namespaces.hh" 28 using namespace ::boost::multi_index; 29 30 #include <boost/multi_index/hashed_index.hpp> 31 32 #include "dns.hh" 33 #include "dnspacket.hh" 34 #include "lock.hh" 35 36 class AuthQueryCache : public boost::noncopyable 37 { 38 public: 39 AuthQueryCache(size_t mapsCount=1024); 40 ~AuthQueryCache(); 41 42 void insert(const DNSName &qname, const QType& qtype, vector<DNSZoneRecord>&& content, uint32_t ttl, int zoneID); 43 44 bool getEntry(const DNSName &qname, const QType& qtype, vector<DNSZoneRecord>& entry, int zoneID); 45 size()46 size_t size() { return *d_statnumentries; } //!< number of entries in the cache 47 void cleanup(); //!< force the cache to preen itself from expired queries 48 uint64_t purge(); 49 uint64_t purge(const std::string& match); // could be $ terminated. Is not a dnsname! 50 uint64_t purgeExact(const DNSName& qname); // no wildcard matching here 51 52 map<char,uint64_t> getCounts(); 53 setMaxEntries(uint64_t maxEntries)54 void setMaxEntries(uint64_t maxEntries) 55 { 56 d_maxEntries = maxEntries; 57 for (auto& shard : d_maps) { 58 shard.reserve(maxEntries / d_maps.size()); 59 } 60 } 61 private: 62 63 struct CacheEntry 64 { 65 DNSName qname; 66 mutable vector<DNSZoneRecord> drs; 67 mutable time_t created{0}; 68 mutable time_t ttd{0}; 69 uint16_t qtype{0}; 70 int zoneID{-1}; 71 }; 72 73 struct HashTag{}; 74 struct NameTag{}; 75 struct SequencedTag{}; 76 typedef multi_index_container< 77 CacheEntry, 78 indexed_by < 79 hashed_unique<tag<HashTag>, composite_key<CacheEntry, 80 member<CacheEntry,DNSName,&CacheEntry::qname>, 81 member<CacheEntry,uint16_t,&CacheEntry::qtype>, 82 member<CacheEntry,int, &CacheEntry::zoneID> > > , 83 ordered_non_unique<tag<NameTag>, member<CacheEntry,DNSName,&CacheEntry::qname>, CanonDNSNameCompare >, 84 /* Note that this sequence holds 'least recently inserted or replaced', not least recently used. 85 Making it a LRU would require taking a write-lock when fetching from the cache, making the RW-lock inefficient compared to a mutex */ 86 sequenced<tag<SequencedTag>> 87 > 88 > cmap_t; 89 90 91 struct MapCombo 92 { MapComboAuthQueryCache::MapCombo93 MapCombo() { 94 } ~MapComboAuthQueryCache::MapCombo95 ~MapCombo() { 96 } 97 MapCombo(const MapCombo &) = delete; 98 MapCombo & operator=(const MapCombo &) = delete; 99 100 void reserve(size_t numberOfEntries); 101 102 ReadWriteLock d_mut; 103 cmap_t d_map; 104 }; 105 106 vector<MapCombo> d_maps; getMap(const DNSName & qname)107 MapCombo& getMap(const DNSName& qname) 108 { 109 return d_maps[qname.hash() % d_maps.size()]; 110 } 111 112 bool getEntryLocked(cmap_t& map, const DNSName &content, uint16_t qtype, vector<DNSZoneRecord>& entry, int zoneID, time_t now); 113 void cleanupIfNeeded(); 114 115 AtomicCounter d_ops{0}; 116 AtomicCounter *d_statnumhit; 117 AtomicCounter *d_statnummiss; 118 AtomicCounter *d_statnumentries; 119 120 uint64_t d_maxEntries{0}; 121 time_t d_lastclean; // doesn't need to be atomic 122 unsigned long d_nextclean{4096}; 123 unsigned int d_cleaninterval{4096}; 124 bool d_cleanskipped{false}; 125 126 static const unsigned int s_mincleaninterval=1000, s_maxcleaninterval=300000; 127 }; 128