From 39ea3b389a45f6c433b6102b61191583ac381425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sun, 2 Oct 2022 00:31:22 +0200 Subject: [PATCH] net: avoid assigning .0 and .255 IPs for higher VM ID Those occasionally cause issues if OS within a VM (especially without qubes tools installed) assumes /24 netmask. It wasn't an issue before, because max QID was 254. --- qubes/tests/vm/mix/net.py | 22 ++++++++++++++++++++++ qubes/vm/mix/net.py | 21 +++++++++++++++------ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/qubes/tests/vm/mix/net.py b/qubes/tests/vm/mix/net.py index a8b1e1f58..f7d99032f 100644 --- a/qubes/tests/vm/mix/net.py +++ b/qubes/tests/vm/mix/net.py @@ -27,6 +27,8 @@ import qubes.tests import qubes.tests.vm.qubesvm +from qubes.vm.mix.net import vmid_to_ipv4 + class TC_00_NetVMMixin( qubes.tests.vm.qubesvm.QubesVMTestsMixin, qubes.tests.QubesTestCase): @@ -154,3 +156,23 @@ def test_170_provides_network_netvm(self): self.assertPropertyValue(vm2, 'netvm', None, None, '') self.assertPropertyValue(vm2, 'netvm', '', None, '') self.assertPropertyValue(vm, 'provides_network', False, False, 'False') + + def test_200_vmid_to_ipv4(self): + testcases = ( + (1, '0.1'), + (2, '0.2'), + (254, '0.254'), + (255, '1.1'), + (256, '1.2'), + (257, '1.3'), + (508, '1.254'), + (509, '2.1'), + (510, '2.2'), + (511, '2.3'), + (512, '2.4'), + (513, '2.5'), + ) + for vmid, ip in testcases: + with self.subTest(str(vmid)): + self.assertEqual(ipaddress.IPv4Address('1.1.' + ip), + vmid_to_ipv4('1.1', vmid)) diff --git a/qubes/vm/mix/net.py b/qubes/vm/mix/net.py index 258e685a1..afe63941e 100644 --- a/qubes/vm/mix/net.py +++ b/qubes/vm/mix/net.py @@ -101,6 +101,19 @@ def __str__(self): return ' '.join(self) +def vmid_to_ipv4(prefix, vmid): + # avoid .0 and .255 addresses, it may trip some heuristics + # if OS assumes /24 netmask + # preserve unchanged IPs for low vmid + if vmid < 255: + return ipaddress.IPv4Address('{}.{}.{}'.format( + prefix, (vmid >> 8) & 0xff, vmid & 0xff)) + # don't reserve first .1 for vmid 0, as it is invalid + vmid -= 1 + return ipaddress.IPv4Address('{}.{}.{}'.format( + prefix, vmid // 254, (vmid % 254) + 1)) + + class NetVMMixin(qubes.events.Emitter): ''' Mixin containing network functionality ''' mac = qubes.property('mac', type=str, @@ -180,13 +193,9 @@ def get_ip_for_vm(vm): ''' import qubes.vm.dispvm # pylint: disable=redefined-outer-name if isinstance(vm, qubes.vm.dispvm.DispVM): - return ipaddress.IPv4Address('10.138.{}.{}'.format( - (vm.dispid >> 8) & 0xff, vm.dispid & 0xff)) + return vmid_to_ipv4('10.138', vm.dispid) - # VM technically can get address which ends in '.0'. This currently - # does not happen, because qid < 253, but may happen in the future. - return ipaddress.IPv4Address('10.137.{}.{}'.format( - (vm.qid >> 8) & 0xff, vm.qid & 0xff)) + return vmid_to_ipv4('10.137', vm.qid) @staticmethod def get_ip6_for_vm(vm):