--- a/jdk/src/share/classes/java/net/InetAddress.java Sun May 01 14:22:32 2011 +0800
+++ b/jdk/src/share/classes/java/net/InetAddress.java Mon May 02 11:02:58 2011 +0100
@@ -1013,6 +1013,12 @@
return InetAddress.getAllByName(host)[0];
}
+ // called from deployment cache manager
+ public static InetAddress getByName(String host, InetAddress reqAddr)
+ throws UnknownHostException {
+ return InetAddress.getAllByName(host, reqAddr)[0];
+ }
+
/**
* Given the name of a host, returns an array of its IP addresses,
* based on the configured name service on the system.
@@ -1054,6 +1060,11 @@
*/
public static InetAddress[] getAllByName(String host)
throws UnknownHostException {
+ return getAllByName(host, null);
+ }
+
+ private static InetAddress[] getAllByName(String host, InetAddress reqAddr)
+ throws UnknownHostException {
if (host == null || host.length() == 0) {
InetAddress[] ret = new InetAddress[1];
@@ -1113,7 +1124,7 @@
// We were expecting an IPv6 Litteral, but got something else
throw new UnknownHostException("["+host+"]");
}
- return getAllByName0(host);
+ return getAllByName0(host, reqAddr, true);
}
/**
@@ -1174,6 +1185,12 @@
*/
static InetAddress[] getAllByName0 (String host, boolean check)
throws UnknownHostException {
+ return getAllByName0 (host, null, check);
+ }
+
+ private static InetAddress[] getAllByName0 (String host, InetAddress reqAddr, boolean check)
+ throws UnknownHostException {
+
/* If it gets here it is presumed to be a hostname */
/* Cache.get can return: null, unknownAddress, or InetAddress[] */
@@ -1191,7 +1208,7 @@
/* If no entry in cache, then do the host lookup */
if (addresses == null) {
- addresses = getAddressesFromNameService(host);
+ addresses = getAddressesFromNameService(host, reqAddr);
}
if (addresses == unknown_array)
@@ -1200,7 +1217,7 @@
return addresses.clone();
}
- private static InetAddress[] getAddressesFromNameService(String host)
+ private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
throws UnknownHostException
{
InetAddress[] addresses = null;
@@ -1256,10 +1273,32 @@
}
}
- // Cache the addresses.
+ // More to do?
+ if (reqAddr != null && addresses.length > 1 && !addresses[0].equals(reqAddr)) {
+ // Find it?
+ int i = 1;
+ for (; i < addresses.length; i++) {
+ if (addresses[i].equals(reqAddr)) {
+ break;
+ }
+ }
+ // Rotate
+ if (i < addresses.length) {
+ InetAddress tmp, tmp2 = reqAddr;
+ for (int j = 0; j < i; j++) {
+ tmp = addresses[j];
+ addresses[j] = tmp2;
+ tmp2 = tmp;
+ }
+ addresses[i] = tmp2;
+ }
+ }
+ // Cache the address.
cacheAddresses(host, addresses, success);
+
if (!success && ex != null)
throw ex;
+
} finally {
// Delete host from the lookupTable and notify
// all threads waiting on the lookupTable monitor.
@@ -1393,7 +1432,7 @@
InetAddress[] localAddrs;
try {
localAddrs =
- InetAddress.getAddressesFromNameService(local);
+ InetAddress.getAddressesFromNameService(local, null);
} catch (UnknownHostException uhe) {
// Rethrow with a more informative error message.
UnknownHostException uhe2 =
--- a/jdk/src/share/classes/java/net/Socket.java Sun May 01 14:22:32 2011 +0800
+++ b/jdk/src/share/classes/java/net/Socket.java Mon May 02 11:02:58 2011 +0100
@@ -127,11 +127,12 @@
}
if (security != null) {
if (epoint.isUnresolved())
- security.checkConnect(epoint.getHostName(),
- epoint.getPort());
+ epoint = new InetSocketAddress(epoint.getHostName(), epoint.getPort());
+ if (epoint.isUnresolved())
+ security.checkConnect(epoint.getHostName(), epoint.getPort());
else
security.checkConnect(epoint.getAddress().getHostAddress(),
- epoint.getPort());
+ epoint.getPort());
}
impl = new SocksSocketImpl(p);
impl.setSocket(this);
--- a/jdk/src/share/classes/java/net/SocketPermission.java Sun May 01 14:22:32 2011 +0800
+++ b/jdk/src/share/classes/java/net/SocketPermission.java Mon May 02 11:02:58 2011 +0100
@@ -41,6 +41,7 @@
import java.io.IOException;
import sun.net.util.IPAddressUtil;
import sun.security.util.SecurityConstants;
+import sun.security.util.Debug;
/**
@@ -211,13 +212,32 @@
// port range on host
private transient int[] portrange;
- // true if the trustProxy system property is set
- private static boolean trustProxy;
+ private transient boolean defaultDeny = false;
+
+ // true if this SocketPermission represents a hostname
+ // that failed our reverse mapping heuristic test
+ private transient boolean untrusted;
+ private transient boolean trusted;
+
+ // true if the sun.net.trustNameService system property is set
+ private static boolean trustNameService;
+
+ private static Debug debug = null;
+ private static boolean debugInit = false;
static {
Boolean tmp = java.security.AccessController.doPrivileged(
- new sun.security.action.GetBooleanAction("trustProxy"));
- trustProxy = tmp.booleanValue();
+ new sun.security.action.GetBooleanAction("sun.net.trustNameService"));
+ trustNameService = tmp.booleanValue();
+ }
+
+ private static synchronized Debug getDebug()
+ {
+ if (!debugInit) {
+ debug = Debug.getInstance("access");
+ debugInit = true;
+ }
+ return debug;
}
/**
@@ -263,6 +283,10 @@
init(getName(), mask);
}
+ private void setDeny() {
+ defaultDeny = true;
+ }
+
private static String getHost(String host)
{
if (host.equals("")) {
@@ -560,6 +584,38 @@
return mask;
}
+ private boolean isUntrusted()
+ throws UnknownHostException
+ {
+ if (trusted) return false;
+ if (invalid || untrusted) return true;
+ try {
+ if (!trustNameService && (defaultDeny ||
+ sun.net.www.URLConnection.isProxiedHost(hostname))) {
+ if (this.cname == null) {
+ this.getCanonName();
+ }
+ if (!match(cname, hostname) &&
+ (defaultDeny || !cname.equals(addresses[0].getHostAddress()))) {
+ // Last chance
+ if (!authorized(hostname, addresses[0].getAddress())) {
+ untrusted = true;
+ Debug debug = getDebug();
+ if (debug != null && Debug.isOn("failure")) {
+ debug.println("socket access restriction: proxied host " + "(" + addresses[0] + ")" + " does not match " + cname + " from reverse lookup");
+ }
+ return true;
+ }
+ }
+ trusted = true;
+ }
+ } catch (UnknownHostException uhe) {
+ invalid = true;
+ throw uhe;
+ }
+ return false;
+ }
+
/**
* attempt to get the fully qualified domain name
*
@@ -567,7 +623,7 @@
void getCanonName()
throws UnknownHostException
{
- if (cname != null || invalid) return;
+ if (cname != null || invalid || untrusted) return;
// attempt to get the canonical name
@@ -593,6 +649,141 @@
}
}
+ private String cdomain, hdomain;
+
+ private boolean match(String cname, String hname) {
+ String a = cname.toLowerCase();
+ String b = hname.toLowerCase();
+ if (a.startsWith(b) &&
+ ((a.length() == b.length()) || (a.charAt(b.length()) == '.')))
+ return true;
+ if (cdomain == null) {
+ cdomain = guessRegisteredDomain(a);
+ }
+ if (hdomain == null) {
+ hdomain = guessRegisteredDomain(b);
+ }
+
+ return cdomain.length() != 0 && hdomain.length() != 0
+ && cdomain.equals(hdomain);
+ }
+
+
+ /* Apart from special cases, this checks for 2 letter TLD
+ * (usually ccTLD) and then for a specific set of common labels
+ * indicating likely 2nd level public suffixes. If both conditions
+ * true then return right most three labels. Otherwise, return
+ * 2 rightmost labels.
+ *
+ * www.sun.com. -> sun.com
+ * www.sun.co.uk -> sun.co.uk
+ * www.sun.com.au -> sun.com.au
+ */
+
+ private String guessRegisteredDomain(String cname) {
+ int dot;
+ dot = cname.lastIndexOf('.');
+ if (dot == -1)
+ return cname;
+ if (dot == 0)
+ return "";
+ if (dot == cname.length() - 1) {
+ cname = cname.substring(0, cname.length() -1);
+ dot = cname.lastIndexOf('.');
+ }
+ if (dot < 1)
+ return "";
+ int second = cname.lastIndexOf('.', dot - 1);
+ if (second == -1)
+ return cname;
+ if (((cname.length() - dot) <= 3) && ((dot - second) <= 4) && second > 0) {
+ if (dot - second == 4) {
+ String s = cname.substring(second + 1, dot);
+ if (!(s.equals("com") || s.equals("org") || s.equals("edu"))) {
+ return cname.substring(second + 1);
+ }
+ }
+ int third = cname.lastIndexOf('.', second - 1);
+ if (third == -1)
+ return cname.substring(second + 1);
+ else
+ return cname.substring(third + 1);
+ }
+ return cname.substring(second + 1);
+ }
+
+
+ private boolean authorized(String cname, byte[] addr) {
+ if (addr.length == 4)
+ return authorizedIPv4(cname, addr);
+ else if (addr.length == 16)
+ return authorizedIPv6(cname, addr);
+ else
+ return false;
+ }
+
+ private boolean authorizedIPv4(String cname, byte[] addr) {
+ String authHost = "";
+ InetAddress auth;
+
+ try {
+ authHost = "auth." +
+ (addr[3] & 0xff) + "." + (addr[2] & 0xff) + "." +
+ (addr[1] & 0xff) + "." + (addr[0] & 0xff) +
+ ".in-addr.arpa";
+ // Following check seems unnecessary
+ // auth = InetAddress.getAllByName0(authHost, false)[0];
+ authHost = hostname + '.' + authHost;
+ auth = InetAddress.getAllByName0(authHost, false)[0];
+ if (auth.equals(InetAddress.getByAddress(addr))) {
+ return true;
+ }
+ Debug debug = getDebug();
+ if (debug != null && Debug.isOn("failure")) {
+ debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr));
+ }
+ } catch (UnknownHostException uhe) {
+ Debug debug = getDebug();
+ if (debug != null && Debug.isOn("failure")) {
+ debug.println("socket access restriction: forward lookup failed for " + authHost);
+ }
+ }
+ return false;
+ }
+
+ private boolean authorizedIPv6(String cname, byte[] addr) {
+ String authHost = "";
+ InetAddress auth;
+
+ try {
+ StringBuffer sb = new StringBuffer(39);
+
+ for (int i = 15; i >= 0; i--) {
+ sb.append(Integer.toHexString(((addr[i]) & 0x0f)));
+ sb.append('.');
+ sb.append(Integer.toHexString(((addr[i] >> 4) & 0x0f)));
+ sb.append('.');
+ }
+ authHost = "auth." + sb.toString() + "IP6.ARPA";
+ //auth = InetAddress.getAllByName0(authHost, false)[0];
+ authHost = hostname + '.' + authHost;
+ auth = InetAddress.getAllByName0(authHost, false)[0];
+ if (auth.equals(InetAddress.getByAddress(addr)))
+ return true;
+ Debug debug = getDebug();
+ if (debug != null && Debug.isOn("failure")) {
+ debug.println("socket access restriction: IP address of " + auth + " != " + InetAddress.getByAddress(addr));
+ }
+ } catch (UnknownHostException uhe) {
+ Debug debug = getDebug();
+ if (debug != null && Debug.isOn("failure")) {
+ debug.println("socket access restriction: forward lookup failed for " + authHost);
+ }
+ }
+ return false;
+ }
+
+
/**
* get IP addresses. Sets invalid to true if we can't get them.
*
@@ -720,12 +911,7 @@
// return if either one of these NetPerm objects are invalid...
if (this.invalid || that.invalid) {
- return (trustProxy ? inProxyWeTrust(that) : false);
- }
-
-
- if (this.getName().equalsIgnoreCase(that.getName())) {
- return true;
+ return compareHostnames(that);
}
try {
@@ -778,28 +964,29 @@
that.getIP();
}
- for (j = 0; j < this.addresses.length; j++) {
- for (i=0; i < that.addresses.length; i++) {
- if (this.addresses[j].equals(that.addresses[i]))
- return true;
+ if (!(that.init_with_ip && this.isUntrusted())) {
+ for (j = 0; j < this.addresses.length; j++) {
+ for (i=0; i < that.addresses.length; i++) {
+ if (this.addresses[j].equals(that.addresses[i]))
+ return true;
+ }
}
+
+ // XXX: if all else fails, compare hostnames?
+ // Do we really want this?
+ if (this.cname == null) {
+ this.getCanonName();
+ }
+
+ if (that.cname == null) {
+ that.getCanonName();
+ }
+
+ return (this.cname.equalsIgnoreCase(that.cname));
}
- // XXX: if all else fails, compare hostnames?
- // Do we really want this?
- if (this.cname == null) {
- this.getCanonName();
- }
-
- if (that.cname == null) {
- that.getCanonName();
- }
-
- return (this.cname.equalsIgnoreCase(that.cname));
-
} catch (UnknownHostException uhe) {
- if (trustProxy)
- return inProxyWeTrust(that);
+ return compareHostnames(that);
}
// make sure the first thing that is done here is to return
@@ -808,19 +995,23 @@
return false;
}
- private boolean inProxyWeTrust(SocketPermission that) {
- // if we trust the proxy, we see if the original names/IPs passed
- // in were equal.
+ private boolean compareHostnames(SocketPermission that) {
+ // we see if the original names/IPs passed in were equal.
String thisHost = hostname;
String thatHost = that.hostname;
- if (thisHost == null)
+ if (thisHost == null) {
return false;
- else
+ } else if (this.wildcard) {
+ final int cnameLength = this.cname.length();
+ return thatHost.regionMatches(true,
+ (thatHost.length() - cnameLength), this.cname, 0, cnameLength);
+ } else {
return thisHost.equalsIgnoreCase(thatHost);
+ }
+ }
- }
/**
* Checks two SocketPermission objects for equality.
* <P>
--- a/jdk/src/share/classes/sun/net/www/URLConnection.java Sun May 01 14:22:32 2011 +0800
+++ b/jdk/src/share/classes/sun/net/www/URLConnection.java Mon May 02 11:02:58 2011 +0100
@@ -238,4 +238,14 @@
public void close() {
url = null;
}
+
+ private static HashMap<String,Void> proxiedHosts = new HashMap<>();
+
+ public synchronized static void setProxiedHost(String host) {
+ proxiedHosts.put(host.toLowerCase(), null);
+ }
+
+ public synchronized static boolean isProxiedHost(String host) {
+ return proxiedHosts.containsKey(host.toLowerCase());
+ }
}
--- a/jdk/src/share/classes/sun/net/www/http/HttpClient.java Sun May 01 14:22:32 2011 +0800
+++ b/jdk/src/share/classes/sun/net/www/http/HttpClient.java Mon May 02 11:02:58 2011 +0100
@@ -301,7 +301,11 @@
} else {
SecurityManager security = System.getSecurityManager();
if (security != null) {
- security.checkConnect(url.getHost(), url.getPort());
+ if (ret.proxy == Proxy.NO_PROXY || ret.proxy == null) {
+ security.checkConnect(InetAddress.getByName(url.getHost()).getHostAddress(), url.getPort());
+ } else {
+ security.checkConnect(url.getHost(), url.getPort());
+ }
}
ret.url = url;
}
@@ -457,11 +461,11 @@
protected synchronized void openServer() throws IOException {
SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkConnect(host, port);
- }
if (keepingAlive) { // already opened
+ if (security != null) {
+ security.checkConnect(host, port);
+ }
return;
}
@@ -469,11 +473,19 @@
url.getProtocol().equals("https") ) {
if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) {
+ sun.net.www.URLConnection.setProxiedHost(host);
+ if (security != null) {
+ security.checkConnect(host,port);
+ }
privilegedOpenServer((InetSocketAddress) proxy.address());
usingProxy = true;
return;
} else {
// make direct connection
+ if (security != null) {
+ // redundant?
+ security.checkConnect(host, port);
+ }
openServer(host, port);
usingProxy = false;
return;
@@ -484,11 +496,19 @@
* ftp url.
*/
if ((proxy != null) && (proxy.type() == Proxy.Type.HTTP)) {
+ sun.net.www.URLConnection.setProxiedHost(host);
+ if (security != null) {
+ security.checkConnect(host,port);
+ }
privilegedOpenServer((InetSocketAddress) proxy.address());
usingProxy = true;
return;
} else {
// make direct connection
+ if (security != null) {
+ // redundant?
+ security.checkConnect(host, port);
+ }
super.openServer(host, port);
usingProxy = false;
return;