firewall: use asyncio's call_later instead of systemd to reload rules

When some expiring rules are present, it is necessary to reload firewall
when those rules expire. Previously systemd timer was used to trigger
this action, but since we have own daemon now, it isn't necessary
anymore - use this daemon for that.
Additionally automatically removing expired rules was completely broken
in R4.0.

Fixes QubesOS/qubes-issues#1173
This commit is contained in:
Marek Marczykowski-Górecki 2018-02-07 02:40:56 +01:00
parent 9b5256f002
commit 5e89b23288
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
3 changed files with 22 additions and 10 deletions

View File

@ -7,8 +7,6 @@ install:
mkdir -p $(DESTDIR)$(UNITDIR)
cp qubes-core.service $(DESTDIR)$(UNITDIR)
cp qubes-vm@.service $(DESTDIR)$(UNITDIR)
cp qubes-reload-firewall@.service $(DESTDIR)$(UNITDIR)
cp qubes-reload-firewall@.timer $(DESTDIR)$(UNITDIR)
cp qubes-qmemman.service $(DESTDIR)$(UNITDIR)
cp qubesd.service $(DESTDIR)$(UNITDIR)
install -d $(DESTDIR)$(UNITDIR)/lvm2-pvscan@.service.d

View File

@ -22,11 +22,12 @@
import datetime
import string
import subprocess
import itertools
import os
import socket
import asyncio
import lxml.etree
import qubes
@ -543,10 +544,19 @@ class Firewall(object):
rule = Rule(xml_rule)
self.rules.append(rule)
def _expire_rules(self):
'''Function called to reload expired rules'''
old_rules = self.rules
self.load()
if self.rules != old_rules:
# this will both save rules skipping those expired and trigger
# QubesDB update; and possibly schedule another timer
self.save()
def save(self):
'''Save firewall rules to a file'''
firewall_conf = os.path.join(self.vm.dir_path, self.vm.firewall_conf)
expiring_rules_present = False
nearest_expire = False
xml_root = lxml.etree.Element('firewall', version=str(2))
@ -556,7 +566,9 @@ class Firewall(object):
if rule.expire and rule.expire.expired:
continue
else:
expiring_rules_present = True
if nearest_expire is None or rule.expire.datetime < \
nearest_expire:
nearest_expire = rule.expire.datetime
xml_rule = lxml.etree.Element('rule')
xml_rule.append(rule.xml_properties())
xml_rules.append(xml_rule)
@ -577,9 +589,13 @@ class Firewall(object):
self.vm.fire_event('firewall-changed')
if expiring_rules_present and not self.vm.app.vmm.offline_mode:
subprocess.call(["sudo", "systemctl", "start",
"qubes-reload-firewall@%s.timer" % self.vm.name])
if nearest_expire and not self.vm.app.vmm.offline_mode:
loop = asyncio.get_event_loop()
# by documentation call_at use loop.time() clock, which not
# necessary must be the same as time module; calculate delay and
# use call_later instead
expire_when = nearest_expire - datetime.datetime.now()
loop.call_later(expire_when, self._expire_rules)
def qdb_entries(self, addr_family=None):
'''Return firewall settings serialized for QubesDB entries

View File

@ -399,8 +399,6 @@ fi
%{_unitdir}/qubes-qmemman.service
%{_unitdir}/qubes-vm@.service
%{_unitdir}/qubesd.service
%{_unitdir}/qubes-reload-firewall@.service
%{_unitdir}/qubes-reload-firewall@.timer
%attr(2770,root,qubes) %dir /var/lib/qubes
%attr(2770,root,qubes) %dir /var/lib/qubes/vm-templates
%attr(2770,root,qubes) %dir /var/lib/qubes/appvms