1 /* cache.h - Definitions for the dns cache
2 
3    Copyright (C) 2000 Thomas Moestl
4    Copyright (C) 2003, 2004, 2005, 2010, 2011 Paul A. Rombouts
5 
6   This file is part of the pdnsd package.
7 
8   pdnsd is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12 
13   pdnsd 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 pdnsd; see the file COPYING. If not, see
20   <http://www.gnu.org/licenses/>.
21 */
22 
23 
24 #ifndef _CACHE_H_
25 #define _CACHE_H_
26 
27 #include <config.h>
28 #include "ipvers.h"
29 #include <stdio.h>
30 #include "list.h"
31 #include "dns.h"
32 #include "conff.h"
33 
34 struct rr_lent_s;
35 
36 /*
37  * These values are converted to host byte order. the data is _not_.
38  */
39 typedef struct rr_b_s  {
40 	struct rr_b_s    *next;                   /* this is the next pointer in the dns_cent_t list. */
41 	unsigned         rdlen;
42 #if ALLOW_LOCAL_AAAA || defined(ENABLE_IPV6)
43 	struct in6_addr  data[0];                 /* dummy for alignment */
44 #else
45 	struct in_addr   data[0];
46 #endif
47 } rr_bucket_t;
48 
49 typedef struct {
50 	struct rr_lent_s *lent;                   /* this points to the list entry */
51 	time_t           ttl;
52 	time_t           ts;
53 	unsigned short   flags;
54 	rr_bucket_t      *rrs;
55 } rr_set_t;
56 
57 
58 typedef struct {
59 	unsigned char    *qname;                  /* Name of the domain in length byte - string notation. */
60 	size_t           cs;                      /* Size of the cache entry, including RR sets. */
61 	unsigned short   num_rrs;                 /* The number of RR sets. When this decreases to 0, the cent is deleted. */
62 	unsigned short   flags;                   /* Flags for the whole domain. */
63 	union {
64 		struct {                          /* Fields used only for negatively cached domains. */
65 			struct rr_lent_s *lent;   /* list entry for the whole cent. */
66 			time_t           ttl;     /* TTL for negative caching. */
67 			time_t           ts;      /* Timestamp. */
68 		} neg;
69 		struct {                          /* Fields used only for domains that actually exist. */
70 			rr_set_t         *(rrmu[NRRMU]); /* The most used records.
71 							    Use the the value obtained from rrlkuptab[] as index. */
72 			rr_set_t         **rrext; /* Pointer (may be NULL) to an array of size NNRREXT storing the
73 						     less frequently used records. */
74 		} rr;
75 	};
76 	unsigned char    c_ns,c_soa;              /* Number of trailing name elements in qname to use to find NS or SOA
77 						     records to add to the authority section of a response. */
78 } dns_cent_t;
79 
80 /* This value is used to represent an undefined c_ns or c_soa field. */
81 #define cundef 0xff
82 
83 /*
84  * the flag values for RR sets in the cache
85  */
86 #define CF_NEGATIVE    1       /* this one is for per-RRset negative caching*/
87 #define CF_LOCAL       2       /* Local zone entry */
88 #define CF_AUTH        4       /* authoritative record */
89 #define CF_NOCACHE     8       /* Only hold for the cache latency time period, then purge.
90 				* Not really written to cache, but used by add_cache. */
91 #define CF_ADDITIONAL 16       /* This was fetched as an additional or "off-topic" record. */
92 #define CF_NOPURGE    32       /* Do not purge this record */
93 #define CF_ROOTSERV   64       /* This record was directly obtained from a root server */
94 
95 #define CFF_NOINHERIT (CF_LOCAL|CF_AUTH|CF_ADDITIONAL|CF_ROOTSERV) /* not to be inherited on requery */
96 
97 /*
98  * the flag values for whole domains in the cache
99  */
100 #define DF_NEGATIVE    1       /* this one is for whole-domain negative caching (created on NXDOMAIN)*/
101 #define DF_LOCAL       2       /* local record (in conj. with DF_NEGATIVE) */
102 #define DF_AUTH        4       /* authoritative record */
103 #define DF_NOCACHE     8       /* Only hold for the cache latency time period, then purge.
104 				* Only used for negatively cached domains.
105 				* Not really written to cache, but used by add_cache. */
106 #define DF_WILD       16       /* subdomains of this domain have wildcard records */
107 
108 /* #define DFF_NOINHERIT (DF_NEGATIVE) */ /* not to be inherited on requery */
109 
110 enum {w_wild=1, w_neg, w_locnerr};  /* Used to distinguish different types of wildcard records. */
111 
112 #if DEBUG>0
113 #define NCFLAGS 7
114 #define NDFLAGS 5
115 #define CFLAGSTRLEN (NCFLAGS*4)
116 #define DFLAGSTRLEN (NDFLAGS*4)
117 extern const char cflgnames[];
118 extern const char dflgnames[];
119 char *flags2str(unsigned flags,char *buf,int nflags,const char *flgnames);
120 #define cflags2str(flags,buf) flags2str(flags,buf,NCFLAGS,cflgnames)
121 #define dflags2str(flags,buf) flags2str(flags,buf,NDFLAGS,dflgnames)
122 #endif
123 
124 /*
125  * This is the time in secs any record remains at least in the cache before it is purged.
126  * (exception is that the cache is full)
127  */
128 #define CACHE_LAT 120
129 #define CLAT_ADJ(ttl) ((ttl)<CACHE_LAT?CACHE_LAT:(ttl))
130 /* This is used internally to check if a rrset has timed out. */
131 #define timedout(rrset) ((rrset)->ts+CLAT_ADJ((rrset)->ttl)<time(NULL))
132 /* This is used internally to check if a negatively cached domain has timed out.
133    Only use if the DF_NEGATIVE bit is set! */
134 #define timedout_nxdom(cent) ((cent)->neg.ts+CLAT_ADJ((cent)->neg.ttl)<time(NULL))
135 
136 extern volatile short int use_cache_lock;
137 
138 
139 #ifdef ALLOC_DEBUG
140 #define DBGPARAM ,int dbg
141 #define DBGARG ,dbg
142 #define DBG0 ,0
143 #define DBG1 ,1
144 #else
145 #define DBGPARAM
146 #define DBGARG
147 #define DBG0
148 #define DBG1
149 #endif
150 
151 
152 /* Initialize the cache. Call only once. */
153 #define init_cache mk_dns_hash
154 
155 /* Initialize the cache lock. Call only once. */
156 inline static void init_cache_lock()  __attribute__((always_inline));
init_cache_lock()157 inline static void init_cache_lock()
158 {
159 	use_cache_lock=1;
160 }
161 
162 int empty_cache(slist_array sla);
163 void destroy_cache(void);
164 void read_disk_cache(void);
165 void write_disk_cache(void);
166 
167 int report_cache_stat(int f);
168 int dump_cache(int fd, const unsigned char *name, int exact);
169 
170 /*
171  *  add_cache expects the dns_cent_t to be filled.
172  */
173 void add_cache(dns_cent_t *cent);
174 int add_reverse_cache(dns_cent_t * cent);
175 void del_cache(const unsigned char *name);
176 void invalidate_record(const unsigned char *name);
177 int set_cent_flags(const unsigned char *name, unsigned flags);
178 unsigned char *getlocalowner(unsigned char *name,int tp);
179 dns_cent_t *lookup_cache(const unsigned char *name, int *wild);
180 rr_set_t *lookup_cache_local_rrset(const unsigned char *name, int type);
181 #if 0
182 int add_cache_rr_add(const unsigned char *name, int tp, time_t ttl, time_t ts, unsigned flags, unsigned dlen, void *data, unsigned long serial);
183 #endif
184 
185 inline static unsigned int mk_flag_val(servparm_t *server)
186   __attribute__((always_inline));
mk_flag_val(servparm_t * server)187 inline static unsigned int mk_flag_val(servparm_t *server)
188 {
189 	unsigned int fl=0;
190 	if (!server->purge_cache)
191 		fl|=CF_NOPURGE;
192 	if (server->nocache)
193 		fl|=CF_NOCACHE;
194 	if (server->rootserver)
195 		fl|=CF_ROOTSERV;
196 	return fl;
197 }
198 
199 int init_cent(dns_cent_t *cent, const unsigned char *qname, time_t ttl, time_t ts, unsigned flags  DBGPARAM);
200 int add_cent_rrset_by_type(dns_cent_t *cent,  int type, time_t ttl, time_t ts, unsigned flags  DBGPARAM);
201 int add_cent_rr(dns_cent_t *cent, int type, time_t ttl, time_t ts, unsigned flags,unsigned dlen, void *data  DBGPARAM);
202 int del_rrset(rr_set_t *rrs  DBGPARAM);
203 void free_cent(dns_cent_t *cent  DBGPARAM);
204 void free_cent0(void *ptr);
205 void negate_cent(dns_cent_t *cent, time_t ttl, time_t ts);
206 void del_cent(dns_cent_t *cent);
207 
208 /* Because this is empty by now, it is defined as an empty macro to save overhead.*/
209 /*void free_rr(rr_bucket_t cent);*/
210 #define free_rr(x)
211 
212 dns_cent_t *copy_cent(dns_cent_t *cent  DBGPARAM);
213 
214 #if 0
215 unsigned long get_serial(void);
216 #endif
217 
218 /* Get pointer to rrset given cache entry and rr type value. */
219 inline static rr_set_t *getrrset(dns_cent_t *cent, int type)
220   __attribute__((always_inline));
getrrset(dns_cent_t * cent,int type)221 inline static rr_set_t *getrrset(dns_cent_t *cent, int type)
222 {
223 	if(!(cent->flags&DF_NEGATIVE)) {
224 		int tpi= type - T_MIN;
225 
226 		if(tpi>=0 && tpi<T_NUM) {
227 			unsigned int idx = rrlkuptab[tpi];
228 			if(idx < NRRMU)
229 				return cent->rr.rrmu[idx];
230 			else {
231 				idx -= NRRMU;
232 				if(idx < NRREXT) {
233 					rr_set_t **rrext= cent->rr.rrext;
234 					if(rrext)
235 						return rrext[idx];
236 				}
237 			}
238 		}
239 	}
240 
241 	return NULL;
242 }
243 
244 /* This version of getrrset is slightly more efficient,
245    but also more dangerous, because it performs less checks.
246    It is safe to use if T_MIN <= type <= T_MAX and cent
247    is not negative.
248 */
249 inline static rr_set_t *getrrset_eff(dns_cent_t *cent, int type)
250   __attribute__((always_inline));
getrrset_eff(dns_cent_t * cent,int type)251 inline static rr_set_t *getrrset_eff(dns_cent_t *cent, int type)
252 {
253 	unsigned int idx = rrlkuptab[type-T_MIN];
254 	if(idx < NRRMU)
255 		return cent->rr.rrmu[idx];
256 	else {
257 		idx -= NRRMU;
258 		if(idx < NRREXT) {
259 			rr_set_t **rrext= cent->rr.rrext;
260 			if(rrext)
261 				return rrext[idx];
262 		}
263 	}
264 
265 	return NULL;
266 }
267 
268 
269 /* have_rr() tests whether a cache entry has at least one record of a given type.
270    Only use if T_MIN <= type <=T_MAX
271 */
272 inline static int have_rr(dns_cent_t *cent, int type)
273   __attribute__((always_inline));
have_rr(dns_cent_t * cent,int type)274 inline static int have_rr(dns_cent_t *cent, int type)
275 {
276 	rr_set_t *rrset;
277 	return !(cent->flags&DF_NEGATIVE) && (rrset=getrrset_eff(cent, type)) && rrset->rrs;
278 }
279 
280 /* Some quick and dirty and hopefully fast macros. */
281 #define PDNSD_NOT_CACHED_TYPE(type) ((type)<T_MIN || (type)>T_MAX || rrlkuptab[(type)-T_MIN]>=NRRTOT)
282 
283 /* This is useful for iterating over all the RR types in a cache entry in strict ascending order. */
284 #define NRRITERLIST(cent) ((cent)->flags&DF_NEGATIVE?0:(cent)->rr.rrext?NRRTOT:NRRMU)
285 #define RRITERLIST(cent)  ((cent)->flags&DF_NEGATIVE?NULL:(cent)->rr.rrext?rrcachiterlist:rrmuiterlist)
286 
287 /* The following macros use array indices as arguments, not RR type values! */
288 #define GET_RRSMU(cent,i)  (!((cent)->flags&DF_NEGATIVE)?(cent)->rr.rrmu[i]:NULL)
289 #define GET_RRSEXT(cent,i) (!((cent)->flags&DF_NEGATIVE) && (cent)->rr.rrext?(cent)->rr.rrext[i]:NULL)
290 #define HAVE_RRMU(cent,i)  (!((cent)->flags&DF_NEGATIVE) && (cent)->rr.rrmu[i] && (cent)->rr.rrmu[i]->rrs)
291 #define HAVE_RREXT(cent,i) (!((cent)->flags&DF_NEGATIVE) && (cent)->rr.rrext && (cent)->rr.rrext[i] && (cent)->rr.rrext[i]->rrs)
292 
293 #define RRARR_LEN(cent) ((cent)->flags&DF_NEGATIVE?0:(cent)->rr.rrext?NRRTOT:NRRMU)
294 
295 /* This allows us to index the RR-set arrays in a cache entry as if they formed one contiguous array. */
296 #define RRARR_INDEX_TESTEXT(cent,i)    ((cent)->flags&DF_NEGATIVE?NULL:(i)<NRRMU?(cent)->rr.rrmu[i]:(cent)->rr.rrext?(cent)->rr.rrext[(i)-NRRMU]:NULL)
297 /* This gets the address where the pointer to an RR-set is stored in a cache entry,
298    given the cache entry and an RR-set index.
299    Address may be NULL if no storage space for the type has been allocated. */
300 #define RRARR_INDEX_PA_TESTEXT(cent,i) ((cent)->flags&DF_NEGATIVE?NULL:(i)<NRRMU?&(cent)->rr.rrmu[i]:(cent)->rr.rrext?&(cent)->rr.rrext[(i)-NRRMU]:NULL)
301 
302 /* The following macros should only be used if 0 <= i < RRARR_LEN(cent) ! */
303 #define RRARR_INDEX(cent,i)    ((i)<NRRMU?(cent)->rr.rrmu[i]:(cent)->rr.rrext[(i)-NRRMU])
304 #define RRARR_INDEX_PA(cent,i) ((i)<NRRMU?&(cent)->rr.rrmu[i]:&(cent)->rr.rrext[(i)-NRRMU])
305 
306 #endif
307