1 ポイント 投稿者 GN⁺ 2024-09-18 | 2件のコメント | WhatsAppで共有
  • Little Snitch 6.1でDNS暗号化が一部の状況で失敗する可能性があったが、macOS全体の問題ではなく当該バージョンの問題に絞り込まれ、6.1.1で修正済み
  • 正常に動作するには、macOSのDNSリクエストがLittle SnitchのDNSプロキシに渡され、プロキシが暗号化された問い合わせを実行する必要がある
  • 調査中、一部の低レベルのレガシーAPIリクエストがプロキシに到達せず、システムのデフォルトネームサーバーへ暗号化されていないUDP 53の問い合わせを送る現象が観測された
  • 再現方法は、Little SnitchでDNS暗号化をオンにし、Wiresharkをport 53フィルタで実行したうえで、Xcode playgroundからgetaddrinfo("dnsproxytest.com")を呼び出すというもの
  • SafariやChromeのような高レベルAPIベースの問い合わせは当初影響がないように見え、Firefoxは影響を受けるように見えたが、最終的な範囲はLittle Snitch 6.1のDNSプロキシの問題として整理された

Little Snitch 6.1で発生したDNS暗号化の失敗

  • Little Snitch 6のDNS暗号化機能は、ホスト名の問い合わせをLittle Snitchへルーティングし、暗号化された形式で処理する
  • そのためにLittle SnitchはDNSプロキシを登録し、macOSはすべてのDNSリクエストをそのプロキシへ送る必要がある
  • 一部のDNSリクエスト、特に特定の低レベルのレガシーAPI経由のリクエストが、プロキシで受信されない現象が見つかった
  • そのリクエストはシステムのデフォルトネームサーバーへ暗号化されていない形式で送信される可能性があり、WiresharkではUDPポート53のトラフィックとして確認できた
  • Little Snitch Network Monitorには当該問い合わせトラフィックは表示されず、問い合わせがネットワークフィルタを完全に迂回していたためである

再現手順とアップデートの経緯

  • 再現手順

    • Little Snitchの設定でDNS encryptionを有効にする
    • Wiresharkport 53キャプチャフィルタで実行する
    • Xcode playgroundでgetaddrinfoを使ってdnsproxytest.comの問い合わせを実行する
    • dnsproxytest.comの問い合わせがUDP 53で暗号化されていない形式として見える場合がある
  • 当初の影響範囲

    • 高レベルAPI経由のDNS問い合わせは影響を受けないように見えた
    • SafariとChromeのWebブラウジングは、暗号化された問い合わせのメリットを維持しているように見えた
    • Firefoxは影響を受けるように見えた
  • 更新履歴

    • 2024-09-17 19:10: この問題がmacOS 14.5 Sonomaから存在していた可能性が確認され、より古い14.xシステムはテストできなかった
    • 2024-09-18 12:05: macOSの一般的なDNSプロキシ問題ではなく、Little Snitch 6.1のDNSプロキシのみに影響する問題として整理された
    • 2024-09-18 15:52: 問題はLittle Snitch 6.1.1で修正された

