メモ的ななにか

@Maleic1618

RFC2671: Extension Mechanisms for DNS (EDNS0)

こんにちは、まれいんです。

この記事は ひとりRFCの旅 Advent Calender 2日目の記事です。

qiita.com

今日は1999年8月に出たDNSにおける拡張オプションのようなものである、EDNS0を定めたRFC2671を読んでいきます。 多分普通にdigコマンドを叩くと使われているので、皆さんも知らず知らずのうちに使っているかと思います。

記事を書いた後に気付いたのですが、JPNICさんが日本語訳を公開しているのでみなさんはこちらを読んでみるとよいと思います。

$ dig maleic1618.hatenablog.jp @8.8.8.8

; <<>> DiG 9.16.8-Debian <<>> maleic1618.hatenablog.jp @8.8.8.8
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19383
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512  <-- これ!
;; QUESTION SECTION:
;maleic1618.hatenablog.jp.      IN      A
...

RFC 2671 - Extension Mechanisms for DNS (EDNS0)

現在はこのRFCはObsoletedとなっており、RFC6891で更新されていますが、歴史を追いかける意味でいったん読んでみます。

概要

DNSプロトコルのフォーマットには多くのフィールドを含んでいますが、512bytesというサイズ制限は多くの場合は小さすぎました。 そのためDNSの最大サイズを拡張したくなったわけですが、クライアントが対応していることをサーバー側に通知する必要がありました。 他にもリクエストのステータスを入れるRCODEフィールドが4bitsしかなかったり、ラベルタイプを表すフィールドが2bitsしかなかったりと、拡張したいものはたくさんあります。

これらのために拡張をいれなくてはいけませんが後方互換性を保つため、未対応のクライアントがバグらないような形で拡張する必要がありました。 これを考慮しつつ生まれた仕組みがEDNS0です。

ちなみに、受け取った側が解釈できなかった場合はNOTIMPL, FORMERR, SERVFAILのいずれかを返すように求められています。

Extended Labels

前回簡単に解説しましたが、ドメイン名の記載方法は普通に書くか、ポインターをつかうかの2種類がありました。 どちらが使われているかはドメイン名の上位2bitによって区別できます。(0b00xxxxxx=普通の記載方法、0b11xxxxxx=ポインター) これがlabel typeです。

では0b01xxxxxxと0b10xxxxxxはどうなのか?というとこれらは将来のために予約されていました。

しかしこれらは2種類しか残ってないので枯渇してしまうかもしれません、というわけで拡張方法が定義され、 label typeのフィールドが0 1の場合は、残りの6bitもラベルの種類を表すフィールドとして使ってよいということになりました。 サロゲートペアのような感じですね。

ただし0b01111111は将来の拡張のためにreservedです。

OPT pseudo-RR

拡張のために用いられる疑似的なリソースレコードタイプのOPTが追加されました。 これを利用してRCODEを拡張したり、DNSの最大ペイロードサイズを変更することができます。 このリソースレコード、構造だけは以下に示す普通のリソースレコードのフォーマットを踏襲しています。 なお、RRtype numberは41です。

いかにwire formatを示します。

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                                               |
    /                                               /
    /                 NAME(root固定)                /
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    TYPE(41)                   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |             最大ペイロードサイズ               |  <- 普通はCLASSが入る
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |    EXTENDED-RCODE     |        VERSION        |  <-|
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |- 普通はTTLが入る
    |                       Z                       |  <-|
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                   RDLENGTH                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
    /                     RDATA                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

元々、RCODEに4bit割り当てられていますが、追加で8bit割り当てられたので、 これらを合わせた12bitで拡張RCODEを表現します。(今回追加の8bitが上位bit) また、新しいBADVERSとしてBADVERSが15に割り当てられました。(0-15は既存のRCODEを利用するので、一番小さい番号が16)

また、RDATAの方にはOPTION-CODEとOPTION-DATAのキーバリュー形式で任意長のオプションを設定することができます。

                +0 (MSB)                            +1 (LSB)
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  0: |                          OPTION-CODE                          |
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  2: |                         OPTION-LENGTH                         |
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  4: |                                                               |
     /                          OPTION-DATA                          /
     /                                                               /
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+