Persist blacklisting from delayed DSNs.
This commit is contained in:
+9
-6
@@ -10,6 +10,11 @@
|
|||||||
# CBV results.
|
# CBV results.
|
||||||
#
|
#
|
||||||
# $Log$
|
# $Log$
|
||||||
|
# Revision 1.6 2007/01/19 23:31:38 customdesigned
|
||||||
|
# Move parse_header to Milter.utils.
|
||||||
|
# Test case for delayed DSN parsing.
|
||||||
|
# Fix plock when source missing or cannot set owner/group.
|
||||||
|
#
|
||||||
# Revision 1.5 2007/01/11 19:59:40 customdesigned
|
# Revision 1.5 2007/01/11 19:59:40 customdesigned
|
||||||
# Purge old entries in auto_whitelist and send_dsn logs.
|
# Purge old entries in auto_whitelist and send_dsn logs.
|
||||||
#
|
#
|
||||||
@@ -129,12 +134,10 @@ class AddrCache(object):
|
|||||||
def __setitem__(self,sender,res):
|
def __setitem__(self,sender,res):
|
||||||
lsender = sender.lower()
|
lsender = sender.lower()
|
||||||
now = time.time()
|
now = time.time()
|
||||||
cached = self.has_key(sender)
|
self.cache[lsender] = (now,res)
|
||||||
if not cached:
|
if not res and self.fname:
|
||||||
self.cache[lsender] = (now,res)
|
s = time.strftime(AddrCache.time_format,time.localtime(now))
|
||||||
if not res and self.fname:
|
print >>open(self.fname,'a'),sender,s # log refreshed senders
|
||||||
s = time.strftime(AddrCache.time_format,time.localtime(now))
|
|
||||||
print >>open(self.fname,'a'),sender,s # log refreshed senders
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.cache)
|
return len(self.cache)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ Here is a history of user visible changes to Python milter.
|
|||||||
0.8.8 move AddrCache, parse_addr, iniplist, parse_header to Milter package
|
0.8.8 move AddrCache, parse_addr, iniplist, parse_header to Milter package
|
||||||
fix plock for missing source and can't change owner/group
|
fix plock for missing source and can't change owner/group
|
||||||
add sample spfmilter.py milter
|
add sample spfmilter.py milter
|
||||||
|
private_relay config option
|
||||||
0.8.7 Move spf module to pyspf
|
0.8.7 Move spf module to pyspf
|
||||||
Prevent PTR cache poisoning
|
Prevent PTR cache poisoning
|
||||||
More lame bounce heuristics
|
More lame bounce heuristics
|
||||||
|
|||||||
@@ -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.90 2007/01/23 19:46:20 customdesigned
|
||||||
|
# Add private relay.
|
||||||
|
#
|
||||||
# Revision 1.89 2007/01/22 02:46:01 customdesigned
|
# Revision 1.89 2007/01/22 02:46:01 customdesigned
|
||||||
# Convert tabs to spaces.
|
# Convert tabs to spaces.
|
||||||
#
|
#
|
||||||
@@ -359,7 +362,7 @@ def findsrs(fp):
|
|||||||
lnl = ln.lower()
|
lnl = ln.lower()
|
||||||
if lnl.startswith('action:'):
|
if lnl.startswith('action:'):
|
||||||
if lnl.split()[-1] != 'failed': break
|
if lnl.split()[-1] != 'failed': break
|
||||||
for k in ('message-id:','x-mailer:','sender:'):
|
for k in ('message-id:','x-mailer:','sender:','references:'):
|
||||||
if lnl.startswith(k):
|
if lnl.startswith(k):
|
||||||
lastln = ln
|
lastln = ln
|
||||||
break
|
break
|
||||||
@@ -907,6 +910,7 @@ class bmsMilter(Milter.Milter):
|
|||||||
self.log('REJECT: RELAY:',to)
|
self.log('REJECT: RELAY:',to)
|
||||||
self.setreply('550','5.7.1','Unauthorized relay for %s' % domain)
|
self.setreply('550','5.7.1','Unauthorized relay for %s' % domain)
|
||||||
return Milter.REJECT
|
return Milter.REJECT
|
||||||
|
|
||||||
# non DSN mail to SRS address will bounce due to invalid local part
|
# non DSN mail to SRS address will bounce due to invalid local part
|
||||||
canon_to = '@'.join(t)
|
canon_to = '@'.join(t)
|
||||||
self.recipients.append(canon_to)
|
self.recipients.append(canon_to)
|
||||||
@@ -941,8 +945,8 @@ class bmsMilter(Milter.Milter):
|
|||||||
self.reject_spam = False
|
self.reject_spam = False
|
||||||
self.smart_alias(to)
|
self.smart_alias(to)
|
||||||
# get recipient after virtusertable aliasing
|
# get recipient after virtusertable aliasing
|
||||||
#rcpt = self.getsymval("{rcpt_addr}")
|
rcpt = self.getsymval("{rcpt_addr}")
|
||||||
#self.log("rcpt-addr",rcpt);
|
self.log("rcpt-addr",rcpt);
|
||||||
return Milter.CONTINUE
|
return Milter.CONTINUE
|
||||||
|
|
||||||
# Heuristic checks for spam headers
|
# Heuristic checks for spam headers
|
||||||
@@ -1379,7 +1383,9 @@ class bmsMilter(Milter.Milter):
|
|||||||
self.fp.seek(0)
|
self.fp.seek(0)
|
||||||
sender = findsrs(self.fp)
|
sender = findsrs(self.fp)
|
||||||
if sender:
|
if sender:
|
||||||
cbv_cache[sender] = 500,self.delayed_failure,time.time()
|
cbv_cache[sender] = 550,self.delayed_failure
|
||||||
|
# make blacklisting persistent, since delayed DSNs are expensive
|
||||||
|
blacklist[sender] = None
|
||||||
try:
|
try:
|
||||||
# save message for debugging
|
# save message for debugging
|
||||||
fname = tempfile.mktemp(".dsn")
|
fname = tempfile.mktemp(".dsn")
|
||||||
@@ -1596,7 +1602,6 @@ class bmsMilter(Milter.Milter):
|
|||||||
self.log('TEMPFAIL:',desc)
|
self.log('TEMPFAIL:',desc)
|
||||||
self.setreply('450','4.2.0',*desc.splitlines())
|
self.setreply('450','4.2.0',*desc.splitlines())
|
||||||
return Milter.TEMPFAIL
|
return Milter.TEMPFAIL
|
||||||
if len(res) < 3: res += time.time(),
|
|
||||||
cbv_cache[sender] = res
|
cbv_cache[sender] = res
|
||||||
self.log('REJECT:',desc)
|
self.log('REJECT:',desc)
|
||||||
self.setreply('550','5.7.1',*desc.splitlines())
|
self.setreply('550','5.7.1',*desc.splitlines())
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<li><a href="logmsgs.html">Log Messages</a>
|
<li><a href="logmsgs.html">Log Messages</a>
|
||||||
<li><a href="http://bmsi.com/mailman/listinfo/pymilter">Mailing List</a>
|
<li><a href="http://bmsi.com/mailman/listinfo/pymilter">Mailing List</a>
|
||||||
<li><a href="credits.html">CREDITS</a>
|
<li><a href="credits.html">CREDITS</a>
|
||||||
|
<li><a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=139894&type=1" width="88" height="31" border="0" alt="SourceForge.net Logo" /></a>
|
||||||
<h3>Links</h3>
|
<h3>Links</h3>
|
||||||
<li><a href="http://www.milter.org/milter_api/api.html">C API</a>
|
<li><a href="http://www.milter.org/milter_api/api.html">C API</a>
|
||||||
<li><a href="http://www.milter.org/">Milter.Org</a>
|
<li><a href="http://www.milter.org/">Milter.Org</a>
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
- move parse_header to Milter.utils
|
- move parse_header to Milter.utils
|
||||||
- fix plock for missing source and can't change owner/group
|
- fix plock for missing source and can't change owner/group
|
||||||
- add sample spfmilter.py milter
|
- add sample spfmilter.py milter
|
||||||
|
- private_relay config option
|
||||||
* 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
|
||||||
- More lame bounce heuristics
|
- More lame bounce heuristics
|
||||||
- SPF moved to pyspf RPM
|
- SPF moved to pyspf RPM
|
||||||
|
|||||||
+12
-2
@@ -8,13 +8,12 @@ class AddrCacheTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.fname = 'test.dat'
|
self.fname = 'test.dat'
|
||||||
self.cache = AddrCache(fname=self.fname)
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
os.remove(self.fname)
|
os.remove(self.fname)
|
||||||
|
|
||||||
def testAdd(self):
|
def testAdd(self):
|
||||||
cache = self.cache
|
cache = AddrCache(fname=self.fname)
|
||||||
cache['foo@bar.com'] = None
|
cache['foo@bar.com'] = None
|
||||||
cache.addperm('baz@bar.com')
|
cache.addperm('baz@bar.com')
|
||||||
cache['temp@bar.com'] = 'testing'
|
cache['temp@bar.com'] = 'testing'
|
||||||
@@ -26,6 +25,17 @@ class AddrCacheTestCase(unittest.TestCase):
|
|||||||
self.failUnless(len(s) == 2)
|
self.failUnless(len(s) == 2)
|
||||||
self.failUnless(s[0].startswith('foo@bar.com '))
|
self.failUnless(s[0].startswith('foo@bar.com '))
|
||||||
self.assertEquals(s[1].strip(),'baz@bar.com')
|
self.assertEquals(s[1].strip(),'baz@bar.com')
|
||||||
|
# check that new result overrides old
|
||||||
|
cache['temp@bar.com'] = None
|
||||||
|
self.failUnless(not cache['temp@bar.com'])
|
||||||
|
|
||||||
|
def testDomain(self):
|
||||||
|
fp = open(self.fname,'w')
|
||||||
|
print >>fp,'spammer.com'
|
||||||
|
fp.close()
|
||||||
|
cache = AddrCache(fname=self.fname)
|
||||||
|
cache.load(self.fname,30)
|
||||||
|
self.failUnless('spammer.com' in cache)
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
s = unittest.makeSuite(AddrCacheTestCase,'test')
|
s = unittest.makeSuite(AddrCacheTestCase,'test')
|
||||||
|
|||||||
Reference in New Issue
Block a user