2件のコメント

 
GN⁺ 2024-09-18
Hacker Newsの意見
  • getaddrinfo() が「低レベルのレガシーAPI」と扱われているのは、少し奇妙に感じる
    macOSでは状況が大きく違うのかもしれないが、Linuxやおそらく *BSD では名前解決に使う標準的な方法
    macOSアプリの多くはDNSクエリにFoundationやNetworkKit系のフレームワークを使うのだろうが、その内部が最終的に getaddrinfo() のような呼び出しに降りて処理していないという点も意外
    GAIはブロッキングなので、おそらく別の低レベルな非同期呼び出しがあるのだと思う

    • その通り。CFNetworkはオープンソースなので実装を確認できるし、以前見たときは getaddrinfo_async のような変種を使っていた記憶がある
      ただしAppleは、エンドユーザーがgetaddrinfoやCFが公開する非同期の変種でIPを直接解決し、そのIPに対して connect() するやり方を望んでいない
      全体としてホスト名で接続するよう誘導されており、そうすることでAppleが内部的にHappy Eyeballsの実装を処理できる
      Appleがgetaddrinfo()モデルを好まない理由は https://www.ietf.org/proceedings/72/slides/plenaryw-6.pdf で見られる。各スライドの下に発表者ノートもある
    • getaddrinfo() がレガシーと見なされているとは思わない。そのブログ記事はこの部分を誤って書いているように思う
      「低レベル」かどうかは見方によって変わる
    • getaddrinfo() はLinuxに関するものではなく、単にglibcの関数
      人々はglibcがLinuxユーザー空間の標準的な方法だと仮定しがちだが、必ずしもそうである必要はない
      例えばsystemdは独自のresolved機構を作り、glibc側よりはるかに優れていることが分かった
      自分もLinux向けのスタンドアロンソフトウェアを作っているので、いずれ自分で似たようなものを作る可能性が高い
    • OpenBSDでは、少なくともgetaddrinfo/gethostbynameのような伝統的・標準的なDNS関数はすべて、Eric Faurotが書いたOpenBSD libc asr実装のラッパー
      https://man.openbsd.org/man3/asr_run.3
      https://github.com/openbsd/src/tree/master/lib/libc/asr
    • このケースが正確にそうなのかは分からないが、同じ名前のシステム関数でも *Linux/BSD/macOS の間で内部実装が大きく異なることがある
      *BSD同士でも違いがある
      あるシステムでは1つの関数呼び出しが長年維持されて「定石」でも、別のシステムでは実際には古くて役に立たないことがある
  • ここで扱われている問題はmacOS全般の問題ではなく、Little Snitch 6.1だけに該当するものだと判明しており、本日遅くにLittle Snitchのアップデートで修正される予定

    • タイトルもこの内容を反映するように更新できるとよさそう
  • 追加調査の結果、このバグは少なくとも macOS 14.5 Sonoma からすでに存在していた
    もしかするとそれ以前からかもしれないが、現在テストできるさらに古い14.xシステムにはアクセスできないとのこと

    • getaddrinfoで実際に動作していたかテストしたことがあるのか気になる
      それともCFNetworkで一度動くのを見て終わりにし、その後壊れたというブログ記事を投稿したのか分からない
    • 開発者がテストのために古いOSバージョンを別途保存しておかなければならない状況は、いまだに納得できない
      Appleがダウングレードを許可できない技術的理由はほぼゼロに近い
    • 製品を販売中で、新しいOSが昨日出たばかりだという点を考えると、これもかなりひどい話
  • Sequoiaでは、macOSファイアウォールが有効で、アプリが「外部からの接続をブロック」として登録されていると、そのアプリがDNSを使う能力、おそらくUDPベースの機能全般も壊してしまう
    https://waclaw.blog/macos-firewall-blocking-web-browsing-aft...

    • 再現しない。一部ではESETに関連していると言われている: https://www.reddit.com/r/MacOS/comments/1fievr5/updating_mad...
    • Sequoia以前は、VPNでOpenDNSを使っていてもVPNに接続したままiMessageや他のアプリが動作し続けていたが、Sequoia以降はVPN接続中にiMessageのテキストメッセージなどが動作しなくなった
      VPNを切断するとすべて通る
      これと関係があるのか気になる。macOSファイアウォールは有効だが、すべての外部からの接続をブロックしているわけではない
    • Sequoiaにアップグレードした後、SafariやMozillaでブラウズできなかった
      Wi-Fi接続のDNS設定に入り、Google DNSサーバーである 8.8.8.88.8.4.4 を追加したら解決し、以前自動入力されていたDNSサーバーを置き換えた
    • 正直、この挙動は問題ないと思う。アプリケーションが設定で指定されたものの外で独自にDNSを解決すべきではない
      アプリがこうする理由は、ユーザーがテレメトリのようなものをブロックできないようにするため
      自分のコンピュータなのだから、何が外へ出ていくかの最終決定権は自分にあるべき
  • タイトルは、これが意図的であるか、Apple に特権的に適用されているかのように示唆しているが、実際には単なる バグ に近いように見える
    こうした内容を報告したというなら、FB 番号 と報告の詳細も一緒に載せてくれるとよい

    • 悪魔の代弁者の立場から言えば、反発を避けるために、わざとこう作って、直さないバグのように見せかけることもできる
      目的さえ達成できるなら、実装方法はいくらでも柔軟にできる
    • 意図的だったなら、おそらくハードコードされ暗号化された URL になっていたはず
      一部のデバイスは、広告ブロックを回避するために、すでにそうした方式を使い始めている
  • 勘違いかもしれないが、iOS や Mac の新リリースのたびに DNS 問題が起き、Little SnitchMullvad のようなものに影響するというデジャヴがある
    事実なら、Apple が数か月にわたる開発者・ベータテストの間に何をしているのか、本当に疑問だ

  • Little Snitch への言及が紛らわしかったが、さらに読んでみると、特定の場合にだけ動作する LS のバグ のように見える
    これが LS のブログだとすれば、なぜ macOS のバグのように描写されているのかだけが疑問だ
    間違っているという意味ではなく、彼らの領域であって自分の領域ではないが、本文だけでは十分に正当化されていないように見える

    • OS が DNS プロキシ登録 を許可しておきながら、一部の呼び出しがそのプロキシを迂回するなら、それは明らかに OS のバグだ
  • Apple がサードパーティ開発者に対して、特定の ネットワーク API の使用を非推奨にしていたと記憶している
    しかし Apple 自身のアプリ、たとえば App Store は同じ制限を受けない
    そのため、新しい API でアプリファイアウォール経由のネットワークトラフィックをフィルタリングしようとすると、App Store がレガシー API を使っているせいで失敗していた
    以前修正されたと思っていた古いバグの一部かもしれない

    • getaddrinfo() はレガシー API ではなく、DNS ルックアップのための 標準的なクロスプラットフォーム API
  • 「新 OS リリースでバグ発見!訂正:実はかなり前からあったバグでした!」みたいな発表はいつも面白い

  • ローカルのスタブリゾルバとして routedns [0] を使い、どのリクエストをどこへ送り、どの転送方式を使うかを自分で選んでいる
    ブロックリスト、リライト、キャッシュ、負荷分散、代替リクエスト処理も可能で、かなり制御できる
    ローカルリクエストには localhost:53 のスタブリスナーを使い、ほとんどのリクエストはキャッシュ付きで UDP QUIC、つまり TLS 0-RTT により Cloudflare 1.1.1.1 へ転送している
    速く、かなり安全だ
    [0] https://github.com/folbricht/routedns

 
nearfall 2024-09-18

重要な情報をありがとうございます。
ひとまずSafariとChromeは安心できるとのことで、よかったです。