PowerDNS recursorのスクリプトでAAAA/A レコードの応答振り分けを行う (オンライン資格確認動作の安定化)

# はじめに
オンライン資格確認システムでは、同一のサーバーに対してIP-VPN用とIPsecVPN用としてIPv6、IPv4の両方のアドレスが振られていますが、フレッツIP-VPN環境ではDNSのIPv4応答（Aレコード）が邪魔になり、IPsecのVPNでは逆にIPv6（AAAAレコード）応答が邪魔になって接続に時間がかかることがあります。
```
% dig @2001:a7ff:f014:d00::53:1 pweb.base.oqs-pdl.org ANY
(略)
;; ANSWER SECTION:
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.11
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.4
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.10
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.15
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.2
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.1
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.7
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.5
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.6
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.9
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.14
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.3
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.8
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.12
pweb.base.oqs-pdl.org.  190     IN      A       10.255.181.13
pweb.base.oqs-pdl.org.  265     IN      AAAA    2001:a250:7c00:1f00::12
pweb.base.oqs-pdl.org.  265     IN      AAAA    2001:a250:7c00:1f00::11
pweb.base.oqs-pdl.org.  265     IN      AAAA    2001:a250:7c00:1f00::9
(略)
```
当方の環境は、オンライン資格確認のみIPv6で、インターネットはIPv4/PPPoE接続なので、オンライン資格確認関連のドメインはAレコードをカットしてAAAAレコードのみを返し、それ以外のインターネットゾーンのドメインに対してはAAAAをカットしてAレコードのみを返すようなキャッシュをおけば良さそうです。（オンライン資格確認PCや電子カルテのみのネットワークであれば、インターネット接続はない方がいいので、上位ルーターでIPv4を遮断するなり、IPv4のDNS設定を空欄にしてください）
こちら「[pdns-recursorでAAAAフィルタをかける](https://note.nogisawa.net/?2020/0202_pdns)」を参考にPowerDNS recursorをDNSキャッシュとし、luaスクリプトを作成してみました。

https://note.nogisawa.net/?2020/0202_pdns

DNSキャッシュの効果で応答が早くなるのと、接続の安定性が増すと思います。オンライン資格確認以外にもIPv4/v6のデュアルスタック環境では利用価値があるかと思います。

# 環境
* Linux server：Raspberry PI 3B/  Raspberry Pi OS を使いました。
* オンライン資格確認PCのあるネットワークに配置します。
* 上位ルーターではTCP/UDP53が通信可能なように設定しておきます。


# PowerDNS recursorのインストールと設定
## インストール
```
# apt install pdns-recursor
```
## recursor.confの編集
```recursor.conf
forward-zones-file=/etc/powerdns/forwardzone.txt
forward-zones-recurse=.=(インターネットプロバイダのDNSサーバー);8.8.8.8
local-port=53
lua-dns-script=/etc/powerdns/deletev4-v6fix.lua
```
## forwardzone.txt（NTT西の場合です）
NTT東の場合は、DNSサーバー`2404:1a8:7f01:a::3`, `2404:1a8:7f01:b::3` に変更が必要です。
```/etc/powerdns/forwardzone.txt
flets-west.jp=2001:a7ff:5f01::a,2001:a7ff:5f01:1::a
+onshikaku.org=2001:a7ff:f014:d00::53:1,2001:a7ff:f014:d00::53:2
+lineauth.mnw=2001:a7ff:f014:d00::53:1,2001:a7ff:f014:d00::53:2
+managedpki.ne.jp=2001:a7ff:f014:d00::53:1,2001:a7ff:f014:d00::53:2
+cybertrust.ne.jp=2001:a7ff:f014:d00::53:1,2001:a7ff:f014:d00::53:2
+secomtrust.net=2001:a7ff:f014:d00::53:1,2001:a7ff:f014:d00::53:2
+oqs-pdl.org=2001:a7ff:f014:d00::53:1,2001:a7ff:f014:d00::53:2
+rece=2001:a7ff:f014:d00::53:1,2001:a7ff:f014:d00::53:2
+healthinsurance.mhlw.go.jp=2001:a7ff:f014:d00::53:1,2001:a7ff:f014:d00::53:2
```
## deletev4-v6fix.lua
```lua:/etc/powerdns/deletev4-v6fix.lua
v6_domains = {
  newDN('flets-west.jp'),
  newDN('onshikaku.org'),
  newDN('lineauth.mnw'),
  newDN('managedpki.ne.jp'),
  newDN('cybertrust.ne.jp'),
  newDN('secomtrust.net'),
  newDN('oqs-pdl.org'),
  newDN('rece'),
  newDN('healthinsurance.mhlw.go.jp')
}

function postresolve(dq)
  local records = dq:getRecords()
  local records_new = {}
  local v6only = 0
  local v6ready = 0

  for i, v6_domain in ipairs(v6_domains) do
    if dq.qname:isPartOf(v6_domain) then
      v6only = 1
    end
  end
  if v6only == 0 then
    for i, record in ipairs(records) do
      if record.type ~= pdns.AAAA then
          records_new[#records_new + 1] = record
      end
    end
  else
    for i, record in ipairs(records) do
      if record.type ~= pdns.A then
        if record.type == pdns.AAAA then
          v6ready = 1
        end
        records_new[#records_new + 1] = record
      end
    end

    if v6ready == 0 then
      print("Error: Received IPv6 question for "..dq.qname:toString().." from "..dq.remoteaddr:toString())
      print("but no AAAA record in the result. " )
    end
  end

  dq:setRecords(records_new)

  return true
end
```
# サービス再起動
```
# systemctl restart pdns-recursor
```
# 動作確認
オンライン資格確認関連はAレコードが消えています。
```
% dig pweb.base.oqs-pdl.org ANY

; <<>> DiG 9.10.3-P4-Raspbian <<>> pweb.base.oqs-pdl.org ANY
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16865
;; flags: qr rd ra; QUERY: 1, ANSWER: 15, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pweb.base.oqs-pdl.org.         IN      ANY

;; ANSWER SECTION:
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::13
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::9
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::1
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::4
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::10
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::2
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::7
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::11
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::6
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::14
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::15
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::5
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::8
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::12
pweb.base.oqs-pdl.org.  142     IN      AAAA    2001:a250:7c00:1f00::3

;; Query time: 9 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Feb 26 11:59:25 JST 2023
;; MSG SIZE  rcvd: 470
```
インターネットゾーンはAAAAが消えています。
```
% dig www.google.co.jp ANY

; <<>> DiG 9.10.3-P4-Raspbian <<>> www.google.co.jp ANY
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10294
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.google.co.jp.              IN      ANY

;; ANSWER SECTION:
www.google.co.jp.       84      IN      A       142.251.42.163
www.google.co.jp.       18217   IN      TYPE65  \# 13 00010000010006026832026833

;; Query time: 20 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sun Feb 26 12:02:49 JST 2023
;; MSG SIZE  rcvd: 86
```
# 注意点
オンライン資格確認のドメインが増えた場合、forwardzone.txtとdeletev4-v6fix.luaの両方でドメイン名の追加が必要です。luaスクリプトからforwardzone.txtを読みに行けるようにすればいいのでしょうが、能力不足でいい方法が思いつきませんでした。いい方法あれば教えてください。


# 参考サイト

https://qiita.com/Shakapon/items/c460a674f1289924fbd8