Remove explicit spf dependency.
This commit is contained in:
@@ -0,0 +1,62 @@
|
|||||||
|
# provide a higher level interface to pydns
|
||||||
|
|
||||||
|
import DNS
|
||||||
|
from DNS import DNSError
|
||||||
|
|
||||||
|
MAX_CNAME = 10
|
||||||
|
|
||||||
|
def DNSLookup(name, qtype):
|
||||||
|
try:
|
||||||
|
req = DNS.DnsRequest(name, qtype=qtype)
|
||||||
|
resp = req.req()
|
||||||
|
#resp.show()
|
||||||
|
# key k: ('wayforward.net', 'A'), value v
|
||||||
|
# FIXME: pydns returns AAAA RR as 16 byte binary string, but
|
||||||
|
# A RR as dotted quad. For consistency, this driver should
|
||||||
|
# return both as binary string.
|
||||||
|
return [((a['name'], a['typename']), a['data']) for a in resp.answers]
|
||||||
|
except IOError, x:
|
||||||
|
raise DNSError, str(x)
|
||||||
|
|
||||||
|
class Session(object):
|
||||||
|
"""A Session object has a simple cache with no TTL that is valid
|
||||||
|
for a single "session", for example an SMTP conversation."""
|
||||||
|
def __init__(self):
|
||||||
|
self.cache = {}
|
||||||
|
|
||||||
|
def dns(self, name, qtype, cnames=None):
|
||||||
|
"""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)
|
||||||
|
"""
|
||||||
|
result = self.cache.get( (name, qtype) )
|
||||||
|
cname = None
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
safe2cache = query.SAFE2CACHE
|
||||||
|
for k, v in DNSLookup(name, qtype, self.strict):
|
||||||
|
if k == (name, 'CNAME'):
|
||||||
|
cname = v
|
||||||
|
if (qtype,k[1]) in safe2cache:
|
||||||
|
self.cache.setdefault(k, []).append(v)
|
||||||
|
result = self.cache.get( (name, qtype), [])
|
||||||
|
if not result and cname:
|
||||||
|
if not cnames:
|
||||||
|
cnames = {}
|
||||||
|
elif len(cnames) >= MAX_CNAME:
|
||||||
|
#return result # if too many == NX_DOMAIN
|
||||||
|
raise DNSError('Length of CNAME chain exceeds %d' % MAX_CNAME)
|
||||||
|
cnames[name] = cname
|
||||||
|
if cname in cnames:
|
||||||
|
raise DNSError, 'CNAME loop'
|
||||||
|
result = self.dns(cname, qtype, cnames=cnames)
|
||||||
|
return result
|
||||||
+9
-5
@@ -5,6 +5,9 @@
|
|||||||
# Send DSNs, do call back verification,
|
# Send DSNs, do call back verification,
|
||||||
# and generate DSN messages from a template
|
# and generate DSN messages from a template
|
||||||
# $Log$
|
# $Log$
|
||||||
|
# Revision 1.14 2007/03/03 18:19:40 customdesigned
|
||||||
|
# Handle DNS error sending DSN.
|
||||||
|
#
|
||||||
# Revision 1.13 2007/01/04 18:01:11 customdesigned
|
# Revision 1.13 2007/01/04 18:01:11 customdesigned
|
||||||
# Do plain CBV when template missing.
|
# Do plain CBV when template missing.
|
||||||
#
|
#
|
||||||
@@ -19,22 +22,22 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import smtplib
|
import smtplib
|
||||||
import spf
|
|
||||||
import socket
|
import socket
|
||||||
from email.Message import Message
|
from email.Message import Message
|
||||||
import Milter
|
import Milter
|
||||||
import time
|
import time
|
||||||
|
import dns
|
||||||
|
|
||||||
def send_dsn(mailfrom,receiver,msg=None,timeout=600):
|
def send_dsn(mailfrom,receiver,msg=None,timeout=600,session=None):
|
||||||
"""Send DSN. If msg is None, do callback verification.
|
"""Send DSN. If msg is None, do callback verification.
|
||||||
Mailfrom is original sender we are sending DSN or CBV to.
|
Mailfrom is original sender we are sending DSN or CBV to.
|
||||||
Receiver is the MTA sending the DSN.
|
Receiver is the MTA sending the DSN.
|
||||||
Return None for success or (code,msg) for failure."""
|
Return None for success or (code,msg) for failure."""
|
||||||
user,domain = mailfrom.split('@')
|
user,domain = mailfrom.split('@')
|
||||||
|
if not session: session = dns.Session()
|
||||||
try:
|
try:
|
||||||
q = spf.query(None,None,None)
|
mxlist = session.dns(domain,'MX')
|
||||||
mxlist = q.dns(domain,'MX')
|
except dns.DNSError:
|
||||||
except spf.TempError:
|
|
||||||
return (450,'DNS Timeout: %s MX'%domain) # temp error
|
return (450,'DNS Timeout: %s MX'%domain) # temp error
|
||||||
if not mxlist:
|
if not mxlist:
|
||||||
mxlist = (0,domain), # fallback to A record when no MX
|
mxlist = (0,domain), # fallback to A record when no MX
|
||||||
@@ -124,6 +127,7 @@ def create_msg(q,rcptlist,origmsg=None,template=None):
|
|||||||
return msg
|
return msg
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
import spf
|
||||||
q = spf.query('192.168.9.50',
|
q = spf.query('192.168.9.50',
|
||||||
'SRS0=pmeHL=RH==stuart@example.com',
|
'SRS0=pmeHL=RH==stuart@example.com',
|
||||||
'red.example.com',receiver='mail.example.com')
|
'red.example.com',receiver='mail.example.com')
|
||||||
|
|||||||
Reference in New Issue
Block a user