Salt: Error while using dnsutil.parse_zone

Created on 14 Aug 2015  路  6Comments  路  Source: saltstack/salt

I need to get the serial of the zone in a local file (I don't have dig on the target server). But dnsutil.parse_zone fails.
Here's a part of my zonefile:

[...]
@               SOA     ns1.XXX.com. hostmaster.XXX.com. (
                                2015071501      ; serial
                                2H              ; refresh
                                1H              ; retry
                                2W              ; expire
                                1H              ; minimum
                        )
 [...]

And the output of salt-call -l debug dnsutil.parse_zone zonefile=/path/to/myzonefile:

[...]
DEBUG   ] LazyLoaded dnsutil.parse_zone
[ERROR   ] An un-handled exception was caught by salt's global exception handler:
IndexError: list index out of range
Traceback (most recent call last):
  File "/usr/local/bin/salt-call", line 9, in <module>
    load_entry_point('salt==2015.5.3', 'console_scripts', 'salt-call')()
  File "/usr/local/lib/python2.7/site-packages/salt/scripts.py", line 227, in salt_call
    client.run()
  File "/usr/local/lib/python2.7/site-packages/salt/cli/call.py", line 69, in run
    caller.run()
  File "/usr/local/lib/python2.7/site-packages/salt/cli/caller.py", line 236, in run
    ret = self.call()
  File "/usr/local/lib/python2.7/site-packages/salt/cli/caller.py", line 138, in call
    ret['return'] = func(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/salt/modules/dnsutil.py", line 173, in parse_zone
    zonedict['EXPIRE'] = _to_seconds(comps[8])
IndexError: list index out of range
Traceback (most recent call last):
  File "/usr/local/bin/salt-call", line 9, in <module>
    load_entry_point('salt==2015.5.3', 'console_scripts', 'salt-call')()
  File "/usr/local/lib/python2.7/site-packages/salt/scripts.py", line 227, in salt_call
    client.run()
  File "/usr/local/lib/python2.7/site-packages/salt/cli/call.py", line 69, in run
    caller.run()
  File "/usr/local/lib/python2.7/site-packages/salt/cli/caller.py", line 236, in run
    ret = self.call()
  File "/usr/local/lib/python2.7/site-packages/salt/cli/caller.py", line 138, in call
    ret['return'] = func(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/salt/modules/dnsutil.py", line 173, in parse_zone
    zonedict['EXPIRE'] = _to_seconds(comps[8])
IndexError: list index out of range

Is it my zone's SOA record syntax error or some "imperfection" in parse_zone function?

Bug Execution Module Needs Testcase P2 Platform severity-medium stale

Most helpful comment

This patch solves the described issues for me (salt 3000.3):

--- /usr/lib/python3/dist-packages/salt/modules/dnsutil.py      2020-05-07 14:37:42.000000000 +0000
+++ /usr/lib/python3/dist-packages/salt/modules/dnsutil-fix.py   2020-08-21 15:07:44.049898578 +0000
@@ -165,17 +165,22 @@
         else:
             comps = line.split()
         if 'SOA' in line:
-            if comps[1] != 'IN':
+            zonedict['NETWORK'] = 'IN'
+            for network in ['CH', 'CS', 'HS', 'IN']:
+                if network in comps:
+                    zonedict['NETWORK'] = network
+                    comps.pop(comps.index(network))
+            if comps[2] == 'SOA':
+                # an optional TTL is present
                 comps.pop(1)
             zonedict['ORIGIN'] = comps[0]
-            zonedict['NETWORK'] = comps[1]
-            zonedict['SOURCE'] = comps[3]
-            zonedict['CONTACT'] = comps[4].replace('.', '@', 1)
-            zonedict['SERIAL'] = comps[5]
-            zonedict['REFRESH'] = _to_seconds(comps[6])
-            zonedict['RETRY'] = _to_seconds(comps[7])
-            zonedict['EXPIRE'] = _to_seconds(comps[8])
-            zonedict['MINTTL'] = _to_seconds(comps[9])
+            zonedict['SOURCE'] = comps[2]
+            zonedict['CONTACT'] = comps[3].replace('.', '@', 1)
+            zonedict['SERIAL'] = comps[4]
+            zonedict['REFRESH'] = _to_seconds(comps[5])
+            zonedict['RETRY'] = _to_seconds(comps[6])
+            zonedict['EXPIRE'] = _to_seconds(comps[7])
+            zonedict['MINTTL'] = _to_seconds(comps[8])
             continue
         if comps[0] == 'IN':
             comps.insert(0, zonedict['ORIGIN'])

All 6 comments

@yermulnik, I am no zone expert, but salt shouldn't error out on an incorrect file format. If it is wrong, it should tell you why. :-)

And it doesn't error out on an incorrect file format =) The format is right. Salt just erroneously counts fields of SOA record in my zone file example, I guess.
Here's a bit of code from dnsutil.py:

        if 'SOA' in line:
            if comps[1] != 'IN':
                comps.pop(1)
            zonedict['ORIGIN'] = comps[0]
            zonedict['NETWORK'] = comps[1]
            zonedict['SOURCE'] = comps[3]
            zonedict['CONTACT'] = comps[4].replace('.', '@', 1)
            zonedict['SERIAL'] = comps[5]
            zonedict['REFRESH'] = _to_seconds(comps[6])
            zonedict['RETRY'] = _to_seconds(comps[7])
            zonedict['EXPIRE'] = _to_seconds(comps[8])
            zonedict['MINTTL'] = _to_seconds(comps[9])
            continue

According to code from dnsutil.py SOA record in my zone is parsed in a wrong way: it pops field SOA and as a result comps has another fields list and count as dnsutil.py expects it to be.
By the way second field in a SOA record according to RFC can be TTL or CLASS. Both of them are optional. And CLASS can be not only IN, but CH or HS as well (though its a rare case).
So, I guess, that condition in a mentioned code should be rewritten. Hope someone could do that =)

Zone SOA record format reference: http://www.zytrax.com/books/dns/ch8/soa.html

Thanks @yermulnik. If salt needs to parse zone files, it shouldn't fail on a correctly formatted file.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

If this issue is closed prematurely, please leave a comment and we will gladly reopen the issue.

Well, if this function is not that popular, I can close this ticket unresolved =(

This patch solves the described issues for me (salt 3000.3):

--- /usr/lib/python3/dist-packages/salt/modules/dnsutil.py      2020-05-07 14:37:42.000000000 +0000
+++ /usr/lib/python3/dist-packages/salt/modules/dnsutil-fix.py   2020-08-21 15:07:44.049898578 +0000
@@ -165,17 +165,22 @@
         else:
             comps = line.split()
         if 'SOA' in line:
-            if comps[1] != 'IN':
+            zonedict['NETWORK'] = 'IN'
+            for network in ['CH', 'CS', 'HS', 'IN']:
+                if network in comps:
+                    zonedict['NETWORK'] = network
+                    comps.pop(comps.index(network))
+            if comps[2] == 'SOA':
+                # an optional TTL is present
                 comps.pop(1)
             zonedict['ORIGIN'] = comps[0]
-            zonedict['NETWORK'] = comps[1]
-            zonedict['SOURCE'] = comps[3]
-            zonedict['CONTACT'] = comps[4].replace('.', '@', 1)
-            zonedict['SERIAL'] = comps[5]
-            zonedict['REFRESH'] = _to_seconds(comps[6])
-            zonedict['RETRY'] = _to_seconds(comps[7])
-            zonedict['EXPIRE'] = _to_seconds(comps[8])
-            zonedict['MINTTL'] = _to_seconds(comps[9])
+            zonedict['SOURCE'] = comps[2]
+            zonedict['CONTACT'] = comps[3].replace('.', '@', 1)
+            zonedict['SERIAL'] = comps[4]
+            zonedict['REFRESH'] = _to_seconds(comps[5])
+            zonedict['RETRY'] = _to_seconds(comps[6])
+            zonedict['EXPIRE'] = _to_seconds(comps[7])
+            zonedict['MINTTL'] = _to_seconds(comps[8])
             continue
         if comps[0] == 'IN':
             comps.insert(0, zonedict['ORIGIN'])
Was this page helpful?
0 / 5 - 0 ratings

Related issues

Jiaion picture Jiaion  路  52Comments

driskell picture driskell  路  64Comments

roflmao picture roflmao  路  58Comments

b-a-t picture b-a-t  路  48Comments

sumeetisp picture sumeetisp  路  54Comments