Limit CNAME chains independently of DNS lookup limit

This commit is contained in:
Stuart Gathman
2005-07-22 16:00:23 +00:00
parent 0cbfc0d249
commit 8df5cd026e
3 changed files with 62 additions and 20 deletions
+9 -2
View File
@@ -24,7 +24,7 @@ ALT="Viewable With Any Browser" BORDER="0"></A>
Stuart D. Gathman</a><br> Stuart D. Gathman</a><br>
This web page is written by Stuart D. Gathman<br>and<br>sponsored by This web page is written by Stuart D. Gathman<br>and<br>sponsored by
<a href="http://www.bmsi.com">Business Management Systems, Inc.</a> <br> <a href="http://www.bmsi.com">Business Management Systems, Inc.</a> <br>
Last updated Jun 09, 2005</h4> Last updated Jul 20, 2005</h4>
See the <a href="faq.html">FAQ</a> | <a href="http://sourceforge.net/project/showfiles.php?group_id=139894">Download now</a> | See the <a href="faq.html">FAQ</a> | <a href="http://sourceforge.net/project/showfiles.php?group_id=139894">Download now</a> |
<a href="/mailman/listinfo/pymilter">Subscribe to mailing list</a> | <a href="/mailman/listinfo/pymilter">Subscribe to mailing list</a> |
@@ -49,7 +49,14 @@ efficient and secure. I recommend upgrading.
Python milter is being moved to Python milter is being moved to
<a href="http://sourceforge.net/projects/pymilter/">pymilter Sourceforge <a href="http://sourceforge.net/projects/pymilter/">pymilter Sourceforge
project</a> for development. project</a> for development and release downloads.
<p>
Release 0.8.2 has changes to SPF to bring it in line with the newly
official RFC. It adds SES support (the original SES without body hash)
for pysrs-0.30.10, and honeypot support for pydspam-1.1.9. There is
a new method in the base milter module. milter.set_exception_policy(i)
lets you choose a policy of CONTINUE, REJECT, or TEMPFAIL (default) for
untrapped exceptions encountered in a milter callback.
<p> <p>
Release 0.8.0 is the first <a href="http://sourceforge.net/">Sourceforge</a> Release 0.8.0 is the first <a href="http://sourceforge.net/">Sourceforge</a>
release. It supports Python-2.4, and provides an option to accept mail release. It supports Python-2.4, and provides an option to accept mail
+9 -4
View File
@@ -1,6 +1,6 @@
%define name milter %define name milter
%define version 0.8.2 %define version 0.8.2
%define release 2.RH7 %define release 4.RH7
# what version of RH are we building for? # what version of RH are we building for?
%define redhat9 0 %define redhat9 0
%define redhat7 1 %define redhat7 1
@@ -31,7 +31,7 @@ Name: %{name}
Version: %{version} Version: %{version}
Release: %{release} Release: %{release}
Source: %{name}-%{version}.tar.gz Source: %{name}-%{version}.tar.gz
#Patch: %{name}-%{version}.patch Patch: %{name}-%{version}.patch
Copyright: GPL Copyright: GPL
Group: Development/Libraries Group: Development/Libraries
BuildRoot: %{_tmppath}/%{name}-buildroot BuildRoot: %{_tmppath}/%{name}-buildroot
@@ -52,7 +52,7 @@ modules provide for navigating and modifying MIME parts.
%prep %prep
%setup %setup
#%patch -p1 %patch -p1
%build %build
env CFLAGS="$RPM_OPT_FLAGS" %{python} setup.py build env CFLAGS="$RPM_OPT_FLAGS" %{python} setup.py build
@@ -166,6 +166,12 @@ rm -rf $RPM_BUILD_ROOT
/usr/share/sendmail-cf/hack/rhsbl.m4 /usr/share/sendmail-cf/hack/rhsbl.m4
%changelog %changelog
* Fri Jul 15 2005 Stuart Gathman <stuart@bmsi.com> 0.8.2-4
- Limit each CNAME chain independently like PTR and MX
* Fri Jul 15 2005 Stuart Gathman <stuart@bmsi.com> 0.8.2-3
- Limit CNAME lookups (regression)
* Fri Jul 15 2005 Stuart Gathman <stuart@bmsi.com> 0.8.2-2
- Handle corrupt ZIP attachments
* Fri Jul 15 2005 Stuart Gathman <stuart@bmsi.com> 0.8.2-1 * Fri Jul 15 2005 Stuart Gathman <stuart@bmsi.com> 0.8.2-1
- Strict processing limits per SPF RFC - Strict processing limits per SPF RFC
- Fixed several parsing bugs under RFC - Fixed several parsing bugs under RFC
@@ -174,7 +180,6 @@ rm -rf $RPM_BUILD_ROOT
- Extended SPF processing results beyond strict RFC limits - Extended SPF processing results beyond strict RFC limits
- Support original SES for local bounce protection (requires pysrs-0.30.10) - Support original SES for local bounce protection (requires pysrs-0.30.10)
- Callback exception processing option in milter module - Callback exception processing option in milter module
- Handle corrupt ZIP attachments
* Thu Jun 16 2005 Stuart Gathman <stuart@bmsi.com> 0.8.1-1 * Thu Jun 16 2005 Stuart Gathman <stuart@bmsi.com> 0.8.1-1
- Fix zip in zip loop in mime.py - Fix zip in zip loop in mime.py
- Fix HeaderParseError in bms.py header callback - Fix HeaderParseError in bms.py header callback
+44 -14
View File
@@ -47,8 +47,24 @@ For news, bugfixes, etc. visit the home page for this implementation at
# Terrence is not responding to email. # Terrence is not responding to email.
# #
# $Log$ # $Log$
# Revision 1.11 2005/07/20 03:30:04 customdesigned # Revision 1.31 2005/07/22 02:11:50 customdesigned
# Check pydspam version for honeypot, include latest pyspf changes. # Use dictionary to check for CNAME loops. Check limit independently for
# each top level name, just like for PTR.
#
# Revision 1.30 2005/07/21 20:07:31 customdesigned
# Translate DNS error in DNSLookup. This completely isolates DNS
# dependencies to the DNSLookup method.
#
# Revision 1.29 2005/07/21 17:49:39 customdesigned
# My best guess at what RFC intended for limiting CNAME loops.
#
# Revision 1.28 2005/07/21 17:37:08 customdesigned
# Break out external DNSLookup method so that test suite can
# duplicate CNAME loop bug. Test zone data dictionary now
# mirrors structure of real DNS.
#
# Revision 1.27 2005/07/21 15:26:06 customdesigned
# First cut at updating docs. Test suite is obsolete.
# #
# Revision 1.26 2005/07/20 03:12:40 customdesigned # Revision 1.26 2005/07/20 03:12:40 customdesigned
# When not in strict mode, don't give PermErr for bad mechanism until # When not in strict mode, don't give PermErr for bad mechanism until
@@ -256,6 +272,16 @@ if not hasattr(DNS.Type,'SPF'):
DNS.Type.typemap[99] = 'SPF' DNS.Type.typemap[99] = 'SPF'
DNS.Lib.RRunpacker.getSPFdata = DNS.Lib.RRunpacker.getTXTdata DNS.Lib.RRunpacker.getSPFdata = DNS.Lib.RRunpacker.getTXTdata
def DNSLookup(name,qtype):
try:
req = DNS.DnsRequest(name, qtype=qtype)
resp = req.req()
#resp.show()
# key k: ('wayforward.net', 'A'), value v
return [((a['name'], a['typename']), a['data']) for a in resp.answers]
except DNS.DNSError,x:
raise TempError,'DNS ' + str(x)
# 32-bit IPv4 address mask # 32-bit IPv4 address mask
MASK = 0xFFFFFFFFL MASK = 0xFFFFFFFFL
@@ -308,6 +334,7 @@ DEFAULT_SPF = 'v=spf1 a/24 mx/24 ptr'
MAX_LOOKUP = 10 #draft-schlitt-spf-classic-02 Para 10.1 MAX_LOOKUP = 10 #draft-schlitt-spf-classic-02 Para 10.1
MAX_MX = 10 #draft-schlitt-spf-classic-02 Para 10.1 MAX_MX = 10 #draft-schlitt-spf-classic-02 Para 10.1
MAX_PTR = 10 #draft-schlitt-spf-classic-02 Para 10.1 MAX_PTR = 10 #draft-schlitt-spf-classic-02 Para 10.1
MAX_CNAME = 10 # analogous interpretation to MAX_PTR
MAX_RECURSION = 20 MAX_RECURSION = 20
ALL_MECHANISMS = ('a', 'mx', 'ptr', 'exists', 'include', 'ip4', 'ip6', 'all') ALL_MECHANISMS = ('a', 'mx', 'ptr', 'exists', 'include', 'ip4', 'ip6', 'all')
COMMON_MISTAKES = { 'prt': 'ptr', 'ip': 'ip4', 'ipv4': 'ip4', 'ipv6': 'ip6' } COMMON_MISTAKES = { 'prt': 'ptr', 'ip': 'ip4', 'ipv4': 'ip4', 'ipv6': 'ip6' }
@@ -412,6 +439,9 @@ class query(object):
>>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ?all moo') >>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ?all moo')
('unknown', 550, 'SPF Permanent Error: Unknown mechanism found: moo') ('unknown', 550, 'SPF Permanent Error: Unknown mechanism found: moo')
>>> q.check(spf='v=spf1 =a ?all moo')
('unknown', 550, 'SPF Permanent Error: Unknown qualifier, IETF draft para 4.6.1, found in: =a')
>>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ~all') >>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ~all')
('pass', 250, 'sender SPF verified') ('pass', 250, 'sender SPF verified')
@@ -453,8 +483,6 @@ class query(object):
self.perm_error.ext = rc self.perm_error.ext = rc
raise self.perm_error raise self.perm_error
return rc return rc
except DNS.DNSError,x:
return ('error', 450, 'SPF DNS Error: ' + str(x))
except TempError,x: except TempError,x:
return ('error', 450, 'SPF Temporary Error: ' + str(x)) return ('error', 450, 'SPF Temporary Error: ' + str(x))
except PermError,x: except PermError,x:
@@ -847,7 +875,7 @@ class query(object):
"""Get a list of domain names for an IP address.""" """Get a list of domain names for an IP address."""
return self.dns(reverse_dots(i) + ".in-addr.arpa", 'PTR') return self.dns(reverse_dots(i) + ".in-addr.arpa", 'PTR')
def dns(self, name, qtype): def dns(self, name, qtype, cnames=None):
"""DNS query. """DNS query.
If the result is in cache, return that. Otherwise pull the If the result is in cache, return that. Otherwise pull the
@@ -864,19 +892,21 @@ class query(object):
result = self.cache.get( (name, qtype) ) result = self.cache.get( (name, qtype) )
cname = None cname = None
if not result: if not result:
req = DNS.DnsRequest(name, qtype=qtype) for k,v in DNSLookup(name,qtype):
resp = req.req()
#resp.show()
for a in resp.answers:
# key k: ('wayforward.net', 'A'), value v
k, v = (a['name'], a['typename']), a['data']
if k == (name, 'CNAME'): if k == (name, 'CNAME'):
cname = v cname = v
self.cache.setdefault(k, []).append(v) self.cache.setdefault(k, []).append(v)
result = self.cache.get( (name, qtype), []) result = self.cache.get( (name, qtype), [])
if not result and cname: if not result and cname:
self.check_lookups() if not cnames:
result = self.dns(cname, qtype) cnames = {}
elif len(cnames) >= MAX_CNAME:
raise PermError(
'Length of CNAME chain exceeds %d' % MAX_CNAME)
cnames[name] = cname
if cname in cnames:
raise PermError,'CNAME loop'
result = self.dns(cname, qtype, cnames=cnames)
return result return result
def get_header(self,res,receiver=None): def get_header(self,res,receiver=None):