diff --git a/fail2ban/server/ipdns.py b/fail2ban/server/ipdns.py index 959e39c4..7256ce4e 100644 --- a/fail2ban/server/ipdns.py +++ b/fail2ban/server/ipdns.py @@ -197,7 +197,7 @@ class IPAddr(object): __slots__ = '_family','_addr','_plen','_maskplen','_raw' # todo: make configurable the expired time and max count of cache entries: - CACHE_OBJ = Utils.Cache(maxCount=1000, maxTime=5*60) + CACHE_OBJ = Utils.Cache(maxCount=10000, maxTime=5*60) CIDR_RAW = -2 CIDR_UNSPEC = -1 @@ -205,6 +205,10 @@ class IPAddr(object): FAM_IPv6 = CIDR_RAW - socket.AF_INET6 def __new__(cls, ipstr, cidr=CIDR_UNSPEC): + if cidr == IPAddr.CIDR_RAW: # don't cache raw + ip = super(IPAddr, cls).__new__(cls) + ip.__init(ipstr, cidr) + return ip # check already cached as IPAddr args = (ipstr, cidr) ip = IPAddr.CACHE_OBJ.get(args) @@ -221,7 +225,8 @@ class IPAddr(object): return ip ip = super(IPAddr, cls).__new__(cls) ip.__init(ipstr, cidr) - IPAddr.CACHE_OBJ.set(args, ip) + if ip._family != IPAddr.CIDR_RAW: + IPAddr.CACHE_OBJ.set(args, ip) return ip @staticmethod diff --git a/fail2ban/server/utils.py b/fail2ban/server/utils.py index 46bb33b8..d88c29b8 100644 --- a/fail2ban/server/utils.py +++ b/fail2ban/server/utils.py @@ -95,31 +95,35 @@ class Utils(): def set(self, k, v): t = time.time() - cache = self._cache # for shorter local access - # clean cache if max count reached: - if len(cache) >= self.maxCount: - # avoid multiple modification of list multi-threaded: - with self.__lock: - if len(cache) >= self.maxCount: - for (ck, cv) in cache.items(): + # avoid multiple modification of dict multi-threaded: + cache = self._cache + with self.__lock: + # clean cache if max count reached: + if len(cache) >= self.maxCount: + if OrderedDict is not dict: + # ordered (so remove some from ahead, FIFO) + while cache: + (ck, cv) = cache.popitem(last=False) + # if not yet expired (but has free slot for new entry): + if cv[1] > t and len(cache) < self.maxCount: + break + else: # pragma: 3.x no cover (dict is in 2.6 only) + remlst = [] + for (ck, cv) in cache.iteritems(): # if expired: if cv[1] <= t: - self.unset(ck) - elif OrderedDict is not dict: - break + remlst.append(ck) + for ck in remlst: + self._cache.pop(ck, None) # if still max count - remove any one: - if len(cache) >= self.maxCount: - if OrderedDict is not dict: # first (older): - cache.popitem(False) - else: # pragma: 3.x no cover - cache.popitem() - cache[k] = (v, t + self.maxTime) + while cache and len(cache) >= self.maxCount: + cache.popitem() + # set now: + cache[k] = (v, t + self.maxTime) def unset(self, k): - try: - del self._cache[k] - except KeyError: - pass + with self.__lock: + self._cache.pop(k, None) @staticmethod