Fixes dnsmasq host file parsing with "addr6_list"

This patch fixes:
- The IPv6 tag added in the "host" file if is supported in
  dnsmasq. That shifts all other parameters in the register.
- IPv6 registers can have more than one IP address; in this
  case, the method "_read_hosts_file_leases" should return a
  tuple per IP address.

Change-Id: I4d0bc1eb9448366d8f1b2dacc9c5c2e4e6958253
Closes-Bug: #1884105
(cherry picked from commit 8eb4955bb6)
This commit is contained in:
Rodolfo Alonso Hernandez 2020-06-18 17:03:47 +00:00
parent 080123851c
commit 68706b556b
2 changed files with 48 additions and 34 deletions

View File

@ -875,6 +875,11 @@ class Dnsmasq(DhcpLocalProcess):
str(DHCP_OPT_CLIENT_ID_NUM)):
return opt.opt_value
@staticmethod
def _parse_ip_addresses(ip_list):
ip_list = [ip.strip('[]') for ip in ip_list]
return [ip for ip in ip_list if netutils.is_valid_ip(ip)]
def _read_hosts_file_leases(self, filename):
leases = set()
try:
@ -886,11 +891,14 @@ class Dnsmasq(DhcpLocalProcess):
if host[1].startswith('set:'):
continue
if host[1].startswith(self._ID):
ip = host[3].strip('[]')
ips = self._parse_ip_addresses(host[3:])
client_id = host[1][len(self._ID):]
elif host[1].startswith('tag:'):
ips = self._parse_ip_addresses(host[3:])
else:
ip = host[2].strip('[]')
leases.add((ip, mac, client_id))
ips = self._parse_ip_addresses(host[2:])
for ip in ips:
leases.add((ip, mac, client_id))
except (OSError, IOError):
LOG.debug('Error while reading hosts file %s', filename)
return leases

View File

@ -2572,51 +2572,57 @@ class TestDnsmasq(TestBase):
def test_release_unused_leases_one_lease_mult_times_removed(self):
self._test_release_unused_leases_one_lease_mult_times(True)
def test_read_hosts_file_leases(self):
def test__parse_ip_addresses(self):
ip_list = ['192.168.0.1', '[fdca:3ba5:a17a::1]', 'no_ip_address']
self.assertEqual(['192.168.0.1', 'fdca:3ba5:a17a::1'],
dhcp.Dnsmasq._parse_ip_addresses(ip_list))
def _test_read_hosts_file_leases(self, lines, expected_result):
filename = '/path/to/file'
lines = ["00:00:80:aa:bb:cc,inst-name,192.168.0.1",
"00:00:80:aa:bb:cc,inst-name,[fdca:3ba5:a17a::1]"]
mock_open = self.useFixture(
lib_fixtures.OpenFixture(filename, '\n'.join(lines))).mock_open
dnsmasq = self._get_dnsmasq(FakeDualNetwork())
leases = dnsmasq._read_hosts_file_leases(filename)
self.assertEqual(set([("192.168.0.1", "00:00:80:aa:bb:cc", None),
("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc",
None)]), leases)
self.assertEqual(expected_result, leases)
mock_open.assert_called_once_with(filename)
def test_read_hosts_file_leases(self):
lines = ["00:00:80:aa:bb:cc,inst-name,192.168.0.1",
"00:00:80:aa:bb:cc,inst-name,[fdca:3ba5:a17a::1]"]
result = {("192.168.0.1", "00:00:80:aa:bb:cc", None),
("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", None)}
self._test_read_hosts_file_leases(lines, result)
def test_read_hosts_file_leases_with_client_id(self):
filename = '/path/to/file'
lines = ["00:00:80:aa:bb:cc,id:client1,inst-name,192.168.0.1",
"00:00:80:aa:bb:cc,id:client2,inst-name,"
"[fdca:3ba5:a17a::1]"]
mock_open = self.useFixture(
lib_fixtures.OpenFixture(filename, '\n'.join(lines))).mock_open
dnsmasq = self._get_dnsmasq(FakeDualNetwork())
leases = dnsmasq._read_hosts_file_leases(filename)
self.assertEqual(set([("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'),
("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc",
'client2')]), leases)
mock_open.assert_called_once_with(filename)
result = {("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'),
("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", 'client2')}
self._test_read_hosts_file_leases(lines, result)
def test_read_hosts_file_leases_with_stateless_IPv6_tag(self):
filename = self.get_temp_file_path('leases')
with open(filename, "w") as leasesfile:
lines = [
"00:00:80:aa:bb:cc,id:client1,inst-name,192.168.0.1\n",
"00:00:80:aa:bb:cc,set:ccccccccc-cccc-cccc-cccc-cccccccc\n",
"00:00:80:aa:bb:cc,id:client2,inst-name,[fdca:3ba5:a17a::1]\n"]
for line in lines:
leasesfile.write(line)
lines = [
"00:00:80:aa:bb:cc,id:client1,inst-name,192.168.0.1",
"00:00:80:aa:bb:cc,set:ccccccccc-cccc-cccc-cccc-cccccccc",
"00:00:80:aa:bb:cc,id:client2,inst-name,[fdca:3ba5:a17a::1]"]
result = {("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'),
("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", 'client2')}
self._test_read_hosts_file_leases(lines, result)
dnsmasq = self._get_dnsmasq(FakeDualNetwork())
leases = dnsmasq._read_hosts_file_leases(filename)
self.assertEqual(set([("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'),
("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc",
'client2')]), leases)
def test_read_hosts_file_leases_with_IPv6_tag_and_multiple_ips(self):
lines = [
"00:00:80:aa:bb:cc,id:client1,inst-name,192.168.0.1",
"00:00:80:aa:bb:cc,set:ccccccccc-cccc-cccc-cccc-cccccccc",
"00:00:80:aa:bb:cc,tag:dhcpv6,inst-name,[fdca:3ba5:a17a::1],"
"[fdca:3ba5:a17a::2],[fdca:3ba5:a17a::3],[fdca:3ba5:a17a::4],"
"set:port-fe2baee9-aba9-4b67-be03-be4aeee40cca"]
result = {("192.168.0.1", "00:00:80:aa:bb:cc", 'client1'),
("fdca:3ba5:a17a::1", "00:00:80:aa:bb:cc", None),
("fdca:3ba5:a17a::2", "00:00:80:aa:bb:cc", None),
("fdca:3ba5:a17a::3", "00:00:80:aa:bb:cc", None),
("fdca:3ba5:a17a::4", "00:00:80:aa:bb:cc", None)}
self._test_read_hosts_file_leases(lines, result)
def _test_read_leases_file_leases(self, ip_version, add_bad_line=False):
filename = '/path/to/file'