Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is java.net.SocksSocketImpl the default java.net.Socket implementation in Java?

Tags:

java

The question is brief. Why is a SOCKS-aware socket implementation the default choice for the implementation of the abstract java.net.Socket class? Naïvely I'd expect java.net.PlainSocketImpl.

The background is a bit more complicated.

I'm trying to kill off GLASSFISH-12213 (or really I'm trying to work around it). The details of the bug itself aren't very important--there's a native library that is not thread safe, and some concurrent usages of it from a GlassFish-authored LDAP realm crash the JVM.

To work around it, I started working backwards: can I avoid having the native library called in the first place? This led me for various reasons to look at sun.net.spi.DefaultProxySelector, which is in charge of finding an appropriate proxy (or not) for a given URI. There's a spot in there where it makes a native method call, and that is where the JVM crash occurs. If I could avoid that call, I'd be in business.

One way I could avoid that call would be if I could ensure that the value of sun.net.spi.NetProperties.getBoolean("java.net.useSystemProxies") false. If that were the case, then the native method I mentioned earlier wouldn't be called. false is the default and I haven't modified anything in this regard at all.

(So actually it is the case; demonstrably proven in the GlassFish instance running on that machine where I observed the bug. I'm not sure how this code, therefore, could possibly still be loading the native library; that's a subject for another day.)

So, punting on that path, I backed up further: what protocol was being passed as the URI scheme in the DefaultProxySelector.select(uri) call? Maybe I could then somehow influence the silly thing to still skip that native call somehow.

As it turns out, the protocol was socket (I had assumed it was probably something like ldap, but no). This fact and my disproven assumption suggested to me that somewhere something in LDAP-realm-land was opening up a direct socket by hand (i.e. not using something like an HttpUrlConnection or some other abstraction). Sure enough, the Sun-authored LDAP-JNDI bridge does just this; the URI that is passed in is socket://somehost:389.

So from all this despite the fact I haven't set up any proxy information, configured anything or done anything other than use straight defaults, it turns out that the JDK attempts to use a SOCKS proxy. See the setImpl() method in java.net.Socket and line 364 or so of SocksSocketImpl.java and trace it through for details.

(This finally suggests that I might be able to skip this whole codepath by simply adding a socksNonProxyHosts=* system property to the mix. Jeez, shouldn't that behavior be the default?)

As a result--and again, taking it on faith that the DefaultProxySelector for some reason is having its hasSystemProxies field set to true despite no changes in configuration by me or GlassFish, a garden variety socket created by a garden variety Sun LDAP connection is causing a native lookup for a SOCKS proxy server. Maybe it's just me, but that strikes me as madness.

So does anyone reading this--perhaps you are on the JDK team, or know someone who is, or know the history here--know why the default implementation of java.net.Socket always looks for a SOCKS proxy?

Update: I can see that the answer would be: so that if you have a system proxy set somewhere, and it's SOCKS-enabled, all stuff flows through it. But if the default value of java.net.useSystemProxies is false, as it is, then what's the point of hunting (by default) for a SOCKS proxy?

like image 242
Laird Nelson Avatar asked Nov 01 '13 20:11

Laird Nelson


Video Answer


1 Answers

The default socket implementation is SocksSocketImpl because the JRE might have been externally configured to use SOCKS via the system properties -DsocksProxyHost and -DsocksProxyPort or ProxySelector.setDefault() or via the default ProxySelector installed by the JRE.

PlainSocketImpl does not consult these properties or classes (because it is a plain socket and should not know anything about proxies) and so these external configurations would be ignored were not SocksSocketImpl always invoked to check on them. I agree it seems odd that you get a SocksSocketImpl when nobody has said anything about SOCKS to the JRE, but I guess the architecture of java.net.Socket and ProxySelector does not allow it to preselect the correct impl at the time of Socket instantiation.

I think you (or whoever is leading the current line of investigation on that Glassfish bug) may be going about this the wrong way: rather than trying to subvert the way the JRE selects socket impls and proxies, why not fix the default ProxySelector and/or OS native calls so that when Java does its standard queries for information about proxies, things don't break. I think the fix is in the guts of the proxy lookup process and classes, not higher up.


Maybe another way to ask what I'm asking is: if DefaultProxySelector can tell me the proxies to use for a socket connection, why doesn't Socket invoke that first to help it pick a sane implementation?

I think the problem is that java.net.Socket supports several programming models. There's the obvious new Socket(host, port) constructor, but there's also a default constructor new Socket() which can be constructed first and then at some arbitrary time in the future can have its connect(SocketAddress) method called.

Since part of the criteria that a ProxySelector can use to determine whether a proxy should be used or not is the name of the remote host and remote port to be connected to (that is, the information supplied to connect), the java.net.Socket constructor is too early to know whether a proxy will be needed or not.

For whatever reason (can we just assume historical? / backwards compatibility reasons? :), the constructor for java.net.Socket the only place where the impl set, and, like I said, that is in some cases too early to tell whether a proxy will be needed or not.

like image 137
Mike Clark Avatar answered Oct 09 '22 13:10

Mike Clark