0
|
1 package net.sourceforge.jsocks;
|
|
2
|
|
3 import java.io.DataInputStream;
|
|
4 import java.io.IOException;
|
|
5 import java.io.InputStream;
|
|
6 import java.io.OutputStream;
|
|
7 import java.net.InetAddress;
|
|
8 import java.net.UnknownHostException;
|
|
9
|
|
10 /**
|
|
11 SOCKS5 request/response message.
|
|
12 */
|
|
13
|
|
14 public class Socks5Message extends ProxyMessage {
|
|
15 /** Address type of given message*/
|
|
16 public int addrType;
|
|
17
|
|
18 byte[] data;
|
|
19
|
|
20 /**
|
|
21 Server error response.
|
|
22 @param cmd Error code.
|
|
23 */
|
|
24 public Socks5Message(int cmd) {
|
|
25 super(cmd, null, 0);
|
|
26 data = new byte[3];
|
|
27 data[0] = SOCKS_VERSION; //Version.
|
|
28 data[1] = (byte)cmd; //Reply code for some kind of failure.
|
|
29 data[2] = 0; //Reserved byte.
|
|
30 }
|
|
31
|
|
32 /**
|
|
33 Construct client request or server response.
|
|
34 @param cmd - Request/Response code.
|
|
35 @param ip - IP field.
|
|
36 @paarm port - port field.
|
|
37 */
|
|
38 public Socks5Message(int cmd, InetAddress ip, int port) {
|
|
39 super(cmd, ip, port);
|
|
40 this.host = ip == null ? "0.0.0.0" : ip.getHostName();
|
|
41 this.version = SOCKS_VERSION;
|
|
42 byte[] addr;
|
|
43
|
|
44 if (ip == null) {
|
|
45 addr = new byte[4];
|
|
46 addr[0] = addr[1] = addr[2] = addr[3] = 0;
|
|
47 }
|
|
48 else
|
|
49 addr = ip.getAddress();
|
|
50
|
|
51 addrType = addr.length == 4 ? SOCKS_ATYP_IPV4
|
|
52 : SOCKS_ATYP_IPV6;
|
|
53 data = new byte[6 + addr.length];
|
|
54 data[0] = (byte) SOCKS_VERSION; //Version
|
|
55 data[1] = (byte) command; //Command
|
|
56 data[2] = (byte) 0; //Reserved byte
|
|
57 data[3] = (byte) addrType; //Address type
|
|
58 //Put Address
|
|
59 System.arraycopy(addr, 0, data, 4, addr.length);
|
|
60 //Put port
|
|
61 data[data.length - 2] = (byte)(port >> 8);
|
|
62 data[data.length - 1] = (byte)(port);
|
|
63 }
|
|
64
|
|
65
|
|
66 /**
|
|
67 Construct client request or server response.
|
|
68 @param cmd - Request/Response code.
|
|
69 @param hostName - IP field as hostName, uses ADDR_TYPE of HOSTNAME.
|
|
70 @paarm port - port field.
|
|
71 */
|
|
72 public Socks5Message(int cmd, String hostName, int port) {
|
|
73 super(cmd, null, port);
|
|
74 this.host = hostName;
|
|
75 this.version = SOCKS_VERSION;
|
|
76 //System.out.println("Doing ATYP_DOMAINNAME");
|
|
77 addrType = SOCKS_ATYP_DOMAINNAME;
|
|
78 byte addr[] = hostName.getBytes();
|
|
79 data = new byte[7 + addr.length];
|
|
80 data[0] = (byte) SOCKS_VERSION; //Version
|
|
81 data[1] = (byte) command; //Command
|
|
82 data[2] = (byte) 0; //Reserved byte
|
|
83 data[3] = (byte) SOCKS_ATYP_DOMAINNAME; //Address type
|
|
84 data[4] = (byte) addr.length; //Length of the address
|
|
85 //Put Address
|
|
86 System.arraycopy(addr, 0, data, 5, addr.length);
|
|
87 //Put port
|
|
88 data[data.length - 2] = (byte)(port >> 8);
|
|
89 data[data.length - 1] = (byte)(port);
|
|
90 }
|
|
91
|
|
92 /**
|
|
93 Initialises Message from the stream. Reads server response from
|
|
94 given stream.
|
|
95 @param in Input stream to read response from.
|
|
96 @throws SocksException If server response code is not SOCKS_SUCCESS(0), or
|
|
97 if any error with protocol occurs.
|
|
98 @throws IOException If any error happens with I/O.
|
|
99 */
|
|
100 public Socks5Message(InputStream in) throws SocksException,
|
|
101 IOException {
|
|
102 this(in, true);
|
|
103 }
|
|
104
|
|
105 /**
|
|
106 Initialises Message from the stream. Reads server response or client
|
|
107 request from given stream.
|
|
108
|
|
109 @param in Input stream to read response from.
|
|
110 @param clinetMode If true read server response, else read client request.
|
|
111 @throws SocksException If server response code is not SOCKS_SUCCESS(0) and
|
|
112 reading in client mode, or if any error with protocol occurs.
|
|
113 @throws IOException If any error happens with I/O.
|
|
114 */
|
|
115 public Socks5Message(InputStream in, boolean clientMode)throws SocksException,
|
|
116 IOException {
|
|
117 read(in, clientMode);
|
|
118 }
|
|
119
|
|
120
|
|
121 /**
|
|
122 Initialises Message from the stream. Reads server response from
|
|
123 given stream.
|
|
124 @param in Input stream to read response from.
|
|
125 @throws SocksException If server response code is not SOCKS_SUCCESS(0), or
|
|
126 if any error with protocol occurs.
|
|
127 @throws IOException If any error happens with I/O.
|
|
128 */
|
|
129 public void read(InputStream in) throws SocksException,
|
|
130 IOException {
|
|
131 read(in, true);
|
|
132 }
|
|
133
|
|
134
|
|
135 /**
|
|
136 Initialises Message from the stream. Reads server response or client
|
|
137 request from given stream.
|
|
138
|
|
139 @param in Input stream to read response from.
|
|
140 @param clinetMode If true read server response, else read client request.
|
|
141 @throws SocksException If server response code is not SOCKS_SUCCESS(0) and
|
|
142 reading in client mode, or if any error with protocol occurs.
|
|
143 @throws IOException If any error happens with I/O.
|
|
144 */
|
|
145 public void read(InputStream in, boolean clientMode) throws SocksException,
|
|
146 IOException {
|
|
147 data = null;
|
|
148 ip = null;
|
|
149 DataInputStream di = new DataInputStream(in);
|
|
150 version = di.readUnsignedByte();
|
|
151 command = di.readUnsignedByte();
|
|
152
|
|
153 if (clientMode && command != 0)
|
|
154 throw new SocksException(command);
|
|
155
|
|
156 @SuppressWarnings("unused")
|
|
157 int reserved = di.readUnsignedByte();
|
|
158 addrType = di.readUnsignedByte();
|
|
159 byte addr[];
|
|
160
|
|
161 switch (addrType) {
|
|
162 case SOCKS_ATYP_IPV4:
|
|
163 addr = new byte[4];
|
|
164 di.readFully(addr);
|
|
165 host = bytes2IPV4(addr, 0);
|
|
166 break;
|
|
167
|
|
168 case SOCKS_ATYP_IPV6:
|
|
169 addr = new byte[SOCKS_IPV6_LENGTH];//I believe it is 16 bytes,huge!
|
|
170 di.readFully(addr);
|
|
171 host = bytes2IPV6(addr, 0);
|
|
172 break;
|
|
173
|
|
174 case SOCKS_ATYP_DOMAINNAME:
|
|
175 //System.out.println("Reading ATYP_DOMAINNAME");
|
|
176 addr = new byte[di.readUnsignedByte()];//Next byte shows the length
|
|
177 di.readFully(addr);
|
|
178 host = new String(addr);
|
|
179 break;
|
|
180
|
|
181 default:
|
|
182 throw(new SocksException(Proxy.SOCKS_JUST_ERROR));
|
|
183 }
|
|
184
|
|
185 port = di.readUnsignedShort();
|
|
186
|
|
187 if (addrType != SOCKS_ATYP_DOMAINNAME && doResolveIP) {
|
|
188 try {
|
|
189 ip = InetAddress.getByName(host);
|
|
190 }
|
|
191 catch (UnknownHostException uh_ex) {
|
|
192 }
|
|
193 }
|
|
194 }
|
|
195
|
|
196 /**
|
|
197 Writes the message to the stream.
|
|
198 @param out Output stream to which message should be written.
|
|
199 */
|
|
200 public void write(OutputStream out)throws SocksException,
|
|
201 IOException {
|
|
202 if (data == null) {
|
|
203 Socks5Message msg;
|
|
204
|
|
205 if (addrType == SOCKS_ATYP_DOMAINNAME)
|
|
206 msg = new Socks5Message(command, host, port);
|
|
207 else {
|
|
208 if (ip == null) {
|
|
209 try {
|
|
210 ip = InetAddress.getByName(host);
|
|
211 }
|
|
212 catch (UnknownHostException uh_ex) {
|
|
213 throw new SocksException(Proxy.SOCKS_JUST_ERROR);
|
|
214 }
|
|
215 }
|
|
216
|
|
217 msg = new Socks5Message(command, ip, port);
|
|
218 }
|
|
219
|
|
220 data = msg.data;
|
|
221 }
|
|
222
|
|
223 out.write(data);
|
|
224 }
|
|
225
|
|
226 /**
|
|
227 Returns IP field of the message as IP, if the message was created
|
|
228 with ATYP of HOSTNAME, it will attempt to resolve the hostname,
|
|
229 which might fail.
|
|
230 @throws UnknownHostException if host can't be resolved.
|
|
231 */
|
|
232 public InetAddress getInetAddress() throws UnknownHostException {
|
|
233 if (ip != null) return ip;
|
|
234
|
|
235 return (ip = InetAddress.getByName(host));
|
|
236 }
|
|
237
|
|
238 /**
|
|
239 Returns string representation of the message.
|
|
240 */
|
|
241 public String toString() {
|
|
242 String s =
|
|
243 "Socks5Message:" + "\n" +
|
|
244 "VN " + version + "\n" +
|
|
245 "CMD " + command + "\n" +
|
|
246 "ATYP " + addrType + "\n" +
|
|
247 "ADDR " + host + "\n" +
|
|
248 "PORT " + port + "\n";
|
|
249 return s;
|
|
250 }
|
|
251
|
|
252
|
|
253 /**
|
|
254 *Wether to resolve hostIP returned from SOCKS server
|
|
255 *that is wether to create InetAddress object from the
|
|
256 *hostName string
|
|
257 */
|
|
258 static public boolean resolveIP() { return doResolveIP;}
|
|
259
|
|
260 /**
|
|
261 *Wether to resolve hostIP returned from SOCKS server
|
|
262 *that is wether to create InetAddress object from the
|
|
263 *hostName string
|
|
264 *@param doResolve Wether to resolve hostIP from SOCKS server.
|
|
265 *@return Previous value.
|
|
266 */
|
|
267 static public boolean resolveIP(boolean doResolve) {
|
|
268 boolean old = doResolveIP;
|
|
269 doResolveIP = doResolve;
|
|
270 return old;
|
|
271 }
|
|
272
|
|
273 /*
|
|
274 private static final void debug(String s){
|
|
275 if(DEBUG)
|
|
276 System.out.print(s);
|
|
277 }
|
|
278 private static final boolean DEBUG = false;
|
|
279 */
|
|
280
|
|
281 //SOCKS5 constants
|
|
282 public static final int SOCKS_VERSION = 5;
|
|
283
|
|
284 public static final int SOCKS_ATYP_IPV4 = 0x1; //Where is 2??
|
|
285 public static final int SOCKS_ATYP_DOMAINNAME = 0x3; //!!!!rfc1928
|
|
286 public static final int SOCKS_ATYP_IPV6 = 0x4;
|
|
287
|
|
288 public static final int SOCKS_IPV6_LENGTH = 16;
|
|
289
|
|
290 static boolean doResolveIP = true;
|
|
291
|
|
292 }
|