Ban ips with too many bad rcpts on a connection.
This commit is contained in:
@@ -139,7 +139,7 @@ import gc
|
|||||||
import anydbm
|
import anydbm
|
||||||
import Milter.dsn as dsn
|
import Milter.dsn as dsn
|
||||||
from Milter.dynip import is_dynip as dynip
|
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 Milter.config import MilterConfigParser
|
||||||
|
|
||||||
from fnmatch import fnmatchcase
|
from fnmatch import fnmatchcase
|
||||||
@@ -251,6 +251,7 @@ spf_reject_noptr = False
|
|||||||
supply_sender = False
|
supply_sender = False
|
||||||
access_file = None
|
access_file = None
|
||||||
timeout = 600
|
timeout = 600
|
||||||
|
banned_ips = set()
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
stream=sys.stdout,
|
stream=sys.stdout,
|
||||||
@@ -583,6 +584,11 @@ class bmsMilter(Milter.Milter):
|
|||||||
if self.missing_ptr:
|
if self.missing_ptr:
|
||||||
connecttype += ' DYN'
|
connecttype += ' DYN'
|
||||||
self.log("connect from %s at %s %s" % (hostname,hostaddr,connecttype))
|
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.hello_name = None
|
||||||
self.connecthost = hostname
|
self.connecthost = hostname
|
||||||
if hostname == 'localhost' and not ipaddr.startswith('127.') \
|
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
|
# we have to wait until envrcpt(). Perhaps an especially
|
||||||
# bad reputation could be rejected here.
|
# bad reputation could be rejected here.
|
||||||
if self.reputation < -70 and self.confidence > 5:
|
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',
|
self.setreply('550','5.7.1',
|
||||||
'Your domain has been sending nothing but spam')
|
'Your domain has been sending nothing but spam')
|
||||||
return Milter.REJECT
|
return Milter.REJECT
|
||||||
@@ -1029,6 +1035,15 @@ class bmsMilter(Milter.Milter):
|
|||||||
self.log('REJECT: RCPT TO:',to,str)
|
self.log('REJECT: RCPT TO:',to,str)
|
||||||
if gossip and self.umis:
|
if gossip and self.umis:
|
||||||
gossip_node.feedback(self.umis,1)
|
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
|
return Milter.REJECT
|
||||||
# FIXME: should dspam_exempt be case insensitive?
|
# FIXME: should dspam_exempt be case insensitive?
|
||||||
if user in block_forward.get(domain,()):
|
if user in block_forward.get(domain,()):
|
||||||
@@ -1746,6 +1761,10 @@ def main():
|
|||||||
except:
|
except:
|
||||||
milter_log.error('Unable to read: %s',access_file)
|
milter_log.error('Unable to read: %s',access_file)
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
|
fp = open('banned_ips','r')
|
||||||
|
banned_ips = set(addr2bin(ip) for ip in fp)
|
||||||
|
except: pass
|
||||||
Milter.factory = bmsMilter
|
Milter.factory = bmsMilter
|
||||||
flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS
|
flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS
|
||||||
if wiretap_dest or smart_alias or dspam_userdir:
|
if wiretap_dest or smart_alias or dspam_userdir:
|
||||||
|
|||||||
Reference in New Issue
Block a user