root/trunk/pdns/pdns/packetcache.cc @ 1127

Revision 1127, 6.1 KB (checked in by ahu, 5 years ago)

add some sanity checking on domain name lengths

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2005  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 as
7    published by the Free Software Foundation
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18#include "utility.hh"
19#include "packetcache.hh"
20#include "logger.hh"
21#include "arguments.hh"
22#include "statbag.hh"
23#include <map>
24
25extern StatBag S;
26
27PacketCache::PacketCache()
28{
29  pthread_rwlock_init(&d_mut,0);
30  pthread_mutex_init(&d_dellock,0);
31  d_hit=d_miss=0;
32
33  d_ttl=-1;
34  d_recursivettl=-1;
35
36  S.declare("packetcache-hit");
37  S.declare("packetcache-miss");
38  S.declare("packetcache-size");
39
40  statnumhit=S.getPointer("packetcache-hit");
41  statnummiss=S.getPointer("packetcache-miss");
42  statnumentries=S.getPointer("packetcache-size");
43}
44
45
46void PacketCache::insert(DNSPacket *q, DNSPacket *r)
47{
48  if(d_ttl < 0)
49    getTTLS();
50 
51  if(ntohs(q->d.qdcount)!=1) {
52    L<<"Warning - tried to cache a packet with wrong number of questions: "<<ntohs(q->d.qdcount)<<endl;
53    return; // do not try to cache packets with multiple questions
54  }
55
56  bool packetMeritsRecursion=d_doRecursion && q->d.rd;
57
58  char ckey[512];
59  unsigned int len=q->qdomain.length();
60  if(len > sizeof(ckey))
61    return;
62  memcpy(ckey,q->qdomain.c_str(),len); // add TOLOWER HERE FIXME XXX
63  ckey[len]='|';
64  ckey[len+1]=packetMeritsRecursion ? 'r' : 'n';
65  ckey[len+2]=(q->qtype.getCode()>>8) & 0xff;
66  ckey[len+3]=(q->qtype.getCode()) & 0xff;
67  string key;
68  key.assign(ckey,q->qdomain.length()+4);
69
70  insert(key,r->getString(), packetMeritsRecursion ? d_recursivettl : d_ttl);
71}
72
73void PacketCache::getTTLS()
74{
75  d_ttl=arg().asNum("cache-ttl");
76  d_recursivettl=arg().asNum("recursive-cache-ttl");
77
78  d_doRecursion=arg().mustDo("recursor"); 
79}
80
81void PacketCache::insert(const char *packet, int length) 
82{
83  if(d_ttl<0)
84    getTTLS();
85
86  DNSPacket p;
87  p.parse(packet,length);
88
89  bool packetMeritsRecursion=d_doRecursion && p.d.rd;
90
91  char ckey[512];
92  unsigned int len=p.qdomain.length();
93  if(len > sizeof(ckey))
94    return;
95  memcpy(ckey, p.qdomain.c_str(), len); // add TOLOWER HERE FIXME XXX
96  ckey[len]='|';
97  ckey[len+1]=packetMeritsRecursion ? 'r' : 'n';
98  ckey[len+2]=(p.qtype.getCode()>>8) & 0xff;
99  ckey[len+3]=(p.qtype.getCode()) & 0xff;
100  string key;
101  key.assign(ckey,p.qdomain.length()+4);
102  //  string key=toLower(p.qdomain+"|"+(packetMeritsRecursion ? "R" : "N")+"|"+p.qtype.getName());
103
104  string buffer;
105  buffer.assign(packet,length);
106  insert(key,buffer, packetMeritsRecursion ? d_recursivettl : d_ttl);
107}
108
109void PacketCache::insert(const string &key, const string &packet, unsigned int ttl)
110{
111  if(!ttl)
112    return;
113
114  cvalue_t val;
115  val.ttd=time(0)+ttl;
116  val.value=packet;
117
118  TryWriteLock l(&d_mut);
119  if(l.gotIt()) 
120    d_map[key]=val;
121  else 
122    S.inc("deferred-cache-inserts"); 
123}
124
125/** purges entries from the packetcache. If prefix ends on a $, it is treated as a suffix */
126int PacketCache::purge(const string &f_prefix)
127{
128  Lock pl(&d_dellock);
129
130  string prefix(f_prefix);
131  if(prefix.empty()) {
132    cmap_t *tmp=new cmap_t;
133    {
134      DTime dt;
135      dt.set();
136      WriteLock l(&d_mut);
137      tmp->swap(d_map);
138      L<<Logger::Error<<"cache clean time: "<<dt.udiff()<<"usec"<<endl;
139    }
140
141    int size=tmp->size();
142    delete tmp;
143
144    *statnumentries=0;
145    return size;
146  }
147
148  bool suffix=false;
149  if(prefix[prefix.size()-1]=='$') {
150    prefix=prefix.substr(0,prefix.size()-1);
151    suffix=true;
152  }
153  string check=prefix+"|";
154
155  vector<cmap_t::iterator> toRemove;
156
157  ReadLock l(&d_mut);
158
159  for(cmap_t::iterator i=d_map.begin();i!=d_map.end();++i) {
160    string::size_type pos=i->first.find(check);
161
162    if(!pos || (suffix && pos!=string::npos)) 
163      toRemove.push_back(i);
164  }
165
166  l.upgrade(); 
167
168  for(vector<cmap_t::iterator>::const_iterator i=toRemove.begin();i!=toRemove.end();++i) 
169    d_map.erase(*i);
170  *statnumentries=d_map.size();
171  return toRemove.size();
172}
173
174bool PacketCache::getKey(const string &key, string &content)
175{
176  TryReadLock l(&d_mut); // take a readlock here
177  if(!l.gotIt()) {
178    S.inc( "deferred-cache-lookup");
179    return false;
180  }
181
182  // needs to do ttl check here
183  cmap_t::const_iterator i=d_map.find(key);
184  time_t now=time(0);
185  bool ret=(i!=d_map.end() && i->second.ttd>now);
186  if(ret)
187    content=i->second.value;
188  return ret;
189}
190
191map<char,int> PacketCache::getCounts()
192{
193  ReadLock l(&d_mut);
194  int counts[256];
195  string::size_type offset;
196  memset(counts,0,256*sizeof(counts[0]));
197  char key;
198  for(cmap_t::const_iterator i=d_map.begin();i!=d_map.end();++i) {
199    if((offset=i->first.find_first_of("|"))==string::npos || offset+1>i->first.size())
200      continue;
201   
202    key=i->first[offset+1];
203    if((key=='Q' || key=='q') && !i->second.value.empty())
204      key='!';
205    counts[(int)key]++;
206  }
207
208  map<char,int>ret;
209  for(int i=0;i<256;++i)
210    if(counts[i])
211      ret[i]=counts[i];
212  return ret;
213
214}
215
216
217int PacketCache::size()
218{
219  ReadLock l(&d_mut);
220  return d_map.size();
221}
222
223/** readlock for figuring out which iterators to delete, upgrade to writelock when actually cleaning */
224void PacketCache::cleanup()
225{
226  Lock pl(&d_dellock); // ALWAYS ACQUIRE DELLOCK FIRST
227  ReadLock l(&d_mut);
228
229  *statnumentries=d_map.size();
230
231  time_t now=time(0);
232
233  DLOG(L<<"Starting cache clean"<<endl);
234  if(d_map.begin()==d_map.end()) {
235    return; // clean
236  }
237
238  vector<cmap_t::iterator> toRemove;
239
240  for(cmap_t::iterator i=d_map.begin();i!=d_map.end();++i) {
241    if(now>i->second.ttd)
242      toRemove.push_back(i);
243  }
244
245  l.upgrade(); 
246
247  for(vector<cmap_t::iterator>::const_iterator i=toRemove.begin();i!=toRemove.end();++i) 
248    d_map.erase(*i);
249   
250  *statnumentries=d_map.size();
251  DLOG(L<<"Done with cache clean"<<endl);
252}
Note: See TracBrowser for help on using the browser.