ProxySOCKS5.java

Go to the documentation of this file.
00001 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
00002 /*
00003 Copyright (c) 2002-2011 ymnk, JCraft,Inc. All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007 
00008   1. Redistributions of source code must retain the above copyright notice,
00009      this list of conditions and the following disclaimer.
00010 
00011   2. Redistributions in binary form must reproduce the above copyright 
00012      notice, this list of conditions and the following disclaimer in 
00013      the documentation and/or other materials provided with the distribution.
00014 
00015   3. The names of the authors may not be used to endorse or promote products
00016      derived from this software without specific prior written permission.
00017 
00018 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
00019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
00020 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
00021 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
00022 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00023 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00024 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00025 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00026 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00027 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028 */
00029 
00030 /*
00031  This file depends on following documents,
00032    - RFC 1928  SOCKS Protocol Verseion 5  
00033    - RFC 1929  Username/Password Authentication for SOCKS V5. 
00034  */
00035 
00036 package com.jcraft.jsch;
00037 
00038 import java.io.*;
00039 import java.net.*;
00040 
00041 
00051 public class ProxySOCKS5 implements Proxy{
00052   private static int DEFAULTPORT=1080;
00053   private String proxy_host;
00054   private int proxy_port;
00055   private InputStream in;
00056   private OutputStream out;
00057   private Socket socket;
00058   private String user;
00059   private String passwd;
00060 
00066   public ProxySOCKS5(String proxy_host){
00067     int port=DEFAULTPORT;
00068     String host=proxy_host;
00069     if(proxy_host.indexOf(':')!=-1){
00070       try{
00071     host=proxy_host.substring(0, proxy_host.indexOf(':'));
00072     port=Integer.parseInt(proxy_host.substring(proxy_host.indexOf(':')+1));
00073       }
00074       catch(Exception e){
00075       }
00076     }
00077     this.proxy_host=host;
00078     this.proxy_port=port;
00079   }
00080 
00086   public ProxySOCKS5(String proxy_host, int proxy_port){
00087     this.proxy_host=proxy_host;
00088     this.proxy_port=proxy_port;
00089   }
00090 
00105   public void setUserPasswd(String user, String passwd){
00106     this.user=user;
00107     this.passwd=passwd;
00108   }
00109 
00110   // javadoc from interface -- P.E.
00111   public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws JSchException{
00112     try{
00113       if(socket_factory==null){
00114         socket=Util.createSocket(proxy_host, proxy_port, timeout);
00115         //socket=new Socket(proxy_host, proxy_port);    
00116         in=socket.getInputStream();
00117         out=socket.getOutputStream();
00118       }
00119       else{
00120         socket=socket_factory.createSocket(proxy_host, proxy_port);
00121         in=socket_factory.getInputStream(socket);
00122         out=socket_factory.getOutputStream(socket);
00123       }
00124       if(timeout>0){
00125         socket.setSoTimeout(timeout);
00126       }
00127       socket.setTcpNoDelay(true);
00128 
00129       byte[] buf=new byte[1024];
00130       int index=0;
00131 
00132 /*
00133                    +----+----------+----------+
00134                    |VER | NMETHODS | METHODS  |
00135                    +----+----------+----------+
00136                    | 1  |    1     | 1 to 255 |
00137                    +----+----------+----------+
00138 
00139    The VER field is set to X'05' for this version of the protocol.  The
00140    NMETHODS field contains the number of method identifier octets that
00141    appear in the METHODS field.
00142 
00143    The values currently defined for METHOD are:
00144 
00145           o  X'00' NO AUTHENTICATION REQUIRED
00146           o  X'01' GSSAPI
00147           o  X'02' USERNAME/PASSWORD
00148           o  X'03' to X'7F' IANA ASSIGNED
00149           o  X'80' to X'FE' RESERVED FOR PRIVATE METHODS
00150           o  X'FF' NO ACCEPTABLE METHODS
00151 */
00152 
00153       buf[index++]=5;           // version
00154 
00155       buf[index++]=2;           // nmethods
00156 
00157       buf[index++]=0;           // NO AUTHENTICATION REQUIRED
00158       buf[index++]=2;           // USERNAME/PASSWORD
00159 
00160       // Shouldn't we send the USERNAME/PASSWORD
00161       // only if a username + password was actually
00162       // specified with setUserPasswd() ?  -- P.E.
00163 
00164       out.write(buf, 0, index);
00165 
00166 /*
00167     The server selects from one of the methods given in METHODS, and
00168     sends a METHOD selection message:
00169 
00170                          +----+--------+
00171                          |VER | METHOD |
00172                          +----+--------+
00173                          | 1  |   1    |
00174                          +----+--------+
00175 */
00176       //in.read(buf, 0, 2);
00177       fill(in, buf, 2);
00178  
00179       boolean check=false;
00180       switch((buf[1])&0xff){
00181         case 0:                // NO AUTHENTICATION REQUIRED
00182           check=true;
00183           break;
00184         case 2:                // USERNAME/PASSWORD
00185           if(user==null || passwd==null)break;
00186 
00187 /*
00188    Once the SOCKS V5 server has started, and the client has selected the
00189    Username/Password Authentication protocol, the Username/Password
00190    subnegotiation begins.  This begins with the client producing a
00191    Username/Password request:
00192 
00193            +----+------+----------+------+----------+
00194            |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
00195            +----+------+----------+------+----------+
00196            | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
00197            +----+------+----------+------+----------+
00198 
00199    The VER field contains the current version of the subnegotiation,
00200    which is X'01'. The ULEN field contains the length of the UNAME field
00201    that follows. The UNAME field contains the username as known to the
00202    source operating system. The PLEN field contains the length of the
00203    PASSWD field that follows. The PASSWD field contains the password
00204    association with the given UNAME.
00205 */
00206           index=0;
00207           buf[index++]=1;
00208           buf[index++]=(byte)(user.length());
00209       System.arraycopy(Util.str2byte(user), 0, buf, index, user.length());
00210       index+=user.length();
00211           buf[index++]=(byte)(passwd.length());
00212       System.arraycopy(Util.str2byte(passwd), 0, buf, index, passwd.length());
00213       index+=passwd.length();
00214 
00215           out.write(buf, 0, index);
00216 
00217 /*
00218    The server verifies the supplied UNAME and PASSWD, and sends the
00219    following response:
00220 
00221                         +----+--------+
00222                         |VER | STATUS |
00223                         +----+--------+
00224                         | 1  |   1    |
00225                         +----+--------+
00226 
00227    A STATUS field of X'00' indicates success. If the server returns a
00228    `failure' (STATUS value other than X'00') status, it MUST close the
00229    connection.
00230 */
00231           //in.read(buf, 0, 2);
00232           fill(in, buf, 2);
00233           if(buf[1]==0)
00234             check=true;
00235           break;
00236         default:
00237       }
00238 
00239       if(!check){
00240         try{ socket.close(); }
00241     catch(Exception eee){
00242     }
00243         throw new JSchException("fail in SOCKS5 proxy");
00244       }
00245 
00246 /*
00247       The SOCKS request is formed as follows:
00248 
00249         +----+-----+-------+------+----------+----------+
00250         |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
00251         +----+-----+-------+------+----------+----------+
00252         | 1  |  1  | X'00' |  1   | Variable |    2     |
00253         +----+-----+-------+------+----------+----------+
00254 
00255       Where:
00256 
00257       o  VER    protocol version: X'05'
00258       o  CMD
00259          o  CONNECT X'01'
00260          o  BIND X'02'
00261          o  UDP ASSOCIATE X'03'
00262       o  RSV    RESERVED
00263          o  ATYP   address type of following address
00264          o  IP V4 address: X'01'
00265          o  DOMAINNAME: X'03'
00266          o  IP V6 address: X'04'
00267       o  DST.ADDR       desired destination address
00268       o  DST.PORT desired destination port in network octet
00269          order
00270 */
00271      
00272       index=0;
00273       buf[index++]=5;
00274       buf[index++]=1;       // CONNECT
00275       buf[index++]=0;
00276 
00277       byte[] hostb=Util.str2byte(host);
00278       int len=hostb.length;
00279       buf[index++]=3;      // DOMAINNAME
00280       buf[index++]=(byte)(len);
00281       System.arraycopy(hostb, 0, buf, index, len);
00282       index+=len;
00283       buf[index++]=(byte)(port>>>8);
00284       buf[index++]=(byte)(port&0xff);
00285 
00286       out.write(buf, 0, index);
00287 
00288 /*
00289    The SOCKS request information is sent by the client as soon as it has
00290    established a connection to the SOCKS server, and completed the
00291    authentication negotiations.  The server evaluates the request, and
00292    returns a reply formed as follows:
00293 
00294         +----+-----+-------+------+----------+----------+
00295         |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
00296         +----+-----+-------+------+----------+----------+
00297         | 1  |  1  | X'00' |  1   | Variable |    2     |
00298         +----+-----+-------+------+----------+----------+
00299 
00300    Where:
00301 
00302    o  VER    protocol version: X'05'
00303    o  REP    Reply field:
00304       o  X'00' succeeded
00305       o  X'01' general SOCKS server failure
00306       o  X'02' connection not allowed by ruleset
00307       o  X'03' Network unreachable
00308       o  X'04' Host unreachable
00309       o  X'05' Connection refused
00310       o  X'06' TTL expired
00311       o  X'07' Command not supported
00312       o  X'08' Address type not supported
00313       o  X'09' to X'FF' unassigned
00314     o  RSV    RESERVED
00315     o  ATYP   address type of following address
00316       o  IP V4 address: X'01'
00317       o  DOMAINNAME: X'03'
00318       o  IP V6 address: X'04'
00319     o  BND.ADDR       server bound address
00320     o  BND.PORT       server bound port in network octet order
00321 */
00322 
00323       //in.read(buf, 0, 4);
00324       fill(in, buf, 4);
00325 
00326       if(buf[1]!=0){
00327         try{ socket.close(); }
00328     catch(Exception eee){
00329     }
00330         throw new JSchException("ProxySOCKS5: server returns "+buf[1]);
00331       }
00332 
00333       switch(buf[3]&0xff){
00334         case 1:
00335           //in.read(buf, 0, 6);
00336           fill(in, buf, 6);
00337       break;
00338         case 3:
00339           //in.read(buf, 0, 1);
00340           fill(in, buf, 1);
00341           //in.read(buf, 0, buf[0]+2);
00342           fill(in, buf, (buf[0]&0xff)+2);
00343       break;
00344         case 4:
00345           //in.read(buf, 0, 18);
00346           fill(in, buf, 18);
00347           break;
00348         default:
00349       }
00350     }
00351     catch(RuntimeException e){
00352       throw e;
00353     }
00354     catch(Exception e){
00355       try{ if(socket!=null)socket.close(); }
00356       catch(Exception eee){
00357       }
00358       String message="ProxySOCKS5: "+e.toString();
00359       if(e instanceof Throwable)
00360         throw new JSchException(message, (Throwable)e);
00361       throw new JSchException(message);
00362     }
00363   }
00364   // javadoc from interface -- P.E.
00365   public InputStream getInputStream(){ return in; }
00366   // javadoc from interface -- P.E.
00367   public OutputStream getOutputStream(){ return out; }
00368   // javadoc from interface -- P.E.
00369   public Socket getSocket(){ return socket; }
00370   // javadoc from interface -- P.E.
00371   public void close(){
00372     try{
00373       if(in!=null)in.close();
00374       if(out!=null)out.close();
00375       if(socket!=null)socket.close();
00376     }
00377     catch(Exception e){
00378     }
00379     in=null;
00380     out=null;
00381     socket=null;
00382   }
00383 
00387   public static int getDefaultPort(){
00388     return DEFAULTPORT;
00389   }
00390 
00391   private void fill(InputStream in, byte[] buf, int len) throws JSchException, IOException{
00392     int s=0;
00393     while(s<len){
00394       int i=in.read(buf, s, len-s);
00395       if(i<=0){
00396         throw new JSchException("ProxySOCKS5: stream is closed");
00397       }
00398       s+=i;
00399     }
00400   }
00401 }

Generated on 5 May 2015 for HPCVIEWER by  doxygen 1.6.1