Trees | Indices | Help |
---|
|
SPF (Sender Policy Framework) implementation. Copyright (c) 2003, Terence Way Portions Copyright (c) 2004,2005,2006 Stuart Gathman <stuart@bmsi.com> Portions Copyright (c) 2005,2006 Scott Kitterman <scott@kitterman.com> This module is free software, and you may redistribute it and/or modify it under the same terms as Python itself, so long as this copyright message and disclaimer are retained in their original form. IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. For more information about SPF, a tool against email forgery, see http://www.openspf.org/ For news, bugfixes, etc. visit the home page for this implementation at http://www.wayforward.net/spf/ http://sourceforge.net/projects/pymilter/
|
|||
|
bool bool(x) -> bool |
||
|
AmbiguityWarning SPF Warning - ambiguous results |
||
|
TempError Temporary SPF error |
||
|
PermError Permanent SPF error |
||
|
query A query object keeps the relevant information about a single SPF query: |
|
|||
| DNSLookup(name, qtype, strict=True) | ||
|
check2(i,
s,
h,
local=None,
receiver=None) Test an incoming MAIL FROM:<s>, from a client with ip address i. |
||
|
check(i,
s,
h,
local=None,
receiver=None) Test an incoming MAIL FROM:<s>, from a client with ip address i. |
||
|
split_email(s,
h) Given a sender email s and a HELO domain h, create a valid tuple (l, d) local-part and domain-part. |
||
|
quote_value(s) Quote the value for a key-value pair in Received-SPF header field if needed. |
||
|
parse_mechanism(str,
d) Breaks A, MX, IP4, and PTR mechanisms into a (name, domain, cidr,cidr6) tuple. |
||
|
reverse_dots(name) Reverse dotted IP addresses or domain names. |
||
|
domainmatch(ptrs,
domainsuffix) grep for a given domain suffix against a list of validated PTR domain names. |
||
|
addr2bin(str) Convert a string IPv4 address into an unsigned integer. |
||
|
bin2long6(str) Convert binary IP6 address into an unsigned Python long integer. |
||
| expand_one(expansion, str, joiner) | ||
|
split(str,
delimiters,
joiner=None) Split a string into pieces by a set of delimiter characters. |
||
|
insert_libspf_local_policy(spftxt,
local=None) Returns spftxt with local inserted just before last non-fail mechanism. |
||
| _test() |
|
|||
|
__author__ = 'Terence Way'
|
||
|
__email__ = 'terry@wayforward.net'
|
||
|
__version__ = '2.1: January 22, 2007'
|
||
|
MODULE = 'spf'
|
||
|
USAGE = 'To check an incoming mail request:\n % python spf.p...
|
||
|
RE_SPF = <_sre.SRE_Pattern object at 0xb7c9a5a0>
|
||
|
RE_MODIFIER = <_sre.SRE_Pattern object at 0xb7f13da0>
|
||
|
PAT_CHAR = '%(%|_|-|(\\{[^\\}]*\\}))'
|
||
|
RE_CHAR = <_sre.SRE_Pattern object at 0xb7cb5210>
|
||
|
RE_ARGS = <_sre.SRE_Pattern object at 0xb7f1db60>
|
||
|
RE_DUAL_CIDR = <_sre.SRE_Pattern object at 0xb7f1dc50>
|
||
|
RE_CIDR = <_sre.SRE_Pattern object at 0xb7c859c0>
|
||
|
PAT_IP4 = '(?:\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(?:\\d...
|
||
|
RE_IP4 = <_sre.SRE_Pattern object at 0x85f8db0>
|
||
|
RE_TOPLAB = <_sre.SRE_Pattern object at 0x85f5fd8>
|
||
|
RE_DOT_ATOM = <_sre.SRE_Pattern object at 0xb7c9e520>
|
||
|
RE_IP6 = <_sre.SRE_Pattern object at 0x8686e00>
|
||
|
JOINERS = {'s': '.', 'l': '.'}
|
||
|
RESULTS = {'permerror': 'permerror', 'none': 'none', 'ambiguou...
|
||
|
EXPLANATIONS = {'permerror': 'permanent error in processing', 'none...
|
||
|
DELEGATE = None
|
||
|
DEFAULT_SPF = 'v=spf1 a/24 mx/24 ptr'
|
||
|
TRUSTED_FORWARDERS = 'v=spf1 ?include:spf.trusted-forwarder.org -all'
|
||
|
MAX_LOOKUP = 10
|
||
|
MAX_MX = 10
|
||
|
MAX_PTR = 10
|
||
|
MAX_CNAME = 10
|
||
|
MAX_RECURSION = 20
|
||
|
ALL_MECHANISMS = ('a', 'mx', 'ptr', 'exists', 'include', 'ip4', 'ip6'...
|
||
|
COMMON_MISTAKES = {'all.': 'all', 'prt': 'ptr', 'ipv6': 'ip6', 'ipv4':...
|
||
|
q = query(i= i, s= s, h= h, receiver= socket.gethostname...
|
||
|
False = False
|
||
|
True = True
|
|
|
Test an incoming MAIL FROM:<s>, from a client with ip address i. h is the HELO/EHLO domain name. This is the RFC4408 compliant pySPF2.0 interface. The interface returns an SPF result and explanation only. SMTP response codes are not returned since RFC 4408 does not specify receiver policy. Applications updated for RFC 4408 should use this interface. Returns (result, explanation) where result in ['pass', 'permerror', 'fail', 'temperror', 'softfail', 'none', 'neutral' ]. Example: #>>> check2(i='61.51.192.42', s='liukebing@bcc.com', h='bmsi.com') |
Test an incoming MAIL FROM:<s>, from a client with ip address i. h is the HELO/EHLO domain name. This is the pre-RFC SPF Classic interface. Applications written for pySPF 1.6/1.7 can use this interface to allow pySPF2 to be a drop in replacement for older versions. With the exception of result codes, performance in RFC 4408 compliant. Returns (result, code, explanation) where result in ['pass', 'unknown', 'fail', 'error', 'softfail', 'none', 'neutral' ]. Example: #>>> check(i='61.51.192.42', s='liukebing@bcc.com', h='bmsi.com') |
>>> split_email('', 'wayforward.net') ('postmaster', 'wayforward.net') >>> split_email('foo.com', 'wayforward.net') ('postmaster', 'foo.com') >>> split_email('terry@wayforward.net', 'optsw.com') ('terry', 'wayforward.net') |
>>> quote_value('foo@bar.com') '"foo@bar.com"' >>> quote_value('mail.example.com') 'mail.example.com' >>> quote_value('A:1.2.3.4') '"A:1.2.3.4"' >>> quote_value('abc"def') '"abc\\"def"' >>> quote_value(r'abc\def') '"abc\\\\def"' >>> quote_value('abc..def') '"abc..def"' >>> quote_value('') '""' >>> quote_value(None) |
Breaks A, MX, IP4, and PTR mechanisms into a (name, domain, cidr,cidr6) tuple. The domain portion defaults to d if not present, the cidr defaults to 32 if not present. Examples:>>> parse_mechanism('a', 'foo.com') ('a', 'foo.com', None, None) >>> parse_mechanism('exists','foo.com') ('exists', None, None, None) >>> parse_mechanism('a:bar.com', 'foo.com') ('a', 'bar.com', None, None) >>> parse_mechanism('a/24', 'foo.com') ('a', 'foo.com', 24, None) >>> parse_mechanism('A:foo:bar.com/16//48', 'foo.com') ('a', 'foo:bar.com', 16, 48) >>> parse_mechanism('-exists:%{i}.%{s1}.100/86400.rate.%{d}','foo.com') ('-exists', '%{i}.%{s1}.100/86400.rate.%{d}', None, None) >>> parse_mechanism('mx:%%%_/.Claranet.de/27','foo.com') ('mx', '%%%_/.Claranet.de', 27, None) >>> parse_mechanism('mx:%{d}//97','foo.com') ('mx', '%{d}', None, 97) >>> parse_mechanism('iP4:192.0.0.0/8','foo.com') ('ip4', '192.0.0.0', 8, None) |
Reverse dotted IP addresses or domain names. Examples:>>> reverse_dots('192.168.0.145') '145.0.168.192' >>> reverse_dots('email.example.com') 'com.example.email' |
grep for a given domain suffix against a list of validated PTR domain names. Examples:>>> domainmatch(['FOO.COM'], 'foo.com') 1 >>> domainmatch(['moo.foo.com'], 'FOO.COM') 1 >>> domainmatch(['moo.bar.com'], 'foo.com') 0 |
Convert a string IPv4 address into an unsigned integer. Examples:>>> addr2bin('127.0.0.1') 2130706433L >>> addr2bin('127.0.0.1') == socket.INADDR_LOOPBACK 1 >>> addr2bin('255.255.255.254') 4294967294L >>> addr2bin('192.168.0.1') 3232235521LUnlike DNS.addr2bin, the n, n.n, and n.n.n forms for IP addresses are handled as well: >>> addr2bin('10.65536') 167837696L >>> 10 * (2 ** 24) + 65536 167837696 >>> addr2bin('10.93.512') 173867520L >>> 10 * (2 ** 24) + 93 * (2 ** 16) + 512 173867520 |
|
|
Split a string into pieces by a set of delimiter characters. The resulting list is delimited by joiner, or the original delimiter if joiner is not specified. Examples:>>> split('192.168.0.45', '.') ['192', '.', '168', '.', '0', '.', '45'] >>> split('terry@wayforward.net', '@.') ['terry', '@', 'wayforward', '.', 'net'] >>> split('terry@wayforward.net', '@.', '.') ['terry', '.', 'wayforward', '.', 'net'] |
Returns spftxt with local inserted just before last non-fail mechanism. This is how the libspf{2} libraries handle "local-policy". Examples:>>> insert_libspf_local_policy('v=spf1 -all') 'v=spf1 -all' >>> insert_libspf_local_policy('v=spf1 -all','mx') 'v=spf1 -all' >>> insert_libspf_local_policy('v=spf1','a mx ptr') 'v=spf1 a mx ptr' >>> insert_libspf_local_policy('v=spf1 mx -all','a ptr') 'v=spf1 mx a ptr -all' >>> insert_libspf_local_policy('v=spf1 mx -include:foo.co +all','a ptr') 'v=spf1 mx a ptr -include:foo.co +all'# FIXME: is this right? If so, "last non-fail" is a bogus description. >>> insert_libspf_local_policy('v=spf1 mx ?include:foo.co +all','a ptr') 'v=spf1 mx a ptr ?include:foo.co +all' >>> spf='v=spf1 ip4:1.2.3.4 -a:example.net -all' >>> local='ip4:192.0.2.3 a:example.org' >>> insert_libspf_local_policy(spf,local) 'v=spf1 ip4:1.2.3.4 ip4:192.0.2.3 a:example.org -a:example.net -all' |
|
|
__author__None
|
__email__None
|
__version__None
|
MODULENone
|
USAGENone
|
RE_SPFNone
|
RE_MODIFIERNone
|
PAT_CHARNone
|
RE_CHARNone
|
RE_ARGSNone
|
RE_DUAL_CIDRNone
|
RE_CIDRNone
|
PAT_IP4None
|
RE_IP4None
|
RE_TOPLABNone
|
RE_DOT_ATOMNone
|
RE_IP6None
|
JOINERSNone
|
RESULTSNone
|
EXPLANATIONSNone
|
DELEGATENone
|
DEFAULT_SPFNone
|
TRUSTED_FORWARDERSNone
|
MAX_LOOKUPNone
|
MAX_MXNone
|
MAX_PTRNone
|
MAX_CNAMENone
|
MAX_RECURSIONNone
|
ALL_MECHANISMSNone
|
COMMON_MISTAKESNone
|
qNone
|
FalseNone
|
TrueNone
|
Trees | Indices | Help |
---|
Generated by Epydoc 3.0alpha3 on Fri Jan 26 00:04:42 2007 | http://epydoc.sourceforge.net |