世界を動かす技術を、日本語で。

DNSを介した画像

概要

  • TXTレコードの 実際のサイズ制限 と誤解についての解説
  • UDPとTCP による制限の違い
  • バイナリデータ の取り扱いと課題
  • Google Public DNSなどを利用した 大容量TXTレコード の実演
  • セキュリティやキャッシュ に関する考察

TXTレコードのサイズ制限と実際

  • TXTレコード は、RFC 1035 section 3.3.14に準拠し、 複数のcharacter-string を持つことが可能
  • 1つのcharacter-stringは 最大255バイト まで、複数連結することでレコード全体のサイズが拡張可能
  • UDPの場合、DNSペイロードは現在 約1232バイト が上限
  • TCP利用時 は、DNSプロトコルの仕様上 最大64KB まで送信可能
  • 実際には、 TXTレコードに画像データ など大容量データを格納し、TCP経由で配信する実験も可能

バイナリデータの扱いとJSON APIの課題

  • Google Public DNSの JSON API を利用し、 大きなTXTレスポンス をTCP経由で配信可能

  • バイナリデータ をTXTレコードに格納することで、 Base64等のエンコードによるオーバーヘッド削減

  • JSONはバイナリデータ処理に最適化されていないため、 独自のJSONパース処理 が必要

  • 実際のデータ取得には、 digコマンドとPerlワンライナー を組み合わせてバイナリ復元が可能

    • 例:
      $ dig +short dog.log.battery.st TXT | perl -pe'chomp; s/" "//g; s/^"//; s/"$//; s/\\(\d{3})/chr $1/eg; s/\\([\\"])/$1/g' > dog.avif
      $ sha256sum dog.avif
      

DNSサーバ・キャッシュ・セキュリティの考察

  • Google Public DNS@dns.google 等のオープンリカーサーを使うことで大容量TXTレコードの取得が容易
  • TTLを10秒 など短く設定し、不要なキャッシュを防止
  • TTLを長く設定すれば、 分散CDN的な利用 も理論上可能(ただしTTL制御が入る可能性あり)
  • DNSトンネリング によるデータ伝送は既知だが、 大容量データをブラウザへ直接送信 は新しいアプローチ
  • Let's Encryptの IPアドレス証明書 普及により、 HTTPS通信の直接化 やDNSフィルタ回避の懸念

サーバ構成とAI活用

  • サーバ側は Go製のカスタムDNSサーバ を使用
  • サーバ実装は ChatGPT を利用しつつ、 細部は手動修正
  • サーバコードは全て 公開、クライアントHTMLやブログ記事は 自作

まとめ

  • TXTレコードの真の上限 はUDP/TCPによるDNSペイロードサイズ依存
  • バイナリデータの直接格納 により、効率的な大容量データ転送が可能
  • セキュリティやキャッシュ の観点からも、今後の活用や規制に注目

Hackerたちの意見

レコードサイズの上限は64KBだけど、レコードの数は自由に増やせるから、複数のTXTレコードのレスポンスを組み合わせれば、もっと大きな画像も可能だよ。

記事に[1]のリンクを貼ったよ。ここで以前に話題になった[2]ところで、その記事の訂正もした。基本的に、TCP DNSレスポンスには2バイトの長さヘッダーがあって、ペイロード(つまりDNSメッセージの中身)が64 KiBに制限されてるんだ。[1]: https://www.netmeister.org/blog/dns-size.html#:~:text=65536%20bytes%20DNS%20payload%20%2B%202%20bytes%20size%20%3D%2065538%20bytes [2]: https://news.ycombinator.com/item?id=39257147

DNSメッセージは64Kを超えられないけど、TCPを使えば複数のメッセージを送信できるんだ。これがAXFR(ゾーン転送)のやり方で、一つの質問に対して複数の応答が返ってくるんだよ。https://github.com/m3047/rear_view_rpz/blob/b17cf943ccd7498d...

すごいね!俺もDNSを使ってBad AppleやDoomをプレイしたことあるよ。https://youtu.be/AJ2Q12vYojY https://youtu.be/GoPWuJR6Npc

いいね!Bad Appleのやつは、俺も似たようなことを試してみたけど、権威DNSサーバーに直接問い合わせると動くんだ。でも、キャッシュが関わると、レコードがランダムに並べ替えられちゃうことがある(TTL=0の場合でも)。だから、すごく長いレコードとしてまとめてやったんだ。そうすれば、並べ替えを気にせずにキャッシュできるからね。

DNSの面白いところは、ポート53がファイアウォールで通常開いていて、データの流出や侵入に最適だってことだね。

そうなの?俺が見るファイアウォールは、デフォルトで受信を許可してないことが多いけど(すべての送信は許可してるけど)。

企業環境では、会社のDNS内部リゾルバーだけを使わないとダメで、外に出るのはポート53だけにするべきだよ。これはDNSトンネリングや情報漏洩の試みを検出してブロックするための基本的なセキュリティ対策なんだ。

でも、すごく検出されやすいよ。最近の次世代ファイアウォールはこれに敏感だからね。

それに、支払い前のキャプティブポータルでも通常は動くよ。

AndroidのAFWall+がその例だね。アプリがブロックされていても、インターネットの権限があればDNSリクエストを送れるから、ファイアウォールがあっても双方向の通信ができちゃうんだよね。

DNSを使ってHNクローンを作ることってできるのかな?

DNSを通じてLLMチャットはどう? https://github.com/accupham/llm-dns-proxy

あ、これを聞いて思い出した!俺が書いたChrome拡張機能で、Webコンテンツ(画像、HTML、JS、何でも)をDNS経由で配布するやつがあるんだ。https://blog.zorinaq.com/cdn53-a-super-distributed-cdn/ これは偽のTLD .cdn53を実装してて、http://zorinaq.com.cdn53にアクセスすると、拡張機能がリクエストをキャッチして、"_cdn53.zorinaq.com"のTXTレコードのDNSクエリを送るんだ。レスポンスにはHTMLコンテンツや他のコンテンツが含まれてて、サイズは約65KBまでいけるんだ。これはすごく分散されてて、ドメインにアクセスする全てのDNSリゾルバーに自然にキャッシュされるからね…。

いいアイデアだね。今の時代だと、Chrome拡張のAPIの変更でこれがうまくいかないかも?ネットワークインターセプションAPIに制限があるからね。

DNSを使って生のIPv4をトンネリングしたいなら、Iodineプロジェクトもあるよ。[53] https://github.com/yarrick/iodine

Iodine大好き!昔、すごくセキュリティが厳しいネットワークの場所でコンサルティングの仕事をしてたんだけど、IodineとWireGuardを使ってほとんどのファイアウォールを突破できた。遅いけど、効果的だったよ。

これは面白いけど、悪意のあるユーザーがこの手段を悪用するせいで、ファイアウォールやエンドポイントエージェントがこれを検出してブロックするだろうね。もしこれを使った真剣なソリューションを作るなら、家庭用や実験にはいいかもね。

俺はクラウドコンピューティングの会社でネットワーキンググループにいたんだ。聞いたことあるでしょ?一部のDNSトラフィックは料金を取ってなかったから、顧客の中にはDNSを使ってデータ転送料金を回避する方法を見つけるやつがいたんだ。要するに、全ての顧客に影響を与えるDoS攻撃みたいなもので、数人が全体の支出のほんの一部を節約するためにね。俺の仲間のチームはその混乱を処理しなきゃいけなかったんだけど、そのチームは年に100%以上のスタッフの入れ替わりがあったよ。問題が出るたびにオンコールのスタッフに対応させて、根本的なDoSベクターを機能としてごまかす問題を解決しようとしなかったからね。

じゃあ、過剰なDNSトラフィックに対して料金を取るのが解決策じゃない?

ドメイン名を受け取ってIPアドレスを返すREST APIを作ることもできるよ!そしたら、そのREST APIを使って表示したい画像のIPアドレスを取得するウェブサーバーを作れるね!

DNS上の画像をDNSCrypt経由で、VPNを通じてTorへのゲートウェイとしてアクセスするDNSリレーを使う。最高のセキュリティだね。