IPv6とのAPI接続

フォローアップ: API接続 IPv6 vs. IPv4 - サポート - Discourse Meta

最近、Node.js を 18 から 20 にアップグレードしたところ、アプリケーションが Discourse から API レスポンスを返さなくなりました。上記の件に関連していることに気づくまで時間がかかりました。以下のような IPv4 のみで接続することで確認しました。

import {Agent} from 'node:https'
import axios from 'axios'
import {env} from 'node:process'
export const axiosDiscourse = axios.create({
  baseURL: 'https://<discourse-url>',
  headers: {
    'api-key': env['DISCOURSE_KEY'],
    'api-username': env['DISCOURSE_USERNAME']
  },
  httpsAgent: new Agent({
    family: 4
  })
})

重要なのは HTTP Agent を指定していることです。それ以前は指定せずに使用していました。これは現在機能しますが、バンドルサイズを削減するためにフロントエンドでも使用できる Wretch のような fetch ベースのライブラリに移行しようとしていました。(主にバンドルサイズを削減するためにフロントエンドでも使用したい): elbywan/wretch: A tiny wrapper built around fetch with an intuitive syntax. :candy: (github.com)。しかし、fetch で IPv4 または IPv6 を指定するオプションはありません。そのため、次のいずれかが必要だと考えました。

  1. どうにかして IPv4 のみの使用を強制する。これまでの試みにもかかわらず、これは不可能でした。
  2. Discourse に、IPv6 でこれを機能させる方法を問い合わせる。

アプリケーションからさまざまな他の API に接続していますが、問題はありません。Discourse との接続のみが失敗しています。

参考までに、以下のようなエラーが発生しています。

Error: connect ETIMEDOUT 184.105.99.43:443
    at createConnectionError (node:net:1634:14)
    at Timeout.internalConnectMultipleTimeout (node:net:1685:38)
    at listOnTimeout (node:internal/timers:575:11)
    at processTimers (node:internal/timers:514:7) {
  errno: -110,
  code: 'ETIMEDOUT',
  syscall: 'connect',
  address: '184.105.99.43',
  port: 443
},
Error: connect ENETUNREACH 2602:fd3f:3:ff01::2b:443 - Local (:::0)
    at internalConnectMultiple (node:net:1176:40)
    at Timeout.internalConnectMultipleTimeout (node:net:1687:3)
    at listOnTimeout (node:internal/timers:575:11)
    at processTimers (node:internal/timers:514:7) {
  errno: -101,
  code: 'ENETUNREACH',
  syscall: 'connect',
  address: '2602:fd3f:3:ff01::2b',
  port: 443
}

興味深いのは、上記で言及されているスレッドとは異なり、応答が遅いのではなく、すぐにこのエラーで失敗することです。API 呼び出しはブラウザ、curl、およびテストできる他のものでは正常に機能します。

API へのリクエストの行い方は、アプリケーションからリクエストを行っている限り問題ありません。単に失敗し、上記で言及されている family オプションを使用した場合にのみ機能します。リンクされたスレッドで、次のように言及されているのを見ました。

IPv6 接続がネットワークで機能しない理由を調査する必要があります。

これには 2 つの懸念があります。

  1. 具体的にどのようにチェックすればよいかわかりません。
  2. Discourse と、私のアプリケーションでのみ問題が発生する理由がわかりません。
「いいね!」 1

もう1つ注意点として、これはWSLインスタンス内でのみ発生します。ホストのWindowsデバイスで直接アプリケーションを実行すると、正常に接続できます。

これはおそらく私のセットアップに非常に固有なものだとわかっていますが、現時点ではどこで問題を探せばよいかわかりません。何かヒントがあれば教えてください!

「いいね!」 1

お使いのライブラリは IPv4 と IPv6 の両方で接続を試みているようです。これは良い兆候であり、こちら と同じ問題ではないことを意味します!

それぞれ個別に見ていきましょう。

これは、お客様側で接続を試みるための TCP SYN を設定しましたが、応答が返ってこなかったことを意味します。一般的に、これは以下のいずれかを意味します。

  • リクエストがサーバーに到達しなかった
  • サーバー(または経路上の何か)が意図的にサイレントドロップした
  • 応答がお客様のマシンに返ってこなかった

そして、

とあることから、お客様のマシンのネットワーク設定の問題である可能性が高いです。

これは、お客様のネットワークスタックが「そこには到達できない」と判断したことを意味しており、使用しているものが明らかに IPv4 にフォールバックするため、これは問題ありません。

全体を見ると、以下のことが疑われます。

  • お客様のマシンから IPv4 が失敗する(これが真実かどうかは不明です。確認してください。「正常に接続できる」というのは、IPv4 または IPv6 のいずれかを使用していることを意味する可能性があります)
  • お客様の WSL コンテナから IPv4 が失敗する
  • お客様のマシンから IPv6 が機能する
  • お客様の WSL コンテナから IPv6 が失敗する

@team にお客様の外部 IPv4 アドレスを記載したメモをお送りください。意図的にドロップされていないか確認します。悪質な IP 範囲をブロックしている場合があり、これによりそれを除外できます。

ただし、お客様のマシンから IPv4 と IPv6 の両方が機能するのに、WSL コンテナから失敗する場合は、WSL の設定に関して解決する必要がある問題です。

ご連絡いただきありがとうございます。

疑わしい点について、これまでにテストできたことは以下の通りです。

これは、私の理解ではIPv4からの接続のみを行うはずです。もしそうであれば、それは機能しました。

  • WSLから以下を実行してみました。
 curl -4 https://<host>/latest.json?order=created

これは問題なく動作しました(応答がありました)。

  • IPv6のみをテストする方法がわかりません。上記のスクリーンショットと同様にIPv4を無効にすると(IPv6を有効にしたまま)、PCは基本的にインターネットから切断され、すべての接続が失敗しました(これは予想されることです)。

  • WSLから以下を試しました。

 curl -6 https://<host>/latest.json?order=created -v
*   Trying 2602:fd3f:3:ff01::2b:443...
* Immediate connect fail for 2602:fd3f:3:ff01::2b: Network is unreachable
* Closing connection 0
curl: (7) Couldn't connect to server

これはすぐに失敗しました。

本日WSLで問題が発生したため、クリーンインストールを構成しました。これは、asdfとNode.jsのみがインストールされ(すべてのシステムパッケージが更新済み)、完全に新しいインスタンスです。これがまだWSL側の設定ミスに関連しているかどうかはわかりません。現在はすべてのデフォルトを使用しているはずです。

言及されたグループに私のパブリックIPv4アドレスを共有しています。

まあ、まだプライベートメッセージを送信する方法が見つかりません。おそらく、私が新規ユーザーだからでしょう。

もっと面白いことが…私のパブリックIPv4アドレスを確認していたところ、ウェブサイトがIPv6アドレスも表示しようとして「IPv6が検出されませんでした」と言いました。そこで、IPv6接続があるかどうかを確認しに行ったところ、このページを見つけました:TP-Link無線ルーターでIPv6サービスを設定する方法

ルーターにはIPv6を使用するための専用セクションがあるはずだと書かれています。私のルーターにはそれがなく、そこにあるようなPPPoE v6オプションも表示されません。したがって、私のルーターはIPv6をまったくサポートしていないのかもしれません。だからこそIPv6接続が失敗しているのでしょう(そして、Windowsの設定でIPv4を無効にしたときにインターネット接続がほぼ失われた理由でもあります)。

編集:このルーターを持っています:TL-WR841N | 300Mbps Wireless N Router | TP-Link India、そしてIPv6がサポートされていると書かれています:thinking:

編集2:しかし、v6.testmyipv6.comのようなものを使用すると、ERR_NAME_NOT_RESOLVEDというエラーが表示されるので、IPv6は確かに機能していないようです。

それが問題だとしても、なぜこれが突然起こり始めたのか、まだわかりません。しばらくの間は正常に機能していました。

少しだけ後押ししておきました。 :slight_smile:@team をクリックすると、メッセージボタンが表示されるはずです。 :+1:

「いいね!」 1

ありがとうございます。送信しました!

「いいね!」 1

追加のデータポイントとして、IPv6を使用するモバイルネットワークのホットスポットに切り替えました。以下を使用して確認できます。

curl -6 https://<host>/latest.json?order=created -v
*   Trying 2602:fd3f:3:ff01::2b:443...
* Immediate connect fail for 2602:fd3f:3:ff01::2b: Network is unreachable
* Closing connection 0
curl: (7) Couldn't connect to server

同様の方法で失敗します。ただし、Windowsの設定でIPv4を無効にすると、以前とは異なりインターネットにアクセスできるようになります。新しいデータは次のとおりです。

  • WindowsのIPv4:動作します
  • WindowsのIPv6:動作します
  • WSLのIPv4:動作します
  • WSLのIPv6:失敗します

curlに-4または-6を指定しない場合、IPv4にフォールバックします(IPv6はすぐに失敗します)。

curl https://<host>/latest.json?order=created -v
*   Trying 184.105.99.43:443...
*   Trying 2602:fd3f:3:ff01::2b:443...
* Immediate connect fail for 2602:fd3f:3:ff01::2b: Network is unreachable
* Connected to <host> (184.105.99.43) port 443 (#0)

また、以下を実行しました。

ping -6 google.com

WindowsとWSLの両方から実行しました。Windowsでは動作しますが、WSLでは失敗します。WSLインスタンスのIPv6接続に何か問題が発生しているという十分な情報と検証が得られたと思います。問題のようです:cannot reach ipv6 only address · Issue #4518 · microsoft/WSL (github.com)

ついに!

上記のリンクされたディスカッションに基づいて、次を追加できました。

[experimental]
networkingMode=mirrored

.wslconfig に追加したところ、WSLインスタンス内でIPv6接続が可能になりました。これで次を実行できるようになりました。

curl -6 https://<host>/latest.json?order=created

ただし、Wi-Fiではまだ機能しません。これは、この古いルーターがIPv6をサポートしていないためである可能性が非常に高いです。スマートフォンのテザリングを使用すると正常に機能します。

ポインターをありがとう、@JammyDodger!正しい方向へ導いてくれました!

OK、元の投稿と今回の投稿の間で何かが変わったようですね。なぜなら、あなたは以下のようなエラーが出ていたからです。

今は動作しているようでよかったです。

ええ、それはまだ私を困惑させます。前にも述べたように、以前はWSL経由でcurlリクエストを送信でき、それは機能していました。なぜか、私のアプリケーションでAxiosを使用すると失敗していました(AxiosまたはNode.jsの問題かもしれません)。

なぜか、curl -4はまだ機能しており、元の投稿に示されているようにhttpFamilyを指定するとAxiosも機能します。しかし、それは私がこれ以上眠りを失うようなエラーではありません。

念のため、Node.js 18 に戻したところ、httpFamily を指定せずに接続できるようになりました。これは Node.js 19 または 20 で変更されたことは間違いありません。しかし、それのおかげで、IPv6 のことについて知ることができ、そうでなければこのことを検索したり学んだりすることはなかったでしょう。

また、Node.js の代わりに bun でコードを実行することもでき、IPv4 のことを指定する必要はありません。Node.js に連絡しました: https://github.com/orgs/nodejs/discussions/50826