From 98587b442c00bdc5e06bc1d8beec5b7cb00f2819 Mon Sep 17 00:00:00 2001 From: wujiawei <12345678> Date: Wed, 30 Apr 2025 13:54:40 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90fix=E3=80=91=20=E6=B7=BB=E5=8A=A0socke?= =?UTF-8?q?t5=E4=BB=A3=E7=90=86demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../socket5/Client2DestInboundHandler.java | 60 ++++++++++++++++ .../socket5/Dest2ClientInboundHandler.java | 53 ++++++++++++++ .../socket5/Socks5CommandRequestHandler.java | 66 +++++++++++++++++ .../socket5/Socks5InitialRequestHandler.java | 34 +++++++++ ...cks5PasswordAuthRequestInboundHandler.java | 28 ++++++++ .../protocol/socket5/Socks5ProxyServer.java | 71 +++++++++++++++++++ .../socket5/Socks5ServerConnectHandler.java | 42 +++++++++++ 7 files changed, 354 insertions(+) create mode 100644 wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Client2DestInboundHandler.java create mode 100644 wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Dest2ClientInboundHandler.java create mode 100644 wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5CommandRequestHandler.java create mode 100644 wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5InitialRequestHandler.java create mode 100644 wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5PasswordAuthRequestInboundHandler.java create mode 100644 wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5ProxyServer.java create mode 100644 wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5ServerConnectHandler.java diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Client2DestInboundHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Client2DestInboundHandler.java new file mode 100644 index 0000000..209bc85 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Client2DestInboundHandler.java @@ -0,0 +1,60 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.socket5; + + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.ReferenceCountUtil; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * @author kdyzm + * @date 2021-04-23 + */ +@Slf4j +public class Client2DestInboundHandler extends ChannelInboundHandlerAdapter { + + private final ChannelFuture dstChannelFuture; + + public Client2DestInboundHandler(ChannelFuture dstChannelFuture) { + this.dstChannelFuture = dstChannelFuture; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + ctx.writeAndFlush(Unpooled.EMPTY_BUFFER); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + log.info("转发客户端的请求到代理服务器"); + if (dstChannelFuture.channel().isActive()) { + dstChannelFuture.channel().writeAndFlush(msg); + } else { + log.info("释放内存"); + ReferenceCountUtil.release(msg); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + log.info("客户端与代理服务器的连接已经断开,即将断开代理服务器和目标服务器的连接"); + if (dstChannelFuture.channel().isActive()) { + if (ctx.channel().isActive()) { + ctx.channel().writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error("Client2DestInboundHandler exception", cause); + ctx.close(); + } +} diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Dest2ClientInboundHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Dest2ClientInboundHandler.java new file mode 100644 index 0000000..9ccc770 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Dest2ClientInboundHandler.java @@ -0,0 +1,53 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.socket5; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.util.ReferenceCountUtil; +import lombok.extern.slf4j.Slf4j; + +/** + * @author kdyzm + * @date 2021-04-24 + */ +@Slf4j +public class Dest2ClientInboundHandler extends ChannelInboundHandlerAdapter { + + private final ChannelHandlerContext clientChannelHandlerContext; + + public Dest2ClientInboundHandler(ChannelHandlerContext clientChannelHandlerContext) { + this.clientChannelHandlerContext = clientChannelHandlerContext; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + ctx.writeAndFlush(Unpooled.EMPTY_BUFFER); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + log.trace("开始写回客户端数据"); + if (clientChannelHandlerContext.channel().isActive()) { + clientChannelHandlerContext.writeAndFlush(msg); + } else { + log.info("释放内存"); + ReferenceCountUtil.release(msg); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + log.trace("代理服务器和目标服务器的连接已经断开,即将断开客户端和代理服务器的连接"); + if (clientChannelHandlerContext.channel().isActive()) { + clientChannelHandlerContext.channel().writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error("Dest2ClientInboundHandler exception", cause); + ctx.close(); + } +} diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5CommandRequestHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5CommandRequestHandler.java new file mode 100644 index 0000000..ab67cf9 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5CommandRequestHandler.java @@ -0,0 +1,66 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.socket5; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.socksx.v5.*; +import io.netty.util.ReferenceCountUtil; +import lombok.extern.slf4j.Slf4j; + +import java.net.InetSocketAddress; + +@Slf4j +public class Socks5CommandRequestHandler extends SimpleChannelInboundHandler { + private final EventLoopGroup group; + + public Socks5CommandRequestHandler(EventLoopGroup group) { + this.group = group; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Socks5CommandRequest request) throws Exception { + if (request.type() == Socks5CommandType.CONNECT) { + Bootstrap b = new Bootstrap(); + b.group(group) + .channel(NioSocketChannel.class) + .option(ChannelOption.TCP_NODELAY, true) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(new Dest2ClientInboundHandler(ctx)); + } + }); + log.info("准备连接目标服务器,ip={},port={}", request.dstAddr(), request.dstPort()); + ChannelFuture f = b.connect(new InetSocketAddress(request.dstAddr(), request.dstPort())); + f.addListener((ChannelFutureListener) future -> { + + if (future.isSuccess()) { + log.info("目标服务器连接成功"); + //添加客户端转发请求到服务端的Handler + ctx.pipeline().addLast(new Client2DestInboundHandler(future)); + DefaultSocks5CommandResponse commandResponse = new DefaultSocks5CommandResponse(Socks5CommandStatus.SUCCESS, request.dstAddrType()); + ctx.writeAndFlush(commandResponse); + ctx.pipeline().remove(Socks5CommandRequestHandler.class); + ctx.pipeline().remove(Socks5CommandRequestDecoder.class); + } else { + log.error("连接目标服务器失败,address={},port={}", request.dstAddr(), request.dstPort()); + DefaultSocks5CommandResponse commandResponse = new DefaultSocks5CommandResponse(Socks5CommandStatus.FAILURE, request.dstAddrType()); + ctx.writeAndFlush(commandResponse); + future.channel().close(); + } + + }); + } else { + log.info("receive commandRequest type={}", request.type()); + ReferenceCountUtil.retain(request); + ctx.fireChannelRead(request); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + ctx.close(); + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5InitialRequestHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5InitialRequestHandler.java new file mode 100644 index 0000000..1979d53 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5InitialRequestHandler.java @@ -0,0 +1,34 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.socket5; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.socksx.v5.*; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class Socks5InitialRequestHandler extends SimpleChannelInboundHandler { + @Override + protected void channelRead0(ChannelHandlerContext ctx, Socks5InitialRequest msg) throws Exception { + boolean failure = msg.decoderResult().isFailure(); + if (failure) { + log.error("初始化socks5失败,请检查是否是socks5协议"); +// ReferenceCountUtil.retain(msg); + ctx.fireChannelRead(msg); + return; + } + log.info("初始化socket连接"); + + // 不验证账号密码 + Socks5InitialResponse socks5InitialResponse = new DefaultSocks5InitialResponse(Socks5AuthMethod.NO_AUTH); + ctx.writeAndFlush(socks5InitialResponse); + + ctx.pipeline().remove(this); + ctx.pipeline().remove(Socks5InitialRequestDecoder.class); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + ctx.close(); + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5PasswordAuthRequestInboundHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5PasswordAuthRequestInboundHandler.java new file mode 100644 index 0000000..fc591ad --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5PasswordAuthRequestInboundHandler.java @@ -0,0 +1,28 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.socket5; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.socksx.v5.*; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class Socks5PasswordAuthRequestInboundHandler extends SimpleChannelInboundHandler { + + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DefaultSocks5PasswordAuthRequest msg) throws Exception { + //认证成功 + + log.info("认证直接成功"); + Socks5PasswordAuthResponse passwordAuthResponse = new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.SUCCESS); + ctx.writeAndFlush(passwordAuthResponse); + ctx.pipeline().remove(this); + ctx.pipeline().remove(Socks5PasswordAuthRequestDecoder.class); + return; + + // 认证失败 +// Socks5PasswordAuthResponse passwordAuthResponse = new DefaultSocks5PasswordAuthResponse(Socks5PasswordAuthStatus.FAILURE); +// //发送鉴权失败消息,完成后关闭channel +// ctx.writeAndFlush(passwordAuthResponse).addListener(ChannelFutureListener.CLOSE); + } +} diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5ProxyServer.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5ProxyServer.java new file mode 100644 index 0000000..29b5ae7 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5ProxyServer.java @@ -0,0 +1,71 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.socket5; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.socksx.v5.Socks5CommandRequestDecoder; +import io.netty.handler.codec.socksx.v5.Socks5InitialRequestDecoder; +import io.netty.handler.codec.socksx.v5.Socks5PasswordAuthRequestDecoder; +import io.netty.handler.codec.socksx.v5.Socks5ServerEncoder; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class Socks5ProxyServer { + private final int port; + + public Socks5ProxyServer(int port) { + this.port = port; + } + + public void run() throws Exception { + EventLoopGroup bossGroup = new NioEventLoopGroup(); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + + EventLoopGroup group = new NioEventLoopGroup(); + try { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + + //socks5响应最后一个encode + ch.pipeline().addLast(Socks5ServerEncoder.DEFAULT); + // 初始化连接 + ch.pipeline().addLast(new Socks5InitialRequestDecoder()); + ch.pipeline().addLast(new Socks5InitialRequestHandler()); + + + // 认证 +// ch.pipeline().addLast(new Socks5PasswordAuthRequestDecoder()); +// ch.pipeline().addLast(new Socks5PasswordAuthRequestInboundHandler()); + + // 连接请求 + ch.pipeline().addLast(new Socks5CommandRequestDecoder()); + ch.pipeline().addLast(new Socks5CommandRequestHandler(group)); + } + }) + .option(ChannelOption.SO_BACKLOG, 512) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000) + ; + + log.info("启动 socket:{}", port); + ChannelFuture f = b.bind(port).sync(); + f.channel().closeFuture().sync(); + + } finally { + workerGroup.shutdownGracefully(); + bossGroup.shutdownGracefully(); + } + } + + public static void main(String[] args) throws Exception { + new Socks5ProxyServer(1080).run(); + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5ServerConnectHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5ServerConnectHandler.java new file mode 100644 index 0000000..0d556af --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/socket5/Socks5ServerConnectHandler.java @@ -0,0 +1,42 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.socket5; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; + +import java.util.concurrent.atomic.AtomicReference; + +public class Socks5ServerConnectHandler extends SimpleChannelInboundHandler { + private final Channel relayChannel; + + public Socks5ServerConnectHandler(Channel relayChannel) { + this.relayChannel = relayChannel; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { + relayChannel.writeAndFlush(msg); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + ctx.read(); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (relayChannel.isActive()) { + relayChannel.writeAndFlush(new io.netty.handler.codec.socksx.v5.DefaultSocks5CommandResponse( + io.netty.handler.codec.socksx.v5.Socks5CommandStatus.FAILURE, + io.netty.handler.codec.socksx.v5.Socks5AddressType.IPv4)) + .addListener(ChannelFutureListener.CLOSE); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + ctx.close(); + } +} \ No newline at end of file