8344220: Remove calls to SecurityManager and doPrivileged in java.net.InetAddress and sun.net.util.IPAddressUtil after JEP 486 integration

Reviewed-by: jpai, dfuchs, alanb
This commit is contained in:
Aleksei Efimov 2024-11-27 19:25:50 +00:00
parent 9527586923
commit 880f9a7b16
6 changed files with 87 additions and 297 deletions

View File

@ -28,8 +28,6 @@ package java.net;
import java.net.spi.InetAddressResolver; import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolverProvider; import java.net.spi.InetAddressResolverProvider;
import java.net.spi.InetAddressResolver.LookupPolicy; import java.net.spi.InetAddressResolver.LookupPolicy;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List; import java.util.List;
import java.util.NavigableSet; import java.util.NavigableSet;
import java.util.ArrayList; import java.util.ArrayList;
@ -62,7 +60,6 @@ import jdk.internal.misc.Blocker;
import jdk.internal.misc.VM; import jdk.internal.misc.VM;
import jdk.internal.vm.annotation.Stable; import jdk.internal.vm.annotation.Stable;
import sun.net.ResolverProviderConfiguration; import sun.net.ResolverProviderConfiguration;
import sun.security.action.*;
import sun.net.InetAddressCachePolicy; import sun.net.InetAddressCachePolicy;
import sun.net.util.IPAddressUtil; import sun.net.util.IPAddressUtil;
import sun.nio.cs.UTF_8; import sun.nio.cs.UTF_8;
@ -364,11 +361,11 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
*/ */
static { static {
PREFER_IPV4_STACK_VALUE = PREFER_IPV4_STACK_VALUE =
GetPropertyAction.privilegedGetProperty("java.net.preferIPv4Stack"); System.getProperty("java.net.preferIPv4Stack");
PREFER_IPV6_ADDRESSES_VALUE = PREFER_IPV6_ADDRESSES_VALUE =
GetPropertyAction.privilegedGetProperty("java.net.preferIPv6Addresses"); System.getProperty("java.net.preferIPv6Addresses");
HOSTS_FILE_NAME = HOSTS_FILE_NAME =
GetPropertyAction.privilegedGetProperty("jdk.net.hosts.file"); System.getProperty("jdk.net.hosts.file");
jdk.internal.loader.BootLoader.loadLibrary("net"); jdk.internal.loader.BootLoader.loadLibrary("net");
SharedSecrets.setJavaNetInetAddressAccess( SharedSecrets.setJavaNetInetAddressAccess(
new JavaNetInetAddressAccess() { new JavaNetInetAddressAccess() {
@ -440,19 +437,9 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
// Native method to check if IPv6 is available // Native method to check if IPv6 is available
private static native boolean isIPv6Supported(); private static native boolean isIPv6Supported();
/**
* The {@code RuntimePermission("inetAddressResolverProvider")} is
* necessary to subclass and instantiate the {@code InetAddressResolverProvider}
* class, as well as to obtain resolver from an instance of that class,
* and it is also required to obtain the operating system name resolution configurations.
*/
private static final RuntimePermission INET_ADDRESS_RESOLVER_PERMISSION =
new RuntimePermission("inetAddressResolverProvider");
private static final ReentrantLock RESOLVER_LOCK = new ReentrantLock(); private static final ReentrantLock RESOLVER_LOCK = new ReentrantLock();
private static volatile InetAddressResolver bootstrapResolver; private static volatile InetAddressResolver bootstrapResolver;
@SuppressWarnings("removal")
private static InetAddressResolver resolver() { private static InetAddressResolver resolver() {
InetAddressResolver cns = resolver; InetAddressResolver cns = resolver;
if (cns != null) { if (cns != null) {
@ -476,10 +463,6 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
if (HOSTS_FILE_NAME != null) { if (HOSTS_FILE_NAME != null) {
// The default resolver service is already host file resolver // The default resolver service is already host file resolver
cns = BUILTIN_RESOLVER; cns = BUILTIN_RESOLVER;
} else if (System.getSecurityManager() != null) {
PrivilegedAction<InetAddressResolver> pa = InetAddress::loadResolver;
cns = AccessController.doPrivileged(
pa, null, INET_ADDRESS_RESOLVER_PERMISSION);
} else { } else {
cns = loadResolver(); cns = loadResolver();
} }
@ -737,25 +720,8 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
* @see InetAddress#getCanonicalHostName * @see InetAddress#getCanonicalHostName
*/ */
public String getHostName() { public String getHostName() {
return getHostName(true);
}
/**
* Returns the hostname for this address.
* If the host is equal to null, then this address refers to any
* of the local machine's available network addresses.
* this is package private so SocketPermission can make calls into
* here without a security check.
*
* @return the host name for this IP address, or if the operation
* is not allowed by the security check, the textual
* representation of the IP address.
*
* @param check make security check if true
*/
String getHostName(boolean check) {
if (holder().getHostName() == null) { if (holder().getHostName() == null) {
holder().hostName = InetAddress.getHostFromNameService(this, check); holder().hostName = InetAddress.getHostFromNameService(this);
} }
return holder().getHostName(); return holder().getHostName();
} }
@ -782,45 +748,31 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
String value = canonicalHostName; String value = canonicalHostName;
if (value == null) if (value == null)
canonicalHostName = value = canonicalHostName = value =
InetAddress.getHostFromNameService(this, true); InetAddress.getHostFromNameService(this);
return value; return value;
} }
/** /**
* Returns the fully qualified domain name for the given address. * Returns the fully qualified domain name for the given address.
* *
* @param check make security check if true
*
* @return the fully qualified domain name for the given IP address. * @return the fully qualified domain name for the given IP address.
* If either the operation is not allowed by the security check * If the system-wide resolver wasn't able to determine the
* or the system-wide resolver wasn't able to determine the
* fully qualified domain name for the IP address, the textual * fully qualified domain name for the IP address, the textual
* representation of the IP address is returned instead. * representation of the IP address is returned instead.
*/ */
private static String getHostFromNameService(InetAddress addr, boolean check) { private static String getHostFromNameService(InetAddress addr) {
String host; String host;
var resolver = resolver(); var resolver = resolver();
try { try {
// first lookup the hostname // first lookup the hostname
host = resolver.lookupByAddress(addr.getAddress()); host = resolver.lookupByAddress(addr.getAddress());
/* check to see if calling code is allowed to know
* the hostname for this IP address, ie, connect to the host
*/
if (check) {
@SuppressWarnings("removal")
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkConnect(host, -1);
}
}
/* now get all the IP addresses for this hostname, /* now get all the IP addresses for this hostname,
* and make sure one of them matches the original IP * and make sure one of them matches the original IP
* address. We do this to try and prevent spoofing. * address. We do this to try and prevent spoofing.
*/ */
InetAddress[] arr = InetAddress.getAllByName0(host, check); InetAddress[] arr = InetAddress.getAllByName0(host);
boolean ok = false; boolean ok = false;
if (arr != null) { if (arr != null) {
@ -1613,7 +1565,7 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
// and ends with square brackets, but we got something else. // and ends with square brackets, but we got something else.
throw invalidIPv6LiteralException(host, true); throw invalidIPv6LiteralException(host, true);
} }
return getAllByName0(host, true, true); return getAllByName0(host, true);
} }
private static UnknownHostException invalidIPv6LiteralException(String host, boolean wrapInBrackets) { private static UnknownHostException invalidIPv6LiteralException(String host, boolean wrapInBrackets) {
@ -1639,9 +1591,8 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
/** /**
* package private so SocketPermission can call it * package private so SocketPermission can call it
*/ */
static InetAddress[] getAllByName0 (String host, boolean check) static InetAddress[] getAllByName0(String host) throws UnknownHostException {
throws UnknownHostException { return getAllByName0(host, true);
return getAllByName0(host, check, true);
} }
/** /**
@ -1682,30 +1633,16 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
* Designated lookup method. * Designated lookup method.
* *
* @param host host name to look up * @param host host name to look up
* @param check perform security check
* @param useCache use cached value if not expired else always * @param useCache use cached value if not expired else always
* perform name service lookup (and cache the result) * perform name service lookup (and cache the result)
* @return array of InetAddress(es) * @return array of InetAddress(es)
* @throws UnknownHostException if host name is not found * @throws UnknownHostException if host name is not found
*/ */
private static InetAddress[] getAllByName0(String host, private static InetAddress[] getAllByName0(String host,
boolean check,
boolean useCache) boolean useCache)
throws UnknownHostException { throws UnknownHostException {
/* If it gets here it is presumed to be a hostname */ /* If it gets here it is presumed to be a hostname */
/* make sure the connection to the host is allowed, before we
* give out a hostname
*/
if (check) {
@SuppressWarnings("removal")
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkConnect(host, -1);
}
}
// remove expired addresses from cache - expirySet keeps them ordered // remove expired addresses from cache - expirySet keeps them ordered
// by expiry time so we only need to iterate the prefix of the NavigableSet... // by expiry time so we only need to iterate the prefix of the NavigableSet...
long now = System.nanoTime(); long now = System.nanoTime();
@ -1822,48 +1759,33 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In
* @see java.net.InetAddress#getByName(java.lang.String) * @see java.net.InetAddress#getByName(java.lang.String)
*/ */
public static InetAddress getLocalHost() throws UnknownHostException { public static InetAddress getLocalHost() throws UnknownHostException {
// is cached data still valid?
@SuppressWarnings("removal") CachedLocalHost clh = cachedLocalHost;
SecurityManager security = System.getSecurityManager(); if (clh != null && (clh.expiryTime - System.nanoTime()) >= 0L) {
try { return clh.addr;
// is cached data still valid?
CachedLocalHost clh = cachedLocalHost;
if (clh != null && (clh.expiryTime - System.nanoTime()) >= 0L) {
if (security != null) {
security.checkConnect(clh.host, -1);
}
return clh.addr;
}
String local = impl.getLocalHostName();
if (security != null) {
security.checkConnect(local, -1);
}
InetAddress localAddr;
if (local.equals("localhost")) {
// shortcut for "localhost" host name
localAddr = impl.loopbackAddress();
} else {
// call getAllByName0 without security checks and
// without using cached data
try {
localAddr = getAllByName0(local, false, false)[0];
} catch (UnknownHostException uhe) {
// Rethrow with a more informative error message.
UnknownHostException uhe2 =
new UnknownHostException(local + ": " +
uhe.getMessage());
uhe2.initCause(uhe);
throw uhe2;
}
}
cachedLocalHost = new CachedLocalHost(local, localAddr);
return localAddr;
} catch (java.lang.SecurityException e) {
return impl.loopbackAddress();
} }
String local = impl.getLocalHostName();
InetAddress localAddr;
if (local.equals("localhost")) {
// shortcut for "localhost" host name
localAddr = impl.loopbackAddress();
} else {
// call getAllByName0 without using cached data
try {
localAddr = getAllByName0(local, false)[0];
} catch (UnknownHostException uhe) {
// Rethrow with a more informative error message.
UnknownHostException uhe2 =
new UnknownHostException(local + ": " +
uhe.getMessage());
uhe2.initCause(uhe);
throw uhe2;
}
}
cachedLocalHost = new CachedLocalHost(local, localAddr);
return localAddr;
} }
/** /**

View File

@ -30,10 +30,8 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.ObjectStreamField; import java.io.ObjectStreamField;
import java.io.Serializable; import java.io.Serializable;
import java.security.AccessController;
import java.security.Permission; import java.security.Permission;
import java.security.PermissionCollection; import java.security.PermissionCollection;
import java.security.PrivilegedAction;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Locale; import java.util.Locale;
@ -638,10 +636,10 @@ public final class SocketPermission extends Permission
// we have to do this check, otherwise we might not // we have to do this check, otherwise we might not
// get the fully qualified domain name // get the fully qualified domain name
if (init_with_ip) { if (init_with_ip) {
cname = addresses[0].getHostName(false).toLowerCase(Locale.ROOT); cname = addresses[0].getHostName().toLowerCase(Locale.ROOT);
} else { } else {
cname = InetAddress.getByName(addresses[0].getHostAddress()). cname = InetAddress.getByName(addresses[0].getHostAddress()).
getHostName(false).toLowerCase(Locale.ROOT); getHostName().toLowerCase(Locale.ROOT);
} }
} catch (UnknownHostException uhe) { } catch (UnknownHostException uhe) {
invalid = true; invalid = true;
@ -705,7 +703,7 @@ public final class SocketPermission extends Permission
// Following check seems unnecessary // Following check seems unnecessary
// auth = InetAddress.getAllByName0(authHost, false)[0]; // auth = InetAddress.getAllByName0(authHost, false)[0];
authHost = hostname + '.' + authHost; authHost = hostname + '.' + authHost;
auth = InetAddress.getAllByName0(authHost, false)[0]; auth = InetAddress.getAllByName0(authHost)[0];
if (auth.equals(InetAddress.getByAddress(addr))) { if (auth.equals(InetAddress.getByAddress(addr))) {
return true; return true;
} }
@ -736,9 +734,8 @@ public final class SocketPermission extends Permission
sb.append('.'); sb.append('.');
} }
authHost = "auth." + sb.toString() + "IP6.ARPA"; authHost = "auth." + sb.toString() + "IP6.ARPA";
//auth = InetAddress.getAllByName0(authHost, false)[0];
authHost = hostname + '.' + authHost; authHost = hostname + '.' + authHost;
auth = InetAddress.getAllByName0(authHost, false)[0]; auth = InetAddress.getAllByName0(authHost)[0];
if (auth.equals(InetAddress.getByAddress(addr))) if (auth.equals(InetAddress.getByAddress(addr)))
return true; return true;
Debug debug = getDebug(); Debug debug = getDebug();
@ -780,7 +777,7 @@ public final class SocketPermission extends Permission
} }
addresses = addresses =
new InetAddress[] {InetAddress.getAllByName0(host, false)[0]}; new InetAddress[] {InetAddress.getAllByName0(host)[0]};
} catch (UnknownHostException uhe) { } catch (UnknownHostException uhe) {
invalid = true; invalid = true;
@ -1191,23 +1188,15 @@ public final class SocketPermission extends Permission
* Check the system/security property for the ephemeral port range * Check the system/security property for the ephemeral port range
* for this system. The suffix is either "high" or "low" * for this system. The suffix is either "high" or "low"
*/ */
@SuppressWarnings("removal")
private static int initEphemeralPorts(String suffix) { private static int initEphemeralPorts(String suffix) {
return AccessController.doPrivileged( int val = Integer.getInteger(
new PrivilegedAction<>(){ "jdk.net.ephemeralPortRange." + suffix, -1);
public Integer run() { if (val != -1) {
int val = Integer.getInteger( return val;
"jdk.net.ephemeralPortRange."+suffix, -1 } else {
); return suffix.equals("low") ?
if (val != -1) { PortConfig.getLower() : PortConfig.getUpper();
return val; }
} else {
return suffix.equals("low") ?
PortConfig.getLower() : PortConfig.getUpper();
}
}
}
);
} }
/** /**

View File

@ -279,8 +279,7 @@ tuning on how the cache is operating.</P>
name lookups will be kept in the cache. A value of -1, or any other name lookups will be kept in the cache. A value of -1, or any other
negative value for that matter, indicates a &ldquo;cache forever&rdquo; negative value for that matter, indicates a &ldquo;cache forever&rdquo;
policy, while a value of 0 (zero) means no caching. The default value policy, while a value of 0 (zero) means no caching. The default value
is -1 (forever) if a security manager is installed, and implementation-specific is implementation-specific.</P>
when no security manager is installed.</P>
<LI><P><B>{@code networkaddress.cache.stale.ttl}</B> (default: see below)<BR> <LI><P><B>{@code networkaddress.cache.stale.ttl}</B> (default: see below)<BR>
Value is an integer corresponding to the number of seconds that stale names Value is an integer corresponding to the number of seconds that stale names
will be kept in the cache. A name is considered stale if the TTL has expired will be kept in the cache. A name is considered stale if the TTL has expired

View File

@ -98,15 +98,6 @@ public abstract class InetAddressResolverProvider {
*/ */
public abstract String name(); public abstract String name();
/**
* The {@code RuntimePermission("inetAddressResolverProvider")} is
* necessary to subclass and instantiate the {@code InetAddressResolverProvider} class,
* as well as to obtain resolver from an instance of that class,
* and it is also required to obtain the operating system name resolution configurations.
*/
private static final RuntimePermission INET_ADDRESS_RESOLVER_PERMISSION =
new RuntimePermission("inetAddressResolverProvider");
/** /**
* Creates a new instance of {@code InetAddressResolverProvider}. * Creates a new instance of {@code InetAddressResolverProvider}.
* *
@ -116,19 +107,6 @@ public abstract class InetAddressResolverProvider {
* service provider. * service provider.
*/ */
protected InetAddressResolverProvider() { protected InetAddressResolverProvider() {
this(checkPermission());
}
private InetAddressResolverProvider(Void unused) {
}
@SuppressWarnings("removal")
private static Void checkPermission() {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(INET_ADDRESS_RESOLVER_PERMISSION);
}
return null;
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,11 +25,8 @@
package sun.net; package sun.net;
import java.security.PrivilegedAction;
import java.security.Security; import java.security.Security;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("removal")
public final class InetAddressCachePolicy { public final class InetAddressCachePolicy {
// Controls the cache policy for successful lookups only // Controls the cache policy for successful lookups only
@ -60,11 +57,9 @@ public final class InetAddressCachePolicy {
* -1: caching forever * -1: caching forever
* any positive value: the number of seconds to cache an address for * any positive value: the number of seconds to cache an address for
* *
* default value is forever (FOREVER), as we let the platform do the * default value is 30 seconds
* caching. For security reasons, this caching is made forever when
* a security manager is set.
*/ */
private static volatile int cachePolicy = FOREVER; private static volatile int cachePolicy = DEFAULT_POSITIVE;
/* The Java-level namelookup cache stale policy: /* The Java-level namelookup cache stale policy:
* *
@ -85,40 +80,22 @@ public final class InetAddressCachePolicy {
*/ */
private static volatile int negativeCachePolicy = NEVER; private static volatile int negativeCachePolicy = NEVER;
/*
* Whether or not the cache policy for successful lookups was set
* using a property (cmd line).
*/
private static boolean propertySet;
/*
* Whether or not the cache policy for negative lookups was set
* using a property (cmd line).
*/
private static boolean propertyNegativeSet;
/* /*
* Initialize * Initialize
*/ */
static { static {
/* If the cache policy property is not specified
* then the default positive cache value is used.
*/
Integer tmp = getProperty(cachePolicyProp, cachePolicyPropFallback); Integer tmp = getProperty(cachePolicyProp, cachePolicyPropFallback);
if (tmp != null) { if (tmp != null) {
cachePolicy = tmp < 0 ? FOREVER : tmp; cachePolicy = tmp < 0 ? FOREVER : tmp;
propertySet = true;
} else {
/* No properties defined for positive caching. If there is no
* security manager then use the default positive cache value.
*/
if (System.getSecurityManager() == null) {
cachePolicy = DEFAULT_POSITIVE;
}
} }
tmp = getProperty(negativeCachePolicyProp, tmp = getProperty(negativeCachePolicyProp,
negativeCachePolicyPropFallback); negativeCachePolicyPropFallback);
if (tmp != null) { if (tmp != null) {
negativeCachePolicy = tmp < 0 ? FOREVER : tmp; negativeCachePolicy = tmp < 0 ? FOREVER : tmp;
propertyNegativeSet = true;
} }
if (cachePolicy > 0) { if (cachePolicy > 0) {
tmp = getProperty(cacheStalePolicyProp, tmp = getProperty(cacheStalePolicyProp,
@ -130,33 +107,25 @@ public final class InetAddressCachePolicy {
} }
private static Integer getProperty(String cachePolicyProp, private static Integer getProperty(String cachePolicyProp,
String cachePolicyPropFallback) String cachePolicyPropFallback) {
{ try {
return java.security.AccessController.doPrivileged( String tmpString = Security.getProperty(cachePolicyProp);
new PrivilegedAction<Integer>() { if (tmpString != null) {
public Integer run() { return Integer.valueOf(tmpString);
try { }
String tmpString = Security.getProperty( } catch (NumberFormatException ignored) {
cachePolicyProp); // Ignore
if (tmpString != null) { }
return Integer.valueOf(tmpString);
}
} catch (NumberFormatException ignored) {
// Ignore
}
try { try {
String tmpString = System.getProperty( String tmpString = System.getProperty(cachePolicyPropFallback);
cachePolicyPropFallback); if (tmpString != null) {
if (tmpString != null) { return Integer.decode(tmpString);
return Integer.decode(tmpString); }
} } catch (NumberFormatException ignored) {
} catch (NumberFormatException ignored) { // Ignore
// Ignore }
} return null;
return null;
}
});
} }
public static int get() { public static int get() {
@ -170,63 +139,4 @@ public final class InetAddressCachePolicy {
public static int getNegative() { public static int getNegative() {
return negativeCachePolicy; return negativeCachePolicy;
} }
/**
* Sets the cache policy for successful lookups if the user has not
* already specified a cache policy for it using a
* command-property.
* @param newPolicy the value in seconds for how long the lookup
* should be cached
*/
public static synchronized void setIfNotSet(int newPolicy) {
/*
* When setting the new value we may want to signal that the
* cache should be flushed, though this doesn't seem strictly
* necessary.
*/
if (!propertySet) {
checkValue(newPolicy, cachePolicy);
cachePolicy = newPolicy;
}
}
/**
* Sets the cache policy for negative lookups if the user has not
* already specified a cache policy for it using a
* command-property.
* @param newPolicy the value in seconds for how long the lookup
* should be cached
*/
public static void setNegativeIfNotSet(int newPolicy) {
/*
* When setting the new value we may want to signal that the
* cache should be flushed, though this doesn't seem strictly
* necessary.
*/
if (!propertyNegativeSet) {
// Negative caching does not seem to have any security
// implications.
// checkValue(newPolicy, negativeCachePolicy);
// but we should normalize negative policy
negativeCachePolicy = newPolicy < 0 ? FOREVER : newPolicy;
}
}
private static void checkValue(int newPolicy, int oldPolicy) {
/*
* If malicious code gets a hold of this method, prevent
* setting the cache policy to something laxer or some
* invalid negative value.
*/
if (newPolicy == FOREVER)
return;
if ((oldPolicy == FOREVER) ||
(newPolicy < oldPolicy) ||
(newPolicy < FOREVER)) {
throw new
SecurityException("can't make InetAddress cache more lax");
}
}
} }

View File

@ -25,8 +25,6 @@
package sun.net.util; package sun.net.util;
import sun.security.action.GetPropertyAction;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.net.Inet6Address; import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
@ -35,9 +33,6 @@ import java.net.NetworkInterface;
import java.net.SocketException; import java.net.SocketException;
import java.net.URL; import java.net.URL;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -396,25 +391,23 @@ public class IPAddressUtil {
} }
} }
@SuppressWarnings("removal")
private static InetAddress findScopedAddress(InetAddress address) { 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)
.toList();
List<InetAddress> result;
try { try {
result = AccessController.doPrivileged(pa); List<InetAddress> result = NetworkInterface.networkInterfaces()
.flatMap(NetworkInterface::inetAddresses)
.filter(a -> (a instanceof Inet6Address)
&& address.equals(a)
&& ((Inet6Address) a).getScopeId() != 0)
.toList();
var sz = result.size(); var sz = result.size();
if (sz == 0) if (sz == 0)
return null; return null;
if (sz > 1) if (sz > 1)
throw new UncheckedIOException(new SocketException( throw new UncheckedIOException(new SocketException(
"Duplicate link local addresses: must specify scope-id")); "Duplicate link local addresses: must specify scope-id"));
return result.get(0); return result.get(0);
} catch (PrivilegedActionException pae) { } catch (SocketException socketException) {
return null; return null;
} }
} }
@ -927,8 +920,8 @@ public class IPAddressUtil {
private static final long TERMINAL_PARSE_ERROR = -2L; private static final long TERMINAL_PARSE_ERROR = -2L;
private static final String ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP = "jdk.net.allowAmbiguousIPAddressLiterals"; private static final String ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP = "jdk.net.allowAmbiguousIPAddressLiterals";
private static final boolean ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE = Boolean.valueOf( private static final boolean ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE =
GetPropertyAction.privilegedGetProperty(ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP, "false")); Boolean.getBoolean(ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP);
private static class MASKS { private static class MASKS {
private static final String DELAY_URL_PARSING_SP = "jdk.net.url.delayParsing"; private static final String DELAY_URL_PARSING_SP = "jdk.net.url.delayParsing";
private static final boolean DELAY_URL_PARSING_SP_VALUE; private static final boolean DELAY_URL_PARSING_SP_VALUE;
@ -939,8 +932,7 @@ public class IPAddressUtil {
static final long L_SCOPE_MASK; static final long L_SCOPE_MASK;
static final long H_SCOPE_MASK; static final long H_SCOPE_MASK;
static { static {
var value = GetPropertyAction.privilegedGetProperty( var value = System.getProperty(DELAY_URL_PARSING_SP, "false");
DELAY_URL_PARSING_SP, "false");
DELAY_URL_PARSING_SP_VALUE = value.isEmpty() DELAY_URL_PARSING_SP_VALUE = value.isEmpty()
|| Boolean.parseBoolean(value); || Boolean.parseBoolean(value);
if (DELAY_URL_PARSING_SP_VALUE) { if (DELAY_URL_PARSING_SP_VALUE) {