FreeBSDをルータにする
ルータとは
ルータ(Router)とは異なるネットワークを相互に接続するためのネットワーク機器です。OSI階層ではネットワーク層でネットワークパケットをルーチング(経路制御)します。データリンク層では隣接ノードや同一セグメントでしかデータの転送ができませんが、ルータはこれを組み合わせてネットワーク内のすべてのノードへのデータ転送を担当しています。受け取ったパケットをどのサブネットに送ればいいのかを判断してくれます。FreeBSDでは標準でこの機能を実現することができます。なお、想定しているネットワークはこの通りです。
NIC間でパケットを通す
FreeBSD箱にNICを複数つなぎ、それぞれにIPを割り当てても通常それだけではNIC間にパケットを通してくれません。FreeBSDでは/etc/rc.confにgateway_enable="YES"を追加し再起動することでNIC間にパケットを通してくれるようになります。再起動しなくてもsysctl net.inet.ip.forwarding=1で有効になります。ルータとしてはこれだけで機能します。ルータの内側のマシンはデフォルトゲートウェイをこのルータの内側のNICのIPにします。
ところでルータのような機器でtcpdumpを実行することはネットワークのパケットの流れが分析できて有用です。しかしながら、もしrootの権限を何らかの手段で手に入れられたときにbpfを組みこんだkernelを持っていると簡単にネットワークを覗かれてしまいます。外にさらされているルータではbpfをカーネルに組み込まないことをお勧めします。調べる必要があったら、その都度他のノートパソコンを当該ネットにつないでtcpdumpを使うことがいいでしょう。
#pseudo-device bpf #Berkeley packet filter
ファイアウォール(FireWall)を設定する
このままではルータの内外でパケットを素通しにしてしまいます。内側のネットワークが守られていません。FreeBSDでファイアウォールを実現することはIPFWやIPFilterとNATをそれぞれ組み合わせるのがポピュラーな様です。私はIPFWを利用しました。私の自宅のネットワークがここにある感じなので、IPアドレスの書き換えについてはDSLモデムに任せて、NATについては設定していません。インターネットに直接つながっているマシンではNATを使ってそのマシンからパケットが出ているように設定をしたらよいと思います。
カーネルを再構築する
まず、カーネルをIPFWが使えるように再構築します。
#options IPDIVERT #divert sockets(natを利用する場合有効にします)
options IPFIREWALL #firewall
options IPFIREWALL_VERBOSE #enable logging to syslogd(8)
options IPFIREWALL_VERBOSE_LIMIT=200 #limit verbosity
options IPFIREWALL_FORWARD #パケットをフォワードさせるときに有効にします
#options IPFIREWALL_DEFAULT_TO_ACCEPT #allow everything by default(これを有効にするとデフォルトはすべて通してしまいます)
/etc/rc.confの設定
/etc/rc.confに以下の設定を追加します。とりあえずFirewallのタイプは"open"とします。どのような定義がされているかは/etc/rc.firewallを読めばわかります。
firewall_enable="YES"
firewall_type="open"
もし、natdも有効にするのなら以下の設定も追加します。
natd_enable="YES"
natd_interface="xx0" <= グローバル側のインターフェイス
natd_flags="-f /etc/natd.conf"
FireWallのルール設定
このままでは"open"というFireWall設定になっています。これは外側からFireWallのマシンへは自由にアクセスできてしまいます。内側で公開しているWebサーバやメイルサーバに対してのみパケットの通過を許可することなどを勘案して、私は以下のFireWallのルールを設定し、/etc/ipfwとして保存しています。なお、ipfwのルールでは上側の設定が優先されます。
# Suck in the configuration variables.
if [ -z "${source_rc_confs_defined}" ]; then
if [ -r /etc/defaults/rc.conf ]; then
. /etc/defaults/rc.conf
source_rc_confs
elif [ -r /etc/rc.conf ]; then
. /etc/rc.conf
fi
fi
fwcmd="/sbin/ipfw -q"
############
# Flush out the list before we begin.
#
${fwcmd} -f flush
############
# set these to your outside interface network and netmask and ip
oif="rl0 #外側のインターフェース
onet="192.168.0.0" #外側のネットワーク
omask="255.255.255.0" #外側のネットマスク
oip="192.168.0.1" #外側のインターフェースに振っているIP
# set these to your inside interface network and netmask and ip
iif="rl1" #内側のインターフェース
inet="192.168.1.0" #内側のネットワーク
imask="255.255.255.0" #内側のネットマスク
iip="192.168.1.1" #内側のネットーマスクに振っているIP
mail_server="192.168.1.2" #メイルサーバのIP
www_server="192.168.1.3" #ウェブサーバのIP
ftp_server="192.168.1.3" #ftpサーバのIP
# Loop-Back
${fwcmd} add pass all from any to any via lo0
${fwcmd} add deny all from any to 127.0.0.0/8
${fwcmd} add deny ip from 127.0.0.0/8 to any
# Allow IP fragments to pass through
${fwcmd} add pass all from any to any frag
# Stop spoofing #詐称されたアドレスはだめです
${fwcmd} add deny all from ${inet}:${imask} to any in via ${oif}
${fwcmd} add deny all from ${onet}:${omask} to any in via ${iif}
# Stop RFC1918 nets on the outside interface プライベートアドレスを外に出さない
${fwcmd} add deny all from any to 10.0.0.0/8 via ${oif}
${fwcmd} add deny all from any to 172.16.0.0/12 via ${oif}
#${fwcmd} add pass all from 192.168.0.0/24 to any via ${oif}
# ↑これはうちではコメントアウト
# Stop draft-manning-dsua-03.txt (1 May 2000) nets (includes RESERVED-1,
# DHCP auto-configuration, NET-TEST, MULTICAST (class D), and class
E)
# on the outside interface
${fwcmd} add deny all from any to 0.0.0.0/8 via ${oif}
${fwcmd} add deny all from any to 169.254.0.0/16 via ${oif}
${fwcmd} add deny all from any to 192.0.2.0/24 via ${oif}
${fwcmd} add deny all from any to 224.0.0.0/4 via ${oif}
${fwcmd} add deny all from any to 240.0.0.0/4 via ${oif}
# Allow TCP through if setup succeeded #一度確立したtcpセッションは通します。
${fwcmd} add pass tcp from any to any established
# Allow IP fragments to pass through
${fwcmd} add pass all from any to any frag
# Allow setup to incoming SSH request SSHは通しますよ
${fwcmd} add pass tcp from any to ${oip} 22 setup
# Allow setup of incoming email #mailサーバへは通しますよ
${fwcmd} add pass tcp from any to ${mail_server} 25 setup
${fwcmd} add pass tcp from any to ${mail_server} 143 setup
# We don't reply IDENT Reqest
${fwcmd} add pass tcp from any to any 113
# Allow access to our WWW webサーバには通しますよ
${fwcmd} add pass tcp from any to ${www_server} 80 setup
# Reject&Log all setup of incoming connections from the outside
# でもその他外側からははだめ。
${fwcmd} add deny log tcp from any to any in via ${oif} setup
# Allow setup of any other TCP connection tcpのsetupは通しますよ。
${fwcmd} add pass tcp from any to any setup
#netbios samba 内側のサンバについて
${fwcmd} add pass udp from ${inet}:${imask} to ${iip} 137-139,445 via
${iif}
${fwcmd} add pass udp from ${iip} 137-139,445 to ${inet}:${imask} via
${iif}
# Allow DNS queries out in the world #DNSクエリを許可
${fwcmd} add pass udp from any to any 53
${fwcmd} add pass udp from any 53 to any
# Allow NTP queries out in the world #NTPクエリを許可
${fwcmd} add pass udp from any to any 123
${fwcmd} add pass udp from any 123 to any
# その他udpはだめ
${fwcmd} add deny log udp from any to any
# pingは返事をします
${fwcmd} add pass icmp from any to any via ${iif}
${fwcmd} add pass icmp from any to any out via ${oif} icmptypes 8
${fwcmd} add pass icmp from any to any in via ${oif} icmptypes 0
${fwcmd} add pass icmp from any to any in via ${oif} icmptypes 3
# その他のICMPはだめ
${fwcmd} add deny log icmp from any to any
以上で設定は終わりです。/etc/rc.confに
#firewall_type="OPEN"
firewall_script="/etc/ipfw.nat"
を追加します。
設定を有効化する
もちろん再起動してもいいのですが、これはシェルスクリプトなので、
# sh /etc/ipfw
としてもいいのですが、リモートから作業している場合切られてしまうときがあります。
# (sleep 3; sh /etc/ipfw) &
などとして切られてもコマンドが実行されるようにするのがよいでしょう。
