Skip to content

Commit

Permalink
net: avoid assigning .0 and .255 IPs for higher VM ID
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
marmarek committed Oct 1, 2022
1 parent e7aa7b5 commit 39ea3b3
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 6 deletions.
22 changes: 22 additions & 0 deletions qubes/tests/vm/mix/net.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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))
21 changes: 15 additions & 6 deletions qubes/vm/mix/net.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit 39ea3b3

Please sign in to comment.