2020年10月31日土曜日

Javaでデュアルスタック環境のときIPv6通信させるには

最近、Java(JDK11)環境でHTTP通信しているときに気が付いたのだが、Javaアプリケーションの通信の多くはIPv4で通信している。IPv6対応のサービスに接続してもIPv4通信している。Javaのドキュメントを見ると、IPv6対応をうたっており、通信できないわけではない。
実際、IPv6のアドレスを直接打って通信させると問題なくIPv6で通信する。
IPv6が使われない理由は、Javaのデフォルト設定だとIPv4とIPv6の両方対応している場合、IPv4を優先して利用するようになっているためである。

IPv4とIPv6の両方対応しているとはどういうことなのか?
ここからはJava固有の話ではなく、インターネット通信全般の話になる。

そもそも、IPv6とIPv4は全く互換性がなく相互通信できない。つまり、IPv4のネットワークとIPv6のネットワークは完全に分離されており別物である。したがって、IPの世界で両方対応するということは不可能である。

そのため、両方対応するにはDNSのデュアルスタックという技術が一般的に利用されている。

DNSの仕様で、IPv4のアドレス解決はAレコード、IPv6のアドレス解決はAAAAレコードを登録することになっている。IPv4/IPv6デュアルスタックとは、同じホスト名に両方のレコードを登録することである。

IPv4ネットワークに接続している端末からは、DNSでAのクエリを発行し、IPv4アドレスに変換する。IPv4アドレスが判明するので、IPv4ネットワークでサーバーに接続しに行く。
IPv6の場合も同様で、IPv6ネットワークに接続している端末から、DNSでAAAAのクエリを発行し、IPv6アドレスに変換する。IPv6アドレスが判明するので、IPv6ネットワークでサーバーに接続しに行く。
つまり、IPv6とIPv4の両方に接続している端末が、最初にAレコードとAAAAレコードのどっちを投げるのかで、IPv4/IPv6のどっちのネットワークに接続するかが決まる。
サーバー側は、IPv4とIPv6で別のサーバーを用意してもいいし、1台で両方のネットワークに接続してもよい。両方のネットワークにサーバーを用意して、DNS設定さえすればいい。

やっと、本題。JavaでIPv4とIPv6どっちを優先するかの設定は、以下のJVMプロパティによって切り替えることになっている。
java.net.preferIPv6Addresses
JVMプロパティなのでこのリクエストはIPv6といったことはできず、アプリケーション単位での切り替えとなる。

JVMプロパティの切り替えは、起動オプションで「-Djava.net.preferIPv6Addresses=true」をつけるか、mainメソッドの最初で以下のコードを実行する。

System.setProperty("java.net.preferIPv6Addresses", "true");

近年はIPv6の普及も進んできているので、基本的に上記の設定を行うことをお勧めする。

0 件のコメント:

コメントを投稿