package net.tools.web; import java.io.*; import java.net.*; public class TunnelClient implements Runnable { private static String tunnelurl; private static void toBytes(long l, byte[] b, int offset, int len) { for(int i = 0; i < len; i++) b[i + offset] = (byte) (l >> (len * 8 - 8 - i * 8)); } private static long fromBytes(byte[] b, int offset, int len) { long l = 0; for(int i = 0; i < len; i++) l |= ((long) (b[i + offset] & 0x00ff)) << (len * 8 - 8 - i * 8); return l; } private static void writeTo(InputStream in, OutputStream out, byte[] buf) throws IOException { if(buf == null) buf = new byte[65536]; int len; while((len = in.read(buf)) > 0) { out.write(buf, 0, len); out.flush(); } } private static int readByte(InputStream in) throws IOException { int b = in.read(); if(b < 0) throw new EOFException(); return b; } private static void fill(InputStream in, byte[] buf, int offset, int len) throws IOException { while(len > 0) { int n = in.read(buf, offset, len); if(n <= 0) throw new EOFException(); offset += n; len -= n; } } private static class Tunnelling implements Runnable { private Socket ssock; private InputStream in; private OutputStream out; private byte[] sessionId; private String tunnelurl; private Tunnelling(Socket ssock, InputStream in, OutputStream out, byte[] sessionId, String tunnelurl) { this.ssock = ssock; this.in = in; this.out = out; this.sessionId = sessionId; this.tunnelurl = tunnelurl; } public void run() { byte[] buf = new byte[65536]; try { while(true) { URLConnection conn = new URL(tunnelurl).openConnection(); conn.setDoOutput(true); OutputStream out = conn.getOutputStream(); out.write(2); out.write(sessionId); out.flush(); InputStream in = conn.getInputStream(); if(in.read() != 1) throw new EOFException(); writeTo(in, ssock.getOutputStream(), buf); } } catch (IOException e) { //e.printStackTrace(); } finally { try { ssock.close(); } catch (Exception e) {} try { in.close(); } catch (Exception e) {} try { out.close(); } catch (Exception e) {} try { URLConnection conn = new URL(tunnelurl).openConnection(); OutputStream out = conn.getOutputStream(); out.write(4); out.write(sessionId); out.flush(); conn.getInputStream(); } catch (Exception e) {} } } } private Socket ssock; private TunnelClient(Socket ssock) { this.ssock = ssock; } public void run() { InputStream in = null; try { OutputStream sout = ssock.getOutputStream(); InputStream sin = ssock.getInputStream(); readByte(sin); int len = readByte(sin); for(int i = 0; i < len; i++) readByte(sin); sout.write(5); sout.write(0); readByte(sin); int cmd = readByte(sin); readByte(sin); int addrtype = readByte(sin); String remoteaddress = null; byte[] buf = new byte[65536]; switch(addrtype) { case 1: { remoteaddress = "" + readByte(sin); for(int i = 1; i < 4; i++) { remoteaddress += "."; remoteaddress += readByte(sin); } } break; case 3: { len = readByte(sin); fill(sin, buf, 0, len); remoteaddress = new String(buf, 0, len); } break; case 4: throw new IOException("No accept address type 4"); default: throw new IOException("No accept address type " + addrtype); } fill(sin, buf, 0, 2); switch(cmd) { case 1: URLConnection conn = new URL(tunnelurl).openConnection(); conn.setDoOutput(true); OutputStream out = conn.getOutputStream(); out.write(1); byte[] addr = remoteaddress.getBytes(); out.write(addr.length); out.write(addr); out.write(buf, 0, 2);//port out.flush(); in = conn.getInputStream(); if(readByte(in) != 1) throw new EOFException(); byte[] sessionId = new byte[8]; fill(in, sessionId, 0, 8); sout.write(5); sout.write(0); sout.write(0); sout.write(1); sout.write(0); sout.write(0); sout.write(0); sout.write(0); sout.write(0); sout.write(0); sout.flush(); new Thread(new Tunnelling(ssock, in, sout, sessionId, tunnelurl)).start(); while((len = sin.read(buf)) > 0) { conn = new URL(tunnelurl).openConnection(); conn.setDoOutput(true); out = conn.getOutputStream(); out.write(3); out.write(sessionId); out.write(buf, 0, len); out.flush(); if(conn.getInputStream().read() != 1) throw new EOFException(); } break; case 2: throw new IOException("No accept command."); case 3: throw new IOException("No accept command."); default: throw new IOException("No accept command."); } } catch (IOException e) { //e.printStackTrace(); } finally { try { ssock.close(); } catch (Exception e) {} try { in.close(); } catch (Exception e) {} } } public static void main(String[] args) throws Exception { ServerSocket sssock = new ServerSocket(Integer.parseInt(args[0])); tunnelurl = args[1]; while(true) { Socket ssock = sssock.accept(); new Thread(new TunnelClient(ssock)).start(); } } }