1. 概要
危険な考えかもしれませんが、優秀なルータを使用して、ルータのファイアウォールが細かく設定されていれば、サーバ側でファイアウォールを使用する必要はないと思っています。
しかし、ルータが非力な場合は、サーバ側にファイアウォールを設定しなければなりません。
「FreeBSD」にデフォルトで用意されているファイアウォールを使用することで十分対応できると思っています。
デフォルトで用意されているファイアウォールは、「IP Firewall」、通称「IPFW」というそうです。
(ここに参考サイトを掲載していましたが、リンク切れになってしまいました)
2. カーネルの再構築
「IPFW」を有効にするには、カーネルの再構築が必要になります。
カーネルの設定の詳細に関しては「基本設定 - カーネルの再構築」をご参照ください。
3つのオプションを追加します。
options IPFIREWALL
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=10
options IPFIREWALL_DEFAULT_TO_ACCEPT
「IPFIREWALL」のオプションは必須、これを定義ことで初めて IPFW が有効になります。
「IPFIREWALL_VERBOSE」のオプションを定義することでログを取ることができます。
「IPFIREWALL_DEFAULT_TO_ACCEPT」は、「IPFW」のデフォルトの動作では、すべてのパケットを「deny」するそうで、これを定義するとデフォルトの動作が「allow」になるそうです。
これは気をつける必要があるようで、下記の定義を有効にするか、後で示す、もう一つの方法で、パケットを通過させるようにしておかないと、ファイアウォールを有効にして起動したら、自分自身のパケットもふさいでしまって何もできない状態に陥ることになります。
他に
options IPFIREWALL_VERBOSE_LIMIT=10 ← 値は変えられます。
というオプションがあって、ログを有効にしたとき、ログが大量に出力されることを防ぐためにあるそうです。
ここで定義した(単位がわかりませんが)量にログが達した場合、ログの出力が停止するとのこと。
出力が停止したら、コマンドで、ログの量をリセットしてやる必要があるそうです。
よって、この定義は有効にしない方がよさそうです。
オプションを設定したら、カーネルをコンパイルしてインストールします。
コンパイル・インストールの手順は「基本設定 - カーネルの再構築」を参照してください。
3. /etc/rc.conf 設定
カーネルの構築までできたら、「/etc/rc.conf」を編集してファイアウォールを有効にします。
「root」ユーザで
service ipfw enable
前項で「options IPFIREWALL_DEFAULT_TO_ACCEPT」を定義していない場合
cat << 'EOF' >> /etc/rc.conf
firewall_type="open"
'EOF'
これを定義することで、デフォルトの動作を「allow」にすることができます。
デフォルトを「allow」にしているならば、この時点で、いったん起動してみます。
$ service ipfw start
Flushed all rules.
00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
00400 deny ip from any to ::1
00500 deny ip from ::1 to any
00600 allow ipv6-icmp from :: to ff02::/16
00700 allow ipv6-icmp from fe80::/10 to fe80::/10
00800 allow ipv6-icmp from fe80::/10 to ff02::/16
00900 allow ipv6-icmp from any to any icmp6types 1
01000 allow ipv6-icmp from any to any icmp6types 2,135,136
Firewall rules loaded.
4. デフォルトの設定を見てみる
ここから先は、「ipfw」というコマンドを使用します。
前項までの設定を終えて、再起動後にファイアウォールのルールがどうなっているのかを見てみます。
$ ipfw -a list
00100 64 22370 allow ip from any to any via lo0
00200 0 0 deny ip from any to 127.0.0.0/8
00300 0 0 deny ip from 127.0.0.0/8 to any
00400 0 0 deny ip from any to ::1
00500 0 0 deny ip from ::1 to any
00600 0 0 allow ipv6-icmp from :: to ff02::/16
00700 0 0 allow ipv6-icmp from fe80::/10 to fe80::/10
00800 0 0 allow ipv6-icmp from fe80::/10 to ff02::/16
00900 0 0 allow ipv6-icmp from any to any ip6 icmp6types 1
01000 0 0 allow ipv6-icmp from any to any ip6 icmp6types 2,135,136
65535 395 44855 allow ip from any to any
「list」は、リスティング。
「-a」オプションが。すべてということのようです。
1フィールド目がフィルタの番号で「0~65535」が設定できるそうです。
フィルタのチェックは若い順にチェックするとのことで、この場合、「200~500」までしか「deny」がないので「100~500」をすり抜けてきたものは最後の「65535」で、「allow ip from any to any」ですべての「ip」が「any」から any へ届くことを許可しているので、通信可能となるわけです。
「200~500」の「deny」はループバックアドレスの通信を語る外部のものや、自分のループバックアドレスから外部へ出るものを遮断しているようです。
5. 拒否のフィルタを追加
わたしがやりたいのは、「ssh」で侵入しようとする外部からの通信を遮断することです。
実現するには例えば以下のように設定します。
「123.0.0.0」のネットワークからの「ssh」の侵入を防ぐには
ipfw add 10000 deny tcp from 123.0.0.0/8 to me 22
ここで「10000」はフィルタの番号です。
デフォルトの設定と重ならないようにするので「10001~65534」の番号にします。
「tcp」 はプロトコルです。
「123.0.0.0/8 to me」 は、「123.0.0.0 ~ 123.255.255.255」の自分に向かってくるアドレスです。
「22」は、「ssh」のポート番号です。
ここのアドレス部を試験的にクライアントマシンのアドレスにすれば試験できますが、手元にサーバマシンのコンソールがないと何もできなくなりますのでご注意を。
6. コンフィグレーションファイルの作成
前項の設定を拒否したいプロトコル・アドレス・方向・ポートを組み合わせて追加していけば、やりたいことは実現できるわけですが。
コマンドで設定したものは、マシンを再起動するとリセットされてしまいます。
設定を記述したコンフィグレーションファイルを作成してロードするようにします。
例えば、「/etc/firewall.conf」というファイルを作成して、以下のように記述します。
add 10000 deny tcp from 123.0.0.0/8 to me 22
前項のコマンドから「ipfw」という、コマンドをはずしたものです。
作成したら「/etc/rc.conf」に以下を追加します。
firewall_type="/etc/firewall.conf"
これで、マシンの再起動もしくは
> service ipfw restart
Flushed all rules.
00100 allow ip from any to any via lo0
00200 deny ip from any to 127.0.0.0/8
00300 deny ip from 127.0.0.0/8 to any
00400 deny ip from any to ::1
00500 deny ip from ::1 to any
00600 allow ipv6-icmp from :: to ff02::/16
00700 allow ipv6-icmp from fe80::/10 to fe80::/10
00800 allow ipv6-icmp from fe80::/10 to ff02::/16
00900 allow ipv6-icmp from any to any ip6 icmp6types 1
01000 allow ipv6-icmp from any to any ip6 icmp6types 2,135,136
Firewall rules loaded.
でコンフィグレーションファイルの設定が反映されるようになります。
7. フィルタ設定のオプション
フィルタを設定する際の主なパラメータ・オプションを提示しておきます。
> ipfw [-N] command [index] action [log] protocol from アドレス [port] \
to アドレス [port] [via interface] [option]
パラメータ | 意味 |
-N | アドレスやサービス名を 文字列に変換して表示します。 |
command | add | ルールを追加します。 |
delete | ルールを削除します。 |
index | ルールの番号を指定します。 |
log | カーネルを IPFIREWALL_VERBOSE つきでコンパイルしていれば、マッチしたルールをログに出力します。 |
action | reject | パケットを捨て、ICMP ホスト / ポート到達不能パケットの適切な方を発信元へ送ります。 |
allow | パケットを通過させます。 |
deny | パケットを捨てます。reject と違うのは ICMP を返さないので、相手には何が起こっているかわかりません。 付き合いたくない相手にはこちらの方が有効かと思います。 |
count | パケットカウンタを更新するのみです。 ログと組み合わせると分析に便利なのかしら? |
protocol | all | 任意のプロトコル。 |
icmp | icmp 。ping に使われるプロトコルですね。 |
tcp | tcp |
udp | udp |
アドレス | アドレスの直接表記とアドレス/ビットマスクでの指定が可能です。 |
ポート番号 | ポート番号-ポート番号と範囲指定することもできるし、ポート番号をカンマで区切って複数記述することができます。両方を記述することもできますが、両方指定する場合は範囲指定を先に記述しなければなりません。 また ssh のように文字列で指定することもできます。 文字列の方が意図的に何を指定しているかがわかって良いように思います。 文字列は /etc/services に定義してあります。 |
interface | 複数の NIC を使用してルーティングしているときに便利ですね。 |
option | in | 入力パケット。 |
out | 出力パケット。 |
established | パケットが既に確立されている TCP コネクションの一部であれば (RST または ACK ビットがセットされていれば) マッチします。 このをチェーンの最初の方に置くと通過させたいパケットのチェックでファイアウォールの負担をかけないようにできます。 |