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