backup: add firewall and appmenus list handling
This commit is contained in:
parent
04ad224a9d
commit
f1036c27a7
@ -442,6 +442,9 @@ class ExtractWorker3(Process):
|
||||
for fname, (data_func, size_func) in self.handlers.items():
|
||||
if not fname.startswith(dirname + '/'):
|
||||
continue
|
||||
if not os.path.exists(fname):
|
||||
# for example firewall.xml
|
||||
continue
|
||||
if size_func is not None:
|
||||
size_func(os.path.getsize(fname))
|
||||
with open(fname, 'rb') as input_file:
|
||||
@ -741,6 +744,10 @@ class BackupVM(object):
|
||||
'''Report whether a VM is included in the backup'''
|
||||
return False
|
||||
|
||||
def handle_firewall_xml(self, vm, stream):
|
||||
'''Import appropriate format of firewall.xml'''
|
||||
raise NotImplementedError
|
||||
|
||||
class BackupRestoreOptions(object):
|
||||
'''Options for restore operation'''
|
||||
# pylint: disable=too-few-public-methods
|
||||
@ -1717,6 +1724,15 @@ class BackupRestore(object):
|
||||
if retcode != 0:
|
||||
self.log.error("*** Error while setting home directory owner")
|
||||
|
||||
def _handle_appmenus_list(self, vm, stream):
|
||||
'''Handle whitelisted-appmenus.list file'''
|
||||
try:
|
||||
subprocess.check_call(
|
||||
['qvm-appmenus', '--set-whitelist=-', vm.name],
|
||||
stdin=stream)
|
||||
except subprocess.CalledProcessError:
|
||||
self.log.exception('Failed to set application list for %s', vm.name)
|
||||
|
||||
def restore_do(self, restore_info):
|
||||
'''
|
||||
|
||||
@ -1753,8 +1769,11 @@ class BackupRestore(object):
|
||||
size_func = volume.resize
|
||||
handlers[os.path.join(vm_info.subdir, name + '.img')] = \
|
||||
(data_func, size_func)
|
||||
# TODO applications whitelist
|
||||
# TODO firewall
|
||||
handlers[os.path.join(vm_info.subdir, 'firewall.xml')] = (
|
||||
functools.partial(vm_info.vm.handle_firewall_xml, vm), None)
|
||||
handlers[os.path.join(vm_info.subdir,
|
||||
'whitelisted-appmenus.list')] = (
|
||||
functools.partial(self._handle_appmenus_list, vm), None)
|
||||
|
||||
if 'dom0' in restore_info.keys() and \
|
||||
restore_info['dom0'].good_to_go:
|
||||
|
@ -25,6 +25,7 @@ import xml.parsers
|
||||
import logging
|
||||
import lxml.etree
|
||||
|
||||
from qubesadmin.firewall import Rule, Action, Proto, DstHost, SpecialTarget
|
||||
import qubesadmin.backup
|
||||
|
||||
service_to_feature = {
|
||||
@ -44,6 +45,102 @@ class Core2VM(qubesadmin.backup.BackupVM):
|
||||
def included_in_backup(self):
|
||||
return self.backup_content
|
||||
|
||||
@staticmethod
|
||||
def rule_from_xml_v1(node, action):
|
||||
'''Parse single rule in old XML format (pre Qubes 4.0)
|
||||
|
||||
:param node: XML node for the rule
|
||||
:param action: action to apply (in old format it wasn't part of the
|
||||
rule itself)
|
||||
'''
|
||||
netmask = node.get('netmask')
|
||||
if netmask is None:
|
||||
netmask = 32
|
||||
else:
|
||||
netmask = int(netmask)
|
||||
address = node.get('address')
|
||||
if address:
|
||||
dsthost = DstHost(address, netmask)
|
||||
else:
|
||||
dsthost = None
|
||||
|
||||
proto = node.get('proto')
|
||||
|
||||
port = node.get('port')
|
||||
toport = node.get('toport')
|
||||
if port and toport:
|
||||
dstports = port + '-' + toport
|
||||
elif port:
|
||||
dstports = port
|
||||
else:
|
||||
dstports = None
|
||||
|
||||
# backward compatibility: protocol defaults to TCP if port is specified
|
||||
if dstports and not proto:
|
||||
proto = 'tcp'
|
||||
|
||||
if proto == 'any':
|
||||
proto = None
|
||||
|
||||
expire = node.get('expire')
|
||||
|
||||
kwargs = {
|
||||
'action': action,
|
||||
}
|
||||
if dsthost:
|
||||
kwargs['dsthost'] = dsthost
|
||||
if dstports:
|
||||
kwargs['dstports'] = dstports
|
||||
if proto:
|
||||
kwargs['proto'] = proto
|
||||
if expire:
|
||||
kwargs['expire'] = expire
|
||||
|
||||
return Rule(None, **kwargs)
|
||||
|
||||
|
||||
def handle_firewall_xml(self, vm, stream):
|
||||
'''Load old (Qubes < 4.0) firewall XML format'''
|
||||
try:
|
||||
tree = lxml.etree.parse(stream) # pylint: disable=no-member
|
||||
xml_root = tree.getroot()
|
||||
policy_v1 = xml_root.get('policy')
|
||||
assert policy_v1 in ('allow', 'deny')
|
||||
default_policy_is_accept = (policy_v1 == 'allow')
|
||||
rules = []
|
||||
|
||||
def _translate_action(key):
|
||||
'''Translate action name'''
|
||||
if xml_root.get(key, policy_v1) == 'allow':
|
||||
return Action.accept
|
||||
return Action.drop
|
||||
|
||||
rules.append(Rule(None,
|
||||
action=_translate_action('dns'),
|
||||
specialtarget=SpecialTarget('dns')))
|
||||
|
||||
rules.append(Rule(None,
|
||||
action=_translate_action('icmp'),
|
||||
proto=Proto.icmp))
|
||||
|
||||
if default_policy_is_accept:
|
||||
rule_action = Action.drop
|
||||
else:
|
||||
rule_action = Action.accept
|
||||
|
||||
for element in xml_root:
|
||||
rule = self.rule_from_xml_v1(element, rule_action)
|
||||
rules.append(rule)
|
||||
if default_policy_is_accept:
|
||||
rules.append(Rule(None, action='accept'))
|
||||
else:
|
||||
rules.append(Rule(None, action='drop'))
|
||||
|
||||
vm.firewall.rules = rules
|
||||
except: # pylint: disable=bare-except
|
||||
vm.log.exception('Failed to set firewall')
|
||||
|
||||
|
||||
class Core2Qubes(qubesadmin.backup.BackupApp):
|
||||
'''Parsed qubes.xml'''
|
||||
def __init__(self, store=None):
|
||||
|
@ -25,6 +25,7 @@ import logging
|
||||
import lxml.etree
|
||||
|
||||
import qubesadmin.backup
|
||||
import qubesadmin.firewall
|
||||
|
||||
class Core3VM(qubesadmin.backup.BackupVM):
|
||||
'''VM object'''
|
||||
@ -33,6 +34,22 @@ class Core3VM(qubesadmin.backup.BackupVM):
|
||||
def included_in_backup(self):
|
||||
return self.backup_path is not None
|
||||
|
||||
def handle_firewall_xml(self, vm, stream):
|
||||
'''Load new (Qubes >= 4.0) firewall XML format'''
|
||||
try:
|
||||
tree = lxml.etree.parse(stream) # pylint: disable=no-member
|
||||
xml_root = tree.getroot()
|
||||
rules = []
|
||||
for rule_node in xml_root.findall('./rules/rule'):
|
||||
rule_opts = {}
|
||||
for rule_opt in rule_node.findall('./properties/property'):
|
||||
rule_opts[rule_opt.get('name')] = rule_opt.text
|
||||
rules.append(qubesadmin.firewall.Rule(None, **rule_opts))
|
||||
|
||||
vm.firewall.rules = rules
|
||||
except: # pylint: disable=bare-except
|
||||
vm.log.exception('Failed to set firewall')
|
||||
|
||||
class Core3Qubes(qubesadmin.backup.BackupApp):
|
||||
'''Parsed qubes.xml'''
|
||||
def __init__(self, store=None):
|
||||
|
Loading…
Reference in New Issue
Block a user