
Debian ベースのルーターで複数の VRF を使用するときに、ソース NAT に関する厄介な問題に遭遇しました。説明するのが少し複雑なので、わかりやすく説明しようとしますが、短くはならないと思います。申し訳ありません。ただし、この問題は簡単に再現できるはずです。
ルーターの「管理」部分 (ssh およびその他のサービス) をルーター ジョブ (パケットのルーティングと NAT) から分離するために、デフォルトの VRF (サービス ソケットの処理が容易) に「mgmt」VRF を設定し、ルーティング VRF を「ファイアウォール」と呼ばれる VRF に設定しようとしました。
この図は次のように要約できます。
「管理」ネットワークは 192.168.100.0/24 で、ネットワーク 10.254.5.0/24 を介してルーターの「ファイアウォール」VRF を持つ L3 を持つ L3 スイッチによってルーティングされます。3 番目のルーター インターフェイスは「インターネット」インターフェイスであり、これを通過するパケットはソース NAT されます。この設定は、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 スイッチによってルーティングされ、eth1 によってファイアウォール VRF に入り、eth2 を介してルーティングおよび NAT されます。INPUT および FORWARD 接続を追跡しているため、パケットが戻ってきたときに conntrack が少し混乱し、パケットをどう処理すればよいかわかりません。
私は、rawテーブルでconntrackゾーンを使用することで、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
。応答が来ると、2 番目の接続が最初に更新され (インターネットに面しているため)、次に最初の接続が更新されます。
これは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 への Telnet クエリは次のようになります。
[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 フローでも期待どおりに動作するようになりました。