Как избежать спуфинга IP и MAC и заблокировать нужные порты для виртуальных машин Qemu/KVM через nft или nftables?

У меня есть сервер Debian 11, на котором запущено несколько виртуальных машин Qemu/KVM (не использующих libvirtd создан исключительно с помощью команд Qemu), я создал сетевой мост, и каждая виртуальная машина имеет свое собственное TAP-устройство, подключенное к мосту. Учтите, что я знаю, что избежать подмены MAC-адреса легко libvirtd через свои сетевые фильтры, но я намерен настроить его самостоятельно для своих виртуальных машин, созданных Qemu. Мой реальный интерфейс называется eth0мой мост называется br0и одно из моих устройств TAP ВМ, подключенных к этому мосту, называется vm0.

Что я хочу сделать, так это использовать nftables, чтобы удалить все OUTPUT пакеты, кроме eth0 а также br0 в первую очередь, а потом разрешать OUTPUT пакеты моих TAP-устройств только в том случае, если исходный MAC-адрес совпадает с фактическим MAC-адресом, который я вижу в моем ip -c a вывод, который я назначил себе при создании виртуальной машины, другими словами, я хочу избежать подмены MAC-адреса на виртуальных машинах через nftables. Кроме того, я хочу заблокировать порты SMTP.

Я уже создал несколько iptables а также ebtables правила для достижения желаемого результата, однако, узнав, что nftables является фреймворком для замены их обоих и что с ним более эффективно достигать таких результатов, я хочу перенести эти правила на nftablesоднако я не могу понять, как написать эти правила.

Мои правила таковы:

правила iptables, первоначально извлеченные из этого поста:

iptables -t filter -A FORWARD -m physdev --physdev-in vm1 --physdev-is-bridged -j 0-out
iptables -t filter -A 0-out -m mac ! --mac-source <SOME_MAC_ADDRESS> -j DROP
iptables -t filter -A 0-out -s 0.0.0.0/32 -d 255.255.255.255/32 -p udp -m udp --sport 68 --dport 67 -j ACCEPT
iptables -t filter -A 0-out ! -s <SOME_IP_ADDRESS> -j DROP
iptables -t filter -A 0-out -j RETURN

правила игры:

# OUTPUT rules

ebtables -A OUTPUT -p IPv4 -o vm0 --ip-protocol tcp --ip-sport 25 -j DROP
ebtables -A OUTPUT -p IPv4 -o vm0 --ip-protocol tcp --ip-sport 587 -j DROP
ebtables -A OUTPUT -p IPv4 -o vm0 --ip-protocol tcp --ip-sport 465 -j DROP
ebtables -A OUTPUT -p IPv4 -o vm0 --ip-protocol udp --ip-sport 25 -j DROP
ebtables -A OUTPUT -p IPv4 -o vm0 --ip-protocol udp --ip-sport 587 -j DROP
ebtables -A OUTPUT -p IPv4 -o vm0 --ip-protocol udp --ip-sport 465 -j DROP

# INPUT rules

ebtables -A INPUT -p IPv4 -i vm0 --ip-protocol tcp --ip-dport 25 -j DROP
ebtables -A INPUT -p IPv4 -i vm0 --ip-protocol tcp --ip-dport 587 -j DROP
ebtables -A INPUT -p IPv4 -i vm0 --ip-protocol tcp --ip-dport 465 -j DROP
ebtables -A INPUT -p IPv4 -i vm0 --ip-protocol udp --ip-dport 25 -j DROP
ebtables -A INPUT -p IPv4 -i vm0 --ip-protocol udp --ip-dport 587 -j DROP
ebtables -A INPUT -p IPv4 -i vm0 --ip-protocol udp --ip-dport 465 -j DROP

Я знаю комбинацию использования обоих ebtables а также iptables по той же самой причине немного неортодоксальна, потому что я новичок во всем этом, и я написал эти правила, изучая несколько источников, однако это еще одна причина использовать nftables унифицировать их.

Приветствуется любая помощь, будь то сам синтаксис набора правил или подсказки и руководства, буквально что угодно.

Заранее спасибо.

