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