1238106Sdes/*
2238106Sdes * services/cache/infra.h - infrastructure cache, server rtt and capabilities
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains the infrastructure cache.
40238106Sdes */
41238106Sdes
42238106Sdes#ifndef SERVICES_CACHE_INFRA_H
43238106Sdes#define SERVICES_CACHE_INFRA_H
44238106Sdes#include "util/storage/lruhash.h"
45291767Sdes#include "util/storage/dnstree.h"
46238106Sdes#include "util/rtt.h"
47238106Sdesstruct slabhash;
48238106Sdesstruct config_file;
49238106Sdes
50238106Sdes/**
51238106Sdes * Host information kept for every server, per zone.
52238106Sdes */
53238106Sdesstruct infra_key {
54238106Sdes	/** the host address. */
55238106Sdes	struct sockaddr_storage addr;
56238106Sdes	/** length of addr. */
57238106Sdes	socklen_t addrlen;
58238106Sdes	/** zone name in wireformat */
59238106Sdes	uint8_t* zonename;
60238106Sdes	/** length of zonename */
61238106Sdes	size_t namelen;
62238106Sdes	/** hash table entry, data of type infra_data. */
63238106Sdes	struct lruhash_entry entry;
64238106Sdes};
65238106Sdes
66238106Sdes/**
67238106Sdes * Host information encompasses host capabilities and retransmission timeouts.
68238106Sdes * And lameness information (notAuthoritative, noEDNS, Recursive)
69238106Sdes */
70238106Sdesstruct infra_data {
71238106Sdes	/** TTL value for this entry. absolute time. */
72269257Sdes	time_t ttl;
73238106Sdes
74238106Sdes	/** time in seconds (absolute) when probing re-commences, 0 disabled */
75269257Sdes	time_t probedelay;
76238106Sdes	/** round trip times for timeout calculation */
77238106Sdes	struct rtt_info rtt;
78238106Sdes
79238106Sdes	/** edns version that the host supports, -1 means no EDNS */
80238106Sdes	int edns_version;
81238106Sdes	/** if the EDNS lameness is already known or not.
82238106Sdes	 * EDNS lame is when EDNS queries or replies are dropped,
83238106Sdes	 * and cause a timeout */
84238106Sdes	uint8_t edns_lame_known;
85238106Sdes
86238106Sdes	/** is the host lame (does not serve the zone authoritatively),
87238106Sdes	 * or is the host dnssec lame (does not serve DNSSEC data) */
88238106Sdes	uint8_t isdnsseclame;
89238106Sdes	/** is the host recursion lame (not AA, but RA) */
90238106Sdes	uint8_t rec_lame;
91238106Sdes	/** the host is lame (not authoritative) for A records */
92238106Sdes	uint8_t lame_type_A;
93238106Sdes	/** the host is lame (not authoritative) for other query types */
94238106Sdes	uint8_t lame_other;
95238106Sdes
96238106Sdes	/** timeouts counter for type A */
97238106Sdes	uint8_t timeout_A;
98238106Sdes	/** timeouts counter for type AAAA */
99238106Sdes	uint8_t timeout_AAAA;
100238106Sdes	/** timeouts counter for others */
101238106Sdes	uint8_t timeout_other;
102238106Sdes};
103238106Sdes
104238106Sdes/**
105238106Sdes * Infra cache
106238106Sdes */
107238106Sdesstruct infra_cache {
108238106Sdes	/** The hash table with hosts */
109238106Sdes	struct slabhash* hosts;
110238106Sdes	/** TTL value for host information, in seconds */
111238106Sdes	int host_ttl;
112291767Sdes	/** hash table with query rates per name: rate_key, rate_data */
113291767Sdes	struct slabhash* domain_rates;
114291767Sdes	/** ratelimit settings for domains, struct domain_limit_data */
115291767Sdes	rbtree_t domain_limits;
116238106Sdes};
117238106Sdes
118291767Sdes/** ratelimit, unless overridden by domain_limits, 0 is off */
119291767Sdesextern int infra_dp_ratelimit;
120291767Sdes
121291767Sdes/**
122291767Sdes * ratelimit settings for domains
123291767Sdes */
124291767Sdesstruct domain_limit_data {
125291767Sdes	/** key for rbtree, must be first in struct, name of domain */
126291767Sdes	struct name_tree_node node;
127291767Sdes	/** ratelimit for exact match with this name, -1 if not set */
128291767Sdes	int lim;
129291767Sdes	/** ratelimit for names below this name, -1 if not set */
130291767Sdes	int below;
131291767Sdes};
132291767Sdes
133291767Sdes/**
134291767Sdes * key for ratelimit lookups, a domain name
135291767Sdes */
136291767Sdesstruct rate_key {
137291767Sdes	/** lruhash key entry */
138291767Sdes	struct lruhash_entry entry;
139291767Sdes	/** domain name in uncompressed wireformat */
140291767Sdes	uint8_t* name;
141291767Sdes	/** length of name */
142291767Sdes	size_t namelen;
143291767Sdes};
144291767Sdes
145291767Sdes/** number of seconds to track qps rate */
146291767Sdes#define RATE_WINDOW 2
147291767Sdes
148291767Sdes/**
149291767Sdes * Data for ratelimits per domain name
150291767Sdes * It is incremented when a non-cache-lookup happens for that domain name.
151291767Sdes * The name is the delegation point we have for the name.
152291767Sdes * If a new delegation point is found (a referral reply), the previous
153291767Sdes * delegation point is decremented, and the new one is charged with the query.
154291767Sdes */
155291767Sdesstruct rate_data {
156291767Sdes	/** queries counted, for that second. 0 if not in use. */
157291767Sdes	int qps[RATE_WINDOW];
158291767Sdes	/** what the timestamp is of the qps array members, counter is
159291767Sdes	 * valid for that timestamp.  Usually now and now-1. */
160291767Sdes	time_t timestamp[RATE_WINDOW];
161291767Sdes};
162291767Sdes
163238106Sdes/** infra host cache default hash lookup size */
164238106Sdes#define INFRA_HOST_STARTSIZE 32
165238106Sdes/** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */
166238106Sdes#define INFRA_BYTES_NAME 14
167238106Sdes
168238106Sdes/**
169238106Sdes * Create infra cache.
170238106Sdes * @param cfg: config parameters or NULL for defaults.
171238106Sdes * @return: new infra cache, or NULL.
172238106Sdes */
173238106Sdesstruct infra_cache* infra_create(struct config_file* cfg);
174238106Sdes
175238106Sdes/**
176238106Sdes * Delete infra cache.
177238106Sdes * @param infra: infrastructure cache to delete.
178238106Sdes */
179238106Sdesvoid infra_delete(struct infra_cache* infra);
180238106Sdes
181238106Sdes/**
182238106Sdes * Adjust infra cache to use updated configuration settings.
183238106Sdes * This may clean the cache. Operates a bit like realloc.
184238106Sdes * There may be no threading or use by other threads.
185238106Sdes * @param infra: existing cache. If NULL a new infra cache is returned.
186238106Sdes * @param cfg: config options.
187238106Sdes * @return the new infra cache pointer or NULL on error.
188238106Sdes */
189238106Sdesstruct infra_cache* infra_adjust(struct infra_cache* infra,
190238106Sdes	struct config_file* cfg);
191238106Sdes
192238106Sdes/**
193238106Sdes * Plain find infra data function (used by the the other functions)
194238106Sdes * @param infra: infrastructure cache.
195238106Sdes * @param addr: host address.
196238106Sdes * @param addrlen: length of addr.
197238106Sdes * @param name: domain name of zone.
198238106Sdes * @param namelen: length of domain name.
199238106Sdes * @param wr: if true, writelock, else readlock.
200238106Sdes * @return the entry, could be expired (this is not checked) or NULL.
201238106Sdes */
202238106Sdesstruct lruhash_entry* infra_lookup_nottl(struct infra_cache* infra,
203238106Sdes	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name,
204238106Sdes	size_t namelen, int wr);
205238106Sdes
206238106Sdes/**
207238106Sdes * Find host information to send a packet. Creates new entry if not found.
208238106Sdes * Lameness is empty. EDNS is 0 (try with first), and rtt is returned for
209238106Sdes * the first message to it.
210238106Sdes * Use this to send a packet only, because it also locks out others when
211238106Sdes * probing is restricted.
212238106Sdes * @param infra: infrastructure cache.
213238106Sdes * @param addr: host address.
214238106Sdes * @param addrlen: length of addr.
215238106Sdes * @param name: domain name of zone.
216238106Sdes * @param namelen: length of domain name.
217238106Sdes * @param timenow: what time it is now.
218238106Sdes * @param edns_vs: edns version it supports, is returned.
219238106Sdes * @param edns_lame_known: if EDNS lame (EDNS is dropped in transit) has
220238106Sdes * 	already been probed, is returned.
221238106Sdes * @param to: timeout to use, is returned.
222238106Sdes * @return: 0 on error.
223238106Sdes */
224238106Sdesint infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
225238106Sdes	socklen_t addrlen, uint8_t* name, size_t namelen,
226269257Sdes	time_t timenow, int* edns_vs, uint8_t* edns_lame_known, int* to);
227238106Sdes
228238106Sdes/**
229238106Sdes * Set a host to be lame for the given zone.
230238106Sdes * @param infra: infrastructure cache.
231238106Sdes * @param addr: host address.
232238106Sdes * @param addrlen: length of addr.
233238106Sdes * @param name: domain name of zone apex.
234238106Sdes * @param namelen: length of domain name.
235238106Sdes * @param timenow: what time it is now.
236238106Sdes * @param dnsseclame: if true the host is set dnssec lame.
237238106Sdes *	if false, the host is marked lame (not serving the zone).
238238106Sdes * @param reclame: if true host is a recursor not AA server.
239238106Sdes *      if false, dnsseclame or marked lame.
240238106Sdes * @param qtype: the query type for which it is lame.
241238106Sdes * @return: 0 on error.
242238106Sdes */
243238106Sdesint infra_set_lame(struct infra_cache* infra,
244238106Sdes        struct sockaddr_storage* addr, socklen_t addrlen,
245269257Sdes	uint8_t* name, size_t namelen, time_t timenow, int dnsseclame,
246238106Sdes	int reclame, uint16_t qtype);
247238106Sdes
248238106Sdes/**
249238106Sdes * Update rtt information for the host.
250238106Sdes * @param infra: infrastructure cache.
251238106Sdes * @param addr: host address.
252238106Sdes * @param addrlen: length of addr.
253238106Sdes * @param name: zone name
254238106Sdes * @param namelen: zone name length
255238106Sdes * @param qtype: query type.
256238106Sdes * @param roundtrip: estimate of roundtrip time in milliseconds or -1 for
257238106Sdes * 	timeout.
258238106Sdes * @param orig_rtt: original rtt for the query that timed out (roundtrip==-1).
259238106Sdes * 	ignored if roundtrip != -1.
260238106Sdes * @param timenow: what time it is now.
261238106Sdes * @return: 0 on error. new rto otherwise.
262238106Sdes */
263238106Sdesint infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr,
264238106Sdes	socklen_t addrlen, uint8_t* name, size_t namelen, int qtype,
265269257Sdes	int roundtrip, int orig_rtt, time_t timenow);
266238106Sdes
267238106Sdes/**
268238106Sdes * Update information for the host, store that a TCP transaction works.
269238106Sdes * @param infra: infrastructure cache.
270238106Sdes * @param addr: host address.
271238106Sdes * @param addrlen: length of addr.
272238106Sdes * @param name: name of zone
273238106Sdes * @param namelen: length of name
274238106Sdes */
275238106Sdesvoid infra_update_tcp_works(struct infra_cache* infra,
276238106Sdes        struct sockaddr_storage* addr, socklen_t addrlen,
277238106Sdes	uint8_t* name, size_t namelen);
278238106Sdes
279238106Sdes/**
280238106Sdes * Update edns information for the host.
281238106Sdes * @param infra: infrastructure cache.
282238106Sdes * @param addr: host address.
283238106Sdes * @param addrlen: length of addr.
284238106Sdes * @param name: name of zone
285238106Sdes * @param namelen: length of name
286238106Sdes * @param edns_version: the version that it publishes.
287238106Sdes * 	If it is known to support EDNS then no-EDNS is not stored over it.
288238106Sdes * @param timenow: what time it is now.
289238106Sdes * @return: 0 on error.
290238106Sdes */
291238106Sdesint infra_edns_update(struct infra_cache* infra,
292238106Sdes        struct sockaddr_storage* addr, socklen_t addrlen,
293269257Sdes	uint8_t* name, size_t namelen, int edns_version, time_t timenow);
294238106Sdes
295238106Sdes/**
296238106Sdes * Get Lameness information and average RTT if host is in the cache.
297238106Sdes * This information is to be used for server selection.
298238106Sdes * @param infra: infrastructure cache.
299238106Sdes * @param addr: host address.
300238106Sdes * @param addrlen: length of addr.
301238106Sdes * @param name: zone name.
302238106Sdes * @param namelen: zone name length.
303238106Sdes * @param qtype: the query to be made.
304238106Sdes * @param lame: if function returns true, this returns lameness of the zone.
305238106Sdes * @param dnsseclame: if function returns true, this returns if the zone
306238106Sdes *	is dnssec-lame.
307238106Sdes * @param reclame: if function returns true, this is if it is recursion lame.
308238106Sdes * @param rtt: if function returns true, this returns avg rtt of the server.
309238106Sdes * 	The rtt value is unclamped and reflects recent timeouts.
310238106Sdes * @param timenow: what time it is now.
311238106Sdes * @return if found in cache, or false if not (or TTL bad).
312238106Sdes */
313238106Sdesint infra_get_lame_rtt(struct infra_cache* infra,
314238106Sdes        struct sockaddr_storage* addr, socklen_t addrlen,
315238106Sdes	uint8_t* name, size_t namelen, uint16_t qtype,
316269257Sdes	int* lame, int* dnsseclame, int* reclame, int* rtt, time_t timenow);
317238106Sdes
318238106Sdes/**
319238106Sdes * Get additional (debug) info on timing.
320238106Sdes * @param infra: infra cache.
321238106Sdes * @param addr: host address.
322238106Sdes * @param addrlen: length of addr.
323238106Sdes * @param name: zone name
324238106Sdes * @param namelen: zone name length
325238106Sdes * @param rtt: the rtt_info is copied into here (caller alloced return struct).
326238106Sdes * @param delay: probe delay (if any).
327238106Sdes * @param timenow: what time it is now.
328238106Sdes * @param tA: timeout counter on type A.
329238106Sdes * @param tAAAA: timeout counter on type AAAA.
330238106Sdes * @param tother: timeout counter on type other.
331238106Sdes * @return TTL the infra host element is valid for. If -1: not found in cache.
332238106Sdes *	TTL -2: found but expired.
333238106Sdes */
334269257Sdeslong long infra_get_host_rto(struct infra_cache* infra,
335238106Sdes        struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name,
336269257Sdes	size_t namelen, struct rtt_info* rtt, int* delay, time_t timenow,
337238106Sdes	int* tA, int* tAAAA, int* tother);
338238106Sdes
339238106Sdes/**
340291767Sdes * Increment the query rate counter for a delegation point.
341291767Sdes * @param infra: infra cache.
342291767Sdes * @param name: zone name
343291767Sdes * @param namelen: zone name length
344291767Sdes * @param timenow: what time it is now.
345291767Sdes * @return 1 if it could be incremented. 0 if the increment overshot the
346291767Sdes * ratelimit or if in the previous second the ratelimit was exceeded.
347291767Sdes * Failures like alloc failures are not returned (probably as 1).
348291767Sdes */
349291767Sdesint infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
350291767Sdes	size_t namelen, time_t timenow);
351291767Sdes
352291767Sdes/**
353291767Sdes * Decrement the query rate counter for a delegation point.
354291767Sdes * Because the reply received for the delegation point was pleasant,
355291767Sdes * we do not charge this delegation point with it (i.e. it was a referral).
356291767Sdes * Should call it with same second as when inc() was called.
357291767Sdes * @param infra: infra cache.
358291767Sdes * @param name: zone name
359291767Sdes * @param namelen: zone name length
360291767Sdes * @param timenow: what time it is now.
361291767Sdes */
362291767Sdesvoid infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name,
363291767Sdes	size_t namelen, time_t timenow);
364291767Sdes
365291767Sdes/**
366291767Sdes * See if the query rate counter for a delegation point is exceeded.
367291767Sdes * So, no queries are going to be allowed.
368291767Sdes * @param infra: infra cache.
369291767Sdes * @param name: zone name
370291767Sdes * @param namelen: zone name length
371291767Sdes * @param timenow: what time it is now.
372291767Sdes * @return true if exceeded.
373291767Sdes */
374291767Sdesint infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
375291767Sdes	size_t namelen, time_t timenow);
376291767Sdes
377291767Sdes/** find the maximum rate stored, not too old. 0 if no information. */
378291767Sdesint infra_rate_max(void* data, time_t now);
379291767Sdes
380291767Sdes/** find the ratelimit in qps for a domain */
381291767Sdesint infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
382291767Sdes	size_t namelen);
383291767Sdes
384291767Sdes/**
385238106Sdes * Get memory used by the infra cache.
386238106Sdes * @param infra: infrastructure cache.
387238106Sdes * @return memory in use in bytes.
388238106Sdes */
389238106Sdessize_t infra_get_mem(struct infra_cache* infra);
390238106Sdes
391238106Sdes/** calculate size for the hashtable, does not count size of lameness,
392238106Sdes * so the hashtable is a fixed number of items */
393238106Sdessize_t infra_sizefunc(void* k, void* d);
394238106Sdes
395238106Sdes/** compare two addresses, returns -1, 0, or +1 */
396238106Sdesint infra_compfunc(void* key1, void* key2);
397238106Sdes
398238106Sdes/** delete key, and destroy the lock */
399238106Sdesvoid infra_delkeyfunc(void* k, void* arg);
400238106Sdes
401238106Sdes/** delete data and destroy the lameness hashtable */
402238106Sdesvoid infra_deldatafunc(void* d, void* arg);
403238106Sdes
404291767Sdes/** calculate size for the hashtable */
405291767Sdessize_t rate_sizefunc(void* k, void* d);
406291767Sdes
407291767Sdes/** compare two names, returns -1, 0, or +1 */
408291767Sdesint rate_compfunc(void* key1, void* key2);
409291767Sdes
410291767Sdes/** delete key, and destroy the lock */
411291767Sdesvoid rate_delkeyfunc(void* k, void* arg);
412291767Sdes
413291767Sdes/** delete data */
414291767Sdesvoid rate_deldatafunc(void* d, void* arg);
415291767Sdes
416238106Sdes#endif /* SERVICES_CACHE_INFRA_H */
417