diff --git a/bms.py b/bms.py index f159b2865965065d027759f863f2fa05aca00bbf..0c26466778764564e32346f279603a1e6031d916 100644 --- a/bms.py +++ b/bms.py @@ -139,7 +139,7 @@ import gc import anydbm import Milter.dsn as dsn from Milter.dynip import is_dynip as dynip -from Milter.utils import iniplist,parse_addr,parse_header,ip4re +from Milter.utils import iniplist,parse_addr,parse_header,ip4re,addr2bin from Milter.config import MilterConfigParser from fnmatch import fnmatchcase @@ -251,6 +251,7 @@ spf_reject_noptr = False supply_sender = False access_file = None timeout = 600 +banned_ips = set() logging.basicConfig( stream=sys.stdout, @@ -583,6 +584,11 @@ class bmsMilter(Milter.Milter): if self.missing_ptr: connecttype += ' DYN' self.log("connect from %s at %s %s" % (hostname,hostaddr,connecttype)) + if addr2bin(ipaddr) in banned_ips: + self.log("REJECT: BANNED IP") + self.setreply('550','5.7.1', 'Banned for dictionary attacks') + return Milter.REJECT + self.bad_rcpts = 0 self.hello_name = None self.connecthost = hostname if hostname == 'localhost' and not ipaddr.startswith('127.') \ @@ -805,7 +811,7 @@ class bmsMilter(Milter.Milter): # we have to wait until envrcpt(). Perhaps an especially # bad reputation could be rejected here. if self.reputation < -70 and self.confidence > 5: - self.log('REJECT: REPUTATION, rcpt to',to,str) + self.log('REJECT: REPUTATION') self.setreply('550','5.7.1', 'Your domain has been sending nothing but spam') return Milter.REJECT @@ -1029,6 +1035,15 @@ class bmsMilter(Milter.Milter): self.log('REJECT: RCPT TO:',to,str) if gossip and self.umis: gossip_node.feedback(self.umis,1) + self.umis = None + self.bad_rcpts += 1 + if self.bad_rcpts > 3: + try: + ip = addr2bin(self.connectip) + if ip not in banned_ips: + banned_ips.add(ip) + print >>open('banned_ips','a'),self.connectip + except: pass return Milter.REJECT # FIXME: should dspam_exempt be case insensitive? if user in block_forward.get(domain,()): @@ -1746,6 +1761,10 @@ def main(): except: milter_log.error('Unable to read: %s',access_file) return + try: + fp = open('banned_ips','r') + banned_ips = set(addr2bin(ip) for ip in fp) + except: pass Milter.factory = bmsMilter flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS if wiretap_dest or smart_alias or dspam_userdir: