YAML になった Knot Resolver を試してみた

・LAN 内のドメインについてのクエリは権威サーバーに転送する
・それ以外のクエリは反復問い合わせする
構成の例です。
## 環境
AlmaLinux 9.5
Knot Resoler 6.0.12
SELinux有効
`192.168.182.10` 上に以下記事同等の権威サーバーが構築されていることを前提とします。

https://qiita.com/ahra_/items/273394cf29fbfb546ce1
## インストール
今回は早期リリースの 6.0.12 を使用するので、公式が用意している Copr のリポを使用します。
stable なバージョンは epel から入手可能です。
```
# dnf install epel-release && dnf upgrade
# dnf copr enable @cznic/knot-resolver
# dnf install knot-resolver
```
## 設定
### Knot Resolverの設定
Knot Resolver 6.0.0 から、定義ファイルの書式に YAML を使用するようになりました。
そのため、以前の lua 言語の定義ファイルとは書式が大幅に異なっています。
以下の定義ファイルを作成します。
```/etc/knot-resolver/config.yaml
workers: 1 #サーバーのCPUコア数に合わせる

logging:
  level: info

network:
  listen:
    - interface: [ 127.0.0.1, 192.168.182.12 ]
  
  do-ipv6: false 

forward: 

  - subtree: 
    - example.com
    - 182.168.192.in-addr.arpa

    servers:
    - 192.168.182.10

    options:
      authoritative: true # 転送先が権威サーバーなので true を指定
      dnssec: false # DNSSEC 非対応のゾーンのため false を指定 

views: # アクセス制限を設定
  - subnets: [ 192.168.182.0/24, 192.168.207.0/24, 127.0.0.1 ] # 許可するサブネット
    answer: allow

  - subnets: [ 0.0.0.0/0 ] # 上記以外は拒否
    answer: refused
```

