Example から読み解く RFC 5155

2016.9.19 DNS温泉3 LT
2017.9.16 updated for DNS温泉4
2018.1.7 updated for DNS温泉補講

T.Suzuki

演習環境起動

login: guest
password: guest

Appendix A. Example Zone

root---example---+---a.example
        +ns1     |     +ns1.a
        +ns2     |     +ns2.a
        +ai      |
        +w       +---c.example
        +*.w           +ns1.c
        +x.w           +ns2.c

        +x.y.w
        +2t7b4g4vsa5smi47k61mv5bv1a22bojr
H(example)       = 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom
H(c.x.w.example) = 0va5bpr2ou0vk0lbqeeljri88laipsfh (query)
H(ns1.example) = 2t7b4g4vsa5smi47k61mv5bv1a22bojr
H(x.y.w.example) = 2vptu5timamqttgl4luu9kg21e0aor3s
H(a.example) = 35mthgpgcu1qg68fab165klnsnk3dpvl
H(c.example) = 4g6p9u5gvfshp30pqecj98b3maqbn1ck (NSEC3 生成は実装依存)
H(*.x.w.example) = 92pqneegtaue7pjatc3l3qnk738c6v5m (不存在)
H(x.w.example) = b4um86eghhds6nea196smvmlo4ors995
H(ai.example) = gjeqe526plbf1g8mklp59enfd789njgi
H(y.w.example) = ji6neoaepv8b5o6k4ev33abha8ht9fgc
H(w.example) = k8udemvp1j2f7eg6jebps17vp3n8i58h
H(2t7b4g4vsa5smi47k61mv5bv1a22bojr.example) = kohar7mbb8dc2ce8a9qvl8hon4k53uhi
H(ns2.example) = q04jkcevqvmu85r014c7dkba38o0ji5r
H(*.w.example) = r53bq7cc2uvmubfu5ocmm6pers9tk9en
H(xx.example) = t644ebqk9bibcna874givr6joj62mlhv

Appendix B. Example Responses

B.1. Name Error (a.c.x.w.example の不存在証明)

a.c.x.w.example の A の問い合わせに否定応答 (RCODE=3, NXDOMAIN) の例

(以下のスライド 1,2 は RFC 5155 と説明順を入れ替えた。また ldns-signzone を使用したため RFC 5155 と一部応答が異なっている)

1. 最近接名 (closest encloser) にマッチする NSEC3

a.c.x.w.example の 最近接名 (最長一致の実在する名前) は x.w.example である。

H(x.w.example) = b4um86eghhds6nea196smvmlo4ors995 と計算でき、その値の次の値は gjeqe526plbf1g8mklp59enfd789njgi = H(ai.example) である。
(これで x.w.example の存在がわかる)

b4um86eghhds6nea196smvmlo4ors995.example. NSEC3 1 1 12 aabbccdd (
                       gjeqe526plbf1g8mklp59enfd789njgi MX RRSIG )

2. 次近接名 (next closer name) をカバーする NSEC3

近接名 x.w.example. が存在し、次近接名は c.x.w.example. である。

H(c.x.w.example) = 0va5bpr2ou0vk0lbqeeljri88laipsfh と計算でき、その値は H(example) = 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom と H(ns1.example) = 2t7b4g4vsa5smi47k61mv5bv1a22bojr の間にカバーされている。
(c.x.w.example. の不存在がわかる)

0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. NSEC3 1 1 12 aabbccdd (
                       2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS
                       SOA NSEC3PARAM RRSIG )

3.最近接名のワイルドカードをカバーする NSEC3

*.x.w.example.(a.c.x.w.example.を含む) のハッシュ値は
H(*.x.w.example) = 92pqneegtaue7pjatc3l3qnk738c6v5m
と計算でき、
4g6p9u5gvfshp30pqecj98b3maqbn1ck = H(c.example) と b4um86eghhds6nea196smvmlo4ors995 = H(x.w.example) の間にカバーされている。
(*.x.w.example の不存在もこれでわかる)

4g6p9u5gvfshp30pqecj98b3maqbn1ck.example. NSEC3 1 1 12 aabbccdd (
                       b4um86eghhds6nea196smvmlo4ors995 NS )

上記は ldns-signzone で署名したゾーンの場合である。dnssec-signzone を用いた場合、RFC 5155 の例と同様になる。
H(c.example) = 4g6p9u5gvfshp30pqecj98b3maqbn1ck の NSEC3 が生成されているかどうかの違いが出る。(c.example は insecure なゾーン)

;; NSEC3 RR that covers wildcard at the closest encloser (*.x.w.example)
;; H(*.x.w.example) = 92pqneegtaue7pjatc3l3qnk738c6v5m
;; H(a.example) = 35mthgpgcu1qg68fab165klnsnk3dpvl
35mthgpgcu1qg68fab165klnsnk3dpvl.example. NSEC3 1 1 12 aabbccdd (
                       b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG )

以上で証明(?)されていること

  1. (最近接名:closest encloser) x.w.example. は存在する
    (最近接名の証明は Section 8.3)
  2. c.x.w.example. (次近接名:next closer name) は存在しない
  3. *.x.w.example. も存在しない
  4. 当然 a.c.x.w.example. も存在しない

B.2. No Data Error

単なる No Data (名前はあるが要求された TYPE はない) の解説は省略

 

B.2.1. No Data Error, Empty Non-Terminal

empty non-terminal の問い合わせは "no data" (RCODE=0, Authority Section に SOA付) になる。名前は存在する (NXDOMAIN ではない) がその RR は存在しない。

y.w.example. に No Data 応答の例

ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. NSEC3 1 1 12 aabbccdd (
                        k8udemvp1j2f7eg6jebps17vp3n8i58h )
ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. RRSIG NSEC3 7 2 3600 (
                        20150420235959 20051021000000 40430 example.
                        gPkFp1s2QDQ6wQzcg1uSebZ61W33rUBDcTj7
                        2F3kQ490fEdp7k1BUIfbcZtPbX3YCpE+sIt0
                        MpzVSKfTwx4uYA== )

y.w.example. のハッシュ値 ji6neoaepv8b5o6k4ev33abha8ht9fgc にマッチする NSEC3 が存在するが、ビットマップフィールドで TYPE A が空とわかる。

NSEC による Empty Non-Terminal の証明とは違って、No Data を示すだけだ。(この例では完全に空だとわかるが)

B.3. Referral to an Opt-Out Unsigned Zone

この委譲は存在していないか署名されていないという証明。未署名の委譲が存在する可能性があることに注意。(ldns-signzone では存在がわかる)

mx.c.example. の MX を example サーバに問い合わせた例
(RCODE=0, Answerなし、Authority Section に NS)

dnssec-signzone だと RFC 5155 の以下の例のようになる。

   ;; Header: QR DO RCODE=0
   ;;
   ;; Question
   mc.c.example.       IN MX

   ;; Answer
   ;; (empty)

   ;; Authority
   c.example.     NS      ns1.c.example.
                  NS      ns2.c.example.

   ;; NSEC3 RR that covers the "next closer" name (c.example)
   ;; H(c.example) = 4g6p9u5gvfshp30pqecj98b3maqbn1ck
   ;; H(a.example) = 35mthgpgcu1qg68fab165klnsnk3dpvl

   35mthgpgcu1qg68fab165klnsnk3dpvl.example. NSEC3 1 1 12 aabbccdd (
                          b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG )
   35mthgpgcu1qg68fab165klnsnk3dpvl.example. RRSIG NSEC3 7 2 3600 (
                          20150420235959 20051021000000 40430 example.
                          g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQ
                          Aynzo8EUWH+z6hEIBlUTPGj15eZll6VhQqgZ
                          XtAIR3chwgW+SA== )

   ;; NSEC3 RR that matches the closest encloser (example)
   ;; H(example) = 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom

   0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. NSEC3 1 1 12 aabbccdd (
                          2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS
                          SOA NSEC3PARAM RRSIG )
   0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. RRSIG NSEC3 7 2 3600 (
                          20150420235959 20051021000000 40430 example.
                          OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKL
                          IBHYH6blRxK9rC0bMJPwQ4mLIuw85H2EY762
                          BOCXJZMnpuwhpA== )

mc.c.example. の証明可能な最近接名は example. でありその NSEC3 が応答されている。また、mc.c.example. の次近接名は c.example であり、そのハッシュ値 H(c.example) = 4g6p9u5gvfshp30pqecj98b3maqbn1ck のカバーが 35mthgpgcu1qg68fab165klnsnk3dpvl = H(a.example) と b4um86eghhds6nea196smvmlo4ors995 = H(x.w.example) で示されている。

ところで、ldns-signzone だと c.example. の NSEC3 レコードが生成されるため、以下のようになる。

  ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 41191
  ;; flags: qr rd ; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 2 
  ;; QUESTION SECTION:
  ;; mc.c.example.         IN      A
 
  ;; ANSWER SECTION:
 
  ;; AUTHORITY SECTION:
  c.example.  3600   IN   NS   ns1.c.example.
  c.example.  3600   IN   NS   ns2.c.example.
  4g6p9u5gvfshp30pqecj98b3maqbn1ck.example.  3600  IN  NSEC3 (
         1 1 12 aabbccdd  b4um86eghhds6nea196smvmlo4ors995 NS) 
  4g6p9u5gvfshp30pqecj98b3maqbn1ck.example.  3600  IN  RRSIG ( 
         NSEC3 7 2 3600 20161010140307 20160912140307 26567 example.
         UUzOf9BWg5t3xbcqkV5cMt8UupBar8X4x9yNsiqm5YFJkTQ2uMiolIKhLGx
         czhm72eexNw3wn4SXOU5Cbldsmn0ATCyBS4JNQnUFWYrNtUIolRmEnzIoDV
         EKrbrHg+Xl/Z3sbo4hlEvKvEmBQwHIkdJPpq2oYweCIxqJ2rcOB3Q= )

"ENT was here!!!" について

example に以下の委任を加えます。

ex.gov.example.      3600  IN  NS    ns.ex.gov.example.
ns.ex.gov.example.   3600  IN  A     192.168.11.21

ldns-signzone で署名 (サーバは NSD の場合)

# ldns-signzone -n -p -t 12 -s aabbccdd -f example.zone.signed example.ent.zone key/Kexample.+007+26567 key/Kexample.+007+24108

gov.example の下の存在しない名前を検索します。
(gov.example zone はないので example zone 内)

 # drill -D hoge.gov.example @192.168.11.1
4g6p9u5gvfshp30pqecj98b3maqbn1ck.example. 3600 IN  NSEC3  1 1 12 aabbccdd  b4um86eghhds6nea196smvmlo4ors995 NS 
jthlauk0mdainrqmnviqj5gqtl3ddnt4.example. 3600 IN  NSEC3  1 1 12 aabbccdd  k8udemvp1j2f7eg6jebps17vp3n8i58h
gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN  NSEC3  1 1 12 aabbccdd  ji6neoaepv8b5o6k4ev33abha8ht9fgc A HINFO AAAA RRSIG 

1行めは以下の不存在をカバー

# ldns-nsec3-hash -a 1 -t 12 -s aabbccdd hoge.gov.example
55ipsf6g5hv6cadallvuaj8ukngtng28.

2行めは以下の exact match で gov.example はあるが NS がないことがわかる。
(bit map field が empty)

# ldns-nsec3-hash -a 1 -t 12 -s aabbccdd gov.example
jthlauk0mdainrqmnviqj5gqtl3ddnt4.

3行めで '*.gov.example' がないことがわかる。

# ldns-nsec3-hash -a 1 -t 12 -s aabbccdd '*.gov.example'
jd9uj6jtma56hf6h1q8tfblt42m0di8t.

dnssec-signzone で署名 (サーバは NSD の場合)

dnssec-signzone -A -H 12 -3 aabbccdd -f example.zone.signed -o example -K key -k Kexample.+007+24108 example.ent.zone Kexample.+007+26567

gov.example の下の存在しない名前を検索

 # drill -D hoge.gov.example @192.168.11.1

以下をカバーする NSEC3 が返る
H(hoge.gov.example) = 55ipsf6g5hv6cadallvuaj8ukngtng28
H(*.gov.example) = jd9uj6jtma56hf6h1q8tfblt42m0di8t.

35mthgpgcu1qg68fab165klnsnk3dpvl.example.  3600  IN  NSEC3 1 1 12 aabbccdd  b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG 
gjeqe526plbf1g8mklp59enfd789njgi.example.  3600  IN  NSEC3 1 1 12 aabbccdd  ji6neoaepv8b5o6k4ev33abha8ht9fgc A HINFO AAAA RRSIG 

最近接名の gov.example の情報 (NSがないとか) がわからない。

ただし gov.example の下に secure な(署名された)ゾーンがあれば以下のようになる。

  35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC31 1 12 AABBCCDD B4UM86EGHHDS6NEA196SMVMLO4ORS995  NS DS RRSIG
  jthlauk0mdainrqmnviqj5gqtl3ddnt4.example. 3600 IN NSEC31 1 12 AABBCCDD K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H
  gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN NSEC31 1 12 AABBCCDD JI6NEOAEPV8B5O6K4EV33ABHA8HT9FGC  A HINFO AAAA RRSIG

ENT was here!!!

こんな話がありました。

gov.example. に TXT "ENT was here!!!" を加えて署名し直すと、、、

35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600  IN NSEC3 1 1 12 aabbccdd  b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG 
jthlauk0mdainrqmnviqj5gqtl3ddnt4.example. 3600  IN NSEC3 1 1 12 aabbccdd  k8udemvp1j2f7eg6jebps17vp3n8i58h TXT RRSIG 
gjeqe526plbf1g8mklp59enfd789njgi.example. 3600  IN NSEC3 1 1 12 aabbccdd  ji6neoaepv8b5o6k4ev33abha8ht9fgc A HINFO AAAA RRSIG 

broken ENT was(?) here!!!

TXT がない状態に戻す。(gov.example の exact match な NSEC3 がなくなる)

 # drill -D hoge.gov.example @192.168.11.1
(snip)
35mthgpgcu1qg68fab165klnsnk3dpvl.example.  3600  IN  NSEC3 1 1 12 aabbccdd  b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG 
gjeqe526plbf1g8mklp59enfd789njgi.example.  3600  IN  NSEC3 1 1 12 aabbccdd  ji6neoaepv8b5o6k4ev33abha8ht9fgc A HINFO AAAA RRSIG 

H(gov.example) = jthlauk0mdainrqmnviqj5gqtl3ddnt4
H(hoge.gov.example) = 55ipsf6g5hv6cadallvuaj8ukngtng28
H(*.gov.example) = jd9uj6jtma56hf6h1q8tfblt42m0di8t

さて、この状態で再帰問い合わせしてみると、、、

root@server_unbound1:/ # dig hoge.gov.example

;; <<>> DiG 9.10.4-P2 <<>> hoge.gov.example
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 47122
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;;hoge.gov.example. IN A

;; Query time: 4 msec
;; SERVER: 192.168.11.22#53(192.168.11.22)
;; WHEN: Tue Sep 19 09:00:38 JST 2017
;; MSG SIZE  rcvd: 45

SERVFAIL になっちゃいますね。なぜこうなるのでしょう。ちなみに +cd (check disabled = 検証無視) してみると、応答はキャッシュに入っています。

root@server_unbound1:/ # dig hoge.gov.example +cd +dnssec

; <<>> DiG 9.10.4-P2 <<>> hoge.gov.example +cd +dnssec
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 39446
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;hoge.gov.example. IN A

;; AUTHORITY SECTION:
35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3597 IN NSEC3 1 1 12 AABBCCDD B4UM86EGHHDS6NEA196SMVMLO4ORS995  NS DS RRSIG
35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3597 IN RRSIGNSEC3 7 2 3600 20171017014906 20170917014906 61667 example. bGlUN/y8CN6iIV51TfgtVZ+guPRNh0ZZ8oDR037uWMgi4fMGClwLBDj+ T65dZ/7r2L6ARcmlf36E5tIfokySuIjX3IH9uI3XU82dHh03tKFHzIKF xWAgbGzeLg1KVzC2umnRz3ZiPDSQOb3enf+0OC6T9c/SSC6+OtUxXsju +GE=
gjeqe526plbf1g8mklp59enfd789njgi.example. 3597 IN NSEC3 1 1 12 AABBCCDD JI6NEOAEPV8B5O6K4EV33ABHA8HT9FGC  A HINFO AAAA RRSIG
gjeqe526plbf1g8mklp59enfd789njgi.example. 3597 IN RRSIG NSEC3 7 2 3600 20171017014906 20170917014906 61667 example. S1BSDNNNq+NK+dg45BatjRLgn9JTCZ+BFbfRGSB/auWBoW3B6Sb84jRR uUFJQh9cV+g9lMD4aSTXBlLZA3vcu6EJVllHhq1uX8nWCpjV2RyQfK27 jDXAKn51IippqOZUREGHfDbd91cirWmV3+vZyZSVb03yxPYq8AY7suzc unE=
example.                                  3597 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
example.                                  3597 IN RRSIG SOA 7 1 3600 20171017014906 20170917014906 61667 example. M2tQa+Q23qWcR1HQ2RxPY2hsjsf6X/8eFJcOaqefSLXO4bvdyOfoRbkr mw9TKK/dRg3rLwhtVjPtU/TcRLzXAjypci64y1Q4q9exD8L0LZ5cVgDL DUpwPzqxbpMeAsAcy/yjnJSmxLYHFAaFkDTVBiSKcerlXVhhYWzyvqil yxk=

;; Query time: 0 msec
;; SERVER: 192.168.11.22#53(192.168.11.22)
;; WHEN: Tue Sep 19 09:00:41 JST 2017
;; MSG SIZE  rcvd: 761

なぜこうなるのでしょうね。まだ NSD 直っていない? それとも validator 側の問題? exact match の NSEC3 がない限り仕様?

ちなみに DNS-ORAC 25 のスライドにある問題となっている Google の例をやってみると、今でもこうなります。こちらもまだ直っていない。

~% dig @8.8.8.8 unsigned.ent.zft-root.rd.nic.fr.

;; <<>> DiG 9.9.5 <<>> @8.8.8.8 unsigned.ent.zft-root.rd.nic.fr.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 64129
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;;unsigned.ent.zft-root.rd.nic.fr. IN A

;; Query time: 1722 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Mon Sep 18 07:39:58 JST 2017
;; MSG SIZE  rcvd: 60

+cd してみると

~% dig @8.8.8.8 unsigned.ent.zft-root.rd.nic.fr. +dnssec +cd

; <<>> DiG 9.9.5 <<>> @8.8.8.8 unsigned.ent.zft-root.rd.nic.fr. +dnssec +cd
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10885
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;unsigned.ent.zft-root.rd.nic.fr. IN A

;; AUTHORITY SECTION:
unsigned.ent.zft-root.rd.nic.fr. 29 IN SOA dns1.configuration02-z1.zft-root.rd.nic.fr. hostmaster.configuration02-z2.zft-root.rd.nic.fr. (
                      2222222237 ; serial
                      3600       ; refresh (1 hour)
                      1800       ; retry (30 minutes)
                      3600000    ; expire (5 weeks 6 days 16 hours)
                      5400       ; minimum (1 hour 30 minutes)
                      )

;; Query time: 666 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Mon Sep 18 07:48:06 JST 2017
;; MSG SIZE  rcvd: 150

~% dig @8.8.8.8 any unsigned.ent.zft-root.rd.nic.fr. +dnssec +cd

; <<>> DiG 9.9.5 <<>> @8.8.8.8 any unsigned.ent.zft-root.rd.nic.fr. +dnssec +cd
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11053
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;unsigned.ent.zft-root.rd.nic.fr. IN ANY

;; ANSWER SECTION:
unsigned.ent.zft-root.rd.nic.fr. 29 IN SOA dns1.configuration02-z1.zft-root.rd.nic.fr. hostmaster.configuration02-z2.zft-root.rd.nic.fr. (
                      2222222237 ; serial
                      3600       ; refresh (1 hour)
                      1800       ; retry (30 minutes)
                      3600000    ; expire (5 weeks 6 days 16 hours)
                      5400       ; minimum (1 hour 30 minutes)
                      )
unsigned.ent.zft-root.rd.nic.fr. 29 IN NS dns1.configuration02-z1.zft-root.rd.nic.fr.
unsigned.ent.zft-root.rd.nic.fr. 29 IN NS dns2.configuration02-z1.zft-root.rd.nic.fr.

;; Query time: 844 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Mon Sep 18 07:48:12 JST 2017
;; MSG SIZE  rcvd: 183

broken ENT was(?) here!!! (cont.)

署名の期限切れてるじゃないですか。議論以前の問題でした。

root@meme:/usr/local/etc/unbound # dig unsigned.ent.zft-root.rd.nic.fr. @vps430862.ovh.net +dnssec

; <<>> DiG 9.9.5 <<>> unsigned.ent.zft-root.rd.nic.fr. @vps430862.ovh.net +dnssec
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11537
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 3
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;unsigned.ent.zft-root.rd.nic.fr. IN A

;; AUTHORITY SECTION:
unsigned.ent.zft-root.rd.nic.fr.                       30 IN NS dns1.configuration02-z1.zft-root.rd.nic.fr.
unsigned.ent.zft-root.rd.nic.fr.                       30 IN NS dns2.configuration02-z1.zft-root.rd.nic.fr.
L88GSU1FPBVDNQS1C05EB9GQ0593L7T1.zft-root.rd.nic.fr. 5400 IN NSEC3 1 1 10 BA5EBA11 L88GSU1FPBVDNQS1C05EB9GQ0593L7T1 NS SOA RRSIG DNSKEY NSEC3PARAM
L88GSU1FPBVDNQS1C05EB9GQ0593L7T1.zft-root.rd.nic.fr. 5400 IN RRSIG NSEC3 8 5 5400 20170820122741 20170721122741 24105 zft-root.rd.nic.fr. FMrZwhyL5ZS1n2EIHW1AfNnlX3dL09AQBQ9w1IouBrIsJX+T/T7oBLXP EtjZPScYj5p04MmoQiVRG1gv1F6BI8Om2XAPrze+2zHbwZqVAHEY+hDf xeHShyV3VLPCveOrOztSuHxxkNNcVTaC2SFjlAAT2B6bZMeAEJFnqHrR JLM=

;; ADDITIONAL SECTION:
dns1.configuration02-z1.zft-root.rd.nic.fr.            30 IN A 145.239.76.199
dns2.configuration02-z1.zft-root.rd.nic.fr.            30 IN A 145.239.76.201

;; Query time: 296 msec
;; SERVER: 145.239.76.202#53(145.239.76.202)
;; WHEN: Tue Sep 19 14:41:13 JST 2017
;; MSG SIZE  rcvd: 411

broken ENT was(?) here!!! (cont.)

ということで SERVFAIL を試すことのできるサンプルを作成しました。
NSD で動いている mufj.jp の下にsub.gov.mufj.jp. という insecure なゾーンをつくり mufj.jp ゾーンを dnssec-signzone で opt-out 署名してあります。(gov.mufj.jp が ENT)
8.8.8.8 でも Unbound でも SERVFAIL になります。

% dig @127.0.0.2 hoge.gov.mufj.jp +nocd +dnssec

; <<>> DiG 9.9.5 <<>> @127.0.0.2 hoge.gov.mufj.jp +nocd +dnssec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 28949
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;hoge.gov.mufj.jp. IN   A

;; Query time: 0 msec
;; SERVER: 127.0.0.2#53(127.0.0.2)
;; WHEN: Tue Sep 19 21:38:11 JST 2017
;; MSG SIZE  rcvd: 45

% dig @127.0.0.2 hoge.gov.mufj.jp +cd +dnssec

; <<>> DiG 9.9.5 <<>> @127.0.0.2 hoge.gov.mufj.jp +cd +dnssec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 16710
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;hoge.gov.mufj.jp.  IN  A

