ネットワーク IPv6 ユーザガイド (J2SDK/JRE 1.4)


このドキュメントでは、次のトピックについて説明します。

概要

J2SDK/JRE 1.4 リリースでは、Java ネットワークに IPv6 サポートが追加されました。 そのため、J2SE は、以下の規格 (RFC) に準拠しています。

J2SDK は raw ソケットをポートしていないため、このリリースでは RFC 2292 (IPv6 用の拡張ソケット API) はサポートされません。

IPv6 のその他の興味深い機能 (トンネリング、アドレスの自動構成、モバイル IP など) は、Java API のレベルではサポートされていません。それらの機能は、基本となる OS またはシステムサポートによって自動的に処理されます。

サポートされるオペレーティングシステム

このリリースでは、次のオペレーティングシステムがサポートされます。

Linux に関する注

  1. Linux カーネル 2.4.0 以降のリリースを使用することをお勧めします。IPv6 のサポートが改善されています。
  2. Linux では、IPv6 が有効なカーネルをインストールするか、IPv6 オプションを有効にしてカーネルを再構築する必要があります。 カーネル 2.4.2 までは、IPv6 の実装には「試験的」というマークが付いていました。 また、いくつかのネットワークユーティリティをインストールする必要があります。 詳細は、http://www.bieringer.de/linux/IPv6/IPv6-HOWTO/IPv6-HOWTO.html を参照してください。

Windows に関する注

J2SETM 1.4 は、Microsoft Windows 上では IPv6 をサポートしていません。 Micorosoft は IPv6 Technology Preview for Windows 2000 をリリースしましたが、別個のスタックを実装した限定的なものに過ぎません。 Microsoft Windows 用の完全なデュアル IPv4/IPv6 スタックの実装は、2002 年かそれ以降までリリースされない見込みです。

特殊な IPv6 アドレス型

未指定アドレス (:: IPv4 の 0.0.0.0 に対応)

これは「エニーローカル (anylocal)」または「ワイルドカード」アドレスとも呼ばれます。 ソケットがデュアルスタックのマシン上の IPv6 エニーローカルアドレスにバインドされている場合、そのソケットは、IPv6 トラフィックと IPv4 トラフィックの両方を受け入れることができます。ソケットが IPv4 (IPv4 マップ) エニーローカルアドレスにバインドされている場合、そのソケットは IPv4 トラフィックだけを受け入れることができます。 デュアルスタックのマシン上では、関連するシステムプロパティで IPv4 スタックの指定が設定されていない限り、IPv6 エニーローカルアドレスにバインドすることが試みられます。

:: にバインドされているとき、メソッド ServerSocket.accept は、IPv6 ホストと IPv4 ホストの両方からの接続を受け入れます。 現在の Java プラットフォーム API では、IPv6 ホストからの接続だけを受け入れるように指定する方法はありません。

アプリケーションでは、NetworkInterface を使用してインタフェースを列挙し、各 IPv6 アドレスに ServerSocketChannel をバインドして、New I/O API からのセレクタを使用してそれらのソケットからの接続を受け入れることができます。

注: このあと説明するオプションは、Draft-ietf-ipngwg-rfc2553bis-03.txt で導入されています。 それが標準規格になった時点で、そのオプションが Java 2 プラットフォームでサポートされる予定です。

ただし、前述の動作を変更する、新しいソケットオプションがあります。 Draft-ietf-ipngwg-rfc2553bis-03.txt では、新しい IP レベルのソケットオプションとして、IPV6_V6ONLY が導入されました。 このソケットオプションは、AF_INET6 ソケットを IPv6 通信だけに限定します。 通常、AF_INET6 ソケットは、IPv4 および IPv6 の両方の通信のために使用できます。 アプリケーションによっては、AF_INET6 ソケットの使用を IPv6 通信だけに限定したい場合があります。 そのようなアプリケーションでは、IPV6_V6ONLY ソケットオプションを定義します。 このオプションをオンに設定すると、IPv6 パケットだけを送受信するためにそのソケットを使用できます。 デフォルトでは、このオプションはオフになっています。

