Module spf :: Class query
[hide private]
[frames] | no frames]

Class query

source code

object --+
         |
        query

A query object keeps the relevant information about a single SPF query:

This is also, by design, the same variables used in SPF macro expansion.

Also keeps cache: DNS cache.

Instance Methods [hide private]
  __init__(self, i, s, h, local=None, receiver=None, strict=True)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
  set_ip(self, i)
Set connect ip, and ip6 or ip4 mode.
  set_default_explanation(self, exp)
  set_explanation(self, exp)
  getp(self)
  best_guess(self, spf=DEFAULT_SPF)
Return a best guess based on a default SPF record.
  check(self, spf=None)
Returns (result, mta-status-code, explanation) where result in ['fail', 'softfail', 'neutral' 'permerror', 'pass', 'temperror', 'none']
  check1(self, spf, domain, recursion)
  note_error(self, *msg)
  expand_domain(self, arg)
validate and expand domain-spec
  validate_mechanism(self, mech)
Parse and validate a mechanism.
  check0(self, spf, recursion)
Test this query information against SPF text.
  check_lookups(self)
  get_explanation(self, spec)
Expand an explanation.
  expand(self, str, stripdot=True)
Do SPF RFC macro expansion.
  dns_spf(self, domain)
Get the SPF record recorded in DNS for a specific domain name.
  dns_txt(self, domainname)
Get a list of TXT records for a domain name.
  dns_99(self, domainname)
Get a list of type SPF=99 records for a domain name.
  dns_mx(self, domainname)
Get a list of IP addresses for all MX exchanges for a domain name.
  dns_a(self, domainname, A='A')
Get a list of IP addresses for a domainname.
  validated_ptrs(self)
Figure out the validated PTR domain names for the connect IP.
  dns_ptr(self, i)
Get a list of domain names for an IP address.
  dns(self, name, qtype, cnames=None)
DNS query.
  cidrmatch(self, ipaddrs, n)
Match connect IP against a list of other IP addresses.
  get_header(self, res, receiver=None)
  get_header_comment(self, res)
Return comment for Received-SPF header.

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__


