005QubesNetVm.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #!/usr/bin/python2
  2. #
  3. # The Qubes OS Project, http://www.qubes-os.org
  4. #
  5. # Copyright (C) 2010 Joanna Rutkowska <joanna@invisiblethingslab.com>
  6. # Copyright (C) 2013 Marek Marczykowski <marmarek@invisiblethingslab.com>
  7. #
  8. # This program is free software; you can redistribute it and/or
  9. # modify it under the terms of the GNU General Public License
  10. # as published by the Free Software Foundation; either version 2
  11. # of the License, or (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program; if not, write to the Free Software
  20. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21. #
  22. #
  23. import sys
  24. import os.path
  25. import xen.lowlevel.xs
  26. from qubes.qubes import QubesVm,register_qubes_vm_class,xs,dry_run
  27. from qubes.qubes import defaults,system_path,vm_files
  28. from qubes.qubes import QubesVmCollection,QubesException
  29. class QubesNetVm(QubesVm):
  30. """
  31. A class that represents a NetVM. A child of QubesCowVM.
  32. """
  33. # In which order load this VM type from qubes.xml
  34. load_order = 70
  35. def get_attrs_config(self):
  36. attrs_config = super(QubesNetVm, self).get_attrs_config()
  37. attrs_config['dir_path']['eval'] = 'value if value is not None else os.path.join(system_path["qubes_servicevms_dir"], self.name)'
  38. attrs_config['label']['default'] = defaults["servicevm_label"]
  39. attrs_config['memory']['default'] = 200
  40. # New attributes
  41. attrs_config['netid'] = { 'save': 'str(self.netid)', 'order': 30,
  42. 'eval': 'value if value is not None else collection.get_new_unused_netid()' }
  43. attrs_config['netprefix'] = { 'eval': '"10.137.{0}.".format(self.netid)' }
  44. attrs_config['dispnetprefix'] = { 'eval': '"10.138.{0}.".format(self.netid)' }
  45. # Dont save netvm prop
  46. attrs_config['netvm'].pop('save')
  47. attrs_config['uses_default_netvm'].pop('save')
  48. return attrs_config
  49. def __init__(self, **kwargs):
  50. super(QubesNetVm, self).__init__(**kwargs)
  51. self.connected_vms = QubesVmCollection()
  52. self.__network = "10.137.{0}.0".format(self.netid)
  53. self.__netmask = defaults["vm_default_netmask"]
  54. self.__gateway = self.netprefix + "1"
  55. self.__secondary_dns = self.netprefix + "254"
  56. self.__external_ip_allowed_xids = set()
  57. @property
  58. def type(self):
  59. return "NetVM"
  60. def is_netvm(self):
  61. return True
  62. @property
  63. def gateway(self):
  64. return self.__gateway
  65. @property
  66. def secondary_dns(self):
  67. return self.__secondary_dns
  68. @property
  69. def netmask(self):
  70. return self.__netmask
  71. @property
  72. def network(self):
  73. return self.__network
  74. def get_ip_for_vm(self, qid):
  75. lo = qid % 253 + 2
  76. assert lo >= 2 and lo <= 254, "Wrong IP address for VM"
  77. return self.netprefix + "{0}".format(lo)
  78. def get_ip_for_dispvm(self, dispid):
  79. lo = dispid % 254 + 1
  80. assert lo >= 1 and lo <= 254, "Wrong IP address for VM"
  81. return self.dispnetprefix + "{0}".format(lo)
  82. def create_xenstore_entries(self, xid = None):
  83. if dry_run:
  84. return
  85. if xid is None:
  86. xid = self.xid
  87. super(QubesNetVm, self).create_xenstore_entries(xid)
  88. xs.write('', "/local/domain/{0}/qubes-netvm-external-ip".format(xid), '')
  89. self.update_external_ip_permissions(xid)
  90. def update_external_ip_permissions(self, xid = -1):
  91. if xid < 0:
  92. xid = self.get_xid()
  93. if xid < 0:
  94. return
  95. perms = [ { 'dom': xid } ]
  96. for xid in self.__external_ip_allowed_xids:
  97. perms.append({ 'dom': xid, 'read': True })
  98. try:
  99. xs.set_permissions('', '/local/domain/{0}/qubes-netvm-external-ip'.format(xid),
  100. perms)
  101. except xen.lowlevel.xs.Error as e:
  102. print >>sys.stderr, "WARNING: failed to update external IP " \
  103. "permissions: %s" % (str(e))
  104. def start(self, **kwargs):
  105. if dry_run:
  106. return
  107. xid=super(QubesNetVm, self).start(**kwargs)
  108. # Connect vif's of already running VMs
  109. for vm in self.connected_vms.values():
  110. if not vm.is_running():
  111. continue
  112. if 'verbose' in kwargs and kwargs['verbose']:
  113. print >> sys.stderr, "--> Attaching network to '{0}'...".format(vm.name)
  114. # Cleanup stale VIFs
  115. vm.cleanup_vifs()
  116. # force frontend to forget about this device
  117. # module actually will be loaded back by udev, as soon as network is attached
  118. vm.run("modprobe -r xen-netfront xennet", user="root")
  119. try:
  120. vm.attach_network(wait=False)
  121. except QubesException as ex:
  122. print >> sys.stderr, ("WARNING: Cannot attach to network to '{0}': {1}".format(vm.name, ex))
  123. return xid
  124. def shutdown(self, force=False):
  125. if dry_run:
  126. return
  127. connected_vms = [vm for vm in self.connected_vms.values() if vm.is_running()]
  128. if connected_vms and not force:
  129. raise QubesException("There are other VMs connected to this VM: " + str([vm.name for vm in connected_vms]))
  130. super(QubesNetVm, self).shutdown(force=force)
  131. def add_external_ip_permission(self, xid):
  132. if int(xid) < 0:
  133. return
  134. self.__external_ip_allowed_xids.add(int(xid))
  135. self.update_external_ip_permissions()
  136. def remove_external_ip_permission(self, xid):
  137. self.__external_ip_allowed_xids.discard(int(xid))
  138. self.update_external_ip_permissions()
  139. register_qubes_vm_class(QubesNetVm)