mitmproxy・DevTools・Gradle:VPNの向こう側にある三つの層
loopback がトンネルに入ることはありません。症状をリスナー、信頼ストア、パケットフィルターのどれかに分類し、実際に壊れた層を修復します。
VPN は接続し、無関係な三つのツールが三通りの方法で失敗します同じ午後に。mitmproxy はリクエストを見なくなり、Chrome はデバッガーを拒否し、Gradle はBindExceptionローカルソケットをバインドする際に例外を投げます。共通の疑いがあるのは、トンネルが localhost を遮断しているというものです。それはありえません:127.0.0.1カーネル内で処理され、アダプターにすら届かず、ましてやゲートウェイには届きません。
三つの層、三つの異なる故障
クライアントで変わったのは loopback への経路ではありません。ローカルプロキシ、マシンの信頼ストア、パケットフィルターであり、それぞれが開発者の作業フローの別の部分を壊します。症状を正しい行に振り分けることが診断の大半です:
| Symptom | Layer | First check |
|---|---|---|
| Proxy sees no traffic | Local proxy or listener | ss -lntp, ornetstat -anoon Windows |
| TLS error in one tool only | Trust store | Which CA bundle does that runtime read? |
| Local bind or connect refused | Packet filter or port owner | Who holds the port, and what rule drops it? |
この種の報告はほぼすべて最後の行から始めて上へ遡りますが、それは逆です。トンネルは loopback のトラフィックを見られないことが証明できる唯一の層なので、最も疑うべきではありません。まずプロセスが何をバインドしたかを見て、次にどの証明書を信頼しているかを尋ね、その後にだけマシン上のポリシーを見てください。
トンネルではなく、リスナーから始めましょう
プロキシが127.0.0.1:8080でトラフィックを受け取らなくなったとき、起きたことは三つのうちの一つです:起動しなかった、別のポートにバインドした、フィルターが loopback 接続を落とした。リッスン中のソケットを一覧にすれば一つのコマンドで答えが出ますし、二つのツールがどちらが先かで意見を違えたときに、どのプロセスがポートを所有しているかも示します。
ルート検索でローカルアドレスが返ることは、反対側から同じことを裏づけます。ip route getを loopback 宛てに対して実行すると loopback デバイスを報告し、トンネルを報告することは決してなく、ルーティング変更を解決策として提案されたときに備えておくと役立つ一文です。
プロキシ層:環境変数は設定ではない
多くの企業クライアントは HTTP プロキシを実行し、アプリケーションがそれを使うことを期待します。HTTPS_PROXYをシェルで設定すれば、それを尊重するコマンドラインツールは直りますが、独自の設定ファイルを読むツールには何の効果もありません。Gradle、Selenium、gRPC はそれぞれ独自の設定を参照し、一つの端末で export したプロキシは IDE が起動したデーモンには見えません。
コンテナーツールは、これが可視化される典型的な場所です。コンテナーの loopback はコンテナー自身のものなので、127.0.0.1コンテナー内ではホストのプロキシを意味せず、ホストのアドレスかホストネットワークの設定が必要です。シェルでは動くのにビルドで失敗する修正は、通常この行であり、トンネルではありません。
信頼層:ツールは別のストアを読む
傍受は二つ目の変更で、最も誤解を招くエラーを生みます。クライアントは検査対象の接続に独自の証明書を提示するため、企業ルートを信頼するブラウザーは成功し、バンドルされた CA ストアを持つツールは失敗します。certifi 経由の Python requests が典型例で、OS のストアが正しくても、そのランタイムがストアを読まないためリクエストは失敗します。エラーメッセージは傍受にほとんど言及しないため、この行は壊れたエンドポイントと誤診されます。
エンドポイントが実際に提示するものと、ツールが検証したものを比較してください。openssl s_clientはサーバーが送ったチェーンを示し、ツール自身の検証出力は何を判断したかを示します。両者が食い違うとき、REQUESTS_CA_BUNDLEまたはSSL_CERT_FILEがそのランタイムのレバーであり、企業ルートはそのランタイムが読むストアに置くべきで、一部のツールしか尊重しないグローバルな場所に置くべきではありません。
SSL エラーを直すバージョン変更は、VPN ではなく信頼と暗号のポリシーに関する証拠です。SOAP クライアントを動かした Python のダウングレードは、同梱の CA ストアと既定の TLS 設定を変えたのであって、ネットワーク経路は動いていません。
フィルター層:loopback も落とせる
三つ目の変更はパケットフィルターで、一部の製品はトンネルに入らないトラフィックを落とすルールをインストールします。ローカルのリスナーも対象になりえます。それにより動作していたソケットが拒否またはタイムアウトの接続になり、結果のエラーはマシン上のポリシーではなくアプリケーションのバグに見えます。
ポートの所有権はこの層のもう半分です。BindExceptionはソケットを開けなかったという意味で、接続が拒否されるのとは別の失敗です。フィルターを責める前に、別のプロセスがすでにポートを保持していないか確認し、次にローカルのトラフィックを落とすルールを探して、製品がサポートする最も狭い許可を追加してください。同じデバッグポートを奪い合う二つのツールは、ポリシーによるブロックとまったく同じメッセージを出しますが、ファイアウォールの変更で直るのは片方だけです。
Chrome のデバッグポートも同じ仲間です。ブラウザーは起動し、ドライバーは DevTools のエンドポイントに到達できず、メッセージはネットワークではなく DevTools を名指しします。追加の起動フラグや不要なドライバーマネージャーがポートの所有者を変えるため、それらを外すと VPN が直ったように見えることがあります。
壊れた層を修復する
トンネルではなく、壊れた層を修復してください。到達できない loopback リスナーは、リスナーかポートを直す必要があり、信頼されていない証明書は、そのランタイムが見る場所に企業ルートをインストールし、例外は狭く保つ必要があります。ローカルのトラフィックを落とすフィルターは、無効化ではなく具体的な許可ルールが必要です。無効化すると、それが守っていた他のすべてまで再び開いてしまうからです。
VPN を再接続しても、これらの層はどれも検証されません。壊した変更を再実行するだけなので、同じ三つの故障が再接続のたびに戻り、クライアントを非アクティブにした再起動のたびに消えるのです。