シンプルなステートフルファイアウォール
このページでは iptables を使ってステートフルファイアウォールを設定する方法を説明します。また、ルールの意味と理由の説明も行います。シンプルに説明するため、大きく2つのセクションにページは分かれています。最初のセクションではシングルマシンのためのファイアウォールを扱い、2番目のセクションでは最初のセクションのファイアウォールに加えて NAT ゲートウェイを設定します。
目次
前提要件
まず、ユーザーランドユーティリティ iptables をインストールしてください。もしくは既にインストール済みかどうか確認してください。
この記事では iptables のルールセットが全く存在しないことを前提としています。現在のルールセットをチェックして、ルールが存在しないことを確認するには、次を実行:
# iptables-save
# Generated by iptables-save v1.4.19.1 on Thu Aug 1 19:28:53 2013 *filter :INPUT ACCEPT [50:3763] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [30:3472] COMMIT # Completed on Thu Aug 1 19:28:53 2013
もしくは
# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 156 packets, 12541 bytes) num pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 82 packets, 8672 bytes) num pkts bytes target prot opt in out source destination
ルールが存在する場合、デフォルトのルールセットをロードすることでルールをリセットすることが可能です:
# iptables-restore < /etc/iptables/empty.rules
もしくは、Iptables#ルールをリセットする を参照。
シングルマシン用のファイアウォール
必要なチェインの作成
基本的なセットアップとして、2つのユーザー定義チェインを作成し、それを使ってファイアウォールのポートを開きます。
# iptables -N TCP # iptables -N UDP
もちろんチェインの名前は何でもかまいません。ここでは後のルールで使用するプロトコルに沿うように名前を決めています。
FORWARD チェイン
マシンを NAT ゲートウェイとしてセットアップしたい場合、#NAT ゲートウェイの設定を見て下さい。シングルマシンの場合、FORWARD チェインのポリシーをとりあえず DROP に設定して先に進みます:
# iptables -P FORWARD DROP
OUTPUT チェイン
送信トラフィックはフィルタリングしません。セットアップがとても複雑になってしまい、いろいろと考える必要が出てくるからです。ここではシンプルに、OUTPUT ポリシーを ACCEPT に設定します。
# iptables -P OUTPUT ACCEPT
INPUT チェイン
上記のチェインと同じように、勝手にルールを通過してしまわないように INPUT チェインのデフォルトポリシーは DROP に設定します。セキュアなファイアウォールを設定するときは、全てのトラフィックをドロップしてから、許可するトラフィックを指定するのがベストです。
# iptables -P INPUT DROP
あらゆるネットワークインターフェイスから受信されたパケットは全て INPUT チェインをまず通過します (パケットの送信先が対象のマシンになっている場合)。このチェインの中では、問題ないと思われるパケットだけを許可するようにします。
INPUT チェインにはまず、確立済みの接続に属するトラフィックや、ICMP エラーまたはエコー応答 (ping されたときにホストが返すパケット) などの接続に関連する正当なトラフィックを許可するルールを追加します。ICMP は Internet Control Message Protocol の略です。ICMP メッセージは輻輳制御や MTU にとても重要なので、このルールによって通してやります。
接続ステート ESTABLISHED
は最初の (--ctstate NEW
) 接続試行で許可された以前の他のルール、またはルールの設定時にアクティブになっていた接続 (例えばアクティブな SSH リモート接続) を示します:
# iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
次のルールでは "loopback" (lo) インターフェイスからのトラフィックを全て許可します。多くのアプリケーションやサービスで必須となります。
# iptables -A INPUT -i lo -j ACCEPT
3番目のルールでは "INVALID" ステートに一致する全てのトラフィックを破棄します。トラフィックは4つの "state" カテゴリに分けることができます: NEW, ESTABLISHED, RELATED, INVALID。これによって "stateless" ファイアウォールではなく "stateful" ファイアウォールと呼称しています。ステートは "nf_conntrack_*" カーネルモジュールによって追跡されます。カーネルモジュールはルールを追加したときにカーネルによって自動的にロードされます。
# iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
次のルールでは ICMP エコー要求 (ping) を全て許可します。最初のパケットだけを NEW としてカウントし、後は全て RELATED,ESTABLISHED ルールで処理します。コンピュータはルーターではないので、他の ICMP トラフィックをステート NEW で許可する必要はありません。
# iptables -A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
新しい接続を処理するために、INPUT チェインに TCP チェインと UDP チェインを適用します。いったん TCP チェインや UDP チェインで接続が許可されると、以降は RELATED/ESTABLISHED のルールで処理されます。TCP チェインと UDP チェインはどちらも新しい接続を許可するか、または丁寧にそれらを REJECT します。新しい TCP 接続は必ず SYN パケットから始まります。
# iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP # iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
ポートを開いていない場合、TCP 接続は TCP RESET パケットで、UDP ストリームは ICMP port unreachable メッセージで拒否します。デフォルトの Linux の挙動と同じであるため (RFC 準拠)、送信者はすみやかに接続を閉じることができます。
# iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable # iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
他のプロトコルのために、icmp protocol unreachable メッセージで残りの受信トラフィックを拒否する最終ルールを INPUT チェインに追加します。Linux のデフォルトの挙動を真似ています。
# iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
iptables.rules のサンプルファイル
上記のコマンドを全て実行した時に作成される iptables.rules
ファイルの例:
/etc/iptables/iptables.rules
# Generated by iptables-save v1.4.18 on Sun Mar 17 14:21:12 2013 *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] :TCP - [0:0] :UDP - [0:0] -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable COMMIT # Completed on Sun Mar 17 14:21:12 2013
このファイルは次のコマンドで生成できます:
# iptables-save > /etc/iptables/iptables.rules
生成したファイルは下のセクションで使うことができます。SSH 経由でリモートからファイアウォールを設定する場合、先に進む前に新しい SSH 接続を許可するため以下のルールを追加してください (ポート番号は必要に応じて変更してください):
-A TCP -p tcp --dport 22 -j ACCEPT
TCP と UDP チェイン
TCP と UDP チェインには特定のポートで新規接続の TCP 接続と UDP ストリームを許可するルールを作成します。
接続要求でポートを開く
ウェブサーバーへの TCP 接続を許可するには (ポート 80):
# iptables -A TCP -p tcp --dport 80 -j ACCEPT
ウェブサーバーへの TCP 接続 (HTTPS) を許可するには (ポート 443):
# iptables -A TCP -p tcp --dport 443 -j ACCEPT
SSH のリモート接続を許可するには (ポート 22):
# iptables -A TCP -p tcp --dport 22 -j ACCEPT
DNS サーバーへの TCP/UDP リクエストを許可するには (ポート 53):
# iptables -A TCP -p tcp --dport 53 -j ACCEPT # iptables -A UDP -p udp --dport 53 -j ACCEPT
複数のポートにマッチするような、高度なルールについては iptables(8) を見て下さい。
ポートノッキング
デフォルトではファイアウォールによって閉じられているポートを、外部から開く方法がポートノッキングです。予め決めておいたポートに連続して接続試行することで行います。正しいポート"ノック" (接続試行) がなされた場合、ファイアウォールは特定のポートを開いて接続できるようにします。詳しくはポートノッキングを見て下さい。
なりすまし攻撃からの防護
インターネットやローカルネットワークからの予約ローカルアドレスの使用は sysctl で rp_filter
(Reverse Path Filter) を 1 に設定することでブロックされます。以下の行を /etc/sysctl.d/90-firewall.conf
ファイルに追加することで Linux カーネルに組み込まれている送信元アドレス検証が有効になります (詳しくは sysctl を参照)。カーネルによる検証は個別の iptables ルールよりもなりすましを上手く処理します:
net.ipv4.conf.all.rp_filter=1
統計が必要な場合、netfilter で設定することもできます:
# iptables -t raw -I PREROUTING -m rpfilter --invert -j DROP
非同期ルーティングを使用する構成の場合、代わりに rp_filter=2
sysctl オプションを使用する必要があります。--loose
スイッチを rpfilter
モジュールに渡すことで netfilter と同じ設定ができます。
コンピュータを"隠匿"する
デスクトップマシンとして使っている場合、特定の接続要求はブロックするのが好ましいでしょう。
ping リクエストのブロック
'Ping' リクエストはデバイス間の通信状態を確認するために送信先アドレスに送られる ICMP パケットです。ネットワークが問題ないようでしたら、ping リクエストは全てブロックしてもかまいません。リクエストをブロックするだけではコンピュータを隠匿することにはならないので注意してください。たとえコンピュータに送られた全てのパケットを拒否したとしても、シンプルな nmap による IP 範囲の "ping スキャン" で露顕してしまいます。
ブロックは初歩的な"防護"であり、将来問題が起こった時にデバッグするのが困難になります。あくまで勉強用にやってみるくらいにしてください。
エコー要求をブロックするには、次の行を /etc/sysctl.d/90-firewall.conf
ファイルに追加してください (詳しくは sysctl を参照):
net.ipv4.icmp_echo_ignore_all = 1
詳しくは iptables の man ページや http://www.snowman.net/projects/ipt_recent/ のドキュメントやサンプルを読んでください。
ポートスキャナを騙す
攻撃者はポートスキャンを使ってコンピュータの開いているポートを確認します。ポートスキャンによって攻撃者は稼働しているサービスを調査することができ、場合によってはサービスの脆弱性を利用してくる可能性があります。
INVALID ステートルールは UDP, ACK, SYN スキャン以外の全てのポートスキャンを処理します (nmap ではそれぞれ -sU, -sA, -sS)。
ACK スキャンは開いているポートを確認するのには使われませんが、ファイアウォールによってフィルタリングされているポートを識別するのには使われます。NEW ステートの TCP 接続は全て SYN チェックするため、ACK スキャンによって送信されたパケットは全て TCP RESET パケットで拒否されます。一部のファイアウォールはパケットを破棄するため、攻撃者はファイアウォールのルールを暴き出すことができます。
recent モジュールを使うことで他の2種類のポートスキャンを騙すことができます。recent モジュールでホストを "recent" リストに追加して、特定の種類の攻撃を停止させます。現在の recent リストは /proc/net/xt_recent/
で確認できます。
SYN スキャン
SYN スキャンでは、ポートスキャナは全てのポートに TCP 接続を開始する SYN (synchronization) パケットを送信します。閉じられているポートは TCP RESET パケットを返しますが、厳格なファイアウォールはパケットを破棄します。開いているポートは、ファイアウォールがあるかどうかに関わらず、SYN ACK パケットを返します。
recent
モジュールを使うことで接続を拒否されたホストの記録をつけることができ、開いているポートに SYN パケットが送信されたときにポートが閉じているかのように TCP RESET を返すことが可能です。開かれているポートが最初にスキャンされた場合、SYN ACK が返されてしまうため、確実にポートを隠匿するには標準以外のポートを ssh などのアプリケーションで使用する必要があります。
まず、TCP チェインの一番上にルールを追加します。以下のルールは過去60秒以内に TCP-PORTSCAN
リストに入ったホストに対して TCP RESET で応答します。--update
スイッチで recent リストが更新され、60秒のカウンターがリセットされます。
# iptables -I TCP -p tcp -m recent --update --rsource --seconds 60 --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset
そして TCP パケットを拒否するルールを修正して拒否されたパケットを送信したホストを TCP-PORTSCAN
リストに追加するようにしてください:
# iptables -D INPUT -p tcp -j REJECT --reject-with tcp-reset # iptables -A INPUT -p tcp -m recent --set --rsource --name TCP-PORTSCAN -j REJECT --reject-with tcp-reset
UDP スキャン
UDP ポートスキャンは TCP の SYN スキャンと似ていますが UDP は "connectionless" プロトコルです。ハンドシェイクや ACK は存在しません。代わりに、スキャナは各 UDP ポートに UDP パケットを送信します。ポートが閉じていると ICMP のポート到達不可メッセージが返ってきますが、ポートが開いている場合、何も返答が返ってきません。UDP は "reliable" プロトコルではないので、パケットが消失したかどうか知る手段がスキャナにはなく、返答がないポートを何度も確認する必要があります。
Linux カーネルは ICMP ポートの到達不可メッセージを非常にゆっくりと送信するため、Linux マシンに対して完全な UDP スキャンをかけようとすると10時間以上かかります。それでも、一般的なポートは識別できるため、SYN スキャンに対してと同じ対抗策を UDP スキャンに対しても設定すると良いでしょう。
まず UDP-PORTSCAN
リストのホストからのパケットを拒否するルールを UDP チェインの一番上に追加してください:
# iptables -I UDP -p udp -m recent --update --rsource --seconds 60 --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable
そして、UDP の拒否パケットルールを以下のように修正します:
# iptables -D INPUT -p udp -j REJECT --reject-with icmp-port-unreachable # iptables -A INPUT -p udp -m recent --set --rsource --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable
最終ルールのリストア
上記のポートスキャンに対抗するテクニックを使用した場合、デフォルトの最終ルールが INPUT チェインの最後のルールではなくなります。最後のルールにしないとポートスキャン対策のルールが遮断されてルールが使われなくなってしまいます。ルールを一度削除 (-D) してから、もういちど追加 (-A) することでチェインの最後に配置することが可能です:
# iptables -D INPUT -j REJECT --reject-with icmp-proto-unreachable # iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable
他の攻撃からの防護
関連するカーネルパラメータは sysctl#TCP/IP スタックの防御 に載っています。
ブルートフォース攻撃
残念ながら、外部 IP アドレスからアクセスできるサービスにはよくブルートフォース攻撃が行われます。ブルートフォース攻撃が普遍的な理由としては、攻撃を行うのがとても簡単で、攻撃用のツールが数多く存在するということが挙げられます。幸いに、ブルートフォース攻撃からサービスを守るための方法はいろいろあります。その一つとして、適切な iptables
ルールを使って接続を開始しようとするパケットが一定数あったときに IP をブラックリストに入れる方法があります。また、ログファイルを監視して、試行失敗からブラックリストを作成する専用のデーモンを使うこともできます。
パスワード認証 (特に sshd
) が何回も失敗した時にその IP を接続不可にするパッケージとして Fail2ban と Sshguard が存在します。どちらも iptables のルールを更新することで、ブラックリストに入っている IP アドレスからの接続を一時的に拒否します。
以下は iptables
を使って SSH のブルートフォース攻撃を止めるための設定例です:
# iptables -N IN_SSH # iptables -N LOG_AND_DROP # iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH # iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 3 --seconds 10 -j LOG_AND_DROP # iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 4 --seconds 1800 -j LOG_AND_DROP # iptables -A IN_SSH -m recent --name sshbf --set -j ACCEPT # iptables -A LOG_AND_DROP -j LOG --log-prefix "iptables deny: " --log-level 7 # iptables -A LOG_AND_DROP -j DROP
ほとんどのルールは特に説明を要しないはずです。最初のルールは最大で10秒間で最大3回までの接続パケットを許可し、同じ IP からの4回以上のパケットは破棄します。次のルールでは30分以内で最大4回のパケットを許可するように規則を追加します。一部のブルートフォース攻撃はゆっくりと実行されることがあり、短い時間で何度も試行されないことがあるためです。上記のルールは追加のオプションを使用しています。オプションについて詳しくは compilefailure.blogspot.com を参照してください。
上のルールはどんなサービスでも保護することができますが、最も保護が必要なデーモンはおそらく SSH デーモンでしょう。
順序に関しては、-A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH
が iptables シーケンスの正しい位置にあることを確認する必要があります。最初に新しい SSH 接続をキャッチするために、TCP チェーンが INPUT に接続されます。このウィキのこれまでのすべての手順が完了している場合、次のポジショニングが機能します。
... -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j IN_SSH -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP ...
IPv6
IPv6 を使用しない場合 (ほとんどの ISP は IPv6 をサポートしていません)、無効化したほうが良いでしょう。
使用する場合、IPv6 のファイアウォールルールを有効にしてください。まず IPv4 のルールをベースとしてコピー:
# cp /etc/iptables/iptables.rules /etc/iptables/ip6tables.rules
最初に、ルールの中で記述している IP を IPv4 のフォーマットから IPv6 のフォーマットに変換します。
次に、ルールの一部を改変する必要があります (この記事のルールは IPv4 用になっています)。IPv6 では ICMP を置き換えて新しい ICMPv6 プロトコルを使います。拒否エラーのリターンコード --reject-with icmp-port-unreachable
と --reject-with icmp-proto-unreachable
は ICMPv6 のコードに変えてください。
利用可能な ICMPv6 エラーコードは RFC 4443 に記載されており、ファイアウォールのルールによって接続をブロックしたときは --reject-with icmp6-adm-prohibited
を使うように定義されています。この場合、リモートのマシンにサービスではなくファイアウォールによって接続が拒否されたことを知らせることになります。
ファイアウォールフィルターが存在することを明らかにしたくない場合、メッセージを付けずにパケットを拒否することも可能です:
-A INPUT -j REJECT
上記の設定だとデフォルトのリターンエラー --reject-with-icmp6-port-unreachable
で拒否します。ただし、ファイアウォールの識別はポートスキャンアプリケーションの基本機能であり、大抵のポートスキャナは上記のように設定していても識別してしまうので注意してください。
In the next step make sure the protocol and extension are changed to be IPv6 appropriate for the rule regarding all new incoming ICMP echo requests (pings):
# ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 128 -m conntrack --ctstate NEW -j ACCEPT
Netfilter conntrack は ICMPv6 近隣探索プロトコル (IPv6 における ARP) を追跡しないため、ステートに関わらず直接接続されたサブネットでは ICMPv6 を全て許可する必要があります。以下のルールを --ctstate INVALID
の破棄の後、ただし他の DROP または REJECT ターゲットの前に、それぞれの直接接続されたサブネットの行と一緒に挿入してください:
# ip6tables -A INPUT -s fe80::/10 -p ipv6-icmp -j ACCEPT
IPv6 用のカーネルの戻り経路フィルタは存在しないため、以下のコマンドで ip6tables のフィルタを有効にすると良いでしょう:
# ip6tables -t raw -A PREROUTING -m rpfilter -j ACCEPT # ip6tables -t raw -A PREROUTING -j DROP
設定が完了したら、ip6tables サービスを有効化してください。iptables とは別個に実行させます。
ルールの保存
ルールセットの設定が完了したら、ハードドライブに保存して、マシンを起動する度にロードされるようにします。
ルールの設定を保存する場所は systemd のユニットファイルで指定します:
iptables=/etc/iptables/iptables.rules ip6tables=/etc/iptables/ip6tables.rules
次のコマンドでルールを保存します:
# iptables-save > /etc/iptables/iptables.rules
そして iptables.service
を起動・有効化して、起動時にルールがロードされるようにしてください。
ip6tables.rules ファイル
上記のすべてのコマンドを実行した後の ip6tables.rules
ファイルの例:
/etc/iptables/ip6tables.rules
# Generated by ip6tables-save v1.8.2 on Sat Apr 20 10:53:41 2019 *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] :TCP - [0:0] :UDP - [0:0] -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -s fe80::/10 -p ipv6-icmp -j ACCEPT -A INPUT -p udp --sport 547 --dport 546 -j ACCEPT -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP -A INPUT -p udp -j REJECT --reject-with icmp6-adm-prohibited -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp6-adm-prohibited -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 128 -m conntrack --ctstate NEW -j ACCEPT COMMIT # Completed on Sat Apr 20 10:53:41 2019
次に、iptables.service
と ip6tables.service
を 有効化 して 起動 します。サービスのステータスをチェックし、ルールが正しくロードされていることを確認します。
NAT ゲートウェイの設定
このセクションでは NAT ゲートウェイについて扱います。ガイドの前半部分を読んで INPUT, OUTPUT, TCP, UDP チェインを設定していることが前提です。これまで全てのルールは filter テーブルに作成していました。このセクションでは、nat テーブルも使用していきます。
フィルターテーブルの設定
必要なチェインの作成
以下の設定では、2つの異なるチェインをフィルターテーブルで使用します: fw-interfaces と fw-open チェインです。以下のコマンドでチェインを作成してください:
# iptables -N fw-interfaces # iptables -N fw-open
FORWARD チェインの設定
FORWARD チェインの設定は上のセクションにある INPUT チェインの設定と大体同じです。
INPUT チェインと同じように conntrack マッチのルールを設定します:
# iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
次のステップは、信頼できるインターフェースの転送を有効にし、すべてのパケットが fw-open チェーンを通過するようにすることです。
# iptables -A FORWARD -j fw-interfaces # iptables -A FORWARD -j fw-open
後のパケットは ICMP メッセージで拒否します:
# iptables -A FORWARD -j REJECT --reject-with icmp-host-unreachable # iptables -P FORWARD DROP
fw-interfaces と fw-open チェインの設定
fw-interfaces と fw-open チェインの意味については後で nat テーブルで POSTROUTING と PREROUTING チェインを扱うときに説明します。
nat テーブルの設定
このセクションでは、出力インターフェイス (公のインターネット IP が付与されるインターフェイス) の名前を ppp0 とします。使用する出力インターフェイスが別の名前の場合、以下のルールで使われている名前もそれにあわせて変更するようにしてください。
POSTROUTING チェインの設定
Now, we have to define who is allowed to connect to the internet. Let's assume we have the subnet 192.168.0.0/24 (which means all addresses that are of the form 192.168.0.*) on eth0. We first need to accept the machines on this interface in the FORWARD table, that is why we created the fw-interfaces chain above:
# iptables -A fw-interfaces -i eth0 -j ACCEPT
Now, we have to alter all outgoing packets so that they have our public IP address as the source address, instead of the local LAN address. To do this, we use the MASQUERADE target:
# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE
上記の -o ppp0 パラメータは必ず必要なので忘れないでください。パラメータを記述しなかった場合、ネットワークが接続できなくなります。
Let's assume we have another subnet, 10.3.0.0/16 (which means all addresses 10.3.*.*), on the interface eth1. We add the same rules as above again:
# iptables -A fw-interfaces -i eth1 -j ACCEPT # iptables -t nat -A POSTROUTING -s 10.3.0.0/16 -o ppp0 -j MASQUERADE
最後にパケット転送を有効化してください (既に有効にしている場合は必要ありません)。
Machines from these subnets can now use your new NAT machine as their gateway. Note that you may want to set up a DNS and DHCP server like dnsmasq or a combination of bind and dhcpd to simplify network settings DNS resolution on the client machines. This is not the topic of this guide.
PREROUTING チェインの設定
ときとして、ゲートウェイからの受信パケットのアドレスを LAN マシンに変更したい場合があります。そのようなときに、上記で定義した fw-open チェインと、以下の2つのサンプルで使っている nat テーブルの PREROUTING チェインを使用します。
まず、SSH の受信パケット (ポート 22) を全て 192.168.0.5 マシンの ssh サーバーに変更したい場合:
# iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 22 -j DNAT --to 192.168.0.5 # iptables -A fw-open -d 192.168.0.5 -p tcp --dport 22 -j ACCEPT
2番目の例では受信ポートと異なるポートにパケットを変更する方法を説明します。ポート 8000 から受信した接続を 192.168.0.6 のポート 80 のウェブサーバーに変更するには:
# iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8000 -j DNAT --to 192.168.0.6:80 # iptables -A fw-open -d 192.168.0.6 -p tcp --dport 80 -j ACCEPT
上記の設定は udp パケットでも機能します。
ルールの保存
ルールを保存してください:
# iptables-save > /etc/iptables/iptables.rules
そして iptables デーモンを有効にすることで、起動時にルールがロードされるようにします。