java runtime 6 with socks v5 proxy - Possible?

2020-06-16 04:12发布

问题:

I have written an application that (amongst other things) runs a local service in windows that acts as a SOCKS v5 proxy for Firefox.

I'm in the debugging phase right now and have found certain websites that don't work correctly. For example the Java Applet for Picture Uploading on Facebook.com fails because is is unable to lookup domains.

My app overrides a hidden FF config setting network.proxy.socks__remote__dns setting it to true. The whole purpose of the app is to allow access to websites when behind a firewall (e.g. if the user is in China), so this setting is essential to ensure domains are resolved remotely also (and not just HTTP requests).

In the JRE6 settings (documented here) there isn't an equivalent setting, and since remote DNS resolution is a feature of SOCKS v5 and not v4 as the documentation seems to imply I'm worried that it's just not possible.

How can I programmatically make sure the JRE uses a SOCKS v5 proxy for all requests (including DNS)?


UPDATE: Steps to reproduce this problem:

  1. Make sure you are behind a firewall that blocks (or redirects) internet access including DNS
  2. Install PuTTY and add a dynamic SSH tunnel on some port number of your choice (e.g. 9870). Then login to a remote server that has full access to the internet
  3. Launch Firefox and you will not be able to browse the web
  4. In FF network settings set the SOCKS v5 proxy to localhost:9870
  5. In FF go to about:config, change network.proxy.socks__remote__dns to true
  6. You will now be able to browse the web.
  7. Go to facebook.com, login, go to your profile and attempt to use the picture uploader java applet to add some pictures
  8. It will fail with a series of class not found errors looking similar to:

    load: class com.facebook.facebookphotouploader5.FacebookPhotoUploader5.class not found.

I believe this is failing because the JRE is unable to resolve the domain that the class resides on. I'm basing this belief on the fact that the documentation (http://java.sun.com/javase/6/docs/technotes/guides/deployment/deployment-guide/properties.html) talks only about SOCKS v4 (which as far as I know does not support remote DNS). My deployment.properties file is located in %APPDATA%\Sun\Java\Deployment. I can confirm that modifications I make in the Java Control Panel get written into that file. If instead of "Use browser setting" the network settings for Java I override and attempt to use the SOCKS proxy settings manually, I still have the issue. There does not seem to be an easy way to force the JRE to do DNS remotely through the Proxy.


UPDATE 2:

Without the SOCKS proxy, from my local client

  • www.facebook.com resolves to 203.161.230.171
  • upload.facebook.com resolves to 64.33.88.161

Neither host is reachable (because of the firewall)

If I login to the remote server, I get:

  • www.facebook.com 69.63.187.17
  • upload.facebook.com 69.63.178.32

Both these IPs change after a few minutes, as it seems Facebook uses round-robin DNS and other load-balancing.

With the Proxy settings set in Firefox, I can navigate to www.facebook.com without any difficulty (since DNS is being resolved remotely on the Proxy). Whey I go to the page with the Java applet it fails with the stacktrace messages I've already reported.

However if I edit Windows\System32\drivers\etc\hosts, adding the correct IP for upload.facebook.com I can get the applet to load and work correctly (restart of FF is sometimes necessary).

This evidence seems to support my theory that the Java Runtime is not resolving DNS on the Proxy, but instead just routing traffic though it.

My application is for mass-deployment, and needs to work with java applets on other sites (not just facebook). I really need a work-around for this problem.


UPDATE 3 Stacktrace dump a requested by ZZ Coder:

load: class com.facebook.facebookphotouploader5.FacebookPhotoUploader5.class not found.
java.lang.ClassNotFoundException: com.facebook.facebookphotouploader5.FacebookPhotoUploader5.class
    at sun.plugin2.applet.Applet2ClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.plugin2.applet.Plugin2ClassLoader.loadCode(Unknown Source)
    at sun.plugin2.applet.Plugin2Manager.createApplet(Unknown Source)
    at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(Unknown Source)
    at java.io.BufferedInputStream.fill(Unknown Source)
    at java.io.BufferedInputStream.read1(Unknown Source)
    at java.io.BufferedInputStream.read(Unknown Source)
    at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
    at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
    at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
    at java.net.HttpURLConnection.getResponseCode(Unknown Source)
    at sun.plugin2.applet.Applet2ClassLoader.getBytes(Unknown Source)
    at sun.plugin2.applet.Applet2ClassLoader.access$000(Unknown Source)
    at sun.plugin2.applet.Applet2ClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    ... 7 more
Exception: java.lang.ClassNotFoundException: com.facebook.facebookphotouploader5.FacebookPhotoUploader5.class

Dumping class loader cache...
 Live entry: key=http://upload.facebook.com/controls/2008.10.10_v5.5.8/,FacebookPhotoUploader5.jar,FacebookPhotoUploader5.jar, refCount=1, threadGroup=sun.plugin2.applet.Applet2ThreadGroup[name=http://upload.facebook.com/controls/2008.10.10_v5.5.8/-threadGroup,maxpri=4]
Done.

回答1:

new InetSocketAddress(hosta, port) which resolve IP by Default, and SocksSocketImpl use IP first if the target address is resolved. If you want RemoteDNS, you can new Socket you An Proxy,then connnect to a InetSocketAddress which is constructed by InetSocketAddress.createUnresolved(host, port).

You Socks Server must be SOCKS5, java SocksSocketImpl auto detect is version.

Proxy p = new Proxy(Proxy.Type.SOCKS, paddr);
Socket s = new Socket(p);
InetSocketAddress addr = InetSocketAddress.createUnresolved("host.blocked.by.gfw", port);
s.connect(addr);


回答2:

JRE certainly supports Socks V5. I have been using it since Java 1.4. JRE only uses V4 if your SOCKS server is V4. The first byte from your server response must be 5.

The V4 support was buggy. It only works with IP address, not domain name because it doesn't know how to resolve the domain name before hand. So you must be use V5 if Socks works at all.

I suspect that your proxy setting is incorrect so socks doesn't work at all. This should be easy to trace with Wireshark. Just check which port the applet is using.

Also the stacktrace will be very helpful. It will show you if Socks is used. For example,

load: class test.MyApplet.class not found.
java.lang.ClassNotFoundException: <name>.class
at sun.applet.AppletClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.applet.AppletClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.applet.AppletClassLoader.loadCode(Unknown Source)
at sun.applet.AppletPanel.createApplet(Unknown Source)
at sun.plugin.AppletViewer.createApplet(Unknown Source)
at sun.applet.AppletPanel.runLoader(Unknown Source)
at sun.applet.AppletPanel.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Caused by: java.net.SocketException: Malformed reply from SOCKS server
at java.net.SocksSocketImpl.readSocksReply(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)

I pointed SOCKS proxy to my HTTP server so this error is expected.