Browse Source

proxyvm: add support for rules with expire time (#760)

Marek Marczykowski-Górecki 10 years ago
parent
commit
e90e1c62ec

+ 18 - 1
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"])
 

+ 12 - 0
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

+ 5 - 0
linux/systemd/qubes-reload-firewall@.timer

@@ -0,0 +1,5 @@
+[Unit]
+Description=Reload VM firewall to expire its temporary rules
+
+[Timer]
+OnActiveSec=1m

+ 12 - 1
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()

+ 4 - 0
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