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