e54cc11a2c
And place them in /qubes-service/ QubesDB directory. This allows extensions to easily store some data not exposed to VM, but also have control what VM will see. And at the same time, it make it compatible with existing services framework QubesOS/qubes-issues#1637
174 lines
6.6 KiB
Python
174 lines
6.6 KiB
Python
#
|
|
# The Qubes OS Project, https://www.qubes-os.org/
|
|
#
|
|
# Copyright (C) 2010 Joanna Rutkowska <joanna@invisiblethingslab.com>
|
|
# Copyright (C) 2013-2016 Marek Marczykowski-Górecki
|
|
# <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.
|
|
#
|
|
|
|
import datetime
|
|
import qubes.ext
|
|
import qubes.firewall
|
|
import qubes.vm.qubesvm
|
|
import qubes.vm.appvm
|
|
import qubes.vm.templatevm
|
|
import qubes.utils
|
|
|
|
yum_proxy_ip = '10.137.255.254'
|
|
yum_proxy_port = '8082'
|
|
|
|
|
|
class R3Compatibility(qubes.ext.Extension):
|
|
'''Maintain VM interface compatibility with R3.0 and R3.1.
|
|
At lease where possible.
|
|
'''
|
|
|
|
features_to_services = {
|
|
'service/ntpd': 'ntpd',
|
|
'check-updates': 'qubes-update-check',
|
|
'dvm': 'qubes-dvm',
|
|
|
|
}
|
|
|
|
# noinspection PyUnusedLocal
|
|
@qubes.ext.handler('domain-qdb-create')
|
|
def on_domain_qdb_create(self, vm, event):
|
|
'''
|
|
:param qubes.vm.qubesvm.QubesVM vm: \
|
|
VM on which QubesDB entries were just created
|
|
''' # pylint: disable=unused-argument
|
|
# /qubes-vm-type: AppVM, NetVM, ProxyVM, TemplateVM
|
|
if isinstance(vm, qubes.vm.templatevm.TemplateVM):
|
|
vmtype = 'TemplateVM'
|
|
elif vm.netvm is not None and vm.provides_network:
|
|
vmtype = 'ProxyVM'
|
|
elif vm.netvm is None and vm.provides_network:
|
|
vmtype = 'NetVM'
|
|
else:
|
|
vmtype = 'AppVM'
|
|
vm.qdb.write('/qubes-vm-type', vmtype)
|
|
|
|
vm.qdb.write("/qubes-iptables-error", '')
|
|
self.write_iptables_qubesdb_entry(vm)
|
|
|
|
self.write_services(vm)
|
|
|
|
@qubes.ext.handler('domain-spawn')
|
|
def on_domain_started(self, vm, event, **kwargs):
|
|
# pylint: disable=unused-argument
|
|
if vm.netvm:
|
|
self.write_iptables_qubesdb_entry(vm.netvm)
|
|
|
|
@qubes.ext.handler('firewall-changed')
|
|
def on_firewall_changed(self, vm, event):
|
|
# pylint: disable=unused-argument
|
|
if vm.is_running() and vm.netvm:
|
|
self.write_iptables_qubesdb_entry(vm.netvm)
|
|
|
|
def write_iptables_qubesdb_entry(self, firewallvm):
|
|
# pylint: disable=no-self-use
|
|
firewallvm.qdb.rm("/qubes-iptables-domainrules/")
|
|
iptables = "# Generated by Qubes Core on {0}\n".format(
|
|
datetime.datetime.now().ctime())
|
|
iptables += "*filter\n"
|
|
iptables += ":INPUT DROP [0:0]\n"
|
|
iptables += ":FORWARD DROP [0:0]\n"
|
|
iptables += ":OUTPUT ACCEPT [0:0]\n"
|
|
|
|
# Strict INPUT rules
|
|
iptables += "-A INPUT -i vif+ -p udp -m udp --dport 68 -j DROP\n"
|
|
iptables += "-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED " \
|
|
"-j ACCEPT\n"
|
|
iptables += "-A INPUT -p icmp -j ACCEPT\n"
|
|
iptables += "-A INPUT -i lo -j ACCEPT\n"
|
|
iptables += "-A INPUT -j REJECT --reject-with icmp-host-prohibited\n"
|
|
|
|
iptables += "-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED " \
|
|
"-j ACCEPT\n"
|
|
# Deny inter-VMs networking
|
|
iptables += "-A FORWARD -i vif+ -o vif+ -j DROP\n"
|
|
iptables += "COMMIT\n"
|
|
firewallvm.qdb.write("/qubes-iptables-header", iptables)
|
|
|
|
for vm in firewallvm.connected_vms:
|
|
iptables = "*filter\n"
|
|
conf = vm.firewall
|
|
|
|
xid = vm.xid
|
|
if xid < 0: # VM not active ATM
|
|
continue
|
|
|
|
ip = vm.ip
|
|
if ip is None:
|
|
continue
|
|
|
|
# Anti-spoof rules are added by vif-script (vif-route-qubes),
|
|
# here we trust IP address
|
|
|
|
for rule in conf.rules:
|
|
if rule.specialtarget == 'dns':
|
|
if rule.dstports not in ('53', None):
|
|
continue
|
|
if rule.proto:
|
|
protos = {'tcp', 'udp'}.intersection(str(rule.proto))
|
|
else:
|
|
protos = {'tcp', 'udp'}
|
|
for proto in protos:
|
|
if rule.dsthost:
|
|
dsthosts = set(vm.dns).intersection(
|
|
[str(rule.dsthost).replace('/24', '')])
|
|
else:
|
|
dsthosts = vm.dns
|
|
for dsthost in dsthosts:
|
|
iptables += '-A FORWARD -s {}'.format(ip)
|
|
iptables += ' -d {!s}'.format(dsthost)
|
|
iptables += ' -p {!s}'.format(proto)
|
|
iptables += ' --dport 53'
|
|
iptables += ' -j {}\n'.format(
|
|
str(rule.action).upper())
|
|
else:
|
|
iptables += '-A FORWARD -s {}'.format(ip)
|
|
if rule.dsthost:
|
|
iptables += ' -d {!s}'.format(rule.dsthost)
|
|
if rule.proto:
|
|
iptables += ' -p {!s}'.format(rule.proto)
|
|
if rule.dstports:
|
|
iptables += ' --dport {}'.format(
|
|
str(rule.dstports).replace('-', ':'))
|
|
iptables += ' -j {0}\n'.format(str(rule.action).upper())
|
|
|
|
iptables += '-A FORWARD -s {0} -j {1}\n'.format(ip,
|
|
str(conf.policy).upper())
|
|
iptables += 'COMMIT\n'
|
|
firewallvm.qdb.write('/qubes-iptables-domainrules/' + str(xid),
|
|
iptables)
|
|
# no need for ending -A FORWARD -j DROP, cause default action is DROP
|
|
|
|
firewallvm.qdb.write('/qubes-iptables', 'reload')
|
|
|
|
def write_services(self, vm):
|
|
for feature, value in vm.features.items():
|
|
service = self.features_to_services.get(feature, None)
|
|
if service is None:
|
|
continue
|
|
# forcefully convert to '0' or '1'
|
|
vm.qdb.write('/qubes-service/{}'.format(service),
|
|
str(int(bool(value))))
|
|
if 'updates-proxy-setup' in vm.features.keys():
|
|
vm.qdb.write('/qubes-service/{}'.format('yum-proxy-setup'),
|
|
str(int(bool(vm.features['updates-proxy-setup']))))
|