「Nftables」の版間の差分
細 英語版の否定の解釈を修正 |
Kusanaginoturugi (トーク | 投稿記録) →参照: update |
||
| (7人の利用者による、間の20版が非表示) | |||
| 3行目: | 3行目: | ||
[[en:nftables]] |
[[en:nftables]] |
||
{{Related articles start}} |
{{Related articles start}} |
||
{{Related|ファイアウォール}} |
|||
{{Related|iptables}} |
{{Related|iptables}} |
||
{{Related|Firewalld}} |
|||
{{Related articles end}} |
{{Related articles end}} |
||
[ |
[https://netfilter.org/projects/nftables/ nftables] は既存の ip-, ip6-, arp-, ebtables フレームワークを置き換える [[Wikipedia:Netfilter|Netfilter]] のプロジェクトです。新しいパケットフィルタリングフレームワーク、新しいユーザースペースユーティリティ (nft)、そして ip- と ip6tables の互換レイヤーを提供します。現行のフック、接続追跡システム、ユーザースペースのキューイングコンポーネント、そして netfilter のログサブシステムを使っています。 |
||
nftables は3つのメインコンポーネントから構成されています: カーネルの実装、libnl netlink communication そして nftables ユーザースペースフロントエンド。カーネルは netlink の設定インターフェイスだけでなく、小さなクラス言語インタプリタを使用するランタイムのルールセットの評価も提供します。libnl にはカーネルと通信するためのローレベルな関数が含まれています。nftables フロントエンドはユーザーが対話するものです。 |
nftables は3つのメインコンポーネントから構成されています: カーネルの実装、libnl netlink communication そして nftables ユーザースペースフロントエンド。カーネルは netlink の設定インターフェイスだけでなく、小さなクラス言語インタプリタを使用するランタイムのルールセットの評価も提供します。libnl にはカーネルと通信するためのローレベルな関数が含まれています。nftables フロントエンドはユーザーが対話するものです。 |
||
[ |
[https://wiki.nftables.org/wiki-nftables/index.php/Main_Page nftables の公式 wiki] には詳しい情報が載っています。 |
||
== インストール == |
== インストール == |
||
ユーザースペースユーティリティパッケージ {{Pkg|nftables}} を[[インストール]]してください。 |
|||
{{Pkg|iptables-legacy}} がインストールされている場合は、{{Pkg|iptables}} をインストールしてください。これにより {{Pkg|iptables-legacy}} が自動的にアンインストールされ、{{Pkg|nftables}} との競合を防ぎます。 |
|||
{{Note|{{Pkg|iptables}} パッケージは、実際には nftables ルールを作成し操作する {{ic|iptables}} コマンドの実装を提供します。ただし、古い {{Pkg|iptables-legacy}} ツールで作成されたルールは別のオブジェクトであり、それらが存在する場合、''iptables'' は警告を表示します。}} |
|||
=== フロントエンド === |
|||
{{Tip|ほとんどの [[iptables#Front-ends|iptables フロントエンド]]は nftables を直接または間接的にサポートしていませんが、将来的に対応する可能性があります。[https://www.spinics.net/lists/netfilter/msg58215.html] nftables と iptables の両方をサポートするグラフィカルフロントエンドの 1 つは [[firewalld]] です。[https://firewalld.org/2018/07/nftables-backend] [[ufw]] は互換レイヤー ''iptables-nft'' を介してサポートされています。[https://bugs.launchpad.net/ufw/+bug/1880453]}} |
|||
* {{App|[[firewalld]] (firewall-cmd)|ネットワークとファイアウォールゾーンの設定、およびファイアウォールルールの設定と構成を行うデーモンおよびコンソールインターフェイス。|https://firewalld.org/|{{Pkg|firewalld}}}} |
|||
* {{App|nft-blackhole|国別およびブラックリストによって nftables で IP をブロックするスクリプト / デーモン。|https://github.com/tomasz-c/nft-blackhole|{{AUR|nft-blackhole}}}} |
|||
* {{App|[[ufw]]|Ufw は Uncomplicated Firewall の略で、netfilter ファイアウォールを管理するためのプログラムです。|https://help.ubuntu.com/community/UFW|{{Pkg|ufw}}}} |
|||
* {{App|reaction|プログラムの出力から繰り返し出現するパターンをスキャンし、アクションを実行するデーモン。fail2ban の軽量な代替です。|https://framagit.org/ppom/reaction|{{AUR|reaction}}}} |
|||
== 使用方法 == |
== 使用方法 == |
||
{{Tip|すでに iptables ルールがある場合は、その iptables ルールを nftables ルールに変換できます。詳しくは [https://wiki.nftables.org/wiki-nftables/index.php/Moving_from_iptables_to_nftables] を参照してください。}} |
|||
nftables ではコマンドラインで作成される一時的なルールと、ファイルに保存して読み込まれる永続的なルールを区別していません。デフォルトファイルの {{ic|/etc/nftables.conf}} には "inet filter" という名前のシンプルな ipv4/ipv6 ファイアウォールテーブルが既に記述されています。 |
|||
'''nftables''' は、コマンドラインで作成された一時的なルールと、ファイルから読み込まれた、またはファイルに保存された永続的なルールを'''区別しません'''。 |
|||
{{ic|nftables.service}} を[[起動]]・[[有効化]]してください。 |
|||
すべてのルールは {{ic|nft}} コマンドラインユーティリティを使って作成または読み込む必要があります。 |
|||
以下のコマンドでルールセットを確認できます: |
|||
使用方法については [[#設定]] セクションを参照してください。 |
|||
現在の ruleset は次のコマンドで表示できます: |
|||
# nft list ruleset |
# nft list ruleset |
||
すべての ruleset を削除し、システムにファイアウォールがない状態にします: |
|||
{{Note|systemd サービスが正しく動作するように必要な nftables 関連のモジュール全てのエントリを含む {{ic|/etc/modules-load.d/nftables.conf}} を作成する必要があります。モジュールのリストは次のコマンドで取得可能です: {{bc|<nowiki>$ lsmod | grep '^nf'</nowiki>}} 作成していないと、{{ic|Error: Could not process rule: No such file or directory}} エラーで終了してしまいます。}} |
|||
# nft flush ruleset |
|||
== 設定 == |
|||
{{ic|nftables.service}} を[[再起動]]することで、{{ic|/etc/nftables.conf}} から ruleset を読み込みます。 |
|||
nftables のユーザースペースユーティリティ {{ic|nft}} は現在カーネルのためにルールセットを処理する前にほとんどのルールセットの評価を行います。ルールはチェインに保存され、チェインはテーブルに保存されます。下のセクションではルールを作成・編集する方法を説明します。 |
|||
=== シンプルなファイアウォール === |
|||
下のセクションで行った変更は全て一時的なものになります。変更を永続化するにはルールセットを {{ic|/etc/nftables.conf}} に保存してください (ルールセットは {{ic|nftables.service}} によって読み込まれます): |
|||
{{Pkg|nftables}} には、{{ic|/etc/nftables.conf}} ファイルに保存されたシンプルで安全なファイアウォール設定が付属しています。 |
|||
# nft list ruleset > /etc/nftables.conf |
|||
{{ic|nftables.service}} は、[[起動/有効化]]されたときに、そのファイルからルールを読み込みます。 |
|||
== 設定 == |
|||
nftables ユーザースペースユーティリティ {{ic|nft}} は、ruleset をカーネルに渡す前に、ルールセット評価の大部分を実行します。ルールはチェインに格納され、チェインはテーブルに格納されます。以下のセクションでは、これらの構造を作成および変更する方法を示します。 |
|||
{{Note|{{ic|nft list}} は変数の定義を出力しません。{{ic|/etc/nftables.conf}} に何か記述していた場合、定義は失われます。ルールによって使われていた変数は変数の値に置き換えられます。}} |
|||
ファイルから入力 |
ファイルから入力を読み込むには、{{ic|-f}}/{{ic|--file}} オプションを使用します: |
||
# nft - |
# nft --file ''filename'' |
||
既に読み込まれているルールは'''自動的には'''フラッシュされないことに注意してください。 |
|||
すべてのコマンドの完全な一覧については {{man|8|nft}} を参照してください。 |
|||
===テーブル=== |
===テーブル=== |
||
| 80行目: | 101行目: | ||
# nft add table ''family'' ''table'' |
# nft add table ''family'' ''table'' |
||
==== テーブルの表示 ==== |
==== テーブルの一覧表示 ==== |
||
全てのテーブルを表示するには: |
全てのテーブルを表示するには: |
||
| 90行目: | 111行目: | ||
指定したテーブルの全てのチェインとルールを表示するには: |
指定したテーブルの全てのチェインとルールを表示するには: |
||
# nft list table '' |
# nft list table ''family_type'' ''table_name'' |
||
例えば |
例えば、{{ic|inet}} family の {{ic|my_table}} テーブルのすべてのルールを一覧表示するには: |
||
# nft list table inet |
# nft list table inet my_table |
||
==== テーブルの削除 ==== |
==== テーブルの削除 ==== |
||
| 100行目: | 121行目: | ||
テーブルを削除するには: |
テーブルを削除するには: |
||
# nft delete table '' |
# nft delete table ''family_type'' ''table_name'' |
||
テーブル |
これにより、テーブル内のすべてのチェインが破棄されます。 |
||
==== テーブルのクリア ==== |
==== テーブルのクリア ==== |
||
| 108行目: | 129行目: | ||
テーブルから全てのルールを消去するには: |
テーブルから全てのルールを消去するには: |
||
# nft flush table '' |
# nft flush table ''family_type'' ''table_name'' |
||
===チェイン=== |
===チェイン=== |
||
| 116行目: | 137行目: | ||
チェインには2つのタイプがあります。''base'' チェインはネットワークスタックからのパケットのエントリポイントとなります。フックの値を指定することができます。''regular'' チェインはジャンプターゲットとして使用することができます。 |
チェインには2つのタイプがあります。''base'' チェインはネットワークスタックからのパケットのエントリポイントとなります。フックの値を指定することができます。''regular'' チェインはジャンプターゲットとして使用することができます。 |
||
以下のコマンドで使っている {{ic|'' |
以下のコマンドで使っている {{ic|''family_type''}} は全て任意であり、指定しなかった場合は {{ic|ip}} が使われます。 |
||
==== チェインの作成 ==== |
==== チェインの作成 ==== |
||
===== |
===== Base chain ===== |
||
base chain を追加するには、type、hook、priority の値を指定する必要があります: |
|||
以下のコマンドは {{ic|''table''}} という名前のテーブルに {{ic|''chain''}} という名前のレギュラーチェインを追加します: |
|||
# nft add chain ''family_type'' ''table_name'' ''chain_name'' '{ type ''chain_type'' hook ''hook_type'' priority ''priority_value'' ; policy ''policy'' ;}' |
|||
# nft add chain ''family'' ''table'' ''chain'' |
|||
{{ic|''chain_type''}} には {{ic|filter}}、{{ic|route}}、{{ic|nat}} を指定できます。 |
|||
例えば、{{ic|inet}} アドレスファミリーの {{ic|filter}} テーブルに {{ic|tcpchain}} という名前のレギュラーチェインを追加するには: |
|||
IPv4/IPv6/Inet address family では、{{ic|''hook_type''}} に {{ic|prerouting}}、{{ic|input}}、{{ic|forward}}、{{ic|output}}、{{ic|postrouting}} を指定できます。サポートされる ''family_type''、''chain_type''、''hook_type'' の組み合わせ一覧については {{man|8|nft|CHAINS}} を参照してください。 |
|||
# nft add chain inet filter tcpchain |
|||
{{ic|''priority_value''}} には priority 名または整数値を指定できます。標準 priority 名と値の一覧については {{man|8|nft|CHAINS}} を参照してください。数値が小さいチェインほど先に処理され、負の値も使用できます。[https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_types] |
|||
===== Base チェイン ===== |
|||
任意で、base chain には {{ic|''policy''}} ({{ic|drop}} またはデフォルトの {{ic|accept}}) を指定できます。これにより、チェイン内のルールで明示的に accept または refuse されなかったパケットに何が起こるかを定義します。 |
|||
ベースチェインを追加するにはフックとプライオリティの値を指定します: |
|||
例えば、入力パケットをフィルタリングする base chain を追加するには: |
|||
# nft add chain ''family'' ''table'' ''chain'' { type ''type'' hook ''hook'' priority ''priority'' \; } |
|||
# nft add chain inet my_table my_chain '{ type filter hook input priority 0; }' |
|||
{{ic|''type''}} は {{ic|filter}}, {{ic|route}}, {{ic|nat}} のどれかから選ぶことができます。 |
|||
上記のいずれでも {{ic|add}} を {{ic|create}} に置き換えると、新しいチェインを追加しますが、チェインが既に存在する場合はエラーを返します。 |
|||
IPv4/IPv6/Inet アドレスファミリーでは {{ic|''hook''}} は {{ic|prerouting}}, {{ic|input}}, {{ic|forward}}, {{ic|output}}, {{ic|postrouting}} のどれかになります。他のファミリーのフックについては {{man|8|nft}} を参照してください。 |
|||
===== Regular chain ===== |
|||
{{ic|''priority''}} には整数値を指定します。低い値のチェインが先に処理され、負の値を指定することもできます [https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_types]。 |
|||
次のコマンドは、{{ic|''table_name''}} という名前のテーブルに {{ic|''chain_name''}} という名前の regular chain を追加します: |
|||
例えば、input パケットをフィルタリングするベースチェインを追加するには: |
|||
# nft add chain |
# nft add chain ''family_type'' ''table_name'' ''chain_name'' |
||
例えば、{{ic|inet}} address family の {{ic|my_table}} テーブルに {{ic|my_tcp_chain}} という regular chain を追加するには: |
|||
{{ic|add}} を {{ic|create}} に置き換えると、チェインが既に存在するときにエラーが返ってくるようになります。 |
|||
# nft add chain inet my_table my_tcp_chain |
|||
==== ルールの表示 ==== |
|||
==== チェインの一覧表示 ==== |
|||
次のコマンドは、''family_type'' のすべてのチェインを、ルールなしで一覧表示します ([[#ルールの一覧表示]] を参照): |
|||
# nft list chain ''family'' ''table'' ''chain'' |
|||
# nft list chains ''family_type'' |
|||
例えば、{{ic|filter}} という名前の {{ic|inet}} テーブルに存在する {{ic|output}} という名前のチェインのルールを表示するには: |
|||
例えば、次のコマンドは IPv6 のチェインを一覧表示します: |
|||
# nft list chain inet filter output |
|||
# nft list chains ip6 |
|||
family_type を省略した場合、すべてのチェインが表示されます。 |
|||
==== チェインの編集 ==== |
==== チェインの編集 ==== |
||
| 162行目: | 187行目: | ||
チェインを編集したいときは、チェインの名前を指定して変更したいルールを定義します: |
チェインを編集したいときは、チェインの名前を指定して変更したいルールを定義します: |
||
# |
# nft chain ''family_type table_name chain_name'' '{ [ type ''chain_type'' hook ''hook_type'' device ''device_name'' priority ''priority_value'' ; policy ''policy_type'' ; ] }' |
||
例えば、デフォルトテーブルの |
例えば、デフォルトテーブル内の {{ic|my_input}} チェインの policy を {{ic|accept}} から {{ic|drop}} に変更するには: |
||
# nft chain inet |
# nft chain inet my_table my_input '{ policy drop ; }' |
||
==== チェインの削除 ==== |
==== チェインの削除 ==== |
||
| 172行目: | 197行目: | ||
チェインを削除するには: |
チェインを削除するには: |
||
# nft delete chain '' |
# nft delete chain ''family_type'' ''table_name'' ''chain_name'' |
||
削除するチェインにはルールやジャンプターゲットが含まれていてはいけません。 |
削除するチェインにはルールやジャンプターゲットが含まれていてはいけません。 |
||
| 180行目: | 205行目: | ||
チェインからルールを消去するには: |
チェインからルールを消去するには: |
||
# nft flush chain '' |
# nft flush chain ''family_type'' ''table_name'' ''chain_name'' |
||
=== ルール === |
=== ルール === |
||
| 192行目: | 217行目: | ||
チェインにルールを追加するには: |
チェインにルールを追加するには: |
||
# nft add rule '' |
# nft add rule ''family_type'' ''table_name'' ''chain_name'' handle ''handle_value'' ''statement'' |
||
ルールは {{ic|'' |
ルールは {{ic|''handle_value''}} の位置に追加されます。これは任意です。指定しない場合、ルールはチェインの末尾に追加されます。 |
||
ルール handle を確認するには、任意の有効な list コマンドに {{ic|--handle}} スイッチを追加する必要があります。このスイッチにより、{{ic|nft}} は出力に handle を表示します。{{ic|--numeric}} 引数は、未解決の IP アドレスなど、一部の数値出力を確認するのに便利です。 |
|||
{{hc|# nft --handle --numeric list chain inet my_table my_input|2=<nowiki> |
|||
table inet my_table { |
|||
chain input { |
|||
type filter hook input priority 0; |
|||
ip saddr 127.0.0.1 accept # handle 10 |
|||
} |
|||
} |
|||
</nowiki>}} |
|||
指定位置の前にルールを挿入するには: |
|||
# nft insert rule '' |
# nft insert rule ''family_type'' ''table_name'' ''chain_name'' handle ''handle_value'' ''statement'' |
||
{{ic|'' |
{{ic|''handle_value''}} が指定されていない場合、ルールはチェインの先頭に挿入されます。 |
||
===== 表現 ===== |
===== 表現 ===== |
||
| 260行目: | 296行目: | ||
ct: |
ct: |
||
state <new | established | related | invalid></nowiki> |
state <new | established | related | invalid></nowiki> |
||
ある意味では、iif と oif に対する iifname と oifname の違いは、static と dynamic の違いに似ています。または、プログラミング概念でいう definition と declaration、あるいは early binding と delayed binding に似ています。使用例と追加説明へのリンクについては [https://serverfault.com/questions/1059391/nftables-error-interface-does-not-exist-after-reboot] を参照してください。 |
|||
==== ルールの一覧表示 ==== |
|||
次のコマンドはチェイン内のすべてのルールを一覧表示します: |
|||
# nft list chain ''family_type'' ''table_name'' ''chain_name'' |
|||
例えば、{{ic|my_table}} という {{ic|inet}} テーブル内の {{ic|my_output}} というチェインのルールを一覧表示するには: |
|||
# nft list chain inet my_table my_output |
|||
====削除==== |
====削除==== |
||
個々のルールはハンドルを使わないと削除することができません。{{ic|nft --handle list}} コマンドを使うことでルールのハンドルを確認できます。{{ic|--handle}} スイッチを付けると、{{ic|nft}} はハンドルを出力するようになります。 |
|||
個々のルールはハンドルを使わないと削除することができません。{{ic|nft --handle list}} コマンドを使うことでルールのハンドルを確認できます。例えば次のような場合: |
|||
{{hc|# nft --handle --numeric list chain filter input|2= |
|||
{{hc|# nft --handle --numeric list chain inet my_table my_input|2=<nowiki> |
|||
<nowiki> |
|||
table |
table inet my_table { |
||
chain input { |
chain input { |
||
type filter hook input priority 0; |
type filter hook input priority 0; |
||
| 273行目: | 320行目: | ||
} |
} |
||
} |
} |
||
</nowiki> |
</nowiki>}} |
||
}} |
|||
# nft delete rule fltrTable input handle 10 |
|||
次のコマンドで削除できます: |
|||
{{ic|nft flush table}} コマンドを使うことでテーブルの全てのチェインをフラッシュできます。個別のチェインをフラッシュするときは {{ic|nft flush chain}} または {{ic|nft delete rule}} コマンドを使います。 |
|||
# nft flush table foo |
|||
# nft delete rule inet my_table my_input handle 10 |
|||
# nft flush chain foo bar |
|||
# nft delete rule ip6 foo bar |
|||
テーブル内のすべてのチェインは {{ic|nft flush table}} コマンドでフラッシュできます。個別のチェインは {{ic|nft flush chain}} または {{ic|nft delete rule}} コマンドでフラッシュできます。 |
|||
# nft flush table ''table_name'' |
|||
# nft flush chain ''family_type'' ''table_name'' ''chain_name'' |
|||
# nft delete rule ''family_type'' ''table_name'' ''chain_name'' |
|||
最初のコマンドは、ip {{ic|''table_name''}} テーブル内のすべてのチェインをフラッシュします。2 番目のコマンドは、{{ic|''family_type''}} {{ic|''table_name''}} テーブル内の {{ic|''chain_name''}} チェインをフラッシュします。3 番目のコマンドは、{{ic|''family_type''}} {{ic|''table_name''}} テーブル内の {{ic|''chain_name''}} チェインのすべてのルールを削除します。 |
|||
=== セット === |
|||
[https://wiki.nftables.org/wiki-nftables/index.php/Sets セットには名前付きセットと匿名セットがあります]。セットは 1 つ以上の要素で構成され、要素はカンマで区切られ、波括弧で囲まれます。匿名セットはルールに埋め込まれ、更新できません。ルールを削除して再追加する必要があります。例えば、次の dports セットから "http" だけを削除することはできません: |
|||
# nft add rule ip6 filter input tcp dport {telnet, http, https} accept |
|||
名前付きセットは更新でき、型付けやフラグ付けが可能です。''sshguard'' は、ブロックされたホストの IP アドレスに名前付きセットを使用します。 |
|||
table ip sshguard { |
|||
set attackers { |
|||
type ipv4_addr |
|||
flags interval |
|||
elements = { 1.2.3.4 } |
|||
} |
|||
セットに要素を''追加''または''削除''するには、次のようにします: |
|||
# nft add element ip sshguard attackers { 5.6.7.8/32 } |
|||
# nft delete element ip sshguard attackers { 1.2.3.4/32 } |
|||
''ipv4_addr'' 型には CIDR netmask を含められることに注意してください (ここでの {{ic|/32}} は必須ではありませんが、完全性のために含めています)。また、ここで {{ic|TABLE ip sshguard { SET attackers }<nowiki/>}} によって定義されたセットは、{{ic|ip sshguard attackers}} として参照されることにも注意してください。 |
|||
{{Tip|[[systemd-networkd]] 接続は、事前定義された名前付きセットにホスト IP アドレス、ネットワークプレフィックス、インターフェイスインデックスを投入するように設定できます。詳しくは {{man|5|systemd.network|[ADDRESS] SECTION OPTIONS}} の {{ic|NFTSet{{=}}}} の説明と [[#systemd-networkd を使った動的名前付きセット]] の例を参照してください。}} |
|||
===アトミックリロード=== |
===アトミックリロード=== |
||
現在のルールセットをフラッシュする: |
現在のルールセットをフラッシュする: |
||
# echo "flush ruleset" > /tmp/nftables |
# echo "flush ruleset" > /tmp/nftables |
||
現在のルールセットをダンプする: |
現在のルールセットをダンプする: |
||
# nft list ruleset >> /tmp/nftables |
# nft list ruleset >> /tmp/nftables |
||
{{ic|/tmp/nftables}} を編集して次のコマンドで変更を適用: |
{{ic|/tmp/nftables}} を編集して次のコマンドで変更を適用: |
||
# nft -f /tmp/nftables |
# nft -f /tmp/nftables |
||
| 298行目: | 379行目: | ||
flush ruleset |
flush ruleset |
||
table inet |
table inet my_table { |
||
set LANv4 { |
|||
chain input { |
|||
type ipv4_addr |
|||
type filter hook input priority 0; |
|||
flags interval |
|||
elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } |
|||
# accept any localhost traffic |
|||
} |
|||
iif lo accept |
|||
set LANv6 { |
|||
type ipv6_addr |
|||
flags interval |
|||
elements = { fd00::/8, fe80::/10 } |
|||
# accept traffic originated from us |
|||
} |
|||
ct state established,related accept |
|||
chain my_input_lan { |
|||
# activate the following line to accept common local services |
|||
udp sport 1900 udp dport >= 1024 meta pkttype unicast limit rate 4/second burst 20 packets accept comment "Accept UPnP IGD port mapping reply" |
|||
#tcp dport { 22, 80, 443 } ct state new accept |
|||
udp sport netbios-ns udp dport >= 1024 meta pkttype unicast accept comment "Accept Samba Workgroup browsing replies" |
|||
# accept neighbour discovery otherwise IPv6 connectivity breaks. |
|||
ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept |
|||
} |
|||
chain my_input { |
|||
type filter hook input priority filter; policy drop; |
|||
iif lo accept comment "Accept any localhost traffic" |
|||
ct state invalid drop comment "Drop invalid connections" |
|||
fib daddr . iif type != { local, broadcast, multicast } drop comment "Drop packets if the destination IP address is not configured on the incoming interface (strong host model)" |
|||
ct state { established, related } accept comment "Accept traffic originated from us" |
|||
meta l4proto { icmp, ipv6-icmp } accept comment "Accept ICMP" |
|||
ip protocol igmp accept comment "Accept IGMP" |
|||
udp dport mdns ip6 daddr ff02::fb accept comment "Accept mDNS" |
|||
udp dport mdns ip daddr 224.0.0.251 accept comment "Accept mDNS" |
|||
ip6 saddr @LANv6 jump my_input_lan comment "Connections from private IP address ranges" |
|||
ip saddr @LANv4 jump my_input_lan comment "Connections from private IP address ranges" |
|||
counter comment "Count any other traffic" |
|||
} |
|||
chain my_forward { |
|||
type filter hook forward priority filter; policy drop; |
|||
# Drop everything forwarded to us. We do not forward. That is routers job. |
|||
} |
|||
chain my_output { |
|||
type filter hook output priority filter; policy accept; |
|||
# Accept every outbound connection |
|||
} |
|||
# count and drop any other traffic |
|||
counter drop |
|||
} |
|||
} |
} |
||
</nowiki>}} |
</nowiki>}} |
||
{{Tip|[[systemd-networkd]] を使用していてローカルネットワークに接続している場合、{{man|5|systemd.network}} オプション {{ic|NFTSet{{=}}}} を使って接続のネットワークプレフィックスを取得することで、ネットワークサブネットのハードコーディングを避けられます。[[#systemd-networkd を使った動的名前付きセット]] を参照してください。}} |
|||
=== シンプルな IPv4/IPv6 ファイアウォール === |
|||
=== サーバー === |
|||
{{hc|firewall.rules|2=<nowiki> |
|||
# A simple firewall |
|||
{{hc|/etc/nftables.conf|2=<nowiki> |
|||
flush ruleset |
flush ruleset |
||
table inet |
table inet my_table { |
||
set LANv4 { |
|||
type ipv4_addr |
|||
type filter hook input priority 0; policy drop; |
|||
flags interval |
|||
elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } |
|||
} |
|||
set LANv6 { |
|||
type ipv6_addr |
|||
flags interval |
|||
elements = { fd00::/8, fe80::/10 } |
|||
} |
|||
chain my_input_lan { |
|||
meta l4proto { tcp, udp } th dport 2049 accept comment "Accept NFS" |
|||
udp dport netbios-ns accept comment "Accept NetBIOS Name Service (nmbd)" |
|||
udp dport netbios-dgm accept comment "Accept NetBIOS Datagram Service (nmbd)" |
|||
tcp dport netbios-ssn accept comment "Accept NetBIOS Session Service (smbd)" |
|||
tcp dport microsoft-ds accept comment "Accept Microsoft Directory Service (smbd)" |
|||
udp sport { bootpc, 4011 } udp dport { bootps, 4011 } accept comment "Accept PXE" |
|||
udp dport tftp accept comment "Accept TFTP" |
|||
} |
|||
chain my_input { |
|||
type filter hook input priority filter; policy drop; |
|||
iif lo accept comment "Accept any localhost traffic" |
|||
ct state invalid drop comment "Drop invalid connections" |
|||
fib daddr . iif type != { local, broadcast, multicast } drop comment "Drop packets if the destination IP address is not configured on the incoming interface (strong host model)" |
|||
ct state { established, related } accept comment "Accept traffic originated from us" |
|||
meta l4proto { icmp, ipv6-icmp } accept comment "Accept ICMP" |
|||
ip protocol igmp accept comment "Accept IGMP" |
|||
udp dport mdns ip6 daddr ff02::fb accept comment "Accept mDNS" |
|||
udp dport mdns ip daddr 224.0.0.251 accept comment "Accept mDNS" |
|||
ip6 saddr @LANv6 jump my_input_lan comment "Connections from private IP address ranges" |
|||
# established/related connections |
|||
ip saddr @LANv4 jump my_input_lan comment "Connections from private IP address ranges" |
|||
ct state established,related accept |
|||
tcp dport ssh accept comment "Accept SSH on port 22" |
|||
# invalid connections |
|||
ct state invalid drop |
|||
# loopback interface |
|||
iif lo accept |
|||
tcp dport ipp accept comment "Accept IPP/IPPS on port 631" |
|||
# ICMP |
|||
# routers may also want: mld-listener-query, nd-router-solicit |
|||
ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept |
|||
ip protocol icmp icmp type { destination-unreachable, router-advertisement, time-exceeded, parameter-problem } accept |
|||
meta l4proto { tcp, udp } th dport { http, https, 8008, 8080 } accept comment "Accept HTTP (ports 80, 443, 8008, 8080)" |
|||
# SSH (port 22) |
|||
tcp dport ssh accept |
|||
udp sport bootpc udp dport bootps ip saddr 0.0.0.0 ip daddr 255.255.255.255 accept comment "Accept DHCPDISCOVER (for DHCP-Proxy)" |
|||
# HTTP (ports 80 & 443) |
|||
tcp dport { http, https } accept |
|||
} |
} |
||
chain |
chain my_forward { |
||
type filter hook forward priority |
type filter hook forward priority filter; policy drop; |
||
# Drop everything forwarded to us. We do not forward. That is routers job. |
|||
} |
} |
||
chain |
chain my_output { |
||
type filter hook output priority |
type filter hook output priority filter; policy accept; |
||
# Accept every outbound connection |
|||
} |
} |
||
| 363行目: | 505行目: | ||
</nowiki>}} |
</nowiki>}} |
||
===レート制限 |
=== レート制限 === |
||
{{ |
{{bc|1=<nowiki> |
||
table inet |
table inet my_table { |
||
chain |
chain my_input { |
||
type filter hook input priority |
type filter hook input priority filter; policy drop; |
||
iif lo accept comment "Accept any localhost traffic" |
|||
# no ping floods: |
|||
ct state invalid drop comment "Drop invalid connections" |
|||
ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate 10/second accept |
|||
fib daddr . iif type != { local, broadcast, multicast } drop comment "Drop packets if the destination IP address is not configured on the incoming interface (strong host model)" |
|||
ip protocol icmp icmp type echo-request limit rate 10/second accept |
|||
meta l4proto icmp icmp type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods" |
|||
ct state established,related accept |
|||
meta l4proto ipv6-icmp icmpv6 type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods" |
|||
ct state invalid drop |
|||
ct state { established, related } accept comment "Accept traffic originated from us" |
|||
iif lo accept |
|||
meta l4proto { icmp, ipv6-icmp } accept comment "Accept ICMP" |
|||
# avoid brute force on ssh: |
|||
ip protocol igmp accept comment "Accept IGMP" |
|||
tcp dport ssh limit rate 15/minute accept |
|||
tcp dport ssh ct state new limit rate 15/minute accept comment "Avoid brute force on SSH" |
|||
} |
|||
chain forward { |
|||
type filter hook forward priority 0; policy drop; |
|||
} |
|||
chain output { |
|||
type filter hook output priority 0; policy accept; |
|||
} |
} |
||
| 398行目: | 534行目: | ||
設定ファイルでジャンプを使うときは、先にターゲットチェインを定義する必要があります。そうしないと {{ic|Error: Could not process rule: No such file or directory}} というエラーが発生します。 |
設定ファイルでジャンプを使うときは、先にターゲットチェインを定義する必要があります。そうしないと {{ic|Error: Could not process rule: No such file or directory}} というエラーが発生します。 |
||
{{hc|jump.rules|2= |
|||
<nowiki> |
{{bc|1=<nowiki> |
||
table inet |
table inet my_table { |
||
chain web { |
chain web { |
||
tcp dport http accept |
tcp dport http accept |
||
tcp dport 8080 accept |
tcp dport 8080 accept |
||
} |
} |
||
chain |
chain my_input { |
||
type filter hook input priority |
type filter hook input priority filter; |
||
ip saddr 10.0.2.0/24 jump web |
ip saddr 10.0.2.0/24 jump web |
||
drop |
drop |
||
} |
} |
||
} |
} |
||
</nowiki> |
</nowiki>}} |
||
}} |
|||
=== インターフェイスによってルールを変える === |
=== インターフェイスによってルールを変える === |
||
| 418行目: | 553行目: | ||
複数のネットワークインターフェイスが存在する場合、それぞれのインターフェイスごとに別々のフィルターチェインを設定したい場合があるかもしれません。例えば、ホームルーターを構築するとき、LAN 上でアクセスできるウェブサーバーを実行しつつ ({{ic|nsp3s0}} インターフェイス)、インターネットからはアクセスできないようにしたい場合 ({{ic|enp2s0}} インターフェイス) などは以下のように設定します: |
複数のネットワークインターフェイスが存在する場合、それぞれのインターフェイスごとに別々のフィルターチェインを設定したい場合があるかもしれません。例えば、ホームルーターを構築するとき、LAN 上でアクセスできるウェブサーバーを実行しつつ ({{ic|nsp3s0}} インターフェイス)、インターネットからはアクセスできないようにしたい場合 ({{ic|enp2s0}} インターフェイス) などは以下のように設定します: |
||
{{bc|<nowiki> |
|||
table inet my_table { |
|||
chain input { # this chain serves as a dispatcher |
|||
chain my_input { # this chain serves as a dispatcher |
|||
type filter hook input priority 0; |
|||
type filter hook input priority filter; policy drop; |
|||
iif lo accept # always accept loopback |
|||
iifname enp2s0 jump input_enp2s0 |
|||
iifname enp3s0 jump input_enp3s0 |
|||
iif lo accept comment "always accept loopback" |
|||
reject with icmp type port-unreachable # refuse traffic from all other interfaces |
|||
iifname enp2s0 jump my_input_public |
|||
iifname enp3s0 jump my_input_private |
|||
} |
} |
||
chain |
chain my_input_public { # rules applicable to public interface interface |
||
ct state {established,related} accept |
ct state {established,related} accept |
||
ct state invalid drop |
ct state invalid drop |
||
udp dport bootpc accept |
udp dport bootpc accept |
||
tcp dport bootpc accept |
tcp dport bootpc accept |
||
reject with icmp type port-unreachable # all other traffic |
|||
} |
} |
||
chain |
chain my_input_private { |
||
ct state {established,related} accept |
ct state {established,related} accept |
||
ct state invalid drop |
ct state invalid drop |
||
| 442行目: | 575行目: | ||
tcp port http accept |
tcp port http accept |
||
tcp port https accept |
tcp port https accept |
||
reject with |
reject with icmpx port-unreachable comment "all other traffic" |
||
} |
} |
||
chain |
chain my_output { # we let everything out |
||
type filter hook output priority |
type filter hook output priority filter; |
||
accept |
accept |
||
} |
} |
||
} |
|||
}</nowiki> |
|||
</nowiki>}} |
|||
あるいは、単一の upstream interface に対する {{ic|iifname}} statement だけを選び、それ以外のすべてのインターフェイスに対するデフォルトルールを 1 か所に置くこともできます。各インターフェイスごとに dispatch する必要はありません。 |
|||
=== マスカレード === |
=== マスカレード === |
||
| 458行目: | 592行目: | ||
{{ic|masquerade}} を使用するには: |
{{ic|masquerade}} を使用するには: |
||
* カーネルコンフィグで以下のマスカレード設定が有効になっている必要があります。 |
|||
* masquerading がカーネルで有効になっていることを確認してください (デフォルトカーネルを使用している場合は true です)。そうでない場合は、カーネル設定で {{ic|1=CONFIG_NFT_MASQ=m}} を設定します。 |
|||
CONFIG_NFT_MASQ=m |
|||
* {{ic|masquerade}} キーワードは {{ic|nat}} type のチェインでのみ使用できます。 |
|||
* masquerading は source NAT の一種であるため、output path でのみ動作します。 |
|||
2 つのインターフェイスを持つマシンの例です: LAN は {{ic|enp3s0}} に接続され、public internet は {{ic|enp2s0}} に接続されています: |
|||
* {{ic|masquerade}} キーワードは {{ic|nat}} タイプのチェインでのみ使うことができ、{{ic|inet}} ファミリーのテーブルでは利用できません。{{ic|ip}} ファミリーや {{ic|ip6}} ファミリーのテーブルを使ってください。 |
|||
* マスカレードは一種のソース NAT であり、出力パスでのみ機能します。 |
|||
{{bc|<nowiki> |
|||
2つのインターフェイスが存在し {{ic|nsp3s0}} が LAN に接続され、{{ic|enp2s0}} がインターネットに接続されているマシンでの設定例: |
|||
table inet my_nat { |
|||
chain my_masquerade { |
|||
<nowiki>table ip nat { |
|||
type nat hook postrouting priority srcnat; |
|||
chain prerouting { |
|||
oifname "enp2s0" masquerade |
|||
type nat hook prerouting priority 0; |
|||
} |
} |
||
} |
|||
chain postrouting { |
|||
</nowiki>}} |
|||
type nat hook postrouting priority 0; |
|||
oifname "enp0s2" masquerade |
|||
テーブル type が {{ic|inet}} なので、IPv4 と IPv6 の両方のパケットが masquerade されます。IPv6 は追加の address space により NAT が不要なため、IPv4 パケットだけを masquerade したい場合は、{{ic|meta nfproto ipv4}} expression を {{ic|oifname "enp2s0"}} の前に使用するか、テーブル type を {{ic|ip}} に変更します。 |
|||
} |
|||
}</nowiki> |
|||
=== NAT とポートフォワーディング === |
|||
この例では、eth0 という WAN インターフェイスを通って出ていくトラフィックを masquerade し、ポート 22 と 80 を {{ic|10.0.0.2}} に転送します。[[sysctl]] によって {{ic|net.ipv4.ip_forward}} を {{ic|1}} に設定する必要があります。 |
|||
{{bc| |
|||
table nat { |
|||
chain prerouting { |
|||
type nat hook prerouting priority dstnat; |
|||
iif eth0 tcp dport {22, 80} dnat to 10.0.0.2 |
|||
} |
|||
chain postrouting { |
|||
type nat hook postrouting priority srcnat; |
|||
oif eth0 masquerade |
|||
} |
|||
} |
|||
}} |
|||
=== IP ごとの新規接続数をカウント === |
|||
HTTPS 接続をカウントするには、次のスニペットを使用します: |
|||
{{hc|/etc/nftables.conf| |
|||
table inet filter { |
|||
set https { |
|||
type ipv4_addr; |
|||
flags dynamic; |
|||
size 65536; |
|||
timeout 60m; |
|||
} |
|||
chain input { |
|||
type filter hook input priority filter; |
|||
ct state new meta l4proto { tcp, udp } th dport 443 update @https { ip saddr counter } |
|||
} |
|||
} |
|||
}} |
|||
カウンターを表示するには、{{ic|nft list set inet filter https}} を実行してください。 |
|||
=== 動的 blackhole === |
|||
このスニペットは、10/second の制限を超えた source IP (または /64 IPv6 range) からのすべての HTTPS 接続を 1 分間 drop します。 |
|||
{{hc|/etc/nftables.conf| |
|||
table inet dev { |
|||
set blackhole_ipv4 { |
|||
type ipv4_addr; |
|||
flags dynamic, timeout; |
|||
size 65536; |
|||
} |
|||
set blackhole_ipv6 { |
|||
type ipv6_addr; |
|||
flags dynamic, timeout; |
|||
size 65536; |
|||
} |
|||
chain input { |
|||
type filter hook input priority filter; policy accept; |
|||
ct state new meta l4proto { tcp, udp } th dport 443 \ |
|||
meter flood_ipv4 size 128000 { ip saddr timeout 10s limit rate over 10/second } \ |
|||
add @blackhole_ipv4 { ip saddr timeout 1m } |
|||
ct state new meta l4proto { tcp, udp } th dport 443 \ |
|||
meter flood_ipv6 size 128000 { ip6 saddr and ffff:ffff:ffff:ffff:: timeout 10s limit rate over 10/second } \ |
|||
add @blackhole_ipv6 { ip6 saddr and ffff:ffff:ffff:ffff:: timeout 1m } |
|||
ip saddr @blackhole_ipv4 counter drop |
|||
ip6 saddr and ffff:ffff:ffff:ffff:: @blackhole_ipv6 counter drop |
|||
} |
|||
} |
|||
}} |
|||
blackhole された IP を表示するには、{{ic|nft list set inet dev blackhole_ipv''X''}} を実行してください。 |
|||
== ヒントとテクニック == |
== ヒントとテクニック == |
||
=== 現在の rule set の保存 === |
|||
{{ic|nft list ruleset}} コマンドの出力は、そのまま有効な入力ファイルとしても使用できます。現在の rule set をファイルに保存し、後で読み戻すことができます。 |
|||
# nft -s list ruleset | tee ''filename'' |
|||
{{Note|元のファイルで変数定義を使っていた場合でも、{{ic|nft list}} は変数定義を出力しません。変数は失われます。ルール内で使われていた変数は、その値に置き換えられます。}} |
|||
=== シンプルなステートフルファイアウォール === |
=== シンプルなステートフルファイアウォール === |
||
| 556行目: | 770行目: | ||
[[Sshguard]] はブルートフォース攻撃を検出して一時的に IP アドレスに基づきブロックするようにファイアウォールを編集します。Sshguard で nftables を使うように設定する方法は [[Sshguard#nftables]] を見てください。 |
[[Sshguard]] はブルートフォース攻撃を検出して一時的に IP アドレスに基づきブロックするようにファイアウォールを編集します。Sshguard で nftables を使うように設定する方法は [[Sshguard#nftables]] を見てください。 |
||
=== トラフィックのログ記録 === |
|||
{{ic|log}} action を使ってパケットをログに記録できます。すべての受信 traffic をログに記録する最も単純なルールは次のとおりです: |
|||
# nft add rule inet filter input log |
|||
詳しくは [https://wiki.nftables.org/wiki-nftables/index.php/Logging_traffic nftables wiki] を参照してください。 |
|||
=== Monitor === |
|||
すべてのイベントを監視し、native nft format で報告します。 |
|||
# nft monitor |
|||
{{man|8|nft|MONITOR}} を参照してください。 |
|||
==== ruleset debugging trace temporary ==== |
|||
'''meta nftrace set 1''' は ruleset packet tracing を on/off します。trace を見るには [[#Monitor|monitor trace]] コマンドを使用します。 |
|||
別の shell で、interactive shell 内にファイルを "include" します: |
|||
# nft -i |
|||
nft> include "/root/nftables.trace" |
|||
必要に応じて調整した例です: |
|||
{{hc|/root/nftables.trace| |
|||
add table ip temp-trace {comment "Temporary table!!"; flags owner;} |
|||
add chain ip temp-trace icmp-prerouting { type filter hook prerouting priority raw - 1 ; } |
|||
add rule ip temp-trace icmp-prerouting ''ip protocol icmp'' '''meta nftrace set 1''' |
|||
}} |
|||
このファイルは一時テーブル (''flags owner'') を追加します。そのため、呼び出し元の interactive nft プロセスが閉じられると自動的に削除されます。Base Chain は用途に応じて調整する必要があります。複数のチェインや複数の "meta nftrace set 1" ルールを作成できます。"ip protocol icmp" は単なる例であり、必須ではありません。同様の効果を得る方法は多数あります。この方法の利点は、interactive shell を閉じることで以前の状態が自動的に復元されることと、ファイル内にエラーがある場合に何も実行されないことです。 |
|||
詳しくは [https://wiki.nftables.org/wiki-nftables/index.php/Ruleset_debug/tracing nftables wiki] と、その処理を自動化して色付けする [https://github.com/aborrero/nftables-tracer python tool] を参照してください。 |
|||
=== iptables-nft の使用 === |
|||
{{Accuracy|nftables は legacy iptables object が読み込まれている場合に警告するため、legacy iptables と nftables を同時に使うことが「完全に問題なく動作する」とは言えません。}} |
|||
古い iptables 言語は Linux ドキュメントでは依然としてかなり支配的であり、Docker のネットワークなど、iptables に依存して動作するものも少なくありません。legacy iptables と nftables を同時に使うことも可能ではありますが、iptables-nft の変換を使うことが推奨されます。理由は次のとおりです: |
|||
* すべてを新しく、より効率的で、ロックを必要としないフレームワークの同じ場所に配置します。 |
|||
* 競合をチェックします。 |
|||
nftables で古い iptables 言語を使用する方法は 2 つあります: |
|||
* {{ic|iptables-translate}} と {{ic|iptables-restore-translate}} ({{ic|ip6tables}}、{{ic|ebtables}} なども同様) は、iptables 言語を受け取り nft 言語を出力します。実行中の nft 設定は変更しません。{{man|8|xtables-translate}} を参照してください。 |
|||
: 後で保守したい設定については、{{ic|-translate}} ツールを使い、その結果のコードを既存のルールに統合するのがよいでしょう。例えば、[[シンプルなステートフルファイアウォール]]やインターネット上で便利なものを見つけた場合、それらを nft 設定に入れられるように変換できます。 |
|||
* {{ic|iptables}} と {{ic|iptables-restore}} ({{ic|ip6tables}} なども同様) は上記の変換を使い、さらに実行中の nft 設定に反映します。通常の iptables と同じように統計情報も提供します。{{man|8|xtables-nft}} を参照してください。 |
|||
: これらのコマンドは、やるべきことを考えれば十分にうまく動作します。単純な使い方では「そのまま動く」はずですが、ときどき手動でのデバッグが必要になることがあります。 |
|||
{{Note|translator は iptables 言語の大部分をカバーしていますが、すべてではありません。一部の iptables ルールは組み合わせて動作し、translator が正しく変換するには文脈が必要です。そのため、変換結果が空になる行があっても慌てないでください。}} |
|||
=== systemd-networkd を使った動的名前付きセット === |
|||
[[systemd-networkd]] の接続は、{{ic|NFTSet{{=}}}} オプションを使用して、事前定義された名前付きセットにホスト IP アドレス、ネットワークプレフィックス、インターフェイスインデックスを投入できます。これにより、{{ic|/etc/nftables.conf}} にそれらをハードコーディングすることを避けられます。{{ic|NFTSet{{=}}}} オプションは、{{ic|[Address]}}、{{ic|[DHCPv4]}}、{{ic|[DHCPv6]}}、{{ic|[IPv6AcceptRA]}} セクションでサポートされています。{{man|5|systemd.network|[ADDRESS] SECTION OPTIONS}} を参照してください。 |
|||
例えば、ローカルネットワークからの接続 (IP アドレスが DHCP または SLAAC で割り当てられる場合) を別の {{ic|my_input_lan}} チェインで処理するには: |
|||
{{hc|/etc/nftables.conf|2= |
|||
... |
|||
table inet my_table { |
|||
set eth_ipv4_prefix { |
|||
type ipv4_addr |
|||
flags interval |
|||
comment "Populated by systemd-networkd" |
|||
} |
|||
set eth_ipv6_prefix { |
|||
type ipv6_addr |
|||
flags interval |
|||
comment "Populated by systemd-networkd" |
|||
elements = { fe80::/10 } |
|||
} |
|||
set eth_ifindex { |
|||
type iface_index |
|||
comment "Populated by systemd-networkd" |
|||
} |
|||
... |
|||
chain my_input { |
|||
type filter hook input priority filter; policy drop; |
|||
iif @eth_ifindex ip6 saddr @eth_ipv6_prefix jump my_input_lan comment "Connections from LAN" |
|||
iif @eth_ifindex ip saddr @eth_ipv4_prefix jump my_input_lan comment "Connections from LAN" |
|||
} |
|||
... |
|||
} |
|||
}} |
|||
{{hc|/etc/systemd/network/my-network.network|2= |
|||
... |
|||
[DHCPv4] |
|||
NFTSet=prefix:inet:my_table:eth_ipv4_prefix |
|||
NFTSet=ifindex:inet:my_table:eth_ifindex |
|||
[DHCPv6] |
|||
NFTSet=prefix:inet:my_table:eth_ipv6_prefix |
|||
NFTSet=ifindex:inet:my_table:eth_ifindex |
|||
[IPv6AcceptRA] |
|||
NFTSet=prefix:inet:my_table:eth_ipv6_prefix |
|||
NFTSet=ifindex:inet:my_table:eth_ifindex |
|||
... |
|||
}} |
|||
== トラブルシューティング == |
|||
=== Docker と共に使う === |
|||
{{Note| |
|||
* 次のセットアップでは、{{ic|--net host --privileged}} を使用してもコンテナ内で {{ic|AF_BLUETOOTH}} などのプロトコルを利用できなくなります。 |
|||
* ルートレス Dockerコンテナはすでに別のネットワーク名前空間で実行されています。何もする必要がないかもしれません。 |
|||
}} |
|||
nftables を使用すると、[[Docker]] のネットワーク (おそらく他のコンテナランタイムも同様) に干渉する可能性があります。 |
|||
iptables ルールにパッチを適用して定義されたサービス開始順序を確保するか、docker の使用が非常に制限される dockerのiptablesの管理を完全に無効にするなど、さまざまな回避策がインターネット上で見つかります。 |
|||
(ポートフォワーディングや docker-compose を考えてください) |
|||
信頼できる方法は、docker を別のネットワーク名前空間で実行させ、そこで任意の処理を実行できるようにすることです。 |
|||
Docker が nftables と iptables ルールを混在させないように、{{Pkg|iptables-nft}} を'''使用しない'''方が良いでしょう。 |
|||
以下の docker サービス [[ドロップインファイル]] を使用してください: |
|||
{{hc|/etc/systemd/system/docker.service.d/netns.conf|2= |
|||
[Service] |
|||
PrivateNetwork=yes |
|||
PrivateMounts=No |
|||
# cleanup |
|||
ExecStartPre=-nsenter -t 1 -n -- ip link delete docker0 |
|||
# add veth |
|||
ExecStartPre=nsenter -t 1 -n -- ip link add docker0 type veth peer name docker0_ns |
|||
ExecStartPre=sh -c 'nsenter -t 1 -n -- ip link set docker0_ns netns "$$BASHPID" && true' |
|||
ExecStartPre=ip link set docker0_ns name eth0 |
|||
# bring host online |
|||
ExecStartPre=nsenter -t 1 -n -- ip addr add 10.0.0.1/24 dev docker0 |
|||
ExecStartPre=nsenter -t 1 -n -- ip link set docker0 up |
|||
# bring ns online |
|||
ExecStartPre=ip addr add 10.0.0.100/24 dev eth0 |
|||
ExecStartPre=ip link set eth0 up |
|||
ExecStartPre=ip route add default via 10.0.0.1 dev eth0 |
|||
}} |
|||
セットアップにおいてIPアドレス {{ic|10.0.0.*}} が適切でない場合は、調整してください。 |
|||
以下のポストルーティングルールで、{{ic|docker0}} のIPフォワーディングを有効にし、NATを設定します: |
|||
iifname docker0 oifname eth0 masquerade |
|||
次に、[[インターネット共有#パケット転送の有効化|kernel IP forwarding]] が有効になっていることを確認します。 |
|||
これで、nftables を使用して {{ic|docker0}} インターフェイスのファイアウォールとポートフォワーディングを干渉することなくセットアップできるようになります。 |
|||
==参照== |
==参照== |
||
* [https://wiki.nftables.org/ netfilter nftables wiki] |
* [https://wiki.nftables.org/ netfilter nftables wiki] |
||
* [[debian:nftables]] |
|||
* [https://lwn.net/Articles/324251/ nftables の最初のリリース] |
|||
* [[gentoo:nftables]] |
|||
* [https://home.regit.org/netfilter-en/nftables-quick-howto/ nftables クイックハウツー] |
|||
* [https://lwn.net/Articles/ |
* [https://lwn.net/Articles/324251/ First release of nftables] |
||
* [https://home.regit.org/netfilter-en/nftables-quick-howto/ nftables quick howto] |
|||
* [http://developers.redhat.com/blog/2016/10/28/what-comes-after-iptables-its-successor-of-course-nftables/ What comes after ‘iptables’? It’s successor, of course: `nftables`] |
|||
* [https://lwn.net/Articles/564095/ The return of nftables] |
|||
* [https://developers.redhat.com/blog/2016/10/28/what-comes-after-iptables-its-successor-of-course/ What comes after ‘iptables’? Its successor, of course: `nftables`] |
|||
* [https://github.com/gene-git/blog/tree/master/nftables Gene's Tech Blog] – ワークステーションおよびファイアウォール向けの追加 nftables サンプル |
|||
2026年5月27日 (水) 13:16時点における最新版
nftables は既存の ip-, ip6-, arp-, ebtables フレームワークを置き換える Netfilter のプロジェクトです。新しいパケットフィルタリングフレームワーク、新しいユーザースペースユーティリティ (nft)、そして ip- と ip6tables の互換レイヤーを提供します。現行のフック、接続追跡システム、ユーザースペースのキューイングコンポーネント、そして netfilter のログサブシステムを使っています。
nftables は3つのメインコンポーネントから構成されています: カーネルの実装、libnl netlink communication そして nftables ユーザースペースフロントエンド。カーネルは netlink の設定インターフェイスだけでなく、小さなクラス言語インタプリタを使用するランタイムのルールセットの評価も提供します。libnl にはカーネルと通信するためのローレベルな関数が含まれています。nftables フロントエンドはユーザーが対話するものです。
nftables の公式 wiki には詳しい情報が載っています。
インストール
ユーザースペースユーティリティパッケージ nftables をインストールしてください。
iptables-legacy がインストールされている場合は、iptables をインストールしてください。これにより iptables-legacy が自動的にアンインストールされ、nftables との競合を防ぎます。
iptables コマンドの実装を提供します。ただし、古い iptables-legacy ツールで作成されたルールは別のオブジェクトであり、それらが存在する場合、iptables は警告を表示します。フロントエンド
- firewalld (firewall-cmd) — ネットワークとファイアウォールゾーンの設定、およびファイアウォールルールの設定と構成を行うデーモンおよびコンソールインターフェイス。
- nft-blackhole — 国別およびブラックリストによって nftables で IP をブロックするスクリプト / デーモン。
- ufw — Ufw は Uncomplicated Firewall の略で、netfilter ファイアウォールを管理するためのプログラムです。
- reaction — プログラムの出力から繰り返し出現するパターンをスキャンし、アクションを実行するデーモン。fail2ban の軽量な代替です。
使用方法
nftables は、コマンドラインで作成された一時的なルールと、ファイルから読み込まれた、またはファイルに保存された永続的なルールを区別しません。
すべてのルールは nft コマンドラインユーティリティを使って作成または読み込む必要があります。
使用方法については #設定 セクションを参照してください。
現在の ruleset は次のコマンドで表示できます:
# nft list ruleset
すべての ruleset を削除し、システムにファイアウォールがない状態にします:
# nft flush ruleset
nftables.service を再起動することで、/etc/nftables.conf から ruleset を読み込みます。
シンプルなファイアウォール
nftables には、/etc/nftables.conf ファイルに保存されたシンプルで安全なファイアウォール設定が付属しています。
nftables.service は、起動/有効化されたときに、そのファイルからルールを読み込みます。
設定
nftables ユーザースペースユーティリティ nft は、ruleset をカーネルに渡す前に、ルールセット評価の大部分を実行します。ルールはチェインに格納され、チェインはテーブルに格納されます。以下のセクションでは、これらの構造を作成および変更する方法を示します。
ファイルから入力を読み込むには、-f/--file オプションを使用します:
# nft --file filename
既に読み込まれているルールは自動的にはフラッシュされないことに注意してください。
すべてのコマンドの完全な一覧については nft(8) を参照してください。
テーブル
テーブルはチェインを保持します。iptables のテーブルと違って、nftables には初めから組み込まれているテーブルはありません。テーブルの数や名前はユーザーが自由に決めることができますが、各テーブルにはアドレスファミリーをひとつしか保持することができません。5つのファミリーのうち指定したファミリーのパケットにだけ適用されます:
| nftables ファミリー | iptables ユーティリティ |
|---|---|
| ip | iptables |
| ip6 | ip6tables |
| inet | iptables と ip6tables |
| arp | arptables |
| bridge | ebtables |
ip (IPv4) がデフォルトのファミリーです。特に指定がなければ ip が使われます。
IPv4 と IPv6 の両方に適用されるルールを作成するには inet を使います。inet を使うには Linux 3.15 以上が必要で、ip と ip6 ファミリーを統一してルールを簡単に定義できます。
アドレスフファミリーの完全な定義は nft(8) の ADDRESS FAMILIES セクションを参照してください。
以下で例示しているコマンドの family は全て任意であり、指定しなかった場合は ip が使われます。
テーブルの作成
以下のコマンドで新しいテーブルが追加されます:
# nft add table family table
テーブルの一覧表示
全てのテーブルを表示するには:
# nft list tables
テーブル内のチェインとルールの表示
指定したテーブルの全てのチェインとルールを表示するには:
# nft list table family_type table_name
例えば、inet family の my_table テーブルのすべてのルールを一覧表示するには:
# nft list table inet my_table
テーブルの削除
テーブルを削除するには:
# nft delete table family_type table_name
これにより、テーブル内のすべてのチェインが破棄されます。
テーブルのクリア
テーブルから全てのルールを消去するには:
# nft flush table family_type table_name
チェイン
チェインの用途はルールを保持することです。iptables のチェインと違って、nftables には初めから組み込まれているチェインはありません。そのためチェインが netfilter フレームワークにあるタイプやフックをどれも使わない場合、iptables とは異なりチェインを通り抜けるパケットは nftables の影響を受けません。
チェインには2つのタイプがあります。base チェインはネットワークスタックからのパケットのエントリポイントとなります。フックの値を指定することができます。regular チェインはジャンプターゲットとして使用することができます。
以下のコマンドで使っている family_type は全て任意であり、指定しなかった場合は ip が使われます。
チェインの作成
Base chain
base chain を追加するには、type、hook、priority の値を指定する必要があります:
# nft add chain family_type table_name chain_name '{ type chain_type hook hook_type priority priority_value ; policy policy ;}'
chain_type には filter、route、nat を指定できます。
IPv4/IPv6/Inet address family では、hook_type に prerouting、input、forward、output、postrouting を指定できます。サポートされる family_type、chain_type、hook_type の組み合わせ一覧については nft(8) § CHAINS を参照してください。
priority_value には priority 名または整数値を指定できます。標準 priority 名と値の一覧については nft(8) § CHAINS を参照してください。数値が小さいチェインほど先に処理され、負の値も使用できます。[5]
任意で、base chain には policy (drop またはデフォルトの accept) を指定できます。これにより、チェイン内のルールで明示的に accept または refuse されなかったパケットに何が起こるかを定義します。
例えば、入力パケットをフィルタリングする base chain を追加するには:
# nft add chain inet my_table my_chain '{ type filter hook input priority 0; }'
上記のいずれでも add を create に置き換えると、新しいチェインを追加しますが、チェインが既に存在する場合はエラーを返します。
Regular chain
次のコマンドは、table_name という名前のテーブルに chain_name という名前の regular chain を追加します:
# nft add chain family_type table_name chain_name
例えば、inet address family の my_table テーブルに my_tcp_chain という regular chain を追加するには:
# nft add chain inet my_table my_tcp_chain
チェインの一覧表示
次のコマンドは、family_type のすべてのチェインを、ルールなしで一覧表示します (#ルールの一覧表示 を参照):
# nft list chains family_type
例えば、次のコマンドは IPv6 のチェインを一覧表示します:
# nft list chains ip6
family_type を省略した場合、すべてのチェインが表示されます。
チェインの編集
チェインを編集したいときは、チェインの名前を指定して変更したいルールを定義します:
# nft chain family_type table_name chain_name '{ [ type chain_type hook hook_type device device_name priority priority_value ; policy policy_type ; ] }'
例えば、デフォルトテーブル内の my_input チェインの policy を accept から drop に変更するには:
# nft chain inet my_table my_input '{ policy drop ; }'
チェインの削除
チェインを削除するには:
# nft delete chain family_type table_name chain_name
削除するチェインにはルールやジャンプターゲットが含まれていてはいけません。
チェインのルールを消去
チェインからルールを消去するには:
# nft flush chain family_type table_name chain_name
ルール
ルールは表現または宣言から構成され、チェインの中に格納されます。
ルールの追加
チェインにルールを追加するには:
# nft add rule family_type table_name chain_name handle handle_value statement
ルールは handle_value の位置に追加されます。これは任意です。指定しない場合、ルールはチェインの末尾に追加されます。
ルール handle を確認するには、任意の有効な list コマンドに --handle スイッチを追加する必要があります。このスイッチにより、nft は出力に handle を表示します。--numeric 引数は、未解決の IP アドレスなど、一部の数値出力を確認するのに便利です。
# nft --handle --numeric list chain inet my_table my_input
table inet my_table {
chain input {
type filter hook input priority 0;
ip saddr 127.0.0.1 accept # handle 10
}
}
指定位置の前にルールを挿入するには:
# nft insert rule family_type table_name chain_name handle handle_value statement
handle_value が指定されていない場合、ルールはチェインの先頭に挿入されます。
表現
statement にはマッチする表現と判断宣言が入ります。判断宣言には accept, drop, queue, continue, return, jump chain, goto chain などが存在します。判断宣言以外の宣言も指定できます。詳しくは nft(8) を参照してください。
nftables では様々な表現を使うことができ、ほとんどは、iptables と対応するようになっています。一番大きな違いは汎用的なマッチと暗黙的なマッチが存在しないことです。汎用的なマッチとは、--protocol や --source のように、いつでも使うことができるマッチで、暗黙的なマッチとは、--sport のように、特定のプロトコルでしか使えないマッチのことです。
以下は利用できるマッチの一部です:
- meta (メタプロパティ。例: インターフェイス)
- icmp (ICMP プロトコル)
- icmpv6 (ICMPv6 プロトコル)
- ip (IP プロトコル)
- ip6 (IPv6 プロトコル)
- tcp (TCP プロトコル)
- udp (UDP プロトコル)
- sctp (SCTP プロトコル)
- ct (接続のトラッキング)
以下はマッチ引数の一部です (完全なリストは nft(8) を見て下さい):
meta: oif <output interface INDEX> iif <input interface INDEX> oifname <output interface NAME> iifname <input interface NAME> (oif and iif accept string arguments and are converted to interface indexes) (oifname and iifname are more dynamic, but slower because of string matching) icmp: type <icmp type> icmpv6: type <icmpv6 type> ip: protocol <protocol> daddr <destination address> saddr <source address> ip6: daddr <destination address> saddr <source address> tcp: dport <destination port> sport <source port> udp: dport <destination port> sport <source port> sctp: dport <destination port> sport <source port> ct: state <new | established | related | invalid>
ある意味では、iif と oif に対する iifname と oifname の違いは、static と dynamic の違いに似ています。または、プログラミング概念でいう definition と declaration、あるいは early binding と delayed binding に似ています。使用例と追加説明へのリンクについては [6] を参照してください。
ルールの一覧表示
次のコマンドはチェイン内のすべてのルールを一覧表示します:
# nft list chain family_type table_name chain_name
例えば、my_table という inet テーブル内の my_output というチェインのルールを一覧表示するには:
# nft list chain inet my_table my_output
削除
個々のルールはハンドルを使わないと削除することができません。nft --handle list コマンドを使うことでルールのハンドルを確認できます。例えば次のような場合:
# nft --handle --numeric list chain inet my_table my_input
table inet my_table {
chain input {
type filter hook input priority 0;
ip saddr 127.0.0.1 accept # handle 10
}
}
次のコマンドで削除できます:
# nft delete rule inet my_table my_input handle 10
テーブル内のすべてのチェインは nft flush table コマンドでフラッシュできます。個別のチェインは nft flush chain または nft delete rule コマンドでフラッシュできます。
# nft flush table table_name # nft flush chain family_type table_name chain_name # nft delete rule family_type table_name chain_name
最初のコマンドは、ip table_name テーブル内のすべてのチェインをフラッシュします。2 番目のコマンドは、family_type table_name テーブル内の chain_name チェインをフラッシュします。3 番目のコマンドは、family_type table_name テーブル内の chain_name チェインのすべてのルールを削除します。
セット
セットには名前付きセットと匿名セットがあります。セットは 1 つ以上の要素で構成され、要素はカンマで区切られ、波括弧で囲まれます。匿名セットはルールに埋め込まれ、更新できません。ルールを削除して再追加する必要があります。例えば、次の dports セットから "http" だけを削除することはできません:
# nft add rule ip6 filter input tcp dport {telnet, http, https} accept
名前付きセットは更新でき、型付けやフラグ付けが可能です。sshguard は、ブロックされたホストの IP アドレスに名前付きセットを使用します。
table ip sshguard {
set attackers {
type ipv4_addr
flags interval
elements = { 1.2.3.4 }
}
セットに要素を追加または削除するには、次のようにします:
# nft add element ip sshguard attackers { 5.6.7.8/32 }
# nft delete element ip sshguard attackers { 1.2.3.4/32 }
ipv4_addr 型には CIDR netmask を含められることに注意してください (ここでの /32 は必須ではありませんが、完全性のために含めています)。また、ここで TABLE ip sshguard { SET attackers } によって定義されたセットは、ip sshguard attackers として参照されることにも注意してください。
NFTSet= の説明と #systemd-networkd を使った動的名前付きセット の例を参照してください。アトミックリロード
現在のルールセットをフラッシュする:
# echo "flush ruleset" > /tmp/nftables
現在のルールセットをダンプする:
# nft list ruleset >> /tmp/nftables
/tmp/nftables を編集して次のコマンドで変更を適用:
# nft -f /tmp/nftables
サンプル
ワークステーション
/etc/nftables.conf
flush ruleset
table inet my_table {
set LANv4 {
type ipv4_addr
flags interval
elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 }
}
set LANv6 {
type ipv6_addr
flags interval
elements = { fd00::/8, fe80::/10 }
}
chain my_input_lan {
udp sport 1900 udp dport >= 1024 meta pkttype unicast limit rate 4/second burst 20 packets accept comment "Accept UPnP IGD port mapping reply"
udp sport netbios-ns udp dport >= 1024 meta pkttype unicast accept comment "Accept Samba Workgroup browsing replies"
}
chain my_input {
type filter hook input priority filter; policy drop;
iif lo accept comment "Accept any localhost traffic"
ct state invalid drop comment "Drop invalid connections"
fib daddr . iif type != { local, broadcast, multicast } drop comment "Drop packets if the destination IP address is not configured on the incoming interface (strong host model)"
ct state { established, related } accept comment "Accept traffic originated from us"
meta l4proto { icmp, ipv6-icmp } accept comment "Accept ICMP"
ip protocol igmp accept comment "Accept IGMP"
udp dport mdns ip6 daddr ff02::fb accept comment "Accept mDNS"
udp dport mdns ip daddr 224.0.0.251 accept comment "Accept mDNS"
ip6 saddr @LANv6 jump my_input_lan comment "Connections from private IP address ranges"
ip saddr @LANv4 jump my_input_lan comment "Connections from private IP address ranges"
counter comment "Count any other traffic"
}
chain my_forward {
type filter hook forward priority filter; policy drop;
# Drop everything forwarded to us. We do not forward. That is routers job.
}
chain my_output {
type filter hook output priority filter; policy accept;
# Accept every outbound connection
}
}
NFTSet= を使って接続のネットワークプレフィックスを取得することで、ネットワークサブネットのハードコーディングを避けられます。#systemd-networkd を使った動的名前付きセット を参照してください。サーバー
/etc/nftables.conf
flush ruleset
table inet my_table {
set LANv4 {
type ipv4_addr
flags interval
elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 }
}
set LANv6 {
type ipv6_addr
flags interval
elements = { fd00::/8, fe80::/10 }
}
chain my_input_lan {
meta l4proto { tcp, udp } th dport 2049 accept comment "Accept NFS"
udp dport netbios-ns accept comment "Accept NetBIOS Name Service (nmbd)"
udp dport netbios-dgm accept comment "Accept NetBIOS Datagram Service (nmbd)"
tcp dport netbios-ssn accept comment "Accept NetBIOS Session Service (smbd)"
tcp dport microsoft-ds accept comment "Accept Microsoft Directory Service (smbd)"
udp sport { bootpc, 4011 } udp dport { bootps, 4011 } accept comment "Accept PXE"
udp dport tftp accept comment "Accept TFTP"
}
chain my_input {
type filter hook input priority filter; policy drop;
iif lo accept comment "Accept any localhost traffic"
ct state invalid drop comment "Drop invalid connections"
fib daddr . iif type != { local, broadcast, multicast } drop comment "Drop packets if the destination IP address is not configured on the incoming interface (strong host model)"
ct state { established, related } accept comment "Accept traffic originated from us"
meta l4proto { icmp, ipv6-icmp } accept comment "Accept ICMP"
ip protocol igmp accept comment "Accept IGMP"
udp dport mdns ip6 daddr ff02::fb accept comment "Accept mDNS"
udp dport mdns ip daddr 224.0.0.251 accept comment "Accept mDNS"
ip6 saddr @LANv6 jump my_input_lan comment "Connections from private IP address ranges"
ip saddr @LANv4 jump my_input_lan comment "Connections from private IP address ranges"
tcp dport ssh accept comment "Accept SSH on port 22"
tcp dport ipp accept comment "Accept IPP/IPPS on port 631"
meta l4proto { tcp, udp } th dport { http, https, 8008, 8080 } accept comment "Accept HTTP (ports 80, 443, 8008, 8080)"
udp sport bootpc udp dport bootps ip saddr 0.0.0.0 ip daddr 255.255.255.255 accept comment "Accept DHCPDISCOVER (for DHCP-Proxy)"
}
chain my_forward {
type filter hook forward priority filter; policy drop;
# Drop everything forwarded to us. We do not forward. That is routers job.
}
chain my_output {
type filter hook output priority filter; policy accept;
# Accept every outbound connection
}
}
レート制限
table inet my_table {
chain my_input {
type filter hook input priority filter; policy drop;
iif lo accept comment "Accept any localhost traffic"
ct state invalid drop comment "Drop invalid connections"
fib daddr . iif type != { local, broadcast, multicast } drop comment "Drop packets if the destination IP address is not configured on the incoming interface (strong host model)"
meta l4proto icmp icmp type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"
meta l4proto ipv6-icmp icmpv6 type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"
ct state { established, related } accept comment "Accept traffic originated from us"
meta l4proto { icmp, ipv6-icmp } accept comment "Accept ICMP"
ip protocol igmp accept comment "Accept IGMP"
tcp dport ssh ct state new limit rate 15/minute accept comment "Avoid brute force on SSH"
}
}
ジャンプ
設定ファイルでジャンプを使うときは、先にターゲットチェインを定義する必要があります。そうしないと Error: Could not process rule: No such file or directory というエラーが発生します。
table inet my_table {
chain web {
tcp dport http accept
tcp dport 8080 accept
}
chain my_input {
type filter hook input priority filter;
ip saddr 10.0.2.0/24 jump web
drop
}
}
インターフェイスによってルールを変える
複数のネットワークインターフェイスが存在する場合、それぞれのインターフェイスごとに別々のフィルターチェインを設定したい場合があるかもしれません。例えば、ホームルーターを構築するとき、LAN 上でアクセスできるウェブサーバーを実行しつつ (nsp3s0 インターフェイス)、インターネットからはアクセスできないようにしたい場合 (enp2s0 インターフェイス) などは以下のように設定します:
table inet my_table {
chain my_input { # this chain serves as a dispatcher
type filter hook input priority filter; policy drop;
iif lo accept comment "always accept loopback"
iifname enp2s0 jump my_input_public
iifname enp3s0 jump my_input_private
}
chain my_input_public { # rules applicable to public interface interface
ct state {established,related} accept
ct state invalid drop
udp dport bootpc accept
tcp dport bootpc accept
}
chain my_input_private {
ct state {established,related} accept
ct state invalid drop
udp dport bootpc accept
tcp dport bootpc accept
tcp port http accept
tcp port https accept
reject with icmpx port-unreachable comment "all other traffic"
}
chain my_output { # we let everything out
type filter hook output priority filter;
accept
}
}
あるいは、単一の upstream interface に対する iifname statement だけを選び、それ以外のすべてのインターフェイスに対するデフォルトルールを 1 か所に置くこともできます。各インターフェイスごとに dispatch する必要はありません。
マスカレード
nftables には特殊なキーワード masquerade が存在し、送信元アドレスが自動的に出力インターフェイスのアドレスに設定されます (ソース)。ルーターのインターフェイスが多数の ISP に接続されているときなど、インターフェイスの IP アドレスが一定でない場合に有用です。通常は、インターフェイスの IP アドレスが変わるたびにネットワークアドレス変換 (NAT) のルールを更新する必要があります。
masquerade を使用するには:
- masquerading がカーネルで有効になっていることを確認してください (デフォルトカーネルを使用している場合は true です)。そうでない場合は、カーネル設定で
CONFIG_NFT_MASQ=mを設定します。 masqueradeキーワードはnattype のチェインでのみ使用できます。- masquerading は source NAT の一種であるため、output path でのみ動作します。
2 つのインターフェイスを持つマシンの例です: LAN は enp3s0 に接続され、public internet は enp2s0 に接続されています:
table inet my_nat {
chain my_masquerade {
type nat hook postrouting priority srcnat;
oifname "enp2s0" masquerade
}
}
テーブル type が inet なので、IPv4 と IPv6 の両方のパケットが masquerade されます。IPv6 は追加の address space により NAT が不要なため、IPv4 パケットだけを masquerade したい場合は、meta nfproto ipv4 expression を oifname "enp2s0" の前に使用するか、テーブル type を ip に変更します。
NAT とポートフォワーディング
この例では、eth0 という WAN インターフェイスを通って出ていくトラフィックを masquerade し、ポート 22 と 80 を 10.0.0.2 に転送します。sysctl によって net.ipv4.ip_forward を 1 に設定する必要があります。
table nat {
chain prerouting {
type nat hook prerouting priority dstnat;
iif eth0 tcp dport {22, 80} dnat to 10.0.0.2
}
chain postrouting {
type nat hook postrouting priority srcnat;
oif eth0 masquerade
}
}
IP ごとの新規接続数をカウント
HTTPS 接続をカウントするには、次のスニペットを使用します:
/etc/nftables.conf
table inet filter {
set https {
type ipv4_addr;
flags dynamic;
size 65536;
timeout 60m;
}
chain input {
type filter hook input priority filter;
ct state new meta l4proto { tcp, udp } th dport 443 update @https { ip saddr counter }
}
}
カウンターを表示するには、nft list set inet filter https を実行してください。
動的 blackhole
このスニペットは、10/second の制限を超えた source IP (または /64 IPv6 range) からのすべての HTTPS 接続を 1 分間 drop します。
/etc/nftables.conf
table inet dev {
set blackhole_ipv4 {
type ipv4_addr;
flags dynamic, timeout;
size 65536;
}
set blackhole_ipv6 {
type ipv6_addr;
flags dynamic, timeout;
size 65536;
}
chain input {
type filter hook input priority filter; policy accept;
ct state new meta l4proto { tcp, udp } th dport 443 \
meter flood_ipv4 size 128000 { ip saddr timeout 10s limit rate over 10/second } \
add @blackhole_ipv4 { ip saddr timeout 1m }
ct state new meta l4proto { tcp, udp } th dport 443 \
meter flood_ipv6 size 128000 { ip6 saddr and ffff:ffff:ffff:ffff:: timeout 10s limit rate over 10/second } \
add @blackhole_ipv6 { ip6 saddr and ffff:ffff:ffff:ffff:: timeout 1m }
ip saddr @blackhole_ipv4 counter drop
ip6 saddr and ffff:ffff:ffff:ffff:: @blackhole_ipv6 counter drop
}
}
blackhole された IP を表示するには、nft list set inet dev blackhole_ipvX を実行してください。
ヒントとテクニック
現在の rule set の保存
nft list ruleset コマンドの出力は、そのまま有効な入力ファイルとしても使用できます。現在の rule set をファイルに保存し、後で読み戻すことができます。
# nft -s list ruleset | tee filename
nft list は変数定義を出力しません。変数は失われます。ルール内で使われていた変数は、その値に置き換えられます。シンプルなステートフルファイアウォール
シンプルなステートフルファイアウォールの記事も参照してください。
シングルマシン
現在のルールセットを消去:
# nft flush ruleset
テーブルを追加:
# nft add table inet filter
input, forward, output ベースチェインを追加。input と forward のポリシーは破棄にして、output のポリシーは許可にする:
# nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
# nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
# nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
レギュラーチェインを追加して tcp と udp に関連付ける:
# nft add chain inet filter TCP # nft add chain inet filter UDP
関連・確立済みトラフィックは許可する:
# nft add rule inet filter input ct state related,established accept
ループバックインターフェイスのトラフィックは全て許可する:
# nft add rule inet filter input iif lo accept
不正なトラフィックは全て破棄する:
# nft add rule inet filter input ct state invalid drop
新しいエコー要求 (ping) は許可する:
# nft add rule inet filter input ip protocol icmp icmp type echo-request ct state new accept
新しい udp トラフィックは UDP チェインにジャンプする:
# nft add rule inet filter input ip protocol udp ct state new jump UDP
新しい tcp トラフィックは TCP チェインにジャンプする:
# nft add rule inet filter input ip protocol tcp tcp flags \& \(fin\|syn\|rst\|ack\) == syn ct state new jump TCP
他のルールによって処理されなかったトラフィックは全て拒否する:
# nft add rule inet filter input ip protocol udp reject # nft add rule inet filter input ip protocol tcp reject with tcp reset # nft add rule inet filter input counter reject with icmp type prot-unreachable
ここから TCP と UDP チェインで処理する接続で開きたいポートを決めます。例えばウェブサーバーの接続を開くには:
# nft add rule inet filter TCP tcp dport 80 accept
ポート 443 からのウェブサーバーの HTTPS 接続を許可するには:
# nft add rule inet filter TCP tcp dport 443 accept
ポート 22 の SSH 接続を許可するには:
# nft add rule inet filter TCP tcp dport 22 accept
DNS リクエストを許可するには:
# nft add rule inet filter TCP tcp dport 53 accept # nft add rule inet filter UDP tcp dport 53 accept
設定に満足したら変更を保存して永続化させてください。
ブルートフォース攻撃の対策
Sshguard はブルートフォース攻撃を検出して一時的に IP アドレスに基づきブロックするようにファイアウォールを編集します。Sshguard で nftables を使うように設定する方法は Sshguard#nftables を見てください。
トラフィックのログ記録
log action を使ってパケットをログに記録できます。すべての受信 traffic をログに記録する最も単純なルールは次のとおりです:
# nft add rule inet filter input log
詳しくは nftables wiki を参照してください。
Monitor
すべてのイベントを監視し、native nft format で報告します。
# nft monitor
nft(8) § MONITOR を参照してください。
ruleset debugging trace temporary
meta nftrace set 1 は ruleset packet tracing を on/off します。trace を見るには monitor trace コマンドを使用します。
別の shell で、interactive shell 内にファイルを "include" します:
# nft -i nft> include "/root/nftables.trace"
必要に応じて調整した例です:
/root/nftables.trace
add table ip temp-trace {comment "Temporary table!!"; flags owner;}
add chain ip temp-trace icmp-prerouting { type filter hook prerouting priority raw - 1 ; }
add rule ip temp-trace icmp-prerouting ip protocol icmp meta nftrace set 1
このファイルは一時テーブル (flags owner) を追加します。そのため、呼び出し元の interactive nft プロセスが閉じられると自動的に削除されます。Base Chain は用途に応じて調整する必要があります。複数のチェインや複数の "meta nftrace set 1" ルールを作成できます。"ip protocol icmp" は単なる例であり、必須ではありません。同様の効果を得る方法は多数あります。この方法の利点は、interactive shell を閉じることで以前の状態が自動的に復元されることと、ファイル内にエラーがある場合に何も実行されないことです。
詳しくは nftables wiki と、その処理を自動化して色付けする python tool を参照してください。
iptables-nft の使用
古い iptables 言語は Linux ドキュメントでは依然としてかなり支配的であり、Docker のネットワークなど、iptables に依存して動作するものも少なくありません。legacy iptables と nftables を同時に使うことも可能ではありますが、iptables-nft の変換を使うことが推奨されます。理由は次のとおりです:
- すべてを新しく、より効率的で、ロックを必要としないフレームワークの同じ場所に配置します。
- 競合をチェックします。
nftables で古い iptables 言語を使用する方法は 2 つあります:
iptables-translateとiptables-restore-translate(ip6tables、ebtablesなども同様) は、iptables 言語を受け取り nft 言語を出力します。実行中の nft 設定は変更しません。xtables-translate(8) を参照してください。
- 後で保守したい設定については、
-translateツールを使い、その結果のコードを既存のルールに統合するのがよいでしょう。例えば、シンプルなステートフルファイアウォールやインターネット上で便利なものを見つけた場合、それらを nft 設定に入れられるように変換できます。
iptablesとiptables-restore(ip6tablesなども同様) は上記の変換を使い、さらに実行中の nft 設定に反映します。通常の iptables と同じように統計情報も提供します。xtables-nft(8) を参照してください。
- これらのコマンドは、やるべきことを考えれば十分にうまく動作します。単純な使い方では「そのまま動く」はずですが、ときどき手動でのデバッグが必要になることがあります。
systemd-networkd を使った動的名前付きセット
systemd-networkd の接続は、NFTSet= オプションを使用して、事前定義された名前付きセットにホスト IP アドレス、ネットワークプレフィックス、インターフェイスインデックスを投入できます。これにより、/etc/nftables.conf にそれらをハードコーディングすることを避けられます。NFTSet= オプションは、[Address]、[DHCPv4]、[DHCPv6]、[IPv6AcceptRA] セクションでサポートされています。systemd.network(5) § [ADDRESS SECTION OPTIONS] を参照してください。
例えば、ローカルネットワークからの接続 (IP アドレスが DHCP または SLAAC で割り当てられる場合) を別の my_input_lan チェインで処理するには:
/etc/nftables.conf
...
table inet my_table {
set eth_ipv4_prefix {
type ipv4_addr
flags interval
comment "Populated by systemd-networkd"
}
set eth_ipv6_prefix {
type ipv6_addr
flags interval
comment "Populated by systemd-networkd"
elements = { fe80::/10 }
}
set eth_ifindex {
type iface_index
comment "Populated by systemd-networkd"
}
...
chain my_input {
type filter hook input priority filter; policy drop;
iif @eth_ifindex ip6 saddr @eth_ipv6_prefix jump my_input_lan comment "Connections from LAN"
iif @eth_ifindex ip saddr @eth_ipv4_prefix jump my_input_lan comment "Connections from LAN"
}
...
}
/etc/systemd/network/my-network.network
... [DHCPv4] NFTSet=prefix:inet:my_table:eth_ipv4_prefix NFTSet=ifindex:inet:my_table:eth_ifindex [DHCPv6] NFTSet=prefix:inet:my_table:eth_ipv6_prefix NFTSet=ifindex:inet:my_table:eth_ifindex [IPv6AcceptRA] NFTSet=prefix:inet:my_table:eth_ipv6_prefix NFTSet=ifindex:inet:my_table:eth_ifindex ...
トラブルシューティング
Docker と共に使う
- 次のセットアップでは、
--net host --privilegedを使用してもコンテナ内でAF_BLUETOOTHなどのプロトコルを利用できなくなります。 - ルートレス Dockerコンテナはすでに別のネットワーク名前空間で実行されています。何もする必要がないかもしれません。
nftables を使用すると、Docker のネットワーク (おそらく他のコンテナランタイムも同様) に干渉する可能性があります。 iptables ルールにパッチを適用して定義されたサービス開始順序を確保するか、docker の使用が非常に制限される dockerのiptablesの管理を完全に無効にするなど、さまざまな回避策がインターネット上で見つかります。 (ポートフォワーディングや docker-compose を考えてください)
信頼できる方法は、docker を別のネットワーク名前空間で実行させ、そこで任意の処理を実行できるようにすることです。 Docker が nftables と iptables ルールを混在させないように、iptables-nft を使用しない方が良いでしょう。
以下の docker サービス ドロップインファイル を使用してください:
/etc/systemd/system/docker.service.d/netns.conf
[Service] PrivateNetwork=yes PrivateMounts=No # cleanup ExecStartPre=-nsenter -t 1 -n -- ip link delete docker0 # add veth ExecStartPre=nsenter -t 1 -n -- ip link add docker0 type veth peer name docker0_ns ExecStartPre=sh -c 'nsenter -t 1 -n -- ip link set docker0_ns netns "$$BASHPID" && true' ExecStartPre=ip link set docker0_ns name eth0 # bring host online ExecStartPre=nsenter -t 1 -n -- ip addr add 10.0.0.1/24 dev docker0 ExecStartPre=nsenter -t 1 -n -- ip link set docker0 up # bring ns online ExecStartPre=ip addr add 10.0.0.100/24 dev eth0 ExecStartPre=ip link set eth0 up ExecStartPre=ip route add default via 10.0.0.1 dev eth0
セットアップにおいてIPアドレス 10.0.0.* が適切でない場合は、調整してください。
以下のポストルーティングルールで、docker0 のIPフォワーディングを有効にし、NATを設定します:
iifname docker0 oifname eth0 masquerade
次に、kernel IP forwarding が有効になっていることを確認します。
これで、nftables を使用して docker0 インターフェイスのファイアウォールとポートフォワーディングを干渉することなくセットアップできるようになります。