diff --git a/bms.py b/bms.py index 74c69c58b0bf856570a765582724766185d3b5ee..2549815acd219dbb96db9167291228424d0b9aa5 100644 --- a/bms.py +++ b/bms.py @@ -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,8 +785,19 @@ 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: - self.blacklist = True - self.log("BLACKLIST",self.canon_from) + 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: global gossip if gossip and domain and rc == Milter.CONTINUE \ @@ -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: diff --git a/milter.spec b/milter.spec index 0ec6f95fc47fad985f82e66dedcb935d91597b0a..ac12761de2c3e493f6eaf6f43a1806f54ca8bba0 100644 --- a/milter.spec +++ b/milter.spec @@ -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