iptablesの後に来るものは何か?: nftables

この記事はRed Hat DeveloperWhat comes after ‘iptables’? Its successor, of course: nftablesを、許可をうけて翻訳したものです。

::: By Florian Westphal October 28, 2016 :::

nftablesは、既存のiptables、ip6tables、arptables、ebtablesを置き換えることを目指した、新たなパケット分類フレームワークです。これは、長く使われてきた ip/ip6tables ツールに存在する制限の多くを解決することを目指しています。古いiptablesと比較して、nftablesの最も注目すべき機能は以下のとおりです。

パフォーマンス:

  • ルックアップテーブルのサポート - ルールをシーケンシャルに評価する必要がなくなります
  • 暗黙のルールカウンタとアドレス/インターフェース・マッチングのオーバーヘッドを避けることができます

ユーザビリティ:

  • トランザクショナルなルール更新 - すべてのルールがアトミックに適用されます
  • アプリケーションはnfnetlinkを購読することで、新しいルールが追加または削除されたときに通知を受信できます
  • nftコマンドラインツールはマッチするルールのライブログを表示することができ、ルールセットのデバッグが容易です

nftablesとは何ですか?

nftablesは当初、2008年のNetfilter Workshop in Parisで発表された後、netfilterのコアチームメンバーとして長期間活躍していてプロジェクトリーダーでもあるPartic McHardyにより2009年3月にリリースされました。2013年後半にLinuxカーネルにマージされ、2014年にリリースされたカーネル3.13から利用可能です。

接続追跡及びNATファシリティなどのnetfilterフレームワークの多くの部分を再使用しています。 また、テーブル、チェーンやルールなどの命名法と基本的なiptablesのデザインのいくつかの部分を引き継いでいます。 iptablesと同じように、テーブルはチェーンのコンテナとして機能し、チェーンは個別のルールを含んでいます。それぞれのルールはパケットをドロップするなどのアクション実行、次のルールへ移動、新しいチェーンへのジャンプを実行することができます。

何が置き換えられますか?

ユーザの観点からは、nftablesはiptables、arptables、ebtablesのすべてのツールを置き換えるnftと呼ばれる新しいツールを追加します。アーキテクチャの観点からは、パケットフィルタリングルールセットの実行時評価を扱うカーネルの部分を置き換えます。

なぜiptablesを置き換えるのか?

その成功にもかかわらず、iptablesはいくつかのアーキテクチャ上の制限があり、それらは多くの根本的な設計変更なしには解決できません。ルールセットの表現がiptablesのようなフロントエンドツールとカーネルの間で共有されているという事実から主な問題が発生します。これは複数の欠点をもたらします。例えば、iptablesのルールセットにルールが追加されたとき

  # インバウンドssh接続を許可します
  iptables -t filter -A INPUT -p tcp --dport 22 -j ACCEPT

iptablesのツールは、まず現在のルールセット(基本的にはさまざまなデータ構造の配列)をダンプする必要があり、その後、このブロブを変更して新しいルールを追加し、カーネルへルールのセット全体を送信します。これは、テーブル全体の処理と新しいものとの交換が必要なため、すべての追加と削除の操作が低速であることを意味しています。

カーネルは、置き換えられたテーブル内のどのルールが修正、追加または削除されたのか理解していません。

カーネルが理解しているのは、新しいテーブルのルールセットがロードされているということだけです。ルールセットのどこが削除または追加されたか、および副作用で影響をうけた(たとえば異なるチェーンへジャンプする際のオフセットが変わった)かはわかりません。

ユーザ空間は、ルールセットが何をしているのかわかりません。

iptablesのツールが行うのは、コマンドライン引数の解析とカーネルが期待するバイナリ表現への変換作業です。ユーザ空間には、「IP」または「TCP」の概念はありません。そのためユーザー空間でルールセットの最適化を行うには、カーネルの評価ロジックを複製する必要があります。

ルールの追加と除去はアトミック操作ではありません。