ループバックアドレス (::1 IPv4 の 127.0.0.1 に対応)

ループバックアドレスを指定されたパケットは、決してリンク上に送信したり、IPv6 ルータによって転送したりしないでください。 IPv4 と IPv6 には 2 つの異なるループバックアドレスがあり、それぞれ別個に処理されます。

IPv4 と IPv6 のアドレスは、「::」の場合を除いて、別々のアドレス空間を占めます。

互換アドレス (::w.x.y.z)

このアドレスは、ホストおよびルータが、IPv6 パケットを IPv4 ルーティングインフラストラクチャ上を動的にトンネルするために使用されます。 このアドレスは、OS カーネルとルータに対して意味を持ちます。 Java では、このアドレスをテストするためのユーティリティメソッドが提供されています。

IPv4 マップアドレス (::ffff:w.x.y.z)

これは、IPv4 アドレスを表現するために使用される IPv6 アドレスです。 このアドレスを利用すると、ネイティブプログラムでは、IPv4 ノードと IPv6 ノードの両方と通信する際に、同じアドレスデータ構造と、さらには同じソケットを使用できます。 このため、IPv4 マップアドレスをサポートするデュアルスタックノード上では、IPv6 アプリケーションは IPv4 ピアと IPv6 ピアの両方と通信できます。 IPv4 のデータグラムを送受信するのに必要な基本となる諸処理は OS が実行して、その結果を IPv6 の宛先ソケットに渡します。また、OS は、必要なときに IPv4 マップ IPv6 アドレスを合成します。

Java では、このアドレスは内部の表現に使用され、機能上の役割はありません。 Java から IPv4 マップアドレスが返されることはありません。 Java では、IPv4 マップアドレスの構文が、バイト配列とテキスト表現の両方で理解されます。 ただし、そのアドレスは IPv4 アドレスに変換されます。

IPv6 関連のシステムプロパティ

デュアルスタックマシンでは、優先されるプロトコルスタック (IPv4 または IPv6) と、優先されるアドレスファミリの型 (inet4 または inet6) を設定するためのシステムプロパティが提供されます。

デフォルトでは、IPv6 スタックが優先されます。デュアルスタックマシンでは、IPv6 ソケットが IPv4 ピアと IPv6 ピアの両方と通信できるためです。

この設定を変更するには、java.net.preferIPv4Stack=<true|false> システムプロパティを使用します。

アドレスのデフォルトについては、IPv6 アドレスよりも IPv4 アドレスをお勧めします。ネームサービス (DNS サービスなど) に照会すると、IPv6 アドレスではなく IPv4 アドレスが返されます。 この選択には、次の 2 つの理由があります。

  1. 一部のアプリケーションでは、IPv4 アドレスのテキスト形式 (%d.%d.%d.%d) が想定されている。 IPv4 アドレスを使用すれば、予期しない動作を最小限にできる
  2. IPv4 アドレスを使用すれば、1 つの呼び出し (IPv6 ソケットを使う) で、旧来の IPv4 だけのサービスと、IPv6 サービスのどちらにも到達できる (IPv6 サービスが IPv6 だけのノード上にない場合)

この設定を変更するには、java.net.preferIPv6Addresses=<true|false> システムプロパティを使用します。

デュアルスタックノード

このさき何年もの間 (永久にではないとしても)、インターネットは IPv6 ノードと IPv4 ノードが混在した状態になるでしょう。 このため、IPv4 ノードの大規模なインストールベースとの互換性が、IPv4 から IPv6 への移行を成功させるために重要です。 デュアルスタック (RFC 1933 で定義されている) は、円滑な移行を保証するための主要な機構の 1 つです。 もう 1 つの機構は IPv6 パケットのトンネリングですが、この機構と J2SDK との関連性は IPv4 互換アドレスに関係するものだけです。 前者の機構は、J2SDK ともっとも関連性があります。 デュアルスタックには、IPv4 と IPv6 の両方のバージョンのインターネットプロトコルを実装することが含まれます。

デュアルスタックノードの一般的な特性は、IPv6 ソケットが IPv4 ピアおよび IPv6 ピアの両方とトランスポート層 (TCP または UDP) で通信できるということです。 ネイティブレベルでは、IPv6 ソケットは、IPv4 マップ IPv6 アドレスを使って IPv4 と通信します。 ただし、ソケットがピアのアドレス型を調べない限り、IPv4 ピアまたは IPv6 ピアのどちらと通信しているかをソケットが認識することはありません。 アドレス型に関係した内部の処理と変換はすべて、デュアルプロトコルスタックによって実行されます。

注: IPv4 マップアドレスは、デュアルプロトコルスタックの実装においてだけ意味を持ちます。 IPv4 マップアドレスは、IPv6 アドレスを「模倣」して (IPv6 と同じ形式になるようにして)、アドレスを IPv6 ソケットに渡せるようにするために使用されます。 概念上のレベルでは特に役割がなく、その役割は Java API のレベルに限定されています。 IPv4 マップアドレスの解析はサポートされていますが、IPv4 マップアドレスが返されることはありません。

Java アプリケーションへの影響

  1. すべてが適切に記述されていれば、Java アプリケーションコードに変更は必要ない。 つまり、IPv4 のリテラルアドレスを直接に参照するのではなく、ホスト名を使用していればよい
  2. アドレスやソケットの型に関する情報はすべて、Java ネットワーク API にカプセル化されている
  3. システムプロパティを設定することで、優先されるアドレスやソケットの型を設定できる
  4. 新規アプリケーションでは、IPv6 に固有の新しいクラスおよび API を利用できる

通信のシナリオ

(ノード) V4 のみ V4/V6 V6 のみ
V4 のみ x x  
V4/V6 x x x
V6 のみ   x x

いちばん上の行と左端の列は、通信しようとするノードの種類を表します。 「x」は、それらのノードが互いに通信できることを示します。

UDP
シナリオ 1:

host1 または host2 のどちらかは、ネイティブアプリケーションにできます。

host1 がサーバ、host2 がクライアント

host2 から host1 に通信しようとするとき、host2 は V6 ソケットを作成します。 次に、host2 は host1 の IP アドレスを検索します。 host1 は V4 プロトコルスタックだけしか持っていないため、名前検索サービスにも IPv4 のレコードしかありません。 そのため、hots2 は IPv4 マップアドレスを使って host1 に到達しようとします。 host2 からは IPv4 パケットが送信されてくるので、host1 は、自身が V4 クライアントと通信しているものと認識します。

host1 がクライアント、host2 がサーバ

host2 がサーバの場合、host2 はまず V6 型のソケット (これがデフォルト) を作成して、接続を待機します。 host1 は V4 だけしかサポートしていないため、host1 は V4 型のソケットを作成します。 両者は、host2 の名前を解決します。 host1 は、IPv6 アドレスを認識しないため、host2 の V4 アドレスだけを取得します。 そのため、host1 は V4 アドレスを使って host2 に接続します。 そして、V4 パケットが回線上に送信されます。 host2 では、デュアルスタックによって V4 パケットが V6 パケット (V4 マップアドレスを持つ) に変換され、V6 ソケットに渡されます。 サーバアプリケーションは、それが V6 ノードからの接続であるかのようにしてパケットを処理します。

クラスの変更

InetAddress

このクラスは、IP アドレスを表します。 そして、アドレスの格納場所、名前とアドレスを変換するメソッド、アドレスを変換するメソッド、およびアドレスをテストするメソッドを提供します。 J2SE 1.4 では、IPv4 アドレスと IPv6 アドレスの両方をサポートするようにこのクラスが拡張されました。 また、アドレス型とスコープをチェックするユーティリティメソッドが追加されました。 IPv4 と IPv6 という 2 つの型のアドレスは、Java 型の Inet4Address および Inet6Address によって区別できます。

InetAddress の新しいサブクラスとして、Inet4Address および Inet6Address の 2 つのクラスが作成されました。 この 2 つのサブクラスには、V4 および V6 に固有の状態と動作が実装されています。 Java のオブジェクト指向の性質のため、アプリケーションは通常、InetAddress クラスを取り扱うだけで済みます。多相性によって、正しい動作を得ることができるためです。 各プロトコルファミリに固有の動作にアクセスする必要がある場合 (たとえば、IPv6 専用のメソッドを呼び出す場合や、IP アドレスのクラス型を知る必要がある場合) に限り、アプリケーションは Inet4AddressInet6Address を区別することになります。

導入された新しいメソッドは次のとおりです。

InetAddress:
isAnyLocalAddress
isLoopbackAddress
isLinkLocalAddress
isSiteLocalAddress
isMCGlobal
isMCNodeLocal
isMCLinkLocal
isMCSiteLocal
isMCOrgLocal
getCanonicalHostName
getByAddr

Inet6Address:
isIPv4CompatibleAddress

InetAddress および異なるネームサービス

1.4 より前では、InetAddress は、システムに構成されたネームサービスを利用してホスト名を解決していました。 1.4 では、代わりになる名前検索手段として、JNDI を介した Java DNS プロバイダが追加されました。 いくつかのシステムプロパティを設定すれば、このプロバイダを使用するように J2SDK に命令することができます。 これらのシステムプロパティについては、Java システムプロパティの項に説明があります。 将来的には、開発者が独自のネームサービスプロバイダを記述できるようにするため、汎用的なサービスプロバイダのフレームワークを提供する予定です。

直列化について

すべての IPv4 アドレスは、Java では Inet4Address オブジェクトとして表現されます。 そのオブジェクトは InetAddress オブジェクトとして直列化され、下位互換性を保つために、InetAddress からは Inet4Address に直列化復元されます。 IPv6 アドレスは Inet6Address として表現され、同様に直列化されます。

SocketServerSocket、および DatagramSocket

Java のオブジェクト指向の性質のため、アドレスの種類と情報を格納している構造体は、ソケット API のレベルでは公開されません。そのため、新しい API は不要です。 既存のソケット API により、IPv4 トラフィックと IPv6 トラフィックの両方が扱われます。

どちらのスタックが使用されるかの選択は、次の基準によります。

  1. 基本となる OS サポート
  2. 優先するスタックに関するプロパティをユーザがどのように設定したか

サポートされるすべての IPv6 ソケットオプションには、対応する IPv4 オプションがあります。 したがって、IPv6 ソケットオプションをサポートするための新しい API は追加されていません。 その代わりに、古い API が、V4 と V6 の両方のソケットオプションをサポートするようにオーバーロードされました。

MulticastSocket

このソケットの場合も、ソケットオプションのすべての API が、IPv6 のマルチキャストソケットオプションをサポートするようにオーバーロードされました。

ネットワークインタフェースを設定および取得するための新しい 2 つの API が追加されました。これは、InetAddress インスタンスを設定および取得する既存の MulticastSocket.setInterface および MulticastSocket.getInterface とは別に追加されたものです。 2 つの既存のメソッドは、マルチキャストパケットを送信するための現在の MulticastSocket で使用されているネットワークインタフェースを設定または取得するために使用されます。 IPv4 の場合、インタフェースは IP アドレスによって示されていました。 そのため、Java では、それと等価の InetAddress を使用できます。 この 2 つのメソッドは、IPv6 のマルチキャストソケットに対しても引き続き機能します。 ただし、IPv6 では、RFC 2553 の仕様によると、インタフェースはインタフェースインデックスを使って示す必要があります。 ネットワークインタフェースの概念をより適切にサポートするため、新しいクラスとして NetworkInterface が導入されました。 このクラスは、ネットワークインタフェースの状態を表すデータをカプセル化します。名前や IP アドレスなどのデータと、いくつかの基本操作を実行するメソッドが組み込まれています。 これに伴い、マルチキャストソケットの送出インタフェースを設定するための新しい 2 つのメソッドとして、setNetworkInterfacegetNetworkInterface が導入されました。 この 2 つのメソッドは、NetworkInterface オブジェクトを引数にとり、戻り値として返します。 新しいメソッドは、V4 と V6 の両方のマルチキャストで使用できます。

さらに、ネットワークインタフェース上のマルチキャストグループに参加したり、そこから抜けたりするためのメソッドも追加されました。 これは、以前の Java API では利用できませんでした。

MulticastSocket:
NetworkInterface getNetworkInterface()
setNetworkInterface(NetworkInterface netIf)
joinGroup(SocketAddress mcastaddr,NetworkInterface netIf)
leaveGroup(SocketAddress mcastaddr,NetworkInterface netIf)

URLURI パーサ

URL や URI では、リテラル IP アドレスを使用できます。 ただし、既存の URL および URI の仕様では、ホストとポートを区切るためにコロン (:) が使用されているため、現状のままで URL または URI にリテラルの IPv6 表現を使用すると、解析に失敗します。 このため、URL や URI にリテラルの IPv6 アドレスを指定するために、RFC 2732 が作成されました。 URL と URI の解析処理は、RFC 2732 に準拠するように更新されました。

SocketPermission

SocketPermission は URL を利用するので、RFC 2732 に準拠するように実装が更新されました。

アクセス権を定義するのに使用される codebase は、URL を変形したものです。 したがって、codebase も、URL の形式と規定に従う必要があります。 URL と codebase の場合は RFC 2732 形式が使用され、その他の場合には RFC 2373 形式が使用されます。

IPv6 のネットワークプロパティ

java.net.preferIPv4Stack (デフォルト: false)

IPv6 を利用可能なオペレーティングシステムでは、基本となるネイティブソケットは IPv6 ソケットです。 このため、Java(TM) アプリケーションは、IPv4 ホストと IPv6 ホストの両方に接続したり、その両方のホストからの接続を受け入れたりできます。

IPv4 ソケットだけを使用するよう設定されているアプリケーションでは、このプロパティを true に設定できます。 つまり、そのアプリケーションは IPv6 ホストと通信できないということです。

java.net.preferIPv6Addresses (デフォルト: false)

IPv6 を利用可能なオペレーティングシステムでは、デフォルトの設定として、IPv4 マップのアドレスを IPv6 アドレスよりも優先するようになっています。 これは、下位互換性の理由によります。たとえば、IPv4 だけのサービスへのアクセスに依存するアプリケーションや、%d.%d.%d.%d の形式で表現された IP アドレスに依存するアプリケーションとの互換性のためです。
IPv6 アドレスを IPv4 アドレスよりも優先する設定を試してみるには、このプロパティを true に設定します。 そうすれば、アプリケーションが IPv6 サービスに接続されると予想される環境でアプリケーションをテストし、そのような環境にアプリケーションを配置することができます。

JNDI DNS サービスプロバイダの設定:

sun.net.spi.nameservice.provider.<n>=<default|dns,sun|...>

使用できるネームサービスプロバイダを指定します。 デフォルトでは、Java は、システムに構成された名前検索機構を使用します (file、nis など)。 このオプションを設定すると、独自の名前サービスプロバイダを指定できます。 <n> には、正の数値を指定します。この数値は優先順位を示しており、小さい値ほど優先順位が高くなります。 1.4 では、JNDI を使用して 1 つの DNS ネームサービスプロバイダが提供されており、その名前は dns,sun です。

sun.net.spi.nameservice.nameservers=<server1_ipaddr,server2_ipaddr ...>

使用する DNS サーバを指す IP アドレスを、コンマで区切ったリストとして指定できます。

sun.net.spi.nameservice.domain=<domainname>

このプロパティでは、デフォルトの DNS ドメイン名 (たとえば、eng.sun.com) を指定します。