From e90e1c62ece3e36543ea7822cb85c5effb26b2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Thu, 27 Mar 2014 17:16:47 +0100 Subject: [PATCH] proxyvm: add support for rules with expire time (#760) --- core-modules/000QubesVm.py | 19 ++++++++++++++++++- linux/systemd/qubes-reload-firewall@.service | 12 ++++++++++++ linux/systemd/qubes-reload-firewall@.timer | 5 +++++ qvm-tools/qvm-firewall | 13 ++++++++++++- rpm_spec/core-dom0.spec | 4 ++++ 5 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 linux/systemd/qubes-reload-firewall@.service create mode 100644 linux/systemd/qubes-reload-firewall@.timer diff --git a/core-modules/000QubesVm.py b/core-modules/000QubesVm.py index 75b8dc46..3a5e0c5a 100644 --- a/core-modules/000QubesVm.py +++ b/core-modules/000QubesVm.py @@ -1247,6 +1247,7 @@ class QubesVm(object): def write_firewall_conf(self, conf): defaults = self.get_firewall_conf() + expiring_rules_present = False for item in defaults.keys(): if item not in conf: conf[item] = defaults[item] @@ -1277,6 +1278,9 @@ class QubesVm(object): element.set("port", str(rule["portBegin"])) if rule["portEnd"] is not None and rule["portEnd"] > 0: element.set("toport", str(rule["portEnd"])) + if "expire" in rule: + element.set("expire", str(rule["expire"])) + expiring_rules_present = True root.append(element) @@ -1303,6 +1307,10 @@ class QubesVm(object): if self.services.has_key('yum-proxy-setup'): self.services.pop('yum-proxy-setup') + if expiring_rules_present: + subprocess.call(["sudo", "systemctl", "start", + "qubes-reload-firewall@%s.timer" % self.name]) + return True def has_firewall(self): @@ -1325,7 +1333,8 @@ class QubesVm(object): for element in root: rule = {} - attr_list = ("address", "netmask", "proto", "port", "toport") + attr_list = ("address", "netmask", "proto", "port", "toport", + "expire") for attribute in attr_list: rule[attribute] = element.get(attribute) @@ -1353,6 +1362,14 @@ class QubesVm(object): else: rule["portEnd"] = None + if rule["expire"] is not None: + rule["expire"] = int(rule["expire"]) + if rule["expire"] <= int(datetime.datetime.now().strftime( + "%s")): + continue + else: + del(rule["expire"]) + del(rule["port"]) del(rule["toport"]) diff --git a/linux/systemd/qubes-reload-firewall@.service b/linux/systemd/qubes-reload-firewall@.service new file mode 100644 index 00000000..c8ee660e --- /dev/null +++ b/linux/systemd/qubes-reload-firewall@.service @@ -0,0 +1,12 @@ +[Unit] +Description=Reload firewall for VM %i +After=qubes-netvm.service + +[Service] +Type=simple +ExecStart=/usr/bin/qvm-firewall --force-root -r %i +ExecStartPost=/bin/sh -c '/usr/bin/qvm-firewall --force-root %i | grep -q "expires at" || systemctl stop %p@%i.timer' +Group=qubes + +[Install] +WantedBy=multi-user.target diff --git a/linux/systemd/qubes-reload-firewall@.timer b/linux/systemd/qubes-reload-firewall@.timer new file mode 100644 index 00000000..a1fd4eb4 --- /dev/null +++ b/linux/systemd/qubes-reload-firewall@.timer @@ -0,0 +1,5 @@ +[Unit] +Description=Reload VM firewall to expire its temporary rules + +[Timer] +OnActiveSec=1m diff --git a/qvm-tools/qvm-firewall b/qvm-tools/qvm-firewall index d9898580..2c9120ca 100755 --- a/qvm-tools/qvm-firewall +++ b/qvm-tools/qvm-firewall @@ -19,6 +19,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # +import datetime from qubes.qubes import QubesVmCollection from optparse import OptionParser; @@ -149,6 +150,10 @@ def list_rules(rules): if rule['portBegin'] is not None and rule['portEnd'] is None: parsed_rule['port(s)'] = get_service_name(rule['portBegin']) + if 'expire' in rule: + parsed_rule['expire'] = str(datetime.datetime.fromtimestamp(rule[ + 'expire'])) + rules_to_display.append(parsed_rule) counter += 1 @@ -184,6 +189,8 @@ def list_rules(rules): for f in fields: fmt=" {{0:<{0}}} |".format(fields_width[f]) s += fmt.format(r[f]) + if 'expire' in r: + s += " <-- expires at %s" % r['expire'] print s def display_firewall(conf): @@ -255,6 +262,9 @@ def main(): help="Set DNS access (allow/deny)") parser.add_option ("-Y", "--yum-proxy", dest="set_yum_proxy", action="store", default=None, help="Set access to Qubes yum proxy (allow/deny)") + parser.add_option ("-r", "--reload", dest="reload", action="store_true", + default=False, help="Reload firewall (implied by any " + "change action") parser.add_option ("-n", "--numeric", dest="numeric", action="store_true", default=False, help="Display port numbers instead of services (makes sense only with --list)") @@ -312,7 +322,7 @@ def main(): elif options.do_del: load_services() changed = del_rule(conf, args) - elif options.do_list: + elif options.do_list and not options.reload: if not options.numeric: load_services() if not vm.has_firewall(): @@ -321,6 +331,7 @@ def main(): if changed: vm.write_firewall_conf(conf) + if changed or options.reload: if vm.is_running(): if vm.netvm is not None and vm.netvm.is_proxyvm(): vm.netvm.write_iptables_xenstore_entry() diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index 4302ed02..c5a0bdda 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -91,6 +91,8 @@ cp linux/systemd/qubes-setupdvm.service $RPM_BUILD_ROOT%{_unitdir} cp linux/systemd/qubes-netvm.service $RPM_BUILD_ROOT%{_unitdir} cp linux/systemd/qubes-qmemman.service $RPM_BUILD_ROOT%{_unitdir} cp linux/systemd/qubes-vm@.service $RPM_BUILD_ROOT%{_unitdir} +cp linux/systemd/qubes-reload-firewall@.service $RPM_BUILD_ROOT%{_unitdir} +cp linux/systemd/qubes-reload-firewall@.timer $RPM_BUILD_ROOT%{_unitdir} mkdir -p $RPM_BUILD_ROOT/usr/bin/ cp qvm-tools/qvm-* $RPM_BUILD_ROOT/usr/bin @@ -302,6 +304,8 @@ fi %{_unitdir}/qubes-netvm.service %{_unitdir}/qubes-qmemman.service %{_unitdir}/qubes-vm@.service +%{_unitdir}/qubes-reload-firewall@.service +%{_unitdir}/qubes-reload-firewall@.timer %attr(0770,root,qubes) %dir /var/lib/qubes %attr(0770,root,qubes) %dir /var/lib/qubes/vm-templates %attr(0770,root,qubes) %dir /var/lib/qubes/appvms