2つのルールが正確に同じ時間に追加された場合は、各プロセスが独立して、現在のテーブルを操作し、その後両方が、新しいテーブルで古いテーブルを交換するようカーネルを要求します。そのため最後に操作を行うプロセスがテーブルをダンプしてからコミットするまでの間に行われた変更は削除されます。これは、システム管理者のみがパケットフィルタルールを変更することが想定されていたiptablesと、その前身であるipchains(1990年代の終わりに開発された)では、問題ではありませんでした。 今日ではこの状況は変わっています。例えば、dockerまたはlibvirtのようなアプリケーションは、コンテナおよび仮想マシンの接続性を提供するために、NATルールを追加します。

iptablesのルールセットの形式は変更できません。

iptablesでは「リビジョン番号」方式により、マッチとターゲットで提供される機能を拡張するため、ルールのブロブは互換性を破壊せずにフォーマットを変更することができません。現在のフォーマットではいくつかの制限が課せられます。

カーネルはアドレスが全く与えられなかった場合であっても、IP送信元と宛先アドレスのマッチングを行います。この場合カーネルは0.0.0.0/0とパケットの送信元と宛先を比較し必ず成功します。IPアドレスと同様に入出力インタフェースも、各ルールのヘッダに格納されているため、各パケットについて常に照合されます。

ルールがマッチするたびにカウンタがインクリメントされます。 これは、期待通りのルールが評価されているかどうかを確認するための簡単でシンプルな方法になりますので、ユーザの視点からは良いものです。しかし、毎秒数百万パケットを処理する場合にはパフォーマンス上の問題になります。

特殊な機能をもつマッチとターゲットが増え続けています。

iptablesには、与えられたパケットが特定の基準を満たしているかどうかを判断するための様々な機能を実装した、いくつかの「マッチ」があります。

基本的なマッチ、たとえばパケットのペイロードからUDPまたはTCPポート番号を照合するものや、より精巧なチェックを実行するマッチ、たとえば conntrack マッチはコネクション追跡の状態を照合して、あるパケットが以前の逆方向のパケットに対する返信であることなどを確認します。他にも指定されたパケットがIPsec処理の対象となるか、パケットが特定のCPUに処理されているか(ロードバランシング時に有用)のマッチなどがあります。

新しいプロトコルをサポートするには、カーネルとiptablesユーザランドの両方を適宜拡張する必要があります。

iptablesは、さらに新奇なターゲットを有しています。例えばHMARKターゲットは、ハッシュ関数に基づいて、パケットのマークを設定します。これはポリシールーティングを介してロードバランシングをサポートするために追加されました。

もう一つの問題は、iptablesは1つのルールで複数のアクション(ターゲット)を実行することができないことです。 例えば、パケットをログに記録するルールを作成することは可能ですが、同じルールの中でそのパケットをドロップするようにカーネルに指示することはできません。 これは、「マークをつけ許可する」のように複数のアクションが望まれる場合、いくつかのルールを複製する必要があるということです。

基本的なマッチング機能が制限されている

iptablesの1つのルールでは1つの送信元アドレス(またはネットワーク)、および1つの宛先アドレス/ネットワークをマッチさせることしかできません。また、送信元または宛先インターフェイスは1つに対してのみ照合できます。アドレスのリストまたは範囲を照合するには、「ipset」ツールなどの外部ファシリティを使用する必要があります。

nftablesは、これらすべての制限を克服するように設計されています。

  1. iptablesのようなシーケンシャルな評価アプローチを強制するのではなく、セットとマップによるルールのコンパクトな表現を可能にします。
  2. ルールの追加及び除去が常にアトミックです。2つのプログラムが同時に追加/削除するときにレース状態になりません。つまりユーザスペースはテーブル全体を変更するのではなく個別のルールを削除/追加します。
  3. カーネルは個々のルールに対して固有の識別番号を付与し、iptablesと比べて、ルールの削除がずっと簡単になります。
  4. アプリケーションは、ルールが追加または削除されたときにカーネルから通知を受け取ることができます。
  5. マッチとターゲットの区別はありません。 nftablesは、機能を実装するために「式」と呼ぶものを使用しています。  例えばパケットにマークを設定し、同じルールで、それを受け入れることが可能です
  6. ユーザ空間にルール処理の大部分を移動します。処理はカーネルにも残りますが、プロトコルはユーザスペースで行われます。たとえば、TCP宛先ポート、IP送信元アドレスをロードする方法や、SPIをESPヘッダからロードする方法をカーネルは知りません。代わりに、NFTツールは、カーネルに特定のオフセットから指定したバイト数を読み込むよう依頼します。新しいトランスポートヘッダをサポートするためにカーネルを変更する必要はありません。ヘッダフィールド、名前、サイズ、場所がわかるようにnftツールだけを拡張します。
  7. ルールの更新を監視できます。nft ツールは、ルールセットの変更を監視するために使用できます. たとえば、「nft monitor」は、カーネルに対して追加または削除されたすべてのルールを表示します。また、'trace mode'も提供されています。システム管理者がたとえば『nft add rule mangle prerouting ip saddr 10.2.3.4 meta nftrace set 1』と実行すると、『nft monitor trace』は、『IP アドレス 10.2.3.4 から送信されたパケット』にマッチするすべてのルールを表示します。

nftablesでの高水準な機能

nftables は、式と呼ばれる一連の命令を実装します。式は多数のレジスタにデータを格納、読み込みしてデータを変更できます。言い換えると、nftables コアは一種の仮想マシンとして見ることができます。

nftables フロントエンドである nft などのアプリケーションは、カーネルが提供する式を使用して、柔軟性を高めつつ、従来の iptables マッチを模倣できます。 たとえば、nft コマンドがパケットが指定の TCP 宛先ポートにマッチするかどうかのチェックを要求されると、TCP ヘッダーの開始から 2 番目のオフセットで 2 バイトを特定のレジスタに読み込み、そのレジスタを即値(ポート番号)と比較するようカーネルに指示します。

# nft add rule ip filter input tcp dport 22

内部で何が起きているかをよりよく理解するために、

--debug=netlink

オプションを指定できます。上記の文でこれを実行すると、次のようなデバッグ出力が行われます。これは、ルールを構成する個々の式を示しています。

[ payload load 1b @ network header + 9 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00001600 ]

したがって、ルールがカーネルで評価されると、最初に IP プロトコルフィールドをレジスタ 1 に読み込み、それを即値 6と比較(トランスポートヘッダーが TCP かどうかの確認)し、次に TCP 宛先ポートを読み込んで、次に、そのポートが即値 22 (ここでは 22 の ネットワークバイトオーダで 0x1600)と一致するかどうかを確認します。カーネルはプロトコルの詳細を知りません。単にデータをレジスタにロードして、比較を行うだけです。

このレジスターのアプローチは、基本的なビルディングブロックを連鎖することで、最も高いレベルの機能を実現することを意味します。 ほとんどの式は、レジスタからのデータを取得するか、またはレジスターに何かを格納する方法を知っているか、あるいは副作用を持つだけです。

レジスタを使用しない式の例:

  •  log:(従来の iptables -j LOG や iptables -j NFLOG のように)カーネルリングバッファーを使用して、カーネルにログエントリーを出力させます。
  • limit:ログのフラッディングを避けるために、ログ式と組み合わせることが多く、レートポリシーの実装にも使用できます。

レジスタにデータを保存する式の例:

  • payload: パケットペイロードからデータを読み込み、レジスタに格納します。
  • immediate: 指定のレジスターに数値を保存します。これは、たとえば、カーネルに accept 文および drop 文を実装するために使用されます。ユーザがパケットをドロップするよう指示すると、nftはverdict(判断)レジスタにimmediate式を使って判断コードを保存します。
  • meta:パケットが到達した入力または出力インターフェースの名前、skb マーク、パケットの長さ/サイズなど、補助的なデータ
  • ct:パケットの方向(オリジナル、応答)、接続追跡カウンタ(これまでに確認したバイト/パケット)、状態(new、established、など)のような接続追跡に関連したデータへのアクセスを提供します。

一部の式では、複数個の属性を設定できます. たとえば、payload式でも逆(レジスタの値を取得してパケット内の特定の場所に配置)の実行が可能です。meta式でパケットマークを設定するようなことができます。

その他の式を使用して、レジスタの値を操作することもできます。

たとえば、ユーザーが特定の IP アドレス 10.0.0.0 ではなく、ネットワーク 10.0.0.0/8 とマッチするように要求すると、nft ツールは IP アドレスをレジスタにロードするように要求し、'bitwise' 式を使用してアドレスの上部 (10) だけを保持し、レジスタを 即値 10 と比較します。

たとえば、特定の接頭辞('ppp'など)で始まるインターフェース名の照合を要求する場合も同様です。

その他のレジスタでテストを実行する式。

  • cmp: レジスタの値が、指定された即値より小さいか、等しいか、より大きいかをチェックします。これは、カーネルが IP アドレス範囲の照合などに対応する必要がないことを意味します。ユーザランドは単純に2つの比較式を指定します。
reg1 >= 0xc0a80010 and reg1 <= 0xc0a80280

レジスタに保存された IP アドレスがアドレス範囲内であるかどうかを判定します。

  • lookup:特定のセットの中にレジスタの値が存在するかを確認します。nftables は、データのセット(アドレス、ポート番号、インターフェース名など)をサポートします。

たとえば、nftables では、TCP 宛先ポートが一連の値に含まれる場合にマッチするルールを作成できます。

# nft add rule ip filter input tcp dport { 80, 443, 8080 }

nft は内部的に、指定された3つの数字をキーとして含む新しいセットを作成します。そして、nftables マシンに結果があるかどうかを確認させます。

[ payload load 1b @ network header + 9 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d ]

これらは、以前とほとんど同じ式ですが、パケットが TCP パケットかどうかを確認し、レジスタを即値と比較するのではなく、レジスタの値がセットに含まれているかどうかを尋ねます。セットは、キーを格納するだけでなく、キーと値のペアを格納することもできます。

lookup 式は、このようなキー/値セットから値を取得することもできます.つまり、ユーザースペースはキーから値へのテーブルマッピングを作成し、そのセットから取得したコンテンツでレジスタを埋めるように要求できます。 これは、ルールセットに分岐(判断マップ)を実装する場合などに使用できます。

判断マップ(ジャンプテーブル)

iptables ルールは、次のルールに移動するのではなく、カスタムチェーンに移動するようにカーネルに指示することができますが、分岐を使用することはできません。たとえば、以下の例を考えます。

 iptables -N MGMT_PACKETS
 iptables -N VM1_PACKETS
 iptables -N VM2_PACKETS
 iptables -A FORWARD -i eth0 -s 192.168.0.1 -j MGMT_PACKETS
 iptables -A FORWARD -i tap0 -s 10.0.0.1 -j VM1_PACKETS
 iptables -A FORWARD -i tap1 -s 10.0.0.2 -j VM2_PACKETS

これにより、3つの新しいチェーンが追加され、転送されたパケットがソースアドレスと入力インターフェースの特定の組み合わせから送信されている場合、より具体的な処理のためにチェーンを評価するようにカーネルに指示します。ルールセット評価はシーケンシャルであるため、カーネルはマッチするルールを検出するまでこれらのルールをすべてチェックする必要があります。これは数百のインタフェースとアドレスの組み合わせを考慮する必要がある場合には十分スケールしません。

ここで、lookupテーブルを使用します。 nftables を使用すると、上記のルールを1つのルールで表すことができます。

chain forward {
   type ip filter hook forward priority 0; policy accept;
   iif . ip saddr vmap { eth0 .192.168.0.1 : jump mgmt_packets,
                         tap0 .10.0.0.1 : jump vm1_packets,
                         tap1 .10.0.0.2 : jump vm2_packets }
 }
 chain vm1_packets {}
 chain vm2_packets {}
 chain local_packets {}

