mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-27 08:42:07 +01:00
200 lines
6.1 KiB
Java
200 lines
6.1 KiB
Java
|
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());
|
||
|
}
|
||
|
}
|
||
|
}
|