Compare commits

..
Author SHA1 Message Date
aoshiguchen afff036641 新增HTTPS支持 2023-05-27 00:47:01 +08:00
aoshiguchen 9944e60825 启动脚本调整 2023-05-23 20:09:44 +08:00
aoshiguchen 74ff0c3b44 Merge branch 'feature/20230520' into dev 2023-05-20 14:28:53 +08:00
aoshiguchen 3e9e7cb370 server端代码优化,将代理隧道配置分离出来 2023-05-03 18:07:12 +08:00
13 changed files with 316 additions and 187 deletions
@@ -64,8 +64,7 @@ public class DBInitialize implements EventListener<AppLoadEndEvent> {
@Override @Override
public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable { public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable {
// TODO 该事件有50%的概率不触发
System.out.println("11");
} }
/** /**
@@ -18,10 +18,15 @@ public class ProxyConfig {
@Inject("${neutrino.proxy.protocol}") @Inject("${neutrino.proxy.protocol}")
private Protocol protocol; private Protocol protocol;
/** /**
* 服务配置 * 代理服务配置
*/ */
@Inject("${neutrino.proxy.server}") @Inject("${neutrino.proxy.server}")
private Server server; private Server server;
/**
* 代理隧道配置
*/
@Inject("${neutrino.proxy.tunnel}")
private Tunnel tunnel;
@Data @Data
public static class Protocol { public static class Protocol {
@@ -37,15 +42,24 @@ public class ProxyConfig {
@Data @Data
public static class Server { 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;
}
@Data
public static class Tunnel {
private Integer bossThreadCount;
private Integer workThreadCount;
private Integer port; private Integer port;
private Integer sslPort; private Integer sslPort;
private String keyStorePassword; private String keyStorePassword;
private String keyManagerPassword; private String keyManagerPassword;
private String jksPath; private String jksPath;
private Integer bossThreadCount;
private Integer workThreadCount;
private String domainName;
private Integer httpProxyPort;
} }
} }
@@ -43,4 +43,14 @@ public class ProxyConfiguration implements LifecycleBean {
return new NioEventLoopGroup(proxyConfig.getServer().getWorkThreadCount()); return new NioEventLoopGroup(proxyConfig.getServer().getWorkThreadCount());
} }
@Bean("tunnelBossGroup")
public NioEventLoopGroup tunnelBossGroup(@Inject ProxyConfig proxyConfig) {
return new NioEventLoopGroup(proxyConfig.getTunnel().getBossThreadCount());
}
@Bean("tunnelWorkerGroup")
public NioEventLoopGroup tunnelWorkerGroup(@Inject ProxyConfig proxyConfig) {
return new NioEventLoopGroup(proxyConfig.getTunnel().getWorkThreadCount());
}
} }
@@ -2,28 +2,17 @@ package org.dromara.neutrinoproxy.server.proxy.core;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import io.netty.bootstrap.ServerBootstrap; import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*; import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j; 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.base.proxy.ProxyConfig; import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
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;
import org.noear.solon.Solon;
import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject; import org.noear.solon.annotation.Inject;
import org.noear.solon.core.event.AppLoadEndEvent; import org.noear.solon.core.event.AppLoadEndEvent;
import org.noear.solon.core.event.EventListener; import org.noear.solon.core.event.EventListener;
import java.net.InetSocketAddress;
/** /**
* @author: aoshiguchen * @author: aoshiguchen
* @date: 2023/4/2 * @date: 2023/4/2
@@ -54,7 +43,7 @@ public class HttpProxy implements EventListener<AppLoadEndEvent> {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addFirst(new BytesMetricsHandler()); ch.pipeline().addFirst(new BytesMetricsHandler());
ch.pipeline().addLast(new VisitorChannelHandler()); ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName()));
} }
}); });
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpProxyPort()).sync(); bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpProxyPort()).sync();
@@ -63,142 +52,4 @@ public class HttpProxy implements EventListener<AppLoadEndEvent> {
log.error("http proxy start err!", e); log.error("http proxy start err!", e);
} }
} }
private class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
if (StrUtil.isBlank(proxyConfig.getServer().getDomainName())) {
ctx.channel().close();
return;
}
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
byteBuf.resetReaderIndex();
ProxyAttachment proxyAttachment = new ProxyAttachment(ctx.channel(), bytes, (channel, buf) -> {
Channel proxyChannel = channel.attr(Constants.NEXT_CHANNEL).get();
if (null == proxyChannel) {
// 该端口还没有代理客户端
ctx.channel().close();
return;
}
proxyChannel.writeAndFlush(ProxyMessage.buildTransferMessage(ProxyUtil.getVisitorIdByChannel(channel), 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)) {
proxyAttachment.execute();
return;
}
// 用户连接到代理服务器时,设置用户连接不可读,等待代理后端服务器连接成功后再改变为可读状态
ctx.channel().config().setOption(ChannelOption.AUTO_READ, false);
String host = getHost(bytes);
if (StringUtils.isBlank(host)) {
ctx.channel().close();
return;
}
log.debug("HttpProxy host: {}", host);
if (!host.endsWith(proxyConfig.getServer().getDomainName())) {
ctx.channel().close();
return;
}
int index = host.lastIndexOf("." + proxyConfig.getServer().getDomainName());
String subdomain = host.substring(0, index);
// 根据域名拿到绑定的映射对应的cmdChannel
Integer serverPort = ProxyUtil.getServerPortBySubdomain(subdomain);
if (null == serverPort) {
ctx.channel().close();
return;
}
Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(serverPort);
if (null == cmdChannel) {
ctx.channel().close();
return;
}
String lanInfo = ProxyUtil.getClientLanInfoByServerPort(serverPort);
if (StringUtils.isBlank(lanInfo)) {
ctx.channel().close();
return;
}
visitorId = ProxyUtil.newVisitorId();
ProxyUtil.addVisitorChannelToCmdChannel(cmdChannel, visitorId, ctx.channel(), serverPort);
ProxyUtil.addProxyConnectAttachment(visitorId, proxyAttachment);
cmdChannel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId).setData(lanInfo.getBytes()));
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// 通知代理客户端
Channel visitorChannel = ctx.channel();
InetSocketAddress sa = (InetSocketAddress) visitorChannel.localAddress();
Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(sa.getPort());
if (cmdChannel == null) {
// 该端口还没有代理客户端
ctx.channel().close();
} else {
// 用户连接断开,从控制连接中移除
String visitorId = ProxyUtil.getVisitorIdByChannel(visitorChannel);
ProxyUtil.removeVisitorChannelFromCmdChannel(cmdChannel, visitorId);
// 删除代理附加对象
ProxyUtil.remoteProxyConnectAttachment(visitorId);
Channel proxyChannel = visitorChannel.attr(Constants.NEXT_CHANNEL).get();
if (proxyChannel != null && proxyChannel.isActive()) {
proxyChannel.attr(Constants.NEXT_CHANNEL).remove();
proxyChannel.attr(Constants.LICENSE_ID).remove();
proxyChannel.attr(Constants.VISITOR_ID).remove();
proxyChannel.config().setOption(ChannelOption.AUTO_READ, true);
// 通知客户端,用户连接已经断开
proxyChannel.writeAndFlush(ProxyMessage.buildDisconnectMessage(visitorId));
}
}
super.channelInactive(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 当出现异常就关闭连接
ctx.close();
}
private String getHost(byte[] buf) {
String req = new String(buf);
String[] lines = req.split("\r\n");
String firstLine = lines[0];
if (!(firstLine.endsWith("HTTP/1.1") || firstLine.endsWith("HTTP/1.0"))) {
return null;
}
for (int i = 1; i < lines.length; i++) {
String line = lines[i];
if (!line.startsWith("Host: ")) {
continue;
}
// 域名
String domain = line.substring(6);
return domain;
}
return null;
}
}
} }
@@ -0,0 +1,170 @@
package org.dromara.neutrinoproxy.server.proxy.core;
import cn.hutool.core.util.StrUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
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.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;
import org.noear.solon.Solon;
import java.net.InetSocketAddress;
/**
* @author: aoshiguchen
* @date: 2023/5/27
*/
@Slf4j
public class HttpVisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf> {
/**
* 域名
*/
private String domainName;
public HttpVisitorChannelHandler(String domainName) {
this.domainName = domainName;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
if (StrUtil.isBlank(domainName)) {
ctx.channel().close();
return;
}
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
byteBuf.resetReaderIndex();
ProxyAttachment proxyAttachment = new ProxyAttachment(ctx.channel(), bytes, (channel, buf) -> {
Channel proxyChannel = channel.attr(Constants.NEXT_CHANNEL).get();
if (null == proxyChannel) {
// 该端口还没有代理客户端
ctx.channel().close();
return;
}
proxyChannel.writeAndFlush(ProxyMessage.buildTransferMessage(ProxyUtil.getVisitorIdByChannel(channel), 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)) {
proxyAttachment.execute();
return;
}
// 用户连接到代理服务器时,设置用户连接不可读,等待代理后端服务器连接成功后再改变为可读状态
ctx.channel().config().setOption(ChannelOption.AUTO_READ, false);
String host = getHost(bytes);
if (StringUtils.isBlank(host)) {
ctx.channel().close();
return;
}
log.debug("HttpProxy host: {}", host);
if (!host.endsWith(domainName)) {
ctx.channel().close();
return;
}
int index = host.lastIndexOf("." + domainName);
String subdomain = host.substring(0, index);
// 根据域名拿到绑定的映射对应的cmdChannel
Integer serverPort = ProxyUtil.getServerPortBySubdomain(subdomain);
if (null == serverPort) {
ctx.channel().close();
return;
}
Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(serverPort);
if (null == cmdChannel) {
ctx.channel().close();
return;
}
String lanInfo = ProxyUtil.getClientLanInfoByServerPort(serverPort);
if (StringUtils.isBlank(lanInfo)) {
ctx.channel().close();
return;
}
visitorId = ProxyUtil.newVisitorId();
ProxyUtil.addVisitorChannelToCmdChannel(cmdChannel, visitorId, ctx.channel(), serverPort);
ProxyUtil.addProxyConnectAttachment(visitorId, proxyAttachment);
cmdChannel.writeAndFlush(ProxyMessage.buildConnectMessage(visitorId).setData(lanInfo.getBytes()));
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// 通知代理客户端
Channel visitorChannel = ctx.channel();
InetSocketAddress sa = (InetSocketAddress) visitorChannel.localAddress();
Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(sa.getPort());
if (cmdChannel == null) {
// 该端口还没有代理客户端
ctx.channel().close();
} else {
// 用户连接断开,从控制连接中移除
String visitorId = ProxyUtil.getVisitorIdByChannel(visitorChannel);
ProxyUtil.removeVisitorChannelFromCmdChannel(cmdChannel, visitorId);
// 删除代理附加对象
ProxyUtil.remoteProxyConnectAttachment(visitorId);
Channel proxyChannel = visitorChannel.attr(Constants.NEXT_CHANNEL).get();
if (proxyChannel != null && proxyChannel.isActive()) {
proxyChannel.attr(Constants.NEXT_CHANNEL).remove();
proxyChannel.attr(Constants.LICENSE_ID).remove();
proxyChannel.attr(Constants.VISITOR_ID).remove();
proxyChannel.config().setOption(ChannelOption.AUTO_READ, true);
// 通知客户端,用户连接已经断开
proxyChannel.writeAndFlush(ProxyMessage.buildDisconnectMessage(visitorId));
}
}
super.channelInactive(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 当出现异常就关闭连接
ctx.close();
}
private String getHost(byte[] buf) {
String req = new String(buf);
String[] lines = req.split("\r\n");
String firstLine = lines[0];
if (!(firstLine.endsWith("HTTP/1.1") || firstLine.endsWith("HTTP/1.0"))) {
return null;
}
for (int i = 1; i < lines.length; i++) {
String line = lines[i];
if (!line.startsWith("Host: ")) {
continue;
}
// 域名
String domain = line.substring(6);
return domain;
}
return null;
}
}
@@ -0,0 +1,89 @@
package org.dromara.neutrinoproxy.server.proxy.core;
import cn.hutool.core.util.StrUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.ssl.SslHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.neutrinoproxy.core.util.FileUtil;
import org.dromara.neutrinoproxy.server.base.proxy.ProxyConfig;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.event.AppLoadEndEvent;
import org.noear.solon.core.event.EventListener;
import javax.net.ssl.*;
import java.io.InputStream;
import java.security.KeyStore;
/**
* @author: aoshiguchen
* @date: 2023/4/2
*/
@Slf4j
@Component
public class HttpsProxy implements EventListener<AppLoadEndEvent> {
@Inject("serverBossGroup")
private NioEventLoopGroup serverBossGroup;
@Inject("serverWorkerGroup")
private NioEventLoopGroup serverWorkerGroup;
@Inject
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())) {
log.info("no config domain name,nonsupport https proxy.");
return;
}
this.start();
}
private void start() {
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(serverBossGroup, serverWorkerGroup)
.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(createSslHandler());
ch.pipeline().addFirst(new BytesMetricsHandler());
ch.pipeline().addLast(new HttpVisitorChannelHandler(proxyConfig.getServer().getDomainName()));
}
});
bootstrap.bind("0.0.0.0", proxyConfig.getServer().getHttpsProxyPort()).sync();
log.info("Https代理服务启动成功!");
} catch (Exception e) {
log.error("https proxy start err!", e);
}
}
private ChannelHandler createSslHandler() {
try {
InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getServer().getJksPath());
SSLContext serverContext = SSLContext.getInstance("TLS");
final KeyStore ks = KeyStore.getInstance("JKS");
ks.load(jksInputStream, proxyConfig.getServer().getKeyStorePassword().toCharArray());
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, proxyConfig.getServer().getKeyStorePassword().toCharArray());
TrustManager[] trustManagers = null;
serverContext.init(kmf.getKeyManagers(), trustManagers, null);
SSLEngine sslEngine = serverContext.createSSLEngine();
sslEngine.setUseClientMode(false);
sslEngine.setNeedClientAuth(false);
return new SslHandler(sslEngine);
} catch (Exception e) {
log.error("创建SSL处理器失败", e);
e.printStackTrace();
}
return null;
}
}
@@ -36,20 +36,10 @@ import java.security.KeyStore;
public class ProxyServerRunner implements EventListener<AppLoadEndEvent> { public class ProxyServerRunner implements EventListener<AppLoadEndEvent> {
@Inject @Inject
private ProxyConfig proxyConfig; private ProxyConfig proxyConfig;
@Inject("serverBossGroup") @Inject("tunnelBossGroup")
private NioEventLoopGroup serverBossGroup; private NioEventLoopGroup serverBossGroup;
@Inject("serverWorkerGroup") @Inject("tunnelWorkerGroup")
private NioEventLoopGroup serverWorkerGroup; private NioEventLoopGroup serverWorkerGroup;
@Inject("${neutrino.proxy.server.port}")
private Integer port;
@Inject("${neutrino.proxy.server.ssl-port}")
private Integer sslPort;
@Inject("${neutrino.proxy.server.jks-path}")
private String jksPath;
@Inject("${neutrino.proxy.server.key-store-password}")
private String keyStorePassword;
@Inject("${neutrino.proxy.server.key-manager-password}")
private String keyManagerPassword;
@Override @Override
public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable { public void onEvent(AppLoadEndEvent appLoadEndEvent) throws Throwable {
startProxyServer(); startProxyServer();
@@ -68,15 +58,15 @@ public class ProxyServerRunner implements EventListener<AppLoadEndEvent> {
} }
}); });
try { try {
bootstrap.bind(port).sync(); bootstrap.bind(proxyConfig.getTunnel().getPort()).sync();
log.info("代理服务启动,端口:{}", port); log.info("代理服务启动,端口:{}", proxyConfig.getTunnel().getPort());
} catch (Exception e) { } catch (Exception e) {
log.error("代理服务异常", e); log.error("代理服务异常", e);
} }
} }
private void startProxyServerForSSL() { private void startProxyServerForSSL() {
if (null == sslPort) { if (null == proxyConfig.getTunnel().getSslPort()) {
return; return;
} }
ServerBootstrap bootstrap = new ServerBootstrap(); ServerBootstrap bootstrap = new ServerBootstrap();
@@ -89,8 +79,8 @@ public class ProxyServerRunner implements EventListener<AppLoadEndEvent> {
} }
}); });
try { try {
bootstrap.bind(sslPort).sync(); bootstrap.bind(proxyConfig.getTunnel().getSslPort()).sync();
log.info("代理服务启动,SSL端口: {}", sslPort); log.info("代理服务启动,SSL端口: {}", proxyConfig.getTunnel().getSslPort());
} catch (Exception e) { } catch (Exception e) {
log.error("代理服务异常", e); log.error("代理服务异常", e);
} }
@@ -98,13 +88,13 @@ public class ProxyServerRunner implements EventListener<AppLoadEndEvent> {
private ChannelHandler createSslHandler() { private ChannelHandler createSslHandler() {
try { try {
InputStream jksInputStream = FileUtil.getInputStream(jksPath); InputStream jksInputStream = FileUtil.getInputStream(proxyConfig.getTunnel().getJksPath());
SSLContext serverContext = SSLContext.getInstance("TLS"); SSLContext serverContext = SSLContext.getInstance("TLS");
final KeyStore ks = KeyStore.getInstance("JKS"); final KeyStore ks = KeyStore.getInstance("JKS");
ks.load(jksInputStream, keyStorePassword.toCharArray()); ks.load(jksInputStream, proxyConfig.getTunnel().getKeyStorePassword().toCharArray());
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, keyManagerPassword.toCharArray()); kmf.init(ks, proxyConfig.getTunnel().getKeyManagerPassword().toCharArray());
TrustManager[] trustManagers = null; TrustManager[] trustManagers = null;
serverContext.init(kmf.getKeyManagers(), trustManagers, null); serverContext.init(kmf.getKeyManagers(), trustManagers, null);
@@ -4,7 +4,6 @@ import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.neutrinoproxy.core.Constants; import org.dromara.neutrinoproxy.core.Constants;
import org.dromara.neutrinoproxy.core.ProxyMessage; import org.dromara.neutrinoproxy.core.ProxyMessage;
import org.dromara.neutrinoproxy.server.proxy.domain.ProxyAttachment;
import org.dromara.neutrinoproxy.server.proxy.domain.VisitorChannelAttachInfo; import org.dromara.neutrinoproxy.server.proxy.domain.VisitorChannelAttachInfo;
import org.dromara.neutrinoproxy.server.service.FlowReportService; import org.dromara.neutrinoproxy.server.service.FlowReportService;
import org.dromara.neutrinoproxy.server.util.ProxyUtil; import org.dromara.neutrinoproxy.server.util.ProxyUtil;
@@ -23,7 +22,7 @@ import java.net.InetSocketAddress;
* @date: 2022/6/16 * @date: 2022/6/16
*/ */
@Slf4j @Slf4j
public class VisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf> { public class TcpVisitorChannelHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
@@ -2,6 +2,7 @@ package org.dromara.neutrinoproxy.server.service;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.neutrinoproxy.server.constant.NetworkProtocolEnum;
import org.dromara.neutrinoproxy.server.controller.res.system.ProtocalListRes; import org.dromara.neutrinoproxy.server.controller.res.system.ProtocalListRes;
import org.noear.solon.annotation.Component; import org.noear.solon.annotation.Component;
@@ -22,7 +23,7 @@ public class ProtocalService {
public List<ProtocalListRes> list() { public List<ProtocalListRes> list() {
return Lists.newArrayList( return Lists.newArrayList(
new ProtocalListRes().setName("TCP").setEnable(Boolean.TRUE).setRemark("支持一切TCP之上的协议"), new ProtocalListRes().setName("TCP").setEnable(Boolean.TRUE).setRemark("支持一切TCP之上的协议"),
new ProtocalListRes().setName("HTTP").setEnable(Boolean.TRUE).setRemark("支持绑定子域名,未绑定时等价于时使用TCP"), new ProtocalListRes().setName("HTTP(S)").setEnable(Boolean.TRUE).setRemark("支持绑定子域名,未绑定时等价于时使用TCP。 若配置了证书,则同时支持HTTPS。"),
new ProtocalListRes().setName("UDP").setEnable(Boolean.FALSE).setRemark("暂不支持") new ProtocalListRes().setName("UDP").setEnable(Boolean.FALSE).setRemark("暂不支持")
); );
} }
@@ -14,7 +14,7 @@ import org.dromara.neutrinoproxy.server.dal.entity.PortMappingDO;
import org.dromara.neutrinoproxy.server.dal.entity.PortPoolDO; import org.dromara.neutrinoproxy.server.dal.entity.PortPoolDO;
import org.dromara.neutrinoproxy.server.dal.entity.UserDO; import org.dromara.neutrinoproxy.server.dal.entity.UserDO;
import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler; import org.dromara.neutrinoproxy.server.proxy.core.BytesMetricsHandler;
import org.dromara.neutrinoproxy.server.proxy.core.VisitorChannelHandler; import org.dromara.neutrinoproxy.server.proxy.core.TcpVisitorChannelHandler;
import org.dromara.neutrinoproxy.server.proxy.domain.CmdChannelAttachInfo; import org.dromara.neutrinoproxy.server.proxy.domain.CmdChannelAttachInfo;
import org.dromara.neutrinoproxy.server.proxy.domain.ProxyMapping; import org.dromara.neutrinoproxy.server.proxy.domain.ProxyMapping;
import org.dromara.neutrinoproxy.server.util.ProxyUtil; import org.dromara.neutrinoproxy.server.util.ProxyUtil;
@@ -224,7 +224,7 @@ public class VisitorChannelService {
@Override @Override
public void initChannel(SocketChannel ch) throws Exception { public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addFirst(new BytesMetricsHandler()); ch.pipeline().addFirst(new BytesMetricsHandler());
ch.pipeline().addLast(new VisitorChannelHandler()); ch.pipeline().addLast(new TcpVisitorChannelHandler());
} }
}); });
@@ -12,17 +12,23 @@ neutrino:
read-idle-time: 40 read-idle-time: 40
write-idle-time: 5 write-idle-time: 5
all-idle-time-seconds: 0 all-idle-time-seconds: 0
server: tunnel:
boss-thread-count: 10 boss-thread-count: 2
work-thread-count: 60 work-thread-count: 10
port: ${OPEN_PORT:9000} port: ${OPEN_PORT:9000}
ssl-port: ${SSL_PORT:9002} ssl-port: ${SSL_PORT:9002}
key-store-password: ${STORE_PASS:123456} key-store-password: ${STORE_PASS:123456}
key-manager-password: ${MGR_PASS:123456} key-manager-password: ${MGR_PASS:123456}
jks-path: ${JKS_PATH:classpath:/test.jks} jks-path: ${JKS_PATH:classpath:/test.jks}
server:
boss-thread-count: 5
work-thread-count: 20
http-proxy-port: ${HTTP_PROXY_PORT:80} http-proxy-port: ${HTTP_PROXY_PORT:80}
https-proxy-port: ${HTTPS_PROXY_PORT:443}
# 如果不配置,则不支持域名映射 # 如果不配置,则不支持域名映射
domain-name: ${DOMAIN_NAME:} domain-name: ${DOMAIN_NAME:}
key-store-password: ${HTTPS_STORE_PASS:}
jks-path: ${HTTPS_JKS_PATH:}
data: data:
db: db:
type: ${DB_TYPE:sqlite} type: ${DB_TYPE:sqlite}
+1 -1
View File
@@ -37,7 +37,7 @@ cp $OUT $JAR_PATH/logs/back_$time.out
fi fi
rm -f $OUT rm -f $OUT
cd $JAR_PATH cd $JAR_PATH
nohup java $JAVA_OPS -jar $NAME.jar $startupParams > $OUT 2>&1 & nohup java -Dfile.encoding=utf-8 $JAVA_OPS -jar $NAME.jar $startupParams > $OUT 2>&1 &
echo "sleep 15s wating service start" echo "sleep 15s wating service start"
sleep 15 sleep 15
tail -200 $OUT tail -200 $OUT
+1 -1
View File
@@ -29,7 +29,7 @@ cp $OUT $JAR_PATH/logs/back_$time.out
fi fi
rm -f $OUT rm -f $OUT
cd $JAR_PATH cd $JAR_PATH
nohup java $JAVA_OPS -jar $NAME.jar > $OUT 2>&1 & nohup java -Dfile.encoding=utf-8 $JAVA_OPS -jar $NAME.jar > $OUT 2>&1 &
echo "sleep 15s wating service start" echo "sleep 15s wating service start"
sleep 15 sleep 15
tail -200 $OUT tail -200 $OUT