rthalley / dnspython

a powerful DNS toolkit for python
http://www.dnspython.org
Other
2.46k stars 518 forks source link

Unable to call dns.zone.from_xfr method with non-relativized names #1120

Closed yeti9990 closed 3 months ago

yeti9990 commented 3 months ago

Describe the bug dns.zone.from_xfr() method is failing with ValueError: origin parameter must be an absolute name when relativize=False on a valid zone.

To Reproduce The following code is producing this odd result:

    try:
        query = dns.query.xfr(where=nameserver, zone=zone_name, keyring=my_tsig_key)
        z = dns.zone.from_xfr(xfr=query, relativize=False)
        print(z.origin)
    except dns.xfr.TransferError:
        print('zone transfer REFUSED')
    else:
        print(z.to_text(relativize=False))

This produces the following error:

Traceback (most recent call last):
  File "/tmp/./get-cnames.py", line 59, in 
    main()
  File "/tmp/./get-cnames.py", line 46, in main
    zone = get_zone(zone_name=zone_name, nameserver=nameserver)
  File "/tmp/./get-cnames.py", line 23, in get_zone
    z = dns.zone.from_xfr(xfr=query, relativize=False)
  File "/tmp/.venv/lib/python3.10/site-packages/dns/zone.py", line 1420, in from_xfr
    z = zone_factory(origin, rdclass, relativize=relativize)
  File "tmp/.venv/lib/python3.10/site-packages/dns/zone.py", line 162, in __init__
    raise ValueError("origin parameter must be an absolute name")
ValueError: origin parameter must be an absolute name

If I set relativize=True, the try/except works, and I can see that z.origin prints to a valid FQDN equal to the zone name, and the zone is output to text using fully qualified domain names i.e. the records are NOT relativized.

# Why does this work?
dns.zone.from_xfr(xfr=query, relativize=True)

# Why does this fail?
dns.zone.from_xfr(xfr=query, relativize=False)

When the function works the zone or origin is printed out, why is "example.com." not considered an abosolute name?

Context (please complete the following information):

rthalley commented 3 months ago

Although admittedly surprising, this is not a bug per se. It's more of a design mistake we can't easily fix due to backwards compatibility. The documentation for both dns.query.xfr() and dns.zone.from_xfr() both say that it is essential that the relativization settings in the two functions match. If you just add relativize=False to your call to dns.query.xfr() it will work.

We're gradually shifting to using dns.query.inbound_xfr() instead as it can do IXFR and is generally friendlier, but it doesn't have a friendly TSIG interface yet.

bwelling commented 3 months ago

We're gradually shifting to using dns.query.inbound_xfr() instead as it can do IXFR and is generally friendlier, but it doesn't have a friendly TSIG interface yet.

I'm not sure that I agree with the "yet" part - the new interface takes a Message rather than a zone name, which is much more flexible, because there are many customizations that can be made to the message before calling inbound_xfr, including specifying a TSIG key.