Fedora 31 호스트에서 CentOS 8 게스트를 실행하고 있습니다. 게스트는 브리지된 네트워크에 연결되어 virbr0
있으며 주소를 가지고 있습니다 192.168.122.217
. 해당 주소에서 SSH를 통해 게스트로 로그인할 수 있습니다.
포트 80에서 수신 대기하는 게스트에서 서비스를 시작하면 다음과 같이 호스트에서 게스트로의 모든 연결이 실패합니다.
$ curl 192.168.122.217
curl: (7) Failed to connect to 192.168.122.217 port 80: No route to host
서비스는 다음을 충족해야 합니다 0.0.0.0
.
guest# ss -tln
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 5 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
tcpdump
( virbr0
호스트 또는 게스트에서) 을 사용하면 eth0
게스트가 ICMP "Admin Forbidden" 메시지로 응답하는 것으로 보입니다.
19:09:25.698175 IP 192.168.122.1.33472 > 192.168.122.217.http: Flags [S], seq 959177236, win 64240, options [mss 1460,sackOK,TS val 3103862500 ecr 0,nop,wscale 7], length 0
19:09:25.698586 IP 192.168.122.217 > 192.168.122.1: ICMP host 192.168.122.217 unreachable - admin prohibited filter, length 68
INPUT
게스트 체인에는 방화벽 규칙이 없습니다.
guest# iptables -S INPUT
-P INPUT ACCEPT
게스트의 라우팅 테이블은 완전히 괜찮아 보입니다.
guest# ip route
default via 192.168.122.1 dev eth0 proto dhcp metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.168.122.0/24 dev eth0 proto kernel scope link src 192.168.122.217 metric 100
SELinux가 허용 모드에 있습니다.
guest# getenforce
Permissive
sshd
포트 22에서 서비스를 중지하고 시작 하면 모든 것이 예상대로 작동합니다.
이러한 연결이 실패하는 원인은 무엇입니까?
누군가 요청하면 iptables-save
게스트의 전체 출력은 다음과 같습니다.
*filter
:INPUT ACCEPT [327:69520]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [285:37235]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
*security
:INPUT ACCEPT [280:55468]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [285:37235]
COMMIT
*raw
:PREROUTING ACCEPT [348:73125]
:OUTPUT ACCEPT [285:37235]
COMMIT
*mangle
:PREROUTING ACCEPT [348:73125]
:INPUT ACCEPT [327:69520]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [285:37235]
:POSTROUTING ACCEPT [285:37235]
COMMIT
*nat
:PREROUTING ACCEPT [78:18257]
:INPUT ACCEPT [10:600]
:POSTROUTING ACCEPT [111:8182]
:OUTPUT ACCEPT [111:8182]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A DOCKER -i docker0 -j RETURN
COMMIT
답변1
알았어, 알아냈어. 정말 대단해요.
CentOS 8은 다음을 사용합니다.nftables, 그 자체로는 놀라운 일이 아닙니다. 이는 명령 을 사용할 때 실제로 nftables에 호환성 테이블 세트를 유지한다는 의미인 명령 nft
버전 과 함께 제공됩니다 .iptables
iptables
하지만...
기본적으로 설치된 방화벽은국가의nftables를 지원하므로 iptables 호환성 레이어를 사용하지 않습니다.
따라서 다음을 iptables -S INPUT
보여줍니다.
# iptables -S INPUT
-P INPUT ACCEPT
너 뭐야실제로다음이 있습니다:
chain filter_INPUT {
type filter hook input priority 10; policy accept;
ct state established,related accept
iifname "lo" accept
jump filter_INPUT_ZONES_SOURCE
jump filter_INPUT_ZONES
ct state invalid drop
reject with icmpx type admin-prohibited <-- HEY LOOK AT THAT!
}
여기서 해결책(그리고 솔직히 일반적으로 좋은 조언)은 다음과 같습니다.
systemctl disable --now firewalld
방화벽을 끄면 표시되는 iptables 규칙이 iptables -S
예상대로 실행됩니다.
답변2
Firewalld를 비활성화하지 않으려는 경우 해결 방법은 하이퍼바이저 호스트에 아래에 언급된 nftables 규칙을 추가하는 것입니다.
아직 다른 특정 영역을 사용하고 있지 않다면 먼저 내부 영역에 docker0을 추가하세요.
firewall-cmd --zone=internal --change-interface=docker0 --permanent firewall-cmd --reload
nftables를 실행하여 대상이 192.168.122.217인 포트 80에서 virbr0 인터페이스로의 TCP 트래픽을 허용하는 규칙을 적용합니다.
/sbin/nft 규칙 추가 inet Firewalld filter_FWDI_internal_allow oifname "virbr0" ip baddr 192.168.122.217 tcp dport 80 counter 댓글 수락 "뭔가에 대한 댓글"
또한 iptables 규칙을 추가해야 합니다(또는 일관성을 위해 이를 nftables로 변환합니다. 아래 참조).
/usr/sbin/iptables -t filter -I FORWARD -p tcp -o virbr0 -d 192.168.122.217 --dport 80 -j ACCEPT -m comment --comment "comment something"
쉘 스크립트를 사용하여 이 두 규칙을 래핑하고 systemd 서비스 단위를 추가하고 지연을 5초로 설정할 수 있습니다. 시작 시 자동으로 실행되게 하세요.
또한 iptables 규칙을 nftables로 변환하고 둘 다 nftables 규칙 세트에 저장할 수 있습니다. 그러나 변환된 iptables 규칙을 실행하면 iptables가 잠기고 iptables에 대한 새로운 변경 사항은 Firewalld 및 nftables를 통해서만 수행할 수 있습니다.
또한 브리지를 통과하는 패킷이 iptables를 통과하지 않도록 사용자 정의 커널 조정 가능 항목이 있어야 합니다.Net.bridge.bridge-nf-call 및 sysctl.conf
sysctl net.bridge.bridge-nf-call-iptables=0
sysctl net.bridge.bridge-nf-call-arptables=0
sysctl net.bridge.bridge-nf-call-ip6tables=0
이를 sysctl.conf에 추가하면 알려진 버그이므로(Linux 배포판에 따라) 재부팅 중에 자동으로 적용되지 않을 수 있습니다.