diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2011-06-07 10:01:48 +0200 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2011-06-07 10:01:48 +0200 |
commit | ddad5b3299191142f500b25e01b827e40e873cd7 (patch) | |
tree | 082bfe7f57bc7abfbca0e73dabced4b83b38c0a9 | |
parent | 2b9e5ac193ea91817ff17851a4a16a42a5b87fdb (diff) | |
download | rsyslog-ddad5b3299191142f500b25e01b827e40e873cd7.tar.gz rsyslog-ddad5b3299191142f500b25e01b827e40e873cd7.tar.bz2 rsyslog-ddad5b3299191142f500b25e01b827e40e873cd7.zip |
added upper limit on # of dns cache entries to prevent DoS
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | runtime/dnscache.c | 61 | ||||
-rw-r--r-- | runtime/nsd_ptcp.c | 2 |
3 files changed, 60 insertions, 5 deletions
@@ -1,7 +1,7 @@ --------------------------------------------------------------------------- Version 6.3.1 [DEVEL] (rgerhards), 2011-06-01 - added a first implementation of a DNS name cache - this still has a couple of weaknesses, like no size limit, no expiration + this still has a couple of weaknesses, like no expiration of entries, suboptimal algorithms -- but it should perform better than what we had previously. Implementation will be improved based on feedback during the next couple of releases diff --git a/runtime/dnscache.c b/runtime/dnscache.c index b47a30b8..5bee47c4 100644 --- a/runtime/dnscache.c +++ b/runtime/dnscache.c @@ -31,6 +31,7 @@ #include "rsyslog.h" #include <stdio.h> +#include <stdlib.h> #include <signal.h> #include <netdb.h> #include <unistd.h> @@ -51,13 +52,16 @@ struct dnscache_entry_s { uchar *pszHostFQDN; uchar *ip; struct dnscache_entry_s *next; + unsigned nUsed; }; typedef struct dnscache_entry_s dnscache_entry_t; struct dnscache_s { pthread_rwlock_t rwlock; dnscache_entry_t *root; + unsigned nEntries; }; typedef struct dnscache_s dnscache_t; +#define MAX_CACHE_ENTRIES 1000 /* static data */ @@ -73,6 +77,7 @@ dnscacheInit(void) { DEFiRet; dnsCache.root = NULL; + dnsCache.nEntries = 0; pthread_rwlock_init(&dnsCache.rwlock, NULL); CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ CHKiRet(objUse(glbl, CORE_COMPONENT)); @@ -94,6 +99,18 @@ dnscacheDeinit(void) } +/* destruct a cache entry. + * Precondition: entry must already be unlinked from list + */ +static inline void +entryDestruct(dnscache_entry_t *etry) +{ + free(etry->pszHostFQDN); + free(etry->ip); + free(etry); +} + + static inline dnscache_entry_t* findEntry(struct sockaddr_storage *addr) { @@ -102,6 +119,8 @@ findEntry(struct sockaddr_storage *addr) ; etry != NULL && !memcmp(addr, &etry->addr, sizeof(struct sockaddr_storage)) ; etry = etry->next) /* just search, no other processing necessary */; + if(etry != NULL) + ++etry->nUsed; /* this is *not* atomic, but we can live with an occasional loss! */ return etry; } @@ -219,11 +238,45 @@ finalize_it: RETiRet; } + +/* evict an entry from the cache. We should try to evict one that does + * not decrease the hit rate that much, but we do not try to hard currently + * (as the base cache data structure may change). + * This MUST NOT be called when the cache is empty! + * rgerhards, 2011-06-06 + */ +static inline void +evictEntry(void) +{ + dnscache_entry_t *prev, *evict, *prevEvict, *etry; + unsigned lowest; + + prev = prevEvict = NULL; + evict = dnsCache.root; + lowest = evict->nUsed; + for(etry = dnsCache.root->next ; etry != NULL ; etry = etry->next) { + if(etry->nUsed < lowest) { + evict = etry; + lowest = etry->nUsed; + prevEvict = prev; + } + prev = etry; + } + + /* found lowest, unlink */ + if(prevEvict == NULL) { /* remove root? */ + dnsCache.root = evict->next; + } else { + prevEvict = evict->next; + } + entryDestruct(evict); +} + + /* add a new entry to the cache. This means the address is resolved and * then added to the cache. */ -//static inline rsRetVal -static rsRetVal +static inline rsRetVal addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) { uchar pszHostFQDN[NI_MAXHOST]; @@ -234,6 +287,7 @@ addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) CHKmalloc(etry = MALLOC(sizeof(dnscache_entry_t))); CHKmalloc(etry->pszHostFQDN = ustrdup(pszHostFQDN)); CHKmalloc(etry->ip = ustrdup(ip)); + etry->nUsed = 0; *pEtry = etry; /* add to list. Currently, we place the new element always at @@ -241,6 +295,9 @@ addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) */ pthread_rwlock_unlock(&dnsCache.rwlock); /* release read lock */ pthread_rwlock_wrlock(&dnsCache.rwlock); /* and re-aquire for writing */ + if(dnsCache.nEntries >= MAX_CACHE_ENTRIES) { + evictEntry(); + } etry->next = dnsCache.root; dnsCache.root = etry; pthread_rwlock_unlock(&dnsCache.rwlock); diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c index 7dd489e9..06f62b7e 100644 --- a/runtime/nsd_ptcp.c +++ b/runtime/nsd_ptcp.c @@ -251,10 +251,8 @@ Abort(nsd_t *pNsd) static rsRetVal FillRemHost(nsd_ptcp_t *pThis, struct sockaddr *pAddr) { - int error; uchar szIP[NI_MAXHOST] = ""; uchar szHname[NI_MAXHOST] = ""; - struct addrinfo hints, *res; size_t len; DEFiRet; |