Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby meets secure DNS & modern Internet protocols

Ruby meets secure DNS & modern Internet protocols

Kasumi Hanazuki

January 18, 2025
Tweet

More Decks by Kasumi Hanazuki

Other Decks in Technology

Transcript

  1. 花月かすみ • https://github.com/hanazuki • 2匹のもるもっとと暮らしています • RubyKaigi NOC (Wi-Fi係) 2

    • 2017 広島 • 2018 仙台 • 2019 福岡 • 2020 松本(中止) • 2022 津 • 2023 松本 • 2024 那覇, KoR • 2025 松山(予定) 2025-01-18 Tokyo RubyKaigi 12
  2. RubyKaigi NOC • 来場者向けWi-Fiの構築運用 • Wi-Fiスポンサー+京大マイコンクラブ+有志 • L1からL7まで ◦ 会場内ケーブル

    ◦ アクセスポイント・スイッチ・ルータ ◦ 対外インターネット接続・クラウド接続 ◦ ネットワークサービス(DHCP, DNS, ...) 3 2025-01-18 Tokyo RubyKaigi 12 ケーブル敷設・機器設置 L7構築
  3. DNS • 「ドメイン名からIPアドレスを検索するやつ」 ◦ “kmc.gr.jp” → 192.50.220.129 • 実際は,ドメイン名にあらゆるデータを紐づけられる 階層型分散データベース

    ◦ (リソースタイプ, ドメイン名) → リソースレコード ◦ レコードは各ドメインの所有者が管理 7 2025-01-18 Tokyo RubyKaigi 12
  4. 暗号化DNSプロトコル • DNS over TLS (DoT) ◦ TCPのやりとりをそのままTLSで暗号化 • DNS

    over HTTPS (DoH) ◦ GET /dns-query?dns=#{base64(query)} ◦ 通例,HTTP/2またはHTTP/3が使われる ▪ どちらもマルチストリームをサポートし, リクエストに対してレスポンスを順不同に返せる ▪ TLSで暗号化 11 2025-01-18 Tokyo RubyKaigi 12
  5. 暗号化DNSプロトコル (DoQ) • QUICのストリームとしてDNSクエリを送信 ◦ DoH/3と比べて,HTTP/3がない分だけ実装が簡易 • クライアント/リゾルバ間の通信では普及しないかも ◦ 主要OS・ブラウザで実装なし

    ◦ パブリックDNSではAdguard DNSがサポート • 権威サーバの暗号化が進めば使われる可能性がある ◦ HTTPSに乗せるメリットがないため 12 2025-01-18 Tokyo RubyKaigi 12
  6. プロトコルスタック 13 2025-01-18 Tokyo RubyKaigi 12 Do53 DoT DoH/2 DoH/3

    DoQ DNS DNS DNS HTTP/2 HTTP/3 DNS DNS DNS TLS TLS QUIC QUIC UDP TCP TCP TCP UDP UDP IPv4/IPv6 * 色付きが暗号化レイヤ
  7. 平文DNSから暗号化DNSへ 15 2025-01-18 Tokyo RubyKaigi 12 クライアントが暗号化DNSを使うように 自動構成するしくみが必要 • 従来のDHCP(v6)やIPv6

    RA (RDNSS)は リゾルバのIPアドレスのみクライアントに伝える → リゾルバがどのような暗号化に対応しているか分からない
  8. 日和見暗号化 (Opportunistic Encryption) リゾルバが暗号化プロトコルに対応していそうなら, クライアントが勝手にアップグレード • 853/tcpにTLS接続してみて, ◦ 接続できれば暗号化通信をする ◦

    接続できなければ平文通信にフォールバック • DoHへのアップグレードは難しい ◦ HTTPのパスが分からないため ◦ GET /dns-query?dns=#{base64(query)} 16 2025-01-18 Tokyo RubyKaigi 12 systemd 239+ (2018-01) Disabled by default Android 9+ (2018-08)
  9. Adaptive DNS Discovery ネットワーク側からクライアントを 明示的に暗号化リゾルバへ誘導する • DDR (RFC 9462) ◦

    リゾルバとクライアントの間で 暗号化プロトコルをネゴシエーション • DNR (RFC 9463) ◦ DHCP(v6)やIPv6 RAを拡張して クライアントに暗号化リゾルバを紹介 17 Windows Insider 25982 (2023-08) macOS* 13+ iOS/iPadOS 16+ (2022-10) 2025-01-18 Tokyo RubyKaigi 12 * Mac ChromeはDDRに未対応
  10. Discovery of Designated Resolvers (DDR) • 初期状態: クライアントは「非暗号化リゾルバのIPアドレス」 だけ知っている •

    リゾルバは特殊用途ドメイン名“resolver.arpa.”で 自身の対応プロトコルを公開する ◦ “arpa.”の権威サーバが答えるわけではない • クライアントはこの情報をもとに接続プロトコルを選ぶ 18 2025-01-18 Tokyo RubyKaigi 12
  11. SVCBレコード _dns.resolver.arpa. IN SVCB 1 resolver.rubykaigi.net. ( alpn="h3,h2" dohpath="/dns-query{?dns}") IN

    SVCB 2 resolver.rubykaigi.net. ( alpn="dot") 19 ターゲット A/AAAAを引くと 暗号化リゾルバの アドレスが分かる 対応プロトコル 優先度 2025-01-18 Tokyo RubyKaigi 12 パラメータで DoHのパスを指定 Service Binding
  12. DDR利用時のフロー 20 🔐 2025-01-18 Tokyo RubyKaigi 12 クライアント DHCPサーバ 非暗号化リゾルバ

    暗号化リゾルバ 非暗号化リゾルバの アドレス SVCB? _dns.resolver.arpa. 暗号化リゾルバのアドレス・プロトコル TLSハンドシェイク DNSクエリ・レスポンス 同じホストでもよい 検証
  13. 暗号化リゾルバの検証 SVCBで知った暗号化リゾルバを信頼して利用する条件 • Verified Discovery a. 証明書がトラストアンカーまで遡って検証可能 b. 証明書のSANが「非暗号化リゾルバのアドレス」を含む •

    Opportunistic Discovery a. 「非暗号化リゾルバのアドレス」がプライベートアドレス b. 「非暗号化リゾルバのアドレス」と 「暗号化リゾルバのアドレス」が一致 21 2025-01-18 Tokyo RubyKaigi 12 Appleデバイスには 実装されていない? 追試おねがいします
  14. 中間にDNSフォワーダがある場合 • 非暗号化リゾルバのアドレス ∉ サーバ証明書のSAN → Verified Discoveryではアップグレードされない • 非暗号化リゾルバのアドレス

    ≠ 暗号化リゾルバのアドレス → Opportunistic Discoveryでもアップグレードされない 22 2025-01-18 Tokyo RubyKaigi 12 クライアント フォワーダ リゾルバ _dns.resolver.arpa. SVCB _dns.resolver.arpa. SVCB 1 one.one.one.one. (...) 192.168.0.1 1.1.1.1
  15. DDRの限界 • 防げる攻撃 ◦ パッシブな盗聴 ◦ 正規のリゾルバへのなりすまし(Verified Discoveryの場合) • 防げない攻撃

    ◦ SVCBクエリを妨害して平文通信へダウングレード ◦ 経路ハイジャックでCAを騙して証明書を不正取得 ◦ 野良DHCP ◦ ハニーポットWi-Fi 24 2025-01-18 Tokyo RubyKaigi 12 多層防御が必要
  16. RubyKaigi 2023のリゾルバ AppleデバイスにDDRが実装されたと知り[WWDC] DNSを暗号化する実験を思いつく • DoT, DoH (HTTP/2, HTTP/3) •

    DDR(2023-05当時ドラフト) • DNR(当時まだオプション番号が未割り当て・クライアント実装がない) 2024もほぼ同じ構成で提供 [WWDC]: https://developer.apple.com/videos/play/wwdc2022/10079/ 26 2025-01-18 Tokyo RubyKaigi 12
  17. 使用したサーバソフトウェア 27 • Unbound ◦ DoTとDoH/2に対応するDNSリゾルバ ◦ DNSリゾルバとして折り紙付き • Envoy

    ◦ HTTP/2と/3に対応するHTTPプロキシ・ロードバランサ ◦ 巨大トラフィックを捌く実績あり 汎用コンポーネントを 使えるHTTPの旨味 2025-01-18 Tokyo RubyKaigi 12
  18. AWS VPC 会議場 パブリックIPアドレスでリゾルバを運用 途中のルータでパブリック→プライベートのNATをしていた 29 クライアント リゾルバ ロード バランサ

    リゾルバ ルータ ルータ 10.0.12.34 10.0.56.78 (AZごとのアドレス) 192.50.220.164 192.50.220.165 NAT 2025-01-18 Tokyo RubyKaigi 12
  19. 1/3から1/2のトランザクションを暗号化 30分ごとに集計した プロトコル別のクエリ割合 31 プロトコル 講演中 昼休憩 平文 62% 43%

    DoT 06% 09% DoH/2 30% 46% DoH/3 03% 03% Day1 10:30-11:00 Day1 12:30-13:00 macOS/iOS Android macOS/iOSが たまにHTTP/3を 使う(詳細不明) Matzのキーノートを PCで実況? PCを閉じて スマホを使っている? 2025-01-18 Tokyo RubyKaigi 12
  20. 課題: 動作検証 • DNSは壊れていても「それっぽく」動くように実装される • プロトコルの組み合わせが多く検証が煩雑 ◦ IPv4, IPv6 (それぞれ複数アドレス)

    ▪ DDRでv4→v6, v6→v4のアップグレードもある ◦ UDP, TCP, DoT, DoH/2, DoH/3 ◦ SNIあり/なし • 動作検証プログラムがほしい 33 2025-01-18 Tokyo RubyKaigi 12 RubyKaigi 2023, KoR 2024では 参加者からミスを指摘していただき……
  21. resolvのコンポーネント • class Resolv ◦ システムリゾルバの互換実装 • class Resolv::DNS ◦

    DNSクライアント(スタブリゾルバ) • class Resolv::DNS::Message ◦ DNSメッセージのデコード・エンコード 37 2025-01-18 Tokyo RubyKaigi 12 DNR DDR SVCB Do[THQ] マージしてもらった OSのAPIがあれば 呼ぶだけ 素直に実装すれば できるか? ??
  22. Do53 DoT DoH/2 DoH/3 DoQ DNS DNS DNS HTTP/2 HTTP/3

    DNS DNS DNS TLS TLS QUIC QUIC UDP TCP TCP TCP UDP UDP IPv4/IPv6 プロトコルスタック 38 2025-01-18 Tokyo RubyKaigi 12 Ruby界に不足 * 色付きが暗号化レイヤ ✔ openssl gem ✔ サードパーティ gems
  23. QUIC UDP上に複数の暗号化された信頼性のあるストリームを構築 • ストリーム: バイトの順番が守られる • 信頼性: 途中のバイトが失われない • 暗号化:

    TLSで通信経路での改竄・盗聴を防ぐ • 複数: リクエスト・レスポンスを同時的に多重化できる (UDPにはいずれもない) 40 2025-01-18 Tokyo RubyKaigi 12
  24. Ruby向けのQUICライブラリ • ngtcp2のRubyバインディングを書いている ◦ ngtcp2はCで書かれたQUIC実装 • できるだけ薄いラッパーにしたい ◦ 特に,IOは呼び出し側が管理する ▪

    Thread vs. Fiber vs. Ractor • 一方,メモリ安全な界面で切る必要がある ◦ どんなにひどいRubyスクリプトを書いても, プロセスがクラッシュしてはいけない 41 2025-01-18 Tokyo RubyKaigi 12
  25. 非同期IO + メモリ管理 • 通常のTCPプログラミングではカーネルが再送管理 ◦ カーネルの送信バッファにデータをコピーする • QUICではアプリケーションが再送管理 ◦

    ngtcp2にデータの送信を依頼してからACKが返るまで, データのメモリ上の位置を固定する必要がある 42 2025-01-18 Tokyo RubyKaigi 12
  26. Stringのメモリ位置を固定する > * 7: STR_TMPLOCK > * The pointer to

    the buffer is passed to > a system call such as read(2). > Any modification and realloc is prohibited. • rb_str_locktmp/rb_str_unlocktmp ◦ Stringのメモリ位置をロックできそう • しかし,GCがembedded stringをムーブしてしまう → rb_gc_markでマークする(🙅rb_gc_mark_movable) 44 2025-01-18 Tokyo RubyKaigi 12
  27. 関連記事 • RubyKaigi 2023でのセキュアなDNSリゾルバの運用 ― DNS-over-HTTPSとDDR (@hanazuki) ◦ https://blog.kmc.gr.jp/entry/2023/05/10/165300 •

    RubyKaigi 2023 Wi-Fi: 足回り徹底解説 (@sorah) ◦ https://techlife.cookpad.com/entry/2023/05/31/113000 • NOCの書いたコード(だいたいオープンにやっています) ◦ https://github.com/ruby-no-kai/rubykaigi-net 48 2025-01-18 Tokyo RubyKaigi 12
  28. Acknowledgement • @sorah, RubyKaigi Organizer & NOC Lead ◦ L1-L4設計,L2-L4構築,その他すべて

    • NOCチームメイトのみなさん ◦ L1構築,ブログ記事・発表資料のレビュー • RubyKaigiスポンサー各社 ◦ おかげさまで好き勝手に実験をできています 49 2025-01-18 Tokyo RubyKaigi 12