Chapter 4 ■ SoCket NameS aNd dNS
72
if answer.rrset is not None:
for record in answer:
print(indent, hostname, 'has AAAA address', record.address)
return
answer = dns.resolver.query(hostname, 'CNAME')
if answer.rrset is not None:
record = answer[0]
cname = record.address
print(indent, hostname, 'is a CNAME alias for', cname) #?
resolve_hostname(cname, indent)
return
print(indent, 'ERROR: no A, AAAA, or CNAME records for', hostname)
def resolve_email_domain(domain):
"For an email address name@domain
find its mail server IP addresses."
try:
answer = dns.resolver.query(domain, 'MX', raise_on_no_answer=False)
except dns.resolver.NXDOMAIN:
print('Error: No such domain', domain)
return
if answer.rrset is not None:
records = sorted(answer, key=lambda record: record.preference)
for record in records:
name = record.exchange.to_text(omit_final_dot=True)
print('Priority', record.preference)
resolve_hostname(name)
else:
print('This domain has no explicit MX records')
print('Attempting to resolve it as an A, AAAA, or CNAME')
resolve_hostname(domain)
if name == 'main':
parser = argparse.ArgumentParser(description='Find mailserver IP address')
parser.add_argument('domain', help='domain that you want to send mail to')
resolve_email_domain(parser.parse_args().domain)
Of course, the implementation of resolve_hostname() shown here is rather fragile since it should really make a
dynamic decision between A and AAAA records based on whether the current host is connected to an IPv4 or to an IPv6
network. In fact, it is likely that our friend getsockaddr() should really be deferred to here instead of trying to resolve
the mail server hostname ourselves! But since Listing 4-3 is designed to show off how the DNS works, I thought I might
as well follow through with the logic using pure DNS so that you could see how the queries are resolved.
Instead of printing the mail server addresses, a real mail server implementation would obviously attempt to
deliver mail to them instead and stop once the first success was achieved. (If it kept going through the server list
after the success, then several copies of the e-mail would be generated, one for each server to which it was delivered
successfully.) Nonetheless, this simple script gives you a good idea of the process. You can see that python.org at the
moment has but a single mail server IP address.
$ python dns_mx.py python.org
This domain has 1 MX records
Priority 50
mail.python.org has A address 82.94.164.166