« FreeBSD の省電力の設定(powerd を使う) | トップページ | RSA暗号のお話 »

パケットフィルタ (ipfw) の設定

 現在、ネットワークの主流は TCP/IP ということで異論はないと思いますが(^^;;、この TCP/IP 上を流れるデータ(パケット)のうち、必要なものだけを通し、不要なものを通さない、パケット選り分け(よりわけ)の役目を果たすのが、パケットフィルタです。

 一般には、パケットフィルタよりも、ファイアウォールという名前の方が、通りがいいようですが…。


 …それと、毎度のことながら、説明が長いので、注意してください(^^;;;


■ ipfw とは

 FreeBSD のパケットフィルタは、パケットの選り分けという基本的な機能のほかに、NAT帯域制御なども備える、高機能なものです。
 そして、このパケットフィルタを設定するプログラムとして、ipfw があります。

 一般に、パケットフィルタは、パケットの種類と IPアドレス、ポート番号の組み合わせにより、パケットを通す/通さないを決めますが、パケットフィルタ=ファイアウォールと普通に思われているように、外部からの不正アクセスを防止するのに、とても効果的です。

 しかし、パケットフィルタも決して万全ではないので、ほかのセキュリティがおろそかにならないよう、注意しましょう。


■ 事前準備

 本来なら、ネットワーク(特に、TCP/IP)の仕組みや、インターネット上で流行っているウイルスの振る舞いなどを勉強してから、パケットフィルタの構築に入るのがよいのですが、今回は、とりあえず「パケットフィルタを動かすこと」を目標にしてみます。

 基本的な注意ですが、パケットフィルタを設定するときは、必ず、コンソールからログインして行いましょう。
 ネットワーク経由でログインして作業をしていると、パケットフィルタの設定を間違った瞬間に、FreeBSD から閉め出されてしまいます(^^;


■ ipfw のインストール

 ipfw は、最初から FreeBSD の中に含まれているので、改めてインストールする必要はありません。

 ただし、パケットフィルタの機能は、カーネルモジュールという形で分離されているので、パケットフィルタを使えるようにするために、ちょっとしたワザが必要になります(後述)。


■ ipfw の設定

 FreeBSD には、/etc/rc.firewall という、パケットフィルタのサンプルが準備されていますが、今回は、まったくのオリジナルで、比較的単純、かつ、そこそこ役に立つパケットフィルタ(私が使っているもの(^^;;)を作ってみます。

 では、/etc/rc.fw の名前で、以下の内容のファイルを準備しましょう。
#!/bin/sh
#       /etc/rc.fw

  fw_cmd="/sbin/ipfw -q"
  fw_add="${fw_cmd} add"
  my_ifn="re0"
  my_net="192.168.1.0/24"

# flush old rules
  ${fw_cmd} -f flush

# rules on localhost
  ${fw_add} 100 allow     all  from any to any  via lo0
  ${fw_add} 200 deny      all  from any to 127.0.0.0/8
  ${fw_add} 300 deny      all  from 127.0.0.0/8 to any

# accelerator
  ${fw_add}     allow     tcp  from any to any  established
  ${fw_add}     allow     all  from any to any  frag
  ${fw_add}     check-state

# deny rules
  ${fw_add}     deny      tcp  from any 137-139,445 to any
  ${fw_add}     deny      tcp  from any to any 137-139,445
  ${fw_add}     deny      udp  from any 137-139,445 to any
  ${fw_add}     deny      udp  from any to any 137-139,445

# my network
  ${fw_add}     allow     udp  from ${my_net} to me 53   keep-state
  ${fw_add}     allow     udp  from ${my_net} to me 123  keep-state
  ${fw_add}     allow     tcp  from ${my_net} to me  setup
  ${fw_add}     allow     all  from ${my_net} to me
  ${fw_add}     allow     all  from me to ${my_net}

# outer network
  ${fw_add}     allow     udp  from ${my_net} to any 53   keep-state
  ${fw_add}     allow     udp  from ${my_net} to any 123  keep-state
  ${fw_add}     allow     tcp  from ${my_net} to any  setup

# icmp from/to outer network
  ${fw_add}     allow     icmp from any to any  in \
                               icmptypes 0,3,4,11,12
  ${fw_add}     allow     icmp from any to any  out \
                               icmptypes 3,4,8,11,12

# defalut to deny (with log)
  ${fw_add}     deny  log all  from any to any
● FreeBSD のパケットフィルタの基本

 まず最初に、FreeBSD のパケットフィルタの動作を簡単に説明しておくと…

 パケットフィルタは、「ipfw add」コマンドで、ルールを1つずつ追加して作ります。
 ルールは、「番号」を指定しないと、今ある一番大きいルールの番号+100 という「番号」が自動的に振られます。

 また、FreeBSD のパケットフィルタには、「first win」=「早い者勝ち」という原則があり、
  (1) 1つ1つのパケットに対して、「番号」の小さいルールから順番に比較を行う
  (2) パケットが、ルールの「条件」とマッチ(一致)したら、
   (2.1) それが「許可allow)」のルールならば、そのパケットを通過させて終了
   (2.2) それが「禁止deny)」のルールならば、そのパケットを廃棄して終了
  (3) マッチしなかったら、次の「番号」のルールに進む
 という処理を行っています。

 この、「早い者勝ち」という原則があるため、FreeBSD のパケットフィルタは、最初は範囲が限定されたルールから始めて、だんだんと範囲を広げていくようにすると、分かりやすいルールを書くことができます(^^)

 なお、パケットフィルタを使う人のポリシーの違いによって、上の例で「許可」しているパケットが、ほかでは「禁止」すべし!と言われている場合もあります。
 でも、どちらかが正しくて、もう一方が誤りとは決め付けられない場合もあるので、使いながら手直ししてみて下さい(^^;;


● ファイル内容の解説

01行目:#!/bin/sh
 このスクリプトを実行するプログラムを指定します
 ここでは、「/bin/sh」を指定しています。

04~07行目:
 sh のシェル変数を設定しています。
 シェル変数に設定した内容は、あとで「${シェル変数}」の形で呼び出すことができるので、ここでは、主に、キーボードを打つ回数を節約する目的で(^^;;、活用しています

04行目:fw_cmd="/sbin/ipfw -q"
 パケットフィルタを設定するためのコマンドを、シェル変数に設定します。
 「-q」は、ipfw を無口にするためのオプションです

05行目:fw_add="${fw_cmd} add"
 パケットフィルタのルール追加用に使うコマンドです。
 「${fw_cmd}」は「/sbin/ipfw -q」に展開されるので、結局、これは「/sbin/ipfw -q add」を設定したのと同じ効果があります

06行目:my_ifn="re0"
 FreeBSD のネットワークインターフェイスの名前を設定します。
 ただし、今回は(設定するルールが単純なので)使わずに済んでます(^^;

07行目:my_net="192.168.1.0/24"
 わが家の LAN の、ネットワークアドレスです。
 必ず、ご自分が使っているアドレスに書き換えて使って下さい(^^;;

10行目:${fw_cmd} -f flush
 ここから、パケットフィルタの設定が始まります。
 パケットフィルタに新しいルールを設定する前準備として、いまあるルールをすべて破棄します。

13~15行目:
 ローカルホスト関連の設定
 この3行は、決まり文句みたいなものなので、このまま覚えてしまいましょう(^^)
 ちなみに、この3行にだけ、ルール番号(100番~300番)が指定してあります

13行目:${fw_add} 100 allow all from any to any via lo0
 ループバックインターフェイスを通る(via lo0)パケットは、発信元・送信先に関わらず(from any to any)、全ての種類のパケット(all)を許可(allow)します。
 (ループバックインターフェイスには、PC 外部からの(PC 外部へも)パケットは流れないので、全てのパケットを信用します

14行目:${fw_add} 200 deny all from any to 127.0.0.0/8
 「送信先が自分自身(to 127.0.0.0/8)」を名乗るパケットがあれば、それは禁止(deny)します。

 パケットフィルタの原則が「早い者勝ち」であることを考えると、「すぐ上のルールにマッチしなかった」このパケットは、「外部から来たか、外部に出て行こうとしてる」パケットのはずで、このような「オレオレ詐欺パケット」は、捨ててしまうに限ります

15行目:${fw_add} 300 deny all from 127.0.0.0/8 to any
 「発信元が自分自身(from 127.0.0.0/8)」を名乗る「オレオレ詐欺パケット」も、上と同じ理由で捨てます

18~20行目:
 アクセラレータ の設定。
 パケットフィルタのルールは、「番号」の若い順から比較されるので、パケットの遅延とシステム負荷を減らす観点から、過去に「許可」の判定が出ているパケットは、早めに許可しておくのが得策です

18行目:${fw_add} allow tcp from any to any established
 TCP パケットのうち、すでに接続が確立している(established)ものを許可します

19行目:${fw_add} allow all from any to any frag
 大きすぎて、複数のパケットに分割された(frag)パケットを許可します

20行目:${fw_add} check-state
 動的ルールで許可された、同じ相手先(パケットの種類と IPアドレス、ポート番号が全て一致したときに限ります)との送受信を許可します。
 (詳細は、keep-state のところで(^^)

23~26行目:
 (ローカルホストを除く)全体的な禁止ルールの設定。
 ここでは、Windows が使う NetBIOS137,138/TCP,UDP)と ファイル共有139/TCP,UDP および 445/TCP,UDP)を禁止しています

23行目:${fw_add} deny tcp from any 137-139,445 to any
24行目:${fw_add} deny tcp from any to any 137-139,445
25行目:${fw_add} deny udp from any 137-139,445 to any
26行目:${fw_add} deny udp from any to any 137-139,445

29~33行目:
 LAN 内部を流れるパケットに関する設定です

29行目:${fw_add} allow udp from ${my_net} to me 53 keep-state
 FreeBSD 上で動いている、DNS サーバunbound)への接続を許可する設定。
 LAN 内部から(from ${my_net}) FreeBSD の 53番ポートへの(to me 53UDP 接続を受け付け、動的ルールに追加(keep-state)します。

 発信元と送信先が「合意」したあとで本番の通信が始まる TCP とは異なり、UDP は、送信元が受信先へパケットを一方的に送りつけて終わり、という通信方式ですが、もし、通信相手の IPアドレスとポート番号を記憶しておくことができれば、その相手だけを選んで、パケットのやりとりを許可することができます。

 この、通信相手の IPアドレスとポート番号、そしてパケットの種類を(ある意味、PC の搭載メモリ量と CPU パワーにものを言わせて、力まかせで(^^;;)記憶して、一定時間だけ通信を許可するしくみを、動的ルールと呼びます

30行目:${fw_add} allow udp from ${my_net} to me 123 keep-state
 FreeBSD 上で動いている、NTP サーバntpd)への接続を許可する設定。
 LAN 内部からの時刻(NTP)問い合わせを受け付け(udpto me 123)、動的ルールに追加(keep-state)します

31行目:${fw_add} allow tcp from ${my_net} to me setup
 LAN 内部から FreeBSD への、TCP 接続開始要求setup)を受け付けます。
 TCP の接続が確立したあとは、その接続が切断されるまで、前述の established のルールにより、発信元と接続先 (FreeBSD) 間の通信が許可されます

32行目:${fw_add} allow all from ${my_net} to me
 LAN 内の PC から FreeBSD に向けて発信されたパケットを全て許可します

33行目:${fw_add} allow all from me to ${my_net}
 FreeBSD から LAN 内部の PC に向けて発信するパケットを全て許可します(※)

※ ただし、FreeBSD で、外部向けのサービスを提供している場合(インターネット向けのWebサーバを立てている場合など)には、FreeBSD から LAN 内部に向けて発信するパケットは、「許可」ではなく「禁止」にしておいた方がよいかもしれません。
(万一、Webサーバのバグなどが原因で FreeBSD が乗っ取られてしまった場合、ここを拠点に、LAN 内部の PC に対して攻撃が行なわれる可能性があるので…)

 …ところで、気付いている方もいると思いますが、単に必要なパケットを通すのだけが目的なら、32行目と33行目があれば、29~30行目のルールはなくても、結果は変わりません(^^;;

 でも、このように、普段よく使われるルールを分けておくと、32行目や33行目にマッチしたパケットがあったときに、あれ、これはなんだろう、と異変に気付くきっかけになるので、このように一見無駄な設定をしています。

36~38行目:
 ローカルホストおよび LAN 以外… つまり、インターネットに関する設定。

 ここでの考え方として、TCP、UDP については、LAN 内部から発信されるパケットのみを許可します。
 インターネットから入ってくるパケットは(LAN 内部から発信されたパケットに対する応答を除き)、47行目より前のルールの中でマッチするものがないので、結局、47行目の「すべて禁止」ルールにより全て破棄されます

36行目:${fw_add} allow udp from ${my_net} to any 53 keep-state
 LAN 内の PC(ここでは、LAN 内の PC に、FreeBSD も含まれていることに注意(^-^;)が発信元となっている DNS 問い合わせを許可し、動的ルールに追加します。
 (動的ルールに合致したパケットは、前述の check-state ルールにより許可されます)

37行目:${fw_add} allow udp from ${my_net} to any 123 keep-state
 LAN 内の PC が発信元となっている、時刻(NTP)問い合わせを許可し、動的ルールに追加します

38行目:${fw_add} allow tcp from ${my_net} to any setup
 LAN 内の PC が発信元の、TCP 接続要求を許可します。
 (接続が確立した後の通信は、established ルールにより許可されます)

41~44行目:
 ICMP に関する設定。
 ただし、LAN 内部向けについては、32,33行目で、すでに全種類のパケットについて許可済みなので、ここでの設定は、インターネット用の設定ということになります。
 (このあたりが、パケットフィルタは難しい、と思われる原因なんでしょうね。 …慣れてしまえば、なんとかなるものですが(^^;

41行目:${fw_add} allow icmp from any to any in \
42行目:                icmptypes 0,3,4,11,12
 インターネットからやってくる(inICMP パケットのうち、icmptypes で指定したものを許可します

43行目:${fw_add} allow icmp from any to any out \
44行目:                icmptypes 3,4,8,11,12
 インターネットへ出て行く(outICMP パケットのうち、icmptypes で指定したものを許可します

 ここで、icmptypes の後ろの数字は、それぞれ
   0番:エコー応答(Echo Reply) … ping に対する応答
   3番:宛先へ到達不可(Destination Unreachable
   4番:通信速度の抑制要求(Source Quench
   8番:エコー要求(Echo Request) … ping による応答要求
  11番:パケットの寿命が尽きた(Time Exceeded
  12番:パケットのパラメータ異常(Parameter Problem
 に対応する ICMP のパケットを指します。

 ちなみに、41行目と43行目の最後の「 \ 」(FreeBSD 上では「 」に見えます)は、/bin/sh のコマンドを1行で書ききれなかったときに、次の行に続くということを表す「決まりごと」です(^^)

47行目:${fw_add} deny log all from any to any
 あらゆるパケット(all from any to any)を廃棄します。
 また、それらのパケットについての情報を、ログ(log)に残します(ファイル名は、/var/log/security です)。

● ファイルの確認

 パケットフィルタは、セキュリティ上、とても重要な設定なので、作成した /etc/rc.fw および関連するファイルが、適切なパーミッションを持っていることを確認しておきます。
 (パケットフィルタの設定が、誰にでも書き換え可能になっていたら… やっぱり、危ないですよね(^^;;
 《 "/etc/rc…"というパス名で始まるファイルの、詳細情報を表示 》
$ ls -dl /etc/rc*[Enter]
-rw-r--r--  1 root  wheel   3753 May  1 15:56 /etc/rc
-rw-r--r--  1 root  wheel   4611 May  1 15:56 /etc/rc.bsdextended
-rw-r--r--  1 root  wheel    568 Aug  6 21:15 /etc/rc.conf ← FreeBSD のシステム設定ファイル
drwxr-xr-x  2 root  wheel   2560 Jun 22 03:49 /etc/rc.d
-rw-r--r--  1 root  wheel  13732 May  1 15:56 /etc/rc.firewall
-rw-r--r--  1 root  wheel   9473 May  1 15:56 /etc/rc.firewall6
-rw-r--r--  1 root  wheel   1598 Aug 12 21:29 /etc/rc.fw ← パケットフィルタの設定ファイル
-rw-r--r--  1 root  wheel  11418 May  1 15:56 /etc/rc.initdiskless
-rw-r--r--  1 root  wheel    114 Aug  6 21:15 /etc/rc.local
-rwxr-xr-x  1 root  wheel   2322 May  1 15:56 /etc/rc.resume
-rw-r--r--  1 root  wheel   5790 May  1 15:56 /etc/rc.sendmail
-rw-r--r--  1 root  wheel   3311 May  1 15:56 /etc/rc.shutdown
-rw-r--r--  1 root  wheel  36048 May  1 15:56 /etc/rc.subr
-rwxr-xr-x  1 root  wheel   2291 May  1 15:56 /etc/rc.suspend
$  
 /etc/rc.conf と、/etc/rc.fw が、「-rw-r--r--」、「root wheel」と表示されていれば、合格です(^^)


■ パケットフィルタの有効化

 パケットフィルタの設定ファイルが準備できたら、パケットフィルタを有効化する設定を行います。

 /etc/rc.conf に、次の3行を追加し、
 firewall_enable="YES"
 firewall_logging="YES"
 firewall_script="/etc/rc.fw"
 FreeBSD を一度、再起動します。
 (firewall_enable="YES" の設定で、FreeBSD の起動時に「ipfw.ko」という名前のカーネルモジュールが呼び出され、パケットフィルタが使えるようになります)
 《 FreeBSD を再起動する 》
# reboot[Enter]
 ● パケットフィルタの動作確認

 FreeBSD が再起動したら、パケットフィルタがきちんと設定されているか、確認します。
 《 パケットフィルタのルールを表示する 》
# ipfw list[Enter]
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 allow tcp from any to any established
00500 allow ip from any to any frag
00600 check-state
00700 deny tcp from any 137-139,445 to any
00800 deny tcp from any to any dst-port 137-139,445
00900 deny udp from any 137-139,445 to any
01000 deny udp from any to any dst-port 137-139,445
01100 allow udp from 192.168.1.0/24 to me dst-port 53 keep-state
01200 allow udp from 192.168.1.0/24 to me dst-port 123 keep-state
01300 allow tcp from 192.168.1.0/24 to me setup
01400 allow ip from 192.168.1.0/24 to me
01500 allow ip from me to 192.168.1.0/24
01600 allow udp from 192.168.1.0/24 to any dst-port 53 keep-state
01700 allow udp from 192.168.1.0/24 to any dst-port 123 keep-state
01800 allow tcp from 192.168.1.0/24 to any setup
01900 allow icmp from any to any in icmptypes 0,3,4,11,12
02000 allow icmp from any to any out icmptypes 3,4,8,11,12
02100 deny log ip from any to any
65535 deny ip from any to any
#  
 /etc/rc.fw で設定したものと、用語が多少違ってはいますが (allip と表示されていたり、dst-port が勝手に追加されているなど)、覚えのあるルールが全て表示されていれば、OK です。
65535番のルールは、ipfw -f flush でも消えないデフォルトのルールなので、気にしなくて OK です(^^;

 もし、間違いを見つけたら、/etc/rc.fw を修正した後、今度は、
 《 sh に /etc/rc.fw を読み込ませて実行させる 》
# sh /etc/rc.fw[Enter]
#  
 で、パケットフィルタのルールを書き換えることができます


 ここまで、うまくいっていれば、今度は ssh を使ってネットワーク経由で接続した後、パケットフィルタの働きぶりを見てみましよう。
 《 パケットフィルタのパケット情報をあわせて表示する 》
# ipfw -a list[Enter]
00100  36  3474 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 692 63917 allow tcp from any to any established
00500   0     0 allow ip from any to any frag
00600   0     0 check-state
00700   0     0 deny tcp from any 137-139,445 to any
00800   0     0 deny tcp from any to any dst-port 137-139,445
00900  17  2000 deny udp from any 137-139,445 to any
01000   0     0 deny udp from any to any dst-port 137-139,445
01100   0     0 allow udp from 192.168.1.0/24 to me dst-port 53 keep-state
01200   0     0 allow udp from 192.168.1.0/24 to me dst-port 123 keep-state
01300   1    48 allow tcp from 192.168.1.0/24 to me setup
01400   0     0 allow ip from 192.168.1.0/24 to me
01500   0     0 allow ip from me to 192.168.1.0/24
01600  26  3879 allow udp from 192.168.1.0/24 to any dst-port 53 keep-state
01700 100  7600 allow udp from 192.168.1.0/24 to any dst-port 123 keep-state
01800   0     0 allow tcp from 192.168.1.0/24 to any setup
01900   0     0 allow icmp from any to any in icmptypes 0,3,4,11,12
02000   0     0 allow icmp from any to any out icmptypes 3,4,8,11,12
02100   0     0 deny ip from any to any
65535   0     0 deny ip from any to any
#  
 これは、ssh でログインして 10分ほど経ったときのものです。
 一応、解説しておくと、左端の数字がルール番号、2番目がルールにマッチしたパケット数、3番目が流れたパケットのバイト数で、

 00100番:FreeBSD 上のループバックインターフェイスを流れたパケット
      (中身は、ntpd から unbound への DNS 問い合わせと、その返答)
 00400番:接続が確立された後の TCP パケット
      (ssh を使った、Windows ~ FreeBSD 間の TCP 通信)
 00900番:Windows から発信された NetBIOS パケット
      (中身は、137/UDP と 138/UDP で、すべて拒否されました(^^;)
 01300番:LAN 内部からの TCP 接続要求パケット
      (Windows の ssh クライアントから発信されたもの)
 01600番:インターネットへの DNS 問い合わせ
      (unbound による DNS 問い合わせと、その返答)
 01700番:インターネットへの NTP 問い合わせ
      (ntpd による時刻問い合わせと、その返答)

 となります。

 ちなみに、00600番の check-state ルールにマッチしたパケットは、もとの動的ルール(1600番と1700番)のところに加算されています。

|

« FreeBSD の省電力の設定(powerd を使う) | トップページ | RSA暗号のお話 »

コメント

ipfwについての基本的な内容を分かりやすく記載して頂けており、とても助かりました。仕事上、急遽freebsdの知識を身につける必要に迫られ困っていたので本当にありがとうございます。

投稿: ty | 2009/10/08 19:00

 お役に立てて、なによりです(^^)

投稿: むらさき | 2009/10/11 15:20

Everything is very open with a clear explanation of the challenges. It was truly informative. Your website is very useful. Thank you for sharing!

投稿: https://cryptoparty.org | 2013/03/15 03:07

Every weekend i used to go to see this web site, because i want enjoyment, for the reason that this this website conations in fact nice funbny ddata too.

投稿: imprimante multifonction | 2013/10/30 19:54

Order Brand Amoxil, canada brand amoxil Usa brand amoxil, discount brand amoxil 52889, uk brand amoxil purchase brand amoxil, get brand amoxil canada brand amoxil, cheap brand amoxil order brand amoxil, buy brand amoxil buy brand amoxil!

投稿: cheap brand amoxil | 2013/11/26 10:46

Glimepiride 4mg Tablets, glimepiride 3 mg glimepiride price, order amaryl amaryl glimepiride 2mg (idledetrte1984.soup.io), amaryl glimepiride 2mg amaryl 2mg tablets, purchase glimepiride order amaryl (miiduu.com)!

投稿: glimepiride 1mg metformin 500mg | 2013/12/03 12:16

Apcalis Sx Oral Jelly, purchase apcalis sx apcalis-sx 20mg oral jelly, discount apcalis sx apcalis-sx 20mg oral Jelly, buy apcalis sx get apcalis sx (miiduu.com), canada apcalis sx apcalis sx oral jelly!

投稿: 52547 | 2014/01/12 05:11

Everything is very open with a clear explanation of the challenges.

It was truly informative. Your website is very useful.

Thank you for sharing!

投稿: SeniorPeopleMeet Login | 2016/03/30 04:45

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: パケットフィルタ (ipfw) の設定:

« FreeBSD の省電力の設定(powerd を使う) | トップページ | RSA暗号のお話 »