1 # Copyright (C) 2009 Raul Jimenez
2 # Released under GNU LGPL 2.1
3 # See LICENSE.txt for more information
6 Floodbarrier is a protection mechanism which protects us from
7 host processing too many messages from a single host.
13 import logging, logging_conf
15 logger = logging.getLogger('dht')
18 CHECKING_PERIOD = 2 # seconds
19 MAX_PACKETS_PER_PERIOD = 20
20 BLOCKING_PERIOD = 100 # seconds
22 class HalfPeriodRegister(object):
24 """Helper class. Not meant to be used outside this module"""
29 def get_num_packets(self, ip):
30 return self.ip_dict.get(ip, 0)
32 def register_ip(self, ip):
33 self.ip_dict[ip] = self.ip_dict.get(ip, 0) + 1
35 class FloodBarrier(object):
38 Object which keeps track of packets received from different
39 hosts. Default values are coded but users can choose their own.
40 The main function is ip_blocked().
44 def __init__(self, checking_period=CHECKING_PERIOD,
45 max_packets_per_period=MAX_PACKETS_PER_PERIOD,
46 blocking_period=BLOCKING_PERIOD):
47 self.checking_period = checking_period
48 self.max_packets_per_period = max_packets_per_period
49 self.blocking_period = blocking_period
51 self.last_half_period_time = time.time()
52 self.ip_registers = [HalfPeriodRegister(), HalfPeriodRegister()]
55 def ip_blocked(self, ip):
57 Register that a packet has been received from the given IP and return
58 whether the host is blocked and, hence, the packet should be dropped
61 current_time = time.time()
62 if current_time > self.last_half_period_time + self.checking_period / 2:
63 self.half_period_timeout = current_time
64 self.ip_registers = [self.ip_registers[1], HalfPeriodRegister()]
65 if current_time > self.last_half_period_time + self.checking_period:
66 self.ip_registers = [self.ip_registers[1], HalfPeriodRegister()]
67 self.ip_registers[1].register_ip(ip)
68 num_packets = self.ip_registers[0].get_num_packets(ip) + \
69 self.ip_registers[1].get_num_packets(ip)
70 if num_packets > self.max_packets_per_period:
71 logger.debug('Got %d packets: blocking %r...' % (
73 self.blocked_ips[ip] = current_time + self.blocking_period
75 # At this point there are no enough packets to block ip (in current
76 # period). Now, we need to check whether the ip is currently blocked
77 if ip in self.blocked_ips:
78 logger.debug('Ip %r (%d) currently blocked' % (ip,
80 if current_time > self.blocked_ips[ip]:
82 'Block for %r (%d) has expired: unblocking...' %
84 # Blocking period already expired
85 del self.blocked_ips[ip]
88 # IP is currently blocked (block hasn't expired)