;; AUTHORITY SECTION:
h86ajsso49ii5hl8ki8hc6f8a9he736p.mufj.jp. 291 IN NSEC3 1 1 12 DECAFE OV6O1L520EKOHT4V7GIABK95FUA0SOLK A RRSIG
h86ajsso49ii5hl8ki8hc6f8a9he736p.mufj.jp. 291 IN RRSIG NSEC3 7 3 300 20200101000000 20170919113022 19682 mufj.jp. IiAbaPZTGBjv56b6CoAHwrAd7c3TLwND1n7djqzL3zAKrVafFSjmsvJ0 mDYv8zSJeJhOVqtWXIW1w5Xhu3GFgJQ1kaU/BUhVQIRl2sS02wFiyAGp /Y2LO1CkqBEhduiTkLwt27B3JH7O0A/IMUzqF9V4TWjEbyIuF3rzYKeK Q2E=
uqhn509734gpuulr1r76p6qrsitd2lfg.mufj.jp. 291 IN NSEC3 1 1 12 DECAFE AE1H13EECDKG02L57UHK6VUMBLRFFRS5 A RRSIG
uqhn509734gpuulr1r76p6qrsitd2lfg.mufj.jp. 291 IN RRSIG NSEC3 7 3 300 20200101000000 20170919113022 19682 mufj.jp. V0cHNYX+/0pLOOVcJ7rQON5fU2XXpJ6e1AOQCMcZ3VscA3DnVJ+T3xyL B0Z6vKWNRYy9gsu952a5qVd/lE1BBC3iQGjsDH6sX6RIlrvOpd/iPGI8 IzEpGvRlHSDpUn98LN+4GjCd8IV8ZwXJWlrBp3PRldSOi4Rt7wDnJleC U6Q=
mufj.jp.                                  291 IN SOA ns.mufj.jp. tss.e-ontap.com. 2017082802 3600 600 86400 300
mufj.jp.                                  291 IN RRSIG SOA 7 2 3600 20200101000000 20170919113022 19682 mufj.jp. jlSUvbaSaGxgzIQyKhOSLDEa9dYTs/ba3xNQrIV8t+qYbvvqMJ8vSLRP DL4Hw6GRsF82kgdHFxOIXMRr8PLZX5HsE8ZSoLCGbOS4ddVhbGUsAK4E dkjyH1Xv64fG8qnuVKIftwi7PwIgUs5YiuovOJjGNNou8og7Wj74plQC 8k0=

;; Query time: 0 msec
;; SERVER: 127.0.0.2#53(127.0.0.2)
;; WHEN: Tue Sep 19 21:38:17 JST 2017
;; MSG SIZE  rcvd: 764

% dig @8.8.8.8 nodomain.gov.mufj.jp +nocd +dnssec

; <<>> DiG 9.9.5 <<>> @8.8.8.8 nodomain.gov.mufj.jp +nocd +dnssec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 6676
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;nodomain.gov.mufj.jp.  IN   A

;; Query time: 433 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Tue Sep 19 21:50:57 JST 2017
;; MSG SIZE  rcvd: 49

さてさて、これどうしますかね。
仕様のバグ (RFC5155 に Errata) な気がしますが意見が分かれているようで、ISC は dnssec-signzone を直す気はなさそうだし、NSD のバグだというなら NSD を直せばよいですがこれがなぜ NSD の問題なのかよくわかりませんし、バリデータの問題なのであれば Google をはじめとして世界中のバリデータを直さなきゃなきゃいけませんし、はてさて私にはさっぱりわかりません。そもそも opt-out された insecure なゾーンたちを不存在証明で守ってあげようなんて考えなくてよいのではないでしょうかね。

この件を議論するには、やはり DNS 温泉 4 の補講が必要ですかね、、、

NSD broken ENT was here!!!

2017/12/4 追記: 禁断の BIND 権威サーバに手を出しました。(触りたくなかった)

p.14 のケースで BIND を権威サーバにするとこうなります。

0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example. 3600 IN NSEC3 1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR  NS SOA MX RRSIG DNSKEY NSEC3PARAM
JI6NEOAEPV8B5O6K4EV33ABHA8HT9FGC.example. 3600 IN NSEC3 1 1 12 AABBCCDD K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H
GJEQE526PLBF1G8MKLP59ENFD789NJGI.example. 3600 IN NSEC3 1 1 12 AABBCCDD JI6NEOAEPV8B5O6K4EV33ABHA8HT9FGC  A HINFO AAAA RRSIG

1行目は example の exact match
3行目は *.gov.example (jd9uj6jtma56hf6h1q8tfblt42m0di8t) をカバー
2行目で gov.example (jthlauk0mdainrqmnviqj5gqtl3ddnt4) をカバーしている解釈になるのでしょうかね。でも opt-out なので insecure な gov.example は存在するかもしれないけれど良いのかな... (意味深)

これだと hoge.gov.example は SERVFAIL にはならず NXDOMAIN となります。

これが "NSD broken" の意味だったのでしょうか。
... 未だ直っていないから違うでしょう。彼らは何か見落としていると思います。そして BIND と同様に直すのは危なそうです。

2018/1/7 追記: DNSSEC への毒入れ実験を行って全貌がわかりました。1/13 の補講に際して資料 Forged Delegation Injection into Empty Non-Terminal with NSEC3 を公開しました。