22 * or visit www.oracle.com if you need additional information or have any |
22 * or visit www.oracle.com if you need additional information or have any |
23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package sun.net.util; |
26 package sun.net.util; |
|
27 |
|
28 import java.io.IOException; |
|
29 import java.io.UncheckedIOException; |
|
30 import java.net.Inet6Address; |
|
31 import java.net.InetAddress; |
|
32 import java.net.InetSocketAddress; |
|
33 import java.net.NetworkInterface; |
|
34 import java.net.SocketException; |
|
35 import java.security.AccessController; |
|
36 import java.security.PrivilegedExceptionAction; |
|
37 import java.security.PrivilegedActionException; |
|
38 import java.util.List; |
|
39 import java.util.concurrent.ConcurrentHashMap; |
|
40 import java.util.stream.Collectors; |
27 |
41 |
28 public class IPAddressUtil { |
42 public class IPAddressUtil { |
29 private static final int INADDR4SZ = 4; |
43 private static final int INADDR4SZ = 4; |
30 private static final int INADDR16SZ = 16; |
44 private static final int INADDR16SZ = 16; |
31 private static final int INT16SZ = 2; |
45 private static final int INT16SZ = 2; |
285 (addr[11] == (byte)0xff)) { |
299 (addr[11] == (byte)0xff)) { |
286 return true; |
300 return true; |
287 } |
301 } |
288 return false; |
302 return false; |
289 } |
303 } |
|
304 /** |
|
305 * Mapping from unscoped local Inet(6)Address to the same address |
|
306 * including the correct scope-id, determined from NetworkInterface. |
|
307 */ |
|
308 private final static ConcurrentHashMap<InetAddress,InetAddress> |
|
309 cache = new ConcurrentHashMap<>(); |
|
310 |
|
311 /** |
|
312 * Returns a scoped version of the supplied local, link-local ipv6 address |
|
313 * if that scope-id can be determined from local NetworkInterfaces. |
|
314 * If the address already has a scope-id or if the address is not local, ipv6 |
|
315 * or link local, then the original address is returned. |
|
316 * |
|
317 * @param addr |
|
318 * @exception SocketException if the given ipv6 link local address is found |
|
319 * on more than one local interface |
|
320 * @return |
|
321 */ |
|
322 public static InetAddress toScopedAddress(InetAddress address) |
|
323 throws SocketException { |
|
324 |
|
325 if (address instanceof Inet6Address && address.isLinkLocalAddress() |
|
326 && ((Inet6Address) address).getScopeId() == 0) { |
|
327 |
|
328 InetAddress cached = null; |
|
329 try { |
|
330 cached = cache.computeIfAbsent(address, k -> findScopedAddress(k)); |
|
331 } catch (UncheckedIOException e) { |
|
332 throw (SocketException)e.getCause(); |
|
333 } |
|
334 return cached != null ? cached : address; |
|
335 } else { |
|
336 return address; |
|
337 } |
|
338 } |
|
339 |
|
340 /** |
|
341 * Same as above for InetSocketAddress |
|
342 */ |
|
343 public static InetSocketAddress toScopedAddress(InetSocketAddress address) |
|
344 throws SocketException { |
|
345 InetAddress addr; |
|
346 InetAddress orig = address.getAddress(); |
|
347 if ((addr = toScopedAddress(orig)) == orig) { |
|
348 return address; |
|
349 } else { |
|
350 return new InetSocketAddress(addr, address.getPort()); |
|
351 } |
|
352 } |
|
353 |
|
354 private static InetAddress findScopedAddress(InetAddress address) { |
|
355 PrivilegedExceptionAction<List<InetAddress>> pa = () -> NetworkInterface.networkInterfaces() |
|
356 .flatMap(NetworkInterface::inetAddresses) |
|
357 .filter(a -> (a instanceof Inet6Address) |
|
358 && address.equals(a) |
|
359 && ((Inet6Address) a).getScopeId() != 0) |
|
360 .collect(Collectors.toList()); |
|
361 List<InetAddress> result; |
|
362 try { |
|
363 result = AccessController.doPrivileged(pa); |
|
364 var sz = result.size(); |
|
365 if (sz == 0) |
|
366 return null; |
|
367 if (sz > 1) |
|
368 throw new UncheckedIOException(new SocketException( |
|
369 "Duplicate link local addresses: must specify scope-id")); |
|
370 return result.get(0); |
|
371 } catch (PrivilegedActionException pae) { |
|
372 return null; |
|
373 } |
|
374 } |
290 } |
375 } |