From f05c244321fab1c61049beb1afe1aea9d240c8ff Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Wed, 9 Mar 2011 17:27:35 +0100 Subject: [PATCH 1/8] Added AppVM version of xenstore-watch. --- appvm/Makefile | 7 +++++-- appvm/xenstore-watch.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 appvm/xenstore-watch.c diff --git a/appvm/Makefile b/appvm/Makefile index 6bb1dea6..0ef375a7 100644 --- a/appvm/Makefile +++ b/appvm/Makefile @@ -1,11 +1,14 @@ CC=gcc CFLAGS=-Wall -all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm +all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm xenstore-watch qubes_penctl: qubes_penctl.o $(CC) -o qubes_penctl qubes_penctl.o -lxenstore qubes_add_pendrive_script: qubes_add_pendrive_script.o $(CC) -o qubes_add_pendrive_script qubes_add_pendrive_script.o -lxenstore qvm-open-in-dvm: qvm-open-in-dvm.o $(CC) -o qvm-open-in-dvm qvm-open-in-dvm.o -lxenstore +xenstore-watch: xenstore-watch.o + $(CC) -o xenstore-watch xenstore-watch.o -lxenstore + clean: - rm -f qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm *.o *~ + rm -f qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm xenstore-watch *.o *~ diff --git a/appvm/xenstore-watch.c b/appvm/xenstore-watch.c new file mode 100644 index 00000000..497ed294 --- /dev/null +++ b/appvm/xenstore-watch.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +main(int argc, char **argv) +{ + struct xs_handle *xs; + unsigned int count; + char **vec; + char dummy; + if (argc != 2) { + fprintf(stderr, "usage: %s xenstore_path\n", argv[0]); + exit(1); + } + xs = xs_domain_open(); + if (!xs) { + perror("xs_domain_open"); + exit(1); + } + if (!xs_watch(xs, argv[1], &dummy)) { + perror("xs_watch"); + exit(1); + } + vec = xs_read_watch(xs, &count); + free(vec); + vec = xs_read_watch(xs, &count); + free(vec); +} From ca81f0103d0d9741f6c7b0b232f14cdde75bc111 Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Wed, 9 Mar 2011 17:38:34 +0100 Subject: [PATCH 2/8] Update firewall rules on VM start --- dom0/qvm-core/qubes.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index adde77ec..04ef5616 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -552,11 +552,16 @@ class QubesVm(object): self.force_shutdown() raise OSError ("ERROR: Cannot attach to network backend!") - #if verbose: - # print "--> Updating FirewallVMs rules..." - #for vm in qvm_collection.values(): - # if vm.is_fwvm(): - # vm.write_iptables_xenstore_entry() + qvm_collection = QubesVmCollection() + qvm_collection.lock_db_for_reading() + qvm_collection.load() + qvm_collection.unlock_db() + + if verbose: + print "--> Updating FirewallVMs rules..." + for vm in qvm_collection.values(): + if vm.is_fwvm(): + vm.write_iptables_xenstore_entry() if verbose: print "--> Starting the VM..." From fd8ecca9bdb2369a87ba53e3bdb72c34fd28adac Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Wed, 9 Mar 2011 17:39:09 +0100 Subject: [PATCH 3/8] Create qubes_iptables_error xenstore file in FwVM and set its permissions. --- dom0/qvm-core/qubes.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index 04ef5616..d6d9a28f 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -943,6 +943,14 @@ class QubesFirewallVm(QubesNetVm): return super(QubesFirewallVm, self).create_xenstore_entries(xid) + retcode = subprocess.check_call ([ + "/usr/bin/xenstore-write", + "/local/domain/{0}/qubes_iptables_error".format(xid), + ""]) + retcode = subprocess.check_call ([ + "/usr/bin/xenstore-chmod", + "/local/domain/{0}/qubes_iptables_error".format(xid), + "r{0} w{1}".format(xid,xid)]) self.write_iptables_xenstore_entry() def write_iptables_xenstore_entry(self): From 6ad91617a79e9a2d61a72274845f08ee275aadc3 Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Wed, 9 Mar 2011 18:07:22 +0100 Subject: [PATCH 4/8] Store the state of FwVM rules --- dom0/qvm-core/qubes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index d6d9a28f..d28dbeeb 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -933,6 +933,7 @@ class QubesFirewallVm(QubesNetVm): """ def __init__(self, **kwargs): super(QubesFirewallVm, self).__init__(uses_default_netvm=False, **kwargs) + self.rules_applied = None @property def type(self): @@ -1021,6 +1022,7 @@ class QubesFirewallVm(QubesNetVm): iptables += "COMMIT" + self.rules_applied = None return subprocess.check_call ([ "/usr/bin/xenstore-write", "/local/domain/{0}/qubes_iptables".format(self.get_xid()), From 87ff30fe2626515d1e00df89f8433ae6fea66114 Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Wed, 9 Mar 2011 19:47:08 +0100 Subject: [PATCH 5/8] Fixed xenstore-chmod call syntax --- dom0/qvm-core/qubes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index d28dbeeb..93934f5e 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -951,7 +951,7 @@ class QubesFirewallVm(QubesNetVm): retcode = subprocess.check_call ([ "/usr/bin/xenstore-chmod", "/local/domain/{0}/qubes_iptables_error".format(xid), - "r{0} w{1}".format(xid,xid)]) + "n0", "r{0}".format(xid), "w{0}".format(xid)]) self.write_iptables_xenstore_entry() def write_iptables_xenstore_entry(self): From 58a4b4c82bc53f9727b8e414325f62f5a22c04f9 Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Wed, 9 Mar 2011 19:47:12 +0100 Subject: [PATCH 6/8] Implemented qubes_netvm_external_ip feature. --- dom0/qvm-core/qubes.py | 47 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index 93934f5e..e7c75b3d 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -883,6 +883,8 @@ class QubesNetVm(QubesServiceVm): self.__gateway = self.netprefix + "0.1" self.__secondary_dns = self.netprefix + "255.254" + self.__external_ip_allowed_xids = set() + if "label" not in kwargs or kwargs["label"] is None: kwargs["label"] = default_servicevm_label super(QubesNetVm, self).__init__(installed_by_rpm=True, **kwargs) @@ -913,6 +915,42 @@ class QubesNetVm(QubesServiceVm): assert hi >= 0 and hi <= 254 and lo >= 2 and lo <= 254, "Wrong IP address for VM" return self.netprefix + "{0}.{1}".format(hi,lo) + def create_xenstore_entries(self, xid): + if dry_run: + return + + super(QubesNetVm, self).create_xenstore_entries(xid) + retcode = subprocess.check_call ([ + "/usr/bin/xenstore-write", + "/local/domain/{0}/qubes_netvm_external_ip".format(xid), + ""]) + self.update_external_ip_permissions() + + def update_external_ip_permissions(self): + xid = self.get_xid() + command = [ + "/usr/bin/xenstore-chmod", + "/local/domain/{0}/qubes_netvm_external_ip".format(xid) + ] + + command.append("r{0}".format(xid,xid)) + command.append("w{0}".format(xid,xid)) + + for id in self.__external_ip_allowed_xids: + command.append("r{0}".format(id)) + + return subprocess.check_call(command) + + def add_external_ip_permission(self, xid): + if int(xid) < 0: + return + self.__external_ip_allowed_xids.add(int(xid)) + self.update_external_ip_permissions() + + def remove_external_ip_permission(self, xid): + self.__external_ip_allowed_xids.discard(int(xid)) + self.update_external_ip_permissions() + def create_xml_element(self): element = xml.etree.ElementTree.Element( "QubesNetVm", @@ -934,11 +972,18 @@ class QubesFirewallVm(QubesNetVm): def __init__(self, **kwargs): super(QubesFirewallVm, self).__init__(uses_default_netvm=False, **kwargs) self.rules_applied = None + self.netvm_vm.add_external_ip_permission(self.get_xid()) @property def type(self): return "FirewallVM" + def force_shutdown(self): + if dry_run: + return + self.netvm_vm.remove_external_ip_permission(self.get_xid()) + super(QubesFirewallVm, self).force_shutdown() + def create_xenstore_entries(self, xid): if dry_run: return @@ -951,7 +996,7 @@ class QubesFirewallVm(QubesNetVm): retcode = subprocess.check_call ([ "/usr/bin/xenstore-chmod", "/local/domain/{0}/qubes_iptables_error".format(xid), - "n0", "r{0}".format(xid), "w{0}".format(xid)]) + "r{0}".format(xid), "w{0}".format(xid)]) self.write_iptables_xenstore_entry() def write_iptables_xenstore_entry(self): From afbdfe8ae4f2aa7f594307b6fe15675e3e39b45f Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Wed, 9 Mar 2011 20:38:14 +0100 Subject: [PATCH 7/8] Store netvm domid in FwVM. --- dom0/qvm-core/qubes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index e7c75b3d..7b3e48d7 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -989,6 +989,10 @@ class QubesFirewallVm(QubesNetVm): return super(QubesFirewallVm, self).create_xenstore_entries(xid) + retcode = subprocess.check_call ([ + "/usr/bin/xenstore-write", + "/local/domain/{0}/qubes_netvm_domid".format(xid), + "{0}".format(self.netvm_vm.get_xid())]) retcode = subprocess.check_call ([ "/usr/bin/xenstore-write", "/local/domain/{0}/qubes_iptables_error".format(xid), From a71b846ee2855e12be6df26aea98b66e4937b861 Mon Sep 17 00:00:00 2001 From: Tomasz Sterna Date: Wed, 9 Mar 2011 20:50:13 +0100 Subject: [PATCH 8/8] Added FirewallVM related VM scripts --- fwvm/bin/qubes_firewall | 33 +++++++++++++++++++ fwvm/init.d/qubes_core | 67 ++++++++++++++++++++++++++++++++++++++ fwvm/init.d/qubes_firewall | 42 ++++++++++++++++++++++++ netvm/30-qubes_external_ip | 8 +++++ rpm_spec/core-netvm.spec | 1 + 5 files changed, 151 insertions(+) create mode 100755 fwvm/bin/qubes_firewall create mode 100755 fwvm/init.d/qubes_core create mode 100755 fwvm/init.d/qubes_firewall create mode 100755 netvm/30-qubes_external_ip diff --git a/fwvm/bin/qubes_firewall b/fwvm/bin/qubes_firewall new file mode 100755 index 00000000..6f1cc267 --- /dev/null +++ b/fwvm/bin/qubes_firewall @@ -0,0 +1,33 @@ +#!/bin/bash +set -e + +PIDFILE=/var/run/qubes/qubes_firewall.pid +XENSTORE_IPTABLES=qubes_iptables +XENSTORE_ERROR=qubes_iptables_error +OLD_RULES="" + +# PIDfile handling +[[ -e $PIDFILE ]] && kill -s 0 $(<$PIDFILE) 2>/dev/null && exit 0 +echo $$ >$PIDFILE + +trap 'exit 0' SIGTERM + +while true; do + RULES=$(/usr/bin/xenstore-read $XENSTORE_IPTABLES) + + if [[ "$RULES" != "$OLD_RULES" ]]; then + IPTABLES_SAVE=$(/sbin/iptables-save | sed '/^\*filter/,/^COMMIT/d') + OUT=`echo -e "$RULES\n$IPTABLES_SAVE" | /sbin/iptables-restore 2>&1 || :` + /usr/bin/xenstore-write $XENSTORE_ERROR "$OUT" + + if [[ -z "$OUT" ]]; then + # If OK save it for later + /sbin/service iptables save >/dev/null + fi + + OLD_RULES="$RULES" + fi + + # Wait for changes in xenstore file + /usr/bin/xenstore-watch $XENSTORE_IPTABLES +done diff --git a/fwvm/init.d/qubes_core b/fwvm/init.d/qubes_core new file mode 100755 index 00000000..d6bcac28 --- /dev/null +++ b/fwvm/init.d/qubes_core @@ -0,0 +1,67 @@ +#!/bin/sh +# +# chkconfig: 345 90 90 +# description: Executes Qubes core scripts at VM boot +# +# Source function library. +. /etc/rc.d/init.d/functions + +start() +{ + echo -n $"Executing Qubes Core scripts FirewallVM:" + + if ! [ -x /usr/bin/xenstore-read ] ; then + echo "ERROR: /usr/bin/xenstore-read not found!" + exit 1 + fi + + name=$(/usr/bin/xenstore-read name) + hostname $name + + # Setup gateway for all the VMs this netVM is serviceing... + modprobe netbk + gateway=$(/usr/bin/xenstore-read qubes_netvm_gateway) + netmask=$(/usr/bin/xenstore-read qubes_netvm_netmask) + network=$(/usr/bin/xenstore-read qubes_netvm_network) + secondary_dns=$(/usr/bin/xenstore-read qubes_netvm_secondary_dns) + echo "NS1=$gateway" > /var/run/qubes/qubes_ns + echo "NS2=$secondary_dns" >> /var/run/qubes/qubes_ns + /usr/lib/qubes/qubes_setup_dnat_to_ns + echo "1" > /proc/sys/net/ipv4/ip_forward + + # Now setup "AppVM" part of FirewallVM + ip=$(/usr/bin/xenstore-read qubes_ip) + netmask=$(/usr/bin/xenstore-read qubes_netmask) + gateway=$(/usr/bin/xenstore-read qubes_gateway) + secondary_dns=$(/usr/bin/xenstore-read qubes_secondary_dns) + if [ x$ip != x ]; then + /sbin/ifconfig eth0 $ip netmask 255.255.255.255 up + /sbin/route add default dev eth0 + echo "nameserver $gateway" > /etc/resolv.conf + echo "nameserver $secondary_dns" >> /etc/resolv.conf + fi + + success + echo "" + return 0 +} + +stop() +{ + return 0 +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + *) + echo $"Usage: $0 {start|stop}" + exit 3 + ;; +esac + +exit $RETVAL diff --git a/fwvm/init.d/qubes_firewall b/fwvm/init.d/qubes_firewall new file mode 100755 index 00000000..f970734f --- /dev/null +++ b/fwvm/init.d/qubes_firewall @@ -0,0 +1,42 @@ +#!/bin/sh +# +# chkconfig: 345 91 91 +# description: Starts Qubes Firewall monitor +# +# Source function library. +. /etc/rc.d/init.d/functions + +PIDFILE=/var/run/qubes/qubes_firewall.pid + +start() +{ + echo -n $"Starting Qubes Firewall monitor:" + /sbin/ethtool -K eth0 sg off + /usr/bin/qubes_firewall & + success + echo "" + return 0 +} + +stop() +{ + echo -n "Stopping Qubes Firewall monitor:" + kill $(cat $PIDFILE) 2>/dev/null && success || failure + echo "" + return 0 +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + *) + echo $"Usage: $0 {start|stop}" + exit 3 + ;; +esac + +exit $RETVAL diff --git a/netvm/30-qubes_external_ip b/netvm/30-qubes_external_ip new file mode 100755 index 00000000..66ae5269 --- /dev/null +++ b/netvm/30-qubes_external_ip @@ -0,0 +1,8 @@ +#!/bin/sh +if [ x$2 == xup ]; then + INET=$(/sbin/ip addr show dev $1 | /bin/grep inet) + /usr/bin/xenstore-write qubes_netvm_external_ip "$INET" +fi +if [ x$2 == xdown ]; then + /usr/bin/xenstore-write qubes_netvm_external_ip "" +fi diff --git a/rpm_spec/core-netvm.spec b/rpm_spec/core-netvm.spec index 83d88c29..47a04ff0 100644 --- a/rpm_spec/core-netvm.spec +++ b/rpm_spec/core-netvm.spec @@ -67,6 +67,7 @@ mkdir -p $RPM_BUILD_ROOT/etc/dhclient.d ln -s /usr/lib/qubes/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/etc/dhclient.d/qubes_setup_dnat_to_ns.sh mkdir -p $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/ cp ../common/qubes_nmhook $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/ +cp ../netvm/30-qubes_external_ip $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/ mkdir -p $RPM_BUILD_ROOT/etc/yum.repos.d cp ../netvm/qubes.repo $RPM_BUILD_ROOT/etc/yum.repos.d mkdir -p $RPM_BUILD_ROOT/sbin