Class Variables [hide private]
  SAFE2CACHE = {('TXT', 'TXT'): None, ('A', 'A'): None, ('MX', 'MX'...

Properties [hide private]

Inherited from object: __class__


Method Details [hide private]

__init__(self, i, s, h, local=None, receiver=None, strict=True)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

set_ip(self, i)

source code 
Set connect ip, and ip6 or ip4 mode.

set_default_explanation(self, exp)

source code 
None

set_explanation(self, exp)

source code 
None

getp(self)

source code 
None

best_guess(self, spf=DEFAULT_SPF)

source code 
Return a best guess based on a default SPF record. >>> q = query('1.2.3.4','','SUPERVISION1',receiver='example.com') >>> q.best_guess()[0] 'none'

check(self, spf=None)

source code 

Returns (result, mta-status-code, explanation) where result in ['fail', 'softfail', 'neutral' 'permerror', 'pass', 'temperror', 'none']

Examples: >>> q = query(s='strong-bad@email.example.com', ... h='mx.example.org', i='192.0.2.3') >>> q.check(spf='v=spf1 ?all') ('neutral', 250, 'access neither permitted nor denied')
>>> q.check(spf='v=spf1 redirect=controlledmail.com exp=_exp.controlledmail.com')
('fail', 550, 'SPF fail - not authorized')
>>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ?all moo')
('permerror', 550, 'SPF Permanent Error: Unknown mechanism found: moo')
>>> q.check(spf='v=spf1 =a ?all moo')
('permerror', 550, 'SPF Permanent Error: Unknown qualifier, RFC 4408 para 4.6.1, found in: =a')
>>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ~all')
('pass', 250, 'sender SPF authorized')
>>> q.check(spf='v=spf1 ip4:192.0.0.0/8 -all moo=')
('pass', 250, 'sender SPF authorized')
>>> q.check(spf='v=spf1 ip4:192.0.0.0/8 -all match.sub-domains_9=yes')
('pass', 250, 'sender SPF authorized')
>>> q.strict = False
>>> q.check(spf='v=spf1 ip4:192.0.0.0/8 -all moo')
('permerror', 550, 'SPF Permanent Error: Unknown mechanism found: moo')
>>> q.perm_error.ext
('pass', 250, 'sender SPF authorized')
>>> q.strict = True
>>> q.check(spf='v=spf1 ip4:192.1.0.0/16 moo -all')
('permerror', 550, 'SPF Permanent Error: Unknown mechanism found: moo')
>>> q.check(spf='v=spf1 ip4:192.1.0.0/16 ~all')
('softfail', 250, 'domain owner discourages use of this host')
>>> q.check(spf='v=spf1 -ip4:192.1.0.0/6 ~all')
('fail', 550, 'SPF fail - not authorized')
# Assumes DNS available >>> q.check() ('none', 250, '')
>>> q.check(spf='v=spf1 ip4:1.2.3.4 -a:example.net -all')
('fail', 550, 'SPF fail - not authorized')
>>> q.libspf_local='ip4:192.0.2.3 a:example.org'
>>> q.check(spf='v=spf1 ip4:1.2.3.4 -a:example.net -all')
('pass', 250, 'sender SPF authorized')
>>> q.check(spf='v=spf1 ip4:1.2.3.4 -all exp=_exp.controlledmail.com')
('fail', 550, 'Controlledmail.com does not send mail from itself.')
>>> q.check(spf='v=spf1 ip4:1.2.3.4 ?all exp=_exp.controlledmail.com')
('neutral', 250, 'access neither permitted nor denied')

check1(self, spf, domain, recursion)

source code 
None

note_error(self, *msg)

source code 
None

expand_domain(self, arg)

source code 
validate and expand domain-spec

validate_mechanism(self, mech)

source code 

Parse and validate a mechanism. Returns mech,m,arg,cidrlength,result

Examples: >>> q = query(s='strong-bad@email.example.com.', ... h='mx.example.org', i='192.0.2.3') >>> q.validate_mechanism('A') ('A', 'a', 'email.example.com', 32, 'pass')
>>> q = query(s='strong-bad@email.example.com',
...           h='mx.example.org', i='192.0.2.3')    
>>> q.validate_mechanism('A')
('A', 'a', 'email.example.com', 32, 'pass')
>>> q.validate_mechanism('?mx:%{d}/27')
('?mx:%{d}/27', 'mx', 'email.example.com', 27, 'neutral')
>>> try: q.validate_mechanism('ip4:1.2.3.4/247')
... except PermError,x: print x
Invalid IP4 CIDR length: ip4:1.2.3.4/247
>>> try: q.validate_mechanism('ip4:1.2.3.4/33')
... except PermError,x: print x
Invalid IP4 CIDR length: ip4:1.2.3.4/33
>>> try: q.validate_mechanism('a:example.com:8080')
... except PermError,x: print x
Invalid domain found (use FQDN): example.com:8080
>>> try: q.validate_mechanism('ip4:1.2.3.444/24')
... except PermError,x: print x
Invalid IP4 address: ip4:1.2.3.444/24
>>> try: q.validate_mechanism('ip4:1.2.03.4/24')
... except PermError,x: print x
Invalid IP4 address: ip4:1.2.03.4/24
>>> try: q.validate_mechanism('-all:3030')
... except PermError,x: print x
Invalid all mechanism format - only qualifier allowed with all: -all:3030
>>> q.validate_mechanism('-mx:%%%_/.Clara.de/27')
('-mx:%%%_/.Clara.de/27', 'mx', '% /.Clara.de', 27, 'fail')
>>> q.validate_mechanism('~exists:%{i}.%{s1}.100/86400.rate.%{d}')
('~exists:%{i}.%{s1}.100/86400.rate.%{d}', 'exists', '192.0.2.3.com.100/86400.rate.email.example.com', 32, 'softfail')
>>> q.validate_mechanism('a:mail.example.com.')
('a:mail.example.com.', 'a', 'mail.example.com', 32, 'pass')
>>> try: q.validate_mechanism('a:mail.example.com,')
... except PermError,x: print x
Do not separate mechnisms with commas: a:mail.example.com,

check0(self, spf, recursion)

source code 

Test this query information against SPF text.

Returns (result, mta-status-code, explanation) where result in ['fail', 'unknown', 'pass', 'none']

check_lookups(self)

source code 
None

get_explanation(self, spec)

source code 
Expand an explanation.

expand(self, str, stripdot=True)

source code 

Do SPF RFC macro expansion.

Examples: >>> q = query(s='strong-bad@email.example.com', ... h='mx.example.org', i='192.0.2.3') >>> q.p = 'mx.example.org' >>> q.r = 'example.net'
>>> q.expand('%{d}')
'email.example.com'
>>> q.expand('%{d4}')
'email.example.com'
>>> q.expand('%{d3}')
'email.example.com'
>>> q.expand('%{d2}')
'example.com'
>>> q.expand('%{d1}')
'com'
>>> q.expand('%{p}')
'mx.example.org'
>>> q.expand('%{p2}')
'example.org'
>>> q.expand('%{dr}')
'com.example.email'
>>> q.expand('%{d2r}')
'example.email'
>>> q.expand('%{l}')
'strong-bad'
>>> q.expand('%{l-}')
'strong.bad'
>>> q.expand('%{lr}')
'strong-bad'
>>> q.expand('%{lr-}')
'bad.strong'
>>> q.expand('%{l1r-}')
'strong'
>>> q.expand('%{c}',stripdot=False)
'192.0.2.3'
>>> q.expand('%{r}',stripdot=False)
'example.net'
>>> q.expand('%{ir}.%{v}._spf.%{d2}')
'3.2.0.192.in-addr._spf.example.com'
>>> q.expand('%{lr-}.lp._spf.%{d2}')
'bad.strong.lp._spf.example.com'
>>> q.expand('%{lr-}.lp.%{ir}.%{v}._spf.%{d2}')
'bad.strong.lp.3.2.0.192.in-addr._spf.example.com'
>>> q.expand('%{ir}.%{v}.%{l1r-}.lp._spf.%{d2}')
'3.2.0.192.in-addr.strong.lp._spf.example.com'
>>> try: q.expand('%(ir).%{v}.%{l1r-}.lp._spf.%{d2}')
... except PermError,x: print x
invalid-macro-char : %(ir)
>>> q.expand('%{p2}.trusted-domains.example.net')
'example.org.trusted-domains.example.net'
>>> q.expand('%{p2}.trusted-domains.example.net.')
'example.org.trusted-domains.example.net'
>>> q = query(s='@email.example.com',
...           h='mx.example.org', i='192.0.2.3')
>>> q.p = 'mx.example.org'
>>> q.expand('%{l}')
'postmaster'

dns_spf(self, domain)

source code 
Get the SPF record recorded in DNS for a specific domain name. Returns None if not found, or if more than one record is found.

dns_txt(self, domainname)

source code 
Get a list of TXT records for a domain name.

dns_99(self, domainname)

source code 
Get a list of type SPF=99 records for a domain name.

dns_mx(self, domainname)

source code 
Get a list of IP addresses for all MX exchanges for a domain name.

dns_a(self, domainname, A='A')

source code 
Get a list of IP addresses for a domainname.

validated_ptrs(self)

source code 
Figure out the validated PTR domain names for the connect IP.

dns_ptr(self, i)

source code 
Get a list of domain names for an IP address.

dns(self, name, qtype, cnames=None)

source code 

DNS query.

If the result is in cache, return that. Otherwise pull the result from DNS, and cache ALL answers, so additional info is available for further queries later.

CNAMEs are followed.

If there is no data, [] is returned.

pre: qtype in ['A', 'AAAA', 'MX', 'PTR', 'TXT', 'SPF'] post: isinstance(__return__, types.ListType)

cidrmatch(self, ipaddrs, n)

source code 
Match connect IP against a list of other IP addresses.

get_header(self, res, receiver=None)

source code 
None

get_header_comment(self, res)

source code 
Return comment for Received-SPF header.

Class Variable Details [hide private]

SAFE2CACHE

None
Value:
{('A', 'A'): None,
 ('AAAA', 'AAAA'): None,
 ('CNAME', 'A'): None,
 ('CNAME', 'CNAME'): None,
 ('MX', 'A'): None,
 ('MX', 'MX'): None,
 ('PTR', 'PTR'): None,
 ('SPF', 'SPF'): None,
...