1 | package nu.fw.jeti.plugins.filetransfer.socks5.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 | |
---|
14 | 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 | |
---|
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; |
---|
53 | |
---|
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 |
---|
59 | |
---|
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(); |
---|
83 | |
---|
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 | /** |
---|
112 | Initialises Message from the stream. Reads server response or client |
---|
113 | request from given stream. |
---|
114 | |
---|
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 | /** |
---|
142 | Initialises Message from the stream. Reads server response or client |
---|
143 | request from given stream. |
---|
144 | |
---|
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(Proxy.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(Proxy.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 | } |
---|
250 | |
---|
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 | } |
---|