はじめに
netfilterについて少し調べてみました。
いろいろと認識の相違があったことがわかったので、記録します。
認識の相違
CentOS8(に限らずだけど)では、以下のことがわかった。
iptablesはiptablesではなくnftablesである
firewall-cmdで設定したルールはiptablesでは表示されない
すべてのルール確認はnftを使う
Linuxでのパケットの流れについて
netfilter
netfilterはLinuxでパケットの処理をする基本ルール
インタフェイスで受信したパケットがどんな処理をされていくか、というやつです。
netfilter.orgによると、
netfilterは、カーネルモジュールがネットワークスタックにコールバック関数を登録できるようにするLinuxカーネル内の一連のフックです。登録されたコールバック関数は、ネットワークスタック内の各フックを通過するすべてのパケットに対してコールバックされます。
だそうです。ありがとうgoogle翻訳!
つまり、パケットがネットワークスタックを通り抜けるときに、netfilterで定義した「フック」というものにより、何らかの処理を挟み込めるようにした仕組み。ということでしょうか。
netfilterのchain
ネットワークスタックを通り抜ける一連の処理のことをchainと呼びます。
chainは、以下のものから構成されます。
名称 | 意味 |
---|---|
hook | (ネットワークスタックの)どの部分 で |
priority | どのような順番 で |
type | どのような処理をする か |
基本は以下の図です。
参考:https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg
netfilterのchainのhook
「(ネットワークスタックの)どの部分」で、処理が行われるか、を表現したものが、hookです。
つまり、ひっかけるタイミングを表現しています。
上図の中央付近にある、 routing decision
の部分で処理が変わっているのがわかると思います。
流入したパケットが「ローカル宛て」か、「ローカル宛てじゃない(=転送する)」かで、使われるhookが変わります。
hookの部分にフォーカスしたものが以下です。
Local
process
^ | .-----------.
.-----------. | | | Routing |
| |-----> input / \---> | Decision |----> output \
--> prerouting --->| Routing | .-----------. \
| Decision | --> postrouting
| | /
| |---------------> forward ---------------------------
.-----------.
参考:https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks
つまり、宛先によって、使われるhookが以下の2通りになります。
ローカルあての場合
prerouting -> input -> output -> postrouting
転送する場合
prerouting -> forward -> postrouting
(このほかにも、ingressというL2へのパケットに対するhookもあるみたいです。)
netfilterのchainのpriority
「どのような順番」で、処理が行われるか、を表現したものが、priorityです。
つまり、各hookの中での処理の順序を表現しています。
priorityは正負の数値で表現されますが、別名が定義されています。
dstnatとscrnatはそれぞれ、preroutingとpostroutingのhookでのみ利用可能です。
ですが、実体は飽くまで数値です。
通称 | 定義 | priority | 利用可能なhook |
---|---|---|---|
- | NF_IP_PRI_RAW_BEFORE_DEFRAG | -450 | すべて |
- | NF_IP_PRI_CONNTRACK_DEFRAG | -400 | すべて |
raw | NF_IP_PRI_RAW | -300 | すべて |
- | NF_IP_PRI_SELINUX_FIRST | -225 | すべて |
- | NF_IP_PRI_CONNTRACK | -200 | すべて |
mangle | NF_IP_PRI_MANGLE | -150 | すべて |
dstnat | NF_IP_PRI_NAT_DST | -100 | prerouting |
filter | NF_IP_PRI_FILTER | 0 | すべて |
security | NF_IP_PRI_SECURITY | 50 | すべて |
srcnat | NF_IP_PRI_NAT_SRC | 100 | postrouting |
- | NF_IP_PRI_SELINUX_LAST | 225 | すべて |
- | NF_IP_PRI_CONNTRACK_HELPER | 300 | すべて |
参考:http://git.netfilter.org/nftables/tree/include/linux/netfilter_ipv4.h
参考:https://manpages.debian.org/testing/nftables/nft.8.en.html
いわゆる「テーブル」ってやつに似てますね。
netfilterのchainのtype
「どのような処理をする」のか、を表現したものが、typeです。
つまり、具体的にパケットをどうするのか、ということを表現しています。
type | 利用可能なhook |
---|---|
filter | すべて |
nat | prerouting,postrouting,input,output |
route | output |
あれ?こっちも「テーブル」ってやつに似てますね。
だから紛らわしいんだよ!
参考:https://www.netfilter.org/projects/nftables/manpage.html
firewalldとiptablesとnftables
netfilterを構成するものについては、上で解説しましたが、じゃあnetfilterをどう操作するの?
ということで、それらを操作するソフトウェアの話です。
firewalld ってなんだ?
firewalld が最上位にいて、バックエンドでiptablesもしくはnftablesが動作している。
バックエンドで動作するiptablesもしくはnftablesがnetfilterの操作をしている。
古いバージョンの firewalld ではバックエンドに iptables が、
新しいバージョンの firewalld ではバックエンドに nftables が、採用されている。
とても分かりやすい。
てか、本稿のタイトルはもはやこれ1枚でいいんではなかろうか。
参考:https://firewalld.org/documentation/concepts.html
iptables ってなんだ?
iptablesはnetfilterを操作できるツールだ。
firewalldが導入される前の古いCentOSでは、iptablesをiptables-serviceというものでデーモン化(サービス化?)していた。
つまり、iptablesコマンドでiptablesのルールを直接変更したり、特定のファイルを読み込ませたりすることで、フィルタリングなりNATなりをしていたんだ。
CentOS8にもiptablesはあるが、実体はnftablesで動作している。
# iptables --version
iptables v1.8.2 (nf_tables)
とはいえ、すでに iptables は iptables ではない。
# ll /usr/sbin/iptables
lrwxrwxrwx. 1 root root 17 11月 9 03:40 /usr/sbin/iptables -> xtables-nft-multi
# man xtables-nft
NAME
xtables-nft ― iptables using nftables kernel api
DESCRIPTION
xtables-nft are versions of iptables that use the nftables
API. This is a set of tools to help the system administra‐
tor migrate the ruleset from iptables(8), ip6tables(8),
arptables(8), and ebtables(8) to nftables(8).
iptablesを叩くと、それっぽい書式でルールが見える。
けど、iptablesからは、後述するnftablesで追加したテーブルが見えない。
だから、iptables -L -nv -t nat|filter で表示されるルールと実際の動作が噛み合わないことがある。
例えば、Dockerホストからbridge接続されているコンテナへポート転送をするために firewall-cmd --add-masquerade
としたとき。nftでchainを確認すると、以下の動作が見える。
# nft list chain ip firewalld nat_POST_public_allow
table ip firewalld {
chain nat_POST_public_allow {
oifname != "lo" masquerade
}
}
けど、iptablesから firewalld というテーブルは見れない。
# iptables -L -t firewalld
iptables v1.8.2 (nf_tables): table 'firewalld' does not exist
Perhaps iptables or your kernel needs to be upgraded.
man iptables
でTABLESの部分をみてみると、iptablesでは、決められたキーワードのテーブルしか確認ができない。
TABLES
There are currently five independent tables (which tables are present at any time depends on the kernel configuration options and which modules are
present).
-t, --table table
The tables are as follows:
filter:
nat:
mangle:
raw:
security:
つまり、firewalldのバックでnftablesが動作している場合、 iptablesで表示したルールは正しくない!
ので、ルール確認は、 iptablesでなくnftを使う!
nftables ってなんだ?
nftablesもnetfilterを操作できる、iptabesに置き換わるツールだ。
前述のiptablesと同じような感じで、nftablesもサービス化できるみたいだけど、、、
# systemctl status nftables
● nftables.service - Netfilter Tables
Loaded: loaded (/usr/lib/systemd/system/nftables.service; disabled; vendor preset: disabled)
Active: inactive (dead)
Docs: man:nft(8)
CentOS8ではfirewalldが動作していて、nftablesが裏で動作しているので、nftablesとしてのデーモンは休んでいるみたい。
その中身は、以下のように、 nft
コマンドでルールのflush(=除去)と設定ファイルの読み込みをしている。
iptablesをデーモン化したときと似ているね。
# cat /usr/lib/systemd/system/nftables.service | grep nft
Documentation=man:nft(8)
ExecStart=/sbin/nft -f /etc/sysconfig/nftables.conf
ExecReload=/sbin/nft 'flush ruleset; include "/etc/sysconfig/nftables.conf";'
ExecStop=/sbin/nft flush ruleset
debian/arch/ubuntu/fedora では、nftablesのデーモン動作がデフォルトになっているようだ。
参考:https://wiki.nftables.org/wiki-nftables/index.php/Nftables_from_distributions
基本的なnftablesの使い方
nft
nftablesは nft
というコマンドで提供されます。
nftで設定するルールは、処理そのものであるchainと、chainをひとまとめにしたtableとして表現されます。
chainは特定のhookで特定のtypeで表現される処理をまとめたものであり、「(ネットワークスタックの)どの部分」で「どのような順番」で「どのような処理をする」かは、ひとつのchainでまとめられます。
tableは複数のchainをまとめた仮想的なグループとしてとらえます。
設定の確認は nft list
というコマンドを使います。
nft list table(s)
設定されているすべてのtableの名称のみ表示します。
# nft list tables
table ip filter
table ip6 filter
(とか、たくさん)
指定したtableの設定されているすべてのchainを表示します。
# nft list table ip nat
table ip nat {
chain PREROUTING {
type nat hook prerouting priority -100; policy accept;
fib daddr type local counter packets 0 bytes 0 jump DOCKER
}
(table ip natに含まれるchainがすべて表示されます)
nft list chain(s)
設定されているすべてのchainに対して、各chainがどのtableに含まれているか、発動条件である「(ネットワークスタックの)どの部分」で「どのような順番」の処理を行うのか、が表示されます。
(具体的な処理内容は表示されません)
# nft list chains
table ip filter {
chain INPUT {
type filter hook input priority 0; policy accept;
}
chain FORWARD {
type filter hook forward priority 0; policy drop;
}
(たくさん表示されます)
指定したchainを表示します
# nft list chain ip filter FORWARD
table ip filter {
chain FORWARD {
type filter hook forward priority 0; policy drop;
counter packets 0 bytes 0 jump DOCKER-USER
(たくさん表示されます)
すべてのルールの表示
設定されているすべてのルールが表示されます。
# nft list ruleset
table ip filter {
chain INPUT {
type filter hook input priority 0; policy accept;
}
chain FORWARD {
type filter hook forward priority 0; policy drop;
counter packets 0 bytes 0 jump DOCKER-USER
(すごくたくさん表示されます)
さいごに
netfilterはじめ、パケットの取り扱いは奥が深い。
これでもまちがった理解をしているかもしれないし、テキトーに設定してもなんとか動いちゃうこともある。
なるべく正しい知識を取り入れたい。