core-agent-linux/network/vif-route-qubes
Demi Marie Obenour 6517cca2a4
NAT network namespaces need neighbor entries
If we are using a NAT network namespace, it needs its own neighbor
entries.  For consistency, give it the same MAC address as the VM it
connects to.
2020-11-19 12:08:23 -05:00

188 lines
6.0 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#============================================================================
# /etc/xen/vif-route-qubes
#
# Script for configuring a vif in routed mode.
# The hotplugging system will call this script if it is specified either in
# the device configuration given to Xend, or the default Xend configuration
# in /etc/xen/xend-config.sxp. If the script is specified in neither of those
# places, then vif-bridge is the default.
#
# Usage:
# vif-route (add|remove|online|offline)
#
# Environment vars:
# vif vif interface name (required).
# XENBUS_PATH path to this device's details in the XenStore (required).
#
# Read from the store:
# ip list of IP networks for the vif, space-separated (default given in
# this script).
#============================================================================
dir=$(dirname "$0")
# shellcheck disable=SC1091,SC1090
. "$dir/vif-common.sh"
set -o pipefail
#main_ip=$(dom0_ip)
# Network Hooks for triggering supplementary actions on AppVM connect
network_hooks() {
local command="$1"
local vif="$2"
local addr="$3"
local vif_type
vif_type="$(xenstore-read "${XENBUS_PATH}/type")"
if [ -d /rw/config/network-hooks.d ]; then
for hook in /rw/config/network-hooks.d/*
do
if [ -x "$hook" ]; then
log debug "Executing network-hook $(basename "$hook")..."
do_without_error "${hook}" "${command}" "${vif}" "${vif_type}" "${addr}"
fi
done
fi
}
ipt_arg=
if "iptables-restore" --help 2>&1 | grep -q wait=; then
# 'wait' must be last on command line if secs not specified
ipt_arg=--wait
fi
# shellcheck disable=SC2154
if [ "${ip}" ]; then
# get first IPv4 and first IPv6
for addr in ${ip}; do
if [ -z "$ip4" ] && [[ "$addr" = *.* ]]; then
ip4="$addr"
elif [ -z "$ip6" ] && [[ "$addr" = *:* ]]; then
ip6="$addr"
fi
done
# IPs as seen by this VM
netvm_ip="$ip4"
netvm_gw_ip=$(qubesdb-read /qubes-netvm-gateway)
netvm_gw_ip6=$(qubesdb-read /qubes-netvm-gateway6 || :)
netvm_dns1_ip=$(qubesdb-read /qubes-netvm-primary-dns)
netvm_dns2_ip=$(qubesdb-read /qubes-netvm-secondary-dns)
back_ip="$netvm_gw_ip"
back_ip6="$netvm_gw_ip6"
# IPs as seen by the VM - if other than $netvm_ip
appvm_gw_ip="$(qubesdb-read "/mapped-ip/$ip4/visible-gateway" 2>/dev/null || :)"
appvm_ip="$(qubesdb-read "/mapped-ip/$ip4/visible-ip" 2>/dev/null || :)"
fi
readonly max_domid=32752
# if domid is 0 something is seriously wrong, so dont check for that case
if ! [[ $vif =~ ^vif([1-9][0-9]{,4})\.(0|[1-9][0-9]*)$ ]]; then
printf 'Bad interface name %q\n' "$vif">&2
exit 1
fi
domid=${BASH_REMATCH[1]} sub=${BASH_REMATCH[2]}
# metric must be positive, but prefer later interface
# 32752 is max XID aka domid
if (( domid > max_domid )); then
printf %s\\n "domid $domid too large"
exit 1
fi
metric=$(( max_domid - domid ))
# shellcheck disable=SC2154
case "$command" in
online)
echo 1 >"/proc/sys/net/ipv4/conf/${vif}/proxy_arp"
ipcmd='add'
iptables_cmd='-I PREROUTING 1'
cmdprefix=''
ipv6_disabled=$(cat /proc/sys/net/ipv6/conf/"${vif}"/disable_ipv6 || echo 1)
# without a MAC address we will fail later with a confusing error
mac=$(xenstore-read "backend/vif/$domid/$sub/mac") || exit 1
;;
offline)
do_without_error ifdown "${vif}"
ipcmd='del'
iptables_cmd='-D PREROUTING'
cmdprefix='do_without_error'
# cleanup IPv6 config even if _now_ it is disabled
ipv6_disabled=0
;;
esac
# Apply NAT if IP visible from the VM is different than the "real" one
# See vif-qubes-nat.sh for details
# XXX: supported only for the first IPv4 address, IPv6 is dropped if this
# feature is enabled
if [ -n "$appvm_ip" ] && [ -n "$appvm_gw_ip" ] && [ "$appvm_ip" != "$netvm_ip" ]; then
# shellcheck source=network/vif-qubes-nat.sh
. "$dir/vif-qubes-nat.sh"
fi
# add anti-spoofing rules before enabling the interface
if [ "${ip}" ]; then
# If weve been given a list of IP addresses, then add routes from us to
# the VMs we serve using those addresses.
for addr in ${ip};
do
if [[ "$addr" = *:* ]]; then
ipt=ip6tables-restore
else
ipt=iptables-restore
fi
printf '%s\n' "*raw" \
"$iptables_cmd -i ${vif} ! -s ${addr} -j DROP" \
"$iptables_cmd ! -i vif+ -s ${addr} -j DROP" \
"COMMIT" | \
${cmdprefix} $ipt --noflush $ipt_arg
if [[ "$command" = 'online' ]]; then
ip -- neighbour "${ipcmd}" to "${addr}" \
dev "${vif}" lladdr "$mac" nud permanent
fi
done
# if no IPv6 is assigned, block all IPv6 traffic on that interface
if ! [[ "$ip" = *:* ]]; then
echo -e "*raw\\n$iptables_cmd -i ${vif} -j DROP\\nCOMMIT" | \
${cmdprefix} ip6tables-restore --noflush $ipt_arg
fi
fi
if [ "$command" = "online" ]; then
ifconfig "${vif}" up
fi
if [ "${ip}" ]; then
# If we've been given a list of IP addresses, then add routes from dom0 to
# the guest using those addresses.
for addr in ${ip};
do
if [[ "$addr" = *:* ]] && [[ "$ipv6_disabled" = 1 ]]; then
log error "Cannot set IPv6 route to ${addr}, IPv6 disabled in the kernel"
continue
fi
${cmdprefix} ip route "${ipcmd}" "${addr}" dev "${vif}" metric "$metric"
network_hooks "${command}" "${vif}" "${addr}"
done
${cmdprefix} ip addr "${ipcmd}" "${back_ip}/32" dev "${vif}"
if [ "${back_ip6}" ] && [[ "${back_ip6}" != "fe80:"* ]] && [[ "$ipv6_disabled" != 1 ]]; then
${cmdprefix} ip addr "${ipcmd}" "${back_ip6}/128" dev "${vif}"
fi
else
network_hooks "${command}" "${vif}"
fi
log debug "Successful vif-route-qubes $command for $vif."
if [ "$command" = "online" ]; then
# disable tx checksumming offload, apparently it doesn't work with our ancient qemu in stubdom
do_without_error ethtool -K "$vif" tx off
success
fi