nftables の「.」構文は、1つのキーを構成するために、2つの異なるソースを連結するために使用されます。 ここでは、入力インターフェースと IP ソースアドレスで構成されるキーを使用して、ジャンプ先を取得するように nftables に指示します。ここで、この例を、数十、あるいは数百の「パケット送信元が特定のインターフェース/アドレスのペアであればこのチェーンへ移動」と考えてみましょう。iptables では、これはスケールしません。 しかしnft では、参照テーブルにジャンプターゲットを追加しても、追加の情報を保存するメモリ消費以外には追加の処理コストがかかりません。

flow文

iptables は「hashlimit」というマッチを提供します。 limitマッチに似ていますが、limitを特定のプロパティをキーとして行うことができる点が異なります。たとえば、送信元IPアドレスや送信元と宛先のペアに対してhashlimitを利用できます。これを行うために、hashlimit マッチは、これらのレート制限カウンターを動的に作成し、それをハッシュテーブルに格納します。

1 対 1 の置き換えを実装する代わりに、nftables は同じコンセプトをより汎用的な方法で実現しています。IP アドレスまたはネットワークごとに制限を動的にインスタンス化するだけではなく、任意の基準のキーに対して式を対応づけます。iptables の hashlimit マッチと同様の効果がある例は以下のようなものです。

nft add rule ip filter input flow table mylimit { ip saddr . tcp dport limit rate 10/second }

flow 文には、特定の期間で認識されなかったフローを自動的に削除するタイムアウトオプションもあります。また、ホスト別やサービス別のアカウンティングにも、同じ文を使用できます。

nft add rule ip filter forward flow table ipacct { ip daddr counter }
nft add rule ip filter forward flow table portcount { tcp dport counter }

次のコマンドを使用して、フローテーブルを一覧表示できます。

nft list flow tables

その内容は以下のようにして確認できます

nft list flow table filter ipacct
 table ip filter {
   flow table ipacct {
      type ipv4_addr
      elements = { 192.168.7.1 : counter packets 4 bytes 336,
                  192.168.0.7 : counter packets 10 bytes 688,
                  127.0.0.1 : counter packets 18 bytes 1512}
   }
 }

このフローテーブルには、認識されている IP アドレスとそのカウンターが一覧表示されます. これにより、ホスト別のトラフィックアカウンティングを簡単に実行できます。

inetファミリー

IPv4 および IPv6 の両方を使用するホスト用のルールセットの作成を容易にするため、nftables には IPv4 と IPv6 の両方に適用される 1つのルールセットを作成するのに使用できる新しい「inet」ファミリーが同梱されています。 これは、デフォルトの ip キーワードの代わりに inet キーワードを使用します。

table inet filter {
  chain input {
    type filter hook input priority 0; policy accept;
    tcp dport ssh
    ip saddr 1.2.3.4
   }
 }

これは2つのルールを含んでいます。最初のルールは、共通のプロトコル(この場合は TCP)のみを調べるため、IPv4 と IPv6 の両方のトラフィックとマッチします。2つ目のルールは、IP アドレスをテストします。ルールは ipv4 固有の ip テーブルではなく、ipv4 と ipv6 の組み合わせの inet テーブルにあるため、nftable は、いわゆる「payload dependency」を挿入しています。以下のようなものです

 inet filter input 5
   [ meta load l4proto => reg 1 ]
   [ cmp eq reg 1 0x00000006 ]
   [ payload load 2b @ transport header + 2 => reg 1 ]
   [ cmp eq reg 1 0x00001600 ]
 inet filter input 6
   [ meta load nfproto => reg 1 ]
   [ cmp eq reg 1 0x00000002 ]
   [ payload load 4b @ network header + 12 => reg 1 ]
   [ cmp eq reg 1 0x04030201 ]

