Saturday, May 19, 2012

NetCat in Java

Recently, I tried to run netcat under Windows and I failed to compile it. So I decided to write a simple equivalent in Java, which works under all platforms.

NetCat is a very simple and useful tool, which allows to see contents of TCP/IP requests, like HTTP etc., both server and client side. With NetCat it is possible to either set up TCP/IP listener on a port and receive data or send TCP/IP request to remote server.

The code and executable for Java version of NetCat is available on GitHub:
http://github.com/rafalrusin/netcat/downloads

I used Jakarta Commons CLI to handle commandline parameters. The code is as simple as that:

public static void main(String[] args) throws Exception {
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("l", "listen", false, "listen mode");
options.addOption("p", "port", true, "port number");
CommandLine line = parser.parse(options, args);
if (line.hasOption('l')) {
if (line.hasOption('p')) {
int port = Integer.parseInt(line.getOptionValue('p'));
listen(port);
}
} else {
if (line.hasOption('p')) {
int port = Integer.parseInt(line.getOptionValue('p'));
connect(line.getArgs()[0], port);
} else {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("netcat [OPTIONS] <HOST>", options);
}
}
}


In order to handle stream I/O I implemented a simple StreamTransferer class like this:

public class StreamTransferer implements Runnable {
private InputStream input;
private OutputStream output;
public StreamTransferer(InputStream input, OutputStream output) {
this.input = input;
this.output = output;
}
@Override
public void run() {
try {
PrintWriter writer = new PrintWriter(output);
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line;
while ((line = reader.readLine()) != null) {
writer.println(line);
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}


The only issue I had was that whenever I closed Java I/O stream using OutputStream.close(), it was closing the whole socket. So I couldn't receive any response back from server. So instead of doing that I had to use Socket shutdownOutput method, like in the code below.

private static void transferStreams(Socket socket) throws IOException,
InterruptedException {
InputStream input1 = System.in;
OutputStream output1 = socket.getOutputStream();
InputStream input2 = socket.getInputStream();
PrintStream output2 = System.out;
Thread thread1 = new Thread(new StreamTransferer(input1, output1));
Thread thread2 = new Thread(new StreamTransferer(input2, output2));
thread1.start();
thread2.start();
thread1.join();
socket.shutdownOutput();
thread2.join();
}


It worked perfectly then.

So it is possible to send HTTP GET requests to google using this tool. In order to do that, you need to connect to google.com and type GET and enter. CTRL+Z and enter is for closing input stream under Windows. CTRL+D is for Linux. The example looks like below:

$ java -jar netcat.jar google.com -p 80
Connecting to google.com port 80
GET
HTTP/1.0 302 Found
Location: http://www.google.pl/
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Set-Cookie: PREF=ID=d3ab73f155cad978:FF=0:TM=1337454744:LM=1337454744:S=q7r3IZqRmvlnVqwn; expires=Mon, 19-May-2014 19:12:24 GMT; path=/; domain=.google.com
Set-Cookie: NID=59=j3omC2VT9csLVOvUOZdmom-YTRVeXXWUEc6FoMnUrMh_4HBFS1MStyT5tN4rzC1846-wmuXros8ZFYUPyBIP5l9kwF6z4nMtyNmXmGhByd15Zrlhwj-NxNmeuu9mrbJU; expires=Sun
, 18-Nov-2012 19:12:24 GMT; path=/; domain=.google.com; HttpOnly
P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
Date: Sat, 19 May 2012 19:12:24 GMT
Server: gws
Content-Length: 218
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.pl/">here</A>.
</BODY></HTML>
^Z