:::note info
組み込み以外のルートヒントファイルを使用する場合は、定義ファイルに以下を追加します。
```diff:/etc/knot-resolver/config.yaml
+ lua:
+   script: |

+     modules = { 'hints > iterate' }
    
+     hints.root_file('<ルートヒントファイルの絶対パス>')
```
:::
以下のコマンドで内容が正しいか確認します。
何も出力されなければ OK です。
```
# kresctl validate /etc/knot-resolver/config.yaml
```
## 起動
FW に通信許可を設定し、Knot Resolver を起動します。
```
# firewall-cmd --add-service=dns --permanent
# firewall-cmd --reload
# systemctl enable knot-resolver
# systemctl start knot-resolver
```
## 確認
以下の通り解決できます。
```192.168.182.10 上のレコード
# dig @192.168.182.12 dns1.example.com.

; <<>> DiG 9.18.30-0ubuntu0.22.04.2-Ubuntu <<>> @192.168.182.12 dns1.example.com.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35143
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;dns1.example.com.              IN      A

;; ANSWER SECTION:
dns1.example.com.       3597    IN      A       192.168.182.10

;; Query time: 0 msec
;; SERVER: 192.168.182.12#53(192.168.182.12) (UDP)
;; WHEN: Thu May 08 15:53:16 JST 2025
;; MSG SIZE  rcvd: 61

# dig @192.168.182.12 -x 192.168.182.12

; <<>> DiG 9.18.30-0ubuntu0.22.04.2-Ubuntu <<>> @192.168.182.12 -x 192.168.182.12
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62123
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;12.182.168.192.in-addr.arpa.   IN      PTR

;; ANSWER SECTION:
12.182.168.192.in-addr.arpa. 3600 IN    PTR     dns-r.example.com.

;; Query time: 9 msec
;; SERVER: 192.168.182.12#53(192.168.182.12) (UDP)
;; WHEN: Thu May 08 15:53:37 JST 2025
;; MSG SIZE  rcvd: 87
```
```:自身で反復問い合わせするレコード
# dig @192.168.182.12 google.com.

; <<>> DiG 9.18.30-0ubuntu0.22.04.2-Ubuntu <<>> @192.168.182.12 google.com.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43153
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;google.com.                    IN      A

;; ANSWER SECTION:
google.com.             300     IN      A       216.58.220.110

;; Query time: 50 msec
;; SERVER: 192.168.182.12#53(192.168.182.12) (UDP)
;; WHEN: Thu May 08 15:53:59 JST 2025
;; MSG SIZE  rcvd: 55
```
DNSSEC 検証も正しく成功・失敗しています。
```:DNSSEC が正しく設定されているドメイン
# delv @192.168.182.12 jprs.co.jp. +vtrace
;; fetch: jprs.co.jp/A
;; validating jprs.co.jp/A: starting
;; validating jprs.co.jp/A: attempting positive response validation
;; fetch: jprs.co.jp/DNSKEY
;; validating jprs.co.jp/DNSKEY: starting
;; validating jprs.co.jp/DNSKEY: attempting positive response validation
;; fetch: jprs.co.jp/DS
;; validating jprs.co.jp/DS: starting
;; validating jprs.co.jp/DS: attempting positive response validation
;; fetch: jp/DNSKEY
;; validating jp/DNSKEY: starting
;; validating jp/DNSKEY: attempting positive response validation
;; fetch: jp/DS
;; validating jp/DS: starting
;; validating jp/DS: attempting positive response validation
;; fetch: ./DNSKEY
;; validating ./DNSKEY: starting
;; validating ./DNSKEY: attempting positive response validation
;; validating ./DNSKEY: verify rdataset (keyid=20326): success
;; validating ./DNSKEY: marking as secure (DS)
;; validating jp/DS: in fetch_callback_dnskey
;; validating jp/DS: keyset with trust secure
;; validating jp/DS: resuming validate
;; validating jp/DS: verify rdataset (keyid=53148): success
;; validating jp/DS: marking as secure, noqname proof not needed
;; validating jp/DNSKEY: in fetch_callback_ds
;; validating jp/DNSKEY: dsset with trust secure
;; validating jp/DNSKEY: verify rdataset (keyid=35821): success
;; validating jp/DNSKEY: marking as secure (DS)
;; validating jprs.co.jp/DS: in fetch_callback_dnskey
;; validating jprs.co.jp/DS: keyset with trust secure
;; validating jprs.co.jp/DS: resuming validate
;; validating jprs.co.jp/DS: verify rdataset (keyid=13611): success
;; validating jprs.co.jp/DS: marking as secure, noqname proof not needed
;; validating jprs.co.jp/DNSKEY: in fetch_callback_ds
;; validating jprs.co.jp/DNSKEY: dsset with trust secure
;; validating jprs.co.jp/DNSKEY: verify rdataset (keyid=63574): success
;; validating jprs.co.jp/DNSKEY: marking as secure (DS)
;; validating jprs.co.jp/A: in fetch_callback_dnskey
;; validating jprs.co.jp/A: keyset with trust secure
;; validating jprs.co.jp/A: resuming validate
;; validating jprs.co.jp/A: verify rdataset (keyid=43611): success
;; validating jprs.co.jp/A: marking as secure, noqname proof not needed
; fully validated
jprs.co.jp.             300     IN      A       117.104.133.165
jprs.co.jp.             300     IN      RRSIG   A 8 3 300 20250604023001 20250505023001 43611 jprs.co.jp. GNkmT72CLP6GLbPBoVCUNYDKJKdNQqEoT7mBgXr+L4sPVjh1K9oCttS6 eQrBrfBpwFQwSjOmJKk1VcN3aclxF2xd2s1UnOH8tmhKkj0tm16J1GY5 +oLQ+yOwI7MRDLZkevEnbdSjiYDI/EWOavyzEt707VizoD0JsaUTbdfF 2QI=
```
```:意図的に不正な設定がされているドメイン
# delv @192.168.182.12 dnssec-failed.mufj.jp. +vtrace
;; fetch: dnssec-failed.mufj.jp/A
;; resolution failed: SERVFAIL
```
## 補足
フォワーダーとして使用する場合は以下のようにします。（Google Public DNS に転送する例）
```diff:/etc/knot-resolver/config.yaml
（前略）
forward: 

+  - subtree: 
+    - .
+    servers:
+    - 8.8.8.8

  - subtree: 
    - example.com
    - 182.168.192.in-addr.arpa

    servers:
    - 192.168.182.10

    options:
      authoritative: true
      dnssec: false
（後略）
```