linux networking iptables kvm-virtualization nftables

Шкипер

1 ответ
1

После долгих исследований и чтения документации я наконец нашел правильный подход и ответ:

IP- и MAC-спуфинг + блокировка портов

Мои правила блокировки портов SMTP работают нормально, на самом деле мой подход к использованию ebtables для блокировки портов на хосте виртуализации правильно, однако после исследования я обнаружил правила подмены MAC/IP, написанные через iptables на самом деле не лучший подход, благодаря этому сообщению я узнал, что должен использовать ebtables также для подмены MAC/IP.

Правила

Поскольку я использую эти правила на узле виртуализации, чтобы избежать злоупотребления SMTP и подделки MAC/IP, эти правила должны применяться на ВМ чтобы быть динамичным, — опять же благодаря сообщению, упомянутому ранее — мы создаем пользовательскую цепочку и добавляем ее в FORWARD цепочка ebtables.

Правила, которые я создал, следующие:

Создание пользовательской цепочки, присоединенной к цепочке FORWARD для каждой виртуальной машины для спуфинга MAC/IP:

ebtables -A FORWARD -p ip -i $VM_INTERFACE_NAME -j VM-MAC # just a name

Создание пользовательской цепочки, присоединенной к цепочке FORWARD для блокировки портов

ebtables -A FORWARD -p ip -o $VM_INTERFACE_NAME -j VM-PORT # again just a name
# note that the target chain for these rules are custom chains.

Отбрасывание всего ВХОДНОГО трафика в первую очередь

ebtables -P VM-MAC DROP

Теперь создайте правило и добавьте его к цепочке VM-MAC, чтобы сопоставить IP-адрес виртуальной машины и MAC-адрес интерфейса виртуальной машины внутри виртуальной машины.

ebtables -A VM-MAC -p ip --ip-src IP_ADDR_ALLOWED_FOR_VM -s VM_MAC_ADDR -j ACCEPT

Наконец, мы блокируем нужные порты (в моем случае SMTP), создавая следующие правила и добавляя их в цепочку VM-PORT.

ebtables -A VM-PORT -p ip --ip-protocol tcp --ip-sport 25 -j DROP
ebtables -A VM-PORT -p ip --ip-protocol tcp --ip-sport 587 -j DROP
ebtables -A VM-PORT -p ip --ip-protocol tcp --ip-sport 465 -j DROP
ebtables -A VM-PORT -p ip --ip-protocol udp --ip-sport 25 -j DROP
ebtables -A VM-PORT -p ip --ip-protocol udp --ip-sport 587 -j DROP
ebtables -A VM-PORT -p ip --ip-protocol udp --ip-sport 465 -j DROP

Сохранение правил.

ebtables-save

Преобразование в nftables

Теперь о преобразовательной части, согласно nftables как вики

С июня 2018 года старые инструменты xtables/setsockopt считаются устаревшими. Однако существует поддержка использования старого синтаксиса iptables/ip6tables/arptables/ebtables с серверной частью ядра nf_tables.

Это означает, что мы можем просто использовать ebtables-nft утилита для записи nft наборы правил через наследие ebtables синтаксис, поэтому мы можем просто переписать предыдущие команды, как показано ниже:

ebtables-nft -A FORWARD -p ip -i $VM_INTERFACE_NAME -j VM-MAC
ebtables-nft -A FORWARD -p ip -o $VM_INTERFACE_NAME -j VM-PORT
ebtables-nft -P VM-MAC DROP
ebtables-nft -A VM-MAC -p ip --ip-src IP_ADDR_ALLOWED_FOR_VM -s VM_MAC_ADDR -j ACCEPT
ebtables-nft -A VM-PORT -p ip --ip-protocol tcp --ip-sport 25 -j DROP
ebtables-nft -A VM-PORT -p ip --ip-protocol tcp --ip-sport 587 -j DROP
ebtables-nft -A VM-PORT -p ip --ip-protocol tcp --ip-sport 465 -j DROP
ebtables-nft -A VM-PORT -p ip --ip-protocol udp --ip-sport 25 -j DROP
ebtables-nft -A VM-PORT -p ip --ip-protocol udp --ip-sport 587 -j DROP
ebtables-nft -A VM-PORT -p ip --ip-protocol udp --ip-sport 465 -j DROP
ebtables-nft-save

