On Wednesday, April 10, 2019 12:36:34 PM Dave Crocker wrote:
> Folks,
>
> Howdy.
>
> I'm trying to get a bit of education about reality. Always dangerous,
> but I've no choice...
>
>
> For the software you know about, how are queries to the DNS performed,
> to obtain the TXT records associated with DKIM and/or DMARC?
>
> I'm trying to understand the breadth and limitations of returned
> information that is filtered or passed by the code that is actually in
> use. Which libraries and which calls from those libraries.
I'm most familiar with how it's done with dkimpy (Python DKIM library) [1].
It uses an internal abstraction layer (we call dnsplug) to that the module
itself works with either pydns/py3dns [2] or dnspython. I'm not sure exactly
what you're after here, but the code's simple enough, so here it is:
def get_txt_dnspython(name):
"""Return a TXT record associated with a DNS name."""
try:
a = dns.resolver.query(name, dns.rdatatype.TXT,raise_on_no_answer=False)
for r in a.response.answer:
if r.rdtype == dns.rdatatype.TXT:
return b"".join(r.items[0].strings)
except dns.resolver.NXDOMAIN: pass
return None
def get_txt_pydns(name):
"""Return a TXT record associated with a DNS name."""
# Older pydns releases don't like a trailing dot.
if name.endswith('.'):
name = name[:-1]
response = DNS.DnsRequest(name, qtype='txt').req()
if not response.answers:
return None
return b''.join(response.answers[0]['data'])
There is a detection process that will decide what to use and then define
dnsplug.get_txt as the appropriate variant.
Not being sure how far you want to take this, here's an example of a TXT query
using pydns or py3dns (I picked this one because it has multiple TXT records):
Code:
>>> import DNS
>>> response = DNS.DnsRequest('google.com', qtype='txt').req()
>>> print(response.answers)
Result (whitespace added for clarity):
[
{'classstr': 'IN', 'ttl': 299, 'rdlength': 46, 'class': 1, 'typename': 'TXT',
'data': [b'docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e'], 'name':
'google.com', 'type': 16},
{'classstr': 'IN', 'ttl': 3599, 'rdlength': 36, 'class': 1, 'typename': 'TXT',
'data': [b'v=spf1 include:_spf.google.com ~all'], 'name': 'google.com',
'type': 16},
{'classstr': 'IN', 'ttl': 3599, 'rdlength': 60, 'class': 1, 'typename': 'TXT',
'data': [b'facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95'],
'name': 'google.com', 'type': 16},
{'classstr': 'IN', 'ttl': 3599, 'rdlength': 65, 'class': 1, 'typename': 'TXT',
'data': [b'globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8='],
'name': 'google.com', 'type': 16}
]
For completeness, here's the balance of what you can pull out of the response
object for this request:
>>> print(response.header)
{'ra': 1, 'qdcount': 1, 'opcode': 0, 'id': 46730, 'tc': 0, 'nscount': 0,
'arcount': 0, 'z': 0, 'ancount': 4, 'aa': 0, 'status': 'NOERROR', 'qr': 1,
'rd': 1, 'opcodestr': 'QUERY', 'rcode': 0}
>>> print(response.questions)
[{'qname': 'google.com', 'qtypestr': 'TXT', 'qclassstr': 'IN', 'qclass': 1,
'qtype': 16}]
>>> print(response.authority)
[]
>>> print(response.additional)
[]
>>> print(response.args)
{'qtype': 'txt', 'port': 53, 'protocol': 'udp', 'elapsed': 95.10970115661621,
'opcode': 0, 'server_rotate': 0, 'rd': 1, 'timeout': 30, 'timing': 1, 'name':
'google.com', 'server': '127.0.1.1'}
What gets returned to the application from dnsplug is a list of the TXT data.
In this case:
[b'docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e', b'v=spf1
include:_spf.google.com ~all', b'facebook-domain-
verification=22rm551cu4k0ab0bxsw536tlds4h95', b'globalsign-smime-
dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8=']
Is that the kind of thing you're after?
Scott K
[1] https://git.launchpad.net/dkimpy/tree/dkim/dnsplug.py
[2] For pydns/py3dns there are separate code bases for python2 and python3,
but the calls are the same.
_______________________________________________
dmarc mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/dmarc