core-admin/dom0/core-modules/005QubesNetVm.py

202 lines
6.7 KiB
Python
Raw Normal View History

2013-03-16 02:39:30 +01:00
#!/usr/bin/python2
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010 Joanna Rutkowska <joanna@invisiblethingslab.com>
# Copyright (C) 2013 Marek Marczykowski <marmarek@invisiblethingslab.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
from qubes.qubes import QubesVm,register_qubes_vm_class,xs,dry_run
from qubes.qubes import defaults,system_path,vm_files
from qubes.qubes import QubesVmCollection,QubesException
class QubesNetVm(QubesVm):
"""
A class that represents a NetVM. A child of QubesCowVM.
"""
# In which order load this VM type from qubes.xml
load_order = 70
def get_attrs_config(self):
attrs_config = super(QubesNetVm, self).get_attrs_config()
2013-03-16 02:39:30 +01:00
attrs_config['dir_path']['eval'] = 'value if value is not None else os.path.join(system_path["qubes_servicevms_dir"], self.name)'
attrs_config['label']['default'] = defaults["servicevm_label"]
attrs_config['memory']['default'] = 200
# New attributes
attrs_config['netid'] = { 'save': 'str(self.netid)', 'order': 30,
'eval': 'value if value is not None else collection.get_new_unused_netid()' }
attrs_config['netprefix'] = { 'eval': '"10.137.{0}.".format(self.netid)' }
attrs_config['dispnetprefix'] = { 'eval': '"10.138.{0}.".format(self.netid)' }
# Dont save netvm prop
attrs_config['netvm'].pop('save')
attrs_config['uses_default_netvm'].pop('save')
return attrs_config
def __init__(self, **kwargs):
super(QubesNetVm, self).__init__(**kwargs)
self.connected_vms = QubesVmCollection()
self.__network = "10.137.{0}.0".format(self.netid)
self.__netmask = defaults["vm_default_netmask"]
self.__gateway = self.netprefix + "1"
self.__secondary_dns = self.netprefix + "254"
self.__external_ip_allowed_xids = set()
@property
def type(self):
return "NetVM"
def is_netvm(self):
return True
@property
def gateway(self):
return self.__gateway
@property
def secondary_dns(self):
return self.__secondary_dns
@property
def netmask(self):
return self.__netmask
@property
def network(self):
return self.__network
def get_ip_for_vm(self, qid):
lo = qid % 253 + 2
assert lo >= 2 and lo <= 254, "Wrong IP address for VM"
return self.netprefix + "{0}".format(lo)
def get_ip_for_dispvm(self, dispid):
lo = dispid % 254 + 1
assert lo >= 1 and lo <= 254, "Wrong IP address for VM"
return self.dispnetprefix + "{0}".format(lo)
def create_xenstore_entries(self, xid = None):
if dry_run:
return
if xid is None:
xid = self.xid
super(QubesNetVm, self).create_xenstore_entries(xid)
xs.write('', "/local/domain/{0}/qubes-netvm-external-ip".format(xid), '')
self.update_external_ip_permissions(xid)
def update_external_ip_permissions(self, xid = -1):
if xid < 0:
xid = self.get_xid()
if xid < 0:
return
command = [
"/usr/bin/xenstore-chmod",
"/local/domain/{0}/qubes-netvm-external-ip".format(xid)
]
command.append("n{0}".format(xid))
for id in self.__external_ip_allowed_xids:
command.append("r{0}".format(id))
return subprocess.check_call(command)
def start(self, **kwargs):
if dry_run:
return
xid=super(QubesNetVm, self).start(**kwargs)
# Connect vif's of already running VMs
for vm in self.connected_vms.values():
if not vm.is_running():
continue
if 'verbose' in kwargs and kwargs['verbose']:
print >> sys.stderr, "--> Attaching network to '{0}'...".format(vm.name)
# Cleanup stale VIFs
vm.cleanup_vifs()
# force frontend to forget about this device
# module actually will be loaded back by udev, as soon as network is attached
vm.run("modprobe -r xen-netfront xennet", user="root")
try:
vm.attach_network(wait=False)
except QubesException as ex:
print >> sys.stderr, ("WARNING: Cannot attach to network to '{0}': {1}".format(vm.name, ex))
return xid
def shutdown(self, force=False):
if dry_run:
return
connected_vms = [vm for vm in self.connected_vms.values() if vm.is_running()]
if connected_vms and not force:
raise QubesException("There are other VMs connected to this VM: " + str([vm.name for vm in connected_vms]))
super(QubesNetVm, self).shutdown(force=force)
def add_external_ip_permission(self, xid):
if int(xid) < 0:
return
self.__external_ip_allowed_xids.add(int(xid))
self.update_external_ip_permissions()
def remove_external_ip_permission(self, xid):
self.__external_ip_allowed_xids.discard(int(xid))
self.update_external_ip_permissions()
def create_on_disk(self, verbose, source_template = None):
if dry_run:
return
super(QubesNetVm, self).create_on_disk(verbose, source_template=source_template)
if os.path.exists(os.path.join(source_template.dir_path, 'netvm-' + vm_files["whitelisted_appmenus"])):
if verbose:
print >> sys.stderr, "--> Creating default whitelisted apps list: {0}".\
format(self.dir_path + '/' + vm_files["whitelisted_appmenus"])
shutil.copy(os.path.join(source_template.dir_path, 'netvm-' + vm_files["whitelisted_appmenus"]),
os.path.join(self.dir_path, vm_files["whitelisted_appmenus"]))
if not self.internal:
self.create_appmenus (verbose=verbose, source_template=source_template)
def remove_from_disk(self):
if dry_run:
return
if not self.internal:
self.remove_appmenus()
super(QubesNetVm, self).remove_from_disk()
register_qubes_vm_class(QubesNetVm)