Вышеуказанные правила будут автоматически преобразованы в nft набор правил, вы даже можете проверить это с помощью следующей команды:

nft list ruleset

Вывод выглядит следующим образом:

nft list ruleset
table bridge filter {
      
        chain FORWARD {
                type filter hook forward priority filter; policy accept;
                iifname "<INTERFACE_NAME>" ether type ip counter packets 139 bytes 24158 jump VM-MAC
                oifname "<INTERFACE_NAME>" ether type ip counter packets 279 bytes 23784 jump VM-PORT
        }

        chain VM-MAC {
                ether saddr <MAC_ADDR> ether type ip ip saddr <IP_ADDR>  counter packets 75 bytes 7646 accept
                counter packets 64 bytes 16512 drop
        }

        chain VM-PORT {
                ether type ip tcp sport 25  counter packets 14 bytes 840 drop
                ether type ip tcp sport 587  counter packets 0 bytes 0 drop
                ether type ip tcp sport 465  counter packets 0 bytes 0 drop
                ether type ip udp sport 25  counter packets 0 bytes 0 drop
                ether type ip udp sport 587  counter packets 0 bytes 0 drop
                ether type ip udp sport 465  counter packets 0 bytes 0 drop
                counter packets 265 bytes 22944 accept
        }
}

Ну вот!

Скрипт

Если кому интересно, я тоже создал скрипт:

#!/usr/bin/env bash

# set -x for debugging
set +x
readonly SCRIPT_NAME=$(basename $0)

function help {
    echo "Usage: $0 options"
    echo "  -n <ifname> VM TAP interface name on the host"
    echo "  -m <mac>    VM MAC address inside the virtual machine"
    echo "  -i <id>     VM id"
    echo "  -h <ip>     Allowed IP address for the VM"
}

function err {
    logger -p user.crit -t $SCRIPT_NAME "$@"
}

optstring=":n:m:i:h:"
while getopts $optstring opt
do
    case $opt in
    n)
    VM_IF=$OPTARG
    ;;

    m)
    VM_MAC=$OPTARG
    ;;

    i)
    VM_ID=$OPTARG
    ;;

    h)
    VM_IP=$OPTARG
    ;;
    esac
done

if [[ -z $VM_IF || 
      -z $VM_MAC  ||
      -z $VM_ID ||
      -z $VM_IP ]]
then
    help
    exit 1
fi

ebtables-nft -N $VM_ID-MAC
ebtables-nft -N $VM_ID-PORT
ebtables-nft -A FORWARD -p ip -i $VM_IF -j $VM_ID-MAC
ebtables-nft -A FORWARD -p ip -o $VM_IF -j $VM_ID-PORT
ebtables-nft -P $VM_ID-MAC DROP
ebtables-nft -A $VM_ID-MAC -p ip --ip-src $VM_IP -s $VM_MAC -j ACCEPT
ebtables-nft -A $VM_ID-PORT -p ip --ip-protocol tcp --ip-sport 25 -j DROP
ebtables-nft -A $VM_ID-PORT -p ip --ip-protocol tcp --ip-sport 587 -j DROP
ebtables-nft -A $VM_ID-PORT -p ip --ip-protocol tcp --ip-sport 465 -j DROP
ebtables-nft -A $VM_ID-PORT -p ip --ip-protocol udp --ip-sport 25 -j DROP
ebtables-nft -A $VM_ID-PORT -p ip --ip-protocol udp --ip-sport 587 -j DROP
ebtables-nft -A $VM_ID-PORT -p ip --ip-protocol udp --ip-sport 465 -j DROP
ebtables-nft-save

ret=$?

if [[ $ret -ne 0 ]]
then
    err "Could not create nft ruleset for instance ${VM_ID}"
    exit $ret
fi

echo -e "nft ruleset for instance ${VM_ID} created."
exit $ret

Ссылка на суть

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *