Reject on bad_reputation or blacklist and nodspam. Match valid helo like

PTR for guessed SPF pass.
This commit is contained in:
Stuart Gathman
2006-12-28 01:54:32 +00:00
parent 2bea6ad76f
commit 1bc0a4faef
2 changed files with 41 additions and 17 deletions
+40 -16
View File
@@ -1,6 +1,9 @@
#!/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.74 2006/12/19 00:59:30 customdesigned
# Add archive option to wiretap.
#
# Revision 1.73 2006/12/04 18:47:03 customdesigned # Revision 1.73 2006/12/04 18:47:03 customdesigned
# Reject multiple recipients to DSN. # Reject multiple recipients to DSN.
# Auto-disable gossip on DB error. # Auto-disable gossip on DB error.
@@ -818,20 +821,27 @@ class bmsMilter(Milter.Milter):
or domain in blacklist: or domain in blacklist:
self.blacklist = True self.blacklist = True
self.log("BLACKLIST",self.canon_from) self.log("BLACKLIST",self.canon_from)
global gossip else:
if gossip and domain and rc == Milter.CONTINUE \ global gossip
and not self.internal_connection: if gossip and domain and rc == Milter.CONTINUE \
if self.spf and self.spf.result == 'pass': and not self.internal_connection:
qual = 'SPF' if self.spf and self.spf.result == 'pass':
else: qual = 'SPF'
qual = self.connectip elif res == 'pass':
try: qual = 'GUESS'
self.umis = gossip.umis(domain+qual,self.id+time.time()) else:
res,hdr,val = gossip_node.query(self.umis,domain,qual,1) qual = self.connectip
self.add_header(hdr,val) try:
except: umis = gossip.umis(domain+qual,self.id+time.time())
gossip = None res,hdr,val = gossip_node.query(umis,domain,qual,1)
raise 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 return rc
def check_spf(self): def check_spf(self):
@@ -884,6 +894,8 @@ class bmsMilter(Milter.Milter):
res,code,txt = q.best_guess('v=spf1 a/24 mx/24') res,code,txt = q.best_guess('v=spf1 a/24 mx/24')
else: else:
res,code,txt = q.best_guess() 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' \ if self.missing_ptr and ores == 'none' and res != 'pass' \
and hres != 'pass': and hres != 'pass':
# this bad boy has no credentials whatsoever # 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. # Currently, a sendmail map reverses SRS. We just log it here.
self.log("srs rcpt:",newaddr) self.log("srs rcpt:",newaddr)
self.dspam = False # verified as reply to mail we sent self.dspam = False # verified as reply to mail we sent
self.blacklist = False
except: except:
if not (self.internal_connection or self.trusted_relay): if not (self.internal_connection or self.trusted_relay):
if srsre.match(oldaddr): if srsre.match(oldaddr):
@@ -1022,7 +1035,8 @@ class bmsMilter(Milter.Milter):
if self.discard: if self.discard:
self.del_recipient(to) self.del_recipient(to)
# don't check userlist if signed MFROM for now # 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) self.log('REJECT: RCPT TO:',to)
return Milter.REJECT return Milter.REJECT
# FIXME: should dspam_exempt be case insensitive? # FIXME: should dspam_exempt be case insensitive?
@@ -1030,7 +1044,17 @@ class bmsMilter(Milter.Milter):
self.forward = False self.forward = False
exempt_users = dspam_exempt.get(domain,()) exempt_users = dspam_exempt.get(domain,())
if user in exempt_users or '' in exempt_users: 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 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: if domain in hide_path:
self.hidepath = True self.hidepath = True
if not domain in dspam_reject: if not domain in dspam_reject:
@@ -1196,7 +1220,7 @@ class bmsMilter(Milter.Milter):
hd = t[1].lower() hd = t[1].lower()
if hd == mf_domain or mf_domain.endswith('.'+hd): break if hd == mf_domain or mf_domain.endswith('.'+hd): break
else: else:
for f in msg.get_all('from'): for f in msg.get_all('from',[]):
self.log(f) self.log(f)
sender = msg.get_all('sender') sender = msg.get_all('sender')
if sender: if sender:
+1 -1
View File
@@ -175,9 +175,9 @@ rm -rf $RPM_BUILD_ROOT
%changelog %changelog
* Sat Nov 04 2006 Stuart Gathman <stuart@bmsi.com> 0.8.7-1 * Sat Nov 04 2006 Stuart Gathman <stuart@bmsi.com> 0.8.7-1
- Prevent PTR cache poisoning
- More lame bounce heuristics - More lame bounce heuristics
- SPF moved to pyspf RPM - SPF moved to pyspf RPM
- wiretap archive option
* Tue May 23 2006 Stuart Gathman <stuart@bmsi.com> 0.8.6-2 * Tue May 23 2006 Stuart Gathman <stuart@bmsi.com> 0.8.6-2
- Support CBV timeout - Support CBV timeout
- Support fail template, headers in templates - Support fail template, headers in templates