네트워크 연결이 거부된 이유는 무엇입니까?

네트워크 연결이 거부된 이유는 무엇입니까?

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버전 과 함께 제공됩니다 .iptablesiptables

하지만...

기본적으로 설치된 방화벽은국가의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 규칙을 추가하는 것입니다.

  1. 아직 다른 특정 영역을 사용하고 있지 않다면 먼저 내부 영역에 docker0을 추가하세요.

    firewall-cmd --zone=internal --change-interface=docker0 --permanent
    firewall-cmd --reload
    
  2. 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 댓글 수락 "뭔가에 대한 댓글"

  3. 또한 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 배포판에 따라) 재부팅 중에 자동으로 적용되지 않을 수 있습니다.

관련 정보