Ban IPs based on too many invalid recipients in a connection. Requires
configuring check_user. Tighten HELO best_guess policy.
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# A simple milter that has grown quite a bit.
|
||||
# $Log$
|
||||
# Revision 1.108 2007/04/19 16:02:43 customdesigned
|
||||
# Do not process valid SRS recipients as delayed_failure.
|
||||
#
|
||||
# Revision 1.107 2007/04/15 01:01:13 customdesigned
|
||||
# Ban ips with too many bad rcpts on a connection.
|
||||
#
|
||||
@@ -182,9 +185,9 @@ _subjpats = (
|
||||
r'\buser unknown\b',
|
||||
r'^failed', r'^mail failed',
|
||||
r'^echec de distribution',
|
||||
r'\berror\s+sending\b',
|
||||
r'^fallo en la entrega',
|
||||
r'\bfehlgeschlagen\b',
|
||||
r'^error sending\b'
|
||||
r'\bfehlgeschlagen\b'
|
||||
)
|
||||
refaildsn = re.compile('|'.join(_subjpats),re.IGNORECASE)
|
||||
|
||||
@@ -782,6 +785,17 @@ class bmsMilter(Milter.Milter):
|
||||
self.log("PROBATION",self.canon_from)
|
||||
elif cbv_cache.has_key(self.canon_from) and cbv_cache[self.canon_from] \
|
||||
or domain in blacklist:
|
||||
if not self.internal_connection:
|
||||
if not dspam_userdir:
|
||||
if domain in blacklist:
|
||||
self.log('REJECT: BLACKLIST',self.canon_from)
|
||||
self.setreply('550','5.7.1', 'Sender email local blacklist')
|
||||
else:
|
||||
res = cbv_cache[self.canon_from]
|
||||
desc = "CBV: %d %s" % res[:2]
|
||||
self.log('REJECT:',desc)
|
||||
self.setreply('550','5.7.1',*desc.splitlines())
|
||||
return Milter.REJECT
|
||||
self.blacklist = True
|
||||
self.log("BLACKLIST",self.canon_from)
|
||||
else:
|
||||
@@ -828,6 +842,8 @@ class bmsMilter(Milter.Milter):
|
||||
for tf in trusted_forwarder:
|
||||
q = spf.query(self.connectip,'',tf,receiver=receiver,strict=False)
|
||||
res,code,txt = q.check()
|
||||
if res == 'none':
|
||||
res,code,txt = q.best_guess('v=spf1 a mx')
|
||||
if res == 'pass':
|
||||
self.log("TRUSTED_FORWARDER:",tf)
|
||||
break
|
||||
@@ -861,7 +877,9 @@ class bmsMilter(Milter.Milter):
|
||||
return Milter.REJECT
|
||||
if hres == 'none' and spf_best_guess \
|
||||
and not dynip(self.hello_name,self.connectip):
|
||||
hres,hcode,htxt = h.best_guess()
|
||||
# HELO must match more exactly. Don't match PTR or zombies
|
||||
# will be able to get a best_guess pass on their ISPs domain.
|
||||
hres,hcode,htxt = h.best_guess('v=spf1 a mx')
|
||||
else:
|
||||
hres,hcode,htxt = res,code,txt
|
||||
ores = res
|
||||
@@ -889,6 +907,7 @@ class bmsMilter(Milter.Milter):
|
||||
if policy == 'CBV':
|
||||
if self.mailfrom != '<>':
|
||||
self.cbv_needed = (q,ores) # accept, but inform sender via DSN
|
||||
self.bad_rcpts = 3 # ban ip if any bad recipient
|
||||
elif policy != 'OK':
|
||||
self.log('REJECT: no PTR, HELO or SPF')
|
||||
self.setreply('550','5.7.1',
|
||||
@@ -1129,7 +1148,7 @@ class bmsMilter(Milter.Milter):
|
||||
return Milter.REJECT
|
||||
|
||||
# check for delayed bounce of CBV
|
||||
if (self.is_bounce or self.postmaster_reply) and srs:
|
||||
if self.postmaster_reply and srs:
|
||||
if refaildsn.search(lval):
|
||||
self.delayed_failure = val.strip()
|
||||
# if confirmed by finding our signed Message-ID,
|
||||
@@ -1766,9 +1785,13 @@ def main():
|
||||
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
|
||||
from glob import glob
|
||||
banned_ips = set(addr2bin(ip)
|
||||
for fn in glob('banned_ips*')
|
||||
for ip in open(fn))
|
||||
print len(banned_ips),'banned ips'
|
||||
except:
|
||||
milter_log.exception('Error reading banned_ips')
|
||||
Milter.factory = bmsMilter
|
||||
flags = Milter.CHGBODY + Milter.CHGHDRS + Milter.ADDHDRS
|
||||
if wiretap_dest or smart_alias or dspam_userdir:
|
||||
|
||||
+7
-1
@@ -77,6 +77,11 @@ cat >$RPM_BUILD_ROOT/etc/logrotate.d/milter <<'EOF'
|
||||
copytruncate
|
||||
compress
|
||||
}
|
||||
/var/log/milter/banned_ips {
|
||||
rotate 3
|
||||
daily
|
||||
copytruncate
|
||||
}
|
||||
EOF
|
||||
|
||||
# purge saved defanged message copies
|
||||
@@ -152,7 +157,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files -f INSTALLED_FILES
|
||||
%defattr(-,root,root)
|
||||
%doc README HOWTO ChangeLog NEWS TODO CREDITS sample.py
|
||||
%doc README HOWTO ChangeLog NEWS TODO CREDITS sample.py milter-template.py
|
||||
/etc/logrotate.d/milter
|
||||
/etc/cron.daily/milter
|
||||
%ifos aix4.1
|
||||
@@ -183,6 +188,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||
- add sample spfmilter.py milter
|
||||
- private_relay config option
|
||||
- persist delayed DSN blacklisting
|
||||
- handle gossip server restart without disabling gossip
|
||||
* Sat Nov 04 2006 Stuart Gathman <stuart@bmsi.com> 0.8.7-1
|
||||
- More lame bounce heuristics
|
||||
- SPF moved to pyspf RPM
|
||||
|
||||
Reference in New Issue
Block a user