diff --git a/debian/qubes-core-agent-networking.install b/debian/qubes-core-agent-networking.install index 7f371ef..c26f251 100644 --- a/debian/qubes-core-agent-networking.install +++ b/debian/qubes-core-agent-networking.install @@ -11,8 +11,12 @@ etc/xen/scripts/vif-route-qubes lib/systemd/system/qubes-firewall.service lib/systemd/system/qubes-iptables.service lib/systemd/system/qubes-network.service +lib/systemd/system/qubes-network-uplink.service +lib/systemd/system/qubes-network-uplink@.service lib/systemd/system/qubes-updates-proxy.service usr/lib/qubes/init/network-proxy-setup.sh +usr/lib/qubes/init/network-proxy-stop.sh +usr/lib/qubes/init/network-uplink-wait.sh usr/lib/qubes/init/qubes-iptables usr/lib/qubes/iptables-updates-proxy usr/lib/qubes/qubes-setup-dnat-to-ns diff --git a/init/functions b/init/functions index 2582b4d..ba05485 100644 --- a/init/functions +++ b/init/functions @@ -118,7 +118,7 @@ umount_retry() { get_mac_from_iface() { local iface="$1" - local mac + local mac= if [ "x$iface" != "x" ] && [ -e "/sys/class/net/$iface" ]; then mac="$(cat "/sys/class/net/$iface/address")" fi @@ -127,7 +127,7 @@ get_mac_from_iface() { get_iface_from_mac() { local mac="$1" - local iface + local iface= if [ "x$mac" != "x" ]; then iface="$(ip -o link | grep -i "$mac" | awk '{print $2}' | cut -d ':' -f1)" fi @@ -141,7 +141,7 @@ get_qubes_managed_iface() { qubes_iface="$(get_iface_from_mac "$mac")" if [ "x$qubes_iface" != "x" ]; then echo "$qubes_iface" - else + elif [ -e /sys/class/net/eth0 ]; then echo eth0 fi } diff --git a/network/ip6tables-enabled b/network/ip6tables-enabled index fc5aec1..d2e4a56 100644 --- a/network/ip6tables-enabled +++ b/network/ip6tables-enabled @@ -26,6 +26,7 @@ COMMIT -A INPUT -m state --state INVALID -j DROP -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT +-A INPUT ! -i vif+ -p udp -s fe80::/64 -d fe80::/64 --dport 546 -j ACCEPT -A INPUT -i vif+ -p icmpv6 --icmpv6-type router-advertisement -j DROP -A INPUT -i vif+ -p icmpv6 --icmpv6-type redirect -j DROP -A INPUT -i vif+ -p icmpv6 -j ACCEPT diff --git a/network/setup-ip b/network/setup-ip index 35e9fba..07c8568 100755 --- a/network/setup-ip +++ b/network/setup-ip @@ -173,67 +173,80 @@ qubes_ip_change_hook() { have_qubesdb || exit 0 -if [ -n "$INTERFACE" ]; then - if [ "$ACTION" == "add" ]; then - MAC="$(get_mac_from_iface "$INTERFACE")" - if [ -n "$MAC" ]; then - ip="$(/usr/bin/qubesdb-read "/net-config/$MAC/ip" 2> /dev/null)" || ip= - ip6="$(/usr/bin/qubesdb-read "/net-config/$MAC/ip6" 2> /dev/null)" || ip6= - netmask="$(/usr/bin/qubesdb-read "/net-config/$MAC/netmask" 2> /dev/null)" || netmask= - netmask6="$(/usr/bin/qubesdb-read "/net-config/$MAC/netmask6" 2> /dev/null)" || netmask6= - gateway="$(/usr/bin/qubesdb-read "/net-config/$MAC/gateway" 2> /dev/null)" || gateway= - gateway6="$(/usr/bin/qubesdb-read "/net-config/$MAC/gateway6" 2> /dev/null)" || gateway6= +ACTION="$1" +INTERFACE="$2" - # Handle legacy values - LEGACY_MAC="$(/usr/bin/qubesdb-read /qubes-mac 2> /dev/null)" || LEGACY_MAC= - if [ "$MAC" == "$LEGACY_MAC" ] || [ -z "$LEGACY_MAC" ]; then - if [ -z "$ip" ]; then - ip="$(/usr/bin/qubesdb-read /qubes-ip 2> /dev/null)" || ip= - fi - if [ -z "$ip6" ]; then - ip6="$(/usr/bin/qubesdb-read /qubes-ip6 2> /dev/null)" || ip6= - fi - if [ -z "$gateway" ]; then - gateway="$(/usr/bin/qubesdb-read /qubes-gateway 2> /dev/null)" || gateway= - fi - if [ -z "$gateway6" ]; then - gateway6="$(/usr/bin/qubesdb-read /qubes-gateway6 2> /dev/null)" || gateway6= - fi +if [ -z "$INTERFACE" ]; then + echo "Missing INTERFACE argument" >&2 + exit 1 +fi + +if [ "$ACTION" == "add" ]; then + MAC="$(get_mac_from_iface "$INTERFACE")" + if [ -n "$MAC" ]; then + ip="$(/usr/bin/qubesdb-read "/net-config/$MAC/ip" 2> /dev/null)" || ip= + ip6="$(/usr/bin/qubesdb-read "/net-config/$MAC/ip6" 2> /dev/null)" || ip6= + netmask="$(/usr/bin/qubesdb-read "/net-config/$MAC/netmask" 2> /dev/null)" || netmask= + netmask6="$(/usr/bin/qubesdb-read "/net-config/$MAC/netmask6" 2> /dev/null)" || netmask6= + gateway="$(/usr/bin/qubesdb-read "/net-config/$MAC/gateway" 2> /dev/null)" || gateway= + gateway6="$(/usr/bin/qubesdb-read "/net-config/$MAC/gateway6" 2> /dev/null)" || gateway6= + + # Handle legacy values + LEGACY_MAC="$(/usr/bin/qubesdb-read /qubes-mac 2> /dev/null)" || LEGACY_MAC= + if [ "$MAC" == "$LEGACY_MAC" ] || [ -z "$LEGACY_MAC" ]; then + if [ -z "$ip" ]; then + ip="$(/usr/bin/qubesdb-read /qubes-ip 2> /dev/null)" || ip= fi - - if [ -z "$netmask" ]; then - netmask="255.255.255.255" + if [ -z "$ip6" ]; then + ip6="$(/usr/bin/qubesdb-read /qubes-ip6 2> /dev/null)" || ip6= fi - if [ -z "$netmask6" ]; then - netmask6="128" + if [ -z "$gateway" ]; then + gateway="$(/usr/bin/qubesdb-read /qubes-gateway 2> /dev/null)" || gateway= fi - - primary_dns=$(/usr/bin/qubesdb-read /qubes-primary-dns 2>/dev/null) || primary_dns= - secondary_dns=$(/usr/bin/qubesdb-read /qubes-secondary-dns 2>/dev/null) || secondary_dns= - - if [ -n "$ip" ]; then - /sbin/ethtool -K "$INTERFACE" sg off - /sbin/ethtool -K "$INTERFACE" tx off - - # If NetworkManager is enabled, let it configure the network - if qsvc network-manager && [ -e /usr/bin/nmcli ]; then - configure_network_nm "$MAC" "$INTERFACE" "$ip" "$ip6" "$netmask" "$netmask6" "$gateway" "$gateway6" "$primary_dns" "$secondary_dns" - else - configure_network "$MAC" "$INTERFACE" "$ip" "$ip6" "$netmask" "$netmask6" "$gateway" "$gateway6" "$primary_dns" "$secondary_dns" - fi - - network=$(qubesdb-read /qubes-netvm-network 2>/dev/null) || network= - if [ -n "$network" ]; then - if ! qsvc disable-dns-server; then - configure_qubes_ns - fi - qubes_ip_change_hook - fi + if [ -z "$gateway6" ]; then + gateway6="$(/usr/bin/qubesdb-read /qubes-gateway6 2> /dev/null)" || gateway6= + fi + fi + + if [ -z "$netmask" ]; then + netmask="255.255.255.255" + fi + if [ -z "$netmask6" ]; then + netmask6="128" + fi + + primary_dns=$(/usr/bin/qubesdb-read /qubes-primary-dns 2>/dev/null) || primary_dns= + secondary_dns=$(/usr/bin/qubesdb-read /qubes-secondary-dns 2>/dev/null) || secondary_dns= + + if [ -n "$ip" ]; then + /sbin/ethtool -K "$INTERFACE" sg off + /sbin/ethtool -K "$INTERFACE" tx off + + # If NetworkManager is enabled, let it configure the network + if qsvc network-manager && [ -e /usr/bin/nmcli ]; then + configure_network_nm "$MAC" "$INTERFACE" "$ip" "$ip6" "$netmask" "$netmask6" "$gateway" "$gateway6" "$primary_dns" "$secondary_dns" + else + configure_network "$MAC" "$INTERFACE" "$ip" "$ip6" "$netmask" "$netmask6" "$gateway" "$gateway6" "$primary_dns" "$secondary_dns" + fi + + network=$(qubesdb-read /qubes-netvm-network 2>/dev/null) || network= + if [ -n "$network" ]; then + if ! qsvc disable-dns-server; then + configure_qubes_ns + fi + qubes_ip_change_hook fi fi - elif [ "$ACTION" == "remove" ]; then - # If exists, we delete NetworkManager configuration file to prevent duplicate entries - nm_config="/etc/NetworkManager/system-connections/qubes-uplink-$INTERFACE" - rm -rf "$nm_config" fi +elif [ "$ACTION" == "remove" ]; then + # make sure network is disabled, especially on shutdown, to prevent + # leaks when firewall will get stopped too + ip link set "$INTERFACE" down 2>/dev/null || : + + # If exists, we delete NetworkManager configuration file to prevent duplicate entries + nm_config="/etc/NetworkManager/system-connections/qubes-uplink-$INTERFACE" + rm -rf "$nm_config" +else + echo "Invalid action '$ACTION'" >&2 + exit 1 fi diff --git a/network/udev-qubes-network.rules b/network/udev-qubes-network.rules index 0ae83b2..fde5fe9 100644 --- a/network/udev-qubes-network.rules +++ b/network/udev-qubes-network.rules @@ -1,5 +1,5 @@ # old udev has ENV{ID_NET_DRIVER} -SUBSYSTEMS=="xen", KERNEL=="eth*", ACTION=="add", ENV{ID_NET_DRIVER}=="vif", RUN+="/usr/lib/qubes/setup-ip" -SUBSYSTEMS=="net", KERNEL=="eth*", ACTION=="remove", ENV{ID_NET_DRIVER}=="vif", RUN+="/usr/lib/qubes/setup-ip" +SUBSYSTEMS=="xen", KERNEL=="eth*", ACTION=="add", ENV{ID_NET_DRIVER}=="vif", ENV{SYSTEMD_WANTS}+="qubes-network-uplink@%k.service" +SUBSYSTEMS=="net", KERNEL=="eth*", ACTION=="remove", ENV{ID_NET_DRIVER}=="vif", ENV{SYSTEMD_WANTS}+="qubes-network-uplink@%k.service" # new udev has DRIVERS -SUBSYSTEMS=="xen", KERNEL=="eth*", ACTION=="add", DRIVERS=="vif", RUN+="/usr/lib/qubes/setup-ip" +SUBSYSTEMS=="xen", KERNEL=="eth*", ACTION=="add", DRIVERS=="vif", ENV{SYSTEMD_WANTS}+="qubes-network-uplink@%k.service" diff --git a/rpm_spec/core-agent.spec.in b/rpm_spec/core-agent.spec.in index 0ec54e0..17720ab 100644 --- a/rpm_spec/core-agent.spec.in +++ b/rpm_spec/core-agent.spec.in @@ -797,8 +797,12 @@ rm -f %{name}-%{version} /lib/systemd/system/qubes-firewall.service /lib/systemd/system/qubes-iptables.service /lib/systemd/system/qubes-network.service +/lib/systemd/system/qubes-network-uplink.service +/lib/systemd/system/qubes-network-uplink@.service /lib/systemd/system/qubes-updates-proxy.service /usr/lib/qubes/init/network-proxy-setup.sh +/usr/lib/qubes/init/network-proxy-stop.sh +/usr/lib/qubes/init/network-uplink-wait.sh /usr/lib/qubes/init/qubes-iptables /usr/lib/qubes/iptables-updates-proxy /usr/lib/qubes/qubes-setup-dnat-to-ns diff --git a/vm-systemd/75-qubes-vm.preset b/vm-systemd/75-qubes-vm.preset index a2f6cd8..c0fcbe3 100644 --- a/vm-systemd/75-qubes-vm.preset +++ b/vm-systemd/75-qubes-vm.preset @@ -91,6 +91,7 @@ enable qubes-update-check.timer enable qubes-misc-post.service enable qubes-updates-proxy.service enable qubes-network.service +enable qubes-network-uplink.service enable qubes-qrexec-agent.service enable qubes-mount-dirs.service enable qubes-rootfs-resize.service diff --git a/vm-systemd/NetworkManager.service.d/30_qubes.conf b/vm-systemd/NetworkManager.service.d/30_qubes.conf index 047cc22..5f598a1 100644 --- a/vm-systemd/NetworkManager.service.d/30_qubes.conf +++ b/vm-systemd/NetworkManager.service.d/30_qubes.conf @@ -4,6 +4,8 @@ ConditionPathExists=/var/run/qubes-service/network-manager After=qubes-mount-dirs.service # For /var/run/qubes-service After=qubes-sysinit.service +# For configuration of qubes-provided interfaces +After=qubes-network-uplink.service [Service] ExecStartPre=/usr/lib/qubes/network-manager-prepare-conf-dir diff --git a/vm-systemd/misc-post.sh b/vm-systemd/misc-post.sh index f284efd..1ffaae0 100755 --- a/vm-systemd/misc-post.sh +++ b/vm-systemd/misc-post.sh @@ -11,15 +11,6 @@ if [ -n "$(ls -A /usr/local/lib 2>/dev/null)" ] || \ ldconfig fi -# Set IP address again (besides action in udev rules); this is needed by -# DispVM (to override DispVM-template IP) and in case when qubes-ip was -# called by udev before loading evtchn kernel module - in which case -# qubesdb-read fails -QUBES_MANAGED_IFACE="$(get_qubes_managed_iface)" -if [ "x$QUBES_MANAGED_IFACE" != "x" ]; then -INTERFACE="$QUBES_MANAGED_IFACE" ACTION="add" /usr/lib/qubes/setup-ip -fi - if [ -x /rw/config/rc.local ] ; then /rw/config/rc.local fi diff --git a/vm-systemd/network-proxy-stop.sh b/vm-systemd/network-proxy-stop.sh new file mode 100755 index 0000000..4ef924e --- /dev/null +++ b/vm-systemd/network-proxy-stop.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +echo 0 > /proc/sys/net/ipv4/ip_forward +# disable also IPv6 forwarding, if IPv6 applicable +if [ -w /proc/sys/net/ipv6/conf/all/forwarding ]; then + echo 0 > /proc/sys/net/ipv6/conf/all/forwarding +fi diff --git a/vm-systemd/network-uplink-wait.sh b/vm-systemd/network-uplink-wait.sh new file mode 100644 index 0000000..bb0bc34 --- /dev/null +++ b/vm-systemd/network-uplink-wait.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +# Source Qubes library. +# shellcheck source=init/functions +. /usr/lib/qubes/init/functions + +# Setup IP address at specific time of system boot, instead of asynchronously +# by udev +QUBES_MANAGED_IFACE="$(get_qubes_managed_iface)" +if [ "x$QUBES_MANAGED_IFACE" != "x" ]; then + # systemd does not support conditional After= dependencies, nor a tool to + # just wait for the unit to be activated + # if the network interface is expected, use `systemctl start` to wait for + # it to be started - it would be started by udev (SYSTEMD_WANTS) anyway + systemctl start "qubes-network-uplink@$QUBES_MANAGED_IFACE.service" +fi diff --git a/vm-systemd/qubes-early-vm-config.service b/vm-systemd/qubes-early-vm-config.service index 36601b6..dddbc49 100644 --- a/vm-systemd/qubes-early-vm-config.service +++ b/vm-systemd/qubes-early-vm-config.service @@ -1,7 +1,7 @@ [Unit] Description=Early Qubes VM settings DefaultDependencies=no -Before=sysinit.target +Before=sysinit.target network-pre.target After=local-fs.target qubes-db.service [Service] diff --git a/vm-systemd/qubes-network-uplink.service b/vm-systemd/qubes-network-uplink.service new file mode 100644 index 0000000..acf8649 --- /dev/null +++ b/vm-systemd/qubes-network-uplink.service @@ -0,0 +1,11 @@ +[Unit] +Description=Qubes network uplink wait +Before=network.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/qubes/init/network-uplink-wait.sh + +[Install] +WantedBy=multi-user.target diff --git a/vm-systemd/qubes-network-uplink@.service b/vm-systemd/qubes-network-uplink@.service new file mode 100644 index 0000000..74bf689 --- /dev/null +++ b/vm-systemd/qubes-network-uplink@.service @@ -0,0 +1,11 @@ +[Unit] +Description=Qubes network uplink (%i) setup +After=network-pre.target qubes-iptables.service +After=sys-subsystem-net-devices-%i.device +BindsTo=sys-subsystem-net-devices-%i.device + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/lib/qubes/setup-ip add "%i" +ExecStop=/usr/lib/qubes/setup-ip remove "%i" diff --git a/vm-systemd/qubes-network.service b/vm-systemd/qubes-network.service index c5aa410..5281bf1 100644 --- a/vm-systemd/qubes-network.service +++ b/vm-systemd/qubes-network.service @@ -8,6 +8,7 @@ After=network-pre.target qubes-iptables.service Type=oneshot RemainAfterExit=yes ExecStart=/usr/lib/qubes/init/network-proxy-setup.sh +ExecStop=/usr/lib/qubes/init/network-proxy-stop.sh [Install] WantedBy=multi-user.target