mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 11:04:34 +02:00
8216417: cleanup of IPv6 scope-id handling
Reviewed-by: alanb, chegar, dfuchs
This commit is contained in:
parent
04ea6ae9b3
commit
247a6a2ce4
23 changed files with 761 additions and 595 deletions
|
@ -33,6 +33,7 @@ import java.util.Set;
|
|||
|
||||
import sun.net.ResourceManager;
|
||||
import sun.net.ext.ExtendedSocketOptions;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
|
@ -110,6 +111,9 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
|
|||
*/
|
||||
protected synchronized void bind(int lport, InetAddress laddr)
|
||||
throws SocketException {
|
||||
if (laddr.isLinkLocalAddress()) {
|
||||
laddr = IPAddressUtil.toScopedAddress(laddr);
|
||||
}
|
||||
bind0(lport, laddr);
|
||||
}
|
||||
|
||||
|
@ -121,7 +125,19 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
|
|||
* destination address to send the packet to.
|
||||
* @param p the packet to be sent.
|
||||
*/
|
||||
protected abstract void send(DatagramPacket p) throws IOException;
|
||||
protected void send(DatagramPacket p) throws IOException {
|
||||
InetAddress orig = p.getAddress();
|
||||
if (orig.isLinkLocalAddress()) {
|
||||
InetAddress scoped = IPAddressUtil.toScopedAddress(orig);
|
||||
if (orig != scoped) {
|
||||
p = new DatagramPacket(p.getData(), p.getOffset(),
|
||||
p.getLength(), scoped, p.getPort());
|
||||
}
|
||||
}
|
||||
send0(p);
|
||||
}
|
||||
|
||||
protected abstract void send0(DatagramPacket p) throws IOException;
|
||||
|
||||
/**
|
||||
* Connects a datagram socket to a remote destination. This associates the remote
|
||||
|
@ -131,6 +147,9 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
|
|||
* @param port the remote port number
|
||||
*/
|
||||
protected void connect(InetAddress address, int port) throws SocketException {
|
||||
if (address.isLinkLocalAddress()) {
|
||||
address = IPAddressUtil.toScopedAddress(address);
|
||||
}
|
||||
connect0(address, port);
|
||||
connectedAddress = address;
|
||||
connectedPort = port;
|
||||
|
|
|
@ -43,6 +43,7 @@ import sun.net.NetHooks;
|
|||
import sun.net.PlatformSocketImpl;
|
||||
import sun.net.ResourceManager;
|
||||
import sun.net.ext.ExtendedSocketOptions;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
import sun.net.util.SocketExceptions;
|
||||
|
||||
/**
|
||||
|
@ -157,8 +158,12 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
|
|||
boolean connected = false;
|
||||
try {
|
||||
InetAddress address = InetAddress.getByName(host);
|
||||
this.port = port;
|
||||
// recording this.address as supplied by caller before calling connect
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
if (address.isLinkLocalAddress()) {
|
||||
address = IPAddressUtil.toScopedAddress(address);
|
||||
}
|
||||
|
||||
connectToAddress(address, port, timeout);
|
||||
connected = true;
|
||||
|
@ -182,8 +187,12 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
|
|||
* @param port the specified port
|
||||
*/
|
||||
protected void connect(InetAddress address, int port) throws IOException {
|
||||
this.port = port;
|
||||
// recording this.address as supplied by caller before calling connect
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
if (address.isLinkLocalAddress()) {
|
||||
address = IPAddressUtil.toScopedAddress(address);
|
||||
}
|
||||
|
||||
try {
|
||||
connectToAddress(address, port, timeout);
|
||||
|
@ -215,10 +224,14 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
|
|||
InetSocketAddress addr = (InetSocketAddress) address;
|
||||
if (addr.isUnresolved())
|
||||
throw new UnknownHostException(addr.getHostName());
|
||||
// recording this.address as supplied by caller before calling connect
|
||||
InetAddress ia = addr.getAddress();
|
||||
this.address = ia;
|
||||
this.port = addr.getPort();
|
||||
this.address = addr.getAddress();
|
||||
|
||||
connectToAddress(this.address, port, timeout);
|
||||
if (ia.isLinkLocalAddress()) {
|
||||
ia = IPAddressUtil.toScopedAddress(ia);
|
||||
}
|
||||
connectToAddress(ia, port, timeout);
|
||||
connected = true;
|
||||
} finally {
|
||||
if (!connected) {
|
||||
|
@ -546,6 +559,9 @@ abstract class AbstractPlainSocketImpl extends SocketImpl implements PlatformSoc
|
|||
NetHooks.beforeTcpBind(fd, address, lport);
|
||||
}
|
||||
}
|
||||
if (address.isLinkLocalAddress()) {
|
||||
address = IPAddressUtil.toScopedAddress(address);
|
||||
}
|
||||
socketBind(address, lport);
|
||||
isBound = true;
|
||||
}
|
||||
|
|
|
@ -176,11 +176,6 @@ public final
|
|||
class Inet6Address extends InetAddress {
|
||||
static final int INADDRSZ = 16;
|
||||
|
||||
/*
|
||||
* cached scope_id - for link-local address use only.
|
||||
*/
|
||||
private transient int cached_scope_id; // 0
|
||||
|
||||
private class Inet6AddressHolder {
|
||||
|
||||
private Inet6AddressHolder() {
|
||||
|
|
|
@ -25,6 +25,20 @@
|
|||
|
||||
package sun.net.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class IPAddressUtil {
|
||||
private static final int INADDR4SZ = 4;
|
||||
private static final int INADDR16SZ = 16;
|
||||
|
@ -287,4 +301,75 @@ public class IPAddressUtil {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Mapping from unscoped local Inet(6)Address to the same address
|
||||
* including the correct scope-id, determined from NetworkInterface.
|
||||
*/
|
||||
private final static ConcurrentHashMap<InetAddress,InetAddress>
|
||||
cache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Returns a scoped version of the supplied local, link-local ipv6 address
|
||||
* if that scope-id can be determined from local NetworkInterfaces.
|
||||
* If the address already has a scope-id or if the address is not local, ipv6
|
||||
* or link local, then the original address is returned.
|
||||
*
|
||||
* @param addr
|
||||
* @exception SocketException if the given ipv6 link local address is found
|
||||
* on more than one local interface
|
||||
* @return
|
||||
*/
|
||||
public static InetAddress toScopedAddress(InetAddress address)
|
||||
throws SocketException {
|
||||
|
||||
if (address instanceof Inet6Address && address.isLinkLocalAddress()
|
||||
&& ((Inet6Address) address).getScopeId() == 0) {
|
||||
|
||||
InetAddress cached = null;
|
||||
try {
|
||||
cached = cache.computeIfAbsent(address, k -> findScopedAddress(k));
|
||||
} catch (UncheckedIOException e) {
|
||||
throw (SocketException)e.getCause();
|
||||
}
|
||||
return cached != null ? cached : address;
|
||||
} else {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above for InetSocketAddress
|
||||
*/
|
||||
public static InetSocketAddress toScopedAddress(InetSocketAddress address)
|
||||
throws SocketException {
|
||||
InetAddress addr;
|
||||
InetAddress orig = address.getAddress();
|
||||
if ((addr = toScopedAddress(orig)) == orig) {
|
||||
return address;
|
||||
} else {
|
||||
return new InetSocketAddress(addr, address.getPort());
|
||||
}
|
||||
}
|
||||
|
||||
private static InetAddress findScopedAddress(InetAddress address) {
|
||||
PrivilegedExceptionAction<List<InetAddress>> pa = () -> NetworkInterface.networkInterfaces()
|
||||
.flatMap(NetworkInterface::inetAddresses)
|
||||
.filter(a -> (a instanceof Inet6Address)
|
||||
&& address.equals(a)
|
||||
&& ((Inet6Address) a).getScopeId() != 0)
|
||||
.collect(Collectors.toList());
|
||||
List<InetAddress> result;
|
||||
try {
|
||||
result = AccessController.doPrivileged(pa);
|
||||
var sz = result.size();
|
||||
if (sz == 0)
|
||||
return null;
|
||||
if (sz > 1)
|
||||
throw new UncheckedIOException(new SocketException(
|
||||
"Duplicate link local addresses: must specify scope-id"));
|
||||
return result.get(0);
|
||||
} catch (PrivilegedActionException pae) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
|
||||
import sun.net.ResourceManager;
|
||||
import sun.net.ext.ExtendedSocketOptions;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
|
||||
/**
|
||||
* An implementation of DatagramChannels.
|
||||
|
@ -527,14 +528,16 @@ class DatagramChannelImpl
|
|||
} else {
|
||||
// not connected
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
InetAddress ia = isa.getAddress();
|
||||
if (sm != null) {
|
||||
InetAddress ia = isa.getAddress();
|
||||
if (ia.isMulticastAddress()) {
|
||||
sm.checkMulticast(ia);
|
||||
} else {
|
||||
sm.checkConnect(ia.getHostAddress(), isa.getPort());
|
||||
}
|
||||
}
|
||||
if (ia.isLinkLocalAddress())
|
||||
isa = IPAddressUtil.toScopedAddress(isa);
|
||||
n = send(fd, src, isa);
|
||||
if (blocking) {
|
||||
while (IOStatus.okayToRetry(n) && isOpen()) {
|
||||
|
|
|
@ -50,6 +50,7 @@ import java.security.PrivilegedAction;
|
|||
import java.util.Enumeration;
|
||||
|
||||
import sun.net.ext.ExtendedSocketOptions;
|
||||
import sun.net.util.IPAddressUtil;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
public class Net {
|
||||
|
@ -462,6 +463,9 @@ public class Net {
|
|||
{
|
||||
boolean preferIPv6 = isIPv6Available() &&
|
||||
(family != StandardProtocolFamily.INET);
|
||||
if (addr.isLinkLocalAddress()) {
|
||||
addr = IPAddressUtil.toScopedAddress(addr);
|
||||
}
|
||||
bind0(fd, preferIPv6, exclusiveBind, addr, port);
|
||||
}
|
||||
|
||||
|
@ -481,6 +485,9 @@ public class Net {
|
|||
static int connect(ProtocolFamily family, FileDescriptor fd, InetAddress remote, int remotePort)
|
||||
throws IOException
|
||||
{
|
||||
if (remote.isLinkLocalAddress()) {
|
||||
remote = IPAddressUtil.toScopedAddress(remote);
|
||||
}
|
||||
boolean preferIPv6 = isIPv6Available() &&
|
||||
(family != StandardProtocolFamily.INET);
|
||||
return connect0(preferIPv6, fd, remote, remotePort);
|
||||
|
|
|
@ -37,7 +37,6 @@ jfieldID ia6_holder6ID;
|
|||
|
||||
jfieldID ia6_ipaddressID;
|
||||
jfieldID ia6_scopeidID;
|
||||
jfieldID ia6_cachedscopeidID;
|
||||
jfieldID ia6_scopeidsetID;
|
||||
jfieldID ia6_scopeifnameID;
|
||||
jmethodID ia6_ctrID;
|
||||
|
@ -65,8 +64,6 @@ Java_java_net_Inet6Address_init(JNIEnv *env, jclass cls) {
|
|||
CHECK_NULL(ia6_ipaddressID);
|
||||
ia6_scopeidID = (*env)->GetFieldID(env, ia6h_class, "scope_id", "I");
|
||||
CHECK_NULL(ia6_scopeidID);
|
||||
ia6_cachedscopeidID = (*env)->GetFieldID(env, ia6_class, "cached_scope_id", "I");
|
||||
CHECK_NULL(ia6_cachedscopeidID);
|
||||
ia6_scopeidsetID = (*env)->GetFieldID(env, ia6h_class, "scope_id_set", "Z");
|
||||
CHECK_NULL(ia6_scopeidsetID);
|
||||
ia6_scopeifnameID = (*env)->GetFieldID(env, ia6h_class, "scope_ifname", "Ljava/net/NetworkInterface;");
|
||||
|
|
|
@ -107,7 +107,6 @@ extern jclass ia6_class;
|
|||
extern jfieldID ia6_holder6ID;
|
||||
extern jfieldID ia6_ipaddressID;
|
||||
extern jfieldID ia6_scopeidID;
|
||||
extern jfieldID ia6_cachedscopeidID;
|
||||
extern jfieldID ia6_scopeidsetID;
|
||||
extern jfieldID ia6_scopeifnameID;
|
||||
extern jmethodID ia6_ctrID;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue