다음과 같은 복잡한 브리지 구성이 있습니다.
기본 경로가 있습니다 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 규칙을 추가했지만 문제를 일으키는 것은 바로 이 규칙이었습니다. .tcpdump ping 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였습니다. 또한 두 개의 브리지만 사용하여 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
문제를 재현해 보기 위해 테스트 환경을 설정했습니다. 다음 스크립트는 세 개의 시스템을 나타내는 세 개의 네트워크 네임스페이스를 설정합니다.
- 질문에 묘사한 노드를 라고 합니다
n0
. gw
eth0
주소 가 있는 시스템173.31.0.1
n1
eth1
주소 에 연결된 시스템입니다192.168.100.100
.
192.168.100.0/24 네트워크와 173.31.0.0/24 네트워크를 나타내는 두 개의 브리지를 호스트에 생성합니다.
내부 구성은 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
모든 것이 예상대로 작동하기 시작합니다.