![JAR search and dependency download from the Maven repository](/logo.png)
cn.banny.rp.socks.bio.SocksHandler Maven / Gradle / Ivy
package cn.banny.rp.socks.bio;
import cn.banny.rp.socks.SocketFactory;
import cn.banny.rp.socks.SocketType;
import cn.banny.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.ExecutorService;
public class SocksHandler implements Runnable {
private static final Logger log = LoggerFactory.getLogger(SocksHandler.class);
private static final int CONNECT_TIMEOUT = 20000;
private static final int SO_TIMEOUT = 60000;
private final ExecutorService executorService;
private final Socket socket;
private final SocketFactory socketFactory;
SocksHandler(ExecutorService executorService, Socket socket, SocketFactory socketFactory) {
this.executorService = executorService;
this.socket = socket;
this.socketFactory = socketFactory;
}
public void handle() {
Thread thread = new Thread(this, getClass().getSimpleName() + "[" + socket + "]");
thread.setDaemon(true);
thread.start();
}
@Override
public void run() {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
socket.setSoTimeout(SO_TIMEOUT);
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
process(inputStream, outputStream);
} catch (IOException e) {
log.debug(e.getMessage(), e);
IOUtils.close(inputStream);
IOUtils.close(outputStream);
IOUtils.close(socket);
}
}
private void process(InputStream inputStream, OutputStream outputStream) throws IOException {
DataInputStream dis = new DataInputStream(inputStream);
byte v = dis.readByte();
switch (v) {
case 0x4:
handleConnectV4(dis, inputStream, outputStream);
break;
case 0x5:
handleV5(dis, inputStream, outputStream);
break;
default:
throw new IOException("Not socks request");
}
}
private Socket connectSocket(SocketType socketType, InetSocketAddress address) throws IOException {
if (socketFactory != null) {
return socketFactory.connectSocket(socketType, address);
}
Socket socket = new Socket();
try {
socket.setSoTimeout(SO_TIMEOUT);
socket.connect(address, CONNECT_TIMEOUT);
return socket;
} catch (IOException e) {
IOUtils.close(socket);
throw e;
}
}
private void handleV5(DataInputStream dis, InputStream inputStream, OutputStream outputStream) throws IOException {
DataOutputStream dos = new DataOutputStream(outputStream);
byte methods = dis.readByte();
for(int i = 0; i < methods; i++) {
dis.readByte();
}
dos.write(new byte[] { 0x5, 0x0 }); // no auth
dos.flush();
byte v = dis.readByte();
if (v != 5) {
throw new IOException("Unsupported handleConnect version: " + v);
}
byte ip = dis.readByte();
if(ip != 1) {
throw new IOException("Unsupported ip version type: " + ip);
}
dis.readByte();//0
final Socket socket;
DateFormat dateFormat = new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]");
StringBuilder builder = new StringBuilder(dateFormat.format(new Date())).append("PROXY => ");
byte addrType = dis.readByte();
if(addrType == 3) {//host
byte[] hb = new byte[dis.readUnsignedByte()];
dis.readFully(hb);
String host = new String(hb, StandardCharsets.UTF_8);
int port = dis.readUnsignedShort();
socket = connectSocket(SocketType.V5Host, new InetSocketAddress(host, port));
builder.append(host).append(":").append(port);
} else if(addrType == 1) {//address
byte[] ipv4 = new byte[4];
dis.readFully(ipv4);
int port = dis.readUnsignedShort();
InetAddress address = InetAddress.getByAddress(ipv4);
socket = connectSocket(SocketType.V5, new InetSocketAddress(address, port));
builder.append(address.getHostAddress()).append(":").append(port);
} else {
throw new IOException("Unsupported tcp address type: " + addrType);
}
InetSocketAddress socketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
byte[] ipv4 = socketAddress.getAddress().getAddress();
if (ipv4.length != 4) {
throw new IOException("ipv4 failed: " + Arrays.toString(ipv4));
}
dos.writeInt(0x5000001);
dos.write(ipv4);
dos.writeShort(socketAddress.getPort());
dos.flush();
ShutdownListener listener = new SocksShutdownListener(builder.toString());
executorService.submit(new StreamPipe(this.socket, inputStream, socket, socket.getOutputStream(), listener));
executorService.submit(new StreamPipe(socket, socket.getInputStream(), this.socket, outputStream, listener));
}
private void handleConnectV4(DataInputStream dis, InputStream inputStream, OutputStream outputStream) throws IOException {
DataOutputStream dos = new DataOutputStream(outputStream);
byte cd = dis.readByte();
if(cd != 1) {
throw new IOException("Unsupported socks CONNECT type: " + cd);
}
int port = dis.readUnsignedShort();
byte[] ipv4 = new byte[4];
dis.readFully(ipv4);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte b;
while((b = dis.readByte()) != 0) {
baos.write(b);
}
String user = new String(baos.toByteArray(), StandardCharsets.UTF_8);
log.debug("handleV4 user={}", user);
final Socket socket;
DateFormat dateFormat = new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]");
StringBuilder builder = new StringBuilder(dateFormat.format(new Date())).append("PROXY => ");
if(ipv4[0] == 0 && ipv4[1] == 0 && ipv4[2] == 0 && ipv4[3] != 0) { // socksv4a
baos.reset();
while((b = dis.readByte()) != 0) {
baos.write(b);
}
String host = new String(baos.toByteArray(), StandardCharsets.UTF_8);
socket = connectSocket(SocketType.V4A, new InetSocketAddress(host, port));
builder.append(host).append(":").append(port);
} else { // socksv4
InetAddress address = InetAddress.getByAddress(ipv4);
socket = connectSocket(SocketType.V4, new InetSocketAddress(address, port));
builder.append(address.getHostAddress()).append(":").append(port);
}
InetSocketAddress socketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
ipv4 = socketAddress.getAddress().getAddress();
if (ipv4.length != 4) {
throw new IOException("ipv4 failed: " + Arrays.toString(ipv4));
}
dos.writeShort(0x5a);
dos.writeShort(port);
dos.write(ipv4);
dos.flush();
ShutdownListener listener = new SocksShutdownListener(builder.toString());
executorService.submit(new StreamPipe(this.socket, inputStream, socket, socket.getOutputStream(), listener));
executorService.submit(new StreamPipe(socket, socket.getInputStream(), this.socket, outputStream, listener));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy