IPTABLESの設定方法



iptablesとは

 現在、自宅や仕事場でのインターネット接続は、ADSLやCATVなどの利用が増えています。その場合、ケーブルモデム、ルータなどを介してパソコンに繋ぎます。最近のルータなどのネットワーク機器には、標準でファイアウォール機能が搭載され、最初から基本的な設定は行われています。
 今回紹介する「iptables」は、高度なパケットフィルタリング機能を提供し、Linux機をルータやファイアウォールとして機能させることが出来ます。
 例えば、インターネットにはケーブルモデム、市販ルータで繋ぎ、その次にファイアウォールを設置することで、きめ細かいパケット制御が可能になります。
 また、外部に公開するサーバを設置するためのDMZ(De-Militarized Zone:不正アクセスを防ぐために設置されたファイア・ウォールの内側にあって、外部とも内部のLANとも切り離された区域)を設置することも出来ます。
 最近の市販ルータの大半には一般的な用途で使うには十分といえるファイアウォール機能が搭載されているので、単にインターネットに接続するだけならば、別にファイアウォールを設置する必要もないでしょう。
 ただし、市販ルータのファイアウォール設定も今回紹介する「iptables」の設定と似通っているモノが少なくない(ルータのOSにLinuxを使い、iptablesでファイアウォール機能を提供しているモノもあります)ので、ここでの説明を参考にすることが出来ると思います。
 Linuxカーネル2.4系よりも前は「ipchains」が使われていました。「ipchains」と「iptables」はパケットフィルタリングを行うと言う点で似ています。どちらもファイアウォールとしての必要条件を満たしていますが、「iptables」はさらに柔軟な方法できめ細かいパケット制御が可能になります。
 カーネル2.4系以降では、「ipchains」も「iptables」にも対応していますが、どちらかを選択する必要があり、基本的に共に使うことは出来ません。
 ファイアウォールとするLinux機で、KDEやGNOMEなどのGUIが使えるならば、それらGUI上でグラフィカルに「iptables」の設定を行うことも出来ます。
 「iptables」はRPMパッケージでも提供されていて、Red Hat系の最新は、

  RedHat-7.3 for i386 : iptables-1.2.8-8.72.3.i386.rpm
  RedHat-8.0 for i386 : iptables-1.2.8-8.80.2.i386.rpm
  RedHat-9  for i386 : iptables-1.2.7a-2.i386.rpm

となっているようです。

パケットフィルタリングとは

 「iptables」で行う「パケットフィルタリング(Packet Filtering)」とは、TCP/IPを用いたネットワークで、不正なアクセスを防止するために、ブリッジ、ルータ、ゲートウエイ、ファイア・ウォールなどが持っている機能の一つで、パケットの宛先アドレスや、送信元アドレスと宛先アドレスの組み合わせ、ポート番号などを調べて、通過させて良いパケットと阻止するパケットを区別する機能のことです。「スクリーニング(Screening)」とも呼ばれます。
という機能です。
 パケットの通過、または阻止を判断するためには、ネットワークの管理者がそのルールを設定しなければなりません。一般的には許可すべきアクセスを決め、それ以外は全て阻止するような設定にします。
 これらの設定をもとに「iptables」がパケットを監視して、通過・阻止などの制御を行います。

iptablesのための準備

 さて、iptablesを機能させるためには、幾つかの前準備が必要です。今回の説明では、下図のようなネットワークを想定します。
      ┌───────┐
      │インターネット│
      │  (外 部)  │
      └───┬───┘
      ┌───┴───┐
      │ケーブルモデム│
      └───┬───┘
      ┌───┴───┐
      │   ルータ   │
      └───┬───┘
     ┏━━━━┷━━━━┓
     ┃ ファイアウォール ┃
     ┗━━┯━━━┯━━┛
     ┌──┴──┐│ ┌──────┐
     │  L A N   │└─┤ Web サーバ │
     └─────┘  └──────┘
 今回は、Webサーバのみを公開するネットワークを想定しています。もちろんDNSサーバやMailサーバを追加する場合には、ここでの説明を参考にして下さい。
 まず、「iptables」がインストールされているか確認しましょう。suコマンドでrootユーザーになって、rpmコマンドで、
  # rpm -qa | grep iptables
  iptables-1.2.7a-2
などの表示があればインストールされています。もし、インストールされていない場合や、バージョンが古い場合は、最新のRPMパッケージをディストリビューションのサイトなどでダウンロードして、インストールまたはアップグレードしてください。
 「iptables」はカーネルに組み込まれて機能しますので、RPMパッケージを使わない場合は、カーネルの再構築が必要になります。カーネルの再構築は前回までのカーネルのアップグレードの方法を参考にして下さい。
 「iptables」を有効にするには、カーネルの環境設定で「Networking options」のサブ項目「Network packet filtering (replaces ipchains)」を有効にし、さらに「IP: Netfilter Configuration」を選び、そのサブ項目全てを有効またはモジュールに設定します。
 その後コンパイル、インストールを行い、再起動してください。
 つぎに、「iptables」が機能しているか確認しましょう。「iptables」に「-L」オプションを付けて実行すると、
  # /sbin/iptables -L
  Chain INPUT (policy ACCEPT) 
  target     prot opt source               destination 
  Chain FORWARD (policy ACCEPT) 
  target     prot opt source               destination 
  Chain OUTPUT (policy ACCEPT) 
  target     prot opt source               destination 
と表示されるはずです。「-L」オプションは、選択された「チェイン」にある全てのルールを一覧表示します。「チェイン」とは、パケットを検査するルールのリストのことです。詳しくは後で説明します。ここでは、上記のような表示がされるか確認してください。それ以外の表示ならば「iptables」が正しく機能していないので、設定などを確認してください。
 次に、ハードウェアを準備します。今回想定しているネットワークにファイアウォールを導入するには、ファイアウォールとなるLinux機に、ルータ(外部側)との接続のためのLANカード(ネットワーク・アダプタ)が1枚、WebサーバとLANとの接続のためのLANカードが1枚の合計2枚が最低必要になります。
 この場合、WebサーバをLAN側に設置します。外部からのWeb接続要求にはファイアウォールがLAN内のWebサーバへ転送するように設定します。
 もちろん、LANカードを3枚にしてWebサーバを内部LANから切り離すことも可能です。その場合も、外部からのWeb接続要求をファイアウォールがWebサーバが設置されているネットワーク・セグメント(ネットワークの範囲)へ転送するように設定します。LANカードを3枚にしたときも、ここでの説明を参考にして設定して下さい。
 たぶん最近のパソコンなら、最初からネットワーク・アダプタが一つ搭載されているでしょう。そこで、もう一つネットワーク・アダプタをPCIバスなどに追加してください。
 次に、それぞれのLANカードの設定を行いましょう。なお、設定は全てroot権限で行ってください。
 取り付けたLANカードの説明書や製造元のWebサイトなどで、そのLANカードで使用するドライバを確認してください。取り付けたLANカードが「NE2000」互換ならば「/lib/modules/2.4.25/kernel/drivers/net/」ディレクトリ(2.4.25の部分はカーネルのバージョンによって変わります)の「ne2k-pci.o」がドライバです。
 では、「/etc/modules.conf」ファイルをviなどのエディタで開いて下さい。そこに下記のような記述があると思います。
  alias eth0 3c59x
 この記述は「eth0」がインターフェース名で「3c59x」がドライバ・モジュール名を表しています。その行の下に、
  alias eth1 ne2k-pci
を追加してください。「eth1」が追加したLANカードのインターフェース名です。LANカードを追加しているので、数字の部分が「1」になります。次の「ne2k-pci」がそのドライバ・モジュール名です。
 これで追加したLANカードが「eth1」として認識されます。
 次に、それぞれのLANカード(インターフェース)の設定です。設定は、
 /etc/sysconfig/network-scripts/ifcfg-eth0
ファイルに記述します。このファイルは元から搭載されていたインターフェイスに対する設定なのでファイル名が「ifcfg-eth0」となっています。追加したインターフェイスに対する設定は、同じディレクトリでファイル名が「ifcfg-eth1」になります。「ifcfg-eth0」をコピーしてもいいでしょう。
 まずは、元から搭載されていたLANカードの設定を確認しましよう。
  DEVICE=eth0              インターフェイス名
  BOOTPROTO=static         DHCPサーバを使わないで設定する場合は、「static」
  BROADCAST=192.168.0.255  ブロードキャスト・アドレス
  IPADDR=192.168.0.10      IPアドレス
  NETMASK=255.255.255.0    サブネットマスク
  NETWORK=192.168.0.0      ネットワーク・アドレス
  ONBOOT=yes               起動時にこのインターフェイスを使うならば、「yes」
のようになっていると思います。2行目は、「static」の代わりに「none」になっているかもしれません。3行目から6行目までのアドレスは皆さんの環境に合わせてください。これらの他にも数行の設定が記述されていると思いますが、基本的にはこのよう になっているはずです。
 先ほどのネットワークで、アドレスを以下のようにします。
         ┌───┴───┐
         │   ルータ   │
         └───┬───┘
          (172.16.0.0/24)
       ┏━━━━━┷━━━━━┓
       ┃  ファイアウォール ┃
       ┗━━┯━━━━┯━━━┛
         (192.168.0.0/24)
       ┌──┴──┐ │ ┌──────┐
       │  L A N   │ └─┤ Web サーバ │
       └─────┘   └──────┘
 WebサーバはLAN内に設置され、他のパソコンと同じネットワークにあります。ルータとLANはネットワークセグメントを分け、ルータ側は「172.16.0.0/24」、LAN側を「192.168.0.0/24」とします。このネットワーク構成ではWebサーバとLANが同じセグメントなので、セキュリティの面ではあまり良くない構成ですが、部署内サーバなどあまりセキュリティに気を使わなくてもよいネットワークでは、このような構成になります。これら以外の構成もここでの説明を参考にして設定してください。
 ここでは、「eth0」をLAN側のインターフェイス、「eth1」をルータ側のインターフェイスとします。
 LAN側は「eth0」で、インターフェイスのIPアドレスを「192.168.0.10」とし、現在の「ifcfg-eth0」をそのまま使います。
 ルータ側は[eth1」で、インターフェイスのIPアドレスを「172.16.0.10」とします。設定ファイル「ifcfg-eth1」は「ifcfg-eth0」をコピーして、以下のように編集します。
  DEVICE=eth1
  BOOTPROTO=static
  BROADCAST=172.16.0.255
  IPADDR=172.16.0.10
  NETMASK=255.255.255.0
  NETWORK=172.16.0.0
  ONBOOT=yes
 1行目のインターフェイス名を「eth1」に変更し、3から6行目のアドレスを変更します。これら以外に「GATEWAY=***.***.***.***(***は任意のアドレス)」の行があれば、このアドレスもルータ側のゲートウェイアドレスに変更してください。
 設定が終わったら、
  # /etc/rc.d/init.d/network restart
を入力して、ネットワークシステムを再起動させてください。
 また設定された内容は、「ifconfig」コマンドで確認できます。「ifconfig」と入力しても「command not found」と表示される場合は「/sbin/ifconfig」と入力してみてください。
  # /sbin/ifconfig
 表示されるインターフェイスが「eth0」と「eth1」と「lo」で、設定内容が先ほどの編集内容と同じであるか確認してください。なお、「lo」は自分自身の仮想的なアドレスです。通常、デフォルトでIPアドレス「127.0.0.1」が使われているはずです。

iptablesの機能と設定

 「iptables」が提供する機能は多彩で大変有益な機能ではありますが、例えば、NAT(Network Address Translation)では通信途中でIPアドレスを書き換えてしまうわけで、十分にその機能を理解して設定していないと通信がまったく出来なくなるかもしれません。
 ここでは「iptables」の機能とその設定方法について説明します。
 「iptables」は、これまで説明してきたようなサーバ・アプリケーションのように設定ファイルを編集して設定を行うのではなく、コマンドラインからコマンドを打ち込んで設定を行います。
 説明は、コマンドラインに記述する要素(コマンドやオプションなど)毎に行います。たぶん、説明を読んでもその要素とコマンドとの関係や用法など、詳しく理解し辛いと思いますが、まずはそれぞれの要素について理解してください。詳しくはこの後、ルール設計を行った後にそのルールに沿った設定例を示しながら説明します。

 テーブル

 「テーブル」は、iptablesの機能である「アクセス制御(パケットフィルタリング)」と、「アドレス変換(NAT)」のどちらかを指定するために使用します。
 テーブルには、「filter」と、「nat」、「mangle」の3つのテーブルがあり、何も指定しないで設定を行った場合は、デフォルトテーブルである「filter」を指定していることになります。
 「filter」テーブルでは、アクセス制御を行うパケットフィルタリングで参照するルールを指定します。
 「nat」テーブルでは、アドレス変換のために、新しい接続を開くようなパケットに対してのルールを指定します。
 「mangle」テーブルは、特別なアドレス変換に使われるテーブルで、natテーブルでは処理できない一部のパケット(マルチキャスト・パケットやICMP(Internet Control Message Protocol):TCP/IPの機能を補助するための制御用プロトコル)パケットの一部など)の処理を行いたい場合に使用されるテーブルです。

 
チェイン

 「チェイン」は、それぞれのテーブルでのパケット検査のルールを設定します。例えば、「INPUT」では外部からそのホストへ入ってくるためのルールを設定します。
 「チェイン」は5種類あり、

チェイン 検査ルール
INPUT 入力(受信)パケットに対する制
OUTPUT 出力(送信)パケットに対する制御
FORWARD フォワードするパケットに対する制御
PREROUTING 受信時を変換するチェインに対する制御
POSTROUTING 送信時を変換するチェインに対する制御


です。また、「チェイン」はテーブル毎に使用できる「チェイン」が決まっていて、

テーブル チェイン
filter INPUT、FORWARD、OUTPUT
nat PREROUTING、OUTPUT、POSTROUTING
mangle INPUT、FORWARD、PREROUTING、OUTPUT、POSTROUTING


となっています。ただし、「mangle」テーブルの「INPUT」チェイン、「FORWARD」チェイン、「POSTROUTING」チェインは、Linuxカーネル2.4.18以降から組み込まれています。

 iptablesコマンドオプション

 オプションは、iptablesが実行する特定の動作を指定するために使われます。

オプション 機能
-A、--append 選択されたチェインに1つ以上のルールを追加。送信元や送信先の名前が1つ以上のアドレスに解決された場合は、可能なアドレスの組合せに対してルールが追加されます。
-D、--delete 選択されたチェインから1つ以上のルールを削除。選択されたチェインの中の番号を指定する方法と、マッチするルールを指定する方法がある。
-E、--rename-chain ユーザー定義のチェインを指定した名前に変更。このオプションは見かけの名前を変更するだけで、テーブルの構造には何も影響しません。
-F、--flush 選択されたチェインの内容を全消去。何も指定しなければテーブル内の全てのチェインの内容を全消去します。
-h 簡単なコマンド書式の説明表示。
-I、--insert 選択されたチェインにルール番号を指定して1つ以上のルールを挿入します。ルール番号が1の場合、または指定がない場合、そのルールはチェインの先頭に挿入されます。
-L、--list 選択されたチェインにある全てのルールを一覧表示。チェインが指定されない場合、全てのチェインのリストが一覧表示されます。ただし、「-v」オプションを指定しない限り、実際のルールそのものは表示されません。
-N、--new-chain 指定した名前でユーザー定義チェインを作成。同じ名前が既に存在してはいけません。
-P、--policy チェインのポリシーを指定したターゲットに設定します。ただし、ユーザー定義ではない組み込み済みチェインにしかポリシーは設定できません。また、組み込み済みチェインもユーザー定義チェインもポリシーのターゲットに設定することはできません。
-R、--replace 選択されたチェインでルールを置換。送信元や送信先の名前が1つ以上のアドレスに解決された場合、失敗します。なお、ルール番号は1から始まります。
-X、--delete-chain 指定したユーザー定義チェインを削除。そのチェインが参照されていない場合のみです。チェインを削除する前に、そのチェインを参照しているルールを削除か置換して下さい。引き数が与えられない場合、テーブルにあるチェインのうち組み込み済みチェインでないものが全て削除されます。
-Z、--zero すべてのチェインのパケットカウンタとバイトカウンタをゼロにします。クリアされる直前のカウンタを見るには、「-L」オプションと共に指定することもできます。


 この表で例えば「-L、--list」と記されている場合は、「-L」または「--list」とコマンドラインに記述することが出来ます。また、長いオプション名などは、他のオプション名などと区別できれば文字を省略して指定することもできます。
 一つのコマンドに指定できるオプションは、基本的に一つのオプションだけです。例外は、「-Z」オプションなどで「-L」オプションと共に使用されたりします。

 パラメータ

 パラメータは、チェイン内のルールの仕様を指定するために使います。

パラメータ 機能
-c、--set-counters PKTS BYTES insert, append, replace操作で使うと、パケットカウンタとバイトカウンタを初期化します。
-d、--destination [!] address[/mask] 送信先の指定に使います。「address」には、ホスト名か、「/mask」を指定したネットワーク・アドレス、IPアドレスのどれかを指定します。ただし、ホスト名はリモートのDNSへの問い合わせで解決するような名前を指定すること避けた方が良いでしょう。また「mask」は、「255.255.255.0」と「/24」のどちらの表記も使用できます。アドレス指定の前に「!」を付けると、そのアドレスを除外するという意味になります。「--dst」フラグはこのオプションの別名です。
[!] -f、--fragment 分割されたパケットの2番目以降のパケットやICMPタイプのパケットは、送信元・送信先ポートを知る方法がないので、送信元や送信先を指定するようなルールを適用することが出来ません。このオプションは、分割されたパケット(fragmented packet)のうち2番目以降のパケットだけを参照するルールであることを意味します。「-f」の前に「!」を付けると、分割されたパケットのうち最初のものか、分割されていないパケットだけにマッチします。
-i、--in-interface [!] name INPUT、FORWARD、PREROUTINGチェインに入るパケットを受信することになるインターフェース名を指定します。インターフェース名の前に「!」を付けると、そのインターフェースを除外するという意味になります。インターフェース名が「+」で終っている場 合は、その名前で始まる任意のインターフェース名にマッチします。例えば、「-i eth+」と指定して、eth0、eth1のインターフェイスがあれば、そ の両方に対しての指定になります。このオプションを省略すると、任意のインターフェース名を指定したことになります。
-j、--jump target ルールのターゲット、つまりパケットがマッチした場合にどうするかを指定します。「ターゲット」とは、パケットがマッチした時、何をするかを指定するものです。「ターゲット」は、ユーザー定義チェインでも、パケットの行方を即時に決定する特別な組み込み済みターゲットでも、拡張されたターゲットでも構いません。このパラメータをルールに指定しないと、ルールにマッチするパケットが流れても何も影響しません。ただ、ルールのカウンタが1つ加算されるだけです。
-o、--out-interface [!] name FORWARD、OUTPUT、POSTROUTINGチェインに入るパケットを送信することになるインターフェース名を指定します。「-i」の逆です。「-i」の時と同様に、インターフェース名の前に「!」を付けると、そのインターフェースを除外するという意味になり、インターフェース名が「+」で終っていると、その名前で始まる任意のインターフェース名にマッチします。また、このオプションが省略された場合は任意のインターフェース名にマッチします。
-p、--protocol [!] protocol ルールで使われるプロトコルや、チェックされるパケットのプロトコルを指定します。指定できるプロトコルは、「tcp」、「udp」、「icmp」、「all」のどれか一つ、「/etc/protocols」にあるプロトコル名が指定できます。(数値で も指定できますが、プロトコル名を使った方が理解しやすいでしょう)プロトコルに「all」を指定した場合は、全てのプロトコルとマッチします。このオプションが省略された時のデフォルトは「all」です。プロトコルの前に「!」を付けると、そのプロトコルを除外するという意味になります。
-s、--source [!] address[/mask] 送信元を指定します。「-d」の逆です。指定する「address」や「/mask」や「!」などは「-d」の概要を参照してください。「--src」フラグは、このオプションの別名です。


などのチェインがあります。

 「-j」パラメータで「ターゲットを指定」と説明しましたが、基本的な「ターゲット」には、

ターゲット 機能
ACCEPT パケットの通過を許可。
DROP パケットを破棄。
QUEUE カーネルがサポートしていれば、パケットをユーザー空間に渡す。
RETURN このチェインの検討を中止して、呼び出し元である以前のチェイン内の次のルールから検討を再開する。


があります。ただし、「QUEUE」、「RETURN」はあまり使うことがないでしょう。ユーザー定義の定義チェインの名前もターゲットとすることも出来ます。
 また、iptablesは拡張ターゲット・モジュールを使うことができ、標準的なディストリビューションには統一された拡張ターゲットが含まれている。よく使う拡張ターゲットには、

ターゲット 機能
DNAT NATテーブルのPREROUTING、OUTPUTチェイン、またはこれらのチェインから呼び出されるユーザー定義チェインのみで有効で、パケットの送信先アドレスを、この接続以降のパケットで修正して分からないようにして、ルールによるチェックを止めさせます。このターゲットには一つオプションがあります。

-to-destination ipaddr[-ipaddr][:port-port]

一つの新しい送信先IPアドレス、またはIPアドレスの範囲が指定できます。また、ルールで「-p tcp」または「-p udp」を指定している場合には、ポートの範囲を指定することもできます。ただし、ポートの範囲が指定されていない場合、送信先ポートは変更されません。複数の「--to-destination」オプションを指定することもできます。
SNAT NATテーブルのPOSTROUTINGチェインのみで有効でパケットの送信元アドレスを、この接続以降のパケットで修正して分からないようにして、ルールによるチェックを止めさせます。このターゲットには一つオプションがあります。

--to-source ipaddr[-ipaddr][:port-port]

一つの新しい送信元IPアドレス、またはIPアドレスの範囲が指定できます。また、ルールで「-p tcp」または「-p udp」を指定している場合には、ポートの範囲を指定することもできます。ポートの範囲を指定しない場合、「512」未満の送信元ポートは他の「512」未満のポートに、「512〜1023」までのポートは他の「1024」未満のポートに、それ以外 のポートは、「1024」以上のポートにマッピングされます。可能であればポートの変換は起こりません。複数の「--to-source」オプションを指定することもできます。
REDIRECT NATテーブル内のPREROUTING、OUTPUTチェイン、これらチェインから呼び出されるユーザー定義チェインでのみ有効で、パケットの送信先IPアドレスをマシン自身のIPアドレスにします。ローカルで生成されたパケットの場合は、「127.0.0.1」にマップされます。このターゲットには一つオプションがあります。

--to-ports port[-port]

ルールが「-p tcp」または「-p udp」を指定している場合にのみ有効で、使用される送信先ポート・ポート範囲・複数ポートを指定します。このオプションが指定されないと、送信先ポートは変更されません。
REJECT INPUT、FORWARD、OUTPUTチェインと、これらのチェインから呼ばれるユーザー定義チェインだけで有効で、パケットを拒否し、ICMPメッセージ(エラーパケット)を返信します。ICMPメッセージを送らなければ、「DROP」と同じで、TARGETを終了して、ルールの検討を終了します。


などがあります。これ以外にも拡張ターゲットがありますが、それらについてはmanコマンドで確認してください。
 iptablesではさらに、拡張ターゲットの他に、「拡張マッチング・モジュール」を使うことも出来ます。
 「拡張マッチング・モジュール」とは、「-p」パラメータなどでパラメータを指定することによって、さらに指定を拡張出来る機能です。
 「拡張マッチング・モジュール」は、「-p」または、「--protocol」パラメータで暗黙のうちに指定するか、 「-m」または、「--match」の後にモジュール名を続けて指定すると、ロードされます。
 「拡張マッチング・モジュール」には、それぞれのモジュールによって色々なオプションを指定することが出来ます。また、複数のモジュールを一行で指定することも可能です。

 拡張マッチング

拡張マッチング 機能
--destination-port [!] port[:port] 「--protocol tcp」が指定され場合にロードされ、送信先ポートまたはポート範囲を指定します。書式は「--source-port」と同じですので、上の説明を参照してください。
--icmp-type [!] typename 「--protocol icmp」が指定された場合 にロードされ、数値のICMPタイプ、または「iptables -p icmp -h」で、表示されるICMPタイプ名(echo-requestやecho-replyなど)を指定できます。
--mac-source [!] address PREROUTING、FORWARD、INPUTチェインに入るイーサーネットデバイスからのパケッで、送信元MACアドレスにマッチします。「address」は「XX:XX:XX:XX:XX:XX」形式指定してください。PREROUTING、FORWARD、INPUTチェインに入るイーサーネットデバイスからのパケッで、送信元MACアドレスにマッチします。「address」は「XX:XX:XX:XX:XX:XX」形式指定してください。
--source-port [!] port[:port] 「--protocol tcp」が指定され場合にロードされ、送信元ポートまたはポート範囲を指定します。サービス名か、ポート番号を指定できます。「port:port」という形式で、前後の番号を含む範囲を指定することも可能です。「port:port」形式で、最初のポートを省略すると「0」を指定したことになり、最後のポートを省略すると、「65535」を指定したことになります。「--sport」フラグは、このオプションの別名です。


などです。これら以外の「拡張マッチング」は、manコマンドで確認して下さい。
 ほとんどの拡張マッチングは、「!」を前に付けるとマッチングの意味を逆にできます。
 モジュールの詳細は、manコマンドで確認するか、コマンドでモジュールを指定した後で「-h」または「--help」を指定すれば表示されます。

 iptablesの機能と設定でいろいろ書きましたが、すべて理解できなくても大丈夫です。こういうものがあるという程度の理解で問題ありません。

ルールの設計

 「iptables」の設定の前に、そのLinux機に届いたパケット、送り出すパケットをどのように処理するか、ルールを決める必要があります。
 ルールは、NATのためのルールと、フィルタリングのためのルールの二つが必要です。ここでは、下図のようなネットワークを例にして、それぞれのルールを説明します。
   ┌───────┐       ┏━━━━━━━━┳━━━━━━┓
   │インターネット│       ┃  機  器  ┃ IPアドレス ┃
   │  (外 部)  │       ┣━━━━━━━━╋━━━━━━┫
   └───┬───┘       ┃ルータ      ┃172.16.0.1 ┃
   ┌───┴───┐       ┣━━━━━━━━╋━━━━━━┫
   │   ルータ   │       ┃ファイアウォール┃172.16.0.10 ┃
   └───┬───┘       ┃    外向き ┃      ┃
    (172.16.0.0/24)        ┣━━━━━━━━╋━━━━━━┫
       eth1           ┃ファイアウォール┃192.168.0.10┃
 ┏━━━━━┷━━━━━┓     ┃    内向き ┃      ┃
 ┃  ファイアウォール ┃     ┣━━━━━━━━╋━━━━━━┫
 ┗━━┯━━━━━┯━━┛     ┃  Webサーバ   ┃192.168.0.21┃
    │  eth0  │        ┣━━━━━━━━╋━━━━━━┫
   (192.168.0.0/24)        ┃メンテ用ホスト ┃192.168.0.11┃
 ┌──┴────┐│┌──────┐┗━━━━━━━━┻━━━━━━┛
 │  L A N  │└┤ Web サーバ │
 └───┬───┘ └──────┘
 ┌───┴───┐
 │メンテ用ホスト│
 └───────┘
 Webサーバ以外にも外部に公開するサーバがあれば、Webサーバの設定を参考にして設定してください。

NATルール

 「NAT」とは、「Network Address Translation」の略で、IPパケットの送信元や送信先のアドレスをパケットの中継時に書き換える機能のことです。
 一般的には、社内LANなどプライベート・アドレスで構築したIPネットワークのアドレス体系を変えることなく、インターネットに接続するためにルータやファイアウォールなどで使用されます。もちろん、外部(インターネット側)から内部(社内の公開Webサーバなど)に対してのアクセスもNATで処理出来ます。
 今回想定しているネットワークで、WebサーバについてのアクセスのNATルールを、

アクセス 変換前 −−> 変換後
外部からWebサーバへ 172.16.0.1 −−> 192.168.0.21


とします。また、LANについてのアクセスは、

アクセス 変換前 −−> 変換後
外部からLANへ 172.16.0.1 −−> 192.168.0.0/24
LANから外部へ 192.168.0.0/24 −−> 172.16.0.1


とします。

フィルタリングルール

 「パケットフィルタリング」は、ファイアウォールのもっとも基本的で重要な機能です。外部から内部に向けて届くIPパケットや、内部から外部に向けてのIPパケットをファイアウォールで遮断するか、転送するか、通過させるか、を設定します。
 一般的には、外部からの公開しているサーバに対してのアクセスや、内部LANからのアクセスに対する返答などに対しては通過を許可(または転送)し、内部からは外部からの公開サーバに対するアクセスの返答や、内部LANからのアクセスなどは通過を許可します。
 ただし、内部向け、外部向け共に必要なポートに対するアクセス以外は遮断する必要があります。2003年1月に韓国でインターネットを不通にさせてしまった「SQL Slammer」ワームは、「UDP 1434番ポート」を使って感染を広げました。
 今回想定しているネットワークでは、LAN内からネットサーフィンが出来るように基本的な接続は許可し、さらに以下のルールを適用します。

アクセス TCP/UDP ポート ルール
Webサーバへ TCP 80/HTTP 全て許可。
メンテ用ホストからWebサーバへ TCP 22/ssh 許可。
Webサーバからメンテ用ホストへ     icmp echo-requestとそれに対するecho-replyを許可。
メンテ用ホストからWebサーバへ     icmp echo-requestとそれに対するecho-replyを許可。
LAN内部から外部へ     icmp echo-requestとそれに対するecho-replyを許可。
Webサーバから外部へ     ファイアウォールを介したSYNパケットのみでは不許可。
WebサーバからLAN内部へ     必ずファイアウォールを中継させる。


とします。上記ルールに適さないパケットは全て不許可とします。

iptablesのNATの設定

 まずは、「ルールの設計」で決めた、外部からWebサーバへのアクセスについての設定を考えましょう。
 外部のホストから、インターネットに公開されたLAN内のWebサーバへのアクセスでは、ルータからファイアウォールに入った時点で送信パケットに宛先IPアドレスとして「172.16.0.1」が記載されています。
 この「172.16.0.1」をLAN内で有効なWebサーバのIPアドレス「192.168.0.21」に書き換えなければ、そのパケットはWebサーバに届きません。
 ちなみに、宛先(送信先)IPアドレスを「Destination Address」、送信元IPアドレス「Source Address」と呼びます。
 iptablesのnatテーブルは3つのチェインで構成されますが、外部からWebサーバへのアクセスは、「PREROUTING」チェインで設定します。PREROUTINGチェインでは、パケットが入ってきた場合に宛先IPアドレスを変換します。
 では、実際の設定コマンドです。
 # /sbin/iptables -t nat -A PREROUTING -d 172.16.0.1 -i eth1 -j DNAT --to 192.168.0.21
 それぞれのチェインやオプションなどは、

チェインやオプション 解説
-t nat natテーブルを指定。
-A PREROUTING 「-A」は追加オプションで、PREROUTINGチェインにこれ以降のルールを追加。
-d 172.16.0.1 「-d」は、Destination(送信先)アドレスの指定で、ここでは「172.16.0.1」を指定しています。
-i eth1 「-i」はパケットを受信することになるインターフェース名の指定で、ここでは「eth1」を指定しています。
-j DNAT 「-j」はルールのターゲットの指定で、ここでは「DNAT」、つまりパケットの送信先アドレスをこの接続以降のパケットで修正して分からないようにします。
--to 192.168.0.21 「--to」はターゲット「DNAT」のオプションで、ここでは変換後のIPアドレスを「192.168.0.21」にしています。


という意味です。つまり、上記コマンド1行では、
  「natテーブルのPREROUTINGチェインに、インターフェイスeth1に入ってきた
  宛先IPアドレス172.16.0.1を、DNATで192.168.0.21に変換するルールを付け加える。」
という設定になります。
 さらにプロトコルなどを指定してより詳しくNATさせることも可能です。先程のコマンドを、
 # /sbin/iptables -t nat -A PREROUTING -d 172.16.0.1 -i eth1
                                    -p tcp --dport 80 -j DNAT --to 192.168.0.21
とすると、「-p tcp」で、プロトコルを「tcp」に指定し、「--dport 80」で、宛先ポート番号を「80」番に指定しています。
 次に、このWebサーバに対する接続要求に対しての応答パケットについてですが、接続してきたパケットの送信元アドレスは変換させていないので、特にNATで設定する必要はありません。
 例えば、このWebサーバがMailサーバならばどうでしょう。Mailサーバでは、Mailサーバ側から外部のMailサーバなどに接続要求を出す必要があり、送信元がLAN内部のMailサーバですので、送信元IPアドレスを変換する必要があります。Mailサーバの実IPアドレスを「192.168.0.22」とした場合は、
 # /sbin/iptables -t nat -A POSTROUTING -s 192.168.0.22 -o eth1 
                      -p tcp -j SNAT --to 172.16.0.1
となります。この設定では、

チェインやオプション 解説
-t nat natテーブルを指定。
-A PREROUTING PREROUTINGチェインにこれ以降のルールを追加。
-s 192.168.0.22 「-s」はsource(送信元)アドレスの指定で、ここでは「192.168.0.22」を指定しています。
-p tcp 「-p」はプロトコルの指定で、ここでは「tcp」を指定しています。
-o eth1 「-o」はパケットを送信することになるインターフェース名の指定で、ここでは「eth1」を指定しています。
-j SNAT 「-j」はルールのターゲットの指定で、ここでは「SNAT」、つまりパケットの送信元アドレスをこの接続以降のパケットで修正して分からないようにします。
--to 172.16.0.1 「--to」はターゲット「SNAT」のオプションで、ここでは変換後のIPアドレスを「172.16.0.1」にしています。


となります。この設定の意味はもう分かりますね。
 このように、それぞれのサーバで起こり得る接続に対して、必要なnatテーブルとチェインなどを設定します。
 次に、LAN内からインターネット(外部)へのアクセスについては、
 # /sbin/iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth1 -j SNAT --to 172.16.0.1
とします。今回の場合、外部へのインターフェイスに割り当てられるIPアドレスが、静的に固定IPアドレスが割り当てられられているので「SNAT」を使っています。
 もし、外部へのインターフェイスに割り当てられるIPアドレスが動的に変化するならば、
 # /sbin/iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth1 -j MASQUERADE
とて、「MASQUERADE」ターゲットを使います。
 「MASQUERADE」ターゲットは、「SNAT」と似ていますが、インターフェースが停止した場合に、それまでの接続をクリアします。例えば、ダイアルアップでインターネットに接続している場合、外部向けインターフェイスのIPアドレスは接続するたびに変わってしまうので、この方法が用いられています。

 以上が基本的なNATの設定方法です。これらを組み合わせてネットワーク全体のIPアドレス変換を行わせます。
 ただし、これらコマンドをファイアウォールとしているLinux機が起動するたびに入力するのは面倒なので、実際に設定する場合はスクリプトファイルに記述し、実行します。スクリプトファイルの作成方法などは、パケットフィルタリングの説明の後にまとめて説明します。

パケットフィルタリング

 「パケットフィルタリング」は、簡単に言えば、ファイアウォール内でどのようなパケットを通過させたり、あるいは到達を許可または拒否させたりして、不必要な通信を遮断する機能です。
 最近流行しているウイルス(ワームなど)の中には、特定のポートを使って感染拡大するモノもあり、適切に「パケットフィルタリング」を行うことによって、LAN内部の安全性を高めることが出来ます。
 「パケットフィルタリング」は、iptablesの「filter」テーブルとテーブルに含まれる「FORWARD」、「INPUT」、「OUTPUT」チェインを使用して、IPアドレスやプロトコル、ポート、フラグメントなどや、送信先、送信元なのかによって通信に制限をかけます。
 まずは、これらチェインと流れるパケットの関係を見てみましょう。
      │                      Λ
   (パケット受信)                  │
      │                   (パケット送信)
      V                      │
 ┌────┴────┐   ┏━━━━┓   ┌────┴─────┐
 │  PREROUTING  ├─>─┨FORWARD ┠─>─┤   POSTROUTING  │
 │プレ・ルーティング│   ┃チェイン┃   │ポスト・ルーティング│
 └────┬────┘   ┗━━━━┛   └────┬─────┘
      V                      Λ
  ┏━━━┷━━━┓              ┏━━━┷━━━┓
  ┃INPUT チェイン┃              ┃OUTPUTチェイン┃
  ┗━━━┯━━━┛              ┗━━━┯━━━┛
      │      ┏━━━━━━━━━┓     │
      └────>─┨ローカル・プロセス┠─>───┘
             ┗━━━━━━━━━┛
 上図のように、ネットワーク・インターフェイスから入った(受信した)パケットは、プレ・ルーティング処理を受けた後に、ファイアウォール内部での処理の必要が無く、他のホストに転送されるべきパケットは、「FORWARD」チェインへ送られ、ポスト・ルーテング処理の後に目的のホストへ向けて送信されます。
 プレ・ルーティング処理を受けた後に、ファイアウォール内部での処理が必要と判断されたパケットは、「INPUT」チェインへ送られ、ファイアウォール内部でのローカル・プロセスで処理された後に、「OUTPUT」チェインへ送られて、ポスト・ルーテング処理を経て目的のホストに向けて送信されます。
 また、「FORWARD」と「INPUT」チェインでは、不必要と設定されたパケットは破棄(DROP)されます。

 以上のようにパケットを処理することによって、ネットワークの安全性を高めることが出来ます。

フィルタリングの設定

 さて、フィルタリングの設定ですが、前回想定したフィルタリング・ルールを例にして説明します。
 フィルタリングの設定は、まず「基本ポリシー」を設定します。その後、それぞれ個別のパケットに関するフィルタリング・ルールを設定します。
 フィルタリングに到達したパケットは、まず基本ポリシー以外のルールに関して順に比較されていきます。その途中でいずれかのルールに適合した場合、そのルールが適用されます。もし最後まで適合するルールがなければ、基本ポリシーが適用されます。
 ここで注意が必要なのは、適合するルールに当たるとそのルールが適用されるため、それ以外のルールに適合するかのチェックは行われません。言いかえれば、あるパケットに適合するルールを二つ以上設定しても、最初に適合したルールしか適用されません。
 また、iptablesでは、1つのコネクションを1つのルールだけで許可することが出来ません。
 例えば、TCPプロトコルでは「3Way Handshake(3ウェイ・ハンドシェーク)」と呼ばれるコネクションの開始方法を用いています。このような場合には、それぞれのパケットに対する設定を個別に設定する必要があります。詳しくは、以下の設定方法の説明を参考にして下さい。

 FORWARDチェイン

 まずは、前回決めたルールに従うと、個々のルールに適合しないパケットの通信は全て許可しない方針なので、その様なパケットは破棄します。
 # /sbin/iptables -t filter -P FORWARD DROP
または、
 # /sbin/iptables -P FORWARD DROP
と設定します。テーブルのデフォルトは、「filter」なので上記のように「-t」によるテーブルの指定は省略可能です。
 それぞれの項目の内容は、

チェインやオプション 解説
-P FORWARD DROP 「-P」は、チェインの基本ポリシーを指定したターゲットに設定します。ここでは、FORWARDチェインに対して、「DROP」ターゲットを指定しています。


 ここでは、FORWARDチェインの基本ポリシーを「パケット破棄」に設定しています。
 もし、FORWARDチェインに関する設定がこれだけだと、INPUTチェインに回らないパケットは全て破棄されてしまいます。

 次に、許可させるパケットに関する設定をしましょう。

 許可されるパケットで、LAN内に設置された公開Webサーバに対してインターネット(外部)側からの接続があるのでそのパケットに対して設定しましょう。
 ただし、Webサーバに対する接続は、先に説明したようにTCPプロトコルを用いますので、3Way Handshakeのそれぞれのパケットに対して設定が必要です。
 TCP 3Way Handshakeでは、
   ┌───┐    ┏━━━━━━━━┓    ┌───┐
   │   ├─>──┨1:SYN パケット┠──>─┤   │
   │ ク │    ┗━━━━━━━━┛    │   │
   │ ラ │   ┏━━━━━━━━━━┓   │ サ │
   │ イ ├─<─┨2:SYN+ACK パケット┠─<─┤ | │
   │ ア │   ┗━━━━━━━━━━┛   │ バ │
   │ ン │    ┏━━━━━━━━┓    │ | │
   │ ト ├─>──┨3:ACK パケット┠──<─┤   │
   │   │    ┗━━━━━━━━┛    │   │
   └───┘                  └───┘
と、3つのパケットを送受信します。
 「1」で、コネクション開始要求を示す「SYN」フラッグをセットしたパケットがクライアントからサーバに対して送られます。
 「2」で、コネクション開始要求(SYN)と、確認応答(ACK)を示す「SYN+ACK」フラッグをセットしたパケットをサーバからクライアントに送ります。
 「3」で、確認応答を示す「ACK」フラッグをセットしたパケットを送信することによってコネクションが確立します。
 ちなみに、TCPパケットのフラグには、「SYN」や「ACK」以外に、「FIN」「RST」などがあります。
 「1」と「3」は、クライアントから送られてくるTCPパケットで、HTTPアクセスなのでポート番号は「80」番となっているはずです。だから設定は、
 # /sbin/iptables -A FORWARD -p tcp --dport 80 -d 192.168.0.21 -j ACCEPT
となるはずです。
 それぞれの項目の内容は、

チェインやオプション 解説
-A FORWARD 「-A」で、FORWARDチェインに以降の設定を追加します。
-p tcp 「-p」で、適合プロトコルをTCPに設定しています。
-dport 80 「-dport」で、宛先ポートを80(HTTP)に設定しています。
-d 192.168.0.21 「-d」で、送信先IPアドレスを192.168.0.21に設定しています。
-j ACCEPT 「-j」で、ターゲットをACCEPT(パケットの通過許可)に設定しています。


です。
 つまり上記の設定では、「プロトコルが「TCP」で、ポート番号が「80」番、送信先IPアドレスが「192.168.0.21」のパケットを、宛先IPアドレスのホスト(ここではWebサーバ)に転送します。」という設定です。
 次は「2」の「SYN+ACK」パケットに対する設定です。この設定は多少複雑になります。
 # /sbin/iptables -A FORWARD -p tcp ! --syn 
    -m state --state ESTABLISHED --sport 80 -s 192.168.0.21 -j ACCEPT
となります。ここでは今まで説明してない新しい二つのマッチングが使われています。
 一つ目は「! --syn」。このマッチングは、「-p tcp」パラメータと共に使用します。「--syn」で、「SYN、RST、ACKフラグをチェックし、SYNだけがセットされているTCPパケット」と言う意味です。
 ここでは、先頭に「!」がついているのでその逆の意味、「SYN、RST、ACKフラグをチェックし、SYNだけがセットされていないTCPパケット」となります。
 通常、Webサーバ内部からは、SYNフラッグだけがセットされたTCPパケットが送信されることはありません。基本的に、「SYNフラッグだけがセットされたTCPパケット」は接続要求パケットだからで、Webサーバから接続要求が送られることはないからです。
 もし、そういうパケットが送られているとするとWebサーバが乗っ取られた可能性があります。
 二つ目は、「-m state --state ESTABLISHED」です。「-m」で拡張されたパケットマッチングモジュールをロードします。「state」以外のマッチングモジュールはmanページ(「man iptables」コマンド)で調べてください。
 ここでは「state」モジュールをロードしています。「state」モジュールでは、パケットについての接続追跡状態を知ることが出来ます。
 「--state ESTABLISHED」では、「過去双方向にパケットがやり取りされた接続に属するパケット」を指定します。「ESTABLISHED」の他には、

  INVALID :既知の接続と関係していないパケット。
  NEW   :新しい接続を開始した時のパケットか、双方向にはパケットが
       やり取りされていない接続に属するパケット。
  RELATED :新しい接続を開始した時のパケットで、FTPデータ転送やICMPエ
       ラーのように既存の接続に関係しているパケット。

などがあります。
では、その他のオプションなどと共に説明しましょう。

チェインやオプション 解説
-A FORWARD 「-A」で、FORWARDチェインに以降の設定を追加します。
-p tcp 「-p」で、適合プロトコルをTCPに設定しています。
! --syn 「! --syn」で、synフラッグだけをセットしたパケット以外に設定しています。
-m state 「-m」で、「state」パケットマッチングモジュールをロードします。
--state ESTABLISHED 「--state ESTABLISHED」で、過去双方向にパケットがやり取りされた接続に属するパケットに設定しています。
--sport 80 「--sport」で、送信元ポートを80(HTTP)に設定しています。
-d 192.168.0.21 「-d」で、送信先IPアドレスを192.168.0.21に設定しています。
-j ACCEPT 「-j」で、ターゲットをACCEPT(パケットの通過許可)に設定しています。


です。
 つまり上記の設定では、「プロトコルが「TCP」で、ポート番号が「80」番、送信元IPアドレスが「192.168.0.21」、「syn」フラッグだけをセットしていないパケットを、宛先IPアドレスのホストに転送します。」という設定になります。
 ここでは、Webサーバを例にして説明しましたが、ここでの説明とiptableのmanページなどを参考にして、他のMailサーバなどの設定も可能です。
 次に、「メンテ用ホストからWebサーバへssh接続の許可」です。この設定は、
 # /sbin/iptables -A FORWARD -p tcp -s 192.168.0.11 --dport 22 -d 192.168.0.21 -j ACCEPT
となります。
 先に説明した「クライアントからWebサーバ向けのhttp接続」との違いは、「-s 192.168.0.11」が追加されている部分と、「--dport」で指定されているポート番号が「22」になっている部分です。
 「-s 192.168.0.11」は前回も説明していますが、「送信元アドレス」を指定するモノで、「192.168.0.11」がメンテ用ホストのIPアドレスです。もし、LAN内の全てのホストからssh接続を許可するのであれば、「-s 192.168.0.0/24」とネットワークアドレスを指定することで可能になります。
 「--dport 22」はポート番号での指定で、22番がssh通信を示しています。
 次に、「Webサーバからメンテ用ホストへの接続の許可」ですが、
  # /sbin/iptables -A FORWARD -p tcp ! --syn --sport 22
                              -s 192.168.0.21 -d 192.168.0.11 -j ACCEPT
となります。
 これまた前回との相違は、「-d 192.168.0.11」の追加と、「--sport 22」の変更があります。これらについてはもう説明の必要はありませんね。
 もう一つの違いは、「-m state --state ESTABLISHED」の指定が無くなっていることです。この指定は、「過去の双方向にパケットがやり取りされた接続に属するパケットの指定」でした。今回は送信元が決まっているので、パケットのやり取りを監視する必要がないのでこの指定が無くなっています。
 以上の設定を行うことによって、メンテ用ホストからだけ、ssh接続が可能となります。
 次は、ICMPに関する設定を行います。
 ICMPプロトコルは「TCP/IPプロトコルで、その機能を補助するための制御用プロトコル」です。
 最もよく使うのが「ping」コマンドでしょう。「ping」コマンドは目的のサーバなどが、接続可能(例えば起動しているか、とか、ネットにつながっているかなど)かどうかを調べるための基本的なコマンドです。
 この「ping」コマンドが「ICMPプロトコル」を使用しています。
 今回のネットワークでは、メンテ用ホストとWebサーバ間でICMPを通す必要があります。まずは、メンテ用ホストからWebサーバへの設定です。
 # /sbin/iptables -A FORWARD -p icmp -s 192.168.0.11 --icmp-type 8
                                                      -d 192.168.0.21 -j ACCEPT
となります。新しく出てきた項目とその指定は、

チェインやオプション 解説
-p icmp 「-p」で、適合プロトコルをICMPに設定しています。
--icmp-type 8 「--icmp-type」はマッチングの拡張で、「8」を指定することで「Echo Request」を指定しています。


 「--icmp-type」については、もう少し説明をしましょう。
 ICMPプロトコルによるパケットには、ICMPヘッダというデータがあります。このICMPヘッダは、Typeフィールドで始まり、どの様なICMPメッセージであるかを示す番号が示されています。
 上記の設定のように「8」を指定すると、「Echo Request」を指定したことになります。この「Echo Request」はpingコマンドで使用されます。
 メッセージタイプの番号には、

番号 メッセージタイプ 概要
0 Echo Reply エコー応答。「ping」や「traceroute」の応答などに使用。
3 Destination Unreachable 到達不能。ルータがデータグラムを配送できないときに返信。
4 Source Quench 発信抑制。ネットワークの混雑を通知。
5 Redirec ルート変更。最適経路情報を通知。
8 Echo Request エコー要求。ping実行。
9 Router Advertisment ルータ通知。
10 Router Selection ルータ選択。
11 Time Exceeded 時間超過。生存期間が終了しルータがパケットを破棄したときに返信。
12 Parameter Problem パラメータ異常。
13 Timestamp Request タイムスタンプ要求。ネットワーク通過時間計測のために使用。
14 Timestamp Reply タイムスタンプ応答。
15 Information Request 情報要求。
16 Information Reply 情報応答。
17 Address Mask Request アドレスマスク要求。
18 Address Mask Reply アドレスマスク応答。
30 Traceroute トレースルート。
37 Domain Name Request ドメイン名要求。
38 Domain Name Reply ドメイン名応答。


などがあります。
 次に、Webサーバからメンテ用ホストに対する応答に関する設定です。
 # /sbin/iptables -A FORWARD -p icmp --icmp-type 0 -s 192.168.0.21
                                                    -d 192.168.0.11 -j ACCEPT
となります。「--icmp-type 0」で「Echo Reply(応答)」を許可しています。
 次に「INPUT」チェインと「OUTPUT」チェインについて説明します。
 前に説明していますが、再度簡単に「INPUT」チェインと「OUTPUT」チェインを説明します。
 「FORWARD」チェインでは、iptablesを実行しているLinux機では受け取ったパケットを単に他のホスト(Webサーバなど)に転送しているだけです。
 それに対し、「INPUT」チェインと「OUTPUT」チェインはiptablesを実行しているLinux機に関するパケットを対象としています。
 「INPUT」チェインではそのLinux機宛のパケット、「OUTPUT」チェインはそのLinux機から他のホスト宛のパケットを処理します。
 では、設定方法を説明しましょう。ここでは、メンテ用ホストからのpingコマンドとssh接続を許可する設定を例にします。
 まずはpingコマンドを許可しましょう。
  # /sbin/iptables -A INPUT -p icmp -s 192.168.0.11 --icmp-type 8 
                                                 -d 192.168.0.10 -j ACCEPT
  # /sbin/iptables -A OUTPUT -p icmp -s 192.168.0.10 --icmp-type 0 
                                                  -d 192.168.0.11 -j ACCEPT
となります。続けて、
  # /sbin/iptables -A INPUT -p tcp -s 192.168.0.11 --dport 22 
                                                   -d 192.168.0.10 -j ACCEPT
  # /sbin/iptables -A OUTPUT -p icmp ! --syn --sport 22 -s 192.168.0.10 
                                                     -d 192.168.0.11 -j ACCEPT
となります。4行とも「FORWARD」チェインで説明したオプションなどを使用していて、「FORWARD」が「INPUT」、「OUTPUT」に変わっただけなので、内容については理解していただけると思います。

iptablesの設定のスクリプト化

 iptablesの設定は、全てコマンドを入力して行います。iptablesをまともに機能させるには、必要最小限の設定だけでも10数行のコマンドを打ち込まなければならないでしょう。
 その10数行のコマンドを打ち込むのは面倒でもあり、間違いも起こりやすくなるので、必要な設定のためのコマンドを列挙したスクリプト・ファイルを作成し、そのスクリプトを実行させた方が現実的でしょう。

 ここで簡単に「シェル・スクリプト」の説明をしておきます。

 Linux(UNIXなど)では、コマンドなどを列挙したテキストファイルを用意し、そのファイルを実行することによって複数のコマンドを順に自動実行させることが出来ます。ちょうどMS-DOSやWindows OSなどのバッチ・ファイルのようなモノです。
 このコマンドを列挙したテキストファイルのことを「シェル・スクリプト」と言います。
 LinuxやWindowsなどの多くのOSで、OSの中核となる「カーネル」と「ユーザー・インターフェイス」(など)は分離されています。「シェル」はその「カーネル」とユーザーを仲介してくれるプログラムの事です。カーネルを「貝殻」のように包み込んで、ユーザーに近い、OSの一番外側にあるプログラムなので「シェル」と呼ばれています。
 Linuxでは「BASHシェル」、BSD版UNIXでは「Cシェル」を使用しています。また、MS-DOSでは「command.com」が、Windows OSでは「プログラムマネージャ」や「エクスプローラ」が、Mac OSでは「Finder」が、それぞれシェルの役目を果たしています。
 つまり「シェル・スクリプト」は、上記のようなカーネルとのやり取りを受け持つ「シェル」に対して、複数のコマンドなどを自動実行させるためのファイル、ということです。また、「for〜do〜done」、「case〜in〜esac」、「if〜then〜else」、「while〜do〜done」などの構文やシェル変数なども使え、単にコマンドを並べるだけでなく、環境に応じたプログラミングが行えます。

 では、iptablesの設定のシェル・スクリプト化を説明します。

 説明に用いるネットワークは#071で説明していますが、もう一度構成を表して おきます。
             ┌───────┐
             │インターネット│
             │  (外 部) │
             └───┬───┘
             ┌───┴───┐
             │   ルータ   │
             │ 172.16.0.1 │
             └───┬───┘
              (172.16.0.0/24)
                 eth1
           ┏━━━━━┷━━━━━┓
           ┃   172.16.0.10   ┃
           ┃  ファイアウォール ┃
           ┃   192.168.0.10   ┃
           ┗━━━━━┯━━━━━┛
                 eth0
             ┌───┴───┐
             │  L A N  │
             │192.168.0.0/24│
             └┬─────┬┘
        ┌─────┴─┐ ┌─┴────┐
        │メンテ用ホスト│ │ Web サーバ │
        │ 192.168.0.11 │ │192.168.0.21│
        └───────┘ └──────┘
このようなネットワークでの基本的な設定を、前回までに説明してきた設定以外にも必要な設定を加えて、スクリプト化すると、
  1:  #!/bin/sh
  2:  #
  3:  # Define IP Address
  4:  # ファイアウォールの外側のインターフェイス
  5:  FW_OUT='172.16.0.10'
  6:  #
  7:  # ファイアウォールの内側のインターフェイス
  8:  FW_IN='192.168.0.10'
  9:  #
 10:  # Webサーバの公開IPアドレス
 11:  WEB_OPEN='172.16.0.10'
 12:  #
 13:  # Webサーバの実IPアドレス
 14:  WEB_REAL='192.168.0.21'
 15:  #
 16:  # メンテナンス用ホスト
 17:  MAINT='192.168.0.11'
 18:  #
 19:  # LANのネットワークアドレス
 20:  LOCALNET='192.168.0.0/24'
 21:  #
 22:  # すべてのIPアドレス
 23:  ALL='0.0.0.0'
 24:  #
 25:  ##### フィルタリングの設定 #####
 26:  #
 27:  # 以前のチェインの消去
 28:  /sbin/iptables -F
 29:  #
 30:  # 基本ポリシーをすべてのパケットを拒否に設定
 31:  /sbin/iptables -P INPUT DROP
 32:  /sbin/iptables -P FORWARD DROP
 33:  /sbin/iptables -P OUTPUT DROP
 34:  #
 35:  #  ループバックアドレスに関してはすべて許可
 36:  #/sbin/iptables -A INPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
 37:  #/sbin/iptables -A OUTPUT -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
 38:  #
 39:  # メンテナンス用ホストからファイアウォールに対してのみpingを許可
 40:  /sbin/iptables -A OUTPUT -p icmp -s $FW_OUT --icmp-type 0 -d $MAINT -j ACCEPT
 41:  /sbin/iptables -A INPUT -p icmp -s $MAINT --icmp-type 8 -d $FW_OUT -j ACCEPT
 42:  /sbin/iptables -A OUTPUT -p icmp -s $FW_IN --icmp-type 0 -d $MAINT -j ACCEPT
 43:  /sbin/iptables -A INPUT -p icmp -s $MAINT --icmp-type 8 -d $FW_IN -j ACCEPT
 44:  #
 45:  # Webサーバからメンテナンス用ホストへのpingを許可
 46:  /sbin/iptables -A OUTPUT -p icmp -s $WEB_REAL --icmp-type 0 -d $MAINT -j ACCEPT
 47:  /sbin/iptables -A INPUT -p icmp -s $MAINT --icmp-type 8 -d $WEB_REAL -j ACCEPT
 48:  #
 49:  # メンテナンス用ホストからWebサーバへのpingを許可
 50:  /sbin/iptables -A OUTPUT -p icmp -s $MAINT --icmp-type 0 -d $WEB_REAL -j ACCEPT
 51:  /sbin/iptables -A INPUT -p icmp -s $WEB_REAL --icmp-type 8 -d $MAINT -j ACCEPT
 52:  #
 53:  # メンテ用ホストからファイアウォールに対してssh接続(22/TCP)を許可
 54:  /sbin/iptables -A INPUT -p TCP -s $MAINT --dport 22 -d $FW_OUT -i eth0 -j ACCEPT
 55:  /sbin/iptables -A OUTPUT -p TCP ! --syn --sport 22 -s $FW_OUT
                                                         -d $MAINT -o eth0 -j ACCEPT
 56:  #
 57:  # メンテ用ホストからWebサーバに対してssh接続(22/TCP)を許可
 58:  /sbin/iptables -A INPUT -p TCP -s $MAINT --dport 22 -d $WEB_REAL -i eth0 -j ACCEPT
 59:  /sbin/iptables -A OUTPUT -p TCP ! --syn --sport 22 -s $WEB_REAL
                                                         -d $MAINT -o eth0 -j ACCEPT
 60:  #
 61:  # 全てのホストからWebサーバに対してHTTP接続(80/TCP)でのアクセスを許可
 62:  /sbin/iptables -A FORWARD -p TCP -s $ALL --dport 80 -d $WEB_REAL -j ACCEPT
 63:  /sbin/iptables -A FORWARD -p TCP ! --syn -m state --state ESTABLISHED
                                               --sport 80 -s $WEB_REAL -d $ALL -j ACCEPT
 64:  #
 65:  ##### NATの設定 #####
 66:  #
 67:  # 以前のNATルールを消去
 68:  /sbin/iptables -t nat -F
 69:  #
 70:  # 外部のホストからWebサーバへアクセスするためのNATの設定
 71:  /sbin/iptables -t nat -A PREROUTING -d $WEB_OPEN -i eth1
                                          -p tcp --dport 80 -j DNAT --to $WEB_REAL
 72:  #
 73:  # LAN内からインターネット(外部)へアクセスするためのNATの設定
 74:  # /sbin/iptables -t nat -A POSTROUTING -s $LOCALNET -o eth1 -j SNAT --to 172.16.0.10
 75:  #
 76:  ##### ログの設定 #####
 77:  #
 78:  #/sbin/iptables -A INPUT -j LOG --log-level warn --log-prefix "iptables input: "
 79:  #/sbin/iptables -A OUTPUT -j LOG --log-level warn --log-prefix "iptables output: "
 80:  #/sbin/iptables -A FORWARD -j LOG --log-level warn --log-prefix "iptables forward: "
 81:  #
 82:  # END of Script
となります。行頭に行番号が無い行は前の行からの続きです。実際に記述する場合は前の行の後に続けてください。

 では、まだ説明していない部分を主に、スクリプトの内容を説明しましょう。

 まずは、1行目、
  1:  #!/bin/sh
 この呪文は、「「#!」以後に書かれたプログラムでこのスクリプトを実行する」という意味で、この呪文が無ければ、このスクリプトファイルを実行するシェルを指定する必要があります。
 2行目以降の行頭で、「#」が記述されている行はコメント行なので、スクリプトの実行には影響されません。
 5行目の、
  5:  FW_OUT='172.16.0.10'
は、変数「FW_OUT」に「172.16.0.10」を代入しています。
 この行以降(例えば40行目など)で、「$FW_OUT」と記述されている部分がスクリプト実行時に「172.16.0.10」に置き換えられます。
 変数を用いることで、もし、ファイアウォールの外向きIPアドレスが変わっても、5行目を編集するだけで事足ります。また、値の書き間違いも防げます。
 8、11、14、17、20、23行目も同様です。
 28行目の、
  28:  /sbin/iptables -F
は、まだ説明していませんね。この「-F」オプションは、「-F(チェイン)」で、選択されたチェインの内容を全消去するオプションです。チェインの指定がない場合は、テーブル内の全てのチェインの全消去となります。
 例えば、ネットワークの構成に変更があり、iptablesの設定を変更(このスクリプトファイルを編集)した場合に、再度このスクリプトを実行します。その時に以前の設定を消去して、新しい設定を有効にするためにこのコマンドが必要となります。
 31行目から33行目で基本ポリシーを設定しています。
 36、37行目は、「ループバックアドレス」に関する設定をしています。「ループバックアドレス」とは、Linux機自身を指定する特別なIPアドレスのことです。「127.0.0.1」で自身にアクセスすると、実際にネットワークにIPパケットを流すことなく自身にアクセスできます。
 36、37行目で自分自身に対する通信を全て許可しています。
 40から43行目で、メンテ用ホストからファイアウォールの2つのインターフェイスに対してのpingコマンドを許可しています。
 46、47行目で、Webサーバからメンテ用ホストに対するpingコマンドを許可しています。この設定は、Webサーバにアクセスできないなどの問題が起きたときのための許可しています。
 50、51行目は、その逆を許可しています。
 54、55行目で、メンテ用ホストからファイアウォールに対してのssh接続を許可し、同様に、58、59行目で、メンテ用ホストからWebサーバに対してのssh接続を許可しています。
 62、63行目で、あらゆるホストからのWebサーバに対するアクセスを許可しています。
 65行目からがNATの設定です。
 68行目は、28行目と同様にNATテーブルからそれまでの設定を消去しています。
 71行目で、Webサーバの公開IPアドレスを、実IPアドレスに書き換えしていま す。
 74行目で、LANから外部に対するアクセスを、外部向けインターフェイスのIPアドレスに書き換えています。
 78、79、80行目は、「-j LOG」で、パケット・フィルタリングのログをsyslogに記録するように設定しています。この「LOG」ターゲットには、

オプション 機能
--log-level(レベル) ログ記録のレベルを数値、または名前で指定。名前は、emerg、alert、crit、err、warn、notice、info、debugのいずれか。詳しくは「man syslog.conf」の説明を参照。
--log-prefix(プレフィックス) 指定したプレフィックスをログメッセージの前に付ける。プレフィックスは、29文字までの長さで、メッセージを区別するのに利用します。
--log-tcp-sequence TCPシーケンス番号をログに記録。ログがユーザーから読める場合、セキュリティ上、危険です。
--log-tcp-options TCPパケットヘッダーのオプションを、ログに記録する。
--log-ip-options IPパケットヘッダーのオプションを、ログに記録する。


などのオプションがあります。
 今回のスクリプトでは、「INPUT」、「OUTPUT」、「FORWARD」の各チェインでwarn以上のロギングを行い、それぞれログファイルに「iptables input: 」などをログメッセージの前に付けて記録する設定になっています。
 viなどのエディタで、上記の内容を記述し、「fw.sh」など適当な名前で保存します。
  *1:  # chmod 744 fw.sh
として、実行権限を与えて、
  *2:  # ./fw.sh
で、シェル・スクリプトを実行します。
 これで上記スクリプトの内容でiptablesの設定が行えました。でも、このままではLinuxを再起動させると、設定内容が反映されなくなってしまうので、
  *3:  # /sbin/iptables-save > /etc/sysconfig/iptables.save
を実行します。これで、次回Linux起動時にも今回の設定内容が反映されるようになります。

iptablesの運用上の注意点

 iptablesは設定さえ正しく行えば、思い通りに通信パケットを操ることが出来ます。
 但し、設定を間違えると通信が行えなくなったり、思わぬ抜け穴が生じたりします。
 例えば、上記で説明に用いたネットワークでLAN内にWindows機が存在する場合、上記の設定では、「Windows Update」が実行できません。これ以外にも不可能な通信があります。
 実行するには、
  # /sbin/iptables -A FORWARD  -i eth0 -p tcp --dport 443  -j ACCEPT
というような設定を行い、「Windows Update」が使用する443番ポートを開かなければなりません。
 完全なフィルタリングを行うには、ネットワークに流れるパケットで使用されているプロトコルやポート番号を把握し、基本ポリシーで全て閉めた後に、適切に必要なプロトコル、ポートを開けるようにしなければなりません。
 また、通信元、通信先を特定できるような場合はIPアドレスで指定して、それら以外からのアクセスを破棄するなどの制限をする必要があります。
 例えば、企業の本社と支社でそれぞれ固定IPアドレスを取得し、社内向け情報を本社Webサーバで公開するような場合は、
  /sbin/iptables -A FORWARD -p TCP -s [支社IPアドレス] --dport 80 
                                                        -d [本社IPアドレス] -j ACCEPT
  /sbin/iptables -A FORWARD -p TCP ! --syn -m state --state 
                 ESTABLISHED --sport 80 -s [本社IPアドレス] -d [支社IPアドレス] -j ACCEPT
として、支社以外からの本社Webサーバへのアクセスを制限します。
 もちろん、社外に漏れてはいけないような、顧客の個人情報などの重要情報が流れる場合は、VPN(Virtual Private Network)や暗号化通信などと組み合わせてネットワークを構築する必要があります。
 iptablesを適切に設定できたとしても、それだけで安全だとは言えません。ログのチェックや定期的なネットワークの監視など日頃の管理が重要になります。
 ファイアウォールの導通確認には「tcpdump」や「Ethereal」などが有効です。ポートスキャンツールの「Nmap」を使えば、不必要なポートが開いていないか、確認できます。また、「hping2」を使えば、カスタマイズしたTCPパケットを生成して目的のポートに送信し、リプライパケットの状態を確認できます。
 但し、これらのツールの幾つかは、悪用することも出来るので、使用するときは十分注意してください。