ネットワーク接続が拒否されたのはなぜですか?

ネットワーク接続が拒否されたのはなぜですか?

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                  [::]:*

tcpdumpvirbr0ホストまたはゲストから)を使用すると、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

ゲストのルーティングテーブルは完全にOKです。

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"
    

シェルスクリプトを使用してこれら2つのルールをラップし、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ディストリビューションによっては)再起動中に自動的に適用されない可能性があります。

関連情報