diff --git a/bms.py b/bms.py index 6c704f2673a5fcb04536ed9ac820af05e6fa28b5..e967b85566371d5bb3984d426117c7c56609427b 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.74 2006/12/19 00:59:30 customdesigned +# Add archive option to wiretap. +# # Revision 1.73 2006/12/04 18:47:03 customdesigned # Reject multiple recipients to DSN. # Auto-disable gossip on DB error. @@ -818,20 +821,27 @@ class bmsMilter(Milter.Milter): or domain in blacklist: self.blacklist = True self.log("BLACKLIST",self.canon_from) - global gossip - if gossip and domain and rc == Milter.CONTINUE \ - and not self.internal_connection: - if self.spf and self.spf.result == 'pass': - qual = 'SPF' - else: - qual = self.connectip - try: - self.umis = gossip.umis(domain+qual,self.id+time.time()) - res,hdr,val = gossip_node.query(self.umis,domain,qual,1) - self.add_header(hdr,val) - except: - gossip = None - raise + else: + global gossip + if gossip and domain and rc == Milter.CONTINUE \ + and not self.internal_connection: + if self.spf and self.spf.result == 'pass': + qual = 'SPF' + elif res == 'pass': + qual = 'GUESS' + else: + qual = self.connectip + try: + umis = gossip.umis(domain+qual,self.id+time.time()) + res,hdr,val = gossip_node.query(umis,domain,qual,1) + self.add_header(hdr,val) + a = val.split(',') + self.reputation = int(a[-2]) + self.confidence = int(a[-1]) + self.umis = umis + except: + gossip = None + raise return rc def check_spf(self): @@ -884,6 +894,8 @@ class bmsMilter(Milter.Milter): res,code,txt = q.best_guess('v=spf1 a/24 mx/24') else: res,code,txt = q.best_guess() + if res != 'pass' and hres == 'pass' and spf.domainmatch([q.h],q.o): + res = 'pass' # get a guessed pass for valid matching HELO if self.missing_ptr and ores == 'none' and res != 'pass' \ and hres != 'pass': # this bad boy has no credentials whatsoever @@ -998,6 +1010,7 @@ class bmsMilter(Milter.Milter): # Currently, a sendmail map reverses SRS. We just log it here. self.log("srs rcpt:",newaddr) self.dspam = False # verified as reply to mail we sent + self.blacklist = False except: if not (self.internal_connection or self.trusted_relay): if srsre.match(oldaddr): @@ -1022,7 +1035,8 @@ class bmsMilter(Milter.Milter): if self.discard: self.del_recipient(to) # don't check userlist if signed MFROM for now - if users and not newaddr and not user.lower() in users: + userl = user.lower() + if users and not newaddr and not userl in users: self.log('REJECT: RCPT TO:',to) return Milter.REJECT # FIXME: should dspam_exempt be case insensitive? @@ -1030,7 +1044,17 @@ class bmsMilter(Milter.Milter): self.forward = False exempt_users = dspam_exempt.get(domain,()) if user in exempt_users or '' in exempt_users: + if self.blacklist: + self.log('REJECT: BLACKLISTED') + self.setreply('550','5.7.1','Sending domain has been blacklisted') + return Milter.REJECT self.dspam = False + if userl != 'postmaster' and self.umis \ + and self.reputation < -50 and self.confidence > 1: + self.log('REJECT: REPUTATION') + self.setreply('550','5.7.1','Your domain has been sending mostly spam') + return Milter.REJECT + if domain in hide_path: self.hidepath = True if not domain in dspam_reject: @@ -1196,7 +1220,7 @@ class bmsMilter(Milter.Milter): hd = t[1].lower() if hd == mf_domain or mf_domain.endswith('.'+hd): break else: - for f in msg.get_all('from'): + for f in msg.get_all('from',[]): self.log(f) sender = msg.get_all('sender') if sender: diff --git a/milter.spec b/milter.spec index a41f9b7601be6e52f8607a47c167d33b82f2d331..6bb15cfd14c91dbaf8bb12e562b227ee795e6bca 100644 --- a/milter.spec +++ b/milter.spec @@ -175,9 +175,9 @@ rm -rf $RPM_BUILD_ROOT %changelog * Sat Nov 04 2006 Stuart Gathman <stuart@bmsi.com> 0.8.7-1 -- Prevent PTR cache poisoning - More lame bounce heuristics - SPF moved to pyspf RPM +- wiretap archive option * Tue May 23 2006 Stuart Gathman <stuart@bmsi.com> 0.8.6-2 - Support CBV timeout - Support fail template, headers in templates