
org.jivesoftware.smack.proxy.Socks4ProxySocketFactory Maven / Gradle / Ivy
/**
*
* 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.
*/
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());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy