Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
P
pymilter
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Container registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
misc
pymilter
Commits
ef413913
Commit
ef413913
authored
20 years ago
by
Stuart Gathman
Browse files
Options
Downloads
Patches
Plain Diff
Allow extended processing for MX count.
parent
8ad4b161
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
spf.py
+52
-23
52 additions, 23 deletions
spf.py
with
52 additions
and
23 deletions
spf.py
+
52
−
23
View file @
ef413913
...
@@ -47,6 +47,23 @@ For news, bugfixes, etc. visit the home page for this implementation at
...
@@ -47,6 +47,23 @@ 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/15 18:03:02 customdesigned
# Fix unknown Received-SPF header broken by result changes
#
# Revision 1.10 2005/07/15 16:17:05 customdesigned
# Start type99 support.
# Make Scott's "/" support in parse_mechanism more elegant as requested.
# Add test case for "/" support.
#
# Revision 1.9 2005/07/15 03:33:14 kitterma
# Fix for bug 1238403 - Crash if non-CIDR / present. Also added
# validation check for valid IPv4 CIDR range.
#
# Revision 1.8 2005/07/14 04:18:01 customdesigned
# Bring explanations and Received-SPF header into line with
# the unknown=PermErr and error=TempErr convention.
# Hope my case-sensitive mech fix doesn't clash with Scotts.
#
# Revision 1.7 2005/07/12 21:43:56 kitterma
# Revision 1.7 2005/07/12 21:43:56 kitterma
# Added processing to clarify some cases of unknown
# Added processing to clarify some cases of unknown
# qualifier errors (to distinguish between unknown qualifier and
# qualifier errors (to distinguish between unknown qualifier and
...
@@ -189,6 +206,8 @@ RE_CHAR = re.compile(r'%(%|_|-|(\{[a-zA-Z][0-9]*r?[^\}]*\}))')
...
@@ -189,6 +206,8 @@ RE_CHAR = re.compile(r'%(%|_|-|(\{[a-zA-Z][0-9]*r?[^\}]*\}))')
# Regular expression to break up a macro expansion
# Regular expression to break up a macro expansion
RE_ARGS
=
re
.
compile
(
r
'
([0-9]*)(r?)([^0-9a-zA-Z]*)
'
)
RE_ARGS
=
re
.
compile
(
r
'
([0-9]*)(r?)([^0-9a-zA-Z]*)
'
)
RE_CIDR
=
re
.
compile
(
r
'
/(1[0-9]*|2[0-9]*|3[0-2]*)$
'
)
# Local parts and senders have their delimiters replaced with '.' during
# Local parts and senders have their delimiters replaced with '.' during
# macro expansion
# macro expansion
#
#
...
@@ -196,11 +215,12 @@ JOINERS = {'l': '.', 's': '.'}
...
@@ -196,11 +215,12 @@ JOINERS = {'l': '.', 's': '.'}
RESULTS
=
{
'
+
'
:
'
pass
'
,
'
-
'
:
'
fail
'
,
'
?
'
:
'
neutral
'
,
'
~
'
:
'
softfail
'
,
RESULTS
=
{
'
+
'
:
'
pass
'
,
'
-
'
:
'
fail
'
,
'
?
'
:
'
neutral
'
,
'
~
'
:
'
softfail
'
,
'
pass
'
:
'
pass
'
,
'
fail
'
:
'
fail
'
,
'
unknown
'
:
'
unknown
'
,
'
pass
'
:
'
pass
'
,
'
fail
'
:
'
fail
'
,
'
unknown
'
:
'
unknown
'
,
'
neutral
'
:
'
neutral
'
,
'
softfail
'
:
'
softfail
'
,
'
error
'
:
'
error
'
,
'
neutral
'
:
'
neutral
'
,
'
softfail
'
:
'
softfail
'
,
'
none
'
:
'
none
'
,
'
deny
'
:
'
fail
'
}
'
none
'
:
'
none
'
,
'
deny
'
:
'
fail
'
}
EXPLANATIONS
=
{
'
pass
'
:
'
sender SPF verified
'
,
'
fail
'
:
'
access denied
'
,
EXPLANATIONS
=
{
'
pass
'
:
'
sender SPF verified
'
,
'
fail
'
:
'
access denied
'
,
'
unknown
'
:
'
SPF unknown (PermError)
'
,
'
unknown
'
:
'
permanent error in processing
'
,
'
error
'
:
'
temporary error in processing
'
,
'
softfail
'
:
'
domain in transition
'
,
'
softfail
'
:
'
domain in transition
'
,
'
neutral
'
:
'
access neither permitted nor denied
'
,
'
neutral
'
:
'
access neither permitted nor denied
'
,
'
none
'
:
''
'
none
'
:
''
...
@@ -345,11 +365,11 @@ class query(object):
...
@@ -345,11 +365,11 @@ class query(object):
return
(
'
error
'
,
450
,
'
SPF Temporary Error:
'
+
str
(
x
))
return
(
'
error
'
,
450
,
'
SPF Temporary Error:
'
+
str
(
x
))
except
PermError
,
x
:
except
PermError
,
x
:
self
.
prob
=
x
.
msg
self
.
prob
=
x
.
msg
if
x
.
mech
:
self
.
mech
.
append
(
x
.
mech
)
self
.
mech
.
append
(
x
.
mech
)
# Pre-Lentczner draft treats this as an unknown result
# Pre-Lentczner draft treats this as an unknown result
# and equivalent to no SPF record.
# and equivalent to no SPF record.
return
(
'
unknown
'
,
550
,
'
SPF Permanent Error:
'
+
str
(
x
))
return
(
'
unknown
'
,
550
,
'
SPF Permanent Error:
'
+
str
(
x
))
# return ('error', 550, 'SPF Permanent Error: ' + str(x))
def
check1
(
self
,
spf
,
domain
,
recursion
):
def
check1
(
self
,
spf
,
domain
,
recursion
):
# spf rfc: 3.7 Processing Limits
# spf rfc: 3.7 Processing Limits
...
@@ -393,8 +413,7 @@ class query(object):
...
@@ -393,8 +413,7 @@ class query(object):
if
len
(
m
)
!=
2
:
continue
if
len
(
m
)
!=
2
:
continue
if
m
[
0
]
==
'
exp
'
:
if
m
[
0
]
==
'
exp
'
:
exps
[
'
fail
'
]
=
exps
[
'
unknown
'
]
=
\
self
.
set_default_explanation
(
self
.
get_explanation
(
m
[
1
]))
self
.
get_explanation
(
m
[
1
])
elif
m
[
0
]
==
'
redirect
'
:
elif
m
[
0
]
==
'
redirect
'
:
self
.
check_lookups
()
self
.
check_lookups
()
redirect
=
self
.
expand
(
m
[
1
])
redirect
=
self
.
expand
(
m
[
1
])
...
@@ -502,7 +521,7 @@ class query(object):
...
@@ -502,7 +521,7 @@ class query(object):
# fine tune the error).
# fine tune the error).
# eat one character and try again:
# eat one character and try again:
m
=
m
[
1
:]
m
=
m
[
1
:]
if
m
in
[
'
a
'
,
'
mx
'
,
'
ptr
'
,
'
exists
'
,
'
include
'
,
'
ip4
'
,
'
ip6
'
,
'
all
'
]
:
if
m
in
(
'
a
'
,
'
mx
'
,
'
ptr
'
,
'
exists
'
,
'
include
'
,
'
ip4
'
,
'
ip6
'
,
'
all
'
)
:
raise
PermError
(
'
Unknown qualifier, IETF draft para 4.6.1, found in
'
,
mech
)
raise
PermError
(
'
Unknown qualifier, IETF draft para 4.6.1, found in
'
,
mech
)
else
:
else
:
raise
PermError
(
'
Unknown mechanism found
'
,
mech
)
raise
PermError
(
'
Unknown mechanism found
'
,
mech
)
...
@@ -636,13 +655,16 @@ class query(object):
...
@@ -636,13 +655,16 @@ class query(object):
is found.
is found.
"""
"""
a
=
[
t
for
t
in
self
.
dns_txt
(
domain
)
if
t
.
startswith
(
'
v=spf1
'
)]
a
=
[
t
for
t
in
self
.
dns_txt
(
domain
)
if
t
.
startswith
(
'
v=spf1
'
)]
if
not
a
:
if
len
(
a
)
==
1
:
return
a
[
0
]
#a = [t for t in self.dns_99(domain) if t.startswith('v=spf1')]
#if len(a) == 1:
# return a[0]
if
DELEGATE
:
if
DELEGATE
:
a
=
[
t
a
=
[
t
for
t
in
self
.
dns_txt
(
domain
+
'
._spf.
'
+
DELEGATE
)
for
t
in
self
.
dns_txt
(
domain
+
'
._spf.
'
+
DELEGATE
)
if
t
.
startswith
(
'
v=spf1
'
)
if
t
.
startswith
(
'
v=spf1
'
)
]
]
if
len
(
a
)
==
1
:
if
len
(
a
)
==
1
:
return
a
[
0
]
return
a
[
0
]
return
None
return
None
...
@@ -652,6 +674,11 @@ class query(object):
...
@@ -652,6 +674,11 @@ class query(object):
if
domainname
:
if
domainname
:
return
[
''
.
join
(
a
)
for
a
in
self
.
dns
(
domainname
,
'
TXT
'
)]
return
[
''
.
join
(
a
)
for
a
in
self
.
dns
(
domainname
,
'
TXT
'
)]
return
[]
return
[]
def
dns_99
(
self
,
domainname
):
"
Get a list of TYPE99 records for a domain name.
"
if
domainname
:
return
[
''
.
join
(
a
)
for
a
in
self
.
dns
(
domainname
,
'
TYPE99
'
)]
return
[]
def
dns_mx
(
self
,
domainname
):
def
dns_mx
(
self
,
domainname
):
"""
Get a list of IP addresses for all MX exchanges for a
"""
Get a list of IP addresses for all MX exchanges for a
...
@@ -718,7 +745,9 @@ class query(object):
...
@@ -718,7 +745,9 @@ class query(object):
result
=
self
.
dns
(
cname
,
qtype
)
result
=
self
.
dns
(
cname
,
qtype
)
return
result
return
result
def
get_header
(
self
,
res
,
receiver
):
def
get_header
(
self
,
res
,
receiver
=
None
):
if
not
receiver
:
receiver
=
self
.
r
if
res
in
(
'
pass
'
,
'
fail
'
,
'
softfail
'
):
if
res
in
(
'
pass
'
,
'
fail
'
,
'
softfail
'
):
return
'
%s (%s: %s) client-ip=%s; envelope-from=%s; helo=%s;
'
%
(
return
'
%s (%s: %s) client-ip=%s; envelope-from=%s; helo=%s;
'
%
(
res
,
receiver
,
self
.
get_header_comment
(
res
),
self
.
i
,
res
,
receiver
,
self
.
get_header_comment
(
res
),
self
.
i
,
...
@@ -749,10 +778,10 @@ class query(object):
...
@@ -749,10 +778,10 @@ class query(object):
%
(
self
.
i
,
sender
)
%
(
self
.
i
,
sender
)
#"%s does not designate permitted sender hosts" % sender
#"%s does not designate permitted sender hosts" % sender
elif
res
==
'
unknown
'
:
return
\
elif
res
==
'
unknown
'
:
return
\
"
error in processing
during lookup of
domain of %s: %s
"
\
"
permanent
error in processing domain of %s: %s
"
\
%
(
sender
,
self
.
prob
)
%
(
sender
,
self
.
prob
)
elif
res
==
'
error
'
:
return
\
elif
res
==
'
error
'
:
return
\
"
error in processing during lookup of %s
"
%
sender
"
temporary
error in processing during lookup of %s
"
%
sender
elif
res
==
'
fail
'
:
return
\
elif
res
==
'
fail
'
:
return
\
"
domain of %s does not designate %s as permitted sender
"
\
"
domain of %s does not designate %s as permitted sender
"
\
%
(
sender
,
self
.
i
)
%
(
sender
,
self
.
i
)
...
@@ -796,19 +825,19 @@ def parse_mechanism(str, d):
...
@@ -796,19 +825,19 @@ def parse_mechanism(str, d):
>>>
parse_mechanism
(
'
a/24
'
,
'
foo.com
'
)
>>>
parse_mechanism
(
'
a/24
'
,
'
foo.com
'
)
(
'
a
'
,
'
foo.com
'
,
24
)
(
'
a
'
,
'
foo.com
'
,
24
)
>>>
parse_mechanism
(
'
a:bar.com/16
'
,
'
foo.com
'
)
(
'
a
'
,
'
bar.com
'
,
16
)
>>>
parse_mechanism
(
'
A:bar.com/16
'
,
'
foo.com
'
)
>>>
parse_mechanism
(
'
A:bar.com/16
'
,
'
foo.com
'
)
(
'
a
'
,
'
bar.com
'
,
16
)
(
'
a
'
,
'
bar.com
'
,
16
)
>>>
parse_mechanism
(
'
-exists:%{i}.%{s1}.100/86400.rate.%{d}
'
,
'
foo.com
'
)
(
'
-exists
'
,
'
%{i}.%{s1}.100/86400.rate.%{d}
'
,
32
)
"""
"""
a
=
str
.
split
(
'
/
'
)
a
=
RE_CIDR
.
split
(
str
)
if
len
(
a
)
==
2
:
if
len
(
a
)
==
3
:
a
,
port
=
a
[
0
],
int
(
a
[
1
])
a
,
port
=
a
[
0
],
int
(
a
[
1
])
else
:
else
:
a
,
port
=
str
,
32
a
,
port
=
str
,
32
b
=
a
.
split
(
'
:
'
)
b
=
a
.
split
(
'
:
'
,
1
)
if
len
(
b
)
==
2
:
if
len
(
b
)
==
2
:
return
b
[
0
].
lower
(),
b
[
1
],
port
return
b
[
0
].
lower
(),
b
[
1
],
port
else
:
else
:
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment