--- a/jdk/src/java.base/share/classes/java/net/InetAddress.java Sat Apr 09 20:12:13 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/InetAddress.java Mon Apr 11 03:00:50 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,8 +30,10 @@
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;
-import java.util.ServiceLoader;
+import java.util.Scanner;
import java.security.AccessController;
+import java.io.File;
+import java.io.FileNotFoundException;
import java.io.ObjectStreamException;
import java.io.ObjectStreamField;
import java.io.IOException;
@@ -49,7 +51,6 @@
import sun.security.action.*;
import sun.net.InetAddressCachePolicy;
import sun.net.util.IPAddressUtil;
-import sun.net.spi.nameservice.*;
/**
* This class represents an Internet Protocol (IP) address.
@@ -207,6 +208,7 @@
/* Specify address family preference */
static transient boolean preferIPv6Address = false;
+
static class InetAddressHolder {
/**
* Reserve the original application specified hostname.
@@ -279,7 +281,7 @@
}
/* Used to store the name service provider */
- private static List<NameService> nameServices = null;
+ private static transient NameService nameService = null;
/* Used to store the best available hostname */
private transient String canonicalHostName = null;
@@ -623,7 +625,6 @@
*/
private static String getHostFromNameService(InetAddress addr, boolean check) {
String host = null;
- for (NameService nameService : nameServices) {
try {
// first lookup the hostname
host = nameService.getHostByAddr(addr.getAddress());
@@ -657,18 +658,12 @@
host = addr.getHostAddress();
return host;
}
-
- break;
-
} catch (SecurityException e) {
host = addr.getHostAddress();
- break;
} catch (UnknownHostException e) {
host = addr.getHostAddress();
// let next provider resolve the hostname
}
- }
-
return host;
}
@@ -860,88 +855,287 @@
}
}
- static InetAddressImpl impl;
+ /**
+ * NameService provides host and address lookup service
+ *
+ * @since 9
+ */
+ private interface NameService {
+
+ /**
+ * Lookup a host mapping by name. Retrieve the IP addresses
+ * associated with a host
+ *
+ * @param host the specified hostname
+ * @return array of IP addresses for the requested host
+ * @throws UnknownHostException
+ * if no IP address for the {@code host} could be found
+ */
+ InetAddress[] lookupAllHostAddr(String host)
+ throws UnknownHostException;
- private static NameService createNSProvider(String provider) {
- if (provider == null)
- return null;
+ /**
+ * Lookup the host corresponding to the IP address provided
+ *
+ * @param addr byte array representing an IP address
+ * @return {@code String} representing the host name mapping
+ * @throws UnknownHostException
+ * if no host found for the specified IP address
+ */
+ String getHostByAddr(byte[] addr) throws UnknownHostException;
- NameService nameService = null;
- if (provider.equals("default")) {
- // initialize the default name service
- nameService = new NameService() {
+ }
+
+ /**
+ * The default NameService implementation, which delegates to the underlying
+ * OS network libraries to resolve host address mappings.
+ *
+ * @since 9
+ */
+ private static final class PlatformNameService implements NameService {
+
public InetAddress[] lookupAllHostAddr(String host)
throws UnknownHostException {
+
return impl.lookupAllHostAddr(host);
- }
- public String getHostByAddr(byte[] addr)
- throws UnknownHostException {
- return impl.getHostByAddr(addr);
+
+ }
+
+ public String getHostByAddr(byte[] addr) throws UnknownHostException {
+
+ return impl.getHostByAddr(addr);
+
+ }
+
+ }
+
+ /**
+ * The HostsFileNameService provides host address mapping
+ * by reading the entries in a hosts file, which is specified by
+ * {@code jdk.net.hosts.file} system property
+ *
+ * <p>The file format is that which corresponds with the /etc/hosts file
+ * IP Address host alias list.
+ *
+ * <p>When the file lookup is enabled it replaces the default NameService
+ * implementation
+ *
+ * @since 9
+ */
+ private static final class HostsFileNameService implements NameService {
+
+ private final String hostsFile;
+
+ public HostsFileNameService (String hostsFileName) {
+ this.hostsFile = hostsFileName;
+ }
+
+ private String addrToString(byte addr[]) {
+ String stringifiedAddress = null;
+
+ if (addr.length == Inet4Address.INADDRSZ) {
+ stringifiedAddress = Inet4Address.numericToTextFormat(addr);
+ } else { // treat as an IPV6 jobby
+ byte[] newAddr
+ = IPAddressUtil.convertFromIPv4MappedAddress(addr);
+ if (newAddr != null) {
+ stringifiedAddress = Inet4Address.numericToTextFormat(addr);
+ } else {
+ stringifiedAddress = Inet6Address.numericToTextFormat(addr);
}
- };
- } else {
- final String providerName = provider;
- try {
- nameService = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedExceptionAction<>() {
- public NameService run() {
- Iterator<NameServiceDescriptor> itr =
- ServiceLoader.load(NameServiceDescriptor.class)
- .iterator();
- while (itr.hasNext()) {
- NameServiceDescriptor nsd = itr.next();
- if (providerName.
- equalsIgnoreCase(nsd.getType()+","
- +nsd.getProviderName())) {
- try {
- return nsd.createNameService();
- } catch (Exception e) {
- e.printStackTrace();
- System.err.println(
- "Cannot create name service:"
- +providerName+": " + e);
- }
+ }
+ return stringifiedAddress;
+ }
+
+ /**
+ * Lookup the host name corresponding to the IP address provided.
+ * Search the configured host file a host name corresponding to
+ * the specified IP address.
+ *
+ * @param addr byte array representing an IP address
+ * @return {@code String} representing the host name mapping
+ * @throws UnknownHostException
+ * if no host found for the specified IP address
+ */
+ @Override
+ public String getHostByAddr(byte[] addr) throws UnknownHostException {
+ String hostEntry;
+ String host = null;
+
+ String addrString = addrToString(addr);
+ try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), "UTF-8")) {
+ while (hostsFileScanner.hasNextLine()) {
+ hostEntry = hostsFileScanner.nextLine();
+ if (!hostEntry.startsWith("#")) {
+ hostEntry = removeComments(hostEntry);
+ if (hostEntry.contains(addrString)) {
+ host = extractHost(hostEntry, addrString);
+ if (host != null) {
+ break;
+ }
+ }
+ }
+ }
+ } catch (FileNotFoundException e) {
+ throw new UnknownHostException("Unable to resolve address "
+ + addrString + " as hosts file " + hostsFile
+ + " not found ");
+ }
+
+ if ((host == null) || (host.equals("")) || (host.equals(" "))) {
+ throw new UnknownHostException("Requested address "
+ + addrString
+ + " resolves to an invalid entry in hosts file "
+ + hostsFile);
+ }
+ return host;
+ }
+
+
+ /**
+ * <p>Lookup a host mapping by name. Retrieve the IP addresses
+ * associated with a host.
+ *
+ * <p>Search the configured hosts file for the addresses assocaited with
+ * with the specified host name.
+ *
+ * @param host the specified hostname
+ * @return array of IP addresses for the requested host
+ * @throws UnknownHostException
+ * if no IP address for the {@code host} could be found
+ */
+
+ public InetAddress[] lookupAllHostAddr(String host)
+ throws UnknownHostException {
+ String hostEntry;
+ String addrStr = null;
+ InetAddress[] res = null;
+ byte addr[] = new byte[4];
+ ArrayList<InetAddress> inetAddresses = null;
+
+ // lookup the file and create a list InetAddress for the specfied host
+ try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), "UTF-8")) {
+ while (hostsFileScanner.hasNextLine()) {
+ hostEntry = hostsFileScanner.nextLine();
+ if (!hostEntry.startsWith("#")) {
+ hostEntry = removeComments(hostEntry);
+ if (hostEntry.contains(host)) {
+ addrStr = extractHostAddr(hostEntry, host);
+ if ((addrStr != null) && (!addrStr.equals(""))) {
+ addr = createAddressByteArray(addrStr);
+ if (inetAddresses == null) {
+ inetAddresses = new ArrayList<>(1);
+ }
+ if (addr != null) {
+ inetAddresses.add(InetAddress.getByAddress(host, addr));
}
}
-
- return null;
}
}
- );
- } catch (java.security.PrivilegedActionException e) {
+ }
+ } catch (FileNotFoundException e) {
+ throw new UnknownHostException("Unable to resolve host " + host
+ + " as hosts file " + hostsFile + " not found ");
+ }
+
+ if (inetAddresses != null) {
+ res = inetAddresses.toArray(new InetAddress[inetAddresses.size()]);
+ } else {
+ throw new UnknownHostException("Unable to resolve host " + host
+ + " in hosts file " + hostsFile);
}
+ return res;
+ }
+
+ private String removeComments(String hostsEntry) {
+ String filteredEntry = hostsEntry;
+ int hashIndex;
+
+ if ((hashIndex = hostsEntry.indexOf("#")) != -1) {
+ filteredEntry = hostsEntry.substring(0, hashIndex);
+ }
+ return filteredEntry;
+ }
+
+ private byte [] createAddressByteArray(String addrStr) {
+ byte[] addrArray;
+ // check if IPV4 address - most likely
+ addrArray = IPAddressUtil.textToNumericFormatV4(addrStr);
+ if (addrArray == null) {
+ addrArray = IPAddressUtil.textToNumericFormatV6(addrStr);
+ }
+ return addrArray;
}
- return nameService;
+ /** host to ip address mapping */
+ private String extractHostAddr(String hostEntry, String host) {
+ String[] mapping = hostEntry.split("\\s+");
+ String hostAddr = null;
+
+ if (mapping.length >= 2) {
+ // look at the host aliases
+ for (int i = 1; i < mapping.length; i++) {
+ if (mapping[i].equalsIgnoreCase(host)) {
+ hostAddr = mapping[0];
+ }
+ }
+ }
+ return hostAddr;
+ }
+
+ /**
+ * IP Address to host mapping
+ * use first host alias in list
+ */
+ private String extractHost(String hostEntry, String addrString) {
+ String[] mapping = hostEntry.split("\\s+");
+ String host = null;
+
+ if (mapping.length >= 2) {
+ if (mapping[0].equalsIgnoreCase(addrString)) {
+ host = mapping[1];
+ }
+ }
+ return host;
+ }
}
+ static final InetAddressImpl impl;
+
static {
// create the impl
impl = InetAddressImplFactory.create();
- // get name service if provided and requested
- String provider = null;;
- String propPrefix = "sun.net.spi.nameservice.provider.";
- int n = 1;
- nameServices = new ArrayList<>();
- provider = AccessController.doPrivileged(
- new GetPropertyAction(propPrefix + n));
- while (provider != null) {
- NameService ns = createNSProvider(provider);
- if (ns != null)
- nameServices.add(ns);
-
- n++;
- provider = AccessController.doPrivileged(
- new GetPropertyAction(propPrefix + n));
+ // create name service
+ nameService = createNameService();
}
- // if not designate any name services provider,
- // create a default one
- if (nameServices.size() == 0) {
- NameService ns = createNSProvider("default");
- nameServices.add(ns);
+ /**
+ * Create an instance of the NameService interface based on
+ * the setting of the {@codejdk.net.hosts.file} system property.
+ *
+ * <p>The default NameService is the PlatformNameService, which typically
+ * delegates name and address resolution calls to the underlying
+ * OS network libraries.
+ *
+ * <p> A HostsFileNameService is created if the {@code jdk.net.hosts.file}
+ * system property is set. If the specified file doesn't exist, the name or
+ * address lookup will result in an UnknownHostException. Thus, non existent
+ * hosts file is handled as if the file is empty.
+ *
+ * @return a NameService
+ */
+ private static NameService createNameService() {
+
+ String hostsFileName = AccessController
+ .doPrivileged(new GetPropertyAction("jdk.net.hosts.file"));
+ NameService theNameService;
+ if (hostsFileName != null) {
+ theNameService = new HostsFileNameService(hostsFileName);
+ } else {
+ theNameService = new PlatformNameService();
}
+ return theNameService;
}
/**
@@ -1286,20 +1480,16 @@
InetAddress[] addresses = null;
UnknownHostException ex = null;
- for (NameService nameService : nameServices) {
try {
addresses = nameService.lookupAllHostAddr(host);
- break;
} catch (UnknownHostException uhe) {
if (host.equalsIgnoreCase("localhost")) {
addresses = new InetAddress[] { impl.loopbackAddress() };
- break;
}
else {
ex = uhe;
}
}
- }
if (addresses == null) {
throw ex == null ? new UnknownHostException(host) : ex;