RFCを読もう 〜 DNS編 〜
2019/12/22になるまで以下はかしこい人には見えない。
途中で力つきていた……。
何
この記事はKMC Advent Calendar 2019の22日目の記事です。
昨日の記事はten986さんの「」でした。
誰
普段はKMCでは飲酒、SLACKで雑談、サーバ管理、管理の応援、ヴァーチャルYouTuberの視聴等をしています。
RFCを読むと楽しい。
https://emaillab.jp/dns/dns-rfc/ これがDNSのRFCのdependency glaphです。
今回の範囲は以下のRFCぐらいです。逆に言うと多分以下のRFCより情報は増えていません。
DNS本体
その他
使うbase64のエンコーディング RFC4648 https://tools.ietf.org/html/rfc4648
http/2-style formatting RFC7540 https://tools.ietf.org/html/rfc7540#section-8.1.3 RFC8484の例に出てくる。RFC7540自体はHTTP/2について書かれてて超長いのと、まぁ出てくる例はなんとなく意味はわかるから流し読んでしかいないけど多分ここ。
はい
みなさんは生活していると突然車輪の再発明をして車輪の仕組みを学びたくなることありませんか? 私はあります。
ありますよね? あるという体で進めさせてください。 HTTPのパーサ的なものとかなら多くの人がなんだかんだで書いてみたりしているのではないかと予想します。という訳で今回はそれのDNS編です。
DoH
以前Google Public DNS over HTTPS を試すの記事を読んでいたので、DoHはなんかどこかのエンドポイントにリクエストを投げたらJSONでレスポンスが帰ってきて、それをパースするだけでできると思っていたため、ここから実装しようと考えます。
そこでこの記事をもう一度読んでみると、冒頭に以下のような追記があります。
【2018/11/16 追記】
本記事は、2016 年 4 月に Google Public DNS サーバに実装された、実験的な DNS over HTTPS プロトコルについて紹介しています。DNS over HTTPS プロトコルはその後 IETF の doh ワーキンググループにて標準化が進められ、2年半後の 2018 年 10 月に RFC8484 として出版されました。本記事で紹介したプロトコルは RFC8484 に規定されたプロトコルとはいくつもの点で異なっていることにご注意ください。
いきなり躓いてしまいました。
Google Public DNS provides two distinct DoH APIs at these endpoints:
https://dns.google/dns-query – RFC 8484 (GET and POST)
https://dns.google/resolve? – JSON API (GET)
とあります。どうやらJSON APIをGoogleが作ってみた後に、それがブラッシュアップされてRFC8484となったようです。
というわけでRFC8484を読んでいきます。
RFC8484
https://tools.ietf.org/html/rfc8484#section-4.1.1 にRequestのExampleが、 https://tools.ietf.org/html/rfc8484#section-4.2.2 にResponseのExampleがあります。
Requestのほうはこうです。
:method = GET
:scheme = https
:authority = dnsserver.example.net
:path = /dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB
accept = application/dns-message
curlにするならこうでしょうか。
curl https://dns.google/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB -H 'accept: application/dns-message' | od -x --endian=big
ここではエンドポイントとして dns.google を使いリクエストを投げています。また、結果として謎のバイナリが帰ってくるので、とりあえず
od -x
しています。ついでにネットワークバイトオーダーでやっていくので、 --endian=big
もつけておきます。これは以下のような出力となります。
curl https://dns.google/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB -H 'accept: application/dns-message' | od -x --endian=big
0000000 0000 8180 0001 0001 0000 0000 0377 7777
0000020 0765 7861 6d70 6c65 0363 6f6d 0000 0100
0000040 01c0 0c00 0100 0100 0023 5100 045d b8d8
0000060 2200
0000061
謎です。
When the HTTP method is GET, the single variable "dns" is defined as the content of the DNS request (as described in Section 6), encoded with base64url RFC4648.
らしいので、どうやら
dns=AAABA...
はBase64 encodedされたDNS requestで、その中身は(section 4.1.1)In this example, the 33 bytes are the DNS message in DNS wire format RFC1035, starting with the DNS header.
らしいので、RFC1035に定義されたDNS messageらしいですね。
echo AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB | base64 -d | od -x --endian=big
0000000 0000 0100 0001 0000 0000 0000 0377 7777
0000020 0765 7861 6d70 6c65 0363 6f6d 0000 0100
0000040 0100
0000041
中身はこう。謎です。
というわけで、DoHならDNSのパケットの構造をとりあえずは知らなくても、JSON APIで取ってこれる というわけにはいかないようです。RFC1035に潜っていきましょう。
https://developers.google.com/speed/public-dns/docs/doh/json でJSON APIで取ってくることはたしかにできますが、これはGoogle独自のもので、IIJ( https://public.dns.iij.jp/ )やCloudflare( https://1.1.1.1/ )のものでは使えないので、あんまりおもしろくないです(?)。
RFC1035
と、このような感じでDNSパケットが読めるようになり、リクエストが投げられるようになります。
本当はどのようにDNSが動作するかのRFC1034を先にやっておく必要があった気がしてきたけれども、長くなりすぎる気がするのでこのへんで……。
(気合があれば書くかも……)
いかがでしたか?
以上、DNSについて調べてみました! いかがでしたか?
明日の記事はwalkureさんの「」です。