シンプルなステートフルファイアウォール

提供: ArchWiki
ナビゲーションに移動 検索に移動

関連記事

このページでは iptables を使ってステートフルファイアウォールを設定する方法を説明します。また、ルールの意味と理由の説明も行います。シンプルに説明するため、大きく2つのセクションにページは分かれています。最初のセクションではシングルマシンのためのファイアウォールを扱い、2番目のセクションでは最初のセクションのファイアウォールに加えて NAT ゲートウェイを設定します。

警告: 記述されているルールは順番通りに実行してください。リモートマシンにログインしている場合、ルールを設定している間にマシンから閉めだされてしまう可能性があります。以下の手順に従うのはローカルでログインしている場合に限ります。サンプル設定ファイルを使うことでこの問題を回避することが可能です。

前提要件

ノート: iptables のサポートを有効にしてカーネルがコンパイルされている必要があります。Arch Linux の標準カーネルには iptables のサポートが含まれています。

まず、ユーザーランドユーティリティ 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#ルールをリセットする を参照。

シングルマシン用のファイアウォール

ノート: 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 に設定します。セキュアなファイアウォールを設定するときは、全てのトラフィックをドロップしてから、許可するトラフィックを指定するのがベストです。

警告: SSH でログインしている場合、以下の設定をすると SSH セッションが即座に切断されます。切断されないようにするには: (1) 下の INPUT チェインのルールを先に追加 (それでセッションが開いたままになります), (2) インバウンド SSH を許可するルールを追加 (接続が終了した場合に再接続できるようにするため) (3) ポリシーを設定。
# iptables -P INPUT DROP

あらゆるネットワークインターフェイスから受信されたパケットは全て INPUT チェインをまず通過します (パケットの送信先が対象のマシンになっている場合)。このチェインの中では、問題ないと思われるパケットだけを許可するようにします。

INPUT チェインにはまず、確立済みの接続に属するトラフィックや、ICMP エラーまたはエコー応答 (ping されたときにホストが返すパケット) などの接続に関連する正当なトラフィックを許可するルールを追加します。ICMPInternet Control Message Protocol の略です。ICMP メッセージは輻輳制御や MTU にとても重要なので、このルールによって通してやります。

接続ステート ESTABLISHED は最初の (--ctstate NEW) 接続試行で許可された以前の他のルール、またはルールの設定時にアクティブになっていた接続 (例えばアクティブな SSH リモート接続) を示します:

# iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

次のルールでは "loopback" (lo) インターフェイスからのトラフィックを全て許可します。多くのアプリケーションやサービスで必須となります。

ノート: ファイアウォールでトラフィックを規制したくない場合 "eth1" など信頼できるインターフェイスを追加することもできます。ただし、ネットワーク上のあらゆる場所 (例えばルーターなど) からのあらゆるトラフィックを転送する NAT 構成にしている場合、他の設定は無関係になるため注意してください。
# iptables -A INPUT -i lo -j ACCEPT

3番目のルールでは "INVALID" ステートに一致する全てのトラフィックを破棄します。トラフィックは4つの "state" カテゴリに分けることができます: NEW, ESTABLISHED, RELATED, INVALID。これによって "stateless" ファイアウォールではなく "stateful" ファイアウォールと呼称しています。ステートは "nf_conntrack_*" カーネルモジュールによって追跡されます。カーネルモジュールはルールを追加したときにカーネルによって自動的にロードされます。

ノート:
  • 以下のルールはヘッダーやチェック、TCP フラグがおかしいパケットや不適切な ICMP メッセージ (ホストに何も送信していないのにポート到達不可など)、シーケンス番号予測攻撃などによるシーケンス外のパケットを全て破棄します。"DROP" ターゲットは何も返答せずにパケットを破棄します。それに対して REJECT は礼儀正しくパケットを拒否します。INVALID なパケットに対する適切な "REJECT" レスポンスはありえないため、パケットを受信したことを誰にも分からないように DROP を使っています。
  • ICMPv6 近隣探索パケットは未追跡のまま、たとえ壊れていなくても常に "INVALID" に分類されます。次のコマンドで承認することができます: iptables -A INPUT -p 41 -j ACCEPT
# 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 パケットから始まります。

ノート: SYN ビットが設定されていない NEW は INVALID ステートに含まれない唯一の不正な TCP フラグです。悪意のあるパケットである可能性がほとんどないため、破棄せずに、次のルールで TCP RESET を使って拒否するようにします。
# 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 ストリームを許可するルールを作成します。

ノート: リモートからアクセスする SSH や HTTP などのサービスの接続を許可するためのルールを追加する必要があります。

接続要求でポートを開く

ウェブサーバーへの 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) を見て下さい。

ポートノッキング

デフォルトではファイアウォールによって閉じられているポートを、外部から開く方法がポートノッキングです。予め決めておいたポートに連続して接続試行することで行います。正しいポート"ノック" (接続試行) がなされた場合、ファイアウォールは特定のポートを開いて接続できるようにします。詳しくはポートノッキングを見て下さい。

なりすまし攻撃からの防護

ノート: 現在 rp_filter はデフォルトで /usr/lib/sysctl.d/50-default.conf1 に設定されているため、以下の手順は必要ありません。

インターネットやローカルネットワークからの予約ローカルアドレスの使用は 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
ノート: 両方を有効にする意味はありません。netfilter の方法のほうが新しく IPv6 でも機能します。

非同期ルーティングを使用する構成の場合、代わりに 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/ のドキュメントやサンプルを読んでください。

ポートスキャナを騙す

ノート:
  • 以下の設定は DoS 攻撃に悪用される可能性があります。偽装した IP でパケットを送信してサービスへの接続をブロックさせてしまうという攻撃が考えられます。
  • conntrack モジュールによってパケットが INVALID と認識され正当な IP アドレスがブロックされる可能性もあります。ブラックリスト化を防ぐには、特定の宛先ポートへのパケットを全て許可してください。

攻撃者はポートスキャンを使ってコンピュータの開いているポートを確認します。ポートスキャンによって攻撃者は稼働しているサービスを調査することができ、場合によってはサービスの脆弱性を利用してくる可能性があります。

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 をブラックリストに入れる方法があります。また、ログファイルを監視して、試行失敗からブラックリストを作成する専用のデーモンを使うこともできます。

警告: IP ブラックリストを使うことで攻撃を多少止めることはできますが、別段にデーモンを使う必要があり、ログがちゃんと記録されてないと上手くいきません (攻撃者が執拗にサーバーを攻撃した場合、/var を含むパーティションが満杯になる可能性があります)。さらに、攻撃者にあなたの IP アドレスが知られてしまったら、攻撃者はソースヘッダを偽装してパケットを送りつけることができるため、サーバーから締め出される恐れもあります。ブルートフォース攻撃については SSH 鍵がスマートな解決法になるでしょう。

パスワード認証 (特に sshd) が何回も失敗した時にその IP を接続不可にするパッケージとして Fail2banSshguard が存在します。どちらも 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
...
ヒント: セットアップ後にルールを自己テストする場合、実際のブラックリスト登録によってテストが遅くなり、パラメーターの微調整が難しくなる可能性があります。cat /proc/net/xt_recent/sshbf を介して着信試行を監視できます。テスト中に自分の IP のブロックを解除するには、ルートが必要です echo / > /proc/net/xt_recent/sshbf

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 で拒否します。ただし、ファイアウォールの識別はポートスキャンアプリケーションの基本機能であり、大抵のポートスキャナは上記のように設定していても識別してしまうので注意してください。

次のステップでは、すべての新しい着信 ICMP エコー要求 (ping) に関するルールに適した IPv6 になるように、プロトコルと拡張子が変更されていることを確認します。

# 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.serviceip6tables.service有効化 して 起動 します。サービスのステータスをチェックし、ルールが正しくロードされていることを確認します。

NAT ゲートウェイの設定

このセクションでは NAT ゲートウェイについて扱います。ガイドの前半部分を読んで INPUT, OUTPUT, TCP, UDP チェインを設定していることが前提です。これまで全てのルールは filter テーブルに作成していました。このセクションでは、nat テーブルも使用していきます。

フィルターテーブルの設定

必要なチェインの作成

以下の設定では、2つの異なるチェインをフィルターテーブルで使用します: fw-interfacesfw-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-interfacesfw-open チェインの意味については後で nat テーブルで POSTROUTINGPREROUTING チェインを扱うときに説明します。

nat テーブルの設定

このセクションでは、出力インターフェイス (公のインターネット IP が付与されるインターフェイス) の名前を ppp0 とします。使用する出力インターフェイスが別の名前の場合、以下のルールで使われている名前もそれにあわせて変更するようにしてください。

POSTROUTING チェインの設定

次に、インターネットへの接続を誰に許可するかを定義する必要があります。eth0 にサブネット 192.168.0.0/24 (192.168.0.* の形式のすべてのアドレスを意味する) があるとします。まず、FORWARD テーブルでこのインターフェースのマシンを受け入れる必要があります。これが、上記の fw-interfaces チェーンを作成した理由です。

# iptables -A fw-interfaces -i eth0 -j ACCEPT

ここで、ローカル LAN アドレスではなく、送信元アドレスとしてパブリック IP アドレスを持つように、すべての発信パケットを変更する必要があります。これを行うには、MASQUERADE ターゲットを使用します。

# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE

上記の -o ppp0 パラメータは必ず必要なので忘れないでください。パラメータを記述しなかった場合、ネットワークが接続できなくなります。

インターフェイス eth1 上に別のサブネット 10.3.0.0/16 (すべてのアドレスが 10.3.*.* であることを意味します) があるとします。上記と同じルールを再度追加します。

# iptables -A fw-interfaces -i eth1 -j ACCEPT
# iptables -t nat -A POSTROUTING -s 10.3.0.0/16 -o ppp0 -j MASQUERADE

最後に パケット転送を有効化 してください (既に有効にしている場合は必要ありません)

これらのサブネットのマシンは、新しい NAT マシンをゲートウェイとして使用できるようになりました。dnsmasqbinddhcpd の組み合わせのような DNS と DHCP サーバーをセットアップして、クライアントマシンでのネットワーク設定の DNS 解決を簡略化することができます。これは、このガイドのトピックではありません。

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 デーモンを有効にすることで、起動時にルールがロードされるようにします。

参照