Conntrack, 다른 VRF에서 자체 TCP 패킷을 NAT하는 데 실패했습니다.

Conntrack, 다른 VRF에서 자체 TCP 패킷을 NAT하는 데 실패했습니다.

Debian 기반 라우터에서 여러 VRF를 사용할 때 소스 NAT에서 까다로운 문제를 발견했습니다. 설명하기가 좀 복잡해서 명확하게 설명하도록 노력하겠습니다만, 짧지는 않을 것 같습니다. 죄송합니다. 하지만 문제는 재현하기 쉬워야 합니다.

라우터 작업(라우팅 및 NATing 패킷)에서 라우터의 "관리" 부분(Ssh 및 기타 서비스)을 분리하기 위해 기본 VRF에서 "mgmt" VRF를 설정하려고 했습니다(서비스 소켓을 처리하기 더 쉬움). "방화벽"이라는 VRF의 라우팅입니다.

다이어그램은 다음과 같이 요약될 수 있습니다.

네트워크 다이어그램

"관리" 네트워크는 192.168.100.0/24이며 네트워크 10.254.5.0/24를 통해 라우터의 "방화벽" VRF가 있는 L3이 있는 L3 스위치에 의해 라우팅됩니다. 세 번째 라우터 인터페이스는 "인터넷" 인터페이스이며, 이를 통과하는 패킷은 소스 NAT입니다. 이 설정은 conntrack의 원인인 라우터 자체 패킷을 제외하고 mgmt 서브넷의 모든 항목에 매우 잘 작동합니다.

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 스위치에 의해 라우팅되고 eth1에 의해 방화벽 VRF에 들어가고 eth2를 통해 라우팅 및 NAT됩니다. INPUT 및 FORWARD 연결을 추적하기 때문에 conntrack은 패킷이 돌아올 때 약간 혼란스럽고 패킷으로 무엇을 해야할지 알 수 없습니다.

원시 테이블에서 conntrack zone을 사용하여 ICMP 및 UDP에 대해 이 문제를 해결할 수 있었습니다.

# 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에 대한 ping을 사용하면 다음과 같습니다(명령 사용 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에서도 작동합니다(예: 8.8.8.8에 대한 DNS 쿼리).

    [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에서는 작동하지 않습니다. 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이 NAT일 때 자체에서 다른 영역으로의 TCP 연결을 관리하는 데 문제가 있다고 생각합니까? 명확하지 않은 부분이 있으면 이에 대한 질문에 기꺼이 답변해 드리겠습니다.

답변1

이 문제는 커널 4.19.0-12-amd64가 있는 debian 10에서 발생했지만 커널 5.10.0-11-amd64가 있는 debian 11로 업그레이드한 후에는 TCP 흐름에서도 예상대로 작동합니다.

관련 정보