Mercurial > 510Connectbot
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; + +}