From 65126fcdac0431c6a29d40364d84350a05cb0675 Mon Sep 17 00:00:00 2001 From: ghe0 Date: Fri, 10 Jan 2025 19:19:04 +0000 Subject: [PATCH] Add NFT isolation for macvtap (#5) Solves https://gitea.detee.cloud/SNP/daemon/issues/4 Reviewed-on: https://gitea.detee.cloud/SNP/daemon/pulls/5 --- scripts/start_qemu_vm.sh | 51 ++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/scripts/start_qemu_vm.sh b/scripts/start_qemu_vm.sh index e97c5a8..e0694b1 100755 --- a/scripts/start_qemu_vm.sh +++ b/scripts/start_qemu_vm.sh @@ -16,9 +16,44 @@ for var in "${mandatory_vars[@]}"; do fi done +add_nft_rules() { + local nic_index="$1" ifname="$2" vtap_addr="$3" ipv4_addr="" ipv6_addr="" + + nft add table netdev deteemacvtap + nft add chain netdev deteemacvtap ${ifname}_in "{ type filter hook ingress device ${ifname} priority 0; policy accept; }" + nft add chain netdev deteemacvtap ${ifname}_ou "{ type filter hook egress device ${ifname} priority 0; policy accept; }" + # return if the rules already exist + nft list chain netdev deteemacvtap ${ifname}_in | grep ether && return 0 + nft add rule netdev deteemacvtap ${ifname}_in ether daddr != ${vtap_addr} drop + nft list chain netdev deteemacvtap ${ifname}_ou | grep ether && return 0 + nft add rule netdev deteemacvtap ${ifname}_ou ether saddr != ${vtap_addr} drop + + # TODO: This will handle only one IP per VM. If you add multiple IPs, fix this. + # Also, we wish you good luck. We know this code is complicated. We tried, ok? + ipv4_addr=$(echo $PARAMS | grep -m 1 -oE "detee_net_eth${nic_index}=[0-9]{1,3}\.[0-9a-f\.]+" | cut -d "=" -f2 ) + ipv6_addr=$(echo $PARAMS | grep -m 1 -oE "detee_net_eth${nic_index}=[0-9a-f]{1,4}\:[0-9a-f\:]+" | cut -d "=" -f2 ) + + [[ -n "$ipv4_addr" ]] && { + nft add rule netdev deteemacvtap ${ifname}_in ip daddr != $ipv4_addr drop + nft add rule netdev deteemacvtap ${ifname}_ou ip saddr != $ipv4_addr drop + } || { + nft add rule netdev deteemacvtap ${ifname}_in ip version 4 drop + nft add rule netdev deteemacvtap ${ifname}_ou ip version 4 drop + } + + [[ -n "$ipv6_addr" ]] && { + nft add rule netdev deteemacvtap ${ifname}_in ip6 daddr != $ipv6_addr drop + nft add rule netdev deteemacvtap ${ifname}_ou ip6 saddr != $ipv6_addr drop + } || { + nft add rule netdev deteemacvtap ${ifname}_in ip6 version 6 drop + nft add rule netdev deteemacvtap ${ifname}_ou ip6 version 6 drop + } + +} + interfaces=$(env | sort | grep -oE '^NETWORK_INTERFACE_[0-9]*') nat_configured="false" -vtap_nic_count=1 +nic_count=0 qemu_device_params="" while read -r interface; do @@ -27,11 +62,11 @@ while read -r interface; do if [[ "$interface_type" == "macvtap" || "$interface_type" == "ipvtap" ]]; then interface_device="$( echo ${!interface} | cut -d '_' -f2 )" interface_name="$( echo ${!interface} | cut -d '_' -f3 )" - if [[ "$interface_type" == "macvtap" ]]; then + [[ "$interface_type" == "macvtap" ]] && { ip link add link $interface_device name $interface_name type $interface_type mode bridge - else + } || { ip link add link $interface_device name $interface_name type $interface_type mode l3 - fi + } sysctl -w net.ipv6.conf.$interface_name.accept_ra=0 ip link set $interface_name up ip link set $interface_name promisc on @@ -39,10 +74,11 @@ while read -r interface; do vtap_index="$(cat /sys/class/net/${interface_name}/ifindex)" vtap_addr="$(cat /sys/class/net/${interface_name}/address)" + [[ "$interface_type" == "macvtap" ]] && add_nft_rules $nic_count $interface_name $vtap_addr + exec {fd_number}<> /dev/tap${vtap_index} - qemu_device_params+=" -netdev tap,id=hostnet1,fd=${fd_number}" - qemu_device_params+=" -device virtio-net-pci,netdev=hostnet${vtap_nic_count},mac=${vtap_addr},romfile=" - ((vtap_nic_count++)) + qemu_device_params+=" -netdev tap,id=hostnet${nic_count},fd=${fd_number}" + qemu_device_params+=" -device virtio-net-pci,netdev=hostnet${nic_count},mac=${vtap_addr},romfile=" fi if [[ "$interface_type" == "NAT" && "$nat_configured" == "false" ]]; then @@ -59,6 +95,7 @@ while read -r interface; do # TODO: also handle bridge device (when IPs are public, but the host is the gateway) + ((nic_count++)) done <<< "$( echo "$interfaces" )" qemu-system-x86_64 $qemu_device_params \