これは2つのルールを含んでいます。 最初のルールは、共通のプロトコル(この場合は TCP)のみを調べるため、IPv4 と IPv6 の両方のトラフィックとマッチします。2つ目のルールは、IP アドレスをテストします。 ルールは ipv4 固有の ip テーブルではなく、ipv4 と ipv6 の組み合わせの inet テーブルにあるため、nftable は、いわゆる「payload dependency」を挿入しています。最初にパケットが IPv4 (nfprotocol 2) であることを確認し、次にパケットからペイロードを読み込みます。 これは、別のファミリーからのパケットが処理される場合に、誤検出を防止するために必要です。これにより、ipv4 および ipv6 に固有のルールを inet テーブルに追加するか、またはブリッジファミリーへ ipv6 ヘッダーをテストするルールなどを追加できます。

payload dependencyは一般的なものです。 上記の最初のルールにも1つ含まれています。たとえばUDPパケットの22番ポートに対する処理中の誤検出を防ぐため、nftablesは レイヤ4プロトコルが6、つまりTCPであることを確認するルールを挿入しています。

はじめる

iptables、ip6tables、ebtables、 arptables、iptables-save、iptables-restore などに慣れているユーザーは、構文が完全に異なることに気付くでしょう。 しかし、概念上の類似点が多数あるため、がっかりすることはありません。nftables と iptables の両方を同時に使用することも可能です。唯一の制限はネットワークアドレス変換です。 iptable_nat もしくは ip6table_natモジュールが読み込まれている場合には、nftablesの「nat」チェーンは効果がありません。

最新のディストリビューションを使用し、'nftables' パッケージをインストールして、'nft' ツールを手に入れましょう。 nft は、ルールを追加/削除するのに必要な唯一のコマンドです。 nft は、コマンドラインから使用することも、対話(シェル風)モードでの使用も、保存されたルールセットをファイルから復元することもできます。nftが利用可能なら、まずは見てまわります。これは、実稼働システムではなく、vm またはテストマシンで行いましょう。

# nft list tables

デフォルトではテーブルはありませんので、新規のシステムでは何も出力されません。次に、新しいテーブルを作成します。

# nft add table ip foo
# nft list tables
table ip foo
# nft list table foo
table ip foo {}

ご覧のとおり、foo という名前の新しい空のテーブルが作成され、これはipv4 パケットのみを扱います。 nftables で利用可能な他のファミリーは、arp、ip6、bridge、inet、および netdev です。

  • arp ファミリーは ARP パケットのみを表示し、
  • ip6 ファミリーは IPv6 パケットのみを処理します。
  • bridgeファミリーは、イーサネットパケットのみを処理し、
  • inet ファミリーは、IPv4 パケットと IPv6 パケットの両方を受け取ります。
  • netdev ファミリは、ネットワークインターフェースにテーブルを直接アタッチするのに使用できます。 netdev ファミリーのテーブルには、インターフェースで受信したあらゆるトラフィックのフィルタリングに使用できる新しい「ingress」フックポイントがあります。

ファミリーとして処理するパケットタイプを定義する他には、テーブルに特別な意味はありません。チェーンのコンテナーとしてのみ動作します。テーブルは、個別の名前空間を定義するため、異なるテーブルに存在するものであれば、同じ名前を持つチェーンを作成できます。

 

チェーンの追加

iptables に精通しているユーザーは、各テーブルに組み込みチェーンがあることをご存知でしょう。iptables では、これらは、PREROUTING(受信パケット用)、INPUT(ローカルマシン向けパケット用)、 FORWARD(転送またはルーティング中のパケット用)、 OUTPUT(ローカルで生成したパケット用)、および POSTROUTING(送信されるすべてのパケット用)と呼ばれます。

nftables には、これらの組み込みチェーンはありません。 ただし、これらとまったく同じフックポイントが定義されます。フックポイントはカーネルネットワークスタック内の特定の場所で、パケットを検査して検査の結果にもとづいてドロップや許可のような判断をおこなう機能を提供します。これらのフックは、 iptables、ip6tables、ebtables、および arptables の内部でも組み込みチェーンを登録するために使用されています。そこで、inputフックポイントでパケットをフックするチェーンを追加してみましょう。

# nft add chain ip foo bar '{ type filter hook input priority 0; }'
# nft list table foo
table ip foo {
   chain bar {
      type filter hook input priority 0; policy accept;
   }
}

