pythondnsdnspython

Can I write a DNS Zone file with $TTL using dnspython?


I use dns.zone.Zone from dnspython to represent DNS zones, and when I use the to_text() method, I get a zone that looks like this:

@ 86400 IN SOA dns0.noris.net. hostmaster.noris.net. 1234 86400 1800 2419200 600
@ 86400 IN A 185.199.108.153
@ 86400 IN A 185.199.109.153
@ 86400 IN A 185.199.110.153
@ 86400 IN A 185.199.111.153

Is there any way to get the output to use a BIND-style default TTL, instead of one TTL per record, like this?

$TTL 86400
@ IN SOA dns0.noris.net. hostmaster.noris.net. 1234 86400 1800 2419200 600
@ IN A 185.199.108.153
@ IN A 185.199.109.153
@ IN A 185.199.110.153
@ IN A 185.199.111.153

(background: I want to minimize diffs when the default zone TTL changes).


Solution

  • dnspython library, as of v2.1.0rc1 (the latest version as of November, 9, 2020), doesn't support this type of a zone style per se. Going down your stack trace for the to_text() call:

    1. dns/zone.py#622: to_text()
    2. dns/zone.py#586: to_file()
    3. dns/node.py#53: to_text()
    4. dns/rdataset.py#233: to_text()

    ā€” this is where the actual formatting is being done:

    for rd in self:
        extra = ''
        if want_comments:
            if rd.rdcomment:
                extra = f' ;{rd.rdcomment}'
            s.write('%s%s%d %s %s %s%s\n' %
                    (ntext, pad, self.ttl, dns.rdataclass.to_text(rdclass),
                     dns.rdatatype.to_text(self.rdtype),
                     rd.to_text(origin=origin, relativize=relativize,
                                **kw),
                     extra))
    

    So, as you can see, self.ttl is included into the rdataset text output invariably.

    What you can do though is iterate over the zone, creating a zone file of your preferred style yourself ā€” or make changes directly to the to_text() output which is a standardized zone description and thus is stable enough to be processed automatically. Quick example of how that could look:

    zone_lines = ['$TTL %s' % zone['@'].rdatasets[0].ttl]
    for rdat in zone.to_text().decode('ascii').strip().split('\n'):
        rdat_params = rdat.split(' ')
        rdat_params.pop(1)
        zone_lines.append(' '.join(rdat_params))
    
    zone_text = '\n'.join(zone_lines)
    

    You can also create a feature request for the dnspython project on Github. The author would then consider your feature request, they have been quite responsive recently.