Назад | Перейти на главную страницу

Прозрачный межсетевой экран с nftables и VLAN

Я хочу попросить вас дать совет по созданию прозрачного брандмауэра.

У меня есть 2 сегмента сети и серв CentOS с 2 интерфейсами 10G. Я хочу фильтровать / отслеживать / ограничивать / отбрасывать трафик между сегментами. Трафик помечен. Должен ли я снимать теги с трафика для фильтрации и тегировать его обратно или nftable может обрабатывать его с тегами?

Теперь схема выглядит так:

PCs--|                                         |--PCs
PCs--|--untag--[Switch]--tag--[Switch]--untag--|--PCs
PCs--|                                         |--PCs

Я хочу:

PCs--|                                                              |--PCs
PCs--|--untag--[Switch]--tag--**[Firewall]**--tag--[Switch]--untag--|--PCs
PCs--|                                                              |--PCs

TL; DR: nftables на уровне моста может точно обрабатывать как тегированные, так и немаркированные пакеты, используя несколько другие правила. Всю работу с тегами можно выполнить на стороне Linux, используя мост с поддержкой vlan, поэтому никаких изменений конфигурации на коммутаторах не требуется, независимо от выбора, сделанного в брандмауэре для nftables.

В этой серии блогов можно найти много интересной документации о тестировании VLAN (особенно в части IV, даже если некоторые сведения могут быть не совсем точными):

Развлечение с veth-устройствами, мостами Linux и VLAN в безымянных пространствах имен сети Linux я II III IV V VI VII VIII

Поместим две минималистичные модели межсетевого экрана (в сетевое пространство имен). trunk100 и trunk200 связаны с двумя коммутаторами, отправляющими помеченные пакеты vlan 100 с левых компьютеров и помеченные пакеты vlan 200 с правых компьютеров. Обратите внимание, что здесь тегам VLAN явно разрешено появляться на другой стороне либо путем создания субинтерфейса с идентификатором VLAN другой стороны, либо путем прямого добавления идентификатора VLAN другой стороны в интерфейс магистрали.

  1. суб-интерфейсы vlan, помещающие немаркированные пакеты в мост

    ip link add fw0 type bridge vlan_filtering 1
    ip link set fw0 up
    for trunk in 100 200; do
        for vlan in 100 200; do
            ip link add link trunk$trunk name trunk$trunk.$vlan type vlan id $vlan
            ip link set trunk$trunk.$vlan master fw0
            bridge vlan add vid $vlan pvid untagged dev trunk$trunk.$vlan
            bridge vlan del vid 1 dev trunk$trunk.$vlan
            ip link set trunk$trunk.$vlan up
        done
    done
    bridge vlan del vid 1 dev fw0 self
    

    В этом случае тегированные пакеты, поступающие через trunk100 и trunk200, разделяются на субинтерфейсы для каждого vlan, и пакеты не тегируются. Мост все еще внутренне осведомлен об используемых VLAN и применяет фильтрацию vlan к источникам и получателям. nft добавит свои ограничения. Исходящие пакеты будут помечены повторно, как только они будут доставлены на интерфейс родительской магистрали.

  2. помеченные пакеты прямо в мост

    ip link add fw0 type bridge vlan_filtering 1
    ip link set fw0 up
    for trunk in 100 200; do
        ip link set trunk$trunk master fw0
        for vlan in 100 200; do
            bridge vlan add vid $vlan tagged dev trunk$trunk
        done
        bridge vlan del vid 1 dev trunk$trunk
        ip link set trunk$trunk up
    done
    bridge vlan del vid 1 dev fw0 self
    

В этом более простом случае тегированные пакеты проходят через мост, сохраняя свой тег vlan.

Вот единый набор правил nftables, показывающий, как обрабатываются оба случая. iifname был выбран здесь вместо iif поэтому один и тот же набор правил может работать в обоих случаях (без ошибки из-за отсутствия интерфейса). Как обычно iif следует предпочесть. Есть дополнительные записи счетчика, чтобы просто проверить, что именно совпадает, а что нет (с nft list ruleset -a):

#!/usr/sbin/nft -f

flush ruleset

table bridge filter {
    chain input {
        type filter hook input priority -200; policy drop;
    }

    chain forward {
        type filter hook forward priority -200; policy drop;
        counter
        arp operation request counter
        arp operation reply counter
        vlan type arp arp operation request counter
        vlan type arp arp operation reply counter
        arp operation request counter accept
        arp operation reply counter accept
        vlan type arp arp operation request counter accept
        vlan type arp arp operation reply counter accept
        ip protocol icmp icmp type echo-request counter
        ip protocol icmp icmp type echo-reply counter
        vlan type ip icmp type echo-request counter
        vlan type ip icmp type echo-reply counter
        iifname trunk100.100 ip protocol icmp icmp type echo-request counter accept
        oifname trunk100.200 ip protocol icmp icmp type echo-reply counter accept
        vlan id 100 vlan type ip icmp type echo-request counter accept
        vlan id 200 vlan type ip icmp type echo-reply counter accept
    }

    chain output {
        type filter hook output priority 200; policy drop;
    }
}

Обратите внимание, что эти правила можно было бы написать еще более подробно. Пример:

iifname "trunk100.100" ether type ip ip protocol icmp icmp type echo-request

или

ether type vlan vlan id 200 vlan type ip ip protocol icmp icmp type echo-reply

Когда используется первая настройка (немаркированные пакеты через подчиненные интерфейсы), будут соответствовать только классические правила. Когда используется вторая настройка, будут совпадать только правила, явно использующие vlan. Таким образом, этот набор двойных правил, позволяющий базовое разрешение ARP, а также позволяющий VLAN 100 проверять связь с VLAN 200, но не наоборот, будет работать в обоих случаях.

Этот набор правил должен работать при использовании с CentOS nftables v0.6 (не тестировалось на ядре CentOS) или текущей nftables v0.8.3.

Текущие известные ограничения:

Nftables начиная с v0.8.3 не может использовать conntrack так, как это было возможно с взаимодействиями ebtables / iptables. Похоже, есть планы на этот счет, см. Этот PDF: мостовая фильтрация с nftables. Это затрудняет реализацию правил с отслеживанием состояния.

Также обратите внимание, что nftables все еще имеет (по состоянию на 0.8.3) проблемы с отображением: nft list ruleset -a упадет vlan из "декомпилированных" правил, если ни одна из его опций не используется. Например, эти два правила:

nft add rule bridge filter forward ip protocol icmp counter
nft add rule bridge filter forward vlan type ip ip protocol icmp counter

При отображении обратно с nft list ruleset -a (v0.8.3):

        ip protocol icmp counter packets 0 bytes 0 # handle 23
        ip protocol icmp counter packets 0 bytes 0 # handle 24

Это только с nft --debug=netlink list ruleset -a который сбросит байт-код, ясно, что это действительно два разных правила (данные здесь с прямым порядком байтов):

bridge filter forward 23 22 
  [ payload load 2b @ link header + 12 => reg 1 ]
  [ cmp eq reg 1 0x00000008 ]
  [ payload load 1b @ network header + 9 => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ counter pkts 0 bytes 0 ]

bridge filter forward 24 23 
  [ payload load 2b @ link header + 12 => reg 1 ]
  [ cmp eq reg 1 0x00000081 ]
  [ payload load 2b @ link header + 16 => reg 1 ]
  [ cmp eq reg 1 0x00000008 ]
  [ payload load 1b @ network header + 9 => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ counter pkts 0 bytes 0 ]

CentOS 'v0.6 (проверено на ядре 4.15) также имеет свои собственные различные проблемы с отображением "декомпиляции":

ip protocol icmp icmp type echo-request

отображается как:

icmp type echo-request counter

что дает синтаксическую ошибку, если попытаться, как в v0.6 (но нормально в v0.8.3).