何を行ったのでしょうか? カーネルに対して、ローカルマシン向けのパケット(inputフック)を'bar' という名前のチェーンに含まれるルールを介して送信するよう伝えています。 iptables のフィルターテーブルを真似するには、名前をbar から INPUT に変更し、さらに作成していきます。

chain FORWARD {
    type filter hook forward; policy accept;
}

...outputフックについても同様です。 フック名を含むチェーンは、ベースチェーンと呼ばれます。同じフックポイントでも、複数のベースチェーンが存在する可能性があります。この場合、優先度番号が最も小さいチェーン(負の値にもできます)が最初に処理されます。 ベースチェーンの優先順位が同じ場合、順序は未定義になります。

ルールを追加しましょう。

# nft add rule ip foo bar counter
# nft list table foo

table ip foo {
  chain bar {
    type filter hook input priority 0; policy accept;
    counter packets 2 bytes 168
   }
}

ご覧のとおり、1つのテーブルがinputフックポイントにフックされた1つのチェーンを持ち、検出されたすべてのパケットについてカウンターを増加するだけのルールを持っています。単一のルールを追加するためだけに、この作業をすべて実行する必要がある理由、または「type filter」の意味を知りたいことでしょう。

nftables には組み込みテーブルはありませんが、ip (6)tableの組み込みテーブルのnft版を提供する、事前作成済みのルールファイルが付属しています。まず今まで行った変更を元に戻し、nftables で作成される mangle テーブルを確認しましょう。

# nft delete table foo

# cat /etc/nftables/ipv4-mangle
#!/sbin/nft -f
table mangle {
    chain output { type route hook output priority -150; }
}

(ディストリビューションによっては、/usr/etc/nftables などのように、別の場所に配置をしている場合があります。)

このテーブルは、次のコマンドで読み込むことができます。

# nft -f /etc/nftables/ipv4-mangle

特別な「route」タイプは、パケットがチェーンを通過した後に新しいルートルックアップを実行するよう netfilter コアに指示します。 これは、ほとんどの場合、ポリシールーティングを実装するために、パケットマークおよび「ip rule」コマンドと共に使用されます。古い iptables 環境では、このプロパティは mangle テーブルにハードコードされますが、nftables ではベースチェーンのプロパティです。ルート変更のためにパケットのプロパティを変更するチェーンは、このキーワードを使用して再参照をトリガーする必要があります。旧世代のツールでは組み込みであった他のテーブルにも、同様のスケルトンルールセットが存在します。 以下に例を示します。

# ls /etc/nftables

bridge-filter  ipv4-filter  ipv4-nat  ipv6-filter  ipv6-nat  inet-filter    ipv4-mangle  ipv4-raw  ipv6-mangle

それでは、より実用的な、IPv4 および IPv6 の簡単なフィルターセットを追加してみましょう。

# nft -f /etc/nftables/inet-filter

# nft add rule inet filter input iif lo accept

...自分自身の接続への応答トラフィックを受け入れます。

# nft add rule inet filter input ct state established,related accept

... ipv6 近隣探索を受け付けます。

# nft add rule inet filter input ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit,
                              echo-request, nd-router-advert,
                              nd-neighbor-advert } accept

... 誤ってロックアウトされることがないよう、ドロップなしでカウンターを追加します。

# nft add rule inet filter input counter

新しいルールセットを見てみましょう。

# nft list table inet filter
 table inet filter {
   chain input {
      type filter hook input priority 0; policy accept;
      iif lo accept
      ct state established,related accept
      ip6 nexthdr ipv6-icmp icmpv6 type { nd-neighbor-solicit,
                                          nd-neighbor-advert,
                                          nd-router-advert,
                                          echo-request} accept
      counter packets 0 bytes 0
    }
}

次に、ルールの削除方法を説明します。nftables では、内部の「handle」を使用してルールを削除できます。これはカーネルがルールに付与した番号です。 この番号を確認するには、handle オプションを指定して上記のコマンドを再実行します。

