Netty 实现 Socks5 代理服务器:代码示例与优化
import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.socks.SocksAuthResponse; import io.netty.handler.codec.socks.SocksCmdRequest; import io.netty.handler.codec.socks.SocksCmdRequestDecoder; import io.netty.handler.codec.socks.SocksCmdResponse; import io.netty.handler.codec.socks.SocksCmdStatus; import io.netty.handler.codec.socks.SocksInitRequestDecoder; import io.netty.handler.codec.socks.SocksInitResponse; import io.netty.handler.codec.socks.SocksMessageEncoder; import io.netty.handler.codec.socks.SocksRequest; import io.netty.handler.codec.socks.SocksServerHandler; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.handler.codec.socks.SocksAddressType; import io.netty.handler.codec.socks.SocksCmdType;
public class Socks5Server { private static ServerBootstrap serverBootstrap = new ServerBootstrap(); private static SocksInsideChannelInitializer channelInitializer = new SocksInsideChannelInitializer();
public static void main(String[] args) throws Exception {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.group(bossGroup, workerGroup);
serverBootstrap.childHandler(channelInitializer);
serverBootstrap.bind(52007).addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> future) throws Exception {
System.out.println('socks-inside-server started, listening port: ' + 52007);
}
});
}
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);
}
}
@ChannelHandler.Sharable
private static class Socks5ProcessServerHandler extends SimpleChannelInboundHandler<SocksRequest> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, SocksRequest msg) throws Exception {
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;
if (req.cmdType() == SocksCmdType.CONNECT) {
ctx.pipeline().addLast(new SocksServerHandler());
ctx.pipeline().remove(this);
ctx.fireChannelRead(msg);
} else {
ctx.close();
}
break;
case UNKNOWN:
ctx.close();
break;
default:
ctx.close();
break;
}
}
}
private static class SocksServerHandler extends SimpleChannelInboundHandler<SocksCmdRequest> {
@Override
protected void channelRead0(final ChannelHandlerContext browserCtx, final SocksCmdRequest msg) throws Exception {
if (msg.host() == null || msg.host().isEmpty()) {
browserCtx.close();
return;
}
browserCtx.pipeline().remove(this);
browserCtx.pipeline().addLast(new SocksHandler(browserCtx, msg));
browserCtx.channel().writeAndFlush(new SocksCmdResponse(SocksCmdStatus.SUCCESS, SocksAddressType.IPv4));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (ctx.channel().isActive()) {
ctx.channel().close();
}
}
}
private static class SocksHandler extends ChannelInboundHandlerAdapter {
private ChannelHandlerContext browserCtx;
private SocksCmdRequest req;
public SocksHandler(ChannelHandlerContext browserCtx, SocksCmdRequest req) {
this.browserCtx = browserCtx;
this.req = req;
}
@Override
public void channelRead(ChannelHandlerContext outsideProxyCtx, Object msg) throws Exception {
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();
}
}
}
}
}
原文地址: https://www.cveoy.top/t/topic/oafL 著作权归作者所有。请勿转载和采集!