nftables は、Linux の Netfilter サブシステムをバックエンドに実装されたフレームワークのひとつ。 nftables を使うことで、パケットフィルタリングや NAT、パケット分類などを統一的に管理できる。 nftables は、xtables (iptables, ip6tables など) を置き換える後継として開発された。
今回は、その nftables が管理しているルールがどのように動いているかをトレース機能 (meta nftrace) を使って調べる方法について。 nftables のルールをデバッグする際、素朴なやり方ではログやカウンタを用いるやり方がある。 それに比べてトレース機能を使うと、より詳細は情報が得られる。
使った環境は次のとおり。
$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 24.04.2 LTS Release: 24.04 Codename: noble $ uname -srm Linux 6.8.0-58-generic x86_64 $ nft --version nftables v1.0.9 (Old Doc Yak #3)
もくじ
下準備
あらかじめ、必要なパッケージをインストールしておく。
$ sudo apt-get -y install nftables iproute2 iputils-ping
実験用の Network Namespace を用意する
ホストを直接使って nftables の実験をすると不都合が多い。 そこで、Network Namespace を使って隔離されたネットワークスタックを用意する。 今回は 2 つの Network Namespace を用意して、それぞれを veth でつなぐ。
まずは Network Namespace を用意する。
$ sudo ip netns add ns1 $ sudo ip netns add ns2
両者をつなぐための veth を作る。
$ sudo ip link add ns1-veth0 type veth peer name ns2-veth0
veth の両端を Network Namespace に所属させる。
$ sudo ip link set ns1-veth0 netns ns1 $ sudo ip link set ns2-veth0 netns ns2
veth デバイスの MAC アドレスをドキュメンテーションアドレスに変更しておく。
$ sudo ip netns exec ns1 ip link set dev ns1-veth0 address 00:00:5E:00:53:01 $ sudo ip netns exec ns2 ip link set dev ns2-veth0 address 00:00:5E:00:53:02
インターフェイスの状態を UP にする。
$ sudo ip netns exec ns1 ip link set ns1-veth0 up $ sudo ip netns exec ns2 ip link set ns2-veth0 up
インターフェイスにドキュメンテーションアドレスの IP アドレスを付与する。
$ sudo ip netns exec ns1 ip address add 192.0.2.1/24 dev ns1-veth0 $ sudo ip netns exec ns2 ip address add 192.0.2.2/24 dev ns2-veth0
この状態で、一旦 ping による疎通があるかを確認しておく。
$ sudo ip netns exec ns1 ping -c 3 192.0.2.2 -I 192.0.2.1 PING 192.0.2.2 (192.0.2.2) from 192.0.2.1 : 56(84) bytes of data. 64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=0.034 ms 64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.017 ms 64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.030 ms --- 192.0.2.2 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2074ms rtt min/avg/max/mdev = 0.017/0.027/0.034/0.007 ms
以降は Network Namespace の ns1
に nftables の設定を投入して実験していく。
トレース対象のルールを追加する
まず、初期状態では nftables に何も設定が入っていない。
nftables に設定されているルールは nft list ruleset
コマンドで確認できる。
$ sudo ip netns exec ns1 nft list ruleset
ここに nft -f
で設定を投入する。
引数にハイフンを指定することで、標準入力から設定を読み込むことができる。
以下の設定では、inet アドレスファミリの filter
テーブルの中に、input
チェインがある。
input
チェインは type filter hook input
なので、Netfilter の input hook 経由でパケットが入ってくる。
そして、input
チェインには ip protocol icmp icmp type echo-request
というルールが含まれる。
これは ICMPv4 の Echo Request、つまりは Ping の往路と一致するルールになっている。
$ cat << 'EOF' | sudo ip netns exec ns1 nft -f - table inet filter { chain input { type filter hook input priority 0; policy accept ip protocol icmp icmp type echo-request } } EOF
上記を実行すると、Network Namespace の ns1
に nftables の設定が入る。
なお、このルールは一致したとしても何もしない。
また、チェインのデフォルトのポリシーが accept なので、パケットはそのまま通過する。
$ sudo ip netns exec ns1 nft list ruleset table inet filter { chain input { type filter hook input priority filter; policy accept; ip protocol icmp icmp type echo-request } }
上記のルールによってパケットが処理される様子をトレース機能で追跡したい。
トレース用のルールを追加する
続いては、トレース機能を使うためのルールを追加する。 nftables のトレース機能 (meta nftrace) を使うには、パケットにトレースを有効にするメタ情報のフラグをつける必要がある。 トレース機能のメタ情報のフラグが有効になったパケットは、以降の処理でモニター用の機能を使って追跡できるようになる。 そこで、メタ情報のフラグを付与するためのルールが必要になる。
今回は、input hook よりも早く処理される prerouting hook に、トレース用のルールを追加しよう。
以下の設定では、inet アドレスファミリの filter
テーブルの中に、prerouting
チェインを作っている。
prerouting
チェインは type filter hook prerouting
なので、Netfilter の prerouting hook 経由でパケットが入ってくる。
そして、prerouting
チェインには ip protocol icmp meta nftrace set 1
というルールが含まれる。
これは ICMPv4 のパケットにトレース機能のフラグを付与している。
$ cat << 'EOF' | sudo ip netns exec ns1 nft -f - table inet filter { chain prerouting { type filter hook prerouting priority 0; policy accept ip protocol icmp meta nftrace set 1 } } EOF
設定を投入すると、ルールセットは次のようになる。
$ sudo ip netns exec ns1 nft list ruleset table inet filter { chain input { type filter hook input priority filter; policy accept; ip protocol icmp icmp type echo-request } chain prerouting { type filter hook prerouting priority filter; policy accept; ip protocol icmp meta nftrace set 1 } }
処理の流れをモニターする
この状態で nft monitor trace
コマンドを実行しよう。
実行すると出力を待ち受けた状態になる。
$ sudo ip netns exec ns1 nft monitor trace
ここで、別のターミナルを開いて ns2
から ns1
に向けて Ping を打ってみよう。
$ sudo ip netns exec ns2 ping -c 1 192.0.2.1 PING 192.0.2.1 (192.0.2.1) 56(84) bytes of data. 64 bytes from 192.0.2.1: icmp_seq=1 ttl=64 time=0.051 ms --- 192.0.2.1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.051/0.051/0.051/0.000 ms
すると、先ほど実行した nft monitor trace
コマンドに出力が得られる。
$ sudo ip netns exec ns1 nft monitor trace trace id 2d55095a inet filter prerouting packet: iif "ns1-veth0" ether saddr 00:00:5e:00:53:02 ether daddr 00:00:5e:00:53:01 ip saddr 192.0.2.2 ip daddr 192.0.2.1 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 23062 ip protocol icmp ip length 84 icmp type echo-request icmp code net-unreachable icmp id 3186 icmp sequence 1 @th,64,96 0x455136800000000f21b0100 trace id 2d55095a inet filter prerouting rule ip protocol icmp meta nftrace set 1 (verdict continue) trace id 2d55095a inet filter prerouting policy accept trace id 2d55095a inet filter input packet: iif "ns1-veth0" ether saddr 00:00:5e:00:53:02 ether daddr 00:00:5e:00:53:01 ip saddr 192.0.2.2 ip daddr 192.0.2.1 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 23062 ip protocol icmp ip length 84 icmp type echo-request icmp code net-unreachable icmp id 3186 icmp sequence 1 @th,64,96 0x455136800000000f21b0100 trace id 2d55095a inet filter input rule ip protocol icmp icmp type echo-request (verdict continue) trace id 2d55095a inet filter input policy accept
上記から、以下の部分で ICMP の Echo Request のパケットに prerouting のルールでメタ情報が付与され、そのまま通過してチェインのデフォルトのポリシーで accept された様子が確認できる。
trace id 2d55095a inet filter prerouting packet: iif "ns1-veth0" ether saddr 00:00:5e:00:53:02 ether daddr 00:00:5e:00:53:01 ip saddr 192.0.2.2 ip daddr 192.0.2.1 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 23062 ip protocol icmp ip length 84 icmp type echo-request icmp code net-unreachable icmp id 3186 icmp sequence 1 @th,64,96 0x455136800000000f21b0100 trace id 2d55095a inet filter prerouting rule ip protocol icmp meta nftrace set 1 (verdict continue) trace id 2d55095a inet filter prerouting policy accept
同様に、以下の部分では input のルールに一致した後に、そのまま通過してチェインのデフォルトのポリシーで accept されたことが確認できる。
trace id 2d55095a inet filter input packet: iif "ns1-veth0" ether saddr 00:00:5e:00:53:02 ether daddr 00:00:5e:00:53:01 ip saddr 192.0.2.2 ip daddr 192.0.2.1 ip dscp cs0 ip ecn not-ect ip ttl 64 ip id 23062 ip protocol icmp ip length 84 icmp type echo-request icmp code net-unreachable icmp id 3186 icmp sequence 1 @th,64,96 0x455136800000000f21b0100 trace id 2d55095a inet filter input rule ip protocol icmp icmp type echo-request (verdict continue) trace id 2d55095a inet filter input policy accept
このように、ルールでトレース機能を有効化して、それをモニターすることで nftables の処理の流れを把握できる。
まとめ
今回は nftables で処理の流れを追跡してルールのデバッグに活かすことのできるトレース機能 (meta nftrace) について扱った。
今回の例では、メタ情報を付与するための専用のチェインとルールを追加していた。 しかし、必要な区間でピンポイントにメタ情報を付与して、必要なくなったらメタ情報を取り除くといったことも考えられる。
また、nft monitor trace の出力は場合によっては大量になることから grep(1) などを用いて必要な内容だけに絞り込むのも良いようだ。