2013-02-07 15:19:47 +01:00
|
|
|
/**
|
|
|
|
* $RCSfile$
|
2013-02-07 20:10:22 +01:00
|
|
|
* $Revision$
|
|
|
|
* $Date$
|
2013-02-07 15:19:47 +01:00
|
|
|
*
|
|
|
|
* Copyright 2003-2007 Jive Software.
|
|
|
|
*
|
|
|
|
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2008-07-15 04:59:21 +02:00
|
|
|
package org.jivesoftware.smack.proxy;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.net.InetAddress;
|
|
|
|
import java.net.Socket;
|
|
|
|
import java.net.UnknownHostException;
|
|
|
|
import javax.net.SocketFactory;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Socket factory for socks4 proxy
|
|
|
|
*
|
|
|
|
* @author Atul Aggarwal
|
|
|
|
*/
|
|
|
|
public class Socks4ProxySocketFactory
|
|
|
|
extends SocketFactory
|
|
|
|
{
|
|
|
|
private ProxyInfo proxy;
|
|
|
|
|
|
|
|
public Socks4ProxySocketFactory(ProxyInfo proxy)
|
|
|
|
{
|
|
|
|
this.proxy = proxy;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Socket createSocket(String host, int port)
|
|
|
|
throws IOException, UnknownHostException
|
|
|
|
{
|
|
|
|
return socks4ProxifiedSocket(host,port);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public Socket createSocket(String host ,int port, InetAddress localHost,
|
|
|
|
int localPort)
|
|
|
|
throws IOException, UnknownHostException
|
|
|
|
{
|
|
|
|
return socks4ProxifiedSocket(host,port);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Socket createSocket(InetAddress host, int port)
|
|
|
|
throws IOException
|
|
|
|
{
|
|
|
|
return socks4ProxifiedSocket(host.getHostAddress(),port);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Socket createSocket( InetAddress address, int port,
|
|
|
|
InetAddress localAddress, int localPort)
|
|
|
|
throws IOException
|
|
|
|
{
|
|
|
|
return socks4ProxifiedSocket(address.getHostAddress(),port);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private Socket socks4ProxifiedSocket(String host, int port)
|
|
|
|
throws IOException
|
|
|
|
{
|
|
|
|
Socket socket = null;
|
|
|
|
InputStream in = null;
|
|
|
|
OutputStream out = null;
|
|
|
|
String proxy_host = proxy.getProxyAddress();
|
|
|
|
int proxy_port = proxy.getProxyPort();
|
|
|
|
String user = proxy.getProxyUsername();
|
|
|
|
String passwd = proxy.getProxyPassword();
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
socket=new Socket(proxy_host, proxy_port);
|
|
|
|
in=socket.getInputStream();
|
|
|
|
out=socket.getOutputStream();
|
|
|
|
socket.setTcpNoDelay(true);
|
|
|
|
|
|
|
|
byte[] buf=new byte[1024];
|
|
|
|
int index=0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
1) CONNECT
|
|
|
|
|
|
|
|
The client connects to the SOCKS server and sends a CONNECT request when
|
|
|
|
it wants to establish a connection to an application server. The client
|
|
|
|
includes in the request packet the IP address and the port number of the
|
|
|
|
destination host, and userid, in the following format.
|
|
|
|
|
|
|
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
|
|
|
| VN | CD | DSTPORT | DSTIP | USERID |NULL|
|
|
|
|
+----+----+----+----+----+----+----+----+----+----+....+----+
|
|
|
|
# of bytes: 1 1 2 4 variable 1
|
|
|
|
|
|
|
|
VN is the SOCKS protocol version number and should be 4. CD is the
|
|
|
|
SOCKS command code and should be 1 for CONNECT request. NULL is a byte
|
|
|
|
of all zero bits.
|
|
|
|
*/
|
|
|
|
|
|
|
|
index=0;
|
|
|
|
buf[index++]=4;
|
|
|
|
buf[index++]=1;
|
|
|
|
|
|
|
|
buf[index++]=(byte)(port>>>8);
|
|
|
|
buf[index++]=(byte)(port&0xff);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
InetAddress addr=InetAddress.getByName(host);
|
|
|
|
byte[] byteAddress = addr.getAddress();
|
|
|
|
for (int i = 0; i < byteAddress.length; i++)
|
|
|
|
{
|
|
|
|
buf[index++]=byteAddress[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(UnknownHostException uhe)
|
|
|
|
{
|
|
|
|
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4,
|
|
|
|
uhe.toString(), uhe);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(user!=null)
|
|
|
|
{
|
|
|
|
System.arraycopy(user.getBytes(), 0, buf, index, user.length());
|
|
|
|
index+=user.length();
|
|
|
|
}
|
|
|
|
buf[index++]=0;
|
|
|
|
out.write(buf, 0, index);
|
|
|
|
|
|
|
|
/*
|
|
|
|
The SOCKS server checks to see whether such a request should be granted
|
|
|
|
based on any combination of source IP address, destination IP address,
|
|
|
|
destination port number, the userid, and information it may obtain by
|
|
|
|
consulting IDENT, cf. RFC 1413. If the request is granted, the SOCKS
|
|
|
|
server makes a connection to the specified port of the destination host.
|
|
|
|
A reply packet is sent to the client when this connection is established,
|
|
|
|
or when the request is rejected or the operation fails.
|
|
|
|
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
| VN | CD | DSTPORT | DSTIP |
|
|
|
|
+----+----+----+----+----+----+----+----+
|
|
|
|
# of bytes: 1 1 2 4
|
|
|
|
|
|
|
|
VN is the version of the reply code and should be 0. CD is the result
|
|
|
|
code with one of the following values:
|
|
|
|
|
|
|
|
90: request granted
|
|
|
|
91: request rejected or failed
|
|
|
|
92: request rejected becasue SOCKS server cannot connect to
|
|
|
|
identd on the client
|
|
|
|
93: request rejected because the client program and identd
|
|
|
|
report different user-ids
|
|
|
|
|
|
|
|
The remaining fields are ignored.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int len=6;
|
|
|
|
int s=0;
|
|
|
|
while(s<len)
|
|
|
|
{
|
|
|
|
int i=in.read(buf, s, len-s);
|
|
|
|
if(i<=0)
|
|
|
|
{
|
|
|
|
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4,
|
|
|
|
"stream is closed");
|
|
|
|
}
|
|
|
|
s+=i;
|
|
|
|
}
|
|
|
|
if(buf[0]!=0)
|
|
|
|
{
|
|
|
|
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4,
|
|
|
|
"server returns VN "+buf[0]);
|
|
|
|
}
|
|
|
|
if(buf[1]!=90)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
socket.close();
|
|
|
|
}
|
|
|
|
catch(Exception eee)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
String message="ProxySOCKS4: server returns CD "+buf[1];
|
|
|
|
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4,message);
|
|
|
|
}
|
|
|
|
byte[] temp = new byte[2];
|
|
|
|
in.read(temp, 0, 2);
|
|
|
|
return socket;
|
|
|
|
}
|
|
|
|
catch(RuntimeException e)
|
|
|
|
{
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
catch(Exception e)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if(socket!=null)socket.close();
|
|
|
|
}
|
|
|
|
catch(Exception eee)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
throw new ProxyException(ProxyInfo.ProxyType.SOCKS4, e.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|