# nft --handle list table inet filter
[..]
counter packets 0 bytes 0 # handle 10
  }
}
# nft delete rule inet filter input handle 10

上記を実行すると、カウンタールールが無効になります。テーブルを削除して再作成せずに、新しく作りなおしたい場合は、

# nft flush table inet filter

とすることですべてのチェーンを維持したままルールを削除します。

NAT

nftables で定義されていると、ipv4 nat テーブルは次のようになります。

# cat  /etc/netfilter/ipv4-nat
table nat {
  chain prerouting    { type nat hook prerouting priority -150; }
  chain postrouting    { type nat hook postrouting priority -150; }
}

唯一の違いは、「type nat」です。これはカーネルに新しいコネクションの最初のパケットを指定されたチェーンに渡すよう指示します。 チェーン名およびテーブル名は重要ではないことに注意してください.たとえば、次のようにもできます。

# nft add chain filter myredirects “{ type nat hook prerouting; }”

これにより、filterというテーブル内の、チェーン「myredirects」でネットワークアドレス変換を設定できます。

nft add rule filter myredirects ip saddr 192.168.0.024 tcp dport 80 redirect to :8080

nftables は、SNAT およびマスカレードもサポートします。iptables MASQUERADE と同様に、後者は SNAT マッピングの特別なケースで、ネットワークインターフェースのプライマリーアドレスを使用します。 これは、ダイヤルアップ接続などのアドレスを動的に割り当てたインターフェースに適しています。

nft add rule nat postrouting ip saddr 192.168.0.0/24 oif eth0 snat 10.2.3.4
nft add rule nat postrouting ip saddr 192.168.0.0/24 oif eth0 masquerade

既知の制限

ネイティブの nft 置き換えがない iptables マッチおよびターゲットが、いくつか存在します。最も重要なものは、次のとおりです。

  • パケットを処理するためにIPsec が使用するポリシーを調べるために使用されるポリシーマッチ。
  • パケットに対して逆パス IP フィルター(逆引きルートルックアップ)のテストを実行するための rpfilter フィルターマッチ
  • TCP 最大セグメントサイズを変更する TCPMSS ターゲット

(訳注: 2019年現在では、これらの重要な差分についてそれぞれ、ipsec式、rpfilterに対応するfib式、 tcpmssの指定に利用できるextension header文が整備されています。 )

iptables マッチとネイティブ nft 置き換えの一覧

  • Ah, esp, dscp, sctp, ecn, hbh, hl, mac, mh, rt (payload 式)
  • Cgroup, cpu, mark, devgroup, length, owner, pkttype,  realm, statistic (meta 式)
  • Connbytes, connlabel, connmark conntrack, helper (ct 式)
  • Comment
  • Hashlimit (flow 文)
  • Limit
  • Iprange, multiport (sets)

iptables ターゲットとネイティブ nft 置き換えの一覧

  • CLASSIFY (meta 式)
  • DNAT, SNAT, MASQUERADE, REDIRECT
  • DSCP, ECN, HL, TTL (payload 式)
  • LOG, NFLOG (log 文)
  • MARK, TRACE (meta 文)
  • NFQUEUE
  • REJECT
  • TEE

arptables と ebtables は、機能完全と見なされています。つまり、すべての ebtablesマッチにネイティブ nft置き換えがあり、唯一の例外は ebtables の'arpreply'ターゲットです。

rpfilterとポリシーマッチのためのネイティブ置換が実装中です。tcpmss を強制する機能は、将来追加されるでしょう。


(以下は訳者による追記)

関連記事

関連記事へのリンクです。

nftablesとiptablesのベンチマークによる比較記事です。 developers.redhat.com

nftablesを利用する場合、 nftables wikiのドキュメントを読むのがおすすめです。 wiki.nftables.org

firewalldはnftables backendに対応していて、RHEL8ではデフォルトで提供されます。 firewalld.org

iptables, ip6tables等のコマンドを拡張して、カーネルのバックエンドとしてnftablesを利用できるよう開発されています。RHEL8ではデフォルトで提供されます。 wiki.nftables.org

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません