Consider the following snippet:
(in this case OpenJDK 6b24-1.11.5-0ubuntu1~12.10.1, which appears irrelevant since all the JVMs 6&7 both Oracle and OpenJDK have the same behavior)
SocketPermission toCheck = new SocketPermission("www.google.ca", "resolve");
SocketPermission checker = new SocketPermission("*.ca:80", "connect");
System.out.println("Result: " + checker.implies(toCheck));
checker = new SocketPermission("*.1e100.net:80", "connect");
System.out.println("Result: " + checker.implies(toCheck));
The result I get is:
Result: false
Result: true
The issue seems to be that the JVM does a reverse lookup to verify that the address actually matches against the resolved domain.
A dig lookup of the www.google.ca domain reveals the following:
[rotty@rotty-desktop ~]$ dig www.google.ca ANY
; <<>> DiG 9.8.1-P1 <<>> www.google.ca ANY
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48015
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;www.google.ca. IN ANY
;; ANSWER SECTION:
www.google.ca. 114 IN A 74.125.226.55
www.google.ca. 114 IN A 74.125.226.56
www.google.ca. 114 IN A 74.125.226.63
www.google.ca. 74 IN AAAA 2607:f8b0:400b:801::1018
;; Query time: 27 msec
;; SERVER: 127.0.1.1#53(127.0.1.1)
;; WHEN: Mon Jan 14 17:18:50 2013
;; MSG SIZE rcvd: 107
Furthermore, taking the first address in the result and performing a DNS lookup produces:
[rotty@rotty-desktop ~]$ nslookup 74.125.226.55
Server: 127.0.1.1
Address: 127.0.1.1#53
Non-authoritative answer:
55.226.125.74.in-addr.arpa name = yyz06s06-in-f23.1e100.net.
Authoritative answers can be found from:
This seems to clearly demonstrate the issue. A non-authoritative reverse lookup returns the first (by locality in this case) alias defined for the domain.
This means that I need to know, and declare, any potential aliases that may resolve to the underlying address of the specified domain name.
Why would the JVM require such a match? Wouldn't a simple validation that an address does in fact exist be enough for the "resolve" process to be satisfied? There may well be any number of possible reverse mappings for the address. How could this ever work in practice?
[Update] In order to clarify that this in fact behaves the same with a default java policy definition, consider the following additional example:
Socket socket = new Socket("www.google.ca", 80);
socket.close();
Applying the following security policy to the above:
grant {
permission java.net.SocketPermission "*.ca:80", "connect";
//permission java.net.SocketPermission "*.1e100.net:80", "connect";
};
Executing the program as:
java -Djava.security.manager -Djava.security.policy=../security.policy Test
Results in:
Exception in thread "main" java.security.AccessControlException: access denied ("java.net.SocketPermission" "www.google.ca" "resolve")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:366)
at java.security.AccessController.checkPermission(AccessController.java:560)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.SecurityManager.checkConnect(SecurityManager.java:1048)
at java.net.InetAddress.getAllByName0(InetAddress.java:1203)
at java.net.InetAddress.getAllByName(InetAddress.java:1127)
at java.net.InetAddress.getAllByName(InetAddress.java:1063)
at java.net.InetAddress.getByName(InetAddress.java:1013)
at java.net.InetSocketAddress.<init>(InetSocketAddress.java:142)
at java.net.Socket.<init>(Socket.java:208)
at example.security.SocketSecurityExample.test(SocketSecurityExample.java:13)
at example.security.SocketSecurityExample.main(SocketSecurityExample.java:9)
Changing the policy file to:
grant {
//permission java.net.SocketPermission "*.ca:80", "connect";
permission java.net.SocketPermission "*.1e100.net:80", "connect";
};
Results in proper execution of the code.