diff options
Diffstat (limited to 'usr.sbin/unbound/services/cache/infra.h')
-rw-r--r-- | usr.sbin/unbound/services/cache/infra.h | 207 |
1 files changed, 186 insertions, 21 deletions
diff --git a/usr.sbin/unbound/services/cache/infra.h b/usr.sbin/unbound/services/cache/infra.h index 3a3508eac40..6f9471a3941 100644 --- a/usr.sbin/unbound/services/cache/infra.h +++ b/usr.sbin/unbound/services/cache/infra.h @@ -21,28 +21,34 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * - * This file contains the infrastructure cache. + * This file contains the infrastructure cache, as well as rate limiting. + * Note that there are two sorts of rate-limiting here: + * - Pre-cache, per-query rate limiting (query ratelimits) + * - Post-cache, per-domain name rate limiting (infra-ratelimits) */ #ifndef SERVICES_CACHE_INFRA_H #define SERVICES_CACHE_INFRA_H #include "util/storage/lruhash.h" +#include "util/storage/dnstree.h" #include "util/rtt.h" +#include "util/netevent.h" +#include "util/data/msgreply.h" struct slabhash; struct config_file; @@ -68,10 +74,10 @@ struct infra_key { */ struct infra_data { /** TTL value for this entry. absolute time. */ - uint32_t ttl; + time_t ttl; /** time in seconds (absolute) when probing re-commences, 0 disabled */ - uint32_t probedelay; + time_t probedelay; /** round trip times for timeout calculation */ struct rtt_info rtt; @@ -91,6 +97,13 @@ struct infra_data { uint8_t lame_type_A; /** the host is lame (not authoritative) for other query types */ uint8_t lame_other; + + /** timeouts counter for type A */ + uint8_t timeout_A; + /** timeouts counter for type AAAA */ + uint8_t timeout_AAAA; + /** timeouts counter for others */ + uint8_t timeout_other; }; /** @@ -101,8 +114,76 @@ struct infra_cache { struct slabhash* hosts; /** TTL value for host information, in seconds */ int host_ttl; + /** hash table with query rates per name: rate_key, rate_data */ + struct slabhash* domain_rates; + /** ratelimit settings for domains, struct domain_limit_data */ + rbtree_type domain_limits; + /** hash table with query rates per client ip: ip_rate_key, ip_rate_data */ + struct slabhash* client_ip_rates; +}; + +/** ratelimit, unless overridden by domain_limits, 0 is off */ +extern int infra_dp_ratelimit; + +/** + * ratelimit settings for domains + */ +struct domain_limit_data { + /** key for rbtree, must be first in struct, name of domain */ + struct name_tree_node node; + /** ratelimit for exact match with this name, -1 if not set */ + int lim; + /** ratelimit for names below this name, -1 if not set */ + int below; +}; + +/** + * key for ratelimit lookups, a domain name + */ +struct rate_key { + /** lruhash key entry */ + struct lruhash_entry entry; + /** domain name in uncompressed wireformat */ + uint8_t* name; + /** length of name */ + size_t namelen; +}; + +/** ip ratelimit, 0 is off */ +extern int infra_ip_ratelimit; + +/** + * key for ip_ratelimit lookups, a source IP. + */ +struct ip_rate_key { + /** lruhash key entry */ + struct lruhash_entry entry; + /** client ip information */ + struct sockaddr_storage addr; + /** length of address */ + socklen_t addrlen; }; +/** number of seconds to track qps rate */ +#define RATE_WINDOW 2 + +/** + * Data for ratelimits per domain name + * It is incremented when a non-cache-lookup happens for that domain name. + * The name is the delegation point we have for the name. + * If a new delegation point is found (a referral reply), the previous + * delegation point is decremented, and the new one is charged with the query. + */ +struct rate_data { + /** queries counted, for that second. 0 if not in use. */ + int qps[RATE_WINDOW]; + /** what the timestamp is of the qps array members, counter is + * valid for that timestamp. Usually now and now-1. */ + time_t timestamp[RATE_WINDOW]; +}; + +#define ip_rate_data rate_data + /** infra host cache default hash lookup size */ #define INFRA_HOST_STARTSIZE 32 /** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */ @@ -166,7 +247,7 @@ struct lruhash_entry* infra_lookup_nottl(struct infra_cache* infra, */ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, size_t namelen, - uint32_t timenow, int* edns_vs, uint8_t* edns_lame_known, int* to); + time_t timenow, int* edns_vs, uint8_t* edns_lame_known, int* to); /** * Set a host to be lame for the given zone. @@ -185,7 +266,7 @@ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, */ int infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* name, size_t namelen, uint32_t timenow, int dnsseclame, + uint8_t* name, size_t namelen, time_t timenow, int dnsseclame, int reclame, uint16_t qtype); /** @@ -195,6 +276,7 @@ int infra_set_lame(struct infra_cache* infra, * @param addrlen: length of addr. * @param name: zone name * @param namelen: zone name length + * @param qtype: query type. * @param roundtrip: estimate of roundtrip time in milliseconds or -1 for * timeout. * @param orig_rtt: original rtt for the query that timed out (roundtrip==-1). @@ -203,8 +285,8 @@ int infra_set_lame(struct infra_cache* infra, * @return: 0 on error. new rto otherwise. */ int infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t* name, size_t namelen, - int roundtrip, int orig_rtt, uint32_t timenow); + socklen_t addrlen, uint8_t* name, size_t namelen, int qtype, + int roundtrip, int orig_rtt, time_t timenow); /** * Update information for the host, store that a TCP transaction works. @@ -232,7 +314,7 @@ void infra_update_tcp_works(struct infra_cache* infra, */ int infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* name, size_t namelen, int edns_version, uint32_t timenow); + uint8_t* name, size_t namelen, int edns_version, time_t timenow); /** * Get Lameness information and average RTT if host is in the cache. @@ -255,7 +337,7 @@ int infra_edns_update(struct infra_cache* infra, int infra_get_lame_rtt(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, size_t namelen, uint16_t qtype, - int* lame, int* dnsseclame, int* reclame, int* rtt, uint32_t timenow); + int* lame, int* dnsseclame, int* reclame, int* rtt, time_t timenow); /** * Get additional (debug) info on timing. @@ -267,12 +349,71 @@ int infra_get_lame_rtt(struct infra_cache* infra, * @param rtt: the rtt_info is copied into here (caller alloced return struct). * @param delay: probe delay (if any). * @param timenow: what time it is now. + * @param tA: timeout counter on type A. + * @param tAAAA: timeout counter on type AAAA. + * @param tother: timeout counter on type other. * @return TTL the infra host element is valid for. If -1: not found in cache. * TTL -2: found but expired. */ -int infra_get_host_rto(struct infra_cache* infra, +long long infra_get_host_rto(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, - size_t namelen, struct rtt_info* rtt, int* delay, uint32_t timenow); + size_t namelen, struct rtt_info* rtt, int* delay, time_t timenow, + int* tA, int* tAAAA, int* tother); + +/** + * Increment the query rate counter for a delegation point. + * @param infra: infra cache. + * @param name: zone name + * @param namelen: zone name length + * @param timenow: what time it is now. + * @return 1 if it could be incremented. 0 if the increment overshot the + * ratelimit or if in the previous second the ratelimit was exceeded. + * Failures like alloc failures are not returned (probably as 1). + */ +int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name, + size_t namelen, time_t timenow); + +/** + * Decrement the query rate counter for a delegation point. + * Because the reply received for the delegation point was pleasant, + * we do not charge this delegation point with it (i.e. it was a referral). + * Should call it with same second as when inc() was called. + * @param infra: infra cache. + * @param name: zone name + * @param namelen: zone name length + * @param timenow: what time it is now. + */ +void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name, + size_t namelen, time_t timenow); + +/** + * See if the query rate counter for a delegation point is exceeded. + * So, no queries are going to be allowed. + * @param infra: infra cache. + * @param name: zone name + * @param namelen: zone name length + * @param timenow: what time it is now. + * @return true if exceeded. + */ +int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name, + size_t namelen, time_t timenow); + +/** find the maximum rate stored, not too old. 0 if no information. */ +int infra_rate_max(void* data, time_t now); + +/** find the ratelimit in qps for a domain */ +int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name, + size_t namelen); + +/** Update query ratelimit hash and decide + * whether or not a query should be dropped. + * @param infra: infra cache + * @param repinfo: information about client + * @param timenow: what time it is now. + * @return 1 if it could be incremented. 0 if the increment overshot the + * ratelimit and the query should be dropped. */ +int infra_ip_ratelimit_inc(struct infra_cache* infra, + struct comm_reply* repinfo, time_t timenow); /** * Get memory used by the infra cache. @@ -294,4 +435,28 @@ void infra_delkeyfunc(void* k, void* arg); /** delete data and destroy the lameness hashtable */ void infra_deldatafunc(void* d, void* arg); +/** calculate size for the hashtable */ +size_t rate_sizefunc(void* k, void* d); + +/** compare two names, returns -1, 0, or +1 */ +int rate_compfunc(void* key1, void* key2); + +/** delete key, and destroy the lock */ +void rate_delkeyfunc(void* k, void* arg); + +/** delete data */ +void rate_deldatafunc(void* d, void* arg); + +/* calculate size for the client ip hashtable */ +size_t ip_rate_sizefunc(void* k, void* d); + +/* compare two addresses */ +int ip_rate_compfunc(void* key1, void* key2); + +/* delete key, and destroy the lock */ +void ip_rate_delkeyfunc(void* d, void* arg); + +/* delete data */ +#define ip_rate_deldatafunc rate_deldatafunc + #endif /* SERVICES_CACHE_INFRA_H */ |