# FreeBSD によるダイアルアップ式ファイアウォールの構築

Marc
Silver

    marcs@draenor.org

$FreeBSD$
&tm-attrib.freebsd; &tm-attrib.general;

この記事は FreeBSD の PPP ダイアルアップと IPFW を用いながらどのようにファイアウォールをセットアップするか、 特に動的に割り当てられた IP アドレスによるダイアルアップ上のファイアウォールについて、 事実を元に詳細に説明します。 なお、前段階である PPP 接続についての設定は触れていません。

## 序文

FreeBSD によるダイアルアップ式ファイアウォールの構築

この文書はあなたの ISP によって IP アドレスを動的に割り当てられた時、 FreeBSD でファイアウォールをセットアップために 要求される手順を扱うことをめざしたものです。 この文書を可能な限り有益で正確なものにするために努力しているので、 どうぞ意見や提案を marcs@draenor.org に送って下さい。

## カーネルオプション

最初になすべきことはカーネルを再コンパイルすることです。 カーネルを再コンパイルする方法についてさらに情報が必要なら、 ハンドブックの カーネルのコンフィグレーションの節から読み始めるのが最適でしょう。 カーネルを以下のオプションをつけてコンパイルする必要があります:

`options IPFIREWALL`

  カーネルのファイアウォールのコードを有効にします。

`options IPFW2`

  新しいバージョンの IPFW を有効にします。

  FreeBSD 4.X を運用している場合にのみ、 このオプションをつけてください。 (訳注: FreeBSD 5.X のような) 最近の FreeBSD では、 これがデフォルトになっています。

`options IPFIREWALL_VERBOSE`

  システムの logger へ記録されたパケットを送ります。

`options IPFIREWALL_VERBOSE_LIMIT=100`

  記録されるマッチするエントリの数を制限します。 これはログファイルがたくさんの繰返しのエントリで一杯になるのを抑制します。 100 は使用上無理のない数ですが、 自分の要求に基づいて調整することができます。

`options IPDIVERT`

  divertソケット (後述) を有効にします。

更なるセキュリティのために、 カーネルの中に組み込むことのできるオプションが他にいくつかあります。 これらはファイアウォールを動かすためには必要ではありませんが、 セキュリティに猛烈にこだわるユーザは有効にしてかまいません。

`options TCP_DROP_SYNFIN`

  このオプションは SYN と FIN のフラグをもった TCP パケットを無視します。 これは マシンの TCP/IP スタックを識別するので `security/nmap` などのようなツールを妨げることができます。 しかし RFC1644 拡張のサポートに違反しています。 これは現在稼働している web サーバには推奨しません。

いったんカーネルを再コンパイルしたら再起動しないで下さい。 希望的にも、 ファイアウォールの設置を完了するために一回だけ再起動する必要があります。

## ファイアウォールを搭載するように `/etc/rc.conf` を変更する

ファイアウォールを機能させるために、 `/etc/rc.conf` を若干変更する必要があります。 単純に以下の行を加えてください。

    firewall_enable="YES"
    firewall_script="/etc/firewall/fwrules"
    natd_enable="YES"
    natd_interface="tun0"
    natd_flags="-dynamic"

上記の設定に関するより詳しい情報は `/etc/defaults/rc.conf` を参照した上で、 &man.rc.conf.5; を読んで下さい。

## PPP のネットワークアドレス変換を無効にする

もしかすると既に PPP の組込みネットワークアドレス変換 (NAT) を利用しているかも知れません。 それを無効化しなければならない場合であるなら、 &man.natd.8; の例を使い、同じようにして下さい。

既に PPP の自動スタートのエントリのまとまりがあるなら、 多分こんなふうになっているでしょう:

    ppp_enable="YES"
    ppp_mode="auto"
    ppp_nat="YES"
    ppp_profile="profile"

もしそうなら、`/etc/rc.conf` に (訳注: `/etc/defaults/rc.conf` で定義されている `ppp_nat` の初期値は `YES` なので) `ppp_nat="NO"` を明示的に設定して無効にする必要があります。 また `/etc/ppp/ppp.conf` の中の `nat enable yes` または `alias enable yes` を削除する必要があるでしょう。

## ファイアウォールへのルールセット

さて、ほとんどのことをやりおわりました。 残る最後の仕事はファイアウォールのルールを定義することです。 それから再起動すると、ファイアウォールが立ち上がり稼働するはずです。 私はルールベースを定義する段階に達すると、 すべての人が若干異なる何かを求めているのだと実感しています。 私が努力してきたのは、 ほとんどのダイアルアップユーザに適合したルールセットを書くことです。 あなたは自分の必要のために以下のルールを土台として用いることによって 自分用のルールベースに変更することができます。 まず、閉じたファイアウォールの基礎から始めましょう。 望むのは初期状態ですべてを拒否することです。 それからあなたが本当に必要とすることだけのためにファイアウォールをあけましょう。 ルールはまず許可し、それから拒否するという順番であるべきです。 その前提はあなたの許可のための規則を付加するということで、 それから他の全ては拒否されます。:)

では `/etc/firewall` ディレクトリを作成しましょう。 ディレクトリをそこへ変更し、 `rc.conf` で規定した `fwrules` ファイルを編集します。 このファイル名を自分が望む任意のものに変更できるということに気をつけてください。 この手引きはファイル名の一例を与えるだけです。

それでは、ファイアウォールファイルの設定例を見てみましょう。 注釈も参考にしてください。

    # (/etc/rc.firewall にあるように) 参照を簡単にするためにファイアウォールの
    # コマンドを定義します。読みやすくするのに役立ちます。
    fwcmd="/sbin/ipfw"

    # 再読込みする前に現在のルールの消去を強制します。
    $fwcmd -f flush

    # トンネルインタフェースを通じてすべてのパケットを divert します。
    $fwcmd add divert natd all from any to any via tun0

    # 動的ルールを持つすべての接続を許可します。ただし、動的ルールを持たない
    # RST か ACK ビットがセットされている TCP 接続は拒否します。
    # 詳細は ipfw(8) をご覧ください。
    $fwcmd add check-state
    $fwcmd add deny tcp from any to any established

    # ローカルホスト内のすべての接続を許可します。
    $fwcmd add allow tcp from me to any out via lo0 setup keep-state
    $fwcmd add deny  tcp from me to any out via lo0
    $fwcmd add allow ip  from me to any out via lo0 keep-state

    # 自分が着手した、自ネットワークからのすべての接続を許可します。
    Allow all connections from my network card that I initiate
    $fwcmd add allow tcp from me to any out xmit any setup keep-state
    $fwcmd add deny  tcp from me to any
    $fwcmd add allow ip  from me to any out xmit any keep-state

    # 以下のサービスへ接続することをインターネット上のすべての人に許可します。
    # この例では sshd とウェブサーバへの接続を許可します。
    $fwcmd add allow tcp from any to me dst-port 22,80 in recv any setup keep-state

    # すべての ident パケットに RESET を送ります。
    $fwcmd add reset log tcp from any to me 113 in recv any

    # ICMP プロトコルを有効にします。自ホストを ping(8) に応答させたくなければ、
    # icmptypes から 8 を削除してください。
    $fwcmd add allow icmp from any to any icmptypes 0,3,8,11,12,13,14

    # 残りの全てを拒否します。
    $fwcmd add deny log ip from any to any

あなたは 22 番と 80 番のポートへの接続を許可し、 それ以外に試みられるすべての接続を記録する 十分に機能的なファイアウォールを手にしました。 では、あなたは安全に再起動することができて、 あなたのファイアウォールはうまく立ち上がるはずです。 もしこれに正しくないことを見つけたら、 もしくは任意の問題を経験したら、 さもなくばこのページを向上させるための任意の提案があるなら、 そのいずれにしても、どうか私に電子メールを下さい。

## 質問

組込みの &man.ppp.8; フィルタを使ってもよいのに、 なぜ &man.natd.8; と &man.ipfw.8 を使っているのですか?

正直に言うと、 組込みの `ppp` フィルタの代わりに `ipfw` と `natd` を使う決定的な理由はないと言わなければなりません。 いろいろな人と繰り返してきた議論より、 `ipfw` は確かに `ppp` フィルタよりもパワフルで設定に融通がきく一方、 それが機能的であるために作り上げたものはカスタマイズの容易さを 失っているということで意見の一致をみたようです。 私がそれを使う理由のひとつはユーザランドのプログラムでするよりも、 カーネルレベルで行うファイアウォールの方を好むからです。

limit 100 reached on entry 2800 のようなメッセージを受け取った後、 ログの中にそれ以上の拒否を全く見なくなりました。 ファイアウォールはまだ動作しているのでしょうか?

単にルールのログカウントが最大値に達したということを意味しています。 ルール自身はまだ機能していますが、 ログカウンタをリセットするまでそれ以上ログを記録しません。

`ipfw resetlog` コマンドにより、 ログカウンタをリセットすることができます。 また、この限界値を上述の `IPFIREWALL_VERBOSE_LIMIT` オプションで 変更することもできます。 さらに、この値は (カーネルを再構築して再起動せずに) net.inet.ip.fw.verbose_limit を &man.sysctl.8; で変更することができます。

もし内部で 192.168.0.0 の範囲のようなプライベートアドレスを使用しているなら、 `$fwcmd add deny all from any to 192.168.0.0:255.255.0.0 via tun0` のようなコマンドを 内部のマシンへ試みられる外部からの接続を防止するために ファイアウォールのルールに追加してもいいですか?

端的な答えは no です。 この問題に対するその理由は `natd` は tun0 デバイスを通して divert されている あらゆるもの に対してアドレス変換を行っているということです。 それが関係している限り、 入ってくるパケットは動的に割り当てられた IP アドレスに対してのみ話し、 内部ネットワークに対しては話さないのです。 ファイアウォール経由で外へ出て行くホストから あなたの内部ネットワーク上のホストを制限する `$fwcmd add deny all from 192.168.0.4:255.255.0.0 to any via tun0` のようなルールを追加することができるということにも気をつけてください。

何か間違っているに違いありません。 私はあなたの説明に文字通り従いましたが、 締め出されてしまいました。

このチュートリアルはあなたが userland-ppp を稼働していて、その結果 tun0 [&man.ppp.8; (またの名を user-ppp) で作られる最初の接続に相当します] インタフェース上で供給されたルールセットが動作していることを想定しています。 さらなる接続は tun1、tun2 などを用います。

&man.pppd.8; が ppp0 インタフェースを代わりに用いるということにも注意するすべきです。 よって &man.pppd.8; による接続を始めるなら ppp0 の代わりに tun0 を用いて下さい。 この変更を反映するファイアウォールのルールを 編集する早道は以下に示されています。 元のルールセットは `fwrules_tun0` としてバックアップされています。

    	    &prompt.user; cd /etc/firewall
    	    /etc/firewall&prompt.user; su
    	    Password:
    	    /etc/firewall&prompt.root; mv fwrules fwrules_tun0
    	    /etc/firewall&prompt.root; cat fwrules_tun0 | sed s/tun0/ppp0/g > fwrules

いったん接続が確立したら、 現在 &man.ppp.8; か &man.pppd.8; のどちらを利用しているかを知るために &man.ifconfig.8; の出力で検査することができます。 例として、&man.pppd.8; で作成された接続では、 このようなものが目にするでしょう (関係のあるものだけ示しています)。

    	    &prompt.user; ifconfig
    	    (skipped...)
    	    ppp0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1524
                        inet xxx.xxx.xxx.xxx --> xxx.xxx.xxx.xxx netmask 0xff000000
    	    (skipped...)

他方で、&man.ppp.8; (user-ppp) で作成された接続では、 あなたはこれに似たものを目にするはずです。

    	    &prompt.user; ifconfig
    	    (skipped...)
    	    ppp0: flags=8010<POINTOPOINT,MULTICAST> mtu 1500
    	    (skipped...)
    	    tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1524
    	            (IPv6 stuff skipped...)
                        inet xxx.xxx.xxx.xxx --> xxx.xxx.xxx.xxx netmask 0xffffff00
                        Opened by PID xxxxx
                (skipped...)