diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index 4ccff877..51a9b60c 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -29,6 +29,7 @@ import xml.parsers.expat import fcntl import re import shutil +from datetime import datetime from qmemman_client import QMemmanClient # Do not use XenAPI or create/read any VM files @@ -960,8 +961,85 @@ class QubesFirewallVm(QubesNetVm): self.write_iptables_xenstore_entry() def write_iptables_xenstore_entry(self): - iptables = "" - retcode = subprocess.check_call ([ + iptables = "# Generated by Qubes Core on {0}\n".format(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 state --state 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" + + # Allow dom0 networking + iptables += "-A FORWARD -i vif0.0 -j ACCEPT\n" + + qvm_collection = QubesVmCollection() + qvm_collection.lock_db_for_reading() + qvm_collection.load() + qvm_collection.unlock_db() + + vms = [vm for vm in qvm_collection.values() if vm.is_appvm()] + for vm in vms: + conf = vm.get_firewall_conf() + + xid = vm.get_xid() + if xid < 0: # VM not active ATM + continue + + iptables += "# '{0}' VM:\n".format(vm.name) + + if conf["allow"]: + iptables += "-A FORWARD ! -s {0}/32 -i vif{1}.0 -j DROP\n".format(vm.ip, xid) + + allow_rules = 0 + vm_iptables = "" + + for rule in conf["rules"]: + if rule["allow"]: + allow_rules += 1 + + vm_iptables += "# .. {0}:\n".format(rule["name"]) + + vm_iptables += "-A FORWARD -i vif{0}.0 -d {1}".format(xid, rule["address"]) + if rule["netmask"] != 32: + vm_iptables += "/{0}".format(rule["netmask"]) + + if rule["portBegin"] > 0: + vm_iptables += " -p tcp --dport {0}".format(rule["portBegin"]) + if rule["portEnd"] is not None and rule["portEnd"] > rule["portBegin"]: + vm_iptables += ":{0}".format(rule["portEnd"]) + + vm_iptables += " -j {0}\n".format("ACCEPT" if rule["allow"]\ + else "REJECT --reject-with icmp-host-prohibited", + ) + + iptables += vm_iptables + + if allow_rules > 0: + iptables += "# .. Needs DNS access\n" + iptables += "-A FORWARD -i vif{0}.0 -p udp --dport 53 -j ACCEPT\n".format(xid) + iptables += "# .. Allow ICMP to test network connectivity\n" + iptables += "-A FORWARD -i vif{0}.0 -p icmp -j ACCEPT\n".format(xid) + iptables += "# .. Deny everything not allowed before\n" + iptables += "-A FORWARD -i vif{0}.0 -j DROP\n".format(xid) + else: + iptables += "# .. Allow everything not denied before\n" + iptables += "-A FORWARD -i vif{0}.0 -j ACCEPT\n".format(xid) + + else: + iptables += "-A FORWARD -i vif{0}.0 -j DROP\n".format(xid) + + iptables += "#End of VM rules\n" + iptables += "-A FORWARD -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT\n" + iptables += "-A FORWARD -j DROP\n" + + iptables += "COMMIT" + + return subprocess.check_call ([ "/usr/bin/xenstore-write", "/local/domain/{0}/qubes_iptables".format(self.get_xid()), iptables])