nftables

提供: ArchWiki
2017年1月14日 (土) 19:34時点におけるFragment (トーク | 投稿記録)による版 (→‎シンプルな IP/IPv6 ファイアウォール: ポート番号修正)
ナビゲーションに移動 検索に移動

関連記事

nftables は既存の ip-, ip6-, arp-, ebtables フレームワークを置き換える netfilter のプロジェクトです。新しいパケットフィルタリングフレームワーク、新しいユーザースペースユーティリティ (nft)、そして ip- と ip6tables の互換レイヤーを提供します。現行のフック、接続追跡システム、ユーザースペースのキューイングコンポーネント、そして netfilter のログサブシステムを使っています。

nftables は3つのメインコンポーネントから構成されています: カーネルの実装、libnl netlink communication そして nftables ユーザースペースフロントエンド。カーネルは netlink の設定インターフェイスだけでなく、小さなクラス言語インタプリタを使用するランタイムのルールセットの評価も提供します。libnl にはカーネルと通信するためのローレベルな関数が含まれています。nftables フロントエンドはユーザーが対話するものです。

nftables の公式 wiki には詳しい情報が載っています。

インストール

Linux カーネル 3.13 から nftables を使うことはできますが、できるかぎり最新のカーネルを使用すること推奨します。nftables のユーザーランドユーティリティは nftables パッケージで利用できます。AUR には nftables-gitAUR パッケージも存在します。

基本的な実装

他のファイアウォールと異なり、nftables ではコマンドラインで作成される一時的なルールと、ファイルに保存して読み込まれる永続的なルールを区別しています。デフォルトファイルの /etc/nftables.conf には "inet filter" という名前のシンプルな ipv4/ipv6 ファイアウォールテーブルが既に記述されています。

デフォルトルールセットのロード

nftables.service起動有効化してください。

以下のコマンドでルールセットを確認できます:

# nft list ruleset

inet filter テーブルの設定が表示された場合、デスクトップとしてインターネットを問題なく利用できます。

ノート: systemd サービスが正しく動作するように必要な nftables 関連のモジュール全てのエントリを含む /etc/modules-load.d/nftables.conf を作成する必要があります。モジュールのリストは次のコマンドで取得可能です:
$ lsmod | grep '^nf'
作成していないと、Error: Could not process rule: No such file or directory エラーで終了してしまいます。

nft

nftables のユーザースペースユーティリティ nft は現在カーネルのためにルールセットを処理する前にほとんどのルールセットの評価を行います。そのため、nftables はデフォルトのテーブルやチェインを提供していません。しかしながらユーザーが iptables のような設定をエミュレートすることが可能です。

ノート: nftables には "filter" テーブルが記述されている /etc/nftables.conf が含まれています。このテーブルのルールでは、特定のプロトコルだけを許可して、他のプロトコルは全て拒否するようになっています。

nft は ifconfig や iproute2 と同じような感じで動作します。iptables のように引数のスイッチを使う代わりに、長く構造化された連続のコマンドになります。例えば:

nft add rule ip6 filter input ip6 saddr ::1 accept

add はコマンドです。ruleadd のサブコマンドです。ip6rule の引数で、ip6 ファミリーを使うことを宣言しています。filterinputrule の引数で、それぞれ使用するテーブルとチェインを指定しています。残りはルールの定義で、マッチ (ip) とパラメータ (saddr)、パラメータの引数 (::1) そしてジャンプ (accept) からなります。

以下は nft で利用できるコマンドの不完全なリストです:

list
  tables [family]
  table [family] <name>
  chain [family] <table> <name>

add
  table [family] <name>
  chain [family] <table> <name> [chain definitions]
  rule [family] <table> <chain> <rule definition>

table [family] <name> (shortcut for `add table`)

insert
  rule [family] <table> <chain> <rule definition>

delete
  table [family] <name>
  chain [family] <table> <name>
  rule [family] <table> <handle>

flush
  table [family] <name>
  chain [family] <table> <name>

family は任意ですが、デフォルトは ip になります。

テーブル

テーブルの用途はチェインを保持することです。iptables のテーブルと違って、nftables には初めから組み込まれているテーブルはありません。テーブルは指定の5つのファミリーのうちどれか一つを持つことができ、それによって様々な iptables のユーティリティを一つに統一します:

