From 4b278216e59cf0b1f7cf8fbd08c64d760a53ab00 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Tue, 12 Sep 2023 14:07:28 +0800 Subject: [PATCH 01/20] =?UTF-8?q?=E6=9B=B4=E6=96=B0todolist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- todolist.MD | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/todolist.MD b/todolist.MD index e637ffb1..0f245b65 100644 --- a/todolist.MD +++ b/todolist.MD @@ -13,13 +13,18 @@ # 1.8.6 - [x] 端口映射选择端口支持分页 - [x] 新增/更新端口映射,增加端口占用检测 -- [ ] 增加服务端/客户端jar式一键部署脚本 - [x] 拉下搜索license,支持模糊搜索 - [x] license下拉用户搜索,支持模糊搜索 - [x] 端口映射编辑时,如果端口号没有变动,则不验证。避免出现端口映射正在使用时,无法更新端口映射其他信息的问题 - [x] 端口映射HTTP(S)新增打开网页按钮 - [x] 客户端断开连接时,记录日志空指针异常问题修复 + + +# 1.8.7 +- [ ] 增加服务端/客户端jar式一键部署脚本 - [ ] 排查解决问题:https://gitee.com/dromara/neutrino-proxy/issues/I7LGLB +- [ ] 访问白名单 +- [ ] 端口映射分组 # Bug - 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive From 0301f1562816f4665ca6c5ccb644fabe00a9ce0f Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 13 Sep 2023 11:11:32 +0800 Subject: [PATCH 02/20] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/01.使用教程/01.开始使用/01.快速上手.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/01.快速上手.md b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/01.快速上手.md index 5436e5a9..41cb28ca 100644 --- a/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/01.快速上手.md +++ b/neutrino-proxy-vuepress/docs/01.使用教程/01.开始使用/01.快速上手.md @@ -48,7 +48,7 @@ registry.cn-hangzhou.aliyuncs.com/asgc/neutrino-proxy:latest - 解压`neutrino-proxy-admin.zip`文件 - 执行命令`java -Dfile.encoding=utf-8 -jar neutrino-proxy-server.jar`启动服务端完成部署,默认使用sqlite数据库。 - 若需要指定自己的mysql数据库,同样的需要在当前目录下新建`app.yml`文件,文件内容同上。执行命令`java -Dfile.encoding=utf-8 -jar neutrino-proxy-server.jar config=app.yml`启动服务端完成部署 -- 可参照 https://gitee.com/dromara/neutrino-proxy/blob/master/bin/server_start.sh 使用shell脚本启动服务端。 +- 可参照 https://gitee.com/dromara/neutrino-proxy/blob/master/scripts/unix/server_start.sh 使用shell脚本启动服务端。 ## 2、管理后台配置 - 服务端部署成功后,访问`http://{服务端IP}:8888`打开后台管理页面。 From 5b2fe447b21f244e28a305e304c16bc478039631 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Sat, 16 Sep 2023 17:47:27 +0800 Subject: [PATCH 03/20] =?UTF-8?q?=E6=9B=B4=E6=96=B0todolist=EF=BC=8C?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E9=80=82=E5=BA=94udp=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/base/proxy/ProxyConfig.java | 28 +++++-- .../server/base/proxy/ProxyConfiguration.java | 83 ++++++++++++++----- .../controller/DomainNameController.java | 2 +- .../proxy/core/UdpVisitorChannelHandler.java | 18 ++++ .../server/proxy/enhance/HttpProxy.java | 10 +-- .../server/proxy/enhance/HttpsProxy.java | 18 ++-- .../server/service/PortMappingService.java | 10 +-- .../src/main/resources/app.yml | 35 ++++---- todolist.MD | 3 +- 9 files changed, 143 insertions(+), 64 deletions(-) create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java index 928db99f..60f89e23 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfig.java @@ -42,14 +42,8 @@ public class ProxyConfig { @Data public static class Server { - private Integer bossThreadCount; - private Integer workThreadCount; - private String domainName; - private Integer httpProxyPort; - private Integer httpsProxyPort; - private String keyStorePassword; - private String jksPath; - private Boolean transferLogEnable; + private Tcp tcp; + private Udp udp; } @Data @@ -65,4 +59,22 @@ public class ProxyConfig { private Boolean heartbeatLogEnable; } + @Data + public static class Tcp { + private Integer bossThreadCount; + private Integer workThreadCount; + private String domainName; + private Integer httpProxyPort; + private Integer httpsProxyPort; + private String keyStorePassword; + private String jksPath; + private Boolean transferLogEnable; + } + + @Data + public static class Udp { + private Integer bossThreadCount; + private Integer workThreadCount; + private Boolean transferLogEnable; + } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java index 14dd698b..3188e182 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java @@ -1,8 +1,12 @@ package org.dromara.neutrinoproxy.server.base.proxy; +import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.logging.LoggingHandler; import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum; @@ -13,8 +17,8 @@ import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.nio.NioEventLoopGroup; import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler; -import org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelServer; import org.dromara.neutrinoproxy.server.proxy.core.TcpVisitorChannelHandler; +import org.dromara.neutrinoproxy.server.proxy.core.UdpVisitorChannelHandler; import org.noear.solon.Solon; import org.noear.solon.annotation.Bean; import org.noear.solon.annotation.Configuration; @@ -35,43 +39,80 @@ public class ProxyConfiguration implements LifecycleBean { public void start() throws Throwable { List list = Solon.context().getBeansOfType(ProxyMessageHandler.class); Dispatcher dispatcher = new DefaultDispatcher<>("消息调度器", list, - proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ? - null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName()); + proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ? + null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName()); Solon.context().wrapAndPut(Dispatcher.class, dispatcher); } - @Bean("serverBossGroup") - public NioEventLoopGroup serverBossGroup(@Inject ProxyConfig proxyConfig) { - return new NioEventLoopGroup(proxyConfig.getServer().getBossThreadCount()); + @Bean("tcpServerBossGroup") + public NioEventLoopGroup tcpServerBossGroup(@Inject ProxyConfig proxyConfig) { + return new NioEventLoopGroup(proxyConfig.getServer().getTcp().getBossThreadCount()); } - @Bean("serverWorkerGroup") - public NioEventLoopGroup serverWorkerGroup(@Inject ProxyConfig proxyConfig) { - return new NioEventLoopGroup(proxyConfig.getServer().getWorkThreadCount()); + @Bean("tcpServerWorkerGroup") + public NioEventLoopGroup tcpServerWorkerGroup(@Inject ProxyConfig proxyConfig) { + return new NioEventLoopGroup(proxyConfig.getServer().getTcp().getWorkThreadCount()); } @Bean("tcpServerBootstrap") - public ServerBootstrap tcpServerBootstrap(@Inject("serverBossGroup") NioEventLoopGroup serverBossGroup, - @Inject("serverWorkerGroup") NioEventLoopGroup serverWorkerGroup, + public ServerBootstrap tcpServerBootstrap(@Inject("tcpServerBossGroup") NioEventLoopGroup tcpServerBossGroup, + @Inject("tcpServerWorkerGroup") NioEventLoopGroup tcpServerWorkerGroup, @Inject ProxyConfig proxyConfig ) { ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(serverBossGroup, serverWorkerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { - @Override - public void initChannel(SocketChannel ch) throws Exception { - if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) { - ch.pipeline().addFirst(new LoggingHandler(TcpVisitorChannelHandler.class)); - } - ch.pipeline().addFirst(new BytesMetricsHandler()); - ch.pipeline().addLast(new TcpVisitorChannelHandler()); + bootstrap.group(tcpServerBossGroup, tcpServerWorkerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + if (null != proxyConfig.getServer().getTcp().getTransferLogEnable() && proxyConfig.getServer().getTcp().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(TcpVisitorChannelHandler.class)); + } + ch.pipeline().addFirst(new BytesMetricsHandler()); + ch.pipeline().addLast(new TcpVisitorChannelHandler()); } }); return bootstrap; } + @Bean("udpServerBossGroup") + private NioEventLoopGroup udpBossGroup(@Inject ProxyConfig proxyConfig) { + return new NioEventLoopGroup(proxyConfig.getServer().getUdp().getBossThreadCount()); + } + + @Bean("udpServerWorkerGroup") + private NioEventLoopGroup udpWorkerGroup(@Inject ProxyConfig proxyConfig) { + return new NioEventLoopGroup(proxyConfig.getServer().getUdp().getWorkThreadCount()); + } + + @Bean("udpServerBootstrap") + public Bootstrap udpBootstrap(@Inject("udpServerBossGroup") NioEventLoopGroup udpServerBossGroup, + @Inject("udpServerWorkerGroup") NioEventLoopGroup udpServerWorkerGroup, + @Inject ProxyConfig proxyConfig) { + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(udpServerBossGroup) + // 主线程处理 + .channel(NioDatagramChannel.class) + // 广播 + .option(ChannelOption.SO_BROADCAST, true) + // 设置读缓冲区为2M + .option(ChannelOption.SO_RCVBUF, 2048 * 1024) + // 设置写缓冲区为1M + .option(ChannelOption.SO_SNDBUF, 1024 * 1024) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(NioDatagramChannel ch) { + ChannelPipeline pipeline = ch.pipeline(); + if (null != proxyConfig.getServer().getUdp().getTransferLogEnable() && proxyConfig.getServer().getUdp().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(UdpVisitorChannelHandler.class)); + } + pipeline.addLast(udpServerWorkerGroup, new UdpVisitorChannelHandler()); + } + }); + return bootstrap; + } + @Bean("tunnelBossGroup") public NioEventLoopGroup tunnelBossGroup(@Inject ProxyConfig proxyConfig) { return new NioEventLoopGroup(proxyConfig.getTunnel().getBossThreadCount()); diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java index 3ff09d03..3f64d661 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/controller/DomainNameController.java @@ -21,7 +21,7 @@ public class DomainNameController { @Get @Mapping("/bind-info") public String bindInfo () { - return proxyConfig.getServer().getDomainName(); + return proxyConfig.getServer().getTcp().getDomainName(); } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java new file mode 100644 index 00000000..26492d10 --- /dev/null +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java @@ -0,0 +1,18 @@ +package org.dromara.neutrinoproxy.server.proxy.core; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.socket.DatagramPacket; + +/** + * @author: aoshiguchen + * @date: 2023/9/16 + */ +public class UdpVisitorChannelHandler extends SimpleChannelInboundHandler { + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) throws Exception { + + } + +} diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java index 742be02f..9c8716c9 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java @@ -28,7 +28,7 @@ public class HttpProxy implements EventListener { private ProxyConfig proxyConfig; @Override public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable { - if (StrUtil.isBlank(proxyConfig.getServer().getDomainName()) || null == proxyConfig.getServer().getHttpProxyPort()) { + if (StrUtil.isBlank(proxyConfig.getServer().getTcp().getDomainName()) || null == proxyConfig.getServer().getTcp().getHttpProxyPort()) { log.info("no config domain name,nonsupport http proxy."); return; } @@ -42,15 +42,15 @@ public class HttpProxy implements EventListener { .channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { - if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) { + if (null != proxyConfig.getServer().getTcp().getTransferLogEnable() && proxyConfig.getServer().getTcp().getTransferLogEnable()) { ch.pipeline().addFirst(new LoggingHandler(HttpProxy.class)); } ch.pipeline().addFirst(new BytesMetricsHandler()); - ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName())); + ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getTcp().getDomainName())); } }); - bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpProxyPort()).sync(); - log.info("Http代理服务启动成功!port:{}", proxyConfig.getServer().getHttpProxyPort()); + bootstrap.bind("0.0.0.0", proxyConfig.getServer().getTcp().getHttpProxyPort()).sync(); + log.info("Http代理服务启动成功!port:{}", proxyConfig.getServer().getTcp().getHttpProxyPort()); } catch (Exception e) { log.error("http proxy start err!", e); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java index 85699f3d..281cfda0 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java @@ -35,8 +35,8 @@ public class HttpsProxy implements EventListener { private ProxyConfig proxyConfig; @Override public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable { - if (StrUtil.isBlank(proxyConfig.getServer().getDomainName()) || null == proxyConfig.getServer().getHttpsProxyPort() || - StringUtils.isEmpty(proxyConfig.getServer().getJksPath()) || StringUtils.isEmpty(proxyConfig.getServer().getKeyStorePassword())) { + if (StrUtil.isBlank(proxyConfig.getServer().getTcp().getDomainName()) || null == proxyConfig.getServer().getTcp().getHttpsProxyPort() || + StringUtils.isEmpty(proxyConfig.getServer().getTcp().getJksPath()) || StringUtils.isEmpty(proxyConfig.getServer().getTcp().getKeyStorePassword())) { log.info("no config domain name,nonsupport https proxy."); return; } @@ -50,16 +50,16 @@ public class HttpsProxy implements EventListener { .channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { - if (null != proxyConfig.getServer().getTransferLogEnable() && proxyConfig.getServer().getTransferLogEnable()) { + if (null != proxyConfig.getServer().getTcp().getTransferLogEnable() && proxyConfig.getServer().getTcp().getTransferLogEnable()) { ch.pipeline().addFirst(new LoggingHandler(HttpsProxy.class)); } ch.pipeline().addLast(createSslHandler()); ch.pipeline().addFirst(new BytesMetricsHandler()); - ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName())); + ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getTcp().getDomainName())); } }); - bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpsProxyPort()).sync(); - log.info("Https代理服务启动成功!port:{}", proxyConfig.getServer().getHttpsProxyPort()); + bootstrap.bind("0.0.0.0", proxyConfig.getServer().getTcp().getHttpsProxyPort()).sync(); + log.info("Https代理服务启动成功!port:{}", proxyConfig.getServer().getTcp().getHttpsProxyPort()); } catch (Exception e) { log.error("https proxy start err!", e); } @@ -67,13 +67,13 @@ public class HttpsProxy implements EventListener { private ChannelHandler createSslHandler() { try { - InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getServer().getJksPath()); + InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getServer().getTcp().getJksPath()); SSLContext serverContext = SSLContext.getInstance("TLS"); final KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(jksInputStream, proxyConfig.getServer().getKeyStorePassword().toCharArray()); + ks.load(jksInputStream, proxyConfig.getServer().getTcp().getKeyStorePassword().toCharArray()); final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(ks, proxyConfig.getServer().getKeyStorePassword().toCharArray()); + kmf.init(ks, proxyConfig.getServer().getTcp().getKeyStorePassword().toCharArray()); TrustManager[] trustManagers = null; serverContext.init(kmf.getKeyManagers(), trustManagers, null); diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java index 76a5e881..5febb14e 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/PortMappingService.java @@ -110,8 +110,8 @@ public class PortMappingService implements LifecycleBean { return; } item.setUserName(user.getName()); - if (StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(item.getSubdomain())) { - item.setDomain(item.getSubdomain() + "." + proxyConfig.getServer().getDomainName()); + if (StrUtil.isNotBlank(proxyConfig.getServer().getTcp().getDomainName()) && StrUtil.isNotBlank(item.getSubdomain())) { + item.setDomain(item.getSubdomain() + "." + proxyConfig.getServer().getTcp().getDomainName()); } if (NetworkProtocolEnum.HTTP.getDesc().equals(item.getProtocal())) { item.setProtocal("HTTP(S)"); @@ -151,7 +151,7 @@ public class PortMappingService implements LifecycleBean { // 更新VisitorChannel visitorChannelService.addVisitorChannelByPortMapping(portMappingDO); // 更新域名映射 - if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getTcp().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort()); } return new PortMappingCreateRes(); @@ -192,7 +192,7 @@ public class PortMappingService implements LifecycleBean { ProxyUtil.removeSubdomainToServerPort(oldPortMappingDO.getSubdomain()); } // 更新域名映射 - if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { + if (NetworkProtocolEnum.isHttp(portMappingDO.getProtocal()) && StrUtil.isNotBlank(proxyConfig.getServer().getTcp().getDomainName()) && StrUtil.isNotBlank(portMappingDO.getSubdomain())) { ProxyUtil.setSubdomainToServerPort(portMappingDO.getSubdomain(), portMappingDO.getServerPort()); } return new PortMappingUpdateRes(); @@ -279,7 +279,7 @@ public class PortMappingService implements LifecycleBean { portMappingMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date()); // 未配置域名,则不需要处理域名映射逻辑 - if (StrUtil.isBlank(proxyConfig.getServer().getDomainName())) { + if (StrUtil.isBlank(proxyConfig.getServer().getTcp().getDomainName())) { return; } List portMappingDOList = portMappingMapper.selectList(new LambdaQueryWrapper().eq(PortMappingDO::getProtocal, NetworkProtocolEnum.HTTP.getDesc()).isNotNull(PortMappingDO::getSubdomain)); diff --git a/neutrino-proxy-server/src/main/resources/app.yml b/neutrino-proxy-server/src/main/resources/app.yml index 99082f24..d268da3b 100644 --- a/neutrino-proxy-server/src/main/resources/app.yml +++ b/neutrino-proxy-server/src/main/resources/app.yml @@ -35,20 +35,27 @@ neutrino: # 是否开启心跳日志 heartbeat-log-enable: ${HEARTBEAT_LOG:false} server: - # 线程池相关配置,用于技术调优,可忽略 - boss-thread-count: 5 - work-thread-count: 20 - # http代理端口,默认80 - http-proxy-port: ${HTTP_PROXY_PORT:80} - # https代理端口,默认443 (需要配置域名、证书) - https-proxy-port: ${HTTPS_PROXY_PORT:443} - # 如果不配置,则不支持域名映射 - domain-name: ${DOMAIN_NAME:} - # https证书配置 - key-store-password: ${HTTPS_STORE_PASS:} - jks-path: ${HTTPS_JKS_PATH:} - # 是否开启代理服务报文日志(日志级别为debug时开启才有效) - transfer-log-enable: ${SERVER_LOG:false} + tcp: + # 线程池相关配置,用于技术调优,可忽略 + boss-thread-count: 5 + work-thread-count: 20 + # http代理端口,默认80 + http-proxy-port: ${HTTP_PROXY_PORT:80} + # https代理端口,默认443 (需要配置域名、证书) + https-proxy-port: ${HTTPS_PROXY_PORT:443} + # 如果不配置,则不支持域名映射 + domain-name: ${DOMAIN_NAME:} + # https证书配置 + key-store-password: ${HTTPS_STORE_PASS:} + jks-path: ${HTTPS_JKS_PATH:} + # 是否开启代理服务报文日志(日志级别为debug时开启才有效) + transfer-log-enable: ${SERVER_LOG:false} + udp: + # 线程池相关配置,用于技术调优,可忽略 + boss-thread-count: 5 + work-thread-count: 20 + # 是否开启代理服务报文日志(日志级别为debug时开启才有效) + transfer-log-enable: ${SERVER_LOG:false} data: db: # 数据库类型,目前支持sqlite、mysql、mariadb diff --git a/todolist.MD b/todolist.MD index 0f245b65..264c8d08 100644 --- a/todolist.MD +++ b/todolist.MD @@ -20,11 +20,12 @@ - [x] 客户端断开连接时,记录日志空指针异常问题修复 -# 1.8.7 +# 1.9.0 - [ ] 增加服务端/客户端jar式一键部署脚本 - [ ] 排查解决问题:https://gitee.com/dromara/neutrino-proxy/issues/I7LGLB - [ ] 访问白名单 - [ ] 端口映射分组 +- [ ] 支持UDP # Bug - 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive From f46332db4a0ed4759850d1aa6cd39507bdcd3ef6 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Sat, 16 Sep 2023 18:10:26 +0800 Subject: [PATCH 04/20] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E9=80=82?= =?UTF-8?q?=E5=BA=94udp=E9=85=8D=E7=BD=AE=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/client/ProxyClient.java | 12 +++---- .../client/config/ProxyConfig.java | 20 ++++++++++- .../client/core/CmdChannelHandler.java | 4 +-- .../client/core/ProxyClientService.java | 36 +++++++++---------- .../handler/ProxyMessageAuthHandler.java | 2 +- .../handler/ProxyMessageConnectHandler.java | 2 +- .../neutrinoproxy/client/util/ProxyUtil.java | 4 +-- .../src/main/resources/app.yml | 3 +- todolist.MD | 4 +++ 9 files changed, 55 insertions(+), 32 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java index c01f343a..feca73ae 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java @@ -22,12 +22,12 @@ public class ProxyClient { public static void main(String[] args) { Solon.start(ProxyClient.class, args, app -> { - setAlias("neutrino.proxy.client.serverIp", "serverIp"); - setAlias("neutrino.proxy.client.serverPort", "serverPort"); - setAlias("neutrino.proxy.client.sslEnable", "sslEnable"); - setAlias("neutrino.proxy.client.jksPath", "jksPath"); - setAlias("neutrino.proxy.client.keyStorePassword", "keyStorePassword"); - setAlias("neutrino.proxy.client.licenseKey", "licenseKey"); + setAlias("neutrino.proxy.tunnel.serverIp", "serverIp"); + setAlias("neutrino.proxy.tunnel.serverPort", "serverPort"); + setAlias("neutrino.proxy.tunnel.sslEnable", "sslEnable"); + setAlias("neutrino.proxy.tunnel.jksPath", "jksPath"); + setAlias("neutrino.proxy.tunnel.keyStorePassword", "keyStorePassword"); + setAlias("neutrino.proxy.tunnel.licenseKey", "licenseKey"); // 设置日志级别 setLogLevel(app); }); diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java index 68aa435b..1ef6d166 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java @@ -14,6 +14,8 @@ import org.noear.solon.annotation.Inject; public class ProxyConfig { @Inject("${neutrino.proxy.protocol}") private Protocol protocol; + @Inject("${neutrino.proxy.tunnel}") + private Tunnel tunnel; @Inject("${neutrino.proxy.client}") private Client client; @@ -30,7 +32,7 @@ public class ProxyConfig { } @Data - public static class Client { + public static class Tunnel { private String keyStorePassword; private String jksPath; private String serverIp; @@ -45,9 +47,25 @@ public class ProxyConfig { private Reconnection reconnection; } + @Data + public static class Client { +// private Tcp tcp; +// private Udp udp; + } + @Data public static class Reconnection { private Integer intervalSeconds; private Boolean unlimited; } + + @Data + private static class Tcp { + + } + + @Data + private static class Udp { + + } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java index decd5c0b..5d482fea 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java @@ -24,8 +24,8 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler public CmdChannelHandler() { ProxyConfig proxyConfig = Solon.context().getBean(ProxyConfig.class); - if (null != proxyConfig.getClient() && null != proxyConfig.getClient().getHeartbeatLogEnable()) { - transferLogEnable = proxyConfig.getClient().getHeartbeatLogEnable(); + if (null != proxyConfig.getClient() && null != proxyConfig.getTunnel().getHeartbeatLogEnable()) { + transferLogEnable = proxyConfig.getTunnel().getHeartbeatLogEnable(); } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index b3365549..39c6f38c 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -69,8 +69,8 @@ public class ProxyClientService { @Init public void init() { - this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, proxyConfig.getClient().getReconnection().getIntervalSeconds(), TimeUnit.SECONDS); - this.workerGroup = new NioEventLoopGroup(proxyConfig.getClient().getThreadCount()); + this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, proxyConfig.getTunnel().getReconnection().getIntervalSeconds(), TimeUnit.SECONDS); + this.workerGroup = new NioEventLoopGroup(proxyConfig.getTunnel().getThreadCount()); realServerBootstrap.group(workerGroup); realServerBootstrap.channel(NioSocketChannel.class); @@ -78,7 +78,7 @@ public class ProxyClientService { @Override public void initChannel(SocketChannel ch) throws Exception { - if (null != proxyConfig.getClient().getTransferLogEnable() && proxyConfig.getClient().getTransferLogEnable()) { + if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { ch.pipeline().addFirst(new LoggingHandler(RealServerChannelHandler.class)); } ch.pipeline().addLast(new RealServerChannelHandler()); @@ -87,15 +87,15 @@ public class ProxyClientService { proxyTunnelBootstrap.group(workerGroup); proxyTunnelBootstrap.channel(NioSocketChannel.class); - proxyTunnelBootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getClient().getServerIp(), proxyConfig.getClient().getServerPort())); + proxyTunnelBootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getTunnel().getServerIp(), proxyConfig.getTunnel().getServerPort())); proxyTunnelBootstrap.handler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { - if (proxyConfig.getClient().getSslEnable()) { + if (proxyConfig.getTunnel().getSslEnable()) { ch.pipeline().addLast(createSslHandler()); } - if (null != proxyConfig.getClient().getTransferLogEnable() && proxyConfig.getClient().getTransferLogEnable()) { + if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { ch.pipeline().addFirst(new LoggingHandler(ProxyChannelHandler.class)); } ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), @@ -116,16 +116,16 @@ public class ProxyClientService { // * Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。 // */ // cmdTunnelBootstrap.option(ChannelOption.TCP_NODELAY, true); - cmdTunnelBootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getClient().getServerIp(), proxyConfig.getClient().getServerPort())); + cmdTunnelBootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getTunnel().getServerIp(), proxyConfig.getTunnel().getServerPort())); cmdTunnelBootstrap.handler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { - if (proxyConfig.getClient().getSslEnable()) { + if (proxyConfig.getTunnel().getSslEnable()) { ch.pipeline().addLast(createSslHandler()); } - if (null != proxyConfig.getClient().getTransferLogEnable() && proxyConfig.getClient().getTransferLogEnable()) { + if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { ch.pipeline().addFirst(new LoggingHandler(CmdChannelHandler.class)); } ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), @@ -146,23 +146,23 @@ public class ProxyClientService { } public void start() { - if (StrUtil.isEmpty(proxyConfig.getClient().getServerIp())) { + if (StrUtil.isEmpty(proxyConfig.getTunnel().getServerIp())) { log.error("not found server-ip config."); Solon.stop(); return; } - if (null == proxyConfig.getClient().getServerPort()) { + if (null == proxyConfig.getTunnel().getServerPort()) { log.error("not found server-port config."); Solon.stop(); return; } - if (null != proxyConfig.getClient().getSslEnable() && proxyConfig.getClient().getSslEnable() - && StrUtil.isEmpty(proxyConfig.getClient().getJksPath())) { + if (null != proxyConfig.getTunnel().getSslEnable() && proxyConfig.getTunnel().getSslEnable() + && StrUtil.isEmpty(proxyConfig.getTunnel().getJksPath())) { log.error("not found jks-path config."); Solon.stop(); return; } - if (StrUtil.isEmpty(proxyConfig.getClient().getLicenseKey())) { + if (StrUtil.isEmpty(proxyConfig.getTunnel().getLicenseKey())) { log.error("not found license-key config."); Solon.stop(); return; @@ -174,7 +174,7 @@ public class ProxyClientService { log.error("client start error", e); } } else { - channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey(), ProxyUtil.getClientId())); + channel.writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getTunnel().getLicenseKey(), ProxyUtil.getClientId())); } } @@ -191,7 +191,7 @@ public class ProxyClientService { channel = future.channel(); // 连接成功,向服务器发送客户端认证信息(licenseKey) ProxyUtil.setCmdChannel(future.channel()); - future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getClient().getLicenseKey(), ProxyUtil.getClientId())); + future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getTunnel().getLicenseKey(), ProxyUtil.getClientId())); log.info("[客户端指令隧道] 连接代理服务成功. channelId:{}", future.channel().id().asLongText()); // reconnectServiceEnable = true; @@ -205,11 +205,11 @@ public class ProxyClientService { private ChannelHandler createSslHandler() { try { - InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getClient().getJksPath()); + InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getTunnel().getJksPath()); SSLContext clientContext = SSLContext.getInstance("TLS"); final KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(jksInputStream, proxyConfig.getClient().getKeyStorePassword().toCharArray()); + ks.load(jksInputStream, proxyConfig.getTunnel().getKeyStorePassword().toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); TrustManager[] trustManagers = tmf.getTrustManagers(); diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java index e0a05f17..b97b6ed4 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageAuthHandler.java @@ -34,7 +34,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { // 客户端认证失败,直接停止服务 log.info("client auth failed , client stop."); context.channel().close(); - if (!proxyConfig.getClient().getReconnection().getUnlimited()) { + if (!proxyConfig.getTunnel().getReconnection().getUnlimited()) { Solon.stop(); } } else if (ExceptionEnum.CONNECT_FAILED.getCode().equals(code) || diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java index bf74b562..51003346 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java @@ -57,7 +57,7 @@ public class ProxyMessageConnectHandler implements ProxyMessageHandler { realServerChannel.attr(Constants.NEXT_CHANNEL).set(channel); // 远程绑定 - channel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId + "@" + proxyConfig.getClient().getLicenseKey())); + channel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId + "@" + proxyConfig.getTunnel().getLicenseKey())); realServerChannel.config().setOption(ChannelOption.AUTO_READ, true); ProxyUtil.addRealServerChannel(visitorId, realServerChannel); diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java index 4514c78c..80121228 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java @@ -140,8 +140,8 @@ public class ProxyUtil { return clientId; } ProxyConfig proxyConfig = Solon.context().getBean(ProxyConfig.class); - if (StringUtils.isNotBlank(proxyConfig.getClient().getClientId())) { - clientId = proxyConfig.getClient().getClientId(); + if (StringUtils.isNotBlank(proxyConfig.getTunnel().getClientId())) { + clientId = proxyConfig.getTunnel().getClientId(); return clientId; } String id = FileUtil.readContentAsString(CLIENT_ID_FILE); diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml index 23072516..28eb2c0b 100644 --- a/neutrino-proxy-client/src/main/resources/app.yml +++ b/neutrino-proxy-client/src/main/resources/app.yml @@ -15,7 +15,7 @@ neutrino: logger: # 日志级别 level: ${LOG_LEVEL:info} - client: + tunnel: # 线程池相关配置,用于技术调优,可忽略 thread-count: 50 # 隧道SSL证书配置 @@ -41,3 +41,4 @@ neutrino: interval-seconds: 10 # 是否开启无限重连(未开启时,客户端license不合法会自动停止应用,开启了则不会,请谨慎开启) unlimited: false + client: diff --git a/todolist.MD b/todolist.MD index 264c8d08..9017982a 100644 --- a/todolist.MD +++ b/todolist.MD @@ -26,6 +26,10 @@ - [ ] 访问白名单 - [ ] 端口映射分组 - [ ] 支持UDP + - 服务端 + - 原`neutrino.proxy.server`配置移到`neutrino.proxy.server.tcp`下 + - 客户端 + - 原`neutrino.proxy.client`配置移到`neutrino.proxy.tunnel`下 # Bug - 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive From bfe880a6c671e1121bcd84d09690495ab9b53c0c Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Sun, 17 Sep 2023 10:59:20 +0800 Subject: [PATCH 05/20] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=AB=AF=E5=8F=A3?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E6=94=AF=E6=8C=81=E9=80=89=E6=8B=A9UDP?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/base/proxy/ProxyConfiguration.java | 6 +++--- .../proxy/core/UdpVisitorChannelHandler.java | 4 +++- .../server/service/ProtocalService.java | 2 +- .../server/service/VisitorChannelService.java | 18 ++++++++++++++---- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java index 3188e182..0976afa6 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java @@ -77,17 +77,17 @@ public class ProxyConfiguration implements LifecycleBean { } @Bean("udpServerBossGroup") - private NioEventLoopGroup udpBossGroup(@Inject ProxyConfig proxyConfig) { + private NioEventLoopGroup udpServerBossGroup(@Inject ProxyConfig proxyConfig) { return new NioEventLoopGroup(proxyConfig.getServer().getUdp().getBossThreadCount()); } @Bean("udpServerWorkerGroup") - private NioEventLoopGroup udpWorkerGroup(@Inject ProxyConfig proxyConfig) { + private NioEventLoopGroup udpServerWorkerGroup(@Inject ProxyConfig proxyConfig) { return new NioEventLoopGroup(proxyConfig.getServer().getUdp().getWorkThreadCount()); } @Bean("udpServerBootstrap") - public Bootstrap udpBootstrap(@Inject("udpServerBossGroup") NioEventLoopGroup udpServerBossGroup, + public Bootstrap udpServerBootstrap(@Inject("udpServerBossGroup") NioEventLoopGroup udpServerBossGroup, @Inject("udpServerWorkerGroup") NioEventLoopGroup udpServerWorkerGroup, @Inject ProxyConfig proxyConfig) { Bootstrap bootstrap = new Bootstrap(); diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java index 26492d10..6c07bf00 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java @@ -4,6 +4,8 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.DatagramPacket; +import java.nio.charset.StandardCharsets; + /** * @author: aoshiguchen * @date: 2023/9/16 @@ -12,7 +14,7 @@ public class UdpVisitorChannelHandler extends SimpleChannelInboundHandler Date: Mon, 18 Sep 2023 18:53:45 +0800 Subject: [PATCH 06/20] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E6=94=B6?= =?UTF-8?q?=E5=88=B0=E6=9D=A5=E8=87=AA=E8=AE=BF=E9=97=AE=E8=80=85=E7=9A=84?= =?UTF-8?q?udp=E6=95=B0=E6=8D=AE=EF=BC=8C=E8=BD=AC=E5=8F=91=E5=88=B0?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/core/ProxyMessage.java | 24 +++++++++++ .../proxy/core/UdpVisitorChannelHandler.java | 42 ++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java index 5470565e..716557c4 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java @@ -66,6 +66,10 @@ public class ProxyMessage { * 通用异常信息 */ public static final byte TYPE_ERROR = 0x06; + /** + * UDP数据传输 + */ + private static final byte TYPE_UDP_TRANSFER = 0x07; /** * 消息类型 @@ -130,6 +134,17 @@ public class ProxyMessage { .setData(data); } + public static ProxyMessage buildUdpTransferMessage(String visitorIp, int visitorPort, String targetIp, int targetPort, byte[] data) { + return create().setType(TYPE_UDP_TRANSFER) + .setInfo(JSONObject.toJSONString(new UdpBaseInfo() + .setVisitorIp(visitorIp) + .setVisitorPort(visitorPort) + .setTargetIp(targetIp) + .setTargetPort(targetPort) + )) + .setData(data); + } + public static ProxyMessage buildErrMessage(ExceptionEnum exceptionEnum, String info) { JSONObject data = new JSONObject(); data.put("code", exceptionEnum.getCode()); @@ -142,4 +157,13 @@ public class ProxyMessage { public static ProxyMessage buildErrMessage(ExceptionEnum exceptionEnum) { return buildErrMessage(exceptionEnum, null); } + + @Accessors(chain = true) + @Data + public static class UdpBaseInfo { + private String visitorIp; + private int visitorPort; + private String targetIp; + private int targetPort; + } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java index 6c07bf00..546b6993 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java @@ -1,9 +1,15 @@ package org.dromara.neutrinoproxy.server.proxy.core; +import cn.hutool.core.util.StrUtil; +import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOption; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.DatagramPacket; +import org.dromara.neutrinoproxy.core.ProxyMessage; +import org.dromara.neutrinoproxy.server.util.ProxyUtil; +import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; /** @@ -13,8 +19,40 @@ import java.nio.charset.StandardCharsets; public class UdpVisitorChannelHandler extends SimpleChannelInboundHandler { @Override - protected void channelRead0(ChannelHandlerContext channelHandlerContext, DatagramPacket datagramPacket) throws Exception { + protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket datagramPacket) throws Exception { System.out.println("服务端接收到消息 \nsender:" + datagramPacket.sender().toString() + "内容\n" + datagramPacket.content().toString(StandardCharsets.UTF_8)); - } + Channel visitorChannel = ctx.channel(); + InetSocketAddress sa = (InetSocketAddress) visitorChannel.localAddress(); + Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(sa.getPort()); + + if (null == cmdChannel) { + // 该端口还没有代理客户端 + ctx.channel().close(); + return; + } + + // 根据代理服务端端口,获取被代理客户端局域网连接信息 + String lanInfo = ProxyUtil.getClientLanInfoByServerPort(sa.getPort()); + if (StrUtil.isEmpty(lanInfo)) { + ctx.channel().close(); + return; + } + + String[] targetInfo = lanInfo.split(":"); + String targetIp = targetInfo[0]; + int targetPort = Integer.parseInt(targetInfo[1]); + + // 转发代理数据 + byte[] bytes = new byte[datagramPacket.content().readableBytes()]; + datagramPacket.content().readBytes(bytes); + + cmdChannel.writeAndFlush(ProxyMessage.buildUdpTransferMessage( + sa.getAddress().getHostAddress(), + sa.getPort(), + targetIp, + targetPort, + bytes + )); + } } From 67c362b42368c7d19faf0e3859d28c80452aeb0a Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Tue, 19 Sep 2023 12:09:32 +0800 Subject: [PATCH 07/20] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../client/config/ProxyConfiguration.java | 120 +++++++++++++++-- .../client/core/ProxyClientService.java | 121 ------------------ .../handler/ProxyMessageConnectHandler.java | 6 +- .../neutrinoproxy/client/util/ProxyUtil.java | 33 +++++ 5 files changed, 146 insertions(+), 135 deletions(-) diff --git a/.gitignore b/.gitignore index 950efd68..154a6d15 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,4 @@ hs_err_pid* neutrino-proxy-vuepress/deploy.sh .NEUTRINO_PROXY_CLIENT_ID logs +**/ixxxk.com/** diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java index ca206083..a9256185 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java @@ -1,8 +1,16 @@ package org.dromara.neutrinoproxy.client.config; -import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum; -import org.dromara.neutrinoproxy.core.ProxyMessage; -import org.dromara.neutrinoproxy.core.ProxyMessageHandler; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.logging.LoggingHandler; +import io.netty.handler.timeout.IdleStateHandler; +import org.dromara.neutrinoproxy.client.core.CmdChannelHandler; +import org.dromara.neutrinoproxy.client.core.ProxyChannelHandler; +import org.dromara.neutrinoproxy.client.core.RealServerChannelHandler; +import org.dromara.neutrinoproxy.client.util.ProxyUtil; +import org.dromara.neutrinoproxy.core.*; import org.dromara.neutrinoproxy.core.dispatcher.DefaultDispatcher; import org.dromara.neutrinoproxy.core.dispatcher.Dispatcher; import io.netty.bootstrap.Bootstrap; @@ -10,8 +18,10 @@ import io.netty.channel.ChannelHandlerContext; import org.noear.solon.Solon; import org.noear.solon.annotation.Bean; import org.noear.solon.annotation.Configuration; +import org.noear.solon.annotation.Inject; import org.noear.solon.core.bean.LifecycleBean; +import java.net.InetSocketAddress; import java.util.List; /** @@ -31,19 +41,107 @@ public class ProxyConfiguration implements LifecycleBean { Solon.context().wrapAndPut(Dispatcher.class, dispatcher); } - @Bean("cmdTunnelBootstrap") - public Bootstrap cmdTunnelBootstrap() { - return new Bootstrap(); + @Bean("tunnelWorkGroup") + public NioEventLoopGroup tunnelWorkGroup(@Inject ProxyConfig proxyConfig) { + return new NioEventLoopGroup(proxyConfig.getTunnel().getThreadCount()); } - @Bean("proxyTunnelBootstrap") - public Bootstrap proxyTunnelBootstrap() { - return new Bootstrap(); + @Bean("tcpRealServerWorkGroup") + public NioEventLoopGroup tcpRealServerWorkGroup(@Inject ProxyConfig proxyConfig) { + // 暂时先公用此配置 + return new NioEventLoopGroup(proxyConfig.getTunnel().getThreadCount()); + } + + @Bean("cmdTunnelBootstrap") + public Bootstrap cmdTunnelBootstrap(@Inject ProxyConfig proxyConfig, + @Inject("tunnelWorkGroup") NioEventLoopGroup tunnelWorkGroup) { + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(tunnelWorkGroup); + bootstrap.channel(NioSocketChannel.class); +// bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000); +// bootstrap.option(ChannelOption.SO_KEEPALIVE, true); +// /** +// * TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。 +// * Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。 +// */ +// bootstrap.option(ChannelOption.TCP_NODELAY, true); + bootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getTunnel().getServerIp(), proxyConfig.getTunnel().getServerPort())); + + bootstrap.handler(new ChannelInitializer() { + + @Override + public void initChannel(SocketChannel ch) throws Exception { + if (proxyConfig.getTunnel().getSslEnable()) { + ch.pipeline().addLast(ProxyUtil.createSslHandler(proxyConfig)); + } + if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(CmdChannelHandler.class)); + } + ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), + proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(), + proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); + ch.pipeline().addLast(new ProxyMessageEncoder()); + ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds())); + ch.pipeline().addLast(new CmdChannelHandler()); + } + }); + return bootstrap; + } + + @Bean("tcpProxyTunnelBootstrap") + public Bootstrap tcpProxyTunnelBootstrap(@Inject ProxyConfig proxyConfig, + @Inject("tunnelWorkGroup") NioEventLoopGroup tunnelWorkGroup) { + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(tunnelWorkGroup); + bootstrap.channel(NioSocketChannel.class); + bootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getTunnel().getServerIp(), proxyConfig.getTunnel().getServerPort())); + bootstrap.handler(new ChannelInitializer() { + + @Override + public void initChannel(SocketChannel ch) throws Exception { + if (proxyConfig.getTunnel().getSslEnable()) { + ch.pipeline().addLast(ProxyUtil.createSslHandler(proxyConfig)); + } + if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(ProxyChannelHandler.class)); + } + ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), + proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(), + proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); + ch.pipeline().addLast(new ProxyMessageEncoder()); + ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds())); + ch.pipeline().addLast(new ProxyChannelHandler()); + } + }); + return bootstrap; + } + + @Bean("udpProxyTunnelBootstrap") + private Bootstrap udpProxyTunnelBootstrap() { + Bootstrap bootstrap = new Bootstrap(); + + return bootstrap; } @Bean("realServerBootstrap") - public Bootstrap realServerBootstrap() { - return new Bootstrap(); + public Bootstrap realServerBootstrap(@Inject ProxyConfig proxyConfig, + @Inject("tcpRealServerWorkGroup") NioEventLoopGroup tcpRealServerWorkGroup + ) { + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(tcpRealServerWorkGroup); + bootstrap.channel(NioSocketChannel.class); + bootstrap.handler(new ChannelInitializer() { + + @Override + public void initChannel(SocketChannel ch) throws Exception { + if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(RealServerChannelHandler.class)); + } + ch.pipeline().addLast(new RealServerChannelHandler()); + } + }); + return bootstrap; } + } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index 39c6f38c..2bfd9a0d 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -1,33 +1,17 @@ package org.dromara.neutrinoproxy.client.core; import cn.hutool.core.util.StrUtil; -import io.netty.handler.logging.LoggingHandler; import org.dromara.neutrinoproxy.client.config.ProxyConfig; import org.dromara.neutrinoproxy.client.util.ProxyUtil; import org.dromara.neutrinoproxy.core.ProxyMessage; -import org.dromara.neutrinoproxy.core.ProxyMessageDecoder; -import org.dromara.neutrinoproxy.core.ProxyMessageEncoder; -import org.dromara.neutrinoproxy.core.util.FileUtil; import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.handler.ssl.SslHandler; -import io.netty.handler.timeout.IdleStateHandler; import lombok.extern.slf4j.Slf4j; import org.noear.solon.Solon; import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Init; import org.noear.solon.annotation.Inject; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import java.io.InputStream; -import java.net.InetSocketAddress; -import java.security.KeyStore; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -44,24 +28,11 @@ public class ProxyClientService { private ProxyConfig proxyConfig; @Inject("cmdTunnelBootstrap") private Bootstrap cmdTunnelBootstrap; - @Inject("proxyTunnelBootstrap") - private Bootstrap proxyTunnelBootstrap; - @Inject("realServerBootstrap") - private Bootstrap realServerBootstrap; private volatile Channel channel; -// /** -// * 重连间隔(秒) -// */ -// private static final long RECONNECT_INTERVAL_SECONDS = 5; /** * 重连次数 */ private volatile int reconnectCount = 0; -// /** -// * 启用重连服务 -// */ -// private volatile boolean reconnectServiceEnable = false; - private NioEventLoopGroup workerGroup; /** * 重连服务执行器 */ @@ -70,72 +41,6 @@ public class ProxyClientService { @Init public void init() { this.reconnectExecutor.scheduleWithFixedDelay(this::reconnect, 10, proxyConfig.getTunnel().getReconnection().getIntervalSeconds(), TimeUnit.SECONDS); - this.workerGroup = new NioEventLoopGroup(proxyConfig.getTunnel().getThreadCount()); - - realServerBootstrap.group(workerGroup); - realServerBootstrap.channel(NioSocketChannel.class); - realServerBootstrap.handler(new ChannelInitializer() { - - @Override - public void initChannel(SocketChannel ch) throws Exception { - if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { - ch.pipeline().addFirst(new LoggingHandler(RealServerChannelHandler.class)); - } - ch.pipeline().addLast(new RealServerChannelHandler()); - } - }); - - proxyTunnelBootstrap.group(workerGroup); - proxyTunnelBootstrap.channel(NioSocketChannel.class); - proxyTunnelBootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getTunnel().getServerIp(), proxyConfig.getTunnel().getServerPort())); - proxyTunnelBootstrap.handler(new ChannelInitializer() { - - @Override - public void initChannel(SocketChannel ch) throws Exception { - if (proxyConfig.getTunnel().getSslEnable()) { - ch.pipeline().addLast(createSslHandler()); - } - if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { - ch.pipeline().addFirst(new LoggingHandler(ProxyChannelHandler.class)); - } - ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), - proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(), - proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); - ch.pipeline().addLast(new ProxyMessageEncoder()); - ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds())); - ch.pipeline().addLast(new ProxyChannelHandler()); - } - }); - - cmdTunnelBootstrap.group(workerGroup); - cmdTunnelBootstrap.channel(NioSocketChannel.class); -// cmdTunnelBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000); -// cmdTunnelBootstrap.option(ChannelOption.SO_KEEPALIVE, true); -// /** -// * TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头,同时,对方接收到数据,也需要发送ACK表示确认。为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。 -// * Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。 -// */ -// cmdTunnelBootstrap.option(ChannelOption.TCP_NODELAY, true); - cmdTunnelBootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getTunnel().getServerIp(), proxyConfig.getTunnel().getServerPort())); - - cmdTunnelBootstrap.handler(new ChannelInitializer() { - - @Override - public void initChannel(SocketChannel ch) throws Exception { - if (proxyConfig.getTunnel().getSslEnable()) { - ch.pipeline().addLast(createSslHandler()); - } - if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { - ch.pipeline().addFirst(new LoggingHandler(CmdChannelHandler.class)); - } - ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), - proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(), - proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); - ch.pipeline().addLast(new ProxyMessageEncoder()); - ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds())); - ch.pipeline().addLast(new CmdChannelHandler()); - } - }); try { this.start(); @@ -203,33 +108,7 @@ public class ProxyClientService { }).sync(); } - private ChannelHandler createSslHandler() { - try { - InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getTunnel().getJksPath()); - - SSLContext clientContext = SSLContext.getInstance("TLS"); - final KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(jksInputStream, proxyConfig.getTunnel().getKeyStorePassword().toCharArray()); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(ks); - TrustManager[] trustManagers = tmf.getTrustManagers(); - clientContext.init(null, trustManagers, null); - - SSLEngine sslEngine = clientContext.createSSLEngine(); - sslEngine.setUseClientMode(true); - - return new SslHandler(sslEngine); - } catch (Exception e) { - log.error("创建SSL处理器失败", e); - e.printStackTrace(); - } - return null; - } - protected synchronized void reconnect() { -// if (!reconnectServiceEnable) { -// return; -// } if (null != channel) { if (channel.isActive()) { return; diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java index 51003346..50bff9ba 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java @@ -21,8 +21,8 @@ import org.noear.solon.annotation.Inject; @Match(type = Constants.ProxyDataTypeName.CONNECT) @Component public class ProxyMessageConnectHandler implements ProxyMessageHandler { - @Inject("proxyTunnelBootstrap") - private Bootstrap proxyTunnelBootstrap; + @Inject("tcpProxyTunnelBootstrap") + private Bootstrap tcpProxyTunnelBootstrap; @Inject("realServerBootstrap") private Bootstrap realServerBootstrap; @Inject @@ -48,7 +48,7 @@ public class ProxyMessageConnectHandler implements ProxyMessageHandler { realServerChannel.config().setOption(ChannelOption.AUTO_READ, false); // 获取连接 - ProxyUtil.borrowProxyChanel(proxyTunnelBootstrap, new ProxyChannelBorrowListener() { + ProxyUtil.borrowProxyChanel(tcpProxyTunnelBootstrap, new ProxyChannelBorrowListener() { @Override public void success(Channel channel) { diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java index 80121228..6d1aa246 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java @@ -21,6 +21,9 @@ */ package org.dromara.neutrinoproxy.client.util; +import io.netty.channel.ChannelHandler; +import io.netty.handler.ssl.SslHandler; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.dromara.neutrinoproxy.client.config.ProxyConfig; import org.dromara.neutrinoproxy.client.core.ProxyChannelBorrowListener; @@ -34,6 +37,12 @@ import io.netty.util.AttributeKey; import org.dromara.neutrinoproxy.core.util.FileUtil; import org.noear.solon.Solon; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import java.io.InputStream; +import java.security.KeyStore; import java.util.Iterator; import java.util.Map; import java.util.UUID; @@ -45,6 +54,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; * @author: aoshiguchen * @date: 2022/8/31 */ +@Slf4j public class ProxyUtil { private static final AttributeKey USER_CHANNEL_WRITEABLE = AttributeKey.newInstance("user_channel_writeable"); @@ -154,4 +164,27 @@ public class ProxyUtil { clientId = id; return id; } + + public static ChannelHandler createSslHandler(ProxyConfig proxyConfig) { + try { + InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getTunnel().getJksPath()); + + SSLContext clientContext = SSLContext.getInstance("TLS"); + final KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(jksInputStream, proxyConfig.getTunnel().getKeyStorePassword().toCharArray()); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ks); + TrustManager[] trustManagers = tmf.getTrustManagers(); + clientContext.init(null, trustManagers, null); + + SSLEngine sslEngine = clientContext.createSSLEngine(); + sslEngine.setUseClientMode(true); + + return new SslHandler(sslEngine); + } catch (Exception e) { + log.error("创建SSL处理器失败", e); + e.printStackTrace(); + } + return null; + } } From 5578874df77a031573bde10861e9f2f6fbda6b5b Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Tue, 19 Sep 2023 12:56:42 +0800 Subject: [PATCH 08/20] =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E8=8B=B1=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../neutrinoproxy/client/ProxyClient.java | 2 +- .../client/config/ProxyConfiguration.java | 2 +- .../client/core/CmdChannelHandler.java | 6 ++-- .../client/core/ProxyChannelHandler.java | 4 +-- .../client/core/ProxyClientService.java | 10 +++---- .../handler/ProxyMessageAuthHandler.java | 2 +- .../handler/ProxyMessageErrorHandler.java | 2 +- .../neutrinoproxy/client/util/ProxyUtil.java | 2 +- .../neutrinoproxy/core/ExceptionEnum.java | 8 ++--- .../neutrinoproxy/core/ProxyDataTypeEnum.java | 14 ++++----- .../core/dispatcher/DefaultDispatcher.java | 19 ++++++------ .../neutrinoproxy/server/ProxyServer.java | 2 +- .../server/base/db/DBInitialize.java | 6 ++-- .../server/base/proxy/ProxyConfiguration.java | 2 +- .../rest/interceptor/BaseAuthInterceptor.java | 2 +- .../interceptor/GlobalExceptionFilter.java | 2 +- .../rest/interceptor/VisitLogInterceptor.java | 8 ++--- .../server/job/DataCleanJob.java | 12 ++++---- .../proxy/core/ProxyTunnelChannelHandler.java | 2 +- .../server/proxy/core/ProxyTunnelServer.java | 10 +++---- .../server/proxy/enhance/HttpProxy.java | 2 +- .../server/proxy/enhance/HttpsProxy.java | 4 +-- .../handler/ProxyMessageAuthHandler.java | 30 +++++++++---------- .../server/service/JobLogService.java | 8 ++--- .../server/service/ProxyMutualService.java | 4 +-- .../server/service/VisitorChannelService.java | 4 +-- 26 files changed, 84 insertions(+), 85 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java index feca73ae..a1ef6aaa 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/ProxyClient.java @@ -58,7 +58,7 @@ public class ProxyClient { logger.setLevel(level); } } catch (Exception e) { - log.error("日志级别设置失败", e); + log.error("logger level set failed", e); } } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java index a9256185..7dc39597 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java @@ -35,7 +35,7 @@ public class ProxyConfiguration implements LifecycleBean { @Override public void start() throws Throwable { List list = Solon.context().getBeansOfType(ProxyMessageHandler.class); - Dispatcher dispatcher = new DefaultDispatcher<>("消息调度器", list, + Dispatcher dispatcher = new DefaultDispatcher<>("MessageDispatcher", list, proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ? null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName()); Solon.context().wrapAndPut(Dispatcher.class, dispatcher); diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java index 5d482fea..c5c153e9 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java @@ -49,7 +49,7 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { - log.info("Client CmdChannel 与服务端断开连接"); + log.info("Client CmdChannel disconnect"); ProxyUtil.setCmdChannel(null); ProxyUtil.clearRealServerChannels(); @@ -69,14 +69,14 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler switch (event.state()) { case READER_IDLE: // 读超时,断开连接 - log.error("Client CmdChannel 读超时,断开连接"); + log.error("[Client CmdChannel] Read timeout disconnect"); ctx.channel().close(); break; case WRITER_IDLE: ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage()); break; case ALL_IDLE: - log.error("Client CmdChannel 读写超时,断开连接"); + log.error("[Client CmdChannel] ReadWrite timeout disconnect"); ctx.close(); break; } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java index 85e7b0f0..a8a17dd4 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java @@ -64,14 +64,14 @@ public class ProxyChannelHandler extends SimpleChannelInboundHandler cache = Stream.of(values()).collect(Collectors.toMap(ProxyDataTypeEnum::getType, Function.identity())); private int type; diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/dispatcher/DefaultDispatcher.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/dispatcher/DefaultDispatcher.java index efc6959a..7d7a2896 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/dispatcher/DefaultDispatcher.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/dispatcher/DefaultDispatcher.java @@ -35,10 +35,10 @@ public class DefaultDispatcher implements Dispatcher matcher; public DefaultDispatcher(String name, List> handlerList, Function matcher) { - Assert.notNull(name, "名称不能为空!"); - Assert.notNull(matcher, "匹配器不能为空!"); + Assert.notNull(name, "name cannot empty!"); + Assert.notNull(matcher, "matcher cannot empty!"); if (CollectionUtil.isEmpty(handlerList)) { - log.error("{} 处理器列表为空.", name); + log.error("{} handler list empty.", name); return; } this.name = name == null ? "" : name; @@ -48,20 +48,20 @@ public class DefaultDispatcher implements Dispatcher implements Dispatcher handler = handlerMap.get(type); if (null == handler) { -// log.debug("{} 找不到匹配的处理器 type:{}", this.name, type); return; } String handlerName = handler.name(); if (StrUtil.isEmpty(handlerName)) { handlerName = TypeUtil.getSimpleName(handler.getClass()); } - log.debug("{} 处理器[{}]执行.", this.name, handlerName); + log.debug("{} handler[{}]execute.", this.name, handlerName); handler.handle(context, data); } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/ProxyServer.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/ProxyServer.java index e4fa7703..9bc95bc5 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/ProxyServer.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/ProxyServer.java @@ -46,7 +46,7 @@ public class ProxyServer { logger.setLevel(level); } } catch (Exception e) { - log.error("日志级别设置失败", e); + log.error("logger level set failed", e); } } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DBInitialize.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DBInitialize.java index 7d8ac075..a880798b 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DBInitialize.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/db/DBInitialize.java @@ -57,7 +57,7 @@ public class DBInitialize implements EventListener { dbTypeEnum = DbTypeEnum.of(dbConfig.getType()); Assert.notNull(dbTypeEnum, "neutrino.data.db.type取值异常!"); - log.info("{}数据库初始化...", dbConfig.getType()); + log.info("{} database init...", dbConfig.getType()); initDBStructure(); initDBData(); } @@ -82,7 +82,7 @@ public class DBInitialize implements EventListener { } sql += "\r\n" + line.trim(); if (sql.endsWith(";")) { - log.debug("初始化数据库表 sql:{}", sql); + log.debug("init database table sql:{}", sql); Db.update(sql); sql = ""; } @@ -116,7 +116,7 @@ public class DBInitialize implements EventListener { } sql += "\r\n" + line.trim(); if (sql.endsWith(";")) { - log.debug("初始化数据[table={}] sql:{}", tableName, sql); + log.debug("init database data[table={}] sql:{}", tableName, sql); Db.update(sql); sql = ""; } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java index 0976afa6..0228b462 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/proxy/ProxyConfiguration.java @@ -38,7 +38,7 @@ public class ProxyConfiguration implements LifecycleBean { @Override public void start() throws Throwable { List list = Solon.context().getBeansOfType(ProxyMessageHandler.class); - Dispatcher dispatcher = new DefaultDispatcher<>("消息调度器", list, + Dispatcher dispatcher = new DefaultDispatcher<>("MessageDispatcher", list, proxyMessage -> ProxyDataTypeEnum.of((int)proxyMessage.getType()) == null ? null : ProxyDataTypeEnum.of((int)proxyMessage.getType()).getName()); diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/BaseAuthInterceptor.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/BaseAuthInterceptor.java index ab93f554..adb1cb68 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/BaseAuthInterceptor.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/BaseAuthInterceptor.java @@ -74,7 +74,7 @@ public class BaseAuthInterceptor implements RouterInterceptor { } if (result instanceof Throwable) { - log.error("全局异常", (Throwable) result); + log.error("global error", (Throwable) result); if (result instanceof ServiceException) { ServiceException exception = (ServiceException) result; diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/GlobalExceptionFilter.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/GlobalExceptionFilter.java index c2f559bf..4ce17769 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/GlobalExceptionFilter.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/GlobalExceptionFilter.java @@ -23,7 +23,7 @@ public class GlobalExceptionFilter implements Filter { try { chain.doFilter(ctx); } catch (Throwable e) { - log.error("全局异常", e); + log.error("global error", e); if (e instanceof ServiceException) { ServiceException serviceException = (ServiceException) e; diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/VisitLogInterceptor.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/VisitLogInterceptor.java index 181289da..8273b703 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/VisitLogInterceptor.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/base/rest/interceptor/VisitLogInterceptor.java @@ -31,7 +31,7 @@ public class VisitLogInterceptor implements RouterInterceptor { } finally { Date now = new Date(); long elapsedTime = now.getTime() - startTime.getTime(); - log.debug("\n-----------------------------------------------------------------接口请求日志:\n{} url:{} 执行耗时:{}\n请求体参数:{}\n响应结果:{}\n客户端IP:{}\n", + log.debug("\n-----------------------------------------------------------------interface request log:\n{} url:{} elapsed time:{}\nrequest:{}\nresponse:{}\nclient ip:{}\n", ctx.method(), ctx.path(), getElapsedTimeStr(elapsedTime), JSONObject.toJSONString(ctx.paramMap()), JSONObject.toJSONString(JSONObject.toJSONString(ctx.result)), @@ -47,11 +47,11 @@ public class VisitLogInterceptor implements RouterInterceptor { */ private static String getElapsedTimeStr(long elapsedTime) { if (elapsedTime < 1000) { - return String.format("%s毫秒", elapsedTime); + return String.format("%sms", elapsedTime); } else if (elapsedTime < 60000) { - return String.format("%.2f秒", (elapsedTime * 1.0) / 1000); + return String.format("%.2fs", (elapsedTime * 1.0) / 1000); } - return String.format("%.2f分钟", (elapsedTime * 1.0) / 1000 / 60); + return String.format("%.2fm", (elapsedTime * 1.0) / 1000 / 60); } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/job/DataCleanJob.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/job/DataCleanJob.java index fb18839d..766b0495 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/job/DataCleanJob.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/job/DataCleanJob.java @@ -70,37 +70,37 @@ public class DataCleanJob implements IJobHandler { { Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getJobLogKeepDays()); - log.info("清理调度管理日志 date:{}", sdf.format(date)); + log.info("clean job log date:{}", sdf.format(date)); jobLogMapper.clean(date); } { Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getUserLoginRecordKeepDays()); - log.info("清理用户登录日志 date:{}", sdf.format(date)); + log.info("clean user login record date:{}", sdf.format(date)); userLoginRecordMapper.clean(date); } { Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getClientConnectRecordKeepDays()); - log.info("清理客户端连接日志 date:{}", sdf.format(date)); + log.info("clean client connect record date:{}", sdf.format(date)); clientConnectRecordMapper.clean(date); } { Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowMinuteReportKeepDays()); - log.info("清理流通统计分钟报表日志 date:{}", sdf.format(date)); + log.info("clean flow report minute record date:{}", sdf.format(date)); flowReportMinuteMapper.clean(date); } { Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowHourReportKeepDays()); - log.info("清理流通统计小时报表日志 date:{}", sdf.format(date)); + log.info("clean flow report hour record date:{}", sdf.format(date)); flowReportHourMapper.clean(date); } { Date date = DateUtil.addDate(new Date(), Calendar.DATE, -1 * jobParams.getFlowDayReportKeepDays()); - log.info("清理流通统计日报表日志 date:{}", sdf.format(date)); + log.info("clean flow report day record date:{}", sdf.format(date)); flowReportDayMapper.clean(date); } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java index a1f5927d..a3fc522e 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/ProxyTunnelChannelHandler.java @@ -136,7 +136,7 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler { }); try { bootstrap.bind(proxyConfig.getTunnel().getPort()).sync(); - log.info("代理服务启动,端口:{}", proxyConfig.getTunnel().getPort()); + log.info("proxy server started,port:{}", proxyConfig.getTunnel().getPort()); } catch (Exception e) { - log.error("代理服务异常", e); + log.error("proxy server error", e); } } @@ -80,9 +80,9 @@ public class ProxyTunnelServer implements EventListener { }); try { bootstrap.bind(proxyConfig.getTunnel().getSslPort()).sync(); - log.info("代理服务启动,SSL端口: {}", proxyConfig.getTunnel().getSslPort()); + log.info("proxy server started,SSL port: {}", proxyConfig.getTunnel().getSslPort()); } catch (Exception e) { - log.error("代理服务异常", e); + log.error("proxy server error", e); } } @@ -105,7 +105,7 @@ public class ProxyTunnelServer implements EventListener { return new SslHandler(sslEngine); } catch (Exception e) { - log.error("创建SSL处理器失败", e); + log.error("create SSL handler error", e); e.printStackTrace(); } return null; diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java index 9c8716c9..85ccaeba 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpProxy.java @@ -50,7 +50,7 @@ public class HttpProxy implements EventListener { } }); bootstrap.bind("0.0.0.0", proxyConfig.getServer().getTcp().getHttpProxyPort()).sync(); - log.info("Http代理服务启动成功!port:{}", proxyConfig.getServer().getTcp().getHttpProxyPort()); + log.info("Http proxy server start success!port:{}", proxyConfig.getServer().getTcp().getHttpProxyPort()); } catch (Exception e) { log.error("http proxy start err!", e); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java index 281cfda0..9b25ba10 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/enhance/HttpsProxy.java @@ -59,7 +59,7 @@ public class HttpsProxy implements EventListener { } }); bootstrap.bind("0.0.0.0", proxyConfig.getServer().getTcp().getHttpsProxyPort()).sync(); - log.info("Https代理服务启动成功!port:{}", proxyConfig.getServer().getTcp().getHttpsProxyPort()); + log.info("Https proxy server started!port:{}", proxyConfig.getServer().getTcp().getHttpsProxyPort()); } catch (Exception e) { log.error("https proxy start err!", e); } @@ -84,7 +84,7 @@ public class HttpsProxy implements EventListener { return new SslHandler(sslEngine); } catch (Exception e) { - log.error("创建SSL处理器失败", e); + log.error("create SSL handler failed", e); e.printStackTrace(); } return null; diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java index ce3509c8..2fc7a678 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/ProxyMessageAuthHandler.java @@ -89,7 +89,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { } if (StrUtil.isEmpty(licenseKey)) { - log.warn("[客户端连接] license不能为空 info:{} ", info); + log.warn("[client connection] license cannot empty info:{} ", info); ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不能为空!", licenseKey)); ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() @@ -97,14 +97,14 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { .setType(ClientConnectTypeEnum.CONNECT.getType()) .setMsg(licenseKey) .setCode(SuccessCodeEnum.FAIL.getCode()) - .setErr("license不能为空!") + .setErr("license cannot empty!") .setCreateTime(now) ); return; } LicenseDO licenseDO = licenseService.findByKey(licenseKey); if (null == licenseDO) { - log.warn("[客户端连接] license不存在 info:{} ", info); + log.warn("[client connection] license notfound info:{} ", info); ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "license不存在!", licenseKey)); ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() @@ -112,14 +112,14 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { .setType(ClientConnectTypeEnum.CONNECT.getType()) .setMsg(licenseKey) .setCode(SuccessCodeEnum.FAIL.getCode()) - .setErr("license不存在!") + .setErr("license notfound!") .setCreateTime(now) ); return; } if (EnableStatusEnum.DISABLE.getStatus().equals(licenseDO.getEnable())) { - log.warn("[客户端连接] 当前license已被禁用 info:{} ", info); - ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license已被禁用!", licenseKey)); + log.warn("[client connection] the license disabled info:{} ", info); + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "the license disabled!", licenseKey)); ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) @@ -127,14 +127,14 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { .setType(ClientConnectTypeEnum.CONNECT.getType()) .setMsg(licenseKey) .setCode(SuccessCodeEnum.FAIL.getCode()) - .setErr("当前license已被禁用!") + .setErr("the license disabled!") .setCreateTime(now)); return; } UserDO userDO = userService.findById(licenseDO.getUserId()); if (null == userDO || EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) { - log.warn("[客户端连接] 当前license无效 info:{} ", info); - ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license无效!", licenseKey)); + log.warn("[client connection] the license invalid info:{} ", info); + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "the license invalid!", licenseKey)); ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) @@ -142,7 +142,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { .setType(ClientConnectTypeEnum.CONNECT.getType()) .setMsg(licenseKey) .setCode(SuccessCodeEnum.FAIL.getCode()) - .setErr("当前license无效!") + .setErr("the license invalid!") .setCreateTime(now)); return; } @@ -150,8 +150,8 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { if (null != cmdChannel) { String _clientId = ProxyUtil.getClientIdByLicenseId(licenseDO.getId()); if (!clientId.equals(_clientId)) { - log.warn("[客户端连接] 当前license已被另一节点使用 info:{} _clientId:{}", info, _clientId); - ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "当前license已被另一节点使用!", licenseKey)); + log.warn("[client connection] the license on another no used info:{} _clientId:{}", info, _clientId); + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.AUTH_FAILED.getCode(), "the license on another no used!", licenseKey)); ctx.channel().close(); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) @@ -159,13 +159,13 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { .setType(ClientConnectTypeEnum.CONNECT.getType()) .setMsg(licenseKey) .setCode(SuccessCodeEnum.FAIL.getCode()) - .setErr("当前license已被另一节点使用!") + .setErr("the license on another no used!") .setCreateTime(now)); return; } } // 发送认证成功消息 - ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.SUCCESS.getCode(), "认证成功!", licenseKey)); + ctx.channel().writeAndFlush(ProxyMessage.buildAuthResultMessage(ExceptionEnum.SUCCESS.getCode(), "auth success!", licenseKey)); clientConnectRecordService.add(new ClientConnectRecordDO() .setIp(ip) @@ -178,7 +178,7 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler { // 设置当前licenseId对应的客户端ID ProxyUtil.setLicenseIdToClientIdMap(licenseDO.getId(), clientId); - log.warn("[客户端连接] 认证成功 info:{} ", info); + log.warn("[client connection] auth success info:{} ", info); // 更新license在线状态 licenseMapper.updateOnlineStatus(licenseDO.getId(), OnlineStatusEnum.ONLINE.getStatus(), now); diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/JobLogService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/JobLogService.java index b9fd3b44..546f4d6f 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/JobLogService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/JobLogService.java @@ -60,11 +60,11 @@ public class JobLogService implements IJobCallback { Integer code = 0; String msg = ""; if (null == throwable) { - msg = "执行成功"; - log.debug("job[id={},name={}]执行完毕", jobInfo.getId(), jobInfo.getName()); + msg = "execute success"; + log.debug("job[id={},name={}]execute success", jobInfo.getId(), jobInfo.getName()); } else { - log.error("job[id={},name={}]执行异常", jobInfo.getId(), jobInfo.getName(), throwable); - msg = "执行异常:\r\n" + ExceptionUtils.getStackTrace(throwable); + log.error("job[id={},name={}]execute error", jobInfo.getId(), jobInfo.getName(), throwable); + msg = "execute error:\r\n" + ExceptionUtils.getStackTrace(throwable); code = -1; } jobLogMapper.insert(new JobLogDO() diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/ProxyMutualService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/ProxyMutualService.java index c2fd3c63..222fa765 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/ProxyMutualService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/ProxyMutualService.java @@ -53,7 +53,7 @@ public class ProxyMutualService { Date now = new Date(); portMappingMapper.updateOnlineStatus(attachInfo.getLicenseId(), serverPort, OnlineStatusEnum.ONLINE.getStatus(), now); licenseMapper.updateOnlineStatus(attachInfo.getLicenseId(), OnlineStatusEnum.ONLINE.getStatus(), now); - log.info("绑定服务端端口 licenseId:{},ip:{},serverPort:{}", attachInfo.getLicenseId(), attachInfo.getIp(), serverPort); + log.info("bind server port licenseId:{},ip:{},serverPort:{}", attachInfo.getLicenseId(), attachInfo.getIp(), serverPort); } /** @@ -64,7 +64,7 @@ public class ProxyMutualService { Date now = new Date(); portMappingMapper.updateOnlineStatus(attachInfo.getLicenseId(), OnlineStatusEnum.OFFLINE.getStatus(), now); licenseMapper.updateOnlineStatus(attachInfo.getLicenseId(), OnlineStatusEnum.OFFLINE.getStatus(), now); - log.info("客户端下线 licenseId:{},ip:{}", attachInfo.getLicenseId(), attachInfo.getIp()); + log.info("client offline licenseId:{},ip:{}", attachInfo.getLicenseId(), attachInfo.getIp()); } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java index 3b55ff79..dd10d6e1 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/VisitorChannelService.java @@ -232,10 +232,10 @@ public class VisitorChannelService { NetworkProtocolEnum networkProtocolEnum = NetworkProtocolEnum.of(portMapping.getProtocal()); if (networkProtocolEnum == NetworkProtocolEnum.UDP) { udpServerBootstrap.bind(portMapping.getServerPort()).get(); - log.info("绑定UDP用户端口: {}", portMapping.getServerPort()); + log.info("bind UDP user port: {}", portMapping.getServerPort()); } else { tcpServerBootstrap.bind(portMapping.getServerPort()).get(); - log.info("绑定TCP用户端口: {}", portMapping.getServerPort()); + log.info("bind TCP user port: {}", portMapping.getServerPort()); } } catch (Exception ex) { // BindException表示该端口已经绑定过 From 688089832118652e141aa7748e622908161e5d9c Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Tue, 19 Sep 2023 13:16:43 +0800 Subject: [PATCH 09/20] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=96=B0?= =?UTF-8?q?=E5=A2=9EUDP=E9=9A=A7=E9=81=93=E6=B6=88=E6=81=AF=E5=A4=84?= =?UTF-8?q?=E7=90=86=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/config/ProxyConfiguration.java | 30 ++++++- .../client/core/CmdChannelHandler.java | 10 +-- ...ndler.java => TcpProxyChannelHandler.java} | 12 +-- .../client/core/UdpProxyChannelHandler.java | 80 +++++++++++++++++++ .../handler/ProxyMessageConnectHandler.java | 2 +- .../neutrinoproxy/client/util/ProxyUtil.java | 4 +- .../neutrinoproxy/core/ProxyMessage.java | 2 +- 7 files changed, 121 insertions(+), 19 deletions(-) rename neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/{ProxyChannelHandler.java => TcpProxyChannelHandler.java} (83%) create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/UdpProxyChannelHandler.java diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java index 7dc39597..07ca1890 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java @@ -7,8 +7,9 @@ import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import io.netty.handler.timeout.IdleStateHandler; import org.dromara.neutrinoproxy.client.core.CmdChannelHandler; -import org.dromara.neutrinoproxy.client.core.ProxyChannelHandler; +import org.dromara.neutrinoproxy.client.core.TcpProxyChannelHandler; import org.dromara.neutrinoproxy.client.core.RealServerChannelHandler; +import org.dromara.neutrinoproxy.client.core.UdpProxyChannelHandler; import org.dromara.neutrinoproxy.client.util.ProxyUtil; import org.dromara.neutrinoproxy.core.*; import org.dromara.neutrinoproxy.core.dispatcher.DefaultDispatcher; @@ -103,23 +104,44 @@ public class ProxyConfiguration implements LifecycleBean { ch.pipeline().addLast(ProxyUtil.createSslHandler(proxyConfig)); } if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { - ch.pipeline().addFirst(new LoggingHandler(ProxyChannelHandler.class)); + ch.pipeline().addFirst(new LoggingHandler(TcpProxyChannelHandler.class)); } ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(), proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); ch.pipeline().addLast(new ProxyMessageEncoder()); ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds())); - ch.pipeline().addLast(new ProxyChannelHandler()); + ch.pipeline().addLast(new TcpProxyChannelHandler()); } }); return bootstrap; } @Bean("udpProxyTunnelBootstrap") - private Bootstrap udpProxyTunnelBootstrap() { + private Bootstrap udpProxyTunnelBootstrap(@Inject ProxyConfig proxyConfig, + @Inject("tunnelWorkGroup") NioEventLoopGroup tunnelWorkGroup) { Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(tunnelWorkGroup); + bootstrap.channel(NioSocketChannel.class); + bootstrap.remoteAddress(InetSocketAddress.createUnresolved(proxyConfig.getTunnel().getServerIp(), proxyConfig.getTunnel().getServerPort())); + bootstrap.handler(new ChannelInitializer() { + @Override + public void initChannel(SocketChannel ch) throws Exception { + if (proxyConfig.getTunnel().getSslEnable()) { + ch.pipeline().addLast(ProxyUtil.createSslHandler(proxyConfig)); + } + if (null != proxyConfig.getTunnel().getTransferLogEnable() && proxyConfig.getTunnel().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(TcpProxyChannelHandler.class)); + } + ch.pipeline().addLast(new ProxyMessageDecoder(proxyConfig.getProtocol().getMaxFrameLength(), + proxyConfig.getProtocol().getLengthFieldOffset(), proxyConfig.getProtocol().getLengthFieldLength(), + proxyConfig.getProtocol().getLengthAdjustment(), proxyConfig.getProtocol().getInitialBytesToStrip())); + ch.pipeline().addLast(new ProxyMessageEncoder()); + ch.pipeline().addLast(new IdleStateHandler(proxyConfig.getProtocol().getReadIdleTime(), proxyConfig.getProtocol().getWriteIdleTime(), proxyConfig.getProtocol().getAllIdleTimeSeconds())); + ch.pipeline().addLast(new UdpProxyChannelHandler()); + } + }); return bootstrap; } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java index c5c153e9..68db2a0e 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/CmdChannelHandler.java @@ -32,7 +32,7 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler @Override protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception { if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType() || transferLogEnable) { - log.debug("Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType()); + log.debug("[CMD Channel]Client CmdChannel recieved proxy message, type is {}", proxyMessage.getType()); } Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage); } @@ -49,7 +49,7 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { - log.info("Client CmdChannel disconnect"); + log.info("[CMD Channel]Client CmdChannel disconnect"); ProxyUtil.setCmdChannel(null); ProxyUtil.clearRealServerChannels(); @@ -58,7 +58,7 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - log.error("Client CmdChannel Error channelId:{}", ctx.channel().id().asLongText(), cause); + log.error("[CMD Channel]Client CmdChannel Error channelId:{}", ctx.channel().id().asLongText(), cause); ctx.close(); } @@ -69,14 +69,14 @@ public class CmdChannelHandler extends SimpleChannelInboundHandler switch (event.state()) { case READER_IDLE: // 读超时,断开连接 - log.error("[Client CmdChannel] Read timeout disconnect"); + log.error("[CMD Channel] Read timeout disconnect"); ctx.channel().close(); break; case WRITER_IDLE: ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage()); break; case ALL_IDLE: - log.error("[Client CmdChannel] ReadWrite timeout disconnect"); + log.error("[CMD Channel] ReadWrite timeout disconnect"); ctx.close(); break; } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/TcpProxyChannelHandler.java similarity index 83% rename from neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java rename to neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/TcpProxyChannelHandler.java index a8a17dd4..45373152 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/TcpProxyChannelHandler.java @@ -18,13 +18,13 @@ import org.noear.solon.Solon; * @date: 2022/6/16 */ @Slf4j -public class ProxyChannelHandler extends SimpleChannelInboundHandler { +public class TcpProxyChannelHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception { if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) { - log.debug("Client ProxyChannel recieved proxy message, type is {}", proxyMessage.getType()); + log.debug("[TCP Proxy Channel]Client ProxyChannel recieved proxy message, type is {}", proxyMessage.getType()); } Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage); } @@ -53,7 +53,7 @@ public class ProxyChannelHandler extends SimpleChannelInboundHandler { + + + @Override + protected void channelRead0(ChannelHandlerContext ctx, ProxyMessage proxyMessage) throws Exception { + if (ProxyMessage.TYPE_HEARTBEAT != proxyMessage.getType()) { + log.debug("[UDP Proxy Channel]Client ProxyChannel recieved proxy message, type is {}", proxyMessage.getType()); + } + Solon.context().getBean(Dispatcher.class).dispatch(ctx, proxyMessage); + } + + @Override + public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { + Channel realServerChannel = ctx.channel().attr(Constants.NEXT_CHANNEL).get(); + if (realServerChannel != null) { + realServerChannel.config().setOption(ChannelOption.AUTO_READ, ctx.channel().isWritable()); + } + + super.channelWritabilityChanged(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + // 数据传输连接 + Channel realServerChannel = ctx.channel().attr(Constants.NEXT_CHANNEL).get(); + if (realServerChannel != null && realServerChannel.isActive()) { + realServerChannel.close(); + } + + ProxyUtil.removeProxyChanel(ctx.channel()); + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + log.error("[UDP Proxy Channel]Client ProxyChannel Error channelId:{}", ctx.channel().id().asLongText(), cause); + ctx.close(); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if(evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent)evt; + switch (event.state()) { + case READER_IDLE: + // 读超时,断开连接 + log.info("[UDP Proxy Channel]Read timeout"); + ctx.channel().close(); + break; + case WRITER_IDLE: + ctx.channel().writeAndFlush(ProxyMessage.buildHeartbeatMessage()); + break; + case ALL_IDLE: + log.debug("[UDP Proxy Channel]ReadWrite timeout"); + ctx.close(); + break; + } + } + } +} diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java index 50bff9ba..2bca8667 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/ProxyMessageConnectHandler.java @@ -48,7 +48,7 @@ public class ProxyMessageConnectHandler implements ProxyMessageHandler { realServerChannel.config().setOption(ChannelOption.AUTO_READ, false); // 获取连接 - ProxyUtil.borrowProxyChanel(tcpProxyTunnelBootstrap, new ProxyChannelBorrowListener() { + ProxyUtil.borrowTcpProxyChanel(tcpProxyTunnelBootstrap, new ProxyChannelBorrowListener() { @Override public void success(Channel channel) { diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java index 789dc9b9..d42a5cb5 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java @@ -71,14 +71,14 @@ public class ProxyUtil { private static String clientId; private static final String CLIENT_ID_FILE = ".NEUTRINO_PROXY_CLIENT_ID"; - public static void borrowProxyChanel(Bootstrap proxyTunnelBootstrap, final ProxyChannelBorrowListener borrowListener) { + public static void borrowTcpProxyChanel(Bootstrap tcpProxyTunnelBootstrap, final ProxyChannelBorrowListener borrowListener) { Channel channel = proxyChannelPool.poll(); if (null != channel) { borrowListener.success(channel); return; } - proxyTunnelBootstrap.connect().addListener((ChannelFutureListener) future -> { + tcpProxyTunnelBootstrap.connect().addListener((ChannelFutureListener) future -> { if (future.isSuccess()) { borrowListener.success(future.channel()); } else { diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java index 716557c4..43d138e8 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java @@ -69,7 +69,7 @@ public class ProxyMessage { /** * UDP数据传输 */ - private static final byte TYPE_UDP_TRANSFER = 0x07; + private static final byte TYPE_UDP_TRANSFER = 0x08; /** * 消息类型 From fd306ce8c3b2002a6f066d64d3288320b9cc8325 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Wed, 20 Sep 2023 11:57:00 +0800 Subject: [PATCH 10/20] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=AB=AF=E6=94=B6?= =?UTF-8?q?=E5=88=B0UDP=E6=95=B0=E6=8D=AE=E5=8C=85=E8=BD=AC=E5=8F=91?= =?UTF-8?q?=E8=87=B3=E5=AE=A2=E6=88=B7=E7=AB=AF=E8=B0=83=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/core/TcpProxyChannelHandler.java | 2 +- .../client/core/UdpProxyChannelHandler.java | 2 +- .../ProxyMessageDisconnectHandler.java | 2 +- .../UdpProxyMessageConnectHandler.java | 64 +++++++++++++ .../UdpProxyMessageTransferHandler.java | 33 +++++++ .../neutrinoproxy/client/util/ProxyUtil.java | 49 ++++++++-- .../dromara/neutrinoproxy/core/Constants.java | 6 ++ .../neutrinoproxy/core/ProxyDataTypeEnum.java | 5 +- .../neutrinoproxy/core/ProxyMessage.java | 35 +++++-- .../server/dal/PortMappingMapper.java | 8 ++ .../proxy/core/TcpVisitorChannelHandler.java | 3 +- .../proxy/core/UdpVisitorChannelHandler.java | 71 ++++++++++++-- .../domain/VisitorChannelAttachInfo.java | 2 + .../enhance/HttpVisitorChannelHandler.java | 3 +- .../handler/ProxyMessageConnectHandler.java | 12 +-- .../UdpProxyMessageConnectHandler.java | 94 +++++++++++++++++++ .../neutrinoproxy/server/util/ProxyUtil.java | 20 ++-- 17 files changed, 365 insertions(+), 46 deletions(-) create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageConnectHandler.java create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageTransferHandler.java create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/UdpProxyMessageConnectHandler.java diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/TcpProxyChannelHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/TcpProxyChannelHandler.java index 45373152..73283be3 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/TcpProxyChannelHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/TcpProxyChannelHandler.java @@ -47,7 +47,7 @@ public class TcpProxyChannelHandler extends SimpleChannelInboundHandler realServerChannels = new ConcurrentHashMap(); - private static ConcurrentLinkedQueue proxyChannelPool = new ConcurrentLinkedQueue(); + private static ConcurrentLinkedQueue tcpProxyChannelPool = new ConcurrentLinkedQueue(); + private static ConcurrentLinkedQueue udpProxyChannelPool = new ConcurrentLinkedQueue<>(); private static volatile Channel cmdChannel; @@ -72,7 +73,7 @@ public class ProxyUtil { private static final String CLIENT_ID_FILE = ".NEUTRINO_PROXY_CLIENT_ID"; public static void borrowTcpProxyChanel(Bootstrap tcpProxyTunnelBootstrap, final ProxyChannelBorrowListener borrowListener) { - Channel channel = proxyChannelPool.poll(); + Channel channel = tcpProxyChannelPool.poll(); if (null != channel) { borrowListener.success(channel); return; @@ -87,18 +88,52 @@ public class ProxyUtil { }); } - public static void returnProxyChanel(Channel proxyChanel) { - if (proxyChannelPool.size() > MAX_POOL_SIZE) { + public static void returnTcpProxyChanel(Channel proxyChanel) { + if (tcpProxyChannelPool.size() > MAX_POOL_SIZE) { proxyChanel.close(); } else { proxyChanel.config().setOption(ChannelOption.AUTO_READ, true); proxyChanel.attr(Constants.NEXT_CHANNEL).remove(); - proxyChannelPool.offer(proxyChanel); + tcpProxyChannelPool.offer(proxyChanel); } } - public static void removeProxyChanel(Channel proxyChanel) { - proxyChannelPool.remove(proxyChanel); + + + public static void removeTcpProxyChanel(Channel proxyChanel) { + tcpProxyChannelPool.remove(proxyChanel); + } + + public static void borrowUdpProxyChanel(Bootstrap tcpProxyTunnelBootstrap, final ProxyChannelBorrowListener borrowListener) { + Channel channel = udpProxyChannelPool.poll(); + if (null != channel) { + borrowListener.success(channel); + return; + } + + tcpProxyTunnelBootstrap.connect().addListener((ChannelFutureListener) future -> { + if (future.isSuccess()) { + borrowListener.success(future.channel()); + } else { + borrowListener.error(future.cause()); + } + }); + } + + public static void returnUdpProxyChanel(Channel proxyChanel) { + if (udpProxyChannelPool.size() > MAX_POOL_SIZE) { + proxyChanel.close(); + } else { + proxyChanel.config().setOption(ChannelOption.AUTO_READ, true); + proxyChanel.attr(Constants.NEXT_CHANNEL).remove(); + udpProxyChannelPool.offer(proxyChanel); + } + } + + + + public static void removeUdpProxyChanel(Channel proxyChanel) { + udpProxyChannelPool.remove(proxyChanel); } public static void setCmdChannel(Channel cmdChannel) { diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java index c6d04a16..5a3d916c 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/Constants.java @@ -38,6 +38,9 @@ public interface Constants { AttributeKey LICENSE_ID = AttributeKey.newInstance("license_id"); + AttributeKey TARGET_IP = AttributeKey.newInstance("targetIp"); + AttributeKey TARGET_PORT = AttributeKey.newInstance("targetPort"); + int HEADER_SIZE = 4; int TYPE_SIZE = 1; int SERIAL_NUMBER_SIZE = 8; @@ -49,6 +52,9 @@ public interface Constants { String CONNECT = "CONNECT"; String DISCONNECT = "DISCONNECT"; String TRANSFER = "TRANSFER"; + String UDP_CONNECT = "UDP_CONNECT"; + String UDP_DISCONNECT = "UDP_DISCONNECT"; + String UDP_TRANSFER = "UDP_TRANSFER"; String ERROR = "ERROR"; String PORT_MAPPING_SYNC = "PORT_MAPPING_SYNC"; } diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyDataTypeEnum.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyDataTypeEnum.java index 0a62897b..e533bf8e 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyDataTypeEnum.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyDataTypeEnum.java @@ -44,7 +44,10 @@ public enum ProxyDataTypeEnum { DISCONNECT(0x04, Constants.ProxyDataTypeName.DISCONNECT,"DISCONNECT"), TRANSFER(0x05, Constants.ProxyDataTypeName.TRANSFER,"TRANSFER"), ERROR(0x06, Constants.ProxyDataTypeName.ERROR,"ERROR"), - PORT_MAPPING_SYNC(0x07, Constants.ProxyDataTypeName.PORT_MAPPING_SYNC, "PORT_MAPPING_SYNC"); + PORT_MAPPING_SYNC(0x07, Constants.ProxyDataTypeName.PORT_MAPPING_SYNC, "PORT_MAPPING_SYNC"), + UDP_CONNECT(0x08, Constants.ProxyDataTypeName.UDP_CONNECT,"UDP_CONNECT"), + UDP_DISCONNECT(0x09, Constants.ProxyDataTypeName.UDP_DISCONNECT,"UDP_DISCONNECT"), + UDP_TRANSFER(0x10, Constants.ProxyDataTypeName.UDP_TRANSFER,"UDP_TRANSFER"); private static Map cache = Stream.of(values()).collect(Collectors.toMap(ProxyDataTypeEnum::getType, Function.identity())); private int type; diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java index 43d138e8..b349d91a 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java @@ -66,10 +66,18 @@ public class ProxyMessage { * 通用异常信息 */ public static final byte TYPE_ERROR = 0x06; + /** + * UDP代理隧道连接 + */ + public static final byte TYPE_UDP_CONNECT = 0x08; + /** + * UDP代理隧道断开连接 + */ + public static final byte TYPE_UDP_DISCONNECT = 0x09; /** * UDP数据传输 */ - private static final byte TYPE_UDP_TRANSFER = 0x08; + public static final byte TYPE_UDP_TRANSFER = 0x10; /** * 消息类型 @@ -134,15 +142,19 @@ public class ProxyMessage { .setData(data); } - public static ProxyMessage buildUdpTransferMessage(String visitorIp, int visitorPort, String targetIp, int targetPort, byte[] data) { + + public static ProxyMessage buildUdpConnectMessage(UdpBaseInfo info) { + return create().setType(TYPE_UDP_CONNECT) + .setInfo(info.toJsonString()); + } + + public static ProxyMessage buildUdpDisconnectMessage() { + return create().setType(TYPE_UDP_DISCONNECT); + } + + public static ProxyMessage buildUdpTransferMessage(UdpBaseInfo info) { return create().setType(TYPE_UDP_TRANSFER) - .setInfo(JSONObject.toJSONString(new UdpBaseInfo() - .setVisitorIp(visitorIp) - .setVisitorPort(visitorPort) - .setTargetIp(targetIp) - .setTargetPort(targetPort) - )) - .setData(data); + .setInfo(info.toJsonString()); } public static ProxyMessage buildErrMessage(ExceptionEnum exceptionEnum, String info) { @@ -161,9 +173,14 @@ public class ProxyMessage { @Accessors(chain = true) @Data public static class UdpBaseInfo { + private String visitorId; private String visitorIp; private int visitorPort; + private int serverPort; private String targetIp; private int targetPort; + public String toJsonString() { + return JSONObject.toJSONString(this); + } } } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/PortMappingMapper.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/PortMappingMapper.java index cf35a7c0..f8b7a054 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/PortMappingMapper.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/PortMappingMapper.java @@ -74,6 +74,14 @@ public interface PortMappingMapper extends BaseMapper { ); } + default PortMappingDO findByLicenseIdAndServerPort(Integer licenseId, Integer serverPort) { + return this.selectOne(new LambdaQueryWrapper() + .eq(PortMappingDO::getLicenseId, licenseId) + .eq(PortMappingDO::getServerPort, serverPort) + .last("limit 1") + ); + } + default void updateOnlineStatus(Integer licenseId,Integer serverPort, Integer isOnline, Date updateTime) { this.update(null, new LambdaUpdateWrapper() .eq(PortMappingDO::getLicenseId, licenseId) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/TcpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/TcpVisitorChannelHandler.java index 0c52037c..8f0b2186 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/TcpVisitorChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/TcpVisitorChannelHandler.java @@ -4,6 +4,7 @@ import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import org.dromara.neutrinoproxy.core.Constants; import org.dromara.neutrinoproxy.core.ProxyMessage; +import org.dromara.neutrinoproxy.server.constant.NetworkProtocolEnum; import org.dromara.neutrinoproxy.server.proxy.domain.VisitorChannelAttachInfo; import org.dromara.neutrinoproxy.server.service.FlowReportService; import org.dromara.neutrinoproxy.server.util.ProxyUtil; @@ -76,7 +77,7 @@ public class TcpVisitorChannelHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket datagramPacket) throws Exception { + System.out.println("channelId:" + ctx.channel().id().asLongText()); System.out.println("服务端接收到消息 \nsender:" + datagramPacket.sender().toString() + "内容\n" + datagramPacket.content().toString(StandardCharsets.UTF_8)); + // 通知代理客户端 + Channel visitorChannel = ctx.channel(); + Channel proxyChannel = visitorChannel.attr(Constants.NEXT_CHANNEL).get(); + + if (null == proxyChannel) { + // 该端口还没有代理客户端 + ctx.channel().close(); + return; + } + String targetIp = proxyChannel.attr(Constants.TARGET_IP).get(); + int targetPort = proxyChannel.attr(Constants.TARGET_PORT).get(); + + // 转发代理数据 + byte[] bytes = new byte[datagramPacket.content().readableBytes()]; + datagramPacket.content().readBytes(bytes); + String visitorId = ProxyUtil.getVisitorIdByChannel(visitorChannel); + proxyChannel.writeAndFlush(ProxyMessage.buildUdpTransferMessage(new ProxyMessage.UdpBaseInfo() + .setVisitorId(visitorId) + .setVisitorIp(datagramPacket.sender().getAddress().getHostAddress()) + .setVisitorPort(datagramPacket.sender().getPort()) + .setTargetIp(targetIp) + .setTargetPort(targetPort) + ).setData(bytes)); + + // 增加流量计数 + VisitorChannelAttachInfo visitorChannelAttachInfo = ProxyUtil.getAttachInfo(visitorChannel); + Solon.context().getBean(FlowReportService.class).addWriteByte(visitorChannelAttachInfo.getLicenseId(), bytes.length); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + System.out.println("active channelId:" + ctx.channel().id().asLongText()); Channel visitorChannel = ctx.channel(); InetSocketAddress sa = (InetSocketAddress) visitorChannel.localAddress(); Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(sa.getPort()); @@ -43,16 +83,27 @@ public class UdpVisitorChannelHandler extends SimpleChannelInboundHandler Date: Wed, 20 Sep 2023 22:22:36 +0800 Subject: [PATCH 11/20] =?UTF-8?q?UDP=E4=BB=A3=E7=90=86=E9=9A=A7=E9=81=93?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E9=80=BB=E8=BE=91=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UdpProxyMessageConnectHandler.java | 4 +- .../proxy/core/UdpVisitorChannelHandler.java | 85 +++++++++++-------- .../UdpProxyMessageConnectHandler.java | 7 +- 3 files changed, 59 insertions(+), 37 deletions(-) diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageConnectHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageConnectHandler.java index e395ffd1..bac3db9f 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageConnectHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageConnectHandler.java @@ -36,11 +36,11 @@ public class UdpProxyMessageConnectHandler implements ProxyMessageHandler { log.info("[UDP connect]info:{}", proxyMessage.getInfo()); // 获取连接 - ProxyUtil.borrowTcpProxyChanel(udpProxyTunnelBootstrap, new ProxyChannelBorrowListener() { + ProxyUtil.borrowUdpProxyChanel(udpProxyTunnelBootstrap, new ProxyChannelBorrowListener() { @Override public void success(Channel channel) { - ctx.channel().writeAndFlush(ProxyMessage.buildUdpConnectMessage(new ProxyMessage.UdpBaseInfo() + channel.writeAndFlush(ProxyMessage.buildUdpConnectMessage(new ProxyMessage.UdpBaseInfo() .setVisitorId(udpBaseInfo.getVisitorId()) .setServerPort(udpBaseInfo.getServerPort()) .setTargetIp(udpBaseInfo.getTargetIp()) diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java index 018cd936..d05c9483 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java @@ -7,9 +7,11 @@ import io.netty.channel.ChannelOption; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.socket.DatagramPacket; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.dromara.neutrinoproxy.core.Constants; import org.dromara.neutrinoproxy.core.ProxyMessage; import org.dromara.neutrinoproxy.server.constant.NetworkProtocolEnum; +import org.dromara.neutrinoproxy.server.proxy.domain.ProxyAttachment; import org.dromara.neutrinoproxy.server.proxy.domain.VisitorChannelAttachInfo; import org.dromara.neutrinoproxy.server.service.FlowReportService; import org.dromara.neutrinoproxy.server.util.ProxyUtil; @@ -30,42 +32,53 @@ public class UdpVisitorChannelHandler extends SimpleChannelInboundHandler { + Channel proxyChannel = channel.attr(Constants.NEXT_CHANNEL).get(); - // 增加流量计数 - VisitorChannelAttachInfo visitorChannelAttachInfo = ProxyUtil.getAttachInfo(visitorChannel); - Solon.context().getBean(FlowReportService.class).addWriteByte(visitorChannelAttachInfo.getLicenseId(), bytes.length); - } + if (null == proxyChannel) { + // 该端口还没有代理客户端 + ctx.channel().close(); + return; + } + String targetIp = proxyChannel.attr(Constants.TARGET_IP).get(); + int targetPort = proxyChannel.attr(Constants.TARGET_PORT).get(); + + // 转发代理数据 + String visitorId = ProxyUtil.getVisitorIdByChannel(channel); + proxyChannel.writeAndFlush(ProxyMessage.buildUdpTransferMessage(new ProxyMessage.UdpBaseInfo() + .setVisitorId(visitorId) + .setVisitorIp(datagramPacket.sender().getAddress().getHostAddress()) + .setVisitorPort(datagramPacket.sender().getPort()) + .setTargetIp(targetIp) + .setTargetPort(targetPort) + ).setData(bytes)); + + // 增加流量计数 + VisitorChannelAttachInfo visitorChannelAttachInfo = ProxyUtil.getAttachInfo(channel); + Solon.context().getBean(FlowReportService.class).addWriteByte(visitorChannelAttachInfo.getLicenseId(), bytes.length); + }); + +// String visitorId = ProxyUtil.getVisitorIdByChannel(ctx.channel()); +// if (StringUtils.isNotBlank(visitorId)) { +// // UDP代理隧道已就绪,直接转发 +// proxyAttachment.execute(); +// return; +// } + Channel proxyChannel = ctx.channel().attr(Constants.NEXT_CHANNEL).get(); + if (null != proxyChannel && proxyChannel.isActive()) { + // UDP代理隧道已就绪,直接转发 + proxyAttachment.execute(); + return; + } - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - System.out.println("active channelId:" + ctx.channel().id().asLongText()); Channel visitorChannel = ctx.channel(); InetSocketAddress sa = (InetSocketAddress) visitorChannel.localAddress(); Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(sa.getPort()); + // 没有指令通道,直接结束 if (null == cmdChannel) { // 该端口还没有代理客户端 ctx.channel().close(); @@ -86,17 +99,21 @@ public class UdpVisitorChannelHandler extends SimpleChannelInboundHandler Date: Thu, 21 Sep 2023 16:30:48 +0800 Subject: [PATCH 12/20] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AFudp=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=B0=83=E6=95=B4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/config/ProxyConfig.java | 11 ++-- .../client/config/ProxyConfiguration.java | 46 ++++++++++++-- .../client/core/ProxyClientService.java | 4 ++ .../client/core/UdpRealServerHandler.java | 17 +++++ .../neutrinoproxy/client/util/ProxyUtil.java | 1 + .../client/util/UdpServerUtil.java | 63 +++++++++++++++++++ .../src/main/resources/app.yml | 8 +++ .../neutrinoproxy/core/ProxyMessage.java | 8 +++ 8 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/UdpRealServerHandler.java create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpServerUtil.java diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java index 1ef6d166..a33f3520 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfig.java @@ -50,7 +50,7 @@ public class ProxyConfig { @Data public static class Client { // private Tcp tcp; -// private Udp udp; + private Udp udp; } @Data @@ -60,12 +60,15 @@ public class ProxyConfig { } @Data - private static class Tcp { + public static class Tcp { } @Data - private static class Udp { - + public static class Udp { + private Integer bossThreadCount; + private Integer workThreadCount; + private String puppetPortRange; + private Boolean transferLogEnable; } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java index 07ca1890..17b8fd36 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/config/ProxyConfiguration.java @@ -1,15 +1,15 @@ package org.dromara.neutrinoproxy.client.config; import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LoggingHandler; import io.netty.handler.timeout.IdleStateHandler; -import org.dromara.neutrinoproxy.client.core.CmdChannelHandler; -import org.dromara.neutrinoproxy.client.core.TcpProxyChannelHandler; -import org.dromara.neutrinoproxy.client.core.RealServerChannelHandler; -import org.dromara.neutrinoproxy.client.core.UdpProxyChannelHandler; +import org.dromara.neutrinoproxy.client.core.*; import org.dromara.neutrinoproxy.client.util.ProxyUtil; import org.dromara.neutrinoproxy.core.*; import org.dromara.neutrinoproxy.core.dispatcher.DefaultDispatcher; @@ -53,6 +53,18 @@ public class ProxyConfiguration implements LifecycleBean { return new NioEventLoopGroup(proxyConfig.getTunnel().getThreadCount()); } + @Bean("udpServerGroup") + public NioEventLoopGroup udpServerGroup(@Inject ProxyConfig proxyConfig) { + // 暂时先公用此配置 + return new NioEventLoopGroup(proxyConfig.getClient().getUdp().getBossThreadCount()); + } + + @Bean("udpWorkGroup") + public NioEventLoopGroup udpWorkGroup(@Inject ProxyConfig proxyConfig) { + // 暂时先公用此配置 + return new NioEventLoopGroup(proxyConfig.getClient().getUdp().getWorkThreadCount()); + } + @Bean("cmdTunnelBootstrap") public Bootstrap cmdTunnelBootstrap(@Inject ProxyConfig proxyConfig, @Inject("tunnelWorkGroup") NioEventLoopGroup tunnelWorkGroup) { @@ -165,5 +177,31 @@ public class ProxyConfiguration implements LifecycleBean { return bootstrap; } + @Bean("udpServerBootstrap") + public Bootstrap udpServerBootstrap(@Inject ProxyConfig proxyConfig, + @Inject("udpServerGroup") NioEventLoopGroup udpServerGroup, + @Inject("udpWorkGroup") NioEventLoopGroup udpWorkGroup) { + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(udpServerGroup) + // 主线程处理 + .channel(NioDatagramChannel.class) + // 广播 + .option(ChannelOption.SO_BROADCAST, true) + // 设置读缓冲区为2M + .option(ChannelOption.SO_RCVBUF, 2048 * 1024) + // 设置写缓冲区为1M + .option(ChannelOption.SO_SNDBUF, 1024 * 1024) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(NioDatagramChannel ch) { + ChannelPipeline pipeline = ch.pipeline(); + if (null != proxyConfig.getClient().getUdp().getTransferLogEnable() && proxyConfig.getClient().getUdp().getTransferLogEnable()) { + ch.pipeline().addFirst(new LoggingHandler(UdpRealServerHandler.class)); + } + pipeline.addLast(udpWorkGroup, new UdpRealServerHandler()); + } + }); + return bootstrap; + } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java index 673220bd..e7ff1e3f 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/ProxyClientService.java @@ -3,6 +3,7 @@ package org.dromara.neutrinoproxy.client.core; import cn.hutool.core.util.StrUtil; import org.dromara.neutrinoproxy.client.config.ProxyConfig; import org.dromara.neutrinoproxy.client.util.ProxyUtil; +import org.dromara.neutrinoproxy.client.util.UdpServerUtil; import org.dromara.neutrinoproxy.core.ProxyMessage; import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; @@ -28,6 +29,8 @@ public class ProxyClientService { private ProxyConfig proxyConfig; @Inject("cmdTunnelBootstrap") private Bootstrap cmdTunnelBootstrap; + @Inject("udpServerBootstrap") + private Bootstrap udpServerBootstrap; private volatile Channel channel; /** * 重连次数 @@ -44,6 +47,7 @@ public class ProxyClientService { try { this.start(); + UdpServerUtil.initCache(proxyConfig, udpServerBootstrap); } catch (Exception e) { // 启动连不上也做一下重连,因此先catch异常 log.error("[CmdChannel] start error", e); diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/UdpRealServerHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/UdpRealServerHandler.java new file mode 100644 index 00000000..33fb34cb --- /dev/null +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/UdpRealServerHandler.java @@ -0,0 +1,17 @@ +package org.dromara.neutrinoproxy.client.core; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; + +/** + * @author: aoshiguchen + * @date: 2023/9/21 + */ +public class UdpRealServerHandler extends SimpleChannelInboundHandler { + + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { + + } +} diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java index 4cb863db..b44bd4a9 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/ProxyUtil.java @@ -222,4 +222,5 @@ public class ProxyUtil { } return null; } + } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpServerUtil.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpServerUtil.java new file mode 100644 index 00000000..ad3fc281 --- /dev/null +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpServerUtil.java @@ -0,0 +1,63 @@ +package org.dromara.neutrinoproxy.client.util; + +import io.netty.bootstrap.Bootstrap; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.dromara.neutrinoproxy.client.config.ProxyConfig; + +/** + * @author: aoshiguchen + * @date: 2023/9/21 + */ +@Slf4j +public class UdpServerUtil { + private static final Boolean isSupportUdp = Boolean.FALSE; + private static int udpServerPortMin = 0; + private static int udpServerPortMax = 0; + private static int nextUdpServerPort = 0; + private static Bootstrap udpServerBootstrap; + private static final String defaultUdpServerKey = "default"; + + /** + * 初始化UDP缓存 + * 1、初始化一个基础UDP服务,用于不需要响应的UDP转发 + * 2、维护一个UDP服务池,用于需要响应的UDP转发 + * @param proxyConfig + */ + public static void initCache(ProxyConfig proxyConfig, Bootstrap udpServerBootstrap) { + if (null == proxyConfig.getClient().getUdp() || StringUtils.isEmpty(proxyConfig.getClient().getUdp().getPuppetPortRange())) { + return; + } + ProxyConfig.Udp udpConfig = proxyConfig.getClient().getUdp(); + if (StringUtils.isEmpty(udpConfig.getPuppetPortRange())) { + return; + } + String[] tmp = udpConfig.getPuppetPortRange().split("-"); + if (null == tmp || tmp.length != 2) { + log.error("client udp config error!"); + return; + } + try { + udpServerPortMin = Integer.parseInt(tmp[0]); + udpServerPortMax = Integer.parseInt(tmp[1]); + if (udpServerPortMax <= udpServerPortMin) { + // 至少得给2个udp端口,一个用于基础无响应UDP转发,一个用于有响应UDP转发 + throw new RuntimeException("client udp config error!"); + } + nextUdpServerPort = udpServerPortMin; + UdpServerUtil.udpServerBootstrap = udpServerBootstrap; + log.info("udp proxy server port: {} ~ {}", udpServerPortMin, udpServerPortMax); + } catch (Exception e) { + log.error("client udp config error!", e); + return; + } + } + + public static Boolean hasNextUdpServerPort() { + return nextUdpServerPort <= udpServerPortMax; + } + + public static synchronized int nextUdpServerPort() { + return nextUdpServerPort++; + } +} diff --git a/neutrino-proxy-client/src/main/resources/app.yml b/neutrino-proxy-client/src/main/resources/app.yml index 28eb2c0b..89977937 100644 --- a/neutrino-proxy-client/src/main/resources/app.yml +++ b/neutrino-proxy-client/src/main/resources/app.yml @@ -42,3 +42,11 @@ neutrino: # 是否开启无限重连(未开启时,客户端license不合法会自动停止应用,开启了则不会,请谨慎开启) unlimited: false client: + udp: + # 线程池相关配置,用于技术调优,可忽略 + boss-thread-count: 5 + work-thread-count: 20 + # udp傀儡端口范围 + puppet-port-range: 10000-10100 + # 是否开启隧道传输报文日志(日志级别为debug时开启才有效) + transfer-log-enable: ${CLIENT_LOG:false} diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java index b349d91a..52eefdad 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java @@ -179,6 +179,14 @@ public class ProxyMessage { private int serverPort; private String targetIp; private int targetPort; + /** + * 期待的响应数 + */ + private int proxyResponses; + /** + * 超时时间(<=0时,相当于不需要响应) + */ + private int proxyTimeout; public String toJsonString() { return JSONObject.toJSONString(this); } From e416c76ea8b6804d0173393204043e150ff6b663 Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Thu, 21 Sep 2023 23:40:00 +0800 Subject: [PATCH 13/20] =?UTF-8?q?=E8=B0=83=E9=80=9AUDP=E4=BB=A3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/constant/Constants.java | 13 ++ .../client/core/UdpRealServerHandler.java | 30 ++++- .../UdpProxyMessageTransferHandler.java | 20 ++- .../client/util/LockChannel.java | 28 ++++ .../client/util/UdpChannelBindInfo.java | 22 ++++ .../client/util/UdpServerUtil.java | 124 +++++++++++++++++- .../neutrinoproxy/core/ProxyMessage.java | 2 +- .../proxy/core/UdpVisitorChannelHandler.java | 5 +- .../UdpProxyMessageTransferHandler.java | 44 +++++++ 9 files changed, 277 insertions(+), 11 deletions(-) create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/constant/Constants.java create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/LockChannel.java create mode 100644 neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpChannelBindInfo.java create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/handler/UdpProxyMessageTransferHandler.java diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/constant/Constants.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/constant/Constants.java new file mode 100644 index 00000000..f9ab40c3 --- /dev/null +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/constant/Constants.java @@ -0,0 +1,13 @@ +package org.dromara.neutrinoproxy.client.constant; + +import io.netty.util.AttributeKey; +import org.dromara.neutrinoproxy.client.util.UdpChannelBindInfo; + +/** + * @author: aoshiguchen + * @date: 2023/9/21 + */ +public interface Constants { + AttributeKey UDP_CHANNEL_BIND_KEY = AttributeKey.newInstance("udpChannelBindKey"); + +} diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/UdpRealServerHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/UdpRealServerHandler.java index 33fb34cb..1a288e88 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/UdpRealServerHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/core/UdpRealServerHandler.java @@ -1,17 +1,41 @@ package org.dromara.neutrinoproxy.client.core; -import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.socket.DatagramPacket; +import lombok.extern.slf4j.Slf4j; +import org.dromara.neutrinoproxy.client.constant.Constants; +import org.dromara.neutrinoproxy.client.util.UdpChannelBindInfo; +import org.dromara.neutrinoproxy.core.ProxyMessage; + +import java.net.InetSocketAddress; /** * @author: aoshiguchen * @date: 2023/9/21 */ -public class UdpRealServerHandler extends SimpleChannelInboundHandler { +@Slf4j +public class UdpRealServerHandler extends SimpleChannelInboundHandler { @Override - protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { + protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket datagramPacket) throws Exception { + log.debug("chid---<:{} port:{}", ctx.channel().id().asLongText(), ((InetSocketAddress)ctx.channel().localAddress()).getPort()); + UdpChannelBindInfo udpChannelBindInfo = ctx.channel().attr(Constants.UDP_CHANNEL_BIND_KEY).get(); + if (null != udpChannelBindInfo) { + byte[] bytes = new byte[datagramPacket.content().readableBytes()]; + datagramPacket.content().readBytes(bytes); + udpChannelBindInfo.getTunnelChannel().writeAndFlush(ProxyMessage.buildUdpTransferMessage(new ProxyMessage.UdpBaseInfo() + .setVisitorId(udpChannelBindInfo.getVisitorId()) + .setVisitorIp(udpChannelBindInfo.getVisitorIp()) + .setVisitorPort(udpChannelBindInfo.getVisitorPort()) + .setServerPort(udpChannelBindInfo.getServerPort()) + .setTargetIp(udpChannelBindInfo.getTargetIp()) + .setTargetPort(udpChannelBindInfo.getTargetPort())) + .setData(bytes) + ); + + udpChannelBindInfo.getLockChannel().setResponseCount(udpChannelBindInfo.getLockChannel().getResponseCount() + 1); + } } } diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageTransferHandler.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageTransferHandler.java index 308e4551..2ff61e4e 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageTransferHandler.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/handler/UdpProxyMessageTransferHandler.java @@ -1,8 +1,13 @@ package org.dromara.neutrinoproxy.client.handler; import com.alibaba.fastjson.JSONObject; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.socket.DatagramPacket; import lombok.extern.slf4j.Slf4j; +import org.dromara.neutrinoproxy.client.util.UdpServerUtil; import org.dromara.neutrinoproxy.core.Constants; import org.dromara.neutrinoproxy.core.ProxyDataTypeEnum; import org.dromara.neutrinoproxy.core.ProxyMessage; @@ -10,6 +15,9 @@ import org.dromara.neutrinoproxy.core.ProxyMessageHandler; import org.dromara.neutrinoproxy.core.dispatcher.Match; import org.noear.solon.annotation.Component; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; + /** * @author: aoshiguchen * @date: 2023/9/20 @@ -19,11 +27,19 @@ import org.noear.solon.annotation.Component; @Component public class UdpProxyMessageTransferHandler implements ProxyMessageHandler { - @Override public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) { final ProxyMessage.UdpBaseInfo udpBaseInfo = JSONObject.parseObject(proxyMessage.getInfo(), ProxyMessage.UdpBaseInfo.class); - log.info("[UDP transfer]info:{} data:{}", proxyMessage.getInfo(), new String(proxyMessage.getData())); + log.debug("[UDP transfer]info:{} data:{}", proxyMessage.getInfo(), new String(proxyMessage.getData())); + Channel channel = UdpServerUtil.takeChannel(udpBaseInfo, ctx.channel()); + if (null == channel) { + log.error("[UDP transfer] take udp channel failed."); + return; + } + log.debug("chid--->:{} port:{}", ctx.channel().id().asLongText(), ((InetSocketAddress)channel.localAddress()).getPort()); + InetSocketAddress address = new InetSocketAddress(udpBaseInfo.getTargetIp(), udpBaseInfo.getTargetPort()); + ByteBuf byteBuf = Unpooled.copiedBuffer(proxyMessage.getData()); + channel.writeAndFlush(new DatagramPacket(byteBuf, address)); } @Override diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/LockChannel.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/LockChannel.java new file mode 100644 index 00000000..d694ba83 --- /dev/null +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/LockChannel.java @@ -0,0 +1,28 @@ +package org.dromara.neutrinoproxy.client.util; + +import io.netty.channel.Channel; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + * @author: aoshiguchen + * @date: 2023/9/21 + */ +@Accessors(chain = true) +@Data +public class LockChannel { + // 端口号 + private int port; + // 通道 + private Channel channel; + // 期望的响应次数 + private int proxyResponses; + // 超时时间(毫秒) + private long proxyTimeoutMs; + // 被获取的时间 + private Date takeTime; + // 已经响应的次数 + private int responseCount; +} diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpChannelBindInfo.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpChannelBindInfo.java new file mode 100644 index 00000000..fea6aa86 --- /dev/null +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpChannelBindInfo.java @@ -0,0 +1,22 @@ +package org.dromara.neutrinoproxy.client.util; + +import io.netty.channel.Channel; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * @author: aoshiguchen + * @date: 2023/9/21 + */ +@Accessors(chain = true) +@Data +public class UdpChannelBindInfo { + private Channel tunnelChannel; + private LockChannel lockChannel; + private String visitorId; + private String visitorIp; + private int visitorPort; + private int serverPort; + private String targetIp; + private int targetPort; +} diff --git a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpServerUtil.java b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpServerUtil.java index ad3fc281..48b833c0 100644 --- a/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpServerUtil.java +++ b/neutrino-proxy-client/src/main/java/org/dromara/neutrinoproxy/client/util/UdpServerUtil.java @@ -1,9 +1,17 @@ package org.dromara.neutrinoproxy.client.util; import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.dromara.neutrinoproxy.client.config.ProxyConfig; +import org.dromara.neutrinoproxy.client.constant.Constants; +import org.dromara.neutrinoproxy.client.core.CustomThreadFactory; +import org.dromara.neutrinoproxy.core.ProxyMessage; + +import java.util.*; +import java.util.concurrent.*; /** * @author: aoshiguchen @@ -16,7 +24,18 @@ public class UdpServerUtil { private static int udpServerPortMax = 0; private static int nextUdpServerPort = 0; private static Bootstrap udpServerBootstrap; - private static final String defaultUdpServerKey = "default"; + private static int defaultUdpServerPort; + private static Channel defaultUdpServerChannel; + private static Map portToChannelMap = new ConcurrentHashMap<>(); + /** + * udp服务空闲端口池 + */ + private static ConcurrentLinkedQueue udpServerFreePortPool = new ConcurrentLinkedQueue<>(); + private static List lockChannelList = new ArrayList<>(); + /** + * lockChannel扫描器 + */ + private static final ScheduledExecutorService lockChannelScanner = Executors.newSingleThreadScheduledExecutor(new CustomThreadFactory("lockChannelScanner")); /** * 初始化UDP缓存 @@ -41,18 +60,54 @@ public class UdpServerUtil { udpServerPortMin = Integer.parseInt(tmp[0]); udpServerPortMax = Integer.parseInt(tmp[1]); if (udpServerPortMax <= udpServerPortMin) { - // 至少得给2个udp端口,一个用于基础无响应UDP转发,一个用于有响应UDP转发 + // 至少得给1个udp端口,一个用于基础无响应UDP转发 throw new RuntimeException("client udp config error!"); } nextUdpServerPort = udpServerPortMin; UdpServerUtil.udpServerBootstrap = udpServerBootstrap; log.info("udp proxy server port: {} ~ {}", udpServerPortMin, udpServerPortMax); + // 初始化udp服务 + initUdpServer(); + // 初始化lockChannel扫描器 + lockChannelScanner.scheduleWithFixedDelay(UdpServerUtil::lockChannelScan, 5, 3, TimeUnit.SECONDS); } catch (Exception e) { log.error("client udp config error!", e); return; } } + /** + * 初始化udp服务 + */ + private static void initUdpServer() { + defaultUdpServerPort = nextUdpServerPort(); + defaultUdpServerChannel = bindPort(defaultUdpServerPort); + // 初始化默认最多额外开启5个udp服务,其他的需要时再启动 + for (int i = 0; i < 5; i++) { + if (!hasNextUdpServerPort()) { + return; + } + int port = nextUdpServerPort(); + Channel ch = bindPort(port); + portToChannelMap.put(port, ch); + udpServerFreePortPool.offer(port); + } + while (hasNextUdpServerPort()) { + udpServerFreePortPool.offer(nextUdpServerPort()); + } + } + + private static Channel bindPort(int port) { + try { + ChannelFuture channelFuture = udpServerBootstrap.bind(port).sync(); + log.info("[udp server] bind port:{} success!", port); + return channelFuture.channel(); + } catch (InterruptedException e) { + log.error("[udp server] bind port:{} error!", port); + throw new RuntimeException(e); + } + } + public static Boolean hasNextUdpServerPort() { return nextUdpServerPort <= udpServerPortMax; } @@ -60,4 +115,69 @@ public class UdpServerUtil { public static synchronized int nextUdpServerPort() { return nextUdpServerPort++; } + + /** + * 获取一个可用的udp通道 + * 1、如果期待的响应为0,或者超时时间<=0,则认为不需要响应,直接返回默认的udp服务,否则继续下一步 + * 2、从可用端口队列中找到一个可用端口,若不存在可用端口,则降级为不需要响应,返回默认的udp服务。否则继续下一步 + * 3、根据该端口找到udp服务通道,找不到则绑定端口开启一个通道并返回。将该端口添加到锁定列表 + * 4、维护一个定时器的,定时扫描锁定列表,及时释放锁定的端口 + * @param info + * @return + */ + public static synchronized Channel takeChannel(ProxyMessage.UdpBaseInfo info, Channel tunnelChannel) { + if (info.getProxyResponses() <= 0 || info.getProxyTimeoutMs() <= 0) { + return defaultUdpServerChannel; + } + Integer port = udpServerFreePortPool.poll(); + if (null == port) { + return defaultUdpServerChannel; + } + Channel channel = portToChannelMap.get(port); + if (null == channel) { + channel = bindPort(port); + portToChannelMap.put(port, channel); + } + // 添加到锁定队列 + LockChannel lockChannel = new LockChannel() + .setPort(port) + .setChannel(channel) + .setProxyResponses(info.getProxyResponses()) + .setProxyTimeoutMs(info.getProxyTimeoutMs()) + .setTakeTime(new Date()) + .setResponseCount(0); + lockChannelList.add(lockChannel); + channel.attr(Constants.UDP_CHANNEL_BIND_KEY).set(new UdpChannelBindInfo() + .setTunnelChannel(tunnelChannel) + .setVisitorId(info.getVisitorId()) + .setVisitorIp(info.getVisitorIp()) + .setVisitorPort(info.getVisitorPort()) + .setServerPort(info.getServerPort()) + .setTargetIp(info.getTargetIp()) + .setTargetPort(info.getTargetPort()) + .setLockChannel(lockChannel) + ); + return channel; + } + + /** + * lockChannel扫描 + */ + public static synchronized void lockChannelScan() { + if (lockChannelList.isEmpty()) { + return; + } + Iterator iter = lockChannelList.iterator(); + if (iter.hasNext()) { + LockChannel lockChannel = iter.next(); + if (lockChannel.getResponseCount() >= lockChannel.getProxyResponses() || + System.currentTimeMillis() - lockChannel.getTakeTime().getTime() >= lockChannel.getProxyTimeoutMs() + ) { + iter.remove(); + lockChannel.getChannel().attr(Constants.UDP_CHANNEL_BIND_KEY).set(null); + udpServerFreePortPool.offer(lockChannel.getPort()); + log.debug("[udp channel]release udp channel port:{}", lockChannel.getPort()); + } + } + } } diff --git a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java index 52eefdad..b77e3829 100644 --- a/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java +++ b/neutrino-proxy-core/src/main/java/org/dromara/neutrinoproxy/core/ProxyMessage.java @@ -186,7 +186,7 @@ public class ProxyMessage { /** * 超时时间(<=0时,相当于不需要响应) */ - private int proxyTimeout; + private long proxyTimeoutMs; public String toJsonString() { return JSONObject.toJSONString(this); } diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java index d05c9483..5a478adf 100644 --- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java +++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/UdpVisitorChannelHandler.java @@ -29,9 +29,6 @@ public class UdpVisitorChannelHandler extends SimpleChannelInboundHandler Date: Fri, 22 Sep 2023 13:41:50 +0800 Subject: [PATCH 14/20] =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E6=98=A0=E5=B0=84?= =?UTF-8?q?=E6=89=93=E5=BC=80=E7=BD=91=E9=A1=B5=EF=BC=8C=E4=BC=98=E5=85=88?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=9F=9F=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-admin/config/dev.env.js | 2 +- neutrino-proxy-admin/src/views/proxy/portMapping.vue | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/neutrino-proxy-admin/config/dev.env.js b/neutrino-proxy-admin/config/dev.env.js index 825a20c6..03fd65b0 100644 --- a/neutrino-proxy-admin/config/dev.env.js +++ b/neutrino-proxy-admin/config/dev.env.js @@ -1,7 +1,7 @@ module.exports = { NODE_ENV: '"development"', ENV_CONFIG: '"dev"', - BASE_API: '"http://103.163.47.16:8888"', + BASE_API: '"https://neutrino-proxy.asgc.fun/neutrino-proxy-server"', USER_NAME: '"visitor"', USER_PWD: '"123456"' } diff --git a/neutrino-proxy-admin/src/views/proxy/portMapping.vue b/neutrino-proxy-admin/src/views/proxy/portMapping.vue index 59ca8c9b..f83883d3 100644 --- a/neutrino-proxy-admin/src/views/proxy/portMapping.vue +++ b/neutrino-proxy-admin/src/views/proxy/portMapping.vue @@ -463,7 +463,10 @@ export default { }) }, handleOpenWebPage(row) { - const url = location.protocol + '//' + location.hostname + ':' + row.serverPort + let url = location.protocol + '//' + location.hostname + ':' + row.serverPort + if (row.domain) { + url = location.protocol + '//' + row.domain + } open(url) }, handleUpdate(row) { From 4d380dbdf3cf3fc199797daf03d6ad180a7e06ae Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Fri, 22 Sep 2023 20:15:41 +0800 Subject: [PATCH 15/20] =?UTF-8?q?=E6=96=B0=E5=A2=9E/=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E6=98=A0=E5=B0=84=E6=97=B6=E7=AB=AF=E5=8F=A3?= =?UTF-8?q?=E5=8D=A0=E7=94=A8=E6=A3=80=E6=B5=8B=E5=8A=9F=E8=83=BD=E5=B1=8F?= =?UTF-8?q?=E8=94=BD=EF=BC=8C=E8=A7=A3=E5=86=B3docker=E4=B8=8B=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E5=90=84=E7=A7=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- neutrino-proxy-admin/src/views/proxy/portMapping.vue | 5 +++-- todolist.MD | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/neutrino-proxy-admin/src/views/proxy/portMapping.vue b/neutrino-proxy-admin/src/views/proxy/portMapping.vue index f83883d3..c120ac41 100644 --- a/neutrino-proxy-admin/src/views/proxy/portMapping.vue +++ b/neutrino-proxy-admin/src/views/proxy/portMapping.vue @@ -196,7 +196,7 @@