qubes/vm/net: add feature of hiding real IP from the VM

This helps hiding VM IP for anonymous VMs (Whonix) even when some
application leak it. VM will know only some fake IP, which should be set
to something as common as possible.
The feature is mostly implemented at (Proxy)VM side using NAT in
separate network namespace. Core here is only passing arguments to it.
It is designed the way that multiple VMs can use the same IP and still
do not interfere with each other. Even more: it is possible to address
each of them (using their "native" IP), even when multiple of them share
the same "fake" IP.

Original approach (marmarek/old-qubes-core-admin#2) used network script
arguments by appending them to script name, but libxl in Xen >= 4.6
fixed that side effect and it isn't possible anymore. So use QubesDB
instead.

From user POV, this adds 3 "features":
 - net/fake-ip - IP address visible in the VM
 - net/fake-gateway - default gateway in the VM
 - net/fake-netmask - network mask
The feature is enabled if net/fake-ip is set (to some IP address) and is
different than VM native IP. All of those "features" can be set on
template, to affect all of VMs.
Firewall rules etc in (Proxy)VM should still be applied to VM "native"
IP.

Fixes QubesOS/qubes-issues#1143
This commit is contained in:
Marek Marczykowski-Górecki 2016-10-31 02:06:01 +01:00
parent b91714b204
commit 2c6c476410
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
2 changed files with 37 additions and 3 deletions

View File

@ -85,6 +85,27 @@ class NetVMMixin(qubes.events.Emitter):
else:
return self.get_ip_for_vm(self)
@qubes.tools.qvm_ls.column(width=15)
@property
def visible_ip(self):
'''IP address of this domain as seen by the domain.'''
return self.features.check_with_template('net/fake-ip', None) or \
self.ip
@qubes.tools.qvm_ls.column(width=15)
@property
def visible_gateway(self):
'''Default gateway of this domain as seen by the domain.'''
return self.features.check_with_template('net/fake-gateway', None) or \
self.netvm.gateway
@qubes.tools.qvm_ls.column(width=15)
@property
def visible_netmask(self):
'''Netmask as seen by the domain.'''
return self.features.check_with_template('net/fake-netmask', None) or \
self.netvm.netmask
#
# used in netvms (provides_network=True)
# those properties and methods are most likely accessed as vm.netvm.<prop>
@ -274,6 +295,19 @@ class NetVMMixin(qubes.events.Emitter):
# signal its done
self.qdb.write(base_dir[:-1], '')
# add info about remapped IPs (VM IP hidden from the VM itself)
mapped_ip_base = '/mapped-ip/{}'.format(vm.ip)
if vm.visible_ip:
self.qdb.write(mapped_ip_base + '/visible-ip', vm.visible_ip)
else:
self.qdb.rm(mapped_ip_base + '/visible-ip')
if vm.visible_gateway:
self.qdb.write(mapped_ip_base + '/visible-gateway',
vm.visible_gateway)
else:
self.qdb.rm(mapped_ip_base + '/visible-gateway')
@qubes.events.handler('property-del:netvm')
def on_property_del_netvm(self, event, prop, old_netvm=None):
''' Sets the the NetVM to default NetVM '''

View File

@ -1474,9 +1474,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
self.qdb.write('/qubes-netvm-{}-dns'.format(i), addr)
if self.netvm is not None:
self.qdb.write('/qubes-ip', self.ip)
self.qdb.write('/qubes-netmask', self.netvm.netmask)
self.qdb.write('/qubes-gateway', self.netvm.gateway)
self.qdb.write('/qubes-ip', self.visible_ip)
self.qdb.write('/qubes-netmask', self.visible_netmask)
self.qdb.write('/qubes-gateway', self.visible_gateway)
for i, addr in zip(('primary', 'secondary'), self.dns):
self.qdb.write('/qubes-{}-dns'.format(i), addr)