nftables ファミリー iptables ユーティリティ
ip iptables
ip6 ip6tables
inet iptables と ip6tables
arp arptables
bridge ebtables

ファミリー

ip (IPv4) がデフォルトのファミリーです。特に指定がなければ ip が使われます。

IPv6 は ip6 で指定できます。

IPv4 と IPv6 の両方に適用されるルールを作成するには inet を使います。Linux 3.15 以上が必要で、ipip6 ファミリーを統一してルールを簡単に定義できます。

ノート: inetnat タイプのチェインでは使えず、filter タイプのチェインを使う必要があります (ソース)。

表示

ファミリーの現在のテーブルは nft list コマンドで一覧できます。

# nft list tables
# nft list tables ip6

テーブルの名前を指定することで完全なテーブルの定義を一覧できます:

# nft list table foo
# nft list table ip6 foo

作成

テーブルは2つのコマンド (片方はもう片方のショートカットです) で追加することができます。以下は foo という名前の ip テーブルと foo という名前の ip6 テーブルを追加する例です:

# nft add table foo
# nft table ip6 foo

ファミリーが異なっていれば同じ名前のテーブルを作ることが可能です。

削除

テーブルを削除することができるのはチェインが存在しない場合だけです。

# nft delete table foo
# nft delete table ip6 foo

チェイン

チェインの用途はルールを保持することです。iptables のチェインと違って、nftables には初めから組み込まれているチェインはありません。そのためチェインが netfilter フレームワークにあるタイプやフックをどれも使わない場合、iptables とは異なりチェインを通り抜けるパケットは nftables の影響を受けません。

表示

nft list table foo コマンドは foo テーブルの全てのチェインを表示します。個々のチェインからルールを一覧することもできます。

# nft list chain foo bar
# nft list chain ip6 foo bar

上記コマンドは ip と ip6 の foo テーブルの bar チェインを表示します。

作成

テーブルがファイル定義や nft add chain コマンドによって作成されたら、チェインを追加することができます。

# nft add chain foo bar
# nft add chain ip6 foo bar

上記コマンドは bar という名前のチェインを ip と ip6 の foo テーブルに追加します。

プロパティ

nftables には組み込みチェインが存在しないため、チェインは netfilter フレームワークの特定の機能にアクセスすることができます。

# nft add chain filter input \{ type filter hook input priority 0\; \}

上記コマンドは nftables に input という名前のチェインを filter テーブルに追加させ、そのタイプ・フック・プライオリティを定義します。これらのプロパティは基本的に iptables で組み込まれているテーブルやチェインを置き換えるものです。

タイプ

チェインには3つのタイプがあり、iptables で使われているテーブルと対応しています:

  • filter
  • nat
  • route (mangle)
フック

チェインは6つのフックを使うことができ、ingress 以外は iptables で使われているチェインと対応しています:

  • ingress
  • input
  • output
  • forward
  • prerouting
  • postrouting

ingress フックは既存の tc ユーティリティを置き換えます。

プライオリティ
ノート:
  • パケットが先に来るチェインにはプライオリティの効果はありません。
  • プライオリティは符号なしの整数として設定するようになっているため、負のプライオリティを設定した場合、優先度は逆に高くなります。

プライオリティは nftables がどのパケットを初めに通過させるかを示します。整数で指定し、高い値を与えるほど優先されます。

編集

チェインを編集するには、以下のようにコマンドを実行してください:

# nft chain <table> <family> <chain> { [ type <type> hook <hook> device <device> priority <priority> \; policy <policy> \; ] }

例えば、デフォルトテーブルの input チェインのポリシーを "accept" から "drop" に変更するには:

# nft chain inet filter input { policy drop \; }

削除

チェインはルールが存在しない場合にのみ削除することができます。

# nft delete chain foo bar
# nft delete chain ip6 foo bar

以上のコマンドは ip と ip6 の foo テーブルから bar チェインを削除します。

ルール

ルールの用途はパケットを識別(マッチ)して処理を実行(ジャンプ)することです。iptables と同じように、様々なマッチやジャンプが利用できますが、nftables には欠けている機能も存在します。

表示

テーブルを表示するのと同じ方法を使って、nft list コマンドでテーブルの中の現在のルールを表示することができます。個別のチェインからルールを表示することも可能です。

# nft list chain foo bar
# nft list chain ip6 foo bar

上記のコマンドで、ip と ip6 の foo テーブルの bar チェインのルールが表示されます。

