]> Joshua Wise's Git repositories - dumload.git/blob - src/com/jcraft/jsch/ProxySOCKS5.java
Initial commit.
[dumload.git] / src / com / jcraft / jsch / ProxySOCKS5.java
1 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
2 /*
3 Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, 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
18 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
21 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 EVEN 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
36 package com.jcraft.jsch;
37
38 import java.io.*;
39 import java.net.*;
40
41 public 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.040291 seconds and 4 git commands to generate.