Internet Protocol version 4 (IPv4) has long been the industry standard version of the Internet Protocol (IP) for delivering data over the Internet. Internet Protocol version 6 (IPv6) is the next generation Internet layer protocol. Both versions of IP are in use today. Java applications support both IPv4 and IPv6 automatically.
The most significant difference between IPv4 and IPv6 is the address size, which is only 32 bits in IPv4, but 128 bits in IPv6. See the section IPv4 and IPv6 incompatibility in The Java Tutorials for more information.
This document covers the following topics:
IPv6 in Java is transparent and automatic. Porting is not necessary; there is no need to recompile source files.
Consider the Echo Client example described in Reading from and Writing to a Socket in The Java Tutorials. The example connect to an echo server, which receives data from its client and echoes it back. You can run this example in IPv6 mode if the echo client and the echo server are running on IPv6-enabled computers.
You can run any Java applications, client or server, on an IPv6-enabled platform, and that application will automatically become IPv6-enabled.
The Java networking stack first checks whether IPv6 is supported on the underlying OS. If IPv6 is supported, it tries to use the IPv6 stack. More specifically, on dual-stack systems, it creates an IPv6 socket. On separate-stack systems things are much more complicated. The Java runtime creates two sockets, one for IPv4 and one for IPv6 communication. For client-side TCP applications, once the socket is connected, the Internet-protocol family type is fixed, and the extra socket can be closed. For server-side TCP applications, because there is no way to tell from which IP family type the next client request will come, two sockets need to be maintained. For UDP applications, both sockets are needed for the lifetime of the communication.
The Java runtime gets the IP address from a name service.
You don't need to know the following in order to use IPv6 in Java. The following sections explains what happens under various circumstances.
This is also called anylocal or wildcard address. If a socket is bound to an IPv6 anylocal address on a dual-stack machine, it can accept both IPv6 and IPv4 traffic; if it is bound to an IPv4 (IPv4-mapped) anylocal address, it can only accept IPv4 traffic. The Java runtime always tries to bind to IPv6 anylocal address on a dual-stack machine unless a related system property is set to use IPv4 Stack.
When bound to ::
, the method ServerSocket.accept accept connections from both IPv6 or IPv4 hosts. The Java
platform API currently has no way to specify to accept connections
only from IPv6 hosts.
Applications can enumerate the interfaces using NetworkInterface and bind a ServerSocketChannel to each IPv6 address, and then use a selector from the New I/O API to accept connections from these sockets.
However, there is a new socket option that changes the above behavior. Basic Socket Interface Extensions for IPv6 has introduced a new IP level socket option, IPV6_V6ONLY. This socket option restricts AF_INET6 sockets to IPv6 communications only. Normally, AF_INET6 sockets may be used for both IPv4 and IPv6 communications. Some applications may want to restrict their use of an AF_INET6 socket to IPv6 communications only. For these applications the IPV6_V6ONLY socket option is defined. When this option is turned on, the socket can be used to send and receive IPv6 packets only. By default, this option is turned off. Note that Java SE does not currently support this socket option, but it may be added in a future release
Packets with the loopback address must never be sent on a link or forwarded by an IPv6 router. There are two separate loopback addresses for IPv4 and IPv6 and they are treated as such.
IPv4 and IPv6 addresses are separate address spaces except when it comes to "::".
This address type was intended to be used for hosts and routers to dynamically tunnel IPv6 packets over IPv4 routing infrastructure but has been deprecated by the Internet Engineering Task Force (IETF).
This is an IPv6 address that is used to represent an IPv4 address. It allows the native program to use the same address data structure and also the same socket when communicating with both IPv4 and IPv6 nodes. Thus, on a dual-stack node with IPv4-mapped address support, an IPv6 application can talk to both IPv4 and IPv6 peer. The OS will do the underlying plumbing required to send or receive an IPv4 datagram and to hand it to an IPv6 destination socket, and it will synthesize an IPv4-mapped IPv6 address when needed.
For Java, it is used for internal representation; it has no functional role. Java will never return an IPv4-mapped address. It understands IPv4-mapped address syntax, both in byte array and text representation. However, it will be converted into an IPv4 address.
On dual stack machines, system properties are provided for setting the preferred protocol stack—IPv4 or IPv6—as well as the preferred address family types—inet4 or inet6.
IPv6 stack is preferred by default, since on a dual-stack machine IPv6 socket can talk to both IPv4 and IPv6 peers.
This setting can be changed through the
java.net.preferIPv4Stack=<true|false>
system
property.
By default, IPv4 addresses are preferred over IPv6 addresses, for example, when querying the name service (for instance, DNS service), IPv4 addresses would be returned ahead of IPv6 addresses. There are two reasons for this choice:
%d.%d.%d.%d
. Using an IPv4 address
minimizes the surprises.This setting can be changed through the system property
java.net.preferIPv6Addresses=<true|false>
For many years, if not forever, there will be a mix of IPv6 and IPv4 nodes on the Internet. Thus compatibility with the large installed base of IPv4 nodes is crucial for the success of the transition from IPv4 to IPv6. Dual stack, defined in RFC 1933, is one of the main mechanisms for guaranteeing a smooth transition. The other mechanism is IPv6 packet tunneling, which is relevant to the JDK only through the IPv4-compatible address. The former is the most relevant piece to the JDK. A dual stack includes implementations of both versions of the Internet Protocol, IPv4 and IPv6.
A general property of a dual-stack node is that an IPv6 socket can communicate both with an IPv4 and IPv6 peer at the transport layer (TCP or UDP) . At the native level, the IPv6 socket communicates with an IPv4 peer through an IPv4-mapped IPv6 address. However, unless a socket checks for the peers address type, it won't know whether it is talking to an IPv4 or an IPv6 peer. All the internal plumbing and conversion of address types is done by the dual-protocol stack.
Note: IPv4-mapped address has significance only at the implementation of a dual-protocol stack. It is used to fake (for example, appear in the same format as) an IPv6 address to be handed over to an IPv6 socket. At the conceptual level it has no role; its role is limited at the Java API level. Parsing of an IPv4-mapped address is supported, but an IPv4-mapped address is never returned.
(Nodes) | V4 Only | V4/V6 | V6 Only |
---|---|---|---|
V4 Only | x | x | No communication possible |
V4/V6 | x | x | x |
V6 Only | No communication possible | x | x |
The top row and left column represent various node types attempting to communicate. An x indicates that these nodes can communicate with each other.
In the following communication scenarios, either host1 or host2 can be a native application:
java.net.preferIPv4Stack (default: false)
If IPv6 is available on the operating system, the underlying native socket will be an IPv6 socket. This allows Java applications to connect to, and accept connections from, both IPv4 and IPv6 hosts.
If an application has a preference to only use IPv4 sockets, then this property can be set to true. The implication is that the application will not be able to communicate with IPv6 hosts.
java.net.preferIPv6Addresses (default: false)
If IPv6 is available on the operating system, the default
preference is to prefer an IPv4-mapped address over an IPv6
address. This is for backward compatibility reasons—for example,
applications that depend on access to an IPv4-only service, or
applications that depend on the %d.%d.%d.%d
representation of an IP
address.
This property can be set to try to change the preferences to use
IPv6 addresses over IPv4 addresses. This allows applications to be
tested and deployed in environments where the application is
expected to connect to IPv6 services.
sun.net.spi.nameservice.provider.<n>=<default|dns,sun|...>
Specifies the name service provider that you can use. By
default, the Java runtime will use the system-configured, name-lookup
mechanism, such as file or Network Information Service (NIS). You can specify your own by
setting this option. <n>
takes the value of a
positive number and it indicates the precedence order: a small
number takes higher precedence over a bigger number. One DNS name service provider is provided through JNDI, which is
called dns,sun
.
sun.net.spi.nameservice.nameservers=<server1_ipaddr,server2_ipaddr
...>
You can specify a comma separated list of IP addresses that point to the DNS servers you want to use.
sun.net.spi.nameservice.domain=<domainname>
This property specifies the default DNS domain name, for example,
eng.example.com
.