作成

テーブルがファイル定義や nft add rule コマンドによって作成されたら、ルールを追加することができます。

# nft add rule foo bar ip saddr 127.0.0.1 accept
# nft add rule ip6 foo bar ip saddr ::1 accept

上記のコマンドで、ip と ip6 の foo テーブルの bar チェインにルールが追加され、saddr (ソースアドレス) が 127.0.0.1 (IPv4) や ::1 (IPv6) の場合に ip パケットにマッチして、パケットを許可します。

マッチ

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>

ジャンプ

ジャンプは iptables と同じように使うことができますが、ひとつのルールで複数のジャンプを使用できるようになっています。

# nft add rule filter input tcp dport 22 log accept

以下はジャンプの未完成なリストです:

  • accept (パケットを許可)
  • reject (パケットを拒否)
  • drop (パケットを破棄)
  • snat (送信元 NAT を実行)
  • dnat (宛先 NAT を実行)
  • log (パケットを記録)
  • counter (パケットカウンタを保持、nftables ではカウンタはオプションです)
  • return (チェインの横断を停止)
  • jump <chain> (他のチェインにジャンプ)
  • goto <chain> (他のチェインにジャンプ、元のチェインに戻らない)

挿入

先頭に追加

nft insert rule コマンドでチェインにルールを挿入することができます。

# nft insert rule filter input ct state established,related accept

特定の場所に追加

Nftables はハンドルを使用してルールの位置を定義します。情報を取得するには、-a フラグを付けてルールセットを確認してください:

# nft list ruleset -a

特定のハンドラが付いているルールの後にルールを追加するには:

# nft add rule table_name chain_name position handler_number [rule-definition]

削除

個々のルールはハンドルを使わないと削除することができません。nft --handle list コマンドを使うことでルールのハンドルを確認できます。--handle スイッチを付けると、nft はハンドルを出力するようになります。

以下ではルールのハンドルを確認してルールを削除しています。未解決の IP アドレスのような、数字の出力を表示するときは --number 引数を使うと良いでしょう。

# nft --handle --numeric list chain filter input
table ip fltrTable {
     chain input {
          type filter hook input priority 0;
          ip saddr 127.0.0.1 accept # handle 10
     }
}
# nft delete rule fltrTable input handle 10

nft flush table コマンドを使うことでテーブルの全てのチェインをフラッシュできます。個別のチェインをフラッシュするときは nft flush chain または nft delete rule コマンドを使います。

# nft flush table foo
# nft flush chain foo bar
# nft delete rule ip6 foo bar

最初のコマンドでは ip foo テーブルのチェイン全てをフラッシュします。2番目のコマンドは ip foo テーブルの bar チェインをフラッシュします。3番目のコマンドは ip6 foo テーブルの bar チェインの全てのルールを削除します。

アトミックリロード

現在のルールセットをフラッシュする:

# echo "flush ruleset" > /tmp/nftables

現在のルールセットをダンプする:

# nft list ruleset >> /tmp/nftables

/tmp/nftables を編集して次のコマンドで変更を適用:

# nft -f /tmp/nftables

ファイル定義

nft -f コマンドでファイル定義を利用することができます。このコマンドは iptables-restore コマンドと同じように動作します。ただし、iptables-restore と違って、既存のルールセットをフラッシュしないので、前もって flush コマンドを実行する必要があります。

/etc/nftables/filter.rules
flush table ip filter
table ip filter {
     chain input {
          type filter hook input priority 0;
          ct state established,related accept
          ip saddr 127.0.0.1 accept
          tcp dport 22 log accept
          reject
     }
}

ルールを (iptables-save のように) エクスポートするには:

# nft list ruleset

基本的なファイアウォール

以下の例は nft コマンドを使ってベーシックな IPv4 ファイアウォールを設定する方法を示しています。IPv4 と IPv6 の両方をフィルタリングしたい場合、/usr/share/nftables にある他のサンプルを見たり、/etc/nftables.conf のデフォルト (IPv4/IPv6 で動作するように設定済みです) を使うようにしてください。

iptables のようなチェインを設定するには、まず備え付けの IPv4 フィルターファイルを使う必要があります:

# nft -f /usr/share/nftables/ipv4-filter

作成されたチェインを表示するには:

# nft list table filter

特定の宛先への出力を破棄:

# nft add rule ip filter output ip daddr 1.2.3.4 drop

宛先がローカルのポート 80 のパケットを破棄:

# nft add rule ip filter input tcp dport 80 drop

チェインの全てのルールを削除:

# nft delete rule filter output

サンプル

シンプルな IP/IPv6 ファイアウォール

firewall.rules
# A simple firewall

flush ruleset

table inet filter {
	chain input {
		type filter hook input priority 0; policy drop;

		# established/related connections
		ct state established,related accept

		# invalid connections
		ct state invalid drop
		
		# loopback interface
		iif lo accept

		# 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

		# SSH (port 22)
		tcp dport ssh accept

		# HTTP (ports 80 & 443)
		tcp dport { http, https } accept
	}
}

Limit rate IP/IPv6 ファイアウォール

firewall.2.rules
table inet filter {
	chain input {
		type filter hook input priority 0; policy drop;

		# no ping floods:
		ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate 10/second accept
		ip protocol icmp icmp type echo-request limit rate 10/second accept

		ct state established,related accept
		ct state invalid drop

		iifname lo accept

		# avoid brute force on ssh:
		tcp dport ssh limit rate 15/minute accept

	}
}

ジャンプ

設定ファイルでジャンプを使うときは、先にターゲットチェインを定義する必要があります。そうしないと Error: Could not process rule: No such file or directory というエラーが発生します。

jump.rules
table inet filter {
    chain web {
        tcp dport http accept
        tcp dport 8080 accept
    }
    chain input {
        type filter hook input priority 0;
        ip saddr 10.0.2.0/24 jump web
        drop
    }
}

実践的なサンプル

インターフェイスによってルールを変える

複数のネットワークインターフェイスが存在する場合、それぞれのインターフェイスごとに別々のフィルターチェインを設定したい場合があるかもしれません。例えば、ホームルーターを構築するとき、LAN 上でアクセスできるウェブサーバーを実行しつつ (nsp3s0 インターフェイス)、インターネットからはアクセスできないようにしたい場合 (enp2s0 インターフェイス) などは以下のように設定します:

table inet filter {
  chain input { # this chain serves as a dispatcher
    type filter hook input priority 0;

    iifname lo accept # always accept loopback
    iifname enp2s0 jump input_enp2s0
    iifname enp3s0 jump input_enp3s0

    reject with icmp type port-unreachable # refuse traffic from all other interfaces
  }
  chain input_enp2s0 { # rules applicable to public interface interface
    ct state {established,related} accept
    ct state invalid drop
    udp dport bootpc accept
    tcp dport bootpc accept
    reject with icmp type port-unreachable # all other traffic
  }
  chain input_enp3s0 {
    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 icmp type port-unreachable # all other traffic
  }
  chain ouput { # we let everything out
    type filter hook output priority 0;
    accept
  }
 }

もしくは iifname ステートメントを特定のインターフェイスで使用して、他のインターフェイスについてはデフォルトルールを設定するという方法もあります。

マスカレード

nftables には特殊なキーワード masquerade が存在し、送信元アドレスが自動的に出力インターフェイスのアドレスに設定されます (ソース)。ルーターのインターフェイスが多数の ISP に接続されているときなど、インターフェイスの IP アドレスが一定でない場合に有用です。通常は、インターフェイスの IP アドレスが変わるたびにネットワークアドレス変換 (NAT) のルールを更新する必要があります。

masquerade を使用するには:

  • カーネルのバージョンが 3.18 以上である必要があります。
  • カーネルコンフィグで以下のマスカレード設定が有効になっている必要があります。
CONFIG_NFT_MASQ=m
  • masquerade キーワードは nat タイプのチェインでのみ使うことができ、inet ファミリーのテーブルでは利用できません。ip ファミリーや ip6 ファミリーのテーブルを使ってください。
  • マスカレードは一種のソース NAT であり、出力パスでのみ機能します。

2つのインターフェイスが存在し nsp3s0 が LAN に接続され、enp2s0 がインターネットに接続されているマシンでの設定例:

table ip nat {
  chain prerouting {
    type nat hook prerouting priority 0;
  }
  chain postrouting {
    type nat hook postrouting priority 0;
    oifname "enp0s2" masquerade
  }
}

Syslog にログを出力する

Linux カーネル 3.17 未満を使っている場合、ログ出力を有効にするには xt_LOG を modprobe する必要があります。

参照