--- old/src/java.base/share/classes/sun/net/util/IPAddressUtil.java 2019-05-17 12:07:36.931649172 +0100 +++ new/src/java.base/share/classes/sun/net/util/IPAddressUtil.java 2019-05-17 12:07:36.643649182 +0100 @@ -25,6 +25,15 @@ package sun.net.util; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + public class IPAddressUtil { private static final int INADDR4SZ = 4; private static final int INADDR16SZ = 16; @@ -287,4 +296,57 @@ } return false; } + + /** Returns a scopeId suitable for binding, or -1 if none */ + public static int bindingScopeId(InetAddress address) { + if (!(address instanceof Inet6Address)) + return -1; + + Inet6Address ia6 = (Inet6Address)address; + if (ia6.getScopeId() != 0) { // explicit scopeId + return ia6.getScopeId(); + } + + int scopeId = -1; + if (ia6.isLinkLocalAddress()) { + scopeId = IPAddressUtil.scopeFromLocalAddress(ia6); + } + + //TODO: if macOS default interface stuff + + return scopeId; + } + + private static Map localAddressScopeIdMap = new ConcurrentHashMap<>(); + + private static int scopeFromLocalAddress(Inet6Address addr) { + assert addr.isLinkLocalAddress() : addr; + + int scopeId = privilegedLookupScopeId(addr); + if (scopeId == -1) + return -1; + int cur = localAddressScopeIdMap.putIfAbsent(addr, scopeId); + assert cur == scopeId; + return scopeId; + } + + private static int privilegedLookupScopeId(Inet6Address ia6) { + PrivilegedAction pa = () -> lookupScopeID(ia6); + return AccessController.doPrivileged(pa); + } + + private static int lookupScopeID(Inet6Address ia6) { + try { + return NetworkInterface.networkInterfaces() + .filter(nif -> nif.inetAddresses() + .filter(addr -> addr.equals(ia6)) + .findFirst().isPresent()) + .findFirst() + .map(NetworkInterface::getIndex) + .orElse(-1); + } catch (SocketException ignore) { + // ignore, handle as not found + } + return -1; + } }