| 1 | /* |
|---|
| 2 | PowerDNS Versatile Database Driven Nameserver |
|---|
| 3 | Copyright (C) 2002 - 2011 PowerDNS.COM BV |
|---|
| 4 | |
|---|
| 5 | This program is free software; you can redistribute it and/or modify |
|---|
| 6 | it under the terms of the GNU General Public License version 2 |
|---|
| 7 | as published by the Free Software Foundation |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | This program is distributed in the hope that it will be useful, |
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | GNU General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with this program; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|---|
| 18 | */ |
|---|
| 19 | #ifndef PACKETCACHE_HH |
|---|
| 20 | #define PACKETCACHE_HH |
|---|
| 21 | |
|---|
| 22 | #include <string> |
|---|
| 23 | #include <utility> |
|---|
| 24 | #include <map> |
|---|
| 25 | #include <map> |
|---|
| 26 | #include "dns.hh" |
|---|
| 27 | #include <boost/version.hpp> |
|---|
| 28 | #include "namespaces.hh" |
|---|
| 29 | using namespace ::boost::multi_index; |
|---|
| 30 | |
|---|
| 31 | #include "namespaces.hh" |
|---|
| 32 | #include "dnspacket.hh" |
|---|
| 33 | #include "lock.hh" |
|---|
| 34 | #include "statbag.hh" |
|---|
| 35 | |
|---|
| 36 | /** This class performs 'whole packet caching'. Feed it a question packet and it will |
|---|
| 37 | try to find an answer. If you have an answer, insert it to have it cached for later use. |
|---|
| 38 | Take care not to replace existing cache entries. While this works, it is wasteful. Only |
|---|
| 39 | insert packets that where not found by get() |
|---|
| 40 | |
|---|
| 41 | Locking! |
|---|
| 42 | |
|---|
| 43 | The cache itself is protected by a read/write lock. Because deleting is a two step process, which |
|---|
| 44 | first marks and then sweeps, a second lock is present to prevent simultaneous inserts and deletes. |
|---|
| 45 | */ |
|---|
| 46 | |
|---|
| 47 | struct CIBackwardsStringCompare: public std::binary_function<string, string, bool> |
|---|
| 48 | { |
|---|
| 49 | bool operator()(const string& str_a, const string& str_b) const |
|---|
| 50 | { |
|---|
| 51 | string::const_reverse_iterator ra, rb; |
|---|
| 52 | char a=0, b=0; |
|---|
| 53 | for(ra = str_a.rbegin(), rb = str_b.rbegin(); |
|---|
| 54 | ra < str_a.rend() && rb < str_b.rend() && (a=dns_tolower(*ra)) == (b=dns_tolower(*rb)); |
|---|
| 55 | ra++, rb++); |
|---|
| 56 | |
|---|
| 57 | if (ra < str_a.rend() && rb==str_b.rend()) { a=*(ra++); b=0; return false; } // we are at the beginning of b -> b smaller |
|---|
| 58 | if (rb < str_b.rend() && ra==str_a.rend()) { b=*(rb++); a=0; return true; } // we are at the beginning of a -> a smaller |
|---|
| 59 | // if BOTH are at their ends, a and b will be equal, and we should return false, which we will |
|---|
| 60 | return a < b; |
|---|
| 61 | } |
|---|
| 62 | }; |
|---|
| 63 | |
|---|
| 64 | |
|---|
| 65 | class PacketCache : public boost::noncopyable |
|---|
| 66 | { |
|---|
| 67 | public: |
|---|
| 68 | PacketCache(); |
|---|
| 69 | ~PacketCache(); |
|---|
| 70 | enum CacheEntryType { PACKETCACHE, QUERYCACHE}; |
|---|
| 71 | |
|---|
| 72 | void insert(DNSPacket *q, DNSPacket *r, unsigned int maxttl=UINT_MAX); //!< We copy the contents of *p into our cache. Do not needlessly call this to insert questions already in the cache as it wastes resources |
|---|
| 73 | |
|---|
| 74 | void insert(const string &qname, const QType& qtype, CacheEntryType cet, const string& value, unsigned int ttl, int zoneID=-1, bool meritsRecursion=false, |
|---|
| 75 | unsigned int maxReplyLen=512, bool dnssecOk=false, bool EDNS=false); |
|---|
| 76 | |
|---|
| 77 | int get(DNSPacket *p, DNSPacket *q); //!< We return a dynamically allocated copy out of our cache. You need to delete it. You also need to spoof in the right ID with the DNSPacket.spoofID() method. |
|---|
| 78 | bool getEntry(const string &content, const QType& qtype, CacheEntryType cet, string& entry, int zoneID=-1, |
|---|
| 79 | bool meritsRecursion=false, unsigned int maxReplyLen=512, bool dnssecOk=false, bool hasEDNS=false); |
|---|
| 80 | |
|---|
| 81 | int size(); //!< number of entries in the cache |
|---|
| 82 | void cleanup(); //!< force the cache to preen itself from expired packets |
|---|
| 83 | int purge(); |
|---|
| 84 | int purge(const string &match); |
|---|
| 85 | |
|---|
| 86 | map<char,int> getCounts(); |
|---|
| 87 | private: |
|---|
| 88 | bool getEntryLocked(const string &content, const QType& qtype, CacheEntryType cet, string& entry, int zoneID=-1, |
|---|
| 89 | bool meritsRecursion=false, unsigned int maxReplyLen=512, bool dnssecOk=false, bool hasEDNS=false); |
|---|
| 90 | struct CacheEntry |
|---|
| 91 | { |
|---|
| 92 | CacheEntry() { qtype = ctype = 0; zoneID = -1; meritsRecursion=false; dnssecOk=false; hasEDNS=false;} |
|---|
| 93 | |
|---|
| 94 | string qname; |
|---|
| 95 | uint16_t qtype; |
|---|
| 96 | uint16_t ctype; |
|---|
| 97 | int zoneID; |
|---|
| 98 | time_t ttd; |
|---|
| 99 | bool meritsRecursion; |
|---|
| 100 | unsigned int maxReplyLen; |
|---|
| 101 | bool dnssecOk; |
|---|
| 102 | bool hasEDNS; |
|---|
| 103 | string value; |
|---|
| 104 | }; |
|---|
| 105 | |
|---|
| 106 | void getTTLS(); |
|---|
| 107 | |
|---|
| 108 | typedef multi_index_container< |
|---|
| 109 | CacheEntry, |
|---|
| 110 | indexed_by < |
|---|
| 111 | ordered_unique< |
|---|
| 112 | composite_key< |
|---|
| 113 | CacheEntry, |
|---|
| 114 | member<CacheEntry,string,&CacheEntry::qname>, |
|---|
| 115 | member<CacheEntry,uint16_t,&CacheEntry::qtype>, |
|---|
| 116 | member<CacheEntry,uint16_t, &CacheEntry::ctype>, |
|---|
| 117 | member<CacheEntry,int, &CacheEntry::zoneID>, |
|---|
| 118 | member<CacheEntry,bool, &CacheEntry::meritsRecursion>, |
|---|
| 119 | member<CacheEntry,unsigned int, &CacheEntry::maxReplyLen>, |
|---|
| 120 | member<CacheEntry,bool, &CacheEntry::dnssecOk>, |
|---|
| 121 | member<CacheEntry,bool, &CacheEntry::hasEDNS> |
|---|
| 122 | >, |
|---|
| 123 | composite_key_compare<CIBackwardsStringCompare, std::less<uint16_t>, std::less<uint16_t>, std::less<int>, std::less<bool>, |
|---|
| 124 | std::less<unsigned int>, std::less<bool>, std::less<bool> > |
|---|
| 125 | >, |
|---|
| 126 | sequenced<> |
|---|
| 127 | > |
|---|
| 128 | > cmap_t; |
|---|
| 129 | |
|---|
| 130 | |
|---|
| 131 | cmap_t d_map; |
|---|
| 132 | |
|---|
| 133 | pthread_rwlock_t d_mut; |
|---|
| 134 | |
|---|
| 135 | AtomicCounter d_ops; |
|---|
| 136 | int d_ttl; |
|---|
| 137 | int d_recursivettl; |
|---|
| 138 | bool d_doRecursion; |
|---|
| 139 | unsigned int *d_statnumhit; |
|---|
| 140 | unsigned int *d_statnummiss; |
|---|
| 141 | unsigned int *d_statnumentries; |
|---|
| 142 | }; |
|---|
| 143 | |
|---|
| 144 | |
|---|
| 145 | |
|---|
| 146 | #endif /* PACKETCACHE_HH */ |
|---|
| 147 | |
|---|