FreeBSD で Firewallを構築しよう (IPFW2 + NAT)

Firewall を構築する際に、専用機の導入や UNIX を用いて環境を構築するなどいろいろと考えられます。ここでは、FreeBSD で導入されている IPFW2 と nat を用いた Firewall 環境の構築を説明します。この IPFW2 は、アプリケーションレベルの Firewall ではなく、パケットフィルタリングを利用した Firewall です。

* カーネルの再構築

FreeBSD (4.9-RELEASE にてテスト) で、IPFW2 を利用するにはカーネルを再構築する必要があります。(Intel 86系 CPU の場合)

    # cd /sys/i386/conf
      (実際のディレクトリ:/usr/src/sys/i386/conf)
    # cp GENERIC MYKERNEL
    # edit MYKERNEL
       # 以下をコメントアウト(推奨)
       #options NFS                          #Network Filesystem
       #options NFS_ROOT                     #NFS usable as root device
       # 以下を追加
       options IPFW2
       options IPFIREWALL                    #firewall
       options IPFIREWALL_VERBOSE            #enable logging to syslogd(8)
       options IPFIREWALL_VERBOSE_LIMIT=5000 #limit verbosity
       options IPFIREWALL_DEFAULT_TO_ACCEPT  #allow everything by default
       options IPDIVERT                      #divert sockets
       # 以下は必須ではない
       options TCP_DROP_SYNFIN
 
    # /usr/sbin/config MYKERNEL
    # cd ../../compile/MYKERNEL
    # make depend
    # make
    # make install
    # reboot

必要なコマンドとライブラリを IPFW2 対応にする。IPFW2 に対応させる必要のあるモジュールは少ないため、make world;make kernel と FreeBSD の環境すべてを作り変える必要はありません。(もちろん、make world;make kernal を実行してもかまいません。)

    # dmesg -a | grep ipfw2
    ipfw2 initialized, ...
    # edit /etc/defalts/make.conf
       以下を追加
       IPFW2=true
 
    # cd /usr/src/sbin/ipfw
    # make
    # make install
    # cd /usr/src/lib/libalias
    # make
    # make install

* Firewall を有効にする

Firewall を有効にするために、いくつか設定ファイルを変更します。設定には、いくつかマシンの環境を知っている必要があります。その一覧を表にまとめておきます。

内部ネットワーク 192.168.0.0/24
内部ネットワークインターフェース rl0
IP Address (内部) 192.168.0.1
外部ネットワーク 192.168.100.0/24
外部ネットワークインターフェース dc0
IP Address (外部) 192.168.100.1

/etc/rc.conf ファイルの修正(追加)

# for gateway
gateway_enable="YES"
 
# inside interface
ifconfig_rl0="inet 192.168.0.1 netmask 255.255.255.0"
# outside interface
ifconfig_dc0="inet 192.168.100.1 netmask 255.255.255.0"
 
# for Firewall
firewall_enable="YES"
firewall_script="/etc/ipfw.conf"
 
# for NAT
natd_enable="YES"
natd_interface="dc0"
natd_flags="-f /etc/natd.conf" tcp_drop_synfin="YES"

/etc/natd.conf ファイルの作成

# ログの記録 (yes なら /var/log/alias.log に記録)
log no
# 起動時のメッセージ
verbose no
# 外部からの接続要求 (yes なら拒否)
deny_incoming no
# 拒否したパケットの記録
log_denied yes
log_facility security
# socket を利用し NAT の失敗を回避
use_sockets yes
# 可能な限り同じポート番号を利用
same_ports yes
# プライベートアドレスのみの変換
unregistered_only yes

* パケットフィルタリングのルールの設定(例)

/etc/rc.conf ファイルの中で firewall_script="/etc/ipfw.conf" と記述しているので、フィルタリングのルールを記述するファイルは /etc/ipfw.conf となります。

ルールの設定には、まず、ポリシーを作成する必要があります。下のポリシー一覧はあまりよいものではありませんが、まず第一にポリシーを作成しておく必要があることを忘れないでください。ポリシーは、きちんと計画に基づき出来るだけシンプルに作成するほうがよいでしょう。思いつきで変更したり複雑にしすぎるとセキュリティーホールを生む原因になります。許可するサービスの種類なども明確にしておくとよいでしょう。

  • ループバックの処理
  • 必ず拒否しなくてはならないサービスを拒否
  • 外部からアクセス可能なサービスを許可
  • 内側から外部へのサクセスで、禁止したサービス以外のアクセスを許可
  • 許可したサービス以外をすべて拒否
  • 拒否したサービスに対してアクセスがあった場合にログを取る

ルールの設定

#! /bin/sh
#
if [ "x$firewall_quiet" = "xYES" ]; then
    FWCMD="/sbin/ipfw -q"
else
    FWCMD="/sbin/ipfw"
fi
 
# 基本設定
ALLOW="allow"
DENY="deny log"  # log を付加してログをとる
IIF="rl0"
INET="192.168.0.0/24"
IIP="192.168.0.1"
OIF="dc0"
ONET="192.168.100.0/24"
OIP="192.168.100.1"
 
# ルールの初期化
${FWCMD} -q -f flush
 
# ループバックのルール
${FWCMD} add ${ALLOW} 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
 
# 断片化されたパケットの破棄
${FWCMD} add ${DENY} ip from any to any via ${OIF} frag
 
# アドレス詐称パケットの拒否
${FWCMD} add ${DENY} all from ${INET} to any in via ${OIF}
${FWCMD} add ${DENY} all from ${ONET} to any in via ${IIF}
 
# プライベートアドレス(RFC1918)へのアクセス拒否
${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 ${DENY} all from any to 192.168.0.0/16 via ${OIF}
 
# RESERVED-1, DHCP auto-config, NET-TEST, MULTICAST(Class D), Class E アドレスへのアクセス拒否
${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}
 
# NetBIOS を拒否
${FWCMD} add ${DENY} tcp from any 137-139,445 to any
${FWCMD} add ${DENY} udp from any 137-139,445 to any
${FWCMD} add ${DENY} tcp from any to any 137-139,445
${FWCMD} add ${DENY} udp from any to any 137-139,445
 
# NAT 用
${FWCMD} add divert natd all from any to any via ${OIF}
 
# プライベートアドレス(RFC1918)からのアクセス拒否
${FWCMD} add ${DENY} all from 10.0.0.0/8 to any via ${OIF}
${FWCMD} add ${DENY} all from 172.16.0.0/12 to any via ${OIF}
${FWCMD} add ${DENY} all from 192.168.0.0/16 to any via ${OIF}
 
# RESERVED-1, DHCP auto-config, NET-TEST, MULTICAST(Class D), Class E アドレスからのアクセス拒否
${FWCMD} add ${DENY} all from 0.0.0.0/8 to any via ${OIF}
${FWCMD} add ${DENY} all from 169.254.0.0/16 to any via ${OIF}
${FWCMD} add ${DENY} all from 192.0.2.0/24 to any via ${OIF}
${FWCMD} add ${DENY} all from 224.0.0.0/4 to any via ${OIF}
${FWCMD} add ${DENY} all from 240.0.0.0/4 to any via ${OIF}
 
# 既に確立されているパケットを許可
${FWCMD} add ${ALLOW} tcp from any to any established
 
# DNS によるアクセスの許可
${FWCMD} add ${ALLOW} udp from any to any 53
${FWCMD} add ${ALLOW} udp from any 53 to any
 
# 外部から SSH によるアクセスの許可
${FWCMD} add ${ALLOW} tcp from any to ${OIP} 22 setup
 
# 外部から SMTP によるアクセスの許可
${FWCMD} add ${ALLOW} tcp from any to ${OIP} 25 setup
# IDENT には返答しない
${FWCMD} add reset tcp from any to any 113
 
# 外部から POP3 によるアクセスの許可(POP Server を利用している場合)
${FWCMD} add ${ALLOW} tcp from any to ${OIP} 110 setup
 
# 外部からの HTTP によるアクセスの許可(Web Server を利用している場合)
${FWCMD} add ${ALLOW} tcp from any to ${OIP} 80 setup
${FWCMD} add ${ALLOW} tcp from any to ${OIP} 443 setup
 
# 外部から FTP によるアクセスの許可(FTP Server を利用している場合)
${FWCMD} add ${ALLOW} tcp from any to ${OIP} 20 setup
${FWCMD} add ${ALLOW} tcp from any to ${OIP} 21 setup
# PASV モードを利用する場合
${FWCMD} add ${ALLOW} tcp from any to ${OIP} 7000-7500
 
# 上記以外の外部からの TCPアクセスを拒否
${FWCMD} add ${DENY} tcp from any to any in via ${OIF} setup
 
# 上記以外の TCPアクセスの許可(つまり内部から外部への TCPアクセス)
${FWCMD} add ${ALLOW} tcp from any to any setup
##${FWCMD} add ${ALLOW} tcp from any to any out via ${OIF}
 
# NTP によるアクセスの許可
${FWCMD} add ${ALLOW} udp from any 123 to ${OIP}
${FWCMD} add ${ALLOW} udp from ${OIP} to any 123
 
# PING の許可
${FWCMD} add ${ALLOW} icmp from any to any via ${IIF}
${FWCMD} add ${ALLOW} icmp from any to any out via ${OIF} icmptypes 8
${FWCMD} add ${ALLOW} icmp from any to any in via ${OIF} icmptypes 0
 
# RFC2979
${FWCMD} add ${ALLOW} icmp from any to any in via ${OIF} icmptypes 3
 
# 上記以外の ICMP によるアクセスの拒否
${FWCMD} add ${DENY} icmp from any to any
 
# keep-state を使用した内部から外部への UDP 通信の許可
##${FWCMD} add ${ALLOW} udp from any to any keep-state out via ${OIP}
##${FWCMD} add check-state
 
# それ以外は拒否
##${FWCMD} add ${DENY} udp from any to any

ルールの記述が済んだら、ルールを設定確認します。

    # sh /etc/ipfw.conf
    ... エラーが出ていない確認する ...
    # ipfw -a list
    00100    3784     561548 allow ip from any to any via lo0
    ...
    65535   26088    5026210 deny ip from any to any

* ポートフォワード

外部から内部のマシンを直接参照することが出来ないため、外部から内部のマシンのあるサービスにアクセスしたい場合にはポートフォワードが必要になります。

たとえば、外部から内部のマシン 192.168.0.10 の TCPサービス 5963, 11923へアクセスしたい場合:

/etc/natd.conf ファイルへ追加

...
# プライベートアドレスのみの変換
unregistered_only yes
# ポートフォワード
redirect_port tcp 192.168.0.10:5963 5963
redirect_port tcp 192.168.0.10:11923 11923

/etc/ipfw.conf ファイルへ追加

...
# ポートフォワード
${IPFW} add ${ALLOW} tcp from any to 192.168.0.10 5963 setup
${IPFW} add ${ALLOW} tcp from any to 192.168.0.10 11923 setup
 
# 上記以外の外部からの TCPアクセスを拒否
${FWCMD} add ${DENY} tcp from any to any in via ${OIF} setup
 
...

二つのファイルを変更するのは面倒ですね。natd.conf を変更せずに ipfw.conf だけ書き換えれば済む方法ってないのかしら...でも、調べる時間がないので今回は省略...(^-^;)

変更後は、natd の再起動と ipfw の設定しなおしが必要です。簡単に済ますためにシステムをリーブートします。