diff src/net/sourceforge/jsocks/Socks5Message.java @ 0:0ce5cc452d02

initial version
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 10:41:19 -0700
parents
children 205ee2873330
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/net/sourceforge/jsocks/Socks5Message.java	Thu May 22 10:41:19 2014 -0700
@@ -0,0 +1,292 @@
+package net.sourceforge.jsocks;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ SOCKS5 request/response message.
+*/
+
+public class Socks5Message extends ProxyMessage {
+    /** Address type of given message*/
+    public int addrType;
+
+    byte[] data;
+
+    /**
+     Server error response.
+     @param cmd Error code.
+    */
+    public Socks5Message(int cmd) {
+        super(cmd, null, 0);
+        data = new byte[3];
+        data[0] = SOCKS_VERSION; //Version.
+        data[1] = (byte)cmd;     //Reply code for some kind of failure.
+        data[2] = 0;             //Reserved byte.
+    }
+
+    /**
+     Construct client request or server response.
+     @param cmd - Request/Response code.
+     @param ip  - IP field.
+     @paarm port - port field.
+    */
+    public Socks5Message(int cmd, InetAddress ip, int port) {
+        super(cmd, ip, port);
+        this.host = ip == null ? "0.0.0.0" : ip.getHostName();
+        this.version = SOCKS_VERSION;
+        byte[] addr;
+
+        if (ip == null) {
+            addr = new byte[4];
+            addr[0] = addr[1] = addr[2] = addr[3] = 0;
+        }
+        else
+            addr = ip.getAddress();
+
+        addrType = addr.length == 4 ? SOCKS_ATYP_IPV4
+                   : SOCKS_ATYP_IPV6;
+        data = new byte[6 + addr.length];
+        data[0] = (byte) SOCKS_VERSION;       //Version
+        data[1] = (byte) command;         //Command
+        data[2] = (byte) 0;           //Reserved byte
+        data[3] = (byte) addrType;        //Address type
+        //Put Address
+        System.arraycopy(addr, 0, data, 4, addr.length);
+        //Put port
+        data[data.length - 2] = (byte)(port >> 8);
+        data[data.length - 1] = (byte)(port);
+    }
+
+
+    /**
+     Construct client request or server response.
+     @param cmd - Request/Response code.
+     @param hostName  - IP field as hostName, uses ADDR_TYPE of HOSTNAME.
+     @paarm port - port field.
+    */
+    public Socks5Message(int cmd, String hostName, int port) {
+        super(cmd, null, port);
+        this.host = hostName;
+        this.version = SOCKS_VERSION;
+        //System.out.println("Doing ATYP_DOMAINNAME");
+        addrType = SOCKS_ATYP_DOMAINNAME;
+        byte addr[] = hostName.getBytes();
+        data = new byte[7 + addr.length];
+        data[0] = (byte) SOCKS_VERSION;       //Version
+        data[1] = (byte) command;         //Command
+        data[2] = (byte) 0;           //Reserved byte
+        data[3] = (byte) SOCKS_ATYP_DOMAINNAME;   //Address type
+        data[4] = (byte) addr.length;     //Length of the address
+        //Put Address
+        System.arraycopy(addr, 0, data, 5, addr.length);
+        //Put port
+        data[data.length - 2] = (byte)(port >> 8);
+        data[data.length - 1] = (byte)(port);
+    }
+
+    /**
+      Initialises Message from the stream. Reads server response from
+      given stream.
+      @param in Input stream to read response from.
+      @throws SocksException If server response code is not SOCKS_SUCCESS(0), or
+      if any error with protocol occurs.
+      @throws IOException If any error happens with I/O.
+    */
+    public Socks5Message(InputStream in) throws SocksException,
+        IOException {
+        this(in, true);
+    }
+
+    /**
+      Initialises Message from the stream. Reads server response or client
+      request from given stream.
+
+      @param in Input stream to read response from.
+      @param clinetMode If true read server response, else read client request.
+      @throws SocksException If server response code is not SOCKS_SUCCESS(0) and
+      reading in client mode, or if any error with protocol occurs.
+      @throws IOException If any error happens with I/O.
+    */
+    public Socks5Message(InputStream in, boolean clientMode)throws SocksException,
+        IOException {
+        read(in, clientMode);
+    }
+
+
+    /**
+      Initialises Message from the stream. Reads server response from
+      given stream.
+      @param in Input stream to read response from.
+      @throws SocksException If server response code is not SOCKS_SUCCESS(0), or
+      if any error with protocol occurs.
+      @throws IOException If any error happens with I/O.
+    */
+    public void read(InputStream in) throws SocksException,
+        IOException {
+        read(in, true);
+    }
+
+
+    /**
+      Initialises Message from the stream. Reads server response or client
+      request from given stream.
+
+      @param in Input stream to read response from.
+      @param clinetMode If true read server response, else read client request.
+      @throws SocksException If server response code is not SOCKS_SUCCESS(0) and
+      reading in client mode, or if any error with protocol occurs.
+      @throws IOException If any error happens with I/O.
+    */
+    public void read(InputStream in, boolean clientMode) throws SocksException,
+        IOException {
+        data = null;
+        ip = null;
+        DataInputStream di = new DataInputStream(in);
+        version = di.readUnsignedByte();
+        command = di.readUnsignedByte();
+
+        if (clientMode && command != 0)
+            throw new SocksException(command);
+
+        @SuppressWarnings("unused")
+        int reserved = di.readUnsignedByte();
+        addrType = di.readUnsignedByte();
+        byte addr[];
+
+        switch (addrType) {
+            case SOCKS_ATYP_IPV4:
+                addr = new byte[4];
+                di.readFully(addr);
+                host = bytes2IPV4(addr, 0);
+                break;
+
+            case SOCKS_ATYP_IPV6:
+                addr = new byte[SOCKS_IPV6_LENGTH];//I believe it is 16 bytes,huge!
+                di.readFully(addr);
+                host = bytes2IPV6(addr, 0);
+                break;
+
+            case SOCKS_ATYP_DOMAINNAME:
+                //System.out.println("Reading ATYP_DOMAINNAME");
+                addr = new byte[di.readUnsignedByte()];//Next byte shows the length
+                di.readFully(addr);
+                host = new String(addr);
+                break;
+
+            default:
+                throw(new SocksException(Proxy.SOCKS_JUST_ERROR));
+        }
+
+        port = di.readUnsignedShort();
+
+        if (addrType != SOCKS_ATYP_DOMAINNAME && doResolveIP) {
+            try {
+                ip = InetAddress.getByName(host);
+            }
+            catch (UnknownHostException uh_ex) {
+            }
+        }
+    }
+
+    /**
+     Writes the message to the stream.
+     @param out Output stream to which message should be written.
+    */
+    public void write(OutputStream out)throws SocksException,
+        IOException {
+        if (data == null) {
+            Socks5Message msg;
+
+            if (addrType == SOCKS_ATYP_DOMAINNAME)
+                msg = new Socks5Message(command, host, port);
+            else {
+                if (ip == null) {
+                    try {
+                        ip = InetAddress.getByName(host);
+                    }
+                    catch (UnknownHostException uh_ex) {
+                        throw new SocksException(Proxy.SOCKS_JUST_ERROR);
+                    }
+                }
+
+                msg = new Socks5Message(command, ip, port);
+            }
+
+            data = msg.data;
+        }
+
+        out.write(data);
+    }
+
+    /**
+     Returns IP field of the message as IP, if the message was created
+     with ATYP of HOSTNAME, it will attempt to resolve the hostname,
+     which might fail.
+     @throws UnknownHostException if host can't be resolved.
+    */
+    public InetAddress getInetAddress() throws UnknownHostException {
+        if (ip != null) return ip;
+
+        return (ip = InetAddress.getByName(host));
+    }
+
+    /**
+      Returns string representation of the message.
+    */
+    public String toString() {
+        String s =
+            "Socks5Message:" + "\n" +
+            "VN   " + version + "\n" +
+            "CMD  " + command + "\n" +
+            "ATYP " + addrType + "\n" +
+            "ADDR " + host + "\n" +
+            "PORT " + port + "\n";
+        return s;
+    }
+
+
+    /**
+     *Wether to resolve hostIP returned from SOCKS server
+     *that is wether to create InetAddress object from the
+     *hostName string
+     */
+    static public boolean resolveIP() { return doResolveIP;}
+
+    /**
+     *Wether to resolve hostIP returned from SOCKS server
+     *that is wether to create InetAddress object from the
+     *hostName string
+     *@param doResolve Wether to resolve hostIP from SOCKS server.
+     *@return Previous value.
+     */
+    static public boolean resolveIP(boolean doResolve) {
+        boolean old = doResolveIP;
+        doResolveIP = doResolve;
+        return old;
+    }
+
+    /*
+    private static final void debug(String s){
+       if(DEBUG)
+          System.out.print(s);
+    }
+    private static final boolean DEBUG = false;
+    */
+
+    //SOCKS5 constants
+    public static final int SOCKS_VERSION        = 5;
+
+    public static final int SOCKS_ATYP_IPV4      = 0x1; //Where is 2??
+    public static final int SOCKS_ATYP_DOMAINNAME    = 0x3; //!!!!rfc1928
+    public static final int SOCKS_ATYP_IPV6      = 0x4;
+
+    public static final int SOCKS_IPV6_LENGTH        = 16;
+
+    static boolean doResolveIP = true;
+
+}