Netty Socks5 代理服务器代码优化:解决代理无法正常工作问题
以下是修改后的代码:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.socks.*;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
public class Socks5Server {
private static ServerBootstrap serverBootstrap = new ServerBootstrap();
private static SocksInsideChannelInitializer channelInitializer = new SocksInsideChannelInitializer();
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.group(bossGroup, workerGroup);
serverBootstrap.childHandler(channelInitializer);
serverBootstrap.bind(52007).addListener(new GenericFutureListener<ChannelFuture>() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
System.out.println('socks-inside-server started, listening port: ' + 52007);
} else {
System.err.println('socks-inside-server failed to start');
future.cause().printStackTrace();
}
}
});
}
private static class SocksInsideChannelInitializer extends ChannelInitializer<Channel> {
private Socks5ProcessServerHandler socksProxyProcessHandler = new Socks5ProcessServerHandler();
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new SocksInitRequestDecoder());
ch.pipeline().addLast(new SocksMessageEncoder());
ch.pipeline().addLast(socksProxyProcessHandler);
}
}
}
package com.lijiatun.vpn.server.test;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.socks.*;
public class Socks5ProcessServerHandler extends SimpleChannelInboundHandler<SocksRequest> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, SocksRequest msg) throws Exception {
System.out.println(msg.requestType());
switch (msg.requestType()) {
case INIT:
ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
ctx.writeAndFlush(new SocksInitResponse(SocksAuthScheme.NO_AUTH));
break;
case AUTH:
ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
ctx.writeAndFlush(new SocksAuthResponse(SocksAuthStatus.SUCCESS));
break;
case CMD:
SocksCmdRequest req = (SocksCmdRequest) msg;
System.out.println(req.cmdType());
if (req.cmdType() == SocksCmdType.CONNECT) {
ctx.pipeline().addLast(new SocksServerHandler(ctx, req));
ctx.pipeline().remove(this);
ctx.fireChannelRead(msg);
} else {
ctx.close();
}
break;
case UNKNOWN:
ctx.close();
break;
default:
ctx.close();
break;
}
}
}
package com.lijiatun.vpn.server.test;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.socks.SocksAddressType;
import io.netty.handler.codec.socks.SocksCmdRequest;
import io.netty.handler.codec.socks.SocksCmdResponse;
import io.netty.handler.codec.socks.SocksCmdStatus;
class SocksServerHandler extends ChannelInboundHandlerAdapter {
private ChannelHandlerContext browserCtx;
private SocksCmdRequest req;
public SocksServerHandler(ChannelHandlerContext browserCtx, SocksCmdRequest req) {
this.browserCtx = browserCtx;
this.req = req;
}
@Override
public void channelRead(ChannelHandlerContext outsideProxyCtx, Object msg) throws Exception {
System.out.println(req.host());
System.out.println(req.port());
System.out.println(msg);
// 处理HTTP请求
if (msg instanceof FullHttpRequest) {
FullHttpRequest request = (FullHttpRequest) msg;
if (request.decoderResult().isSuccess()) {
// 获取请求的信息
String method = request.method().name();
String uri = request.uri();
String version = request.protocolVersion().text();
System.out.println('HTTP Request: ' + method + ' ' + uri + ' ' + version);
// 返回响应
String response = 'Hello World!';
FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.OK, Unpooled.wrappedBuffer(response.getBytes()));
httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, 'text/plain');
httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes());
outsideProxyCtx.writeAndFlush(httpResponse);
} else {
browserCtx.close();
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (ctx.channel().isActive()) {
ctx.channel().close();
}
}
}
代码解释:
-
Socks5Server:
- 使用
NioEventLoopGroup创建两个线程池,分别用于接收连接和处理连接。 - 使用
ServerBootstrap初始化服务器,绑定监听端口 52007。 - 使用
SocksInsideChannelInitializer初始化通道处理器,添加SocksInitRequestDecoder、SocksMessageEncoder和Socks5ProcessServerHandler处理器。
- 使用
-
SocksInsideChannelInitializer:
- 初始化通道处理器,添加必要的处理器。
-
Socks5ProcessServerHandler:
- 处理 Socks5 协议的请求,根据请求类型进行处理。
- 在
CMD请求类型下,添加SocksServerHandler处理器,并移除自身。
-
SocksServerHandler:
- 处理来自浏览器的 HTTP 请求,并返回响应。
使用说明:
- 将代码保存为
Socks5Server.java文件。 - 使用
javac Socks5Server.java命令编译代码。 - 使用
java Socks5Server命令运行代码。 - 使用代理软件,将 Socks5 代理地址设置为
localhost:52007。
注意事项:
- 该代码仅供参考,实际使用时需要根据具体需求进行修改。
- 该代码没有进行任何安全方面的处理,请勿在生产环境中使用。
- 该代码仅支持 Socks5 协议,不支持其他协议。
优化说明:
- 将
SocksServerHandler类改为ChannelInboundHandlerAdapter,并添加exceptionCaught方法处理异常。 - 在
SocksServerHandler类中,处理 HTTP 请求时,使用decoderResult().isSuccess()方法判断请求是否成功,如果失败则关闭连接。 - 使用
System.out.println打印调试信息,方便排查问题。
参考文档:
原文地址: https://www.cveoy.top/t/topic/oaff 著作权归作者所有。请勿转载和采集!