hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

firewall-cmdの使い方



1 firewall-cmdとは?

firewall-cmdは、ファイアウォールの設定を行うコマンドです。firewall-cmdは、Ubuntuufw,openSUSEのSUSEfirewall2と同じ位置づけのコマンドです。図に書くと、以下のようになります。ufwコマンドの使い方は、ufwコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

     CentOS7         Ubuntu20.04         openSUSE(Leap42.3)
+--------------+    +------------+    +---------------------+   -*-
| firewall-cmd |    |     ufw    |    |    SUSEfirewall2    |    |
+--------------+    +------------+    +---------------------+    |
                                                               ユーザ空間
+-----------------------------------------------------------+    |
|                     iptables  command                     |    |
+-----------------------------------------------------------+   -*-

+-----------------------------------------------------------+   -*-
|                                                           |    |
|                    OS(netfilter)                          |  カーネル空間
|                                                           |    |
+-----------------------------------------------------------+   -*-

2 検証環境

2.1 ネットワーク構成

サーバとクライアントの2台構成です。図中のens33はNICの名前です。

                               192.168.2.0/24
client(ens33) ------------------------------------------(ens33) server
        .105                                           .100

2.2 版数

CentOS版数は、サーバ、クライアントともに下記版数です。

[root@server ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

カーネル版数は以下のとおりです。

[root@server ~]# uname  -r
3.10.0-1160.el7.x86_64

firewall-cmdの版数は以下のとおりです。

[root@server ~]# firewall-cmd --version
0.6.3

3 firewall-cmdの起動、停止方法

firewalldを起動すると、firewall-cmdが使えるようになります。

[root@server ~]# systemctl start firewalld.service
[root@server ~]# firewall-cmd --version
0.6.3

firewalldを停止すると、firewall-cmdが使えなくなります。

[root@server ~]# systemctl stop firewalld.service
[root@server ~]# firewall-cmd --version
FirewallD is not running

4 ランタイムルール、パーマネントルールについて

種別 ルールの保存先
ランタイムルール ランタイムルールはメモリ上に保存されます。firewalldをリスタートするとメモリからルールが消えます
パーマネントルール パーマネントルールはファイル(/etc/firewalld/zones配下)に保存されます。firewalldをリスタートすると、ルールがファイルから読み出され、メモリに展開されます

4.1 ランタイムルールにルールを登録する方法

ランタイムルールはメモリ上に保存されるルールです。firewalldをリスタートすると、ランタイムルールが消えてしまいます。ここでは、firewalldをリスタートすることで、ランタイムルールが消えることを確認してみます。

ランタイムルールを確認します。ルールが登録れていないことがわかります。

[root@server ~]# firewall-cmd --list-ports

[root@server ~]#

TCPの11111番ポートへのアクセスを許可するルールをランタイムルールに登録します。

[root@server ~]# firewall-cmd --add-port=11111/tcp
success

ランタイムルールを確認します。11111番ポートへのアクセスを許可するルールが登録されたことがわかります。

[root@server ~]# firewall-cmd --list-ports
11111/tcp

firewalldを再起動します。

[root@server ~]# systemctl restart firewalld.service

ランタイムルールを確認します。ランタイムルールからルールが削除されたことがわかります(期待値)。

[root@server ~]# firewall-cmd --list-ports

[root@server ~]#

4.2 ランタイムルールをパーマネントルールに保存する方法(--runtime-to-permanent)

ランタイムルールを確認します。ルールが登録されていないことがわかります。

[root@server ~]# firewall-cmd --list-ports

[root@server ~]#

TCPの11111番ポートへのアクセスを許可するルールをランタイムルールに登録します。

[root@server ~]# firewall-cmd --add-port=11111/tcp
success

ランタイムルールを確認します。11111番ポートへのアクセスを許可するルールが登録されたことがわかります。

[root@server ~]# firewall-cmd --list-ports
11111/tcp

ランタイムルールをパーマネントルールに保存します。

[root@server ~]# firewall-cmd --runtime-to-permanent
success

パーマネントルールを確認します。ルールが設定ファイルに登録されたことがわかります。

[root@server ~]# cat /etc/firewalld/zones/public.xml|grep 11111
  <port protocol="tcp" port="11111"/>

firewalldを再起動します。

[root@server ~]# systemctl restart firewalld.service

ランタイムルールを確認します。11111番ポートが開放されていることがわかります。

[root@server ~]# firewall-cmd --list-ports
11111/tcp

4.3 パーマネントルールを削除する方法

登録したルールをランタイムルールから削除します。

[root@server ~]# firewall-cmd --remove-port=11111/tcp
success

ランタイムルールを確認します。登録したルールが削除されたことがわかります。

[root@server ~]# firewall-cmd --list-ports

[root@server ~]#

ランタイムルールをパーマネントルールに保存します。

[root@server ~]# firewall-cmd --runtime-to-permanent
success

パーマネントルールの設定ファイルを確認します。ルールがファイルから削除されたことがわかります。

[root@server ~]# cat /etc/firewalld/zones/public.xml|grep 11111
[root@server ~]#

4.4 ルールをパーマネントルールに直接保存する方法(--permanent)

ルールをランタイムルールに登録するのではなく、パーマネントルールの設定ファイルに直接保存する方法について説明します。
ランタイムルールを確認します。

[root@server ~]# firewall-cmd --list-ports

[root@server ~]#

パーマネントルールを確認します。11111番ポートへのアクセスを許可するルールが登録されていないことがわかります。

[root@server ~]# cat /etc/firewalld/zones/public.xml|grep 11111
[root@server ~]#

11111番ポートへのアクセスを許可するルールをパーマネントルールに保存します。

[root@server ~]# firewall-cmd --permanent --add-port=11111/tcp
success

ランタイムルールを確認します。TCPの11111番ポートにアクセス許可するルールが登録されていないことがわかります。

[root@server ~]# firewall-cmd --list-ports
[root@server ~]#

パーマネントルールを確認します。ルールがパーマネントルールに登録されたことがわかります。

[root@server ~]# cat /etc/firewalld/zones/public.xml|grep 11111
  <port protocol="tcp" port="11111"/>
[root@server ~]#

4.5 パーマネントルールをランタイムルールにロードする方法(--reload)

ランタイムルールを確認します。何も登録されていないことがわかります。

[root@server ~]# firewall-cmd --list-ports

[root@server ~]#

パーマネントルールを確認します。TCPの11111番ポートにアクセス許可するルールが登録されていないことがわかります。

[root@server ~]# cat /etc/firewalld/zones/public.xml|grep 11111
[root@server ~]#

11111番ポートへのアクセスを許可するルールをパーマネントルールに保存します。

[root@server ~]# firewall-cmd --permanent --add-port=11111/tcp
success

ランタイムルールを確認します。TCPの11111番ポートにアクセス許可するルールが登録されていないことがわかります。

[root@server ~]# firewall-cmd --list-ports

[root@server ~]#

パーマネントルールを確認します。ルールがパーマネントルールに登録されたことがわかります。

[root@server ~]# cat /etc/firewalld/zones/public.xml|grep 11111
  <port protocol="tcp" port="11111"/>

パーマネントルールをランタイムルールにロードします。

[root@server ~]# firewall-cmd --reload
success

ランタイムルールを確認します。TCPの11111番ポートにアクセス許可するルールが登録されていることがわかります。

[root@server ~]# firewall-cmd --list-ports
11111/tcp

5 ポートを開放する方法、ポートを閉じる方法

5.1 数値を使う場合

ランタイムルールを確認します。以下の実行結果では、なにもルールが登録されていないことがわかります。

[root@server ~]# firewall-cmd --list-ports

[root@server ~]#

TCPの11111番ポートへのアクセスを許可するルールをランタイムルールに登録します

[root@server ~]# firewall-cmd --add-port=11111/tcp
success

ランタイムルールを確認します。11111番ポートへのアクセス許可のルールが登録されたことがわかります。

[root@server ~]# firewall-cmd --list-ports
11111/tcp

次に、11111番ポートへのアクセスを拒否するため、11111番ポートを閉じます。

[root@server ~]# firewall-cmd --remove-port=11111/tcp
success

ランタイムルールを確認します。11111番ポートへのアクセス許可のルールが削除されたことがわかります。

[root@server ~]# firewall-cmd --list-ports

[root@server ~]#

5.2 サービス名を使う場合

サービス名とはポート番号の別名です。サービス名とポート番号の対応関係は/etc/servicesに登録されていて、たとえば、httpなら80、sshなら22と登録されています。
アクセスが許可されているサービス名一覧を確認してみます。ssh(22番)とdhcpv6-client(546番)へのアクセスが許可されていることがわかる。

[root@server ~]# firewall-cmd --list-services
dhcpv6-client ssh

httpへのアクセスを許可します。

[root@server ~]# firewall-cmd --add-service=http
success

アクセスが許可されているサービス名一覧を確認してみます。dhcpv6-client、http、sshへのアクセスが許可されていることがわかります。

[root@server ~]# firewall-cmd --list-services
dhcpv6-client http ssh

次に、登録したhttpへのアクセスを解除してみます。

[root@server ~]# firewall-cmd --remove-service=http
success

アクセスが許可されているサービス名一覧を確認してみます。httpへのアクセス許可が解除されたことがわかります。

[root@server ~]# firewall-cmd --list-services
dhcpv6-client ssh

6 追加したポート番号はiptablesにどのように設定されているか?

追加したポート番号やサービスが、iptablesにどのように設定されているのかを確認してみます。
まず、11111番ポートへのアクセスを許可します。

[root@server ~]# firewall-cmd --add-port=11111/tcp
success

ランタイムルールを確認します。11111番ポートへのアクセスが許可されたことがわかる。

[root@server ~]#  firewall-cmd --list-ports
11111/tcp
[root@server ~]#

iptablesのINPUTチェインを確認します。

[root@server ~]# iptables -nvL INPUT
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:53
    0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:53
    0     0 ACCEPT     udp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            udp dpt:67
    0     0 ACCEPT     tcp  --  virbr0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:67
  158  9972 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
   16  1692 INPUT_direct  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   16  1692 INPUT_ZONES_SOURCE  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   16  1692 INPUT_ZONES  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate INVALID
   16  1692 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

次に、INPUT_ZONESを確認します。

[root@server ~]# iptables -nvL INPUT_ZONES
Chain INPUT_ZONES (1 references)
 pkts bytes target     prot opt in     out     source               destination
   16  1692 IN_public  all  --  ens33  *       0.0.0.0/0            0.0.0.0/0           [goto]
    0     0 IN_public  all  --  +      *       0.0.0.0/0            0.0.0.0/0           [goto]

次に、IN_publicチェインを確認します。

[root@server ~]# iptables -nvL IN_public
Chain IN_public (2 references)
 pkts bytes target     prot opt in     out     source               destination
   16  1692 IN_public_log  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   16  1692 IN_public_deny  all  --  *      *       0.0.0.0/0            0.0.0.0/0
   16  1692 IN_public_allow  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0

最後にIN_public_allowチェインを確認すると、11111番ポートへのアクセスが許可されたルールが登録されていることがわかります。

[root@server ~]# iptables -nvL IN_public_allow
Chain IN_public_allow (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22 ctstate NEW,UNTRACKED
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:11111 ctstate NEW,UNTRACKED
[root@server ~]#

INPUTチェインから、IN_public_allowチェインまでは、以下のような階層構造になっています。そして、IN_public_allowチェインで、11111番ポートへのアクセスを許可する設定が行われています。

INPUT
 + INPUT_ZONES
    + IN_public
       + IN_public_allow
          + ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:11111 ctstate NEW,UNTRACKED

ランタイムルールから11111番ポートへのアクセス許可のルールを削除します。

[root@server ~]# firewall-cmd --remove-port=11111/tcp
success

IN_public_allowチェインを確認します。11111番ポートへのアクセス許可のルールが削除されたことがわかります。

[root@server ~]# iptables -nvL IN_public_allow
Chain IN_public_allow (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22 ctstate NEW,UNTRACKED

7 ICMPタイプの表示、設定、削除方法

7.1 ICMPタイプを表示する方法(--get-icmptypes)

ICMPタイプの一覧を表示してみます。

[root@server ~]# firewall-cmd --get-icmptypes
address-unreachable bad-header communication-prohibited destination-unreachable echo-reply echo-request fragmentation-needed host-precedence-violation host-prohibited host-redirect host-unknown host-unreachable ip-header-bad neighbour-advertisement neighbour-solicitation network-prohibited network-redirect network-unknown network-unreachable no-route packet-too-big parameter-problem port-unreachable precedence-cutoff protocol-unreachable redirect required-option-missing router-advertisement router-solicitation source-quench source-route-failed time-exceeded timestamp-reply timestamp-request tos-host-redirect tos-host-unreachable tos-network-redirect tos-network-unreachable ttl-zero-during-reassembly ttl-zero-during-transit unknown-header-type unknown-option

7.2 ICMPタイプを設定する方法(--add-icmp-block)

ここでは、ICMP Echo要求をブロックする設定をしてみます。設定するICMPのタイプは、7.1で得たタイプを指定します。

[root@server ~]# firewall-cmd --add-icmp-block=echo-request
success

ブロックしているICMPタイプを確認してみます。

[root@server ~]# firewall-cmd --list-icmp-blocks
echo-request

ICMP Echo要求のブロック設定を行うと、IN_public_denyチェインに下記設定が行われます。

[root@server ~]# iptables -nvL IN_public_deny
Chain IN_public_deny (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 REJECT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0            icmptype 8 reject-with icmp-host-prohibited

IN_public_denyチェインは、以下のようにINPUTチェインから呼び出されています。

INPUT
 + INPUT_ZONES
    + IN_public
       + IN_public_deny
          + REJECT icmptype 8 reject-with icmp-host-prohibited

クライアントからサーバに対してpingを3回実行してみます。"Destination Host Prohibited"と表示され、サーバでICMP echo要求がブロックされていることがわかります。pingコマンドの詳細な使い方は、pingコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@client ~]# ping -c 3 192.168.2.100
PING 192.168.2.100 (192.168.2.100) 56(84) bytes of data.
From 192.168.2.100 icmp_seq=1 Destination Host Prohibited
From 192.168.2.100 icmp_seq=2 Destination Host Prohibited
From 192.168.2.100 icmp_seq=3 Destination Host Prohibited

--- 192.168.2.100 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2016ms

[root@client ~]#

7.3 ICMPタイプを削除する方法(--remove-icmp-block)

ブロックしているICMPタイプを確認してみます。echo-requestが登録されていることがわかります。

[root@server ~]# firewall-cmd --list-icmp-blocks
echo-request

echo-requestを削除します。

[root@server ~]# firewall-cmd --remove-icmp-block=echo-request
success

ブロックしているICMPタイプを確認してみます。何も登録されtいないことがわかります。

[root@server ~]# firewall-cmd --list-icmp-blocks

[root@server ~]#

8 ダイレクトルールの使い方

ダイレクトルールは、OSのNetfilterに直接アクセスするためのものです。ダイレクトルールを使うと、iptablesコマンドで設定できることは、ほぼ全て設定できるようになります。

8.1 ダイレクトルールの追加、削除する方法

TCPの宛先ポート番号が11111番へのパケットを廃棄(DROP)する設定をします。

[root@server ~]# firewall-cmd --direct --add-rule ipv4 filter INPUT 1 -p tcp --dport 11111 -j DROP
success

ルールを確認します。作成したルールが登録されていることがわかります。

[root@server ~]# firewall-cmd --direct --get-all-rules
ipv4 filter INPUT 1 -p tcp --dport 11111 -j DROP

登録したルールを削除します。

[root@server ~]# firewall-cmd --direct --remove-rule ipv4 filter INPUT 1 -p tcp --dport 11111 -j DROP
success

ルールを確認します。ルールが削除されたことがわかります。

[root@server ~]# firewall-cmd --direct --get-all-rules
[root@server ~]#

8.2 ポート番号の範囲を指定する方法(multiport)

指定したポート番号の範囲へのアクセス許可を設定する方法を示します。以下の例は、宛先TCPポート番号10000から10005までのパケットの受信許可をします。

[root@server ~]# firewall-cmd --direct --add-rule ipv4 filter INPUT 1 -i ens33 -p tcp -m multiport --dports 10000:10005 -j ACCEPT
success

ルールを確認します

[root@server ~]# firewall-cmd --direct --get-all-rules
ipv4 filter INPUT 1 -i ens33 -p tcp -m multiport --dports 10000:10005 -j ACCEPT

作成したルールを削除します。

[root@server ~]# firewall-cmd --direct --remove-rule ipv4 filter INPUT 1 -i ens33 -p tcp -m multiport --dports 10000:10005 -j ACCEPT
success

ルールを確認します。ルールが削除されたことがわかります。

[root@server ~]# firewall-cmd --direct --get-all-rules
[root@server ~]#

8.3 ユーザ定義チェインの追加、削除する方法

OUTPUT_direct_xxxxxという名前のユーザ定義チェインを作成します。

[root@server ~]# firewall-cmd --direct --add-chain ipv4 filter OUTPUT_direct_xxxxx
success

ユーザ定義チェインを確認します。 OUTPUT_direct_xxxxxという名前のユーザ定義チェインが作成されたことがわかります。

[root@server ~]# firewall-cmd --direct --get-all-chains
ipv4 filter OUTPUT_direct_xxxxx

OUTPUT_direct_xxxxxという名前のユーザ定義チェインを削除します。

[root@server ~]# firewall-cmd --direct --remove-chain ipv4 filter OUTPUT_direct_xxxxx
success

ユーザ定義チェインを確認します。 OUTPUT_direct_xxxxxという名前のユーザ定義チェインが削除されたことがわかります。

[root@server ~]# firewall-cmd --direct --get-all-chains
[root@server ~]#

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