dmachard / python-dnsdist-console

Python client for the dnsdist console

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Stats truncated during parsing of showServers()

threatstop opened this issue · comments

Hi Denis,
We found the following issue in the module: the output of showServers() can end up truncated, as the length of the data can exceed the length of the header, which is used to split each row in https://github.com/dmachard/python-dnsdist-console/blob/master/dnsdist_console/statistics.py#L39

For example, if a dnsdist server has served 12345678 queries, the module will truncate the leading 1 and return 2345678

DNSDist console

> showServers()
showServers()
#   Name                 Address                       State     Qps    Qlim Ord Wt    Queries   Drops Drate   Lat Outstanding Pools
0   127.0.0.1:5353       127.0.0.1:5353                 down     0.0       0   1  1   12345678       0   0.0   0.0           0 a pool with spaces
All                                                              0.0                         0       0

Python side

console = Console(host="127.0.0.1", port=5199, key="redacted")
stats = Statistics(console)
print(stats['backends'][0])
{'#': '0', 'Name': '127.0.0.1:5353', 'Address': '127.0.0.1:5353', 'State': 'down', 'Qps': '0.0', 'Qlim': '0', 'Ord': '1', 'Wt': '1', 'Queries': '2345678', 'Drops': '0', 'Drate': '0.0', 'Lat': '0.0', 'Outstanding': '0', 'Pools': 'a pool with spaces'}

Here is a possible fix, although it only works as long as pools remains the only field with spaces.

*** statistics.py.orig	2023-01-31 17:02:15.650733020 +0000
--- statistics.py	2023-01-31 17:42:18.499797146 +0000
***************
*** 36,51 ****
          svr_hdr = o_list[0]

          svr_stats = []
          for s in o_list[1:]:
!             svr = {}
!             i = 0
!             j = 0
!             for i in range(len(svr_hdr)):
!                 if i == len(svr_hdr)-1:
!                     svr[svr_hdr[j:].strip().lower()] = s[j:].strip()
!                 if svr_hdr[i].isupper():
!                     svr[svr_hdr[j:i].strip().lower()] = s[j:i].strip()
!                     j = i
              svr_stats.append(svr)

          self.__stats__["backends"] = svr_stats
--- 36,44 ----
          svr_hdr = o_list[0]

          svr_stats = []
+         headers = re.sub('\s+', ' ', svr_hdr).split(' ')
          for s in o_list[1:]:
!             svr = dict(zip(headers, re.sub('\s+', ' ', s).split(' ', len(headers) - 1)))
              svr_stats.append(svr)

          self.__stats__["backends"] = svr_stats

Thank to report this issue, can you push your fix through a pull request ?

The name field can also contains spaces; perhaps we can ignore this field and remove-it during parsing ?
The name can be extracted with getServer(<server_id>):getName()

Adjusting the fix to accounts for spaces in server names. Will submit PR once addressed.

This is quite difficult to parse, given that the server name can also get truncated in the output of showServers() (20 char limit) but isn't in the output of getServer(<server_id>). Sending PR, as ugly as it is.

Not perfect but better than the initial code, thanks again for the PR.
I also added some tests regarding this parsing

def test_backends(self):

Thank you for the quick response