メニュー 閉じる

iptables後継のnftables基本操作

2019年9月24日、皆さん待望のCentOS 8がリリースされました。
CentOS 6から7になった際も色々と変化がありましたが、CentOS 7から8でもやはり何点か変化があります。

主要な変化としては以下の様なものが挙げられるでしょう。

  • カーネルやミドルウェアのバージョン変更
  • yumからdnfへ移行
  • iptablesからnftablesへの移行

これらの差異については他サイトへ譲るとして、今回はnftablesの操作について簡単に紹介します。

nftablesの起動・終了

nftablesはサービスとして導入されています。
そのためsystemctlコマンドで操作が可能です。

# systemctl start nftables
# systemctl stop nftables

設定ファイル

nftablesサービスの起動時、設定ファイルとして/etc/nftables.confを読み込みます。

ルールの表示

nftablesの操作にはnftコマンドを使います。
ルールを表示するには、nft list rulesetを実行します。

# nft list ruleset
table inet filter {
        chain input {
                type filter hook input priority 0; policy accept;
        }

        chain forward {
                type filter hook forward priority 0; policy drop;
        }

        chain output {
                type filter hook output priority 0; policy accept;
        }
}

nftablesではiptablesと同様にルールは上から評価されます。
そのためルールの順番が重要です。
操作するルールの位置を表示するためには、--handleパラメータを使います。

# nft list ruleset --handle
table inet filter { # handle 0
        chain input { # handle 1
                type filter hook input priority 0; policy accept;
                iifname "lo" accept # handle 4
        }
..(snip)..

説明のため異なるルールを表示していますが、tablechain、ルールの末尾にhandleが付くようになりました。
ルールの操作をする際には、この番号を使う事になります。

ルールの構造

nft list rulesetの結果を見ると、iptablesとは出力が全く異なることが分かります。
nftablesでは、

名前 説明
table アドレスファミリー毎にchainをまとめるもの
chain ruleをまとめるもの
rule 通信制御ルール

というような概念となっています。

table inet filterは、アドレスファミリー:inet、テーブル名:filterというテーブルを示します。
chain inputは、チェイン名:inputというチェインを示します。

アドレスファミリー

アドレスファミリーは以下の種類が定義されます。

family 説明
ip IPv4を示します
ip6 IPv6を示します
inet インターネット(IPv4とIPv6)の両方を示します
arp ARPを示します。IPv4 ARPを操作できます
bridge ブリッジを示します。ブリッジデバイスを通るパケットを操作できます
netdev NICドライバがネットワークスタックに渡した直後の、進入する全てのトラフィックを分類できます。DDoS対策などに有用です

inetを使っておけば、IPv4、IPv6の両方を扱えます。
netdevは、iptablesでは扱えなかったファミリーです。Linux kernel 4.2以降が必要です。

チェイン

上の例ではinputforwardoutputチェインが存在しています。
このチェインはiptablesのように事前に定義されたものではなく、単なるチェイン名として名付けられているだけです。
元々はこれらのチェインも存在しません(例示のためにこちらで追加したものです)。

実際にパケットの流入(input)、送出(output)、転送(forward)時に処理をすることを示しているのは、チェインの中のtype filter hook input priority 0; policy accept;というような行です。
このような行を含み、inputやoutput等の基本的なパケットフィルタリングを行うチェインをベースチェインと呼んでいます。

デフォルトでチェインは用意されていないので、まず最初にベースチェインを作成する必要があります。
iptablesにおけるINPUTチェインの様なベースチェインを作成するには、以下の様なコマンドを使います。

## チェインの追加
# nft add chain inet filter input { type filter hook input priority 0\; }

## チェインの表示
# nft list chain inet filter input
table inet filter {
        chain input {
                type filter hook input priority 0; policy accept;
        }
}

上記で追加したベースチェインは以下のような設定になっています。

  • チェイン (chain inet filter inputの部分)
    • ファミリー:inet(IPv4/IPv6)
    • テーブル名:filter
    • チェイン名:input
  • ルール (type filter hook input priority 0の部分)
    • ベースチェインのタイプ(type):filter
    • フック(hook):input
    • プラオリティ(priority):0
    • ポリシー:accept(デフォルト)

nft addを実行する際、ルール末尾の;(セミコロン)はシェルが特別な意味を持つ文字なので、エスケープが必要です。

チェインのタイプ一覧

type filterfilter部分は、filterの他に以下から選択できます。

type 利用可能なファミリー 利用可能なフック 説明
filter all all 標準のチェーンタイプ
nat ip, ip6 prerouting
input
output
postrouting
アドレス変換を行うチェーンタイプ
route ip, ip6 output 通過したパケットの再度ルート探索を行う
IPヘッダの変更を行うルールなどを活用してポリシールーティングなどに利用できる

チェインのフック一覧

hook inputinput部分は、inputの他に以下から選択できます。
※ファミリーがip, ip6, inetの場合

hook 説明
prerouting システムに流入しようとするパケットを処理する
ルーティングに影響する値をフィルタ、変更したい場合に利用する
input システムに流入したパケットを処理する
forward 他のホストに転送されたパケットを処理する
output システムによって送出したパケットを処理する
postrouting システムから流出していくパケットを処理する

ルールの追加

ルールを追加するには、nft add ruleまたはnft insert ruleを実行します。
書式:nft add|insert rule family table chain statement

## inputチェイン末尾にルールを追加
# nft add rule inet filter input iifname ens3 tcp dport http accept

## inputチェイン先頭にルールを追加
# nft insert rule inet filter input iifname ens3 tcp dport http accept

ルールを特定の位置に追加するには、positionにhandleの番号を指定します。
書式:nft add|insert rule family table chain position statement

## handle4の後に追加
# nft add rule inet filter input handle 4 iifname ens3 tcp dport http accept

## #handle4の前に追加
# nft insert rule inet filter input handle 4 iifname ens3 tcp dport http accept

ルールの書式

上記の例では、statementiifname ens3 tcp dport http acceptの部分に該当します。
このstatementは以下の様な意味を持ちます。

  • 入力インタフェース名(iifname)
    • ens3
  • TCP宛先ポート(tcp dport)
    • http
  • 処理
    • accept

statementに該当する部分にはさらに複雑なルールも指定でき、以下に挙げるような表現を使うことができます。
全容は非常に大量の表現がある為、主要なものに絞って紹介します。

メタ表現

パケットに関連したメタデータにマッチさせることができます。

Keyword 値のタイプ 説明
meta length integer (32bit) パケット長(バイト)
iifname ifname 入力インタフェース名
oifname ifname 出力インタフェース名
pkttype pkt_type パケットタイプ
Unicast, Broadcast, Multicast

TCPヘッダ用表現

Keyword 値のタイプ 説明
sport inet_service Source port。送信元ポート
dport inet_service Destination port。送信先ポート
flags tcp_flags TCPのフラグ
nft describe tcp flagsにより出力されるフラグを指定可能

sport/dport

値のタイプであるinet_serviceですが、この値にはポート番号をそのまま指定するほか、/etc/servicesに定義されているサービス名での指定が可能です。
例えば、tcp dport 80tcp dport httpは同じ指定となります。

UDPヘッダ用表現

Keyword 値のタイプ 説明
sport inet_service Source port。送信元ポート
dport inet_service Destination port。送信先ポート
length integer (16bit) 全体のパケット長

ICMPヘッダ用表現

Keyword 値のタイプ 説明
type icmp_type ICMPタイプ
nft describe icmp typeにより出力されるタイプを指定可能
code integer (8bit) ICMPコード
gateway integer (32bit) ゲートウェイのIPアドレス
mtu integer (16bit) 経路MTU探索のMTU

ICMPv6ヘッダ用表現

Keyword 値のタイプ 説明
type icmpv6_type ICMPv6タイプ
nft describe icmpv6 typeにより出力されるタイプを指定可能
code integer (8bit) IMCPv6コード

CT (Conntrack, Connection Tracking) 表現

ステートフルなファイアウォールのため、パケットの状態にマッチさせることができます。

Keyword 値のタイプ 説明
state ct_state パケットのステート
nft describe ct stateにより出力される値を指定可能
direction ct_dir パケットの方向
originalまたはreplyを指定可能
status ct_status パケットの状態
nft describe ct statusにより出力される値を指定可能

処理の表現

Keyword 説明
accept ルールの評価をここで終了し、パケットを許可
drop ルールの評価をここで終了し、パケットを破棄
queue ルールの評価をここで終了し、ユーザスペースのアプリケーションにパケットを渡す
continue ルールの評価を続ける
return 現在のチェインから抜けて、一つ前のチェインの次のルール評価を続ける
ベースチェインでreturnすると、処理はacceptされる
jump chain 別のchainへ飛んで、chainの最初のルールから評価を始める
chainの全ルールの評価が終わった、もしくはreturnした場合に次の行から評価を続ける
goto chain 別のchainへ飛んで、chainの最初のルールから評価を始める
chainの全ルールの評価が終わった、もしくはreturnしても次の行の評価はしない(終了する)

サンプル表現

## 以下全てtype filter hook inputのベースチェイン内のルール

# ステートがestablishedまたはrelatedのパケットを許可
iifname ens3 ct state established, related accept
iifname ens3 ct state { established, related } accept # このように書いてもよい

# 22/tcp宛のパケットを許可
iifname ens3 tcp dport ssh accept

# 22/tcp、80/tcp宛のパケットを許可
iifname ens3 tcp dport { ssh, http } accept

# icmpの宛先到達不可能通知、エコー応答通知を許可
iifname "ens3" icmp type { destination-unreachable, echo-request } accept

なぜだか分かりませんが、ct stateでは{ }で囲わなくても良さそうです。

ルールの削除

ルールを削除するには、nft delete ruleを実行します。

## ルールをhandle付で表示
# nft list ruleset --handle
table inet filter { # handle 0
        chain input { # handle 1
                type filter hook input priority 0; policy accept;
                iifname "lo" accept # handle 4
        }
..(snip)..

## handle4のルールを削除
# nft delete rule inet filter input handle 4

ルールの保存

ルールを保存するには、ルールを/etc/nfttables.confへ出力します。

# nft list ruleset > /etc/nftables.conf

 

コメントを残す