MokaByte Numero  42  - Giugno 2000
Let Java Applications Through Firewall
by 
Zhao Yonghong

 

 


Java, as a network programming language, is fashionable all over the programmer world. With java.net Package, we can write easily many flexible applications which intercommunicate between client and server anywhere at any time. Of course, Java is too young and is still incomplete on many aspects. A lot of Java developers have disappointedly found out that their users can not run normally the Java applications or applets when their users are behind firewalls that do not allow direct stream or datagram socket connections. In this article, I will illustrate how to let your applications through expediently firewall by calling some extended socket classes which utilizing SOCKS or HTTP proxy at the transport layer since the services of SOCKS proxy and HTTP proxy are provided widely on proxy servers.

Overview of Firewall/Proxy Architecture and Extendable Socket
Firewall is a security system intended to protect an intranet against external threats. It is used to limit the communicating directly between the internal network and the external world. A proxy server resides always behind the firewall to allow and relay some particular message communication between intranet clients and internet world. The schemas of SOCKS and HTTP are like these:
 
  ----------              ---------    |-|            ------------
  |        |    SOCKS     | SOCKS |    |-|  TCP/IP    |          |
  | Client | <----------> | Proxy | <--|-|----------> | Internet |
  |        |   Protocol   | Server|    |-| Protocols  |          |
  ----------              ---------    |-|            ------------
                                     Firewall
----------              ---------    |-|            ------------
|        |     HTTP     | HTTP  |    |-|    HTTP    |          |
| Client | <----------> | Proxy | <--|-|----------> | Internet |
|        |   Protocol   | Server|    |-|  Protocol  |          |
----------              ---------    |-|            ------------
                                  Firewall
Firewall will filter the traversed byte stream and transfer data  according to its security policy. The socket stream in Java applications has to abide by the protocol standards for SOCKS and HTTP, otherwise firewall will refuse simply and discard ruthlessly the unrecognized requests from our applications.

Although JDK1.0 has allowed licensees to subclass java.net.SocketImpl for providing added functionality of network transport and layering other protocols on top of TCP, it's an annoying shortage of having a single type of SocketImpl installed for a java runtime, which limits large-scale applications. Since the java.net classes in JDK 1.1 have allowed sockets (DatagramSocket/Socket/ServerSocket) to be non-final, extendable classes, we can happily write our own DatagramSocket, Socket, SocketImpl and SocketImplFactory to extend Socket subclass which can handle transparently the handshaking process with SOCKS or HTTP proxy behind certain kinds of firewalls. If you are interested in complementing and extending these extended socket subclasses to provide richer functionality at the application layer, please also read carefully Networking Guide after click here to download a zip file of source code and its relative documents for this article
Note: Considering the existence of many Java1.0X applications, all showed extended socket classes can be compiled on Java1.0X after removed the clause like"extendeds Socket" and the unnecessary methods, and complement few protected variables which inherit from the latest Socket class.
 
 
 

Through Firewall by SOCKS Proxy
The java.net package does support base SOCKS V4 after setting two system properties about SOCKS by using some code snippets. (For more information, see Example1.java)

//Specify SOCKS proxy host in system properties
 System.getProperties().put("socksProxyHost","your.socks.host");
//Specify SOCKS proxy port number in system properties
 System.getProperties().put("socksProxyPort",""+1080);

There are mainly three cumbersome limitations after enableing java.net package's SOCKS support. First, all stream sockets will always through the SOCKS server for a Java runtime although the stream socket connections on the inside should be sent direct and not through the firewall. Secondly, applications will always throw java.net.UnknownHostException if the client can not find the destination host's IP address notwithstanding the SOCKS server does can resolve the destination host's domain name. Thirdly, applications which are utilizing java.net.DatagramSocket will always fail in going through firewalls because datagram packet can not be relayed by SOCKS4 protocol. The only way to solve these three annoying problems is to construct some extended socket classes for SOCKS4A/SOCKS5 protocols, before the java.net package provides SOCKS4A/SOCKS5 support.

SOCKS 4A protocol, a simple extension to SOCKS 4 protocol, is intended to allow the use of SOCKS 4 on hosts which are not capable of resolving all domain names. SOCKS 5 protocol extends the SOCKS 4 model to include UDP(User Datagram Protocol), and extends the framework to include provisions for generalized strong authentication schemes, and extends the addressing scheme to encompass domain name and V6 IP addresses. It's unnecessary for Java programmers who need SOCKS4A/SOCKS5 support to learn at length how SOCKS4A/SOCKS5 protocols work and how the SocksSocketImpl class, an extended java.net.SocketImpl class, implements SOCKS4A and SOCKS5 supports. All the three classes in the zyh.net package you care about are SocksSocket, SocksDatagramSocket and SocksSocketImplFactory. The API of SocksSocket and SocksDatagramSocket is nearly identical to those of java.net.Socket and java.net.DatagramSocket. Java programmers should be able to modify their Socket (or DatagramSocket) objects to SocksSocket (or SocksDatagramSocket) objects no sweat. Just like this piece of code below.
For Socket (For more help on using SocksSocket, see Example2.java or Example3.java)

Replace

Socket socket = new Socket( host, port);
With
Socket socket = new zyh.net.SocksSocket( host, port);
For DatagramSocket(For more help on using SocksDatagramSocket, see EchoClient.java and EchoServer.java)
Replace
DatagramSocket datagramSocket = new DatagramSocket();
With
DatagramSocket datagramSocket = new zyh.net.SocksDatagramSocket();
If you wish to invoke the SOCKS4A/SOCKS5 support, you need to create a SocksSocketImplFactory factory once for a Java runtime.
For Socket (For more help on using SocksSocket, see Example2.java or Example3.java)
zyh.net.SocksSocketImplFactory factory = new 
   zyh.net.SocksSocketImplFactory(socksProxyHost, 
   socksProxyPort);
zyh.net.SocksSocket.setSocketImplFactory( factory);
For DatagramSocket(For more help on using SocksDatagramSocket, see EchoClient.java and EchoServer.java)
//set stream to false for datagram packet.
zyh.net.SocksSocketImplFactory factory = new 
zyh.net.SocksSocketImplFactory( socksProxyHost, socksProxyPort, false);
zyh.net.SocksDatagramSocket.setSocketImplFactory(factory);
If you wish to set some optional properties for SOCKS server, for instance, username and pasword for SOCKS5 server. Just use a piece of code like:
//Used to keep some optional properties
Properties  properties = new Properties();
properties.put(zyh.net.SocksSocket.USER, "abc");
properties.put(zyh.net.SocksSocket.PASSWD, "efg");
zyh.net.SocksSocketImplFactory factory = new zyh.net.SocksSocketImplFactory( socksProxyHost, socksProxyPort, properties);
zyh.net.SocksSocket.setSocketImplFactory(factory);
As you can see, your applications will be portable across different environments which use SOCKS proxy or not, after modifing simply Socket (or DatagramSocket) objects to SocksSocket (or SocksDatagramSocket) objects.
 
 
 

Through Firewall by HTTP Proxy with Tunneling Support
There are not SOCKS proxys on a lot of  intranets' firewalls since SOCKS protocol is so powerful for many different services, such as telnet, ftp, finger, whois, gopher, WWW, etc. Their rigorous security policy on firewall allows their users to use HTTP service only. That is, all you can do is to surf around the web through your browser.  No FTP, no IRC, no POP3 and other services that use Internet protocols different from HTTP. What's the tip on burrowing through firewall?

Besides the operators of GET, HEADER and POST, HTTP/1.1 has expanded HTTP/1.0to include five new methods of OPTIONS, PUT, DELETE, TRACE and CONNECT. Although all about CONNECT method in RFC2616 is only a summary statement, "This specification reserves the method name CONNECT for use with a proxy that can dynamically switch to being a tunnel (e.g. SSL tunneling [44]).", the HTTP/1.1 compatible web proxy servers do support Tunneling TCP based protocols. HttpSocket and HttpSocketImplFactory has encapsulated the HTTP Tunneling support by utilizing CONNECT operator. You can skip directly to Part IV: Full-duplex Firewall Tunneling with Low Overhead since the detailed usage of HttpSocket class is very similar to that of SocksSocket.
The usage just likes this piece of code below. (Here is two examples using HttpSocket:  Example4.java or Example5.java)
Replace

Socket socket = new Socket(host, port);
With
Socket socket = new zyh.net.HttpSocket(host, port);
If you wish to invoke the HTTP tunneling support, you need to create a HttpSocketImplFactory factory once for a Java runtime.
zyh.net.HttpSocketImplFactory factory = new zyh.net.HttpSocketImplFactory( httpProxyHost, httpProxyPort);
zyh.net.HttpSocket.setSocketImplFactory(factory);
If you wish to set some optional properties for HTTP proxy server, for instance, username and pasword. Just use a piece of code like:
//Used to keep some optional properties
Properties  properties = new Properties();
properties.put(zyh.net.HttpSocket.USER,"abc");
properties.put(zyh.net.HttpSocket.PASSWD,"efg");
zyh.net.HttpSocketImplFactory factory = new zyh.net.HttpSocketImplFactory( httpProxyHost, httpProxyPort,
properties);
zyh.net.HttpSocket.setSocketImplFactory(factory);

 

Full-duplex Firewall Tunneling with Low Overhead
We can't expect all of HTTP/1.0 compliant proxy server will support CONNECT method so that sometimes we have to find an alternative scheme for those clients who are confused for Java applications' abnormal actions in their semi-isolated condition behind firewall. Firewall tunneling techniques are widely used to resolve this problem. A CGI script (servlet or server program) running on the Web server provides simulative multiplexed communication for its clients by using HTTP/1.0's GET or POST operator. This kind of techniques is currently only one effective method for the unsigned client applet because those unsigned client applets are not allowed to connect to any host other than the original web server. As the current techniques is using URLConnection (more exactly, HttpURLConnection) in sending a simple message from the client to the server and using the preparative pending-connection to send a simple message from the server to the client, there are a heavy programming work in simulating full-duplex communication and a heavy system overhead in creating, maintaining and closing so much URLConnections. Maybe we should find a more effective way for our applications since the security scheme for application is loose. Is it possible to create one true full-duplex HttpURLConnection with low overhead? If you are counting on the java.net or sun.net package, the answer is No. But.
.
On the Internet, no one knows you are a dog. Similarly, your HTTP proxy will not take any special action for the HTTP request from your Java applicaton and burthen itself in judging the validity of HTTP POST request through parsing the Content-length header. If we construct our own HTTP POST request and specify the play rule of HttpURLConnection, one true full-duplex HttpURLConnection will appear. The tip is that the client sends an HTTP POST request message for handshaking and receives the server's HTTP response message without message-body, then both of the client and server do not disconnect this HTTP connection and maintain it as a tunneling for TCP/IP stream. HttpURLSocket and HttpURLSocketImplFactory have implemented the similar API like those of Socket and SocketImplFactory by utilizing the true full-duplex HttpURLConnection. The usage is similar to the usage of SocksSocket or HttpSocket. (For more help on using HttpURLSocket, see Example6.java or Example7.java)
 Replace

Socket socket = new Socket(host, port);
With
Socket socket = new zyh.net.HttpURLSocket(host, port);
If you wish to invoke the Full-duplex Firewall Tunneling support, you need to create a HttpURLSocketImplFactory factory once for a Java runtime.
//httpURLProxyURL is the url of HttpURLConnection proxy
zyh.net.HttpURLSocketImplFactory factory = new zyh.net.HttpURLSocketImplFactory( httpProxyHost, httpProxyPort, httpURLProxyURL);    zyh.net.HttpURLSocket.setSocketImplFactory(factory);


Since the Full-duplex Firewall Tunneling support is constructed lately on the base of HTTP connection, the existed server applications will not recognise and cope harmoniously with the HttpURLSocket request. To avoid any code modification for the existed server applications, a multithreaded HttpURLProxy server running on an internet host can parse and relay all HttpURL connections. For performance and efficiency reasons, the HttpURLProxy server has utilized thread pool techniques. You can complement the "protected boolean HttpURLProxy.login(String user,String passwd)" to refuse any uninvited httpURL request. Accordingly, you need to set some optional properties for HttpURLProxy proxy server. Take a look at the code below:

//Used to keep some optional properties
Properties  properties = new Properties();
//client's username on httpURL proxy
properties.put(zyh.net.HttpURLSocket.USER,"abc");
//client's password on httpURL proxy
properties.put(zyh.net.HttpURLSocket.PASSWD,"efg");
zyh.net.HttpURLSocketImplFactory factory = new zyh.net.HttpURLSocketImplFactory( httpProxyHost, httpProxyPort, httpURLProxyURL, properties);
zyh.net.HttpURLSocket.setSocketImplFactory(factory);

 

Unifying the Programming Interface of Three Extended Sockets
Though it is more efficient to adopt the specific extended socket, SocksSocket, HttpSocket or HttpURlSocket for the specific client environment, Java programmers prefer less effort on programming and maintaining code work to more compact released package. SuperSocket and SuperSocketImplFactory are used in creating Socket, SocksSocket, HttpSocket and HttpURlSocket object through a uniform interface. SuperSocketImplFactory will choose automatically an appropriate socket between HttpSocket and HttpURlSocket if the essential setting is present. The specific usage is below: (Two examples using SuperSocket:  Example8.java and Example9.java)

// Create a Properties object to contain 
// some informations about proxy settings.
Properties properties=new Properties();

// Set the proxy type, SuperSocket.HTTP, 
// SuperSocket.SOCKS or SuperSocket.HTTPURL
properties.put(SuperSocket.PROXY_TYPE, SuperSocket.HTTP);
// Set the proxy host 
properties.put(SuperSocket.PROXY_HOST, proxyHost);
// Set the proxy port
// Set the url of HttpURL proxy
properties.put(SuperSocket.PROXY_PORT, ""+proxyPort); 
//Omit it for SOCKS proxy
properties.put(SuperSocket.httpURLProxyURL,httpURLProxyURL);
 

/*
//Use it to avoid the automatic choice between HTTP and HTTPURL
properties.put(SuperSocket.NOTEST,"SKIP");
//Set the username and password for authentication
properties.put(SuperSocket.USER,"abc");
properties.put(SuperSocket.PASSWD,"efg");
*/

// Create a SuperSocketImpl factory.
SuperSocketImplFactory factory=new SuperSocketImplFactory(properties);
// Used it for all SuperSockets create from now on.
SuperSocket.setSocketImplFactory(factory);

//Create a SuperSocket object
Socket socket=new SuperSocket(host,port);

Because all above extended socket classes in this article are constructed on the Socket class, and there is not any native code in all extended SocketImpl classes, Using "Socket.setSocketImplFactory(factory)" for the java.net.Socket class is not supported. They will work normally in applet program only when they have been granted the appropriate security right to communicate directly with proxy server.
 
 
 

Relative References
 1. SOCKS 4 Protocol: A protocol for TCP proxy across firewalls
 2. SOCKS 4A: A Simple Extension to SOCKS 4 Protocol
 3. SOCKS 5: RFC1928 SOCKS Protocol Version 5
 4. RFC1929 Username/Password Authentication for SOCKS V5
 5. SOCKS Protocol Version 5 (22 Feb 1999)
 6. RFC1945 Hypertext Transfer Protocol -- HTTP/1.0
 7. RFC2616 Hypertext Transfer Protocol -- HTTP/1.1
 8. RFC821 Simple Mail Transfer Protocol
 9. Networking Guide in Java2 SDK, Standard Edition Documentation
10. JDC Performance Tips and Firewall tunneling techniques

 

Chi volesse mettersi in contatto con la redazione può farlo scrivendo a mokainfo@mokabyte.it