У меня есть сервер 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 ответ
После долгих исследований и чтения документации я наконец нашел правильный подход и ответ:
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