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