サーバーのパケットフィルタリングも、そろそろ古式ゆかしい iptables から新しい(とはいっても、Linux Kernel 3.13 から使えるようにはなっていたんで、登場して既に8年経ってるのですが) nftables に置き換えるか、ということで試行錯誤を繰り返して何とか設定に成功。とはいえ、先行事例のコピペみたいなものなので、ちょっとは勉強しないとなあと反省した次第。
Debian では、buster からデフォルトになってたんだけど、iptables で別に困ってないからいいや、と放っておいたんです。導入事例が溜まるのを待ってからでも遅くないし、と少々小狡いことも考えてたりした。
一応、謳い文句では IPv4 と IPv6 では別々に設定しなくてはならなかったルールが nftables では統一的に扱えるとの触れ込みだったし、実際 man ページにもそう書かれてるんだけど、試しに設定してみたらなぜか IPv6 のフィルタリングだけ想定したように動かない。というか、全パケット破棄されてしまう。
table inet filter {
chain input {
type filter hook input priority filter; policy accept;
counter packets 0 bytes 0 jump BASE-FILTER
}
chain forward {
type filter hook forward priority filter; policy accept;
counter packets 0 bytes 0 jump BASE-FILTER
}
chain output {
type filter hook output priority filter; policy accept;
}
chain BASE-FILTER {
## local interface
iif "lo" accept
## Home
ip addr 118.118.118.118 counter accept
ip6 saddr [2406:0::]/64 counter accept
## For Ping
meta l4proto icmp counter accept
meta l4proto ipv6-icmp counter accept
## Drop syn packet without new state
meta l4proto tcp tcp flags & (fin | syn | rst | ack) != syn ct state new counter drop
## Accept established connection
ct state established,related counter accept
## HTTP
ct state new tcp dport 80 counter accept
## HTTPS
ct state new tcp dport 443 counter accept
meta l4proto udp udp dport 443 counter accept
## Drop others
counter packets 0 bytes 0 drop
}
}
上記のようなルールセットを書いて読み込ませてみたら、IPv6 で接続していた ssh セッションが見事フリーズ、というか遮断されてにっちもさっちもいかない。あれこれ試しても、IPv4 は疎通するけど、IPv6 が通らない。結局、仕方ないので、ip フィルターと ip6 フィルターで分けたら無事意図した通りに動いた。
table ip filter {
chain input {
type filter hook input priority filter; policy accept;
counter packets 0 bytes 0 jump BASE-FILTER
}
chain forward {
type filter hook forward priority filter; policy accept;
counter packets 0 bytes 0 jump BASE-FILTER
}
chain output {
type filter hook output priority filter; policy accept;
}
chain BASE-FILTER {
## local interface
iif "lo" accept
## Home
ip addr 118.118.118.118 counter accept
## For Ping
meta l4proto icmp counter accept
## Drop syn packet without new state
meta l4proto tcp tcp flags & (fin | syn | rst | ack) != syn ct state new counter drop
## Accept established connection
ct state established,related counter accept
## HTTP
ct state new tcp dport 80 counter accept
## HTTPS
ct state new tcp dport 443 counter accept
meta l4proto udp udp dport 443 counter accept
## Drop others
counter drop
}
}
table ip6 filter {
chain input {
type filter hook input priority filter; policy accept;
counter packets 0 bytes 0 jump BASE-FILTER
}
chain forward {
type filter hook forward priority filter; policy accept;
counter packets 0 bytes 0 jump BASE-FILTER
}
chain output {
type filter hook output priority filter; policy accept;
}
chain BASE-FILTER {
## local interface
iif "lo" accept
## Home
ip6 saddr [2406:0::]/64 counter accept
## For Ping
meta l4proto ipv6-icmp counter accept
## Drop syn packet without new state
meta l4proto tcp tcp flags & (fin | syn | rst | ack) != syn ct state new counter drop
## Accept established connection
ct state established,related counter accept
## HTTP
ct state new tcp dport 80 counter accept
## HTTPS
ct state new tcp dport 443 counter accept
meta l4proto udp udp dport 443 counter accept
## Drop others
counter drop
}
}
何か仕様を誤解してるんだと思うんだけど、登場から8年も経ってるのに、致命的なくらい導入事例がネットにない。みんな、StackOverflow とか、誰かのブログの焼き直し設定事例ばかりでなんと、IPv6 関連の設定例が見つからないときた。これなら、iptables とあんまし変わらないなあとしばし絶望。
まあ、動くことは動くので、切り替えちゃったんですけどね。