1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$ 3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$ 4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$ 5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); 7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License. 8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at 9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * http://www.apache.org/licenses/LICENSE-2.0 11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software 13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS, 14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and 16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License. 17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smack.proxy; 19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.IOException; 21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.InputStream; 22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.OutputStream; 23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.InetAddress; 24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.Socket; 25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.UnknownHostException; 26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport javax.net.SocketFactory; 27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Socket factory for socks4 proxy 30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Atul Aggarwal 32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class Socks4ProxySocketFactory 34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen extends SocketFactory 35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen{ 36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private ProxyInfo proxy; 37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public Socks4ProxySocketFactory(ProxyInfo proxy) 39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.proxy = proxy; 41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public Socket createSocket(String host, int port) 44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throws IOException, UnknownHostException 45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return socks4ProxifiedSocket(host,port); 47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public Socket createSocket(String host ,int port, InetAddress localHost, 51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen int localPort) 52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throws IOException, UnknownHostException 53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return socks4ProxifiedSocket(host,port); 55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public Socket createSocket(InetAddress host, int port) 58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throws IOException 59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return socks4ProxifiedSocket(host.getHostAddress(),port); 61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public Socket createSocket( InetAddress address, int port, 64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen InetAddress localAddress, int localPort) 65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throws IOException 66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return socks4ProxifiedSocket(address.getHostAddress(),port); 68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private Socket socks4ProxifiedSocket(String host, int port) 72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throws IOException 73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Socket socket = null; 75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen InputStream in = null; 76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen OutputStream out = null; 77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String proxy_host = proxy.getProxyAddress(); 78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen int proxy_port = proxy.getProxyPort(); 79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String user = proxy.getProxyUsername(); 80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String passwd = proxy.getProxyPassword(); 81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try 83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen socket=new Socket(proxy_host, proxy_port); 85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen in=socket.getInputStream(); 86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen out=socket.getOutputStream(); 87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen socket.setTcpNoDelay(true); 88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen byte[] buf=new byte[1024]; 90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen int index=0; 91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* 93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 1) CONNECT 94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen The client connects to the SOCKS server and sends a CONNECT request when 96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen it wants to establish a connection to an application server. The client 97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen includes in the request packet the IP address and the port number of the 98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen destination host, and userid, in the following format. 99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen +----+----+----+----+----+----+----+----+----+----+....+----+ 101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen | VN | CD | DSTPORT | DSTIP | USERID |NULL| 102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen +----+----+----+----+----+----+----+----+----+----+....+----+ 103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen # of bytes: 1 1 2 4 variable 1 104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen VN is the SOCKS protocol version number and should be 4. CD is the 106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen SOCKS command code and should be 1 for CONNECT request. NULL is a byte 107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen of all zero bits. 108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen index=0; 111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen buf[index++]=4; 112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen buf[index++]=1; 113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen buf[index++]=(byte)(port>>>8); 115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen buf[index++]=(byte)(port&0xff); 116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try 118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen InetAddress addr=InetAddress.getByName(host); 120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen byte[] byteAddress = addr.getAddress(); 121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (int i = 0; i < byteAddress.length; i++) 122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen buf[index++]=byteAddress[i]; 124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen catch(UnknownHostException uhe) 127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new ProxyException(ProxyInfo.ProxyType.SOCKS4, 129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen uhe.toString(), uhe); 130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if(user!=null) 133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen System.arraycopy(user.getBytes(), 0, buf, index, user.length()); 135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen index+=user.length(); 136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen buf[index++]=0; 138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen out.write(buf, 0, index); 139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* 141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen The SOCKS server checks to see whether such a request should be granted 142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen based on any combination of source IP address, destination IP address, 143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen destination port number, the userid, and information it may obtain by 144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen consulting IDENT, cf. RFC 1413. If the request is granted, the SOCKS 145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen server makes a connection to the specified port of the destination host. 146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen A reply packet is sent to the client when this connection is established, 147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen or when the request is rejected or the operation fails. 148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen +----+----+----+----+----+----+----+----+ 150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen | VN | CD | DSTPORT | DSTIP | 151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen +----+----+----+----+----+----+----+----+ 152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen # of bytes: 1 1 2 4 153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen VN is the version of the reply code and should be 0. CD is the result 155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen code with one of the following values: 156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 90: request granted 158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 91: request rejected or failed 159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 92: request rejected becasue SOCKS server cannot connect to 160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen identd on the client 161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 93: request rejected because the client program and identd 162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen report different user-ids 163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen The remaining fields are ignored. 165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen int len=6; 168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen int s=0; 169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen while(s<len) 170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen int i=in.read(buf, s, len-s); 172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if(i<=0) 173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new ProxyException(ProxyInfo.ProxyType.SOCKS4, 175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen "stream is closed"); 176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen s+=i; 178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if(buf[0]!=0) 180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new ProxyException(ProxyInfo.ProxyType.SOCKS4, 182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen "server returns VN "+buf[0]); 183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if(buf[1]!=90) 185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try 187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen socket.close(); 189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen catch(Exception eee) 191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String message="ProxySOCKS4: server returns CD "+buf[1]; 194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new ProxyException(ProxyInfo.ProxyType.SOCKS4,message); 195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen byte[] temp = new byte[2]; 197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen in.read(temp, 0, 2); 198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return socket; 199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen catch(RuntimeException e) 201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw e; 203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen catch(Exception e) 205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try 207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if(socket!=null)socket.close(); 209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen catch(Exception eee) 211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen { 212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new ProxyException(ProxyInfo.ProxyType.SOCKS4, e.toString()); 214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen} 217