npfを使ってファイアウォールを設定する


NetBSDにはpf(4), ipf(4), bpf(4), npf(7)……と多数のファイアウォールが提供されています。公式にはnpf(7)が標準のファイアウォールです。NetBSDのpf(4)はメンテナがおらずアップストリームの追跡ができていないため、NetBSDのベースシステムから削除されるようです(『Removing PF』)。アップストリームを追いかけられないということは、アップストリームで修正されたバグや脆弱性がそのまま残っていることを意味しています。セキュリティを考えれば、メンテナンスができないから打ち切るというのは正しい対応のように思えます。

GNU/Linuxでよく使われるfirewalld(1)firewall-cmd(1)は通信を許可したいプロトコルやポート番号を指定していくホワイトリスト方式で運用するのが一般的です。一方でnpf(4)はなにを遮断してなにを許可するかをすべて設定ファイルに記載します。一見難しいように見えますが、hosts.allowhosts.denyと同じく、まずはすべてを遮断してから必要な通信だけ許可すれば最低限の設定をしたことになります。

  1. 設定ファイル /etc/npf.conf
  2. npf(7)起動と設定の確認
  3. blacklistd(8)でDoS攻撃を防ぐ

設定ファイル /etc/npf.conf

npf(7)の設定ファイルは/etc/npf.confです。このファイルは標準では存在しません。npf(7)を使いたいときに新規作成します。

このファイルの中身は以下のようになります。インターネットで検索しても設定例が少ないのですが、『 NetBSD 8.0のnpf(7)の設定例』や『NPF documentation』を参照するといいでしょう。オンラインマニュアルnpf.conf(8)も参考にしてください。

# It refered http://blog.onodera.asia/2018/07/netbsdamd64-8.html
# Thank you!
$pub_if = { inet4(vioif0) }
$pub_if6 = { inet6(vioif0) }
$services_tcp = { 1126 }

procedure "log" {
    # npfd(8)でロギングする。
    log: npflog0
}

# IPv4
group "public" on $pub_if {
    # 出ていく通信は通す。
    pass stateful out final all
    # #services_tcpで定義されたサービスやポートへのアクセスを通し、ログに残す。
    pass stateful in final proto tcp to $pub_if port $services_tcp apply "log"
}

# IPv6
group "public" on $pub_if6 {
    # 出ていく通信は通す。
    pass stateful out final all
    # #services_tcpで定義されたサービスやポートへのアクセスを通し、ログに残す。
    pass stateful in final proto tcp to $pub_if port $services_tcp apply "log"
}

group default {
    # lo0へのアクセスはすべて通す。
    pass final on lo0 all

    # blacklistd を使う。
    ruleset "blacklistd"

    # すべて遮断する。
    block all
}

npf(7)起動と設定の確認

/etc/rc.confにnpf(7)npfd(8)の設定を追加します。

echo npf=YES >> /etc/rc.conf
echo npfd=YES >> /etc/rc.conf

デーモンを起動します。

/etc/rc.d/npf reload
service npfd start
service npf start

npf(7)のルールはnpfctl(8)から確認できます。npfd(8)のログは標準では/var/log/npflog0.pcapです。中身はバイナリです。tcpdump -enr /var/log/npflog0.pcapと実行するとログを確認できます。

/etc/npf.confでsshの記述を消してnpfctl reloadする、service httpd onestartしてHTTPサーバを立ち上げる、……などnpf(7)側で通信を許可しないと外部からアクセスできないことを確認してください。

blacklistd(8)でDoS攻撃を防ぐ

npf(7)と併せてblacklistd(8)を活用するとDenial of Service(DoS)攻撃を防止できます。設定方法は簡単です。ついでにやっておくといいでしょう。

blacklistd(8)の設定は/etc/blacklistd.confに記述します。以下の例ではSSHログインに3回連続で失敗するとブラックリストに登録し24時間接続できないようにしています。

# Blacklist rule
# adr/mask:port type    proto   owner           name    nfail   disable
[local]
ssh             stream  tcp     *               *       3       24h
ssh             stream  tcp6    *               *       3       24h

/etc/rc.confblacklistd(8)を自動で起動するよう設定を書き、デーモンを起動します。

echo "blacklistd=YES" >> /etc/rc.conf
service blacklistd start

npf(7)blacklistd(8)を使えるように/etc/npf.confを変更します。ルールに以下を追加してください。

ruleset "blacklistd"

npf(7)に設定を再読み込みさせ、デーモンを再起動してください。

npfctl reload
npfctl stop
npfctl start

blacklistd(8)の状態はblacklistctl dump -aを実行すると確認できます。その他のオプションについてはオンラインマニュアルblacklistctl(8)を参照してください。