<!--
     The FreeBSD Documentation Project
     The FreeBSD Japanese Documentation Project

     Original revision: 1.11
     $FreeBSD$
-->

<!--
訳:
倉品 rushani@bl.mmtr.or.jp
-->

<!DOCTYPE article PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [
<!ENTITY % man PUBLIC "-//FreeBSD//ENTITIES DocBook Manual Page Entities//EN">
%man;
]>

<article>
  <articleinfo>
    <title>FreeBSD によるダイアルアップ式防火壁の構築</title>

    <authorgroup>
      <author>
	<firstname>Marc</firstname>
	<surname>Silver</surname>

	<affiliation>
	  <address><email>marcs@draenor.org</email></address>
	</affiliation>
      </author>
    </authorgroup>

    <pubdate>$FreeBSD$</pubdate>

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

  <sect1 id="preface">
    <title>序文</title>
    
    <para>FreeBSD によるダイアルアップ式防火壁の構築</para>
    
    <para>
      この文書はあなたの ISP によって
      IP アドレスを動的に割り当てられた時、FreeBSD
      で防火壁をセットアップために要求される手順を扱うことをめざしたものです。
      この文書を可能な限り有益で正確なものにするために努力しているので、
      どうぞ意見や提案を
      <email>marcs@draenor.org</email>
      に送って下さい。</para>
   </sect1>

  <sect1 id="kernel">
    <title>カーネルオプション</title>
    
    <para>
      最初になすべきことは FreeBSD のカーネルを再コンパイルすることです。
      カーネルを再コンパイルする方法についてさらに情報が必要なら、
      <ulink URL="http://www.freebsd.org/handbook/kernelconfig.html">
      ハンドブックのカーネルのコンフィグレーションの節</ulink>
      から読み始めるのが最適でしょう。
      カーネルの中に以下のオプションをつけてコンパイルする必要があります: </para>

    <variablelist>
      <varlistentry>
	<term><literal>options IPFIREWALL</literal></term>

	<listitem>
	  <para>カーネルの防火壁のコードを有効にします。</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><literal>options IPFIREWALL_VERBOSE</literal></term>

	<listitem>
	  <para>システムの logger へ記録されたパケットを送ります。</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><literal>options
	    IPFIREWALL_VERBOSE_LIMIT=<replaceable>100</replaceable></literal></term>

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

      <varlistentry>
	<term><literal>options IPDIVERT</literal></term>

	<listitem>
	  <para><emphasis>divert</emphasis>ソケット
	  (後述) を有効にします。</para>
	</listitem>
      </varlistentry>
    </variablelist>

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

    <variablelist>
      <varlistentry>
	<term><literal>options TCP_DROP_SYNFIN</literal></term>

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

    <para>
      いったんカーネルを再コンパイルしたら再起動しないで下さい。
      希望的にも、
      防火壁の設置を完了するために一回だけ再起動する必要があります。</para>
  </sect1>

  <sect1 id="rcconf">
    <title>防火壁を搭載するように
      <filename>/etc/rc.conf</filename> を変更する</title>
    
    <para>
      防火壁について
      <filename>/etc/rc.conf</filename>
      をのことを述べるために、そこにいくつかの変更を行います。
      単純に以下の行を加えます:</para>
    
    <programlisting>firewall_enable="YES"
firewall_script="/etc/firewall/fwrules"
natd_enable="YES"
natd_interface="tun0"
natd_flags="-dynamic"</programlisting>

    <para>
      上でしたものに関する更なる情報は
      <filename>/etc/defaults/rc.conf</filename> を見て、
      &man.rc.conf.5; を読んで下さい。</para>
  </sect1>
  
  <sect1>
    <title>PPP のネットワークアドレス変換を無効にする</title>
    
    <para>
      もしかすると既に PPP の組込みネットワークアドレス変換
      (NAT) を利用しているかも知れません。
      それを無効化しなければならない場合であるなら、
      &man.natd.8; の例を使い、同じようにして下さい。</para>

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

    <programlisting>ppp_enable="YES"
ppp_mode="auto"
ppp_nat="YES"
ppp_profile="<replaceable>profile</replaceable>"</programlisting>

    <para>
      もしそうなら、
      <literal>ppp_nat="YES"</literal> の行を削除して下さい。
      また <filename>/etc/ppp/ppp.conf</filename> の中の
      <literal>nat enable yes</literal> または
      <literal>alias enable yes</literal> を削除する必要があるでしょう。</para>
  </sect1>

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

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

    <para>
      それでは、防火壁ファイルの見本を見てみましょう。
      そのすべてを詳細に説明します。</para>

    <programlisting># Firewall rules
# Written by Marc Silver (marcs@draenor.org)
# http://draenor.org/ipfw
# Freely distributable 


# (/etc/rc.firewall にあるように) 参照を簡単にするために防火壁のコマンドを定義します。
# 読みやすくするのに役立ちます。
fwcmd="/sbin/ipfw"

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

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

# 自分のネットワークとローカルホストからのデータをすべて許可します。
# 再起動する前に自分のネットワークカード (私のは fxp0 です) に変更するのを確認しましょう。:)
$fwcmd add allow ip from any to any via lo0
$fwcmd add allow ip from any to any via fxp0

# 自分が着手したすべての接続を許可します。
$fwcmd add allow tcp from any to any out xmit tun0 setup

# 接続がいったん作成されると、それを許可して開けておきます。
$fwcmd add allow tcp from any to any via tun0 established

# 以下のサービスへ接続することをインターネット上のすべての人に許可します。
# この例では人々は ssh と apache に接続してよいということを示しています。
$fwcmd add allow tcp from any to any 80 setup
$fwcmd add allow tcp from any to any 22 setup

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

# 規定されたサーバに対して *のみ* 外部 DNS の問い合わせを許可します。
$fwcmd add allow udp from any to <replaceable>x.x.x.x</replaceable> 53 out xmit tun0

# 応答とともに戻ってくることを許可します。:)
$fwcmd add allow udp from <replaceable>x.x.x.x</replaceable> 53 to any in recv tun0

# (ping と traceroute を動作させるために) ICMP を許可します。
# これを非許可にしたいと思うかもしれませんが、
# 需要を保ちつづけるには適していると感じています。
$fwcmd add 65435 allow icmp from any to any

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

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

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

      <qandaentry>
        <question>
	  <para>
	    <errorname>limit 100 reached on entry 2800</errorname>
	    のようなメッセージを受け取った後、
	    ログの中にそれ以上の拒否を全く見なくなりました。
	    防火壁はまだ動作しているのでしょうか?</para>
        </question>

	<answer>
	  <para>
	    単にルールのログカウントが最大値に達したということを意味しています。
	    ルール自身はまだ機能していますが、
	    ログカウンタをリセットするまでそれ以上ログを記録しません。
	    これは ipfw コマンドに <literal>resetlog</literal>
	    オプションを頭につけて実行するだけでできます。</para>
        </answer>
      </qandaentry>

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

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

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

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

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

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

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

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

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

	  <screen>	    &prompt.user; <userinput>ifconfig</userinput>
	    <emphasis>(skipped...)</emphasis>
	    ppp0: flags=<replaceable>8010&lt;POINTOPOINT,MULTICAST&gt; mtu 1500</replaceable>
	    <emphasis>(skipped...)</emphasis>
	    tun0: flags=<replaceable>8051&lt;UP,POINTOPOINT,RUNNING,MULTICAST&gt; mtu 1524</replaceable>
	            <emphasis>(IPv6 stuff skipped...)</emphasis>
                    inet <replaceable>xxx.xxx.xxx.xxx</replaceable> --&gt; <replaceable>xxx.xxx.xxx.xxx</replaceable> netmask <replaceable>0xffffff00</replaceable>
                    Opened by PID <replaceable>xxxxx</replaceable>
            <emphasis>(skipped...)</emphasis></screen>
	</answer>
      </qandaentry>
    </qandaset>
  </sect1>
</article>