]> Joshua Wise's Git repositories - dumload.git/blame - src/com/jcraft/jsch/ProxySOCKS5.java
Initial commit.
[dumload.git] / src / com / jcraft / jsch / ProxySOCKS5.java
CommitLineData
0763e16d
JW
1/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
2/*
3Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in
13 the documentation and/or other materials provided with the distribution.
14
15 3. The names of the authors may not be used to endorse or promote products
16 derived from this software without specific prior written permission.
17
18THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
19INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
21INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
22INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30/*
31 This file depends on following documents,
32 - RFC 1928 SOCKS Protocol Verseion 5
33 - RFC 1929 Username/Password Authentication for SOCKS V5.
34 */
35
36package com.jcraft.jsch;
37
38import java.io.*;
39import java.net.*;
40
41public class ProxySOCKS5 implements Proxy{
42 private static int DEFAULTPORT=1080;
43 private String proxy_host;
44 private int proxy_port;
45 private InputStream in;
46 private OutputStream out;
47 private Socket socket;
48 private String user;
49 private String passwd;
50
51 public ProxySOCKS5(String proxy_host){
52 int port=DEFAULTPORT;
53 String host=proxy_host;
54 if(proxy_host.indexOf(':')!=-1){
55 try{
56 host=proxy_host.substring(0, proxy_host.indexOf(':'));
57 port=Integer.parseInt(proxy_host.substring(proxy_host.indexOf(':')+1));
58 }
59 catch(Exception e){
60 }
61 }
62 this.proxy_host=host;
63 this.proxy_port=port;
64 }
65 public ProxySOCKS5(String proxy_host, int proxy_port){
66 this.proxy_host=proxy_host;
67 this.proxy_port=proxy_port;
68 }
69 public void setUserPasswd(String user, String passwd){
70 this.user=user;
71 this.passwd=passwd;
72 }
73 public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws JSchException{
74 try{
75 if(socket_factory==null){
76 socket=Util.createSocket(proxy_host, proxy_port, timeout);
77 //socket=new Socket(proxy_host, proxy_port);
78 in=socket.getInputStream();
79 out=socket.getOutputStream();
80 }
81 else{
82 socket=socket_factory.createSocket(proxy_host, proxy_port);
83 in=socket_factory.getInputStream(socket);
84 out=socket_factory.getOutputStream(socket);
85 }
86 if(timeout>0){
87 socket.setSoTimeout(timeout);
88 }
89 socket.setTcpNoDelay(true);
90
91 byte[] buf=new byte[1024];
92 int index=0;
93
94/*
95 +----+----------+----------+
96 |VER | NMETHODS | METHODS |
97 +----+----------+----------+
98 | 1 | 1 | 1 to 255 |
99 +----+----------+----------+
100
101 The VER field is set to X'05' for this version of the protocol. The
102 NMETHODS field contains the number of method identifier octets that
103 appear in the METHODS field.
104
105 The values currently defined for METHOD are:
106
107 o X'00' NO AUTHENTICATION REQUIRED
108 o X'01' GSSAPI
109 o X'02' USERNAME/PASSWORD
110 o X'03' to X'7F' IANA ASSIGNED
111 o X'80' to X'FE' RESERVED FOR PRIVATE METHODS
112 o X'FF' NO ACCEPTABLE METHODS
113*/
114
115 buf[index++]=5;
116
117 buf[index++]=2;
118 buf[index++]=0; // NO AUTHENTICATION REQUIRED
119 buf[index++]=2; // USERNAME/PASSWORD
120
121 out.write(buf, 0, index);
122
123/*
124 The server selects from one of the methods given in METHODS, and
125 sends a METHOD selection message:
126
127 +----+--------+
128 |VER | METHOD |
129 +----+--------+
130 | 1 | 1 |
131 +----+--------+
132*/
133 //in.read(buf, 0, 2);
134 fill(in, buf, 2);
135
136 boolean check=false;
137 switch((buf[1])&0xff){
138 case 0: // NO AUTHENTICATION REQUIRED
139 check=true;
140 break;
141 case 2: // USERNAME/PASSWORD
142 if(user==null || passwd==null)break;
143
144/*
145 Once the SOCKS V5 server has started, and the client has selected the
146 Username/Password Authentication protocol, the Username/Password
147 subnegotiation begins. This begins with the client producing a
148 Username/Password request:
149
150 +----+------+----------+------+----------+
151 |VER | ULEN | UNAME | PLEN | PASSWD |
152 +----+------+----------+------+----------+
153 | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
154 +----+------+----------+------+----------+
155
156 The VER field contains the current version of the subnegotiation,
157 which is X'01'. The ULEN field contains the length of the UNAME field
158 that follows. The UNAME field contains the username as known to the
159 source operating system. The PLEN field contains the length of the
160 PASSWD field that follows. The PASSWD field contains the password
161 association with the given UNAME.
162*/
163 index=0;
164 buf[index++]=1;
165 buf[index++]=(byte)(user.length());
166 System.arraycopy(Util.str2byte(user), 0, buf, index, user.length());
167 index+=user.length();
168 buf[index++]=(byte)(passwd.length());
169 System.arraycopy(Util.str2byte(passwd), 0, buf, index, passwd.length());
170 index+=passwd.length();
171
172 out.write(buf, 0, index);
173
174/*
175 The server verifies the supplied UNAME and PASSWD, and sends the
176 following response:
177
178 +----+--------+
179 |VER | STATUS |
180 +----+--------+
181 | 1 | 1 |
182 +----+--------+
183
184 A STATUS field of X'00' indicates success. If the server returns a
185 `failure' (STATUS value other than X'00') status, it MUST close the
186 connection.
187*/
188 //in.read(buf, 0, 2);
189 fill(in, buf, 2);
190 if(buf[1]==0)
191 check=true;
192 break;
193 default:
194 }
195
196 if(!check){
197 try{ socket.close(); }
198 catch(Exception eee){
199 }
200 throw new JSchException("fail in SOCKS5 proxy");
201 }
202
203/*
204 The SOCKS request is formed as follows:
205
206 +----+-----+-------+------+----------+----------+
207 |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
208 +----+-----+-------+------+----------+----------+
209 | 1 | 1 | X'00' | 1 | Variable | 2 |
210 +----+-----+-------+------+----------+----------+
211
212 Where:
213
214 o VER protocol version: X'05'
215 o CMD
216 o CONNECT X'01'
217 o BIND X'02'
218 o UDP ASSOCIATE X'03'
219 o RSV RESERVED
220 o ATYP address type of following address
221 o IP V4 address: X'01'
222 o DOMAINNAME: X'03'
223 o IP V6 address: X'04'
224 o DST.ADDR desired destination address
225 o DST.PORT desired destination port in network octet
226 order
227*/
228
229 index=0;
230 buf[index++]=5;
231 buf[index++]=1; // CONNECT
232 buf[index++]=0;
233
234 byte[] hostb=Util.str2byte(host);
235 int len=hostb.length;
236 buf[index++]=3; // DOMAINNAME
237 buf[index++]=(byte)(len);
238 System.arraycopy(hostb, 0, buf, index, len);
239 index+=len;
240 buf[index++]=(byte)(port>>>8);
241 buf[index++]=(byte)(port&0xff);
242
243 out.write(buf, 0, index);
244
245/*
246 The SOCKS request information is sent by the client as soon as it has
247 established a connection to the SOCKS server, and completed the
248 authentication negotiations. The server evaluates the request, and
249 returns a reply formed as follows:
250
251 +----+-----+-------+------+----------+----------+
252 |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
253 +----+-----+-------+------+----------+----------+
254 | 1 | 1 | X'00' | 1 | Variable | 2 |
255 +----+-----+-------+------+----------+----------+
256
257 Where:
258
259 o VER protocol version: X'05'
260 o REP Reply field:
261 o X'00' succeeded
262 o X'01' general SOCKS server failure
263 o X'02' connection not allowed by ruleset
264 o X'03' Network unreachable
265 o X'04' Host unreachable
266 o X'05' Connection refused
267 o X'06' TTL expired
268 o X'07' Command not supported
269 o X'08' Address type not supported
270 o X'09' to X'FF' unassigned
271 o RSV RESERVED
272 o ATYP address type of following address
273 o IP V4 address: X'01'
274 o DOMAINNAME: X'03'
275 o IP V6 address: X'04'
276 o BND.ADDR server bound address
277 o BND.PORT server bound port in network octet order
278*/
279
280 //in.read(buf, 0, 4);
281 fill(in, buf, 4);
282
283 if(buf[1]!=0){
284 try{ socket.close(); }
285 catch(Exception eee){
286 }
287 throw new JSchException("ProxySOCKS5: server returns "+buf[1]);
288 }
289
290 switch(buf[3]&0xff){
291 case 1:
292 //in.read(buf, 0, 6);
293 fill(in, buf, 6);
294 break;
295 case 3:
296 //in.read(buf, 0, 1);
297 fill(in, buf, 1);
298 //in.read(buf, 0, buf[0]+2);
299 fill(in, buf, (buf[0]&0xff)+2);
300 break;
301 case 4:
302 //in.read(buf, 0, 18);
303 fill(in, buf, 18);
304 break;
305 default:
306 }
307 }
308 catch(RuntimeException e){
309 throw e;
310 }
311 catch(Exception e){
312 try{ if(socket!=null)socket.close(); }
313 catch(Exception eee){
314 }
315 String message="ProxySOCKS5: "+e.toString();
316 if(e instanceof Throwable)
317 throw new JSchException(message, (Throwable)e);
318 throw new JSchException(message);
319 }
320 }
321 public InputStream getInputStream(){ return in; }
322 public OutputStream getOutputStream(){ return out; }
323 public Socket getSocket(){ return socket; }
324 public void close(){
325 try{
326 if(in!=null)in.close();
327 if(out!=null)out.close();
328 if(socket!=null)socket.close();
329 }
330 catch(Exception e){
331 }
332 in=null;
333 out=null;
334 socket=null;
335 }
336 public static int getDefaultPort(){
337 return DEFAULTPORT;
338 }
339 private void fill(InputStream in, byte[] buf, int len) throws JSchException, IOException{
340 int s=0;
341 while(s<len){
342 int i=in.read(buf, s, len-s);
343 if(i<=0){
344 throw new JSchException("ProxySOCKS5: stream is closed");
345 }
346 s+=i;
347 }
348 }
349}
This page took 0.047781 seconds and 4 git commands to generate.