diff --git a/pom.xml b/pom.xml index 322864c..ac7c552 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ wu-lazy-cloud-heartbeat-client wu-lazy-cloud-heartbeat-common wu-lazy-cloud-heartbeat-dns + wu-lazy-cloud-heartbeat-protocol-proxy wu-lazy-cloud-heartbeat-start diff --git a/wu-lazy-cloud-heartbeat-client/pom.xml b/wu-lazy-cloud-heartbeat-client/pom.xml index 1158de4..16cf6c7 100644 --- a/wu-lazy-cloud-heartbeat-client/pom.xml +++ b/wu-lazy-cloud-heartbeat-client/pom.xml @@ -23,6 +23,11 @@ top.wu2020 wu-lazy-cloud-heartbeat-common + + top.wu2020 + wu-lazy-cloud-heartbeat-protocol-proxy + 1.3.0-JDK17-SNAPSHOT + com.alibaba fastjson diff --git a/wu-lazy-cloud-heartbeat-common/src/main/java/org/framework/lazy/cloud/network/heartbeat/common/context/SocketApplicationListener.java b/wu-lazy-cloud-heartbeat-common/src/main/java/org/framework/lazy/cloud/network/heartbeat/common/context/SocketApplicationListener.java index c7e68eb..a3928df 100644 --- a/wu-lazy-cloud-heartbeat-common/src/main/java/org/framework/lazy/cloud/network/heartbeat/common/context/SocketApplicationListener.java +++ b/wu-lazy-cloud-heartbeat-common/src/main/java/org/framework/lazy/cloud/network/heartbeat/common/context/SocketApplicationListener.java @@ -39,7 +39,7 @@ public interface SocketApplicationListener extends CommandLineRunner, Disposable /** * 运行 * - * @throws InterruptedException + * @throws InterruptedException 异常信息 */ void doRunning() throws Exception; diff --git a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/EnableDnsAutoConfiguration.java b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/EnableDnsAutoConfiguration.java similarity index 84% rename from wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/EnableDnsAutoConfiguration.java rename to wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/EnableDnsAutoConfiguration.java index 5a6f52a..c62329b 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/EnableDnsAutoConfiguration.java +++ b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/EnableDnsAutoConfiguration.java @@ -1,4 +1,4 @@ -package org.framework.lazy.cloud.network.heartbeat.dns; +package org.framework.lazy.cloud.network.heartbeat.protocol; import org.springframework.context.annotation.ComponentScan; import org.wu.framework.lazy.orm.core.stereotype.LazyScan; @@ -7,6 +7,6 @@ import org.wu.framework.lazy.orm.core.stereotype.LazyScan; "org.framework.lazy.cloud.network.heartbeat.dns.standalone.infrastructure.entity", "org.framework.lazy.cloud.network.heartbeat.dns.cluster.infrastructure.entity" }) -@ComponentScan(basePackages = "org.framework.lazy.cloud.network.heartbeat.dns") +@ComponentScan(basePackages = "org.framework.lazy.cloud.network.heartbeat.protocol") public class EnableDnsAutoConfiguration { } diff --git a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/config/DnsAutoConfiguration.java b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/DnsAutoConfiguration.java similarity index 74% rename from wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/config/DnsAutoConfiguration.java rename to wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/DnsAutoConfiguration.java index dc850f3..6659e63 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/config/DnsAutoConfiguration.java +++ b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/DnsAutoConfiguration.java @@ -1,4 +1,4 @@ -package org.framework.lazy.cloud.network.heartbeat.dns.config; +package org.framework.lazy.cloud.network.heartbeat.protocol.config; import org.springframework.beans.factory.config.BeanDefinition; diff --git a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/config/DnsFlowConfiguration.java b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/DnsFlowConfiguration.java similarity index 86% rename from wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/config/DnsFlowConfiguration.java rename to wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/DnsFlowConfiguration.java index be33aa7..6cd63c1 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/config/DnsFlowConfiguration.java +++ b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/DnsFlowConfiguration.java @@ -1,4 +1,4 @@ -package org.framework.lazy.cloud.network.heartbeat.dns.config; +package org.framework.lazy.cloud.network.heartbeat.protocol.config; import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelFlowAdapter; import org.framework.lazy.cloud.network.heartbeat.common.advanced.flow.HandleChannelFlowAdvanced; diff --git a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/context/NettyDnsSocketApplicationListener.java b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyDnsSocketApplicationListener.java similarity index 87% rename from wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/context/NettyDnsSocketApplicationListener.java rename to wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyDnsSocketApplicationListener.java index 8fcaa55..946dba7 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/context/NettyDnsSocketApplicationListener.java +++ b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyDnsSocketApplicationListener.java @@ -1,4 +1,4 @@ -package org.framework.lazy.cloud.network.heartbeat.dns.context; +package org.framework.lazy.cloud.network.heartbeat.protocol.context; import lombok.extern.slf4j.Slf4j; import org.framework.lazy.cloud.network.heartbeat.common.context.SocketApplicationListener; diff --git a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/init/InitDnsSocket.java b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/init/InitDnsSocket.java similarity index 67% rename from wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/init/InitDnsSocket.java rename to wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/init/InitDnsSocket.java index 0ee461b..557e475 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/dns/init/InitDnsSocket.java +++ b/wu-lazy-cloud-heartbeat-dns/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/init/InitDnsSocket.java @@ -1,8 +1,8 @@ -package org.framework.lazy.cloud.network.heartbeat.dns.init; +package org.framework.lazy.cloud.network.heartbeat.protocol.init; import lombok.extern.slf4j.Slf4j; -import org.framework.lazy.cloud.network.heartbeat.dns.context.NettyDnsSocketApplicationListener; +import org.framework.lazy.cloud.network.heartbeat.protocol.context.NettyDnsSocketApplicationListener; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; diff --git a/wu-lazy-cloud-heartbeat-dns/src/main/resources/META-INF/spring.factories b/wu-lazy-cloud-heartbeat-dns/src/main/resources/META-INF/spring.factories index f9b6772..f240753 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/main/resources/META-INF/spring.factories +++ b/wu-lazy-cloud-heartbeat-dns/src/main/resources/META-INF/spring.factories @@ -1,6 +1,6 @@ # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.framework.lazy.cloud.network.heartbeat.dns.EnableDnsAutoConfiguration,\ -org.framework.lazy.cloud.network.heartbeat.dns.config.DnsAutoConfiguration,\ -org.framework.lazy.cloud.network.heartbeat.dns.init.InitDnsSocket,\ -org.framework.lazy.cloud.network.heartbeat.dns.config.DnsFlowConfiguration +org.framework.lazy.cloud.network.heartbeat.protocol.EnableProtocolProxyAutoConfiguration,\ +org.framework.lazy.cloud.network.heartbeat.protocol.config.ProtocolProxyAutoConfiguration,\ +org.framework.lazy.cloud.network.heartbeat.protocol.init.InitProtocolProxySocket,\ +org.framework.lazy.cloud.network.heartbeat.protocol.config.ProtocolProxyFlowConfiguration diff --git a/wu-lazy-cloud-heartbeat-dns/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/wu-lazy-cloud-heartbeat-dns/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 70b5eaa..dab0105 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/wu-lazy-cloud-heartbeat-dns/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1,4 +1,4 @@ -org.framework.lazy.cloud.network.heartbeat.dns.EnableDnsAutoConfiguration -org.framework.lazy.cloud.network.heartbeat.dns.config.DnsAutoConfiguration -org.framework.lazy.cloud.network.heartbeat.dns.init.InitDnsSocket -org.framework.lazy.cloud.network.heartbeat.dns.config.DnsFlowConfiguration +org.framework.lazy.cloud.network.heartbeat.protocol.EnableProtocolProxyAutoConfiguration +org.framework.lazy.cloud.network.heartbeat.protocol.config.ProtocolProxyAutoConfiguration +org.framework.lazy.cloud.network.heartbeat.protocol.init.InitProtocolProxySocket +org.framework.lazy.cloud.network.heartbeat.protocol.config.ProtocolProxyFlowConfiguration diff --git a/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/DnsServer.java b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServer.java similarity index 96% rename from wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/DnsServer.java rename to wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServer.java index 3e69d6c..cca97f3 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/DnsServer.java +++ b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServer.java @@ -1,4 +1,4 @@ -package org.framework.lazy.cloud.network.heartbeat.dns; +package org.framework.lazy.cloud.network.heartbeat.protocol; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; diff --git a/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/DnsServerHandler.java b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServerHandler.java similarity index 95% rename from wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/DnsServerHandler.java rename to wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServerHandler.java index 18bb9d3..a8b1178 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/DnsServerHandler.java +++ b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServerHandler.java @@ -1,4 +1,4 @@ -package org.framework.lazy.cloud.network.heartbeat.dns; +package org.framework.lazy.cloud.network.heartbeat.protocol; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; @@ -62,6 +62,7 @@ public class DnsServerHandler extends SimpleChannelInboundHandler() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast( + new HttpClientCodec(), + new HttpObjectAggregator(1048576), + new HttpProxyServerHandler() + ); + } + }); + + ChannelFuture f = b.bind(PORT).sync(); + System.out.println("Proxy server started and listening on port " + PORT); + f.channel().closeFuture().sync(); + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + + private static class HttpProxyServerHandler extends ChannelInboundHandlerAdapter { + + private Channel outboundChannel; + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof FullHttpRequest) { + FullHttpRequest request = (FullHttpRequest) msg; + URI uri = new URI(request.uri()); + String host = uri.getHost(); + int port = uri.getPort(); + if (port == -1) { + port = 80; + } + + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast( + new HttpClientCodec(), + new HttpObjectAggregator(1048576), + new ProxyBackendHandler(ctx.channel()) + ); + } + }); + + ChannelFuture f = b.connect(host, port); + outboundChannel = f.channel(); + f.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + // 连接成功,将客户端请求转发到目标服务器 + outboundChannel.writeAndFlush(request.retain()); + } else { + // 连接失败,关闭客户端通道 + ctx.channel().close(); + } + } + }); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (outboundChannel != null) { + closeOnFlush(outboundChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class ProxyBackendHandler extends ChannelInboundHandlerAdapter { + + private final Channel inboundChannel; + + ProxyBackendHandler(Channel inboundChannel) { + this.inboundChannel = inboundChannel; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + // 将目标服务器的响应转发给客户端 + inboundChannel.writeAndFlush(msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + closeOnFlush(inboundChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/MultiProtocolProxyServer.java b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/MultiProtocolProxyServer.java new file mode 100644 index 0000000..4a156e5 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/MultiProtocolProxyServer.java @@ -0,0 +1,312 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.*; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; + +import java.net.InetSocketAddress; +import java.net.URI; + +public class MultiProtocolProxyServer { + private static final int HTTP_PORT = 8080; + private static final int TCP_PORT = 9090; + private static final int UDP_PORT = 10000; + + public static void main(String[] args) throws Exception { + EventLoopGroup bossGroup = new NioEventLoopGroup(); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + + try { + // 启动 HTTP 代理服务器 + startHttpProxy(bossGroup, workerGroup); + // 启动 TCP 代理服务器 + startTcpProxy(bossGroup, workerGroup); + // 启动 UDP 代理服务器 + startUdpProxy(workerGroup); + + System.out.println("Proxy servers started."); + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + + private static void startHttpProxy(EventLoopGroup bossGroup, EventLoopGroup workerGroup) throws InterruptedException { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast( + new HttpClientCodec(), + new HttpObjectAggregator(1048576), + new HttpProxyServerHandler() + ); + } + }); + + b.bind(HTTP_PORT).sync(); + System.out.println("HTTP proxy server started on port " + HTTP_PORT); + } + + private static void startTcpProxy(EventLoopGroup bossGroup, EventLoopGroup workerGroup) throws InterruptedException { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(new TcpProxyServerHandler()); + } + }); + + b.bind(TCP_PORT).sync(); + System.out.println("TCP proxy server started on port " + TCP_PORT); + } + + private static void startUdpProxy(EventLoopGroup workerGroup) throws InterruptedException { + Bootstrap b = new Bootstrap(); + b.group(workerGroup) + .channel(NioDatagramChannel.class) + .handler(new UdpProxyServerHandler()); + + b.bind(UDP_PORT).sync(); + System.out.println("UDP proxy server started on port " + UDP_PORT); + } + + private static class HttpProxyServerHandler extends ChannelInboundHandlerAdapter { + private Channel outboundChannel; + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof FullHttpRequest) { + FullHttpRequest request = (FullHttpRequest) msg; + URI uri = new URI(request.uri()); + String host = uri.getHost(); + int port = uri.getPort(); + if (port == -1) { + port = 80; + } + + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast( + new HttpClientCodec(), + new HttpObjectAggregator(1048576), + new HttpProxyBackendHandler(ctx.channel()) + ); + } + }); + + ChannelFuture f = b.connect(host, port); + outboundChannel = f.channel(); + f.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + outboundChannel.writeAndFlush(request.retain()); + } else { + ctx.channel().close(); + } + } + }); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (outboundChannel != null) { + closeOnFlush(outboundChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class HttpProxyBackendHandler extends ChannelInboundHandlerAdapter { + private final Channel inboundChannel; + + HttpProxyBackendHandler(Channel inboundChannel) { + this.inboundChannel = inboundChannel; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + inboundChannel.writeAndFlush(msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + closeOnFlush(inboundChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class TcpProxyServerHandler extends ChannelInboundHandlerAdapter { + private Channel outboundChannel; + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + if (outboundChannel == null) { + // 假设目标服务器地址和端口 + String targetHost = "example.com"; + int targetPort = 80; + + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(new TcpProxyBackendHandler(ctx.channel())); + } + }); + + ChannelFuture f = b.connect(targetHost, targetPort); + outboundChannel = f.channel(); + f.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + outboundChannel.writeAndFlush(msg); + } else { + ctx.channel().close(); + } + } + }); + } else { + outboundChannel.writeAndFlush(msg); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (outboundChannel != null) { + closeOnFlush(outboundChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class TcpProxyBackendHandler extends ChannelInboundHandlerAdapter { + private final Channel inboundChannel; + + TcpProxyBackendHandler(Channel inboundChannel) { + this.inboundChannel = inboundChannel; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + inboundChannel.writeAndFlush(msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + closeOnFlush(inboundChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class UdpProxyServerHandler extends SimpleChannelInboundHandler { + private InetSocketAddress targetAddress = new InetSocketAddress("example.com", 80); + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioDatagramChannel.class) + .handler(new UdpProxyBackendHandler(ctx.channel(), packet.sender())); + + Channel channel = b.bind(0).sync().channel(); + channel.writeAndFlush(new DatagramPacket(packet.content().retain(), targetAddress)); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + ctx.close(); + } + } + + private static class UdpProxyBackendHandler extends SimpleChannelInboundHandler { + private final Channel inboundChannel; + private final InetSocketAddress clientAddress; + + UdpProxyBackendHandler(Channel inboundChannel, InetSocketAddress clientAddress) { + this.inboundChannel = inboundChannel; + this.clientAddress = clientAddress; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { + inboundChannel.writeAndFlush(new DatagramPacket(packet.content().retain(), clientAddress)); + ctx.channel().close(); + } + + @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-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/demo/DnsServer.java b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/DnsServer.java similarity index 81% rename from wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/demo/DnsServer.java rename to wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/DnsServer.java index 055cf4e..292cef7 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/demo/DnsServer.java +++ b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/DnsServer.java @@ -1,13 +1,11 @@ -package org.framework.lazy.cloud.network.heartbeat.dns.demo; +package org.framework.lazy.cloud.network.heartbeat.protocol.demo; import com.github.xiaoymin.knife4j.core.util.StrUtil; import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.handler.codec.dns.*; import io.netty.util.AttributeKey; @@ -16,6 +14,9 @@ import lombok.extern.slf4j.Slf4j; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; @@ -75,10 +76,25 @@ public final class DnsServer { DatagramDnsResponse dnsResponse = new DatagramDnsResponse(msg.recipient(), msg.sender(), id); dnsResponse.addRecord(DnsSection.QUESTION, question); + InetAddress inetAddress = null; + try { + inetAddress = Inet4Address.getByName("www.baidu.com"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + byte[] ipBytes = inetAddress.getAddress(); // just print the IP after query +// DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord( +// question.name(), +// DnsRecordType.A, 600, Unpooled.wrappedBuffer(new byte[]{(byte) 192, (byte) 168, 1, 1})); + DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord( question.name(), - DnsRecordType.A, 600, Unpooled.wrappedBuffer(new byte[]{(byte) 192, (byte) 168, 1, 1})); + DnsRecordType.A, + 600, + Unpooled.wrappedBuffer(ipBytes) + ); + dnsResponse.addRecord(DnsSection.ANSWER, queryAnswer); return dnsResponse; } diff --git a/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/demo/ProxyUdp.java b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/ProxyUdp.java similarity index 98% rename from wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/demo/ProxyUdp.java rename to wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/ProxyUdp.java index ac4f377..5850dc5 100644 --- a/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/dns/demo/ProxyUdp.java +++ b/wu-lazy-cloud-heartbeat-dns/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/ProxyUdp.java @@ -1,4 +1,4 @@ -package org.framework.lazy.cloud.network.heartbeat.dns.demo; +package org.framework.lazy.cloud.network.heartbeat.protocol.demo; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBufUtil; diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/pom.xml b/wu-lazy-cloud-heartbeat-protocol-proxy/pom.xml new file mode 100644 index 0000000..429533c --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/pom.xml @@ -0,0 +1,59 @@ + + + + top.wu2020 + wu-lazy-cloud-network + 1.3.0-JDK17-SNAPSHOT + + + 4.0.0 + + wu-lazy-cloud-heartbeat-protocol-proxy + 云上心跳服务协议代理 + + + 17 + 17 + + + + + top.wu2020 + wu-framework-web + + + + top.wu2020 + wu-lazy-cloud-heartbeat-common + + + + mysql + mysql-connector-java + 8.0.33 + + + + top.wu2020 + wu-database-lazy-plus-starter + + + com.alibaba + fastjson + 2.0.50 + + + io.swagger.core.v3 + swagger-annotations-jakarta + 2.2.21 + + + top.wu2020 + wu-framework-lazy-orm-spring-starter + + + + + \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/EnableProtocolProxyAutoConfiguration.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/EnableProtocolProxyAutoConfiguration.java new file mode 100644 index 0000000..04ae23b --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/EnableProtocolProxyAutoConfiguration.java @@ -0,0 +1,11 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol; + +import org.springframework.context.annotation.ComponentScan; +import org.wu.framework.lazy.orm.core.stereotype.LazyScan; + +@LazyScan(scanBasePackages = { + "org.framework.lazy.cloud.network.heartbeat.dns.standalone.infrastructure.entity" +}) +@ComponentScan(basePackages = "org.framework.lazy.cloud.network.heartbeat.protocol") +public class EnableProtocolProxyAutoConfiguration { +} diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/ProtocolProxyAutoConfiguration.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/ProtocolProxyAutoConfiguration.java new file mode 100644 index 0000000..d541dbd --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/ProtocolProxyAutoConfiguration.java @@ -0,0 +1,11 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.config; + + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Role; + + +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +public class ProtocolProxyAutoConfiguration { + +} diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/ProtocolProxyFlowConfiguration.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/ProtocolProxyFlowConfiguration.java new file mode 100644 index 0000000..7607755 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/config/ProtocolProxyFlowConfiguration.java @@ -0,0 +1,15 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.config; + +import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelFlowAdapter; +import org.framework.lazy.cloud.network.heartbeat.common.advanced.flow.HandleChannelFlowAdvanced; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Role; + +/** + * @see ChannelFlowAdapter + * @see HandleChannelFlowAdvanced + */ +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +public class ProtocolProxyFlowConfiguration { + +} diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyHttpProxySocketApplicationListener.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyHttpProxySocketApplicationListener.java new file mode 100644 index 0000000..ddc3de9 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyHttpProxySocketApplicationListener.java @@ -0,0 +1,85 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.context; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; +import org.framework.lazy.cloud.network.heartbeat.common.context.SocketApplicationListener; +import org.framework.lazy.cloud.network.heartbeat.protocol.filter.NettyHttpProxyFilter; +import org.framework.lazy.cloud.network.heartbeat.protocol.properties.ProtocolProxyProperties; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class NettyHttpProxySocketApplicationListener implements SocketApplicationListener { + + private final EventLoopGroup bossGroup = new NioEventLoopGroup(); + private final EventLoopGroup workerGroup = new NioEventLoopGroup(); + private ChannelFuture channelFuture; + private final NettyHttpProxyFilter nettyHttpProxyFilter;// 通道业务处理 + private final ProtocolProxyProperties protocolProxyProperties; + + public NettyHttpProxySocketApplicationListener(NettyHttpProxyFilter nettyHttpProxyFilter, ProtocolProxyProperties protocolProxyProperties) { + this.nettyHttpProxyFilter = nettyHttpProxyFilter; + this.protocolProxyProperties = protocolProxyProperties; + } + + + /** + * 运行 + * + * @throws InterruptedException + */ + @Override + public void doRunning() throws Exception { + try { + ProtocolProxyProperties.HttpProtocolProxy httpProtocolProxy = protocolProxyProperties.getHttpProtocolProxy(); + Integer httpProtocolProxyPort = httpProtocolProxy.getPort(); + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + // 给服务端channel设置属性 + // 设置读缓冲区为2M + .childOption(ChannelOption.SO_RCVBUF, 2048 * 1024) + // 设置写缓冲区为1M + .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024) + + .childOption(ChannelOption.SO_KEEPALIVE, true) +// .childOption(ChannelOption.TCP_NODELAY, false) + .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000 * 60)//连接超时时间设置为 60 秒 +// .childOption(ChannelOption.RCVBUF_ALLOCATOR, new NettyRecvByteBufAllocator(1024 * 1024))//用于Channel分配接受Buffer的分配器 默认AdaptiveRecvByteBufAllocator.DEFAULT + .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 1024 * 1024 * 2)) + + .childHandler(nettyHttpProxyFilter); + channelFuture = b.bind(httpProtocolProxyPort).sync(); + + channelFuture.addListener((ChannelFutureListener) channelFuture -> { + // 服务器已启动 + log.info("http 协议代理 服务器启动成功"); + }); + channelFuture.channel().closeFuture().sync(); + } catch (Exception e) { + log.error("启动http 协议代理 失败", e); + } finally { + destroy(); + // 服务器已关闭 + log.warn("http 协议代理 服务关闭"); + } + } + + @PreDestroy + @Override + public void destroy() throws Exception { + if (channelFuture != null) { + channelFuture.channel().close().syncUninterruptibly(); + } + if (!bossGroup.isShutdown()) { + bossGroup.shutdownGracefully(); + } + if (!workerGroup.isShutdown()) { + workerGroup.shutdownGracefully(); + } + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyTcpProxySocketApplicationListener.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyTcpProxySocketApplicationListener.java new file mode 100644 index 0000000..d4ea289 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyTcpProxySocketApplicationListener.java @@ -0,0 +1,86 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.context; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; +import org.framework.lazy.cloud.network.heartbeat.common.context.SocketApplicationListener; +import org.framework.lazy.cloud.network.heartbeat.protocol.filter.NettyHttpProxyFilter; +import org.framework.lazy.cloud.network.heartbeat.protocol.filter.NettyTcpProxyFilter; +import org.framework.lazy.cloud.network.heartbeat.protocol.properties.ProtocolProxyProperties; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class NettyTcpProxySocketApplicationListener implements SocketApplicationListener { + + private final EventLoopGroup bossGroup = new NioEventLoopGroup(); + private final EventLoopGroup workerGroup = new NioEventLoopGroup(); + private final NettyTcpProxyFilter nettyTcpProxyFilter;// 通道业务处理 + private ChannelFuture channelFuture; + private final ProtocolProxyProperties protocolProxyProperties; + + public NettyTcpProxySocketApplicationListener(NettyTcpProxyFilter nettyTcpProxyFilter, ProtocolProxyProperties protocolProxyProperties) { + this.nettyTcpProxyFilter = nettyTcpProxyFilter; + this.protocolProxyProperties = protocolProxyProperties; + } + + + /** + * 运行 + * + * @throws InterruptedException + */ + @Override + public void doRunning() throws Exception { + try { + ProtocolProxyProperties.TcpProtocolProxy tcpHttpProtocolProxy = protocolProxyProperties.getTcpHttpProtocolProxy(); + Integer httpProtocolProxyPort = tcpHttpProtocolProxy.getPort(); + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + // 给服务端channel设置属性 + // 设置读缓冲区为2M + .childOption(ChannelOption.SO_RCVBUF, 2048 * 1024) + // 设置写缓冲区为1M + .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024) + + .childOption(ChannelOption.SO_KEEPALIVE, true) +// .childOption(ChannelOption.TCP_NODELAY, false) + .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000 * 60)//连接超时时间设置为 60 秒 +// .childOption(ChannelOption.RCVBUF_ALLOCATOR, new NettyRecvByteBufAllocator(1024 * 1024))//用于Channel分配接受Buffer的分配器 默认AdaptiveRecvByteBufAllocator.DEFAULT + .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 1024 * 1024 * 2)) + + .childHandler(nettyTcpProxyFilter); + channelFuture = b.bind(httpProtocolProxyPort).sync(); + + channelFuture.addListener((ChannelFutureListener) channelFuture -> { + // 服务器已启动 + log.info("TCP 协议代理 服务器启动成功"); + }); + channelFuture.channel().closeFuture().sync(); + } catch (Exception e) { + log.error("启动TCP 协议代理 失败", e); + } finally { + destroy(); + // 服务器已关闭 + log.warn("TCP 协议代理 服务关闭"); + } + } + + @PreDestroy + @Override + public void destroy() throws Exception { + if (channelFuture != null) { + channelFuture.channel().close().syncUninterruptibly(); + } + if (!bossGroup.isShutdown()) { + bossGroup.shutdownGracefully(); + } + if (!workerGroup.isShutdown()) { + workerGroup.shutdownGracefully(); + } + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyUdpProxySocketApplicationListener.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyUdpProxySocketApplicationListener.java new file mode 100644 index 0000000..b376b5b --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/context/NettyUdpProxySocketApplicationListener.java @@ -0,0 +1,89 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.context; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioDatagramChannel; +import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; +import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelTypeAdapter; +import org.framework.lazy.cloud.network.heartbeat.common.advanced.HandleChannelTypeAdvanced; +import org.framework.lazy.cloud.network.heartbeat.common.context.SocketApplicationListener; +import org.framework.lazy.cloud.network.heartbeat.protocol.handler.NettyUdpProxyHandler; +import org.framework.lazy.cloud.network.heartbeat.protocol.properties.ProtocolProxyProperties; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +public class NettyUdpProxySocketApplicationListener implements SocketApplicationListener { + + private final EventLoopGroup bossGroup = new NioEventLoopGroup(); + private ChannelFuture channelFuture; + private final ProtocolProxyProperties protocolProxyProperties; + private final List handleChannelTypeAdvancedList; + + public NettyUdpProxySocketApplicationListener(ProtocolProxyProperties protocolProxyProperties, + List handleChannelTypeAdvancedList) { + this.protocolProxyProperties = protocolProxyProperties; + this.handleChannelTypeAdvancedList = handleChannelTypeAdvancedList; + } + + + /** + * 运行 + * + * @throws InterruptedException + */ + @Override + public void doRunning() throws Exception { + try { + ChannelTypeAdapter channelTypeAdapter = new ChannelTypeAdapter(handleChannelTypeAdvancedList); + NettyUdpProxyHandler nettyUdpProxyHandler = new NettyUdpProxyHandler(channelTypeAdapter);// 通道业务处理 + + ProtocolProxyProperties.UdpProtocolProxy udpHttpProtocolProxy = protocolProxyProperties.getUdpHttpProtocolProxy(); + Integer udpProtocolProxyPort = udpHttpProtocolProxy.getPort(); + Bootstrap b = new Bootstrap(); + b.group(bossGroup) + .channel(NioDatagramChannel.class) + // 给服务端channel设置属性 + // 设置读缓冲区为2M + .option(ChannelOption.SO_RCVBUF, 2048 * 1024) + // 设置写缓冲区为1M + .option(ChannelOption.SO_SNDBUF, 1024 * 1024) + + .option(ChannelOption.SO_KEEPALIVE, true) +// .childOption(ChannelOption.TCP_NODELAY, false) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000 * 60)//连接超时时间设置为 60 秒 +// .childOption(ChannelOption.RCVBUF_ALLOCATOR, new NettyRecvByteBufAllocator(1024 * 1024))//用于Channel分配接受Buffer的分配器 默认AdaptiveRecvByteBufAllocator.DEFAULT + .option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 1024 * 1024 * 2)) + + .handler(nettyUdpProxyHandler); + channelFuture = b.bind(udpProtocolProxyPort).sync(); + + channelFuture.addListener((ChannelFutureListener) channelFuture -> { + // 服务器已启动 + log.info("UDP 协议代理 服务器启动成功"); + }); + channelFuture.channel().closeFuture().sync(); + } catch (Exception e) { + log.error("启动UDP 协议代理 失败", e); + } finally { + destroy(); + // 服务器已关闭 + log.warn("UDP 协议代理 服务关闭"); + } + } + + @PreDestroy + @Override + public void destroy() throws Exception { + if (channelFuture != null) { + channelFuture.channel().close().syncUninterruptibly(); + } + if (!bossGroup.isShutdown()) { + bossGroup.shutdownGracefully(); + } + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/filter/NettyHttpProxyFilter.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/filter/NettyHttpProxyFilter.java new file mode 100644 index 0000000..43bb33d --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/filter/NettyHttpProxyFilter.java @@ -0,0 +1,52 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.filter; + +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpObjectAggregator; +import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelTypeAdapter; +import org.framework.lazy.cloud.network.heartbeat.common.advanced.HandleChannelTypeAdvanced; +import org.framework.lazy.cloud.network.heartbeat.common.filter.DebugChannelInitializer; +import org.framework.lazy.cloud.network.heartbeat.protocol.handler.NettyHttpProxyHandler; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * description + * + * @author 吴佳伟 + * @date 2023/09/13 10:26 + */ +@Component +public class NettyHttpProxyFilter extends DebugChannelInitializer { + private final List handleChannelTypeAdvancedList; + + public NettyHttpProxyFilter(List handleChannelTypeAdvancedList) { + this.handleChannelTypeAdvancedList = handleChannelTypeAdvancedList; + } + + @Override + protected void initChannel0(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + // 以("\n")为结尾分割的 解码器 + // 解码、编码 +// pipeline.addLast(new NettyProxyMsgDecoder(Integer.MAX_VALUE, 0, 4, -4, 0)); +// pipeline.addLast(new NettyProxyMsgEncoder()); +//// ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); +// // 解码和编码,应和客户端一致 +// //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式 +// +// pipeline.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS)); +// pipeline.addLast("decoder", new StringDecoder()); +// pipeline.addLast("encoder", new StringEncoder()); + + // 类型处理器适配器 + ChannelTypeAdapter channelTypeAdapter = new ChannelTypeAdapter(handleChannelTypeAdvancedList); + pipeline.addLast("doHandler", new NettyHttpProxyHandler(channelTypeAdapter));// 服务端业务逻辑 + pipeline.addLast(new HttpClientCodec()); + pipeline.addLast(new HttpObjectAggregator(1048576)); + + + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/filter/NettyTcpProxyFilter.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/filter/NettyTcpProxyFilter.java new file mode 100644 index 0000000..1374242 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/filter/NettyTcpProxyFilter.java @@ -0,0 +1,40 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.filter; + +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpObjectAggregator; +import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelTypeAdapter; +import org.framework.lazy.cloud.network.heartbeat.common.advanced.HandleChannelTypeAdvanced; +import org.framework.lazy.cloud.network.heartbeat.common.filter.DebugChannelInitializer; +import org.framework.lazy.cloud.network.heartbeat.protocol.handler.NettyHttpProxyHandler; +import org.framework.lazy.cloud.network.heartbeat.protocol.handler.NettyTcpProxyHandler; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * description + * + * @author 吴佳伟 + * @date 2023/09/13 10:26 + */ +@Component +public class NettyTcpProxyFilter extends DebugChannelInitializer { + private final List handleChannelTypeAdvancedList; + + public NettyTcpProxyFilter(List handleChannelTypeAdvancedList) { + this.handleChannelTypeAdvancedList = handleChannelTypeAdvancedList; + } + + @Override + protected void initChannel0(SocketChannel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + // 类型处理器适配器 + ChannelTypeAdapter channelTypeAdapter = new ChannelTypeAdapter(handleChannelTypeAdvancedList); + pipeline.addLast("doHandler", new NettyTcpProxyHandler(channelTypeAdapter));// 服务端业务逻辑 + + + + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyHttpProxyBackendHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyHttpProxyBackendHandler.java new file mode 100644 index 0000000..26a63b1 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyHttpProxyBackendHandler.java @@ -0,0 +1,39 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.handler; + +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; + + + +public class NettyHttpProxyBackendHandler extends ChannelInboundHandlerAdapter { + private final Channel inboundChannel; + + NettyHttpProxyBackendHandler(Channel inboundChannel) { + this.inboundChannel = inboundChannel; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + inboundChannel.writeAndFlush(msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + closeOnFlush(inboundChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyHttpProxyHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyHttpProxyHandler.java new file mode 100644 index 0000000..5cc71da --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyHttpProxyHandler.java @@ -0,0 +1,92 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.handler; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpObjectAggregator; +import lombok.extern.slf4j.Slf4j; +import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelTypeAdapter; + +import java.net.URI; + +/** + * description 服务端数据处理器 + * + * @author 吴佳伟 + * @date 2023/09/13 10:27 + */ +@Slf4j +public class NettyHttpProxyHandler extends ChannelInboundHandlerAdapter { + + private final ChannelTypeAdapter channelTypeAdapter; + /** + * 传出数据延迟次数* 心跳时间作为关闭时间 + */ + private int transfer_count = 1; + + public NettyHttpProxyHandler(ChannelTypeAdapter channelTypeAdapter) { + this.channelTypeAdapter = channelTypeAdapter; + } + + private Channel outboundChannel; + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof FullHttpRequest) { + FullHttpRequest request = (FullHttpRequest) msg; + URI uri = new URI(request.uri()); + String host = uri.getHost(); + int port = uri.getPort(); + if (port == -1) { + port = 80; + } + + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast( + new HttpClientCodec(), + new HttpObjectAggregator(1048576), + new NettyHttpProxyBackendHandler(ctx.channel()) + ); + } + }); + + ChannelFuture f = b.connect(host, port); + outboundChannel = f.channel(); + f.addListener((ChannelFutureListener) future -> { + if (future.isSuccess()) { + outboundChannel.writeAndFlush(request.retain()); + } else { + ctx.channel().close(); + } + }); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (outboundChannel != null) { + closeOnFlush(outboundChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyTcpProxyBackendHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyTcpProxyBackendHandler.java new file mode 100644 index 0000000..8ed76d0 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyTcpProxyBackendHandler.java @@ -0,0 +1,38 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.handler; + +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; + + +public class NettyTcpProxyBackendHandler extends ChannelInboundHandlerAdapter { + private final Channel inboundChannel; + + public NettyTcpProxyBackendHandler(Channel inboundChannel) { + this.inboundChannel = inboundChannel; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + inboundChannel.writeAndFlush(msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + closeOnFlush(inboundChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyTcpProxyHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyTcpProxyHandler.java new file mode 100644 index 0000000..2074868 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyTcpProxyHandler.java @@ -0,0 +1,84 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.handler; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpObjectAggregator; +import lombok.extern.slf4j.Slf4j; +import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelTypeAdapter; + +import java.net.URI; + +/** + * description 服务端数据处理器 + * + * @author 吴佳伟 + * @date 2023/09/13 10:27 + */ +@Slf4j +public class NettyTcpProxyHandler extends ChannelInboundHandlerAdapter { + + private final ChannelTypeAdapter channelTypeAdapter; + + + + public NettyTcpProxyHandler(ChannelTypeAdapter channelTypeAdapter) { + this.channelTypeAdapter = channelTypeAdapter; + } + + private Channel outboundChannel; + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + if (outboundChannel == null) { + // 假设目标服务器地址和端口 + String targetHost = "example.com"; + int targetPort = 80; + + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(new NettyTcpProxyBackendHandler(ctx.channel())); + } + }); + + ChannelFuture f = b.connect(targetHost, targetPort); + outboundChannel = f.channel(); + f.addListener((ChannelFutureListener) future -> { + if (future.isSuccess()) { + outboundChannel.writeAndFlush(msg); + } else { + ctx.channel().close(); + } + }); + } else { + outboundChannel.writeAndFlush(msg); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (outboundChannel != null) { + closeOnFlush(outboundChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } +} \ No newline at end of file diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyUdpProxyBackendHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyUdpProxyBackendHandler.java new file mode 100644 index 0000000..db09297 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyUdpProxyBackendHandler.java @@ -0,0 +1,31 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.handler; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.socket.DatagramPacket; + +import java.net.InetSocketAddress; + + +public class NettyUdpProxyBackendHandler extends SimpleChannelInboundHandler { + private final Channel inboundChannel; + private final InetSocketAddress clientAddress; + + public NettyUdpProxyBackendHandler(Channel inboundChannel, InetSocketAddress clientAddress) { + this.inboundChannel = inboundChannel; + this.clientAddress = clientAddress; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { + inboundChannel.writeAndFlush(new DatagramPacket(packet.content().retain(), clientAddress)); + ctx.channel().close(); + } + + @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/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyUdpProxyHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyUdpProxyHandler.java new file mode 100644 index 0000000..3cc4558 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/handler/NettyUdpProxyHandler.java @@ -0,0 +1,46 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.handler; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.nio.NioDatagramChannel; +import lombok.extern.slf4j.Slf4j; +import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelTypeAdapter; + +import java.net.InetSocketAddress; + +/** + * description 服务端数据处理器 + * + * @author 吴佳伟 + * @date 2023/09/13 10:27 + */ +@Slf4j +public class NettyUdpProxyHandler extends SimpleChannelInboundHandler { + + private final ChannelTypeAdapter channelTypeAdapter; + private InetSocketAddress targetAddress = new InetSocketAddress("example.com", 80); + + public NettyUdpProxyHandler(ChannelTypeAdapter channelTypeAdapter) { + this.channelTypeAdapter = channelTypeAdapter; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioDatagramChannel.class) + .handler(new NettyUdpProxyBackendHandler(ctx.channel(), packet.sender())); + + Channel channel = b.bind(0).sync().channel(); + channel.writeAndFlush(new DatagramPacket(packet.content().retain(), targetAddress)); + } + + @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/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/init/InitProtocolProxySocket.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/init/InitProtocolProxySocket.java new file mode 100644 index 0000000..40fc9e7 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/init/InitProtocolProxySocket.java @@ -0,0 +1,26 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.init; + + +import lombok.extern.slf4j.Slf4j; +import org.framework.lazy.cloud.network.heartbeat.protocol.context.NettyHttpProxySocketApplicationListener; +import org.framework.lazy.cloud.network.heartbeat.protocol.context.NettyTcpProxySocketApplicationListener; +import org.framework.lazy.cloud.network.heartbeat.protocol.context.NettyUdpProxySocketApplicationListener; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + + +/** + * description 初始化服务端 + * + * @author 吴佳伟 + * @date 2023/09/12 18:22 + */ +@Slf4j +@Configuration +@Import({NettyHttpProxySocketApplicationListener.class, + NettyTcpProxySocketApplicationListener.class, + NettyUdpProxySocketApplicationListener.class}) +public class InitProtocolProxySocket { + + +} diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/properties/ProtocolProxyProperties.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/properties/ProtocolProxyProperties.java new file mode 100644 index 0000000..4c79279 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/java/org/framework/lazy/cloud/network/heartbeat/protocol/properties/ProtocolProxyProperties.java @@ -0,0 +1,46 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * 服务端模式配置 + */ +@Configuration +@ConfigurationProperties(prefix = ProtocolProxyProperties.prefix) +@Data +public class ProtocolProxyProperties { + public static final String prefix = "spring.lazy.netty.protocol.proxy"; + + + /** + * http协议代理 + */ + private HttpProtocolProxy httpProtocolProxy; + /** + * tcp协议代理 + */ + private TcpProtocolProxy tcpHttpProtocolProxy; + /** + * udp协议代理 + */ + private UdpProtocolProxy udpHttpProtocolProxy; + + + + @Data + public static class HttpProtocolProxy { + private Integer port=8001; + } + + @Data + public static class TcpProtocolProxy { + private Integer port=9001; + } + @Data + public static class UdpProtocolProxy { + private Integer port=10001; + } + +} diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/resources/META-INF/spring.factories b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..f240753 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +# Auto Configure +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.framework.lazy.cloud.network.heartbeat.protocol.EnableProtocolProxyAutoConfiguration,\ +org.framework.lazy.cloud.network.heartbeat.protocol.config.ProtocolProxyAutoConfiguration,\ +org.framework.lazy.cloud.network.heartbeat.protocol.init.InitProtocolProxySocket,\ +org.framework.lazy.cloud.network.heartbeat.protocol.config.ProtocolProxyFlowConfiguration diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..dab0105 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,4 @@ +org.framework.lazy.cloud.network.heartbeat.protocol.EnableProtocolProxyAutoConfiguration +org.framework.lazy.cloud.network.heartbeat.protocol.config.ProtocolProxyAutoConfiguration +org.framework.lazy.cloud.network.heartbeat.protocol.init.InitProtocolProxySocket +org.framework.lazy.cloud.network.heartbeat.protocol.config.ProtocolProxyFlowConfiguration diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServer.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServer.java new file mode 100644 index 0000000..cca97f3 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServer.java @@ -0,0 +1,52 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol; + +import io.netty.bootstrap.Bootstrap; +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.DatagramChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.handler.codec.dns.DatagramDnsQueryDecoder; +import io.netty.handler.codec.dns.DatagramDnsResponseEncoder; + +public class DnsServer { + + private final int port; + + public DnsServer(int port) { + this.port = port; + } + + public void run() throws Exception { + EventLoopGroup group = new NioEventLoopGroup(); + try { + Bootstrap b = new Bootstrap(); + b.group(group) + .channel(NioDatagramChannel.class) + .option(ChannelOption.SO_BROADCAST, true) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(DatagramChannel ch) throws Exception { + ch.pipeline().addLast( + new DatagramDnsQueryDecoder(), + new DatagramDnsResponseEncoder(), + new DnsServerHandler() + ); + } + }); + + // 绑定端口 + ChannelFuture f = b.bind(port).sync(); + System.out.println("DNS server started and listening on port " + port); + f.channel().closeFuture().await(); + } finally { + group.shutdownGracefully(); + } + } + + public static void main(String[] args) throws Exception { + new DnsServer(53).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/DnsServerHandler.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServerHandler.java new file mode 100644 index 0000000..a8b1178 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/DnsServerHandler.java @@ -0,0 +1,84 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol; + +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.dns.*; +import lombok.extern.slf4j.Slf4j; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class DnsServerHandler extends SimpleChannelInboundHandler { + + + private Map domainIpMapping = new HashMap<>(); + + + { + domainIpMapping.put("test.wu-framework.cn.", "124.222.152.160"); + domainIpMapping.put("www.google.com.hk.", "120.253.253.97"); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery query) throws Exception { + + // 创建DNS响应 + DatagramDnsResponse response = new DatagramDnsResponse(query.recipient(), query.sender(), query.id()); + DefaultDnsQuestion dnsQuestion = query.recordAt(DnsSection.QUESTION); + response.addRecord(DnsSection.QUESTION, dnsQuestion); + DnsRecordType dnsRecordType = dnsQuestion.type(); + + log.info("dns:{}", dnsQuestion.name()); +// log.info("query:{}", query); + String domain = dnsQuestion.name(); + if (dnsRecordType == DnsRecordType.A) { + String ip = domainIpMapping.get(domain); + if (ip != null) { + log.info("ip:{}", ip); + try { + InetAddress address = Inet4Address.getByName(ip); + DefaultDnsRawRecord answer = new DefaultDnsRawRecord( + domain, DnsRecordType.A, 3600, + Unpooled.wrappedBuffer(address.getAddress()) + ); + response.addRecord(DnsSection.ANSWER, answer); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + + // 发送响应 + ctx.writeAndFlush(response); + } else { + // 使用系统默认 DNS 解析 + try { + java.net.InetAddress[] addresses = java.net.InetAddress.getAllByName(domain); + for (java.net.InetAddress address : addresses) { + log.info("使用本地dns解析域名:{} ip:{}", domain, address.getHostAddress()); + response.addRecord(DnsSection.ANSWER, new DefaultDnsRawRecord( + domain, DnsRecordType.A, 3600, Unpooled.wrappedBuffer(address.getAddress()))); + } +// log.info("response:{}",response.toString()); + ctx.writeAndFlush(response); + } catch (Exception e) { + e.printStackTrace(); + } + } + } else { + log.info("type:{}", dnsRecordType.name()); + } + + + } + + + @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/HttpProxyServer.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/HttpProxyServer.java new file mode 100644 index 0000000..a820795 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/HttpProxyServer.java @@ -0,0 +1,146 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.*; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; + +import java.net.URI; + +public class HttpProxyServer { + + private static final int PORT = 8080; + + public static void main(String[] args) throws Exception { + EventLoopGroup bossGroup = new NioEventLoopGroup(); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast( + new HttpClientCodec(), + new HttpObjectAggregator(1048576), + new HttpProxyServerHandler() + ); + } + }); + + ChannelFuture f = b.bind(PORT).sync(); + System.out.println("Proxy server started and listening on port " + PORT); + f.channel().closeFuture().sync(); + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + + private static class HttpProxyServerHandler extends ChannelInboundHandlerAdapter { + + private Channel outboundChannel; + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof FullHttpRequest) { + FullHttpRequest request = (FullHttpRequest) msg; + URI uri = new URI(request.uri()); + String host = uri.getHost(); + int port = uri.getPort(); + if (port == -1) { + port = 80; + } + + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast( + new HttpClientCodec(), + new HttpObjectAggregator(1048576), + new ProxyBackendHandler(ctx.channel()) + ); + } + }); + + ChannelFuture f = b.connect(host, port); + outboundChannel = f.channel(); + f.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + // 连接成功,将客户端请求转发到目标服务器 + outboundChannel.writeAndFlush(request.retain()); + } else { + // 连接失败,关闭客户端通道 + ctx.channel().close(); + } + } + }); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (outboundChannel != null) { + closeOnFlush(outboundChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class ProxyBackendHandler extends ChannelInboundHandlerAdapter { + + private final Channel inboundChannel; + + ProxyBackendHandler(Channel inboundChannel) { + this.inboundChannel = inboundChannel; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + // 将目标服务器的响应转发给客户端 + inboundChannel.writeAndFlush(msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + closeOnFlush(inboundChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.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/MultiProtocolProxyServer.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/MultiProtocolProxyServer.java new file mode 100644 index 0000000..4a156e5 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/MultiProtocolProxyServer.java @@ -0,0 +1,312 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramPacket; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.*; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; + +import java.net.InetSocketAddress; +import java.net.URI; + +public class MultiProtocolProxyServer { + private static final int HTTP_PORT = 8080; + private static final int TCP_PORT = 9090; + private static final int UDP_PORT = 10000; + + public static void main(String[] args) throws Exception { + EventLoopGroup bossGroup = new NioEventLoopGroup(); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + + try { + // 启动 HTTP 代理服务器 + startHttpProxy(bossGroup, workerGroup); + // 启动 TCP 代理服务器 + startTcpProxy(bossGroup, workerGroup); + // 启动 UDP 代理服务器 + startUdpProxy(workerGroup); + + System.out.println("Proxy servers started."); + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + + private static void startHttpProxy(EventLoopGroup bossGroup, EventLoopGroup workerGroup) throws InterruptedException { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast( + new HttpClientCodec(), + new HttpObjectAggregator(1048576), + new HttpProxyServerHandler() + ); + } + }); + + b.bind(HTTP_PORT).sync(); + System.out.println("HTTP proxy server started on port " + HTTP_PORT); + } + + private static void startTcpProxy(EventLoopGroup bossGroup, EventLoopGroup workerGroup) throws InterruptedException { + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(new TcpProxyServerHandler()); + } + }); + + b.bind(TCP_PORT).sync(); + System.out.println("TCP proxy server started on port " + TCP_PORT); + } + + private static void startUdpProxy(EventLoopGroup workerGroup) throws InterruptedException { + Bootstrap b = new Bootstrap(); + b.group(workerGroup) + .channel(NioDatagramChannel.class) + .handler(new UdpProxyServerHandler()); + + b.bind(UDP_PORT).sync(); + System.out.println("UDP proxy server started on port " + UDP_PORT); + } + + private static class HttpProxyServerHandler extends ChannelInboundHandlerAdapter { + private Channel outboundChannel; + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof FullHttpRequest) { + FullHttpRequest request = (FullHttpRequest) msg; + URI uri = new URI(request.uri()); + String host = uri.getHost(); + int port = uri.getPort(); + if (port == -1) { + port = 80; + } + + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast( + new HttpClientCodec(), + new HttpObjectAggregator(1048576), + new HttpProxyBackendHandler(ctx.channel()) + ); + } + }); + + ChannelFuture f = b.connect(host, port); + outboundChannel = f.channel(); + f.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + outboundChannel.writeAndFlush(request.retain()); + } else { + ctx.channel().close(); + } + } + }); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (outboundChannel != null) { + closeOnFlush(outboundChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class HttpProxyBackendHandler extends ChannelInboundHandlerAdapter { + private final Channel inboundChannel; + + HttpProxyBackendHandler(Channel inboundChannel) { + this.inboundChannel = inboundChannel; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + inboundChannel.writeAndFlush(msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + closeOnFlush(inboundChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class TcpProxyServerHandler extends ChannelInboundHandlerAdapter { + private Channel outboundChannel; + + @Override + public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { + if (outboundChannel == null) { + // 假设目标服务器地址和端口 + String targetHost = "example.com"; + int targetPort = 80; + + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast(new TcpProxyBackendHandler(ctx.channel())); + } + }); + + ChannelFuture f = b.connect(targetHost, targetPort); + outboundChannel = f.channel(); + f.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + outboundChannel.writeAndFlush(msg); + } else { + ctx.channel().close(); + } + } + }); + } else { + outboundChannel.writeAndFlush(msg); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (outboundChannel != null) { + closeOnFlush(outboundChannel); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class TcpProxyBackendHandler extends ChannelInboundHandlerAdapter { + private final Channel inboundChannel; + + TcpProxyBackendHandler(Channel inboundChannel) { + this.inboundChannel = inboundChannel; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + inboundChannel.writeAndFlush(msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + closeOnFlush(inboundChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + closeOnFlush(ctx.channel()); + } + + static void closeOnFlush(Channel ch) { + if (ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } + } + + private static class UdpProxyServerHandler extends SimpleChannelInboundHandler { + private InetSocketAddress targetAddress = new InetSocketAddress("example.com", 80); + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { + Bootstrap b = new Bootstrap(); + b.group(ctx.channel().eventLoop()) + .channel(NioDatagramChannel.class) + .handler(new UdpProxyBackendHandler(ctx.channel(), packet.sender())); + + Channel channel = b.bind(0).sync().channel(); + channel.writeAndFlush(new DatagramPacket(packet.content().retain(), targetAddress)); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + cause.printStackTrace(); + ctx.close(); + } + } + + private static class UdpProxyBackendHandler extends SimpleChannelInboundHandler { + private final Channel inboundChannel; + private final InetSocketAddress clientAddress; + + UdpProxyBackendHandler(Channel inboundChannel, InetSocketAddress clientAddress) { + this.inboundChannel = inboundChannel; + this.clientAddress = clientAddress; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception { + inboundChannel.writeAndFlush(new DatagramPacket(packet.content().retain(), clientAddress)); + ctx.channel().close(); + } + + @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/demo/DnsServer.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/DnsServer.java new file mode 100644 index 0000000..292cef7 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/DnsServer.java @@ -0,0 +1,124 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.demo; + + +import com.github.xiaoymin.knife4j.core.util.StrUtil; +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.handler.codec.dns.*; +import io.netty.util.AttributeKey; +import lombok.extern.slf4j.Slf4j; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public final class DnsServer { + + private static final List BLACK_LIST_DOMAIN = new ArrayList<>(); + + static { + + String s; + try (InputStream is = DnsServer.class.getClassLoader().getResourceAsStream("black_list.txt"); + BufferedReader br = new BufferedReader(new InputStreamReader(is))) { + while (StrUtil.isNotBlank(s = br.readLine())) { + BLACK_LIST_DOMAIN.add(s); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + + public static void main(String[] args) throws Exception { + ProxyUdp proxyUdp = new ProxyUdp(); + proxyUdp.init(); + final int[] num = {0}; + final NioEventLoopGroup group = new NioEventLoopGroup(); + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(group).channel(NioDatagramChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(NioDatagramChannel nioDatagramChannel) { + nioDatagramChannel.pipeline().addLast(new DatagramDnsQueryDecoder()); + nioDatagramChannel.pipeline().addLast(new SimpleChannelInboundHandler() { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery msg) { + try { + DefaultDnsQuestion dnsQuestion = msg.recordAt(DnsSection.QUESTION); + String name = dnsQuestion.name(); + log.info(name + ++num[0]); + Channel channel = ctx.channel(); + int id = msg.id(); + channel.attr(AttributeKey.valueOf(String.valueOf(id))).set(msg); + if (BLACK_LIST_DOMAIN.contains(name)) { + DnsQuestion question = msg.recordAt(DnsSection.QUESTION); + DatagramDnsResponse dnsResponse = getDatagramDnsResponse(msg, id, question); + channel.writeAndFlush(dnsResponse); + return; + } + proxyUdp.send(name, msg.id(), channel); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + + private DatagramDnsResponse getDatagramDnsResponse(DatagramDnsQuery msg, int id, DnsQuestion question) { + DatagramDnsResponse dnsResponse = new DatagramDnsResponse(msg.recipient(), msg.sender(), id); + dnsResponse.addRecord(DnsSection.QUESTION, question); + + InetAddress inetAddress = null; + try { + inetAddress = Inet4Address.getByName("www.baidu.com"); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + byte[] ipBytes = inetAddress.getAddress(); + // just print the IP after query +// DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord( +// question.name(), +// DnsRecordType.A, 600, Unpooled.wrappedBuffer(new byte[]{(byte) 192, (byte) 168, 1, 1})); + + DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord( + question.name(), + DnsRecordType.A, + 600, + Unpooled.wrappedBuffer(ipBytes) + ); + + dnsResponse.addRecord(DnsSection.ANSWER, queryAnswer); + return dnsResponse; + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) { + log.error(e.getMessage(), e); + } + }); + nioDatagramChannel.pipeline().addLast(new DatagramDnsResponseEncoder()); + + } + }).option(ChannelOption.SO_BROADCAST, true); + + int port = 53; + ChannelFuture future = bootstrap.bind(port).addListener(future1 -> { + log.info("server listening port:{}", port); + }); + + future.channel().closeFuture().addListener(future1 -> { + if (future.isSuccess()) { + log.info(future.channel().toString()); + } + }); + } +} + diff --git a/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/ProxyUdp.java b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/ProxyUdp.java new file mode 100644 index 0000000..5850dc5 --- /dev/null +++ b/wu-lazy-cloud-heartbeat-protocol-proxy/src/test/java/org/framework/lazy/cloud/network/heartbeat/protocol/demo/ProxyUdp.java @@ -0,0 +1,80 @@ +package org.framework.lazy.cloud.network.heartbeat.protocol.demo; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.handler.codec.dns.*; +import io.netty.util.AttributeKey; +import lombok.extern.slf4j.Slf4j; + +import java.net.InetSocketAddress; + +@Slf4j +class ProxyUdp { + private Channel localChannel; + private Channel proxyChannel; + + public void init() throws InterruptedException { + EventLoopGroup proxyGroup = new NioEventLoopGroup(); + Bootstrap b = new Bootstrap(); + b.group(proxyGroup) + .channel(NioDatagramChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(DatagramChannel ch) { + ChannelPipeline p = ch.pipeline(); + p.addLast(new DatagramDnsQueryEncoder()) + .addLast(new DatagramDnsResponseDecoder()) + .addLast(new SimpleChannelInboundHandler() { + @Override + public void channelActive(ChannelHandlerContext ctx) { + log.info(ctx.channel().toString()); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsResponse msg) { + DatagramDnsQuery dnsQuery = localChannel.attr(AttributeKey.valueOf(String.valueOf(msg.id()))).get(); + DnsQuestion question = msg.recordAt(DnsSection.QUESTION); + DatagramDnsResponse dnsResponse = new DatagramDnsResponse(dnsQuery.recipient(), dnsQuery.sender(), msg.id()); + dnsResponse.addRecord(DnsSection.QUESTION, question); + + for (int i = 0, count = msg.count(DnsSection.ANSWER); i < count; i++) { + DnsRecord record = msg.recordAt(DnsSection.ANSWER, i); + if (record.type() == DnsRecordType.A) { + // just print the IP after query + DnsRawRecord raw = (DnsRawRecord) record; + DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord( + question.name(), + DnsRecordType.A, 600, Unpooled.wrappedBuffer(ByteBufUtil.getBytes(raw.content()))); + dnsResponse.addRecord(DnsSection.ANSWER, queryAnswer); + } + } + + localChannel.writeAndFlush(dnsResponse); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) { + log.error(e.getMessage(), e); + } + }); + + } + }); + proxyChannel = b.bind(0).sync().addListener(future1 -> { + log.info("绑定成功"); + }).channel(); + } + + public void send(String domain, int id, Channel localChannel) { + this.localChannel = localChannel; + DnsQuery query = new DatagramDnsQuery(null, new InetSocketAddress("114.114.114.114", 53), id).setRecord( + DnsSection.QUESTION, + new DefaultDnsQuestion(domain, DnsRecordType.A)); + this.proxyChannel.writeAndFlush(query); + } +} \ No newline at end of file