IPv6 Winsock アプリケーションのDual-Stack ソケット

Service Pack 1 (SP1) と Windows Server 2003 の Windows XP で IPv4 と IPv6 の両方をサポートするには、アプリケーションで 2 つのソケット (IPv4 で使用するソケットと IPv6 で使用するソケット) を作成する必要があります。 これら 2 つのソケットは、アプリケーションで個別に処理する必要があります。

Windows Vista 以降では、IPv6 と IPv4 の両方のトラフィックを処理できる単一の IPv6 ソケットを作成する機能が提供されます。 たとえば、IPv6 用の TCP リッスン ソケットが作成され、デュアル スタック モードになり、ポート 5001 にバインドされます。 このデュアルスタック ソケットは、ポート 5001 に接続している IPv6 TCP クライアントと、ポート 5001 に接続している IPv4 TCP クライアントからの接続を受け入れます。 この機能により、アプリケーション設計が大幅に簡素化され、2 つの別個のソケットに操作を投稿するために必要なリソース オーバーヘッドが削減されます。

Dual-Stack ソケットの作成

既定では、Windows Vista 以降で作成された IPv6 ソケットは、IPv6 プロトコル経由でのみ動作します。 IPv6 ソケットをデュアル スタック ソケットにするためには、ソケットが IP アドレスにバインドされる前に、 setockopt 関数を IPV6_V6ONLY ソケット オプションと共に呼び出して、この値を 0 に設定する必要があります。 IPV6_V6ONLY ソケット オプションを 0 に設定すると、AF_INET6 アドレス ファミリ用に作成されたソケットを使用して、IPv6 アドレスまたは IPv4 マップド アドレスとの間でパケットを送受信できます。

Dual-Stack ソケットを使用した IP アドレス

デュアルスタック ソケットでは、常に IPv6 アドレスが必要です。 IPv4 アドレスを操作するには、IPv4 にマップされた IPv6 アドレス形式を使用する必要があります。 IPv4 アドレスは、IPv4 マップされた IPv6 アドレス形式で表す必要があります。これにより、IPv6 のみのアプリケーションが IPv4 ノードと通信できるようになります。 IPv4 マップ IPv6 アドレス形式を使用すると、IPv4 ノードの IPv4 アドレスを IPv6 アドレスとして表すことができます。 IPv4 アドレスは IPv6 アドレスの下位 32 ビットにエンコードされ、上位 96 ビットは固定プレフィックス 0:0:0:0:0:0:FFFF を保持します。 IPv4 マップ IPv6 アドレス形式は RFC 4291 で指定されています。 詳細については、 www.ietf.org/rfc/rfc4291.txtを参照してください。 Mstcpip.h の IN6ADDR_SETV4MAPPED マクロを使用して、IPv4 アドレスを必要な IPv4 マップ IPv6 アドレス形式に変換できます。

基になるプロトコルが実際に IPv4 である場合、IPv4 アドレスは IPv4 マップされた IPv6 アドレス形式にマップされます。 つまり、 SOCKADDR 構造体のファミリ フィールドはAF_INET6を示しますが、IPv4 マップされた IPv6 アドレスは IPv6 アドレス構造でエンコードされます。 リッスン モードのデュアル スタック ソケットの場合は、受け入れられた IPv4 接続が IPv4 マップされた IPv6 アドレスを返します。 IPv4 宛先に接続しているデュアル スタック ソケットの場合、接続に渡される SOCKADDR 構造体は IPv4 マップされた IPv6 アドレスである必要があります。 アプリケーションでは、これらの IPv4 マップ IPv6 アドレスを適切に処理し、デュアル スタック ソケットでのみ使用するように注意する必要があります。 IP アドレスを通常の IPv4 ソケットに渡す場合、アドレスは IPv4 マップ IPv6 アドレスではなく通常の IPv4 アドレスである必要があります。

Dual-Stack ソケットの使用に関する潜在的な問題

アプリケーションの潜在的な落とし穴は、デュアルスタック ソケットで IPv4 マップされた IPv6 アドレスを取得し、返された IP アドレスを別の IPv6 のみのソケットで使用しようとすることです。 たとえば、 getsockname 関数または getpeername 関数は、デュアルスタック ソケットで使用すると、IPv4 マップされた IPv6 アドレスを返すことができます。 返された IPv4 マップ IPv6 アドレスが、その後、デュアルスタック (ソケット作成時の既定の動作である IPv6 専用ソケット) に設定されていない別のソケットで使用された場合、IPv4 マップ IPv6 アドレスを持つこの IPv6 のみのソケットの使用は失敗します。 IPv4 マップされた IPv6 アドレス形式は、デュアルスタック ソケットでのみ使用できます。

デュアルスタック・データグラム・ソケットで、アプリケーションが IPv4 経由で受信したデータグラムの WSAMSG 構造体内のパケット情報を戻すためにLPFN_WSARECVMSG (WSARecvMsg) 関数を必要とする場合は、ソケットIP_PKTINFOソケット・オプションを true に設定する必要があります。 ソケットで IPV6_PKTINFO オプションのみが true に設定されている場合、IPv6 経由で受信したデータグラムに対してパケット情報が提供されますが、IPv4 経由で受信したデータグラムには提供されない場合があります。

アプリケーションがデュアルスタック・データグラム・ソケットで IP_PKTINFO ソケット・オプションを設定しようとして、システムで IPv4 が使用不可になっている場合、 setsockopt 関数は失敗し、 WSAGetLastErrorWSAEINVAL のエラーで戻ります。 この同じエラーは、他のエラーの結果として setsockopt 関数によっても返されます。 アプリケーションがデュアル スタック ソケットでIPPROTO_IP レベルのソケット オプションを設定しようとして WSAEINVAL で失敗した場合、アプリケーションはローカル コンピューターで IPv4 が無効になっているかどうかを判断する必要があります。 IPv4 が有効または無効になっているかどうかを検出するために使用できる方法の 1 つは、af パラメーターを AF_INET に設定してソケット関数を呼び出して IPv4 ソケットを作成することです。 ソケット関数が失敗し、WSAGetLastError からWSAEAFNOSUPPORT のエラーが返された場合は、IPv4 が有効になっていないことになります。 この場合、IP_PKTINFO ソケット オプションを設定しようとしたときに setsockopt 関数が失敗した場合は、アプリケーションで無視できます。 それ以外の場合は、IP_PKTINFO ソケット オプションを設定しようとしたときにエラーが予期しないエラーとして扱われる必要があります。

WSASendMsg 関数を使用してデータグラムを送信するときに、アプリケーションが使用する特定のローカル IP ソース アドレスを指定する場合のデュアル スタック ソケットの場合、これを処理するメソッドは宛先 IP アドレスによって異なります。 IPv4 宛先アドレスまたは IPv4 マップト IPv6 宛先アドレスに送信する場合、lpMsg パラメーターが指す WSAMSG 構造体で渡される制御データ・オブジェクトの 1 つに、送信に使用するローカル IPv4 ソース・アドレスを含むin_pktinfo構造が含まれている必要があります。 IPv4 マップ IPv6 アドレスではない IPv6 宛先アドレスに送信する場合、lpMsg パラメーターによって指される WSAMSG 構造体で渡される制御データ・オブジェクトの 1 つに、送信に使用するローカル IPv6 ソース・アドレスを含むin6_pktinfo構造体が含まれている必要があります。

Windows ソケット アプリケーションの IPv6 ガイド

IPv6 Winsock アプリケーションのデータ構造の変更

IPv6 Winsock アプリケーションの関数呼び出し

ハードコードされた IPv4 アドレスの使用

IPv6 Winsock アプリケーションのユーザー インターフェイスに関する問題

IPv6 Winsock アプリケーションの基になるプロトコル

getpeername

getsockname

in_pktinfo

in6_pktinfo

IP_PKTINFO

IPV6_PKTINFO

setsockopt

LPFN_WSARECVMSG (WSARecvMsg)

WSASendMsg