Ban ips on bad mailfrom offenses as well as bad rcpts.
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# A simple milter that has grown quite a bit.
|
# A simple milter that has grown quite a bit.
|
||||||
# $Log$
|
# $Log$
|
||||||
|
# Revision 1.109 2007/06/23 20:53:05 customdesigned
|
||||||
|
# Ban IPs based on too many invalid recipients in a connection. Requires
|
||||||
|
# configuring check_user. Tighten HELO best_guess policy.
|
||||||
|
#
|
||||||
# Revision 1.108 2007/04/19 16:02:43 customdesigned
|
# Revision 1.108 2007/04/19 16:02:43 customdesigned
|
||||||
# Do not process valid SRS recipients as delayed_failure.
|
# Do not process valid SRS recipients as delayed_failure.
|
||||||
#
|
#
|
||||||
@@ -594,7 +598,6 @@ class bmsMilter(Milter.Milter):
|
|||||||
self.log("REJECT: BANNED IP")
|
self.log("REJECT: BANNED IP")
|
||||||
self.setreply('550','5.7.1', 'Banned for dictionary attacks')
|
self.setreply('550','5.7.1', 'Banned for dictionary attacks')
|
||||||
return Milter.REJECT
|
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.') \
|
||||||
@@ -602,6 +605,7 @@ class bmsMilter(Milter.Milter):
|
|||||||
self.log("REJECT: PTR is",hostname)
|
self.log("REJECT: PTR is",hostname)
|
||||||
self.setreply('550','5.7.1', '"%s" is not a reasonable PTR name'%hostname)
|
self.setreply('550','5.7.1', '"%s" is not a reasonable PTR name'%hostname)
|
||||||
return Milter.REJECT
|
return Milter.REJECT
|
||||||
|
self.offenses = 0
|
||||||
return Milter.CONTINUE
|
return Milter.CONTINUE
|
||||||
|
|
||||||
def hello(self,hostname):
|
def hello(self,hostname):
|
||||||
@@ -650,6 +654,17 @@ class bmsMilter(Milter.Milter):
|
|||||||
for t in smart_alias[key]:
|
for t in smart_alias[key]:
|
||||||
self.add_recipient('<%s>'%t)
|
self.add_recipient('<%s>'%t)
|
||||||
|
|
||||||
|
def offense(self,inc=1):
|
||||||
|
self.offenses += inc
|
||||||
|
if self.offenses > 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
|
||||||
|
|
||||||
# multiple messages can be received on a single connection
|
# multiple messages can be received on a single connection
|
||||||
# envfrom (MAIL FROM in the SMTP protocol) seems to mark the start
|
# envfrom (MAIL FROM in the SMTP protocol) seems to mark the start
|
||||||
# of each message.
|
# of each message.
|
||||||
@@ -769,7 +784,9 @@ class bmsMilter(Milter.Milter):
|
|||||||
if not (self.internal_connection or self.trusted_relay) \
|
if not (self.internal_connection or self.trusted_relay) \
|
||||||
and self.connectip and spf:
|
and self.connectip and spf:
|
||||||
rc = self.check_spf()
|
rc = self.check_spf()
|
||||||
if rc != Milter.CONTINUE: return rc
|
if rc != Milter.CONTINUE:
|
||||||
|
if rc != Milter.TEMPFAIL: self.offense()
|
||||||
|
return rc
|
||||||
else:
|
else:
|
||||||
rc = Milter.CONTINUE
|
rc = Milter.CONTINUE
|
||||||
# FIXME: parse Received-SPF from trusted_relay for SPF result
|
# FIXME: parse Received-SPF from trusted_relay for SPF result
|
||||||
@@ -786,6 +803,7 @@ class bmsMilter(Milter.Milter):
|
|||||||
elif cbv_cache.has_key(self.canon_from) and cbv_cache[self.canon_from] \
|
elif cbv_cache.has_key(self.canon_from) and cbv_cache[self.canon_from] \
|
||||||
or domain in blacklist:
|
or domain in blacklist:
|
||||||
if not self.internal_connection:
|
if not self.internal_connection:
|
||||||
|
self.offense()
|
||||||
if not dspam_userdir:
|
if not dspam_userdir:
|
||||||
if domain in blacklist:
|
if domain in blacklist:
|
||||||
self.log('REJECT: BLACKLIST',self.canon_from)
|
self.log('REJECT: BLACKLIST',self.canon_from)
|
||||||
@@ -866,6 +884,8 @@ class bmsMilter(Milter.Milter):
|
|||||||
# check hello name via spf unless spf pass
|
# check hello name via spf unless spf pass
|
||||||
h = spf.query(self.connectip,'',self.hello_name,receiver=receiver)
|
h = spf.query(self.connectip,'',self.hello_name,receiver=receiver)
|
||||||
hres,hcode,htxt = h.check()
|
hres,hcode,htxt = h.check()
|
||||||
|
# FIXME: in a few cases, rejecting on HELO neutral causes problems
|
||||||
|
# for senders forced to use their braindead ISPs email service.
|
||||||
if hres in ('deny','fail','neutral','softfail'):
|
if hres in ('deny','fail','neutral','softfail'):
|
||||||
self.log('REJECT: hello SPF: %s 550 %s' % (hres,htxt))
|
self.log('REJECT: hello SPF: %s 550 %s' % (hres,htxt))
|
||||||
self.setreply('550','5.7.1',htxt,
|
self.setreply('550','5.7.1',htxt,
|
||||||
@@ -907,7 +927,7 @@ class bmsMilter(Milter.Milter):
|
|||||||
if policy == 'CBV':
|
if policy == 'CBV':
|
||||||
if self.mailfrom != '<>':
|
if self.mailfrom != '<>':
|
||||||
self.cbv_needed = (q,ores) # accept, but inform sender via DSN
|
self.cbv_needed = (q,ores) # accept, but inform sender via DSN
|
||||||
self.bad_rcpts = 3 # ban ip if any bad recipient
|
self.offenses = 3 # ban ip if any bad recipient
|
||||||
elif policy != 'OK':
|
elif policy != 'OK':
|
||||||
self.log('REJECT: no PTR, HELO or SPF')
|
self.log('REJECT: no PTR, HELO or SPF')
|
||||||
self.setreply('550','5.7.1',
|
self.setreply('550','5.7.1',
|
||||||
@@ -1059,15 +1079,7 @@ class bmsMilter(Milter.Milter):
|
|||||||
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.umis = None
|
||||||
self.bad_rcpts += 1
|
return self.offense()
|
||||||
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?
|
# FIXME: should dspam_exempt be case insensitive?
|
||||||
if user in block_forward.get(domain,()):
|
if user in block_forward.get(domain,()):
|
||||||
self.forward = False
|
self.forward = False
|
||||||
|
|||||||
Reference in New Issue
Block a user