#!/bin/bash # Source Qubes library. # shellcheck disable=SC1091 . /usr/lib/qubes/init/functions set -uo pipefail add_host_route () { /sbin/ip -- route replace to unicast "$1" dev "$2" onlink scope host } add_default_route () { /sbin/ip -- route replace to unicast default via "$1" dev "$2" onlink } configure_network() { local MAC="$1" local INTERFACE="$2" local ip="$3" local ip6="$4" local netmask="$5" local netmask6="$6" local gateway="$7" local gateway6="$8" local primary_dns="$9" local secondary_dns="${10}" local netvm_mac=fe:ff:ff:ff:ff:ff /sbin/ifconfig "$INTERFACE" "$ip" netmask "$netmask" /sbin/ip -- neighbour replace to "$gateway" dev "$INTERFACE" \ lladdr "$netvm_mac" nud permanent if [ -n "$ip6" ]; then /sbin/ifconfig "$INTERFACE" add "$ip6/$netmask6" /sbin/ip -- neighbour replace to "$gateway6" dev "$INTERFACE" \ lladdr "$netvm_mac" nud permanent fi /sbin/ifconfig "$INTERFACE" up if [ -n "$gateway" ]; then add_host_route "$gateway" "$INTERFACE" if [ -n "$gateway6" ] && ! echo "$gateway6" | grep -q "^fe80:"; then add_host_route "$gateway6/$netmask6" "$INTERFACE" fi if ! qsvc disable-default-route ; then add_default_route "$gateway" "$INTERFACE" if [ -n "$gateway6" ]; then add_default_route "$gateway6" "$INTERFACE" fi fi fi if [ -z "$primary_dns" ] && [ -n "$gateway" ]; then primary_dns="$gateway" fi if ! is_protected_file /etc/resolv.conf ; then echo > /etc/resolv.conf if ! qsvc disable-dns-server ; then echo "nameserver $primary_dns" > /etc/resolv.conf echo "nameserver $secondary_dns" >> /etc/resolv.conf fi fi } configure_network_nm() { local MAC="$1" local INTERFACE="$2" local ip="$3" local ip6="$4" local netmask="$5" local netmask6="$6" local gateway="$7" local gateway6="$8" local primary_dns="$9" local secondary_dns="${10}" local prefix local prefix6 local nm_config local ip4_nm_config local ip6_nm_config local uuid prefix="$(get_prefix_from_subnet "$netmask")" prefix6="$netmask6" uuid="de85f79b-8c3d-405f-a652-${MAC//:/}" nm_config="/etc/NetworkManager/system-connections/qubes-uplink-$INTERFACE" cat > "$nm_config" <<__EOF__ [802-3-ethernet] duplex=full [ethernet] mac-address=$MAC [connection] id=VM uplink $INTERFACE uuid=$uuid type=802-3-ethernet __EOF__ ip4_nm_config="" ip6_nm_config="" if ! qsvc disable-dns-server ; then ip4_nm_config="${ip4_nm_config} dns=${primary_dns};${secondary_dns}" fi if ! qsvc disable-default-route ; then ip4_nm_config="${ip4_nm_config} addresses1=$ip;$prefix;$gateway" if [ -n "$ip6" ]; then ip6_nm_config="${ip6_nm_config} addresses1=$ip6;$prefix6;$gateway6" fi else ip4_nm_config="${ip4_nm_config} addresses1=$ip;$prefix" if [ -n "$ip6" ]; then ip6_nm_config="${ip6_nm_config} addresses1=$ip6;$prefix6" fi fi if [ -n "$ip4_nm_config" ]; then cat >> "$nm_config" <<__EOF__ [ipv4] method=manual may-fail=false $ip4_nm_config __EOF__ else cat >> "$nm_config" <<__EOF__ [ipv4] method=ignore __EOF__ fi if [ -n "$ip6_nm_config" ]; then cat >> "$nm_config" <<__EOF__ [ipv6] method=manual may-fail=false $ip6_nm_config __EOF__ else cat >> "$nm_config" <<__EOF__ [ipv6] method=ignore __EOF__ fi chmod 600 "$nm_config" # reload connection nmcli connection load "$nm_config" || : } configure_qubes_ns() { gateway=$(qubesdb-read /qubes-netvm-gateway) #netmask=$(qubesdb-read /qubes-netvm-netmask) primary_dns=$(qubesdb-read /qubes-netvm-primary-dns 2>/dev/null || echo "$gateway") secondary_dns=$(qubesdb-read /qubes-netvm-secondary-dns) echo "NS1=$primary_dns" > /var/run/qubes/qubes-ns echo "NS2=$secondary_dns" >> /var/run/qubes/qubes-ns /usr/lib/qubes/qubes-setup-dnat-to-ns } qubes_ip_change_hook() { if [ -x /rw/config/qubes-ip-change-hook ]; then /rw/config/qubes-ip-change-hook fi # XXX: Backward compatibility if [ -x /rw/config/qubes_ip_change_hook ]; then /rw/config/qubes_ip_change_hook fi } have_qubesdb || exit 0 ACTION="$1" INTERFACE="$2" 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 "$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 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 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