EDNS0(Extension Mechanisms for DNS)
概要
EDNS0(Extension Mechanisms for DNS、バージョン 0) は、DNS プロトコルの拡張メカニズムで、元の DNS 仕様(RFC 1035)にあった制限を緩和し、新しい機能を追加データとして伝える仕組みです。RFC 6891(2013年)で現行仕様が定義されており、OPT 疑似レコードと呼ばれる特殊なレコードを使って拡張情報を伝送します。
元の DNS 仕様では UDP パケットのサイズが 512 バイト に制限され、レスポンスがこのサイズを超える場合に TCP へのフォールバックが必要でした。DNSSEC の署名データ(RRSIG、DNSKEY)を含めると簡単にこの制限を超えるため、EDNS0 によるサイズ拡張が不可欠です。DNS Flag Day 2020 以降、EDNS0 に対応しないリゾルバーやサーバーへの互換性維持は打ち切られ、EDNS0 対応が DNS 運用の前提となっています。
EDNS0 はバージョン番号を持たず、バージョン 0 が唯一の実装です。将来のバージョンが導入される際は、OPT レコードのバージョンフィールドで識別されます。
仕組み
EDNS0 は OPT 疑似レコードを DNS メッセージに追加し、UDP ペイロードサイズの拡張とオプションフィールドの伝送を実現します。
sequenceDiagram
participant C as クライアント
participant S as 権威サーバー
C->>S: クエリ + OPT(udp: 1232, DO=1)
Note over S: 要求サイズ内で<br/>レスポンスを構成
alt レスポンス ≤ 1232 バイト
S-->>C: 応答 + OPT(udp: 4096)
else レスポンス > 1232 バイト
S-->>C: TC=1(切り詰め)
C->>S: TCP で再問い合わせ
S-->>C: 完全なレスポンス
end
OPT 疑似レコード
EDNS0 の情報は、DNS メッセージの ADDITIONAL SECTION に OPT 疑似レコードとして格納されます。OPT レコードは通常のリソースレコードではなく、クエリとレスポンスの間で機能交渉を行うためのメタデータです。
; クエリに含まれる OPT レコードの例
; EDNS: version: 0, flags: do; udp: 1232
OPT レコードの構成要素を次に示します。
| フィールド | 説明 |
|---|---|
| NAME | 空のラベル(ルートドメイン . に相当) |
| TYPE | 41(OPT のレコードタイプ番号) |
| CLASS | リクエスト元の UDP ペイロードサイズ(バイト) |
| TTL | 上位 16 ビットが拡張 RCODE、下位 16 ビットがバージョン(現在は 0) |
| RDATA | EDNS0 オプションのリスト |
最も重要なパラメータが UDP ペイロードサイズ です。クライアントは OPT レコードの CLASS フィールドで自身が受信可能な UDP パケットサイズをサーバーに通知します。サーバーはこのサイズ内でレスポンスを返そうとし、超過する場合は TC(Truncated)フラグを立てて TCP フォールバックを促します。
UDP ペイロードサイズ
DNS Flag Day 2020 では、EDNS0 の UDP ペイロードサイズとして 1232 バイト が推奨値として定められました。この値は IPv4 でフラグメント化のリスクを最小限に抑えつつ、DNSSEC の署名データを収容できる十分なサイズです。
主なサイズ値とその背景を次に示します。
| サイズ(バイト) | 由来 |
|---|---|
| 512 | RFC 1035 の元の制限。DNSSEC レスポンスには不十分 |
| 4096 | 初期の EDNS0 実装で使われた値。フラグメント化のリスクが高い |
| 1232 | DNS Flag Day 2020 の推奨値。IPv4 でフラグメント化を回避 |
dig コマンドはデフォルトで 4096 バイトを要求しますが、フラグメント化によるパケットロスを防ぐため、1232 バイトに制限することが推奨されています。
# EDNS0 を有効にして UDP ペイロードサイズ 1232 で問い合わせる
dig A example.com +bufsize=1232
DO ビット(DNSSEC OK)
OPT レコードの Flags フィールドには DO ビット(DNSSEC OK、ビット 15)が定義されています。クライアントが DO ビットを設定してクエリを送ると、サーバーは DNSSEC の署名データ(RRSIG レコード)をレスポンスに含めます。
# DO ビットを設定して DNSSEC 署名付きで問い合わせる
dig A example.com +dnssec
DO ビットが設定されていない場合、サーバーは RRSIG レコードを含めずに通常のレスポンスを返します。DNSSEC 検証を行うリゾルバーは必ず DO ビットを設定してクエリを送信します。
EDNS0 オプション
EDNS0 は OPT レコードの RDATA にオプションコード(option-code)とオプションデータのペアを格納できます。現在使われている主なオプションを次に示します。
| Option Code | 名称 | 用途 |
|---|---|---|
| 8 | ECS(Client Subnet) | リゾルバーの代わりにクライアントのサブネットを権威サーバーに伝える。CDN のジオルーティングに利用 |
| 10 | Cookie | DNS クッキーにより、IP スプーフィングやリフレクション攻撃を防ぐ(RFC 7873) |
| 12 | Padding | DTLS や DoH でメッセージ長を均一化し、トラフィック分析を困難にする(RFC 7830) |
| 3 | NSID | ネームサーバー識別子。Anycast 環境でどのサーバーが応答したかを特定する |
ECS(EDNS Client Subnet)は DNS over HTTPS のリゾルバーがオリジンの IP アドレスを権威サーバーに伝えるために使います。これにより、CDN はクライアントの地理的位置に基づいて最適なサーバーを返すことができます。
確認方法
dig で EDNS0 の情報を確認するには +bufsize と +dnssec オプションを使います。
# EDNS0 を有効にして UDP ペイロードサイズ 1232 で問い合わせる
dig A example.com +bufsize=1232
;; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 300 IN A 203.0.113.1
EDNS: version: 0, flags: do; udp: 1232 の行が EDNS0 の交渉結果です。flags: do は DO ビットが設定されていることを示します。
EDNS0 に対応していないサーバーは OPT レコードを返さず、512 バイトの制限でレスポンスを返します。
# EDNS0 を無効にして問い合わせる
dig A example.com +noedns
+noedns を付けると OPT レコードが送信されず、元の DNS 仕様の制限で問い合わせます。EDNS0 対応のトラブルシューティングに使います。
OPT レコードの詳細を確認するには +ednsflags オプションを使います。
dig A example.com +dnssec +bufsize=1232
外部の視点から確認したい場合は、Labee Dev Toolbox の DNS API を使います。
curl "https://labee.dev/api/dns?domain=example.com&type=A"
{
"success": true,
"data": {
"domain": "example.com",
"records": {
"A": [
{ "address": "203.0.113.1", "ttl": 300 }
]
}
},
"error": null,
"meta": { "responseTime": 42 }
}
API 側のリゾルバーは EDNS0 に対応し、DNSSEC 検証を行っています。正しくレコードが返っていれば、EDNS0 と DNSSEC の通信が正常に機能しています。
よくある問題
EDNS0 の非対応やサイズ制限は、DNSSEC の検証失敗や TCP フォールバックの増加として現れます。
EDNS0 に対応していないファイアウォールやミドルボックスが DNS を遮断する
一部のファイアウォールやロードバランサーは、OPT レコード(レコードタイプ 41)を含む DNS メッセージを未知のレコードタイプとして破棄します。DNS Flag Day 2020 以降、主要な DNS ソフトウェアは EDNS0 非対応サーバーへのフォールバックを行わなくなったため、EDNS0 パケットを遮断するミドルボックスがあると名前解決が失敗します。
対処法は、ファイアウォールで OPT レコードを通過させる設定にするか、ファイアウォールのファームウェアを更新して EDNS0 に対応させます。dig +noedns で EDNS0 を無効にして名前解決が成功する場合、EDNS0 パケットの遮断が原因です。
UDP ペイロードサイズが大きすぎてフラグメント化される
EDNS0 で 4096 バイトの UDP ペイロードサイズを要求すると、DNSSEC の署名データを含むレスポンスが IP フラグメント化されることがあります。多くのファイアウォールと NAT ルーターはフラグメント化された UDP パケットを破棄するため、レスポンスが届きません。
UDP ペイロードサイズを 1232 バイト に制限することで、フラグメント化を回避しつつ大半の DNSSEC レスポンスを収容できます。レスポンスが 1232 バイトを超える場合は TC フラグが立ち、TCP にフォールバックします。
DNSSEC 検証で SERVFAIL になる
DNSSEC を有効にしたリゾルバー(Google Public DNS、Cloudflare DNS 等)は、EDNS0 の DO ビットを設定してクエリを送信します。権威サーバーが RRSIG レコードを返さない、または署名が期限切れの場合、検証に失敗して SERVFAIL を返します。
EDNS0 自体が原因ではなく、DNSSEC の署名運用の問題です。ただし、ファイアウォールが OPT レコードを遮断している場合、リゾルバーが署名データを受け取れずに SERVFAIL になることがあります。dig +dnssec で RRSIG レコードが返るかを確認します。
ECS によるプライバシー懸念
EDNS0 Client Subnet(ECS)オプションは、リゾルバーがクライアントの IP アドレスの一部を権威サーバーに伝えます。これにより CDN のジオルーティングは改善しますが、クライアントのIP アドレスが権威サーバーに漏洩するプライバシー上の懸念があります。Cloudflare DNS(1.1.1.1)は ECS をデフォルトで無効にしています。Google Public DNS(8.8.8.8)は ECS を有効にしていますが、クライアント IP の下位ビットを削ってプライバシーを保護しています。