次のような複雑なブリッジ構成があります。
デフォルトのパスがありますvia 172.31.0.1 dev eth0_bridge
。
lan_bridge
eth0_bridge
今、別のデバイスが接続し、eth1
DHCPサーバーからアドレスを取得し、デフォルトのルートを介してインターネットにアクセスできるように、間の仮面舞踏会を設定しようとしていますeth0
。
そのために、次のようにiptablesルールを追加しました。
iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth0_bridge -j MASQUERADE
これを行い、他の一般的なNATルールを追加しましたが、問題を引き起こすのはまさにこのルールでした。 .tcpdumpping 172.31.0.1
に接続しようとすると、パケットが元のソースアドレスと一緒に到着したことがわかります。このルールは一度も壊れたことがないようです。だから、次のルールを追加しました。eth1
172.31.0.1
iptables -t nat -I POSTROUTING 1 -s 192.168.100.0/24 -j LOG --log-prefix NAT:
これは dmesg に表示される唯一の一致です。
[10555.271048] NAT:IN= OUT=eth1_bridge PHYSIN=eth1 PHYSOUT=ve_eth1_lan SRC=192.168.100.210 DST=172.31.0.1 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=55162 DF PROTO=ICMP TYPE=8 CODE=0 ID=13662 SEQ=1
したがって、これらのパケットがPOSTROUTINGテーブルに到着する唯一の時間は、eth1_bridge
エントリvethペア(見出し)を離れるときですlan_bridge
。この時点でパケットをMASQUERADEに送信します。
iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth1_bridge -j MASQUERADE
その結果、100%パケット損失が発生しました。
この場合、192.168.100.0/24
ネットワーク間のNATをどのように設定しますか?172.31.0.0/24
編集する詳細は:
私が見つけたシステムは、4.9カーネルを実行するAlpine 3.9でした。また、2つのブリッジを使用して4.15を実行しているUbuntu 18.04で再現されました。
答え1
br_netfilter
この動作は、モジュールをロードして関連ブリッジでiptablesを有効にした場合にのみ観察されます(参照/sys/class/net/*/bridge/nf_call_iptables
と/proc/sys/net/bridge/bridge-nf-call-iptables
- これは論理ORを適用するため、システム内のすべてのブリッジまたは特定のブリッジに対して有効にできます。有効にすると無効にすることはできません)。特定のブリッジ)。
この設定では、NAT POSTROUTINGチェーンは、パケットが最初のブリッジに到達したときにパケットに適用されます。この時点では、質問のログメッセージに示すようにOUT
デバイスがあるため、出力インターフェイスとしてのルールは機能しません。広すぎるマスカレードルールを設定してパケットが開いている間にマスカレードを許可すると、マスカレードが発生しますが、送信元アドレスが正しくありません。eth1_bridge
eth0_bridge
eth1_bridge
理論的な解決策は、ブリッジシステム全体でiptablesを無効にし、実際に必要な場合にのみ有効にすることです。残念ながら、Dockerはここに指を置いて(a)モジュールをロードし、br-netfilter
(b)/proc/sys/net/bridge/bridge-nf-call-iptablesを1に設定するよう強制しました。このシステムではdockerを使用しているので、修正するのは少し難しいです。私はこれについてlibnetworkにバグレポートを提出しました。
答え2
問題を再現するためにテスト環境を設定しました。次のスクリプトは、3つのシステムを表す3つのネットワーク名前空間を設定します。
- 質問に描かれたノードを言います
n0
。 gw
eth0
住所のあるシステム173.31.0.1
n1
eth1
アドレスに接続されているシステム192.168.100.100
。
192.168.100.0/24ネットワークと173.31.0.0/24ネットワークを表す2つのブリッジをホストに作成します。
内部構成はn0
おっしゃった通りです。
#!/bin/sh
set -x
ip netns add gw
ip netns add n0
ip netns add n1
ip link add gw-eth0-out type veth peer name gw-eth0-in
ip link add n0-eth0-out type veth peer name n0-eth0-in
ip link add n0-eth1-out type veth peer name n0-eth1-in
ip link add n1-eth0-out type veth peer name n1-eth0-in
brctl addbr 192_168_100
brctl addbr 172_31_0
brctl addif 172_31_0 gw-eth0-out
brctl addif 172_31_0 n0-eth0-out
brctl addif 192_168_100 n0-eth1-out
brctl addif 192_168_100 n1-eth0-out
for iface in 172_31_0 192_168_100 gw-eth0-out n0-eth0-out n0-eth1-out n1-eth0-out; do
ip link set $iface up
done
ip link set netns gw name eth0 gw-eth0-in
ip link set netns n0 name eth0 n0-eth0-in
ip link set netns n0 name eth1 n0-eth1-in
ip link set netns n1 name eth0 n1-eth0-in
ip netns exec gw ip addr add 172.31.0.1/24 dev eth0
ip netns exec gw ip link set eth0 up
ip netns exec n1 ip addr add 192.168.100.100/24 dev eth0
ip netns exec n1 ip link set eth0 up
ip netns exec n1 ip route add default via 192.168.100.1
ip netns exec n0 brctl addbr eth0_bridge
ip netns exec n0 brctl addbr eth1_bridge
ip netns exec n0 brctl addbr lan_bridge
ip netns exec n0 ip link add patch-eth1 type veth peer name patch-lan
ip netns exec n0 brctl addif eth0_bridge eth0
ip netns exec n0 brctl addif eth1_bridge eth1
ip netns exec n0 brctl addif eth1_bridge patch-lan
ip netns exec n0 brctl addif lan_bridge patch-eth1
ip netns exec n0 ip addr add 172.31.0.10/24 dev eth0_bridge
ip netns exec n0 ip addr add 192.168.100.1/24 dev lan_bridge
for iface in eth0 eth1 eth0_bridge eth1_bridge lan_bridge patch-lan patch-eth1; do
ip netns exec n0 ip link set $iface up
done
スクリプトの実行が完了すると、MASQUERADE
ルールのない環境モデルが作成されます。予想通り、172.31.0.1
pingの試みは192.168.100.100
失敗します。
マスカレーディングルールを次に追加するとn0
、
ip netns exec n0 iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth0_bridge -j MASQUERADE
それでもping
失敗します。
IP転送を有効にするとn0
...
ip netns exec n0 sysctl -w net.ipv4.ip_forward=1
すべてが期待どおりに機能し始めます。