
cc.owoo.godpen.network.proxy.ProxyServer Maven / Gradle / Ivy
package cc.owoo.godpen.network.proxy;
import cc.owoo.godpen.network.InputStreamBuilder;
import cc.owoo.godpen.network.SocketUtil;
import cc.owoo.godpen.network.http.Method;
import cc.owoo.godpen.network.http.Request;
import cc.owoo.godpen.network.http.Response;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Socket5代理服务器
* Created by nimensei
* 2022-07-24 下午 01:58
**/
public class ProxyServer {
private final int port;// 端口号
private ServerSocket serverSocket;// 服务器socket
private OnCreateTCP onCreateTCP;// 创建Socket对象
public ProxyServer(int port) {
this.port = port;
}
/**
* 启动
*/
public void start() throws IOException {
synchronized (this) {
if (serverSocket != null)
return;
serverSocket = SocketUtil.server(port, this::handler, () -> serverSocket = null);
}
}
/**
* 处理连接
*
* @param socket 连接的socket
*/
private void handler(Socket socket) {
try {
int head = socket.getInputStream().read();
if ((head >= 'a' && head <= 'z') || (head >= 'A' && head <= 'Z'))
http(head, socket);
else if (head == 5)
socket5(socket);
} catch (IOException ignored) {
}
try {
socket.close();
} catch (IOException ignored) {
}
}
/**
* HTTP隧道代理
*
* @param head 头字节
* @param client 连接的socket
*/
private void http(int head, Socket client) throws IOException {
InputStreamBuilder inputStreamBuilder = new InputStreamBuilder();
inputStreamBuilder.append(head);
inputStreamBuilder.append(client.getInputStream());
Request request = new Request();
request.read(inputStreamBuilder);
inputStreamBuilder.clear();
if (request.isInvalid())
return;
request.readBytes();
String hostName = request.getHostName();
if (hostName == null)
return;
int port = request.getPort();
if (port < 1)
port = request.getSchemeNotNull().equals("https") ? 443 : 80;
Socket target;
try {
target = new Socket(hostName, port);
} catch (IOException e) {
new Response(400, "socket error: " + e.getMessage()).write(client.getOutputStream());
return;
}
if (request.isMethod(Method.CONNECT))
new Response(200, "Connection established")
.write(client.getOutputStream());
else
request.write(target.getOutputStream());
SocketUtil.socketBindAndClose(client, target);
}
/**
* Socket5代理
*
* @param socket 连接的Socket
*/
private void socket5(Socket socket) throws IOException {
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
int cut = inputStream.read();
if (cut == -1)
return;
byte[] method = inputStream.readNBytes(cut);
if (method[0] != 0)
return;
outputStream.write(new byte[]{5, 0});
outputStream.flush();
int ver = inputStream.read();
int cmd = inputStream.read();
int rsv = inputStream.read();
int aType = inputStream.read();
if (ver != 5 || (cmd != 1 && cmd != 3) || rsv == -1 || aType == -1)
return;
InetAddress inetAddress;
byte[] addressBytes;
switch (aType) {
case 1 -> {
addressBytes = inputStream.readNBytes(4);
if (addressBytes == null || addressBytes.length != 4)
return;
inetAddress = InetAddress.getByAddress(addressBytes);
}
case 3 -> {
int len = inputStream.read();
if (len == -1)
return;
byte[] domain = inputStream.readNBytes(len);
if (domain == null || domain.length != len)
return;
inetAddress = InetAddress.getByName(new String(domain));
addressBytes = inetAddress.getAddress();
aType = addressBytes.length == 4 ? 1 : 4;
}
case 4 -> {
addressBytes = inputStream.readNBytes(16);
if (addressBytes == null || addressBytes.length != 16)
return;
inetAddress = InetAddress.getByAddress(addressBytes);
}
default -> {
return;
}
}
int portBit1 = inputStream.read();
int portBit2 = inputStream.read();
if (portBit1 == -1 || portBit2 == -1)
return;
int port = portBit1 << 8 | portBit2;
outputStream.write(new byte[]{(byte) ver, 0, 0, (byte) aType});
outputStream.write(addressBytes);
outputStream.write(portBit1);
outputStream.write(portBit2);
outputStream.flush();
if (cmd == 1)
tcp(socket, inetAddress, port);
else
udp(socket, inetAddress, port);
}
/**
* 建立TPC代理连接
*
* @param client 代理客户端
* @param inetAddress 目标地址
* @param port 目标端口
* @throws IOException 发生异常
*/
private void tcp(Socket client, InetAddress inetAddress, int port) throws IOException {
Socket socket;
if (onCreateTCP == null)
socket = new Socket(inetAddress, port);
else
socket = onCreateTCP.create(inetAddress, port);
if (socket == null)
return;
SocketUtil.socketBindAndClose(client, socket);
}
/**
* 建立UDP代理连接
*
* @param client 代理客户端
* @param inetAddress 目标地址
* @param port 目标端口
* @throws IOException 发生异常
*/
private void udp(Socket client, InetAddress inetAddress, int port) throws IOException {
// TODO UDP代理协议
}
public void setOnCreateSocket(OnCreateTCP onCreateTCP) {
this.onCreateTCP = onCreateTCP;
}
/**
* 关闭服务器
*
* @throws IOException 关闭异常
*/
public void close() throws IOException {
synchronized (this) {
if (serverSocket == null)
return;
serverSocket.close();
}
}
/**
* 创建TCP Socket对象
*/
public interface OnCreateTCP {
/**
* 创建连接
*
* @param inetAddress 地址
* @param port 端口号
* @return 创建的Socket对象
* @throws IOException 创建异常
*/
Socket create(InetAddress inetAddress, int port) throws IOException;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy