Conntrack не смог преобразовать собственные TCP-пакеты из другого VRF

Conntrack не смог преобразовать собственные TCP-пакеты из другого VRF

Я столкнулся с непростой проблемой с исходным NAT при использовании нескольких VRF на маршрутизаторе на базе Debian. Объяснить это немного сложно, поэтому я постараюсь быть понятным, но это не будет коротко, извините за это. Хотя проблема должна быть легко воспроизведена.

Чтобы изолировать «управляющую» часть маршрутизатора (ssh и другие службы) от его работы маршрутизатора (маршрутизация и NAT-преобразование пакетов), я попытался настроить VRF «mgmt» в VRF по умолчанию (так проще работать с сокетами служб), а маршрутизацию — в VRF под названием «брандмауэр».

Диаграмму можно обобщить следующим образом:

Диаграмма сети

Сеть "управления" - 192.168.100.0/24, и она маршрутизируется коммутатором L3, у которого есть L3 с VRF "брандмауэра" маршрутизатора через сеть 10.254.5.0/24. Третий интерфейс маршрутизатора - это его "интернет", и пакеты, которые проходят через него, подвергаются NAT источника. Эта настройка работает довольно хорошо для всего в подсети mgmt, за исключением собственных пакетов маршрутизатора, из-за conntrack.

О правилах iptables:

# Table filter

# chain INPUT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
(some INPUT rules, for ssh, snmp, etc)
-A INPUT -j DROP

# chain FORWARD
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -m conntrack --ctstate INVALID -j DROP
-A FORWARD -o eth2 -j ACCEPT
-A FORWARD -j DROP

# Table nat

# chain POSTROUTING
-A POSTROUTING -o eth2 -j SNAT --to-source 192.168.122.100

О таблице маршрутизации:

# default VRF
default via 192.168.100.1 dev eth0 proto static metric 20 
192.168.100.0/24 dev eth0 proto kernel scope link src 192.168.100.90

# firewall VRF
default via 192.168.122.1 dev eth2 proto static metric 20
10.254.5.0/24 dev eth1 proto kernel scope link src 10.254.5.2
192.168.100.0/24 proto bgp metric 20 nexthop via 10.254.5.10 dev eth1 weight 1 
192.168.122.0/24 dev eth2 proto kernel scope link src 192.168.122.100 

Итак, когда пакет из VRF по умолчанию пытается получить доступ к интернету, он выходит из eth0, маршрутизируется коммутатором L3, входит в VRF брандмауэра через eth1 и маршрутизируется и NATируется через eth2. Поскольку я отслеживаю соединения INPUT и FORWARD, conntrack немного сбит с толку, когда пакет возвращается, и он не может знать, что с ним делать.

Мне удалось исправить это для ICMP и UDP, используя зону conntrack в таблице raw.

# Table raw
# chain PREROUTING
-A PREROUTING -i eth0 -j CT --zone 5
# chain OUTPUT
-A OUTPUT -o eth0 -j CT --zone 5

Благодаря этим правилам пакеты, исходящие от маршрутизатора и проходящие через него, eth0тегируются zone 5, и когда пакеты поступают на него, eth0они также тегируются zone 5.

При пинге на 8.8.8.8 это выглядит так (с помощью команды conntrack -E):

    [NEW] icmp     1 30 src=192.168.100.90 dst=8.8.8.8 type=8 code=0 id=1999 [UNREPLIED] src=8.8.8.8 dst=192.168.100.90 type=0 code=0 id=1999 zone=5
    [NEW] icmp     1 30 src=192.168.100.90 dst=8.8.8.8 type=8 code=0 id=1999 [UNREPLIED] src=8.8.8.8 dst=192.168.122.100 type=0 code=0 id=1999
 [UPDATE] icmp     1 30 src=192.168.100.90 dst=8.8.8.8 type=8 code=0 id=1999 src=8.8.8.8 dst=192.168.122.100 type=0 code=0 id=1999
 [UPDATE] icmp     1 30 src=192.168.100.90 dst=8.8.8.8 type=8 code=0 id=1999 src=8.8.8.8 dst=192.168.100.90 type=0 code=0 id=1999 zone=5

Мы видим здесь, что первое NEWсоединение создается, когда пакет проходит eth0с zone=5тегом, затем новое, когда он входит в брандмауэр VRF eth1без тега. Когда приходит ответ, сначала обновляется второе соединение (так как оно обращено к интернету), а затем первое.

Это также работает с UDP, например, с DNS-запросом на 8.8.8.8.

    [NEW] udp      17 30 src=192.168.100.90 dst=8.8.8.8 sport=53369 dport=53 [UNREPLIED] src=8.8.8.8 dst=192.168.100.90 sport=53 dport=53369 zone=5
    [NEW] udp      17 30 src=192.168.100.90 dst=8.8.8.8 sport=53369 dport=53 [UNREPLIED] src=8.8.8.8 dst=192.168.122.100 sport=53 dport=53369
 [UPDATE] udp      17 30 src=192.168.100.90 dst=8.8.8.8 sport=53369 dport=53 src=8.8.8.8 dst=192.168.122.100 sport=53 dport=53369
 [UPDATE] udp      17 30 src=192.168.100.90 dst=8.8.8.8 sport=53369 dport=53 src=8.8.8.8 dst=192.168.100.90 sport=53 dport=53369 zone=5

Но с TCP это не работает. Запрос telnet на 172.16.10.10 порт 80 выглядит так:

    [NEW] tcp      6 120 SYN_SENT src=192.168.100.90 dst=172.16.10.10 sport=60234 dport=80 [UNREPLIED] src=172.16.10.10 dst=192.168.100.90 sport=80 dport=60234 zone=5
    [NEW] tcp      6 120 SYN_SENT src=192.168.100.90 dst=172.16.10.10 sport=60234 dport=80 [UNREPLIED] src=172.16.10.10 dst=192.168.122.100 sport=80 dport=60234
 [UPDATE] tcp      6 58 SYN_RECV src=192.168.100.90 dst=172.16.10.10 sport=60234 dport=80 src=172.16.10.10 dst=192.168.122.100 sport=80 dport=60234
 [UPDATE] tcp      6 57 SYN_RECV src=192.168.100.90 dst=172.16.10.10 sport=60234 dport=80 src=172.16.10.10 dst=192.168.122.100 sport=80 dport=60234
(The last line repeat multiple times)

Если я выполню tcpdump, eth2то ответ будет следующим:

IP 192.168.122.100.60236 > 172.16.10.10.80: Flags [S], seq 4203590660, win 62720, options [mss 1460,sackOK,TS val 1511828881 ecr 0,nop,wscale 7], length 0
IP 172.16.10.10.80 > 192.168.122.100.60236: Flags [S.], seq 3672808466, ack 4203590661, win 65535, options [mss 1430,sackOK,TS val 2474659117 ecr 1511828881,nop,wscale 8], length 0
IP 192.168.122.100.60236 > 172.16.10.10.80: Flags [S], seq 4203590660, win 62720, options [mss 1460,sackOK,TS val 1511829887 ecr 0,nop,wscale 7], length 0
IP 172.16.10.10.80 > 192.168.122.100.60236: Flags [S.], seq 3672808466, ack 4203590661, win 65535, options [mss 1430,sackOK,TS val 2474660123 ecr 1511828881,nop,wscale 8], length 0

Но поскольку SIN ACK никогда не подтверждается, маршрутизатор продолжает отправлять новые SIN.

Теперь, если я выполню tcpdump eth1:

IP 192.168.100.90.60238 > 172.16.10.10.80: Flags [S], seq 3124513394, win 62720, options [mss 1460,sackOK,TS val 1511928806 ecr 0,nop,wscale 7], length 0
IP 192.168.100.90.60238 > 172.16.10.10.80: Flags [S], seq 3124513394, win 62720, options [mss 1460,sackOK,TS val 1511929823 ecr 0,nop,wscale 7], length 0
IP 192.168.100.90.60238 > 172.16.10.10.80: Flags [S], seq 3124513394, win 62720, options [mss 1460,sackOK,TS val 1511931839 ecr 0,nop,wscale 7], length 0

Мы видим, что ответ никогда не направляется обратно на 192.168.100.90.

Если я отключил отслеживание подключений и разрешил все в iptables, то все работает. Так что я думаю, что conntrack имеет проблемы с управлением TCP-подключениями из себя в другую зону, когда они NAT? Если что-то не понятно, я с радостью отвечу на любые вопросы по этому поводу.

решение1

Проблема присутствовала в Debian 10 с ядром 4.19.0-12-amd64, но после обновления до Debian 11 с ядром 5.10.0-11-amd64 она работает так, как и ожидалось, даже для потоков TCP.

Связанный контент