代理逻辑优化

This commit is contained in:
aoshiguchen
2022-08-29 21:13:48 +08:00
parent c4cc6e89ed
commit e2f351d898
14 changed files with 108 additions and 28 deletions
@@ -39,7 +39,7 @@ public class ProxyConfig {
public static ProxyConfig instance;
private Protocol protocol;
private Client client;
private ProxyClientConfig clientConfig;
private String licenseKey;
@Data
public static class Protocol {
@@ -28,6 +28,7 @@ import fun.asgc.neutrino.core.annotation.Bean;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.context.ApplicationRunner;
import fun.asgc.neutrino.core.util.ArrayUtil;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.FileUtil;
import fun.asgc.neutrino.core.util.StringUtil;
@@ -71,8 +72,7 @@ public class ProxyClientRunner implements ApplicationRunner {
@Override
public void run(String[] args) {
ProxyClientConfig clientConfig = getClientConfig(args.length >= 1 ? args[args.length - 1] : null);
proxyConfig.setClientConfig(clientConfig);
proxyConfig.setLicenseKey(getLicenseKey(args));
connectProxyServer();
}
@@ -115,13 +115,13 @@ public class ProxyClientRunner implements ApplicationRunner {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// 连接成功,向服务器发送客户端认证信息(clientKey)
ClientChannelMannager.setCmdChannel(future.channel());
future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(JSONObject.toJSONString(proxyConfig.getClientConfig())));
future.channel().writeAndFlush(ProxyMessage.buildAuthMessage(proxyConfig.getLicenseKey()));
log.info("连接代理服务成功.");
} else {
log.info("连接代理服务失败!");
System.exit(-1);
}
}
});
@@ -183,4 +183,25 @@ public class ProxyClientRunner implements ApplicationRunner {
}
return null;
}
private String getLicenseKey(String[] args) {
String license = "";
if (null != args && ArrayUtil.notEmpty(args)) {
for (String s : args) {
if (s.startsWith("license=") && s.length() > 8) {
license = s.substring(8).trim();
}
}
}
if (StringUtil.isEmpty(license)) {
license = FileUtil.readContentAsString("./.neutrino-proxy.license");
}
if (StringUtil.isEmpty(license)) {
log.error("未配置license,执行结束.");
System.exit(-1);
}
FileUtil.write("./.neutrino-proxy.license", license);
return license;
}
}
@@ -75,7 +75,7 @@ public class ProxyMessageConnectHandler implements ProxyMessageHandler {
realServerChannel.attr(Constants.NEXT_CHANNEL).set(channel);
// 远程绑定
channel.writeAndFlush(ProxyMessage.buildConnectMessage(userId + "@" + ProxyConfig.instance.getClientConfig().getClientKey()));
channel.writeAndFlush(ProxyMessage.buildConnectMessage(userId + "@" + ProxyConfig.instance.getLicenseKey()));
realServerChannel.config().setOption(ChannelOption.AUTO_READ, true);
ClientChannelMannager.addRealServerChannel(userId, realServerChannel);
@@ -50,5 +50,6 @@ public interface Constants {
String DISCONNECT = "DISCONNECT";
String TRANSFER = "TRANSFER";
String ERROR = "ERROR";
String PORT_MAPPING_SYNC = "PORT_MAPPING_SYNC";
}
}
@@ -43,7 +43,8 @@ public enum ProxyDataTypeEnum {
CONNECT(0x03, Constants.ProxyDataTypeName.CONNECT,"连接"),
DISCONNECT(0x04, Constants.ProxyDataTypeName.DISCONNECT,"断开连接"),
TRANSFER(0x05, Constants.ProxyDataTypeName.TRANSFER,"数据传输"),
ERROR(0x06, Constants.ProxyDataTypeName.ERROR,"异常");
ERROR(0x06, Constants.ProxyDataTypeName.ERROR,"异常"),
PORT_MAPPING_SYNC(0x07, Constants.ProxyDataTypeName.PORT_MAPPING_SYNC, "端口映射同步");
private static Map<Integer,ProxyDataTypeEnum> cache = Stream.of(values()).collect(Collectors.toMap(ProxyDataTypeEnum::getType, Function.identity()));
private int type;
@@ -27,6 +27,7 @@ import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Arrays;
import java.util.List;
/**
*
@@ -23,6 +23,7 @@
package fun.asgc.neutrino.proxy.server.base.proxy;
import fun.asgc.neutrino.proxy.core.ProxyClientConfig;
import fun.asgc.neutrino.proxy.server.dal.entity.PortMappingDO;
import lombok.Data;
import java.io.Serializable;
@@ -52,12 +53,12 @@ public class ProxyServerConfig implements Serializable {
*/
private volatile Map<Integer, String> inetPortLanInfoMapping = new HashMap<Integer, String>();
public void addClientConfig(ProxyClientConfig clientConfig) {
String clientKey = clientConfig.getClientKey();
public void addClientConfig(String licenseKey, List<PortMappingDO> portMappingList) {
String clientKey = licenseKey;
List<Integer> ports = new ArrayList<>();
for (ProxyClientConfig.Proxy proxy : clientConfig.getProxy()) {
ports.add(proxy.getServerPort());
inetPortLanInfoMapping.put(proxy.getServerPort(), proxy.getClientInfo());
for (PortMappingDO portMapping : portMappingList) {
ports.add(portMapping.getServerPort());
inetPortLanInfoMapping.put(portMapping.getServerPort(), portMapping.getClientIp() + ":" + portMapping.getClientPort());
}
clientInetPortMapping.put(clientKey, ports);
}
@@ -89,4 +89,7 @@ public interface LicenseMapper extends SqlMapper {
@ResultType(LicenseDO.class)
@Select("select * from `license` where user_id = :userId and name =:name and id not in (:excludeIds) limit 0,1")
LicenseDO checkRepeat(@Param("userId") Integer userId, @Param("name") String name, @Param("excludeIds") Set<Integer> excludeIds);
@Select("select * from `license` where key = ?")
LicenseDO findByKey(String licenseKey);
}
@@ -33,6 +33,7 @@ import fun.asgc.neutrino.proxy.server.controller.req.PortMappingListReq;
import fun.asgc.neutrino.proxy.server.controller.res.PortMappingListRes;
import fun.asgc.neutrino.proxy.server.dal.entity.PortMappingDO;
import java.util.List;
import java.util.Set;
/**
@@ -65,4 +66,8 @@ public interface PortMappingMapper extends SqlMapper {
@Select("select * from port_mapping where server_port = :port and id not in (:excludeIds)")
PortMappingDO findByPort(@Param("port") Integer port, @Param("excludeIds") Set<Integer> excludeIds);
@ResultType(PortMappingDO.class)
@Select("select * from port_mapping where license_id = ? and enable = 1")
List<PortMappingDO> findEnableListByLicenseId(Integer licenseId);
}
@@ -22,16 +22,24 @@
package fun.asgc.neutrino.proxy.server.handler;
import com.alibaba.fastjson.JSONObject;
import fun.asgc.neutrino.core.annotation.Autowired;
import fun.asgc.neutrino.core.annotation.Component;
import fun.asgc.neutrino.core.annotation.Match;
import fun.asgc.neutrino.core.annotation.NonIntercept;
import fun.asgc.neutrino.core.util.CollectionUtil;
import fun.asgc.neutrino.core.util.StringUtil;
import fun.asgc.neutrino.proxy.core.*;
import fun.asgc.neutrino.proxy.server.base.proxy.ProxyConfig;
import fun.asgc.neutrino.proxy.server.base.proxy.ProxyServerConfig;
import fun.asgc.neutrino.proxy.server.base.rest.constant.EnableStatusEnum;
import fun.asgc.neutrino.proxy.server.core.BytesMetricsHandler;
import fun.asgc.neutrino.proxy.server.core.UserChannelHandler;
import fun.asgc.neutrino.proxy.server.dal.entity.LicenseDO;
import fun.asgc.neutrino.proxy.server.dal.entity.PortMappingDO;
import fun.asgc.neutrino.proxy.server.dal.entity.UserDO;
import fun.asgc.neutrino.proxy.server.service.LicenseService;
import fun.asgc.neutrino.proxy.server.service.PortMappingService;
import fun.asgc.neutrino.proxy.server.service.UserService;
import fun.asgc.neutrino.proxy.server.util.ProxyChannelManager;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
@@ -61,37 +69,59 @@ public class ProxyMessageAuthHandler implements ProxyMessageHandler {
private NioEventLoopGroup serverWorkerGroup;
@Autowired
private ProxyConfig proxyConfig;
@Autowired
private LicenseService licenseService;
@Autowired
private UserService userService;
@Autowired
private PortMappingService portMappingService;
@Override
public void handle(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
ProxyClientConfig clientConfig = JSONObject.parseObject(proxyMessage.getInfo(), ProxyClientConfig.class);
String clientKey = clientConfig.getClientKey();
if (!proxyConfig.getLicenseMap().containsKey(clientKey)) {
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "无效的clientKey"));
String licenseKey = proxyMessage.getInfo();
if (StringUtil.isEmpty(licenseKey)) {
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "license不能为空!"));
ctx.channel().close();
return;
}
LicenseDO licenseDO = licenseService.findByKey(licenseKey);
if (null == licenseDO) {
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "license不存在!"));
ctx.channel().close();
return;
}
if (EnableStatusEnum.DISABLE.getStatus().equals(licenseDO.getEnable())) {
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "当前license已被禁用!"));
ctx.channel().close();
return;
}
UserDO userDO = userService.findById(licenseDO.getId());
if (null == userDO || EnableStatusEnum.DISABLE.getStatus().equals(userDO.getEnable())) {
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "当前license无效!"));
ctx.channel().close();
return;
}
List<PortMappingDO> portMappingList = portMappingService.findEnableListByLicenseId(licenseDO.getId());
if (CollectionUtil.isEmpty(portMappingList)) {
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "当前license没有可用的端口映射!"));
ctx.channel().close();
return;
}
if (proxyConfig.getLicenseMap().get(clientKey) != -1 && clientConfig.getProxy().size() > proxyConfig.getLicenseMap().get(clientKey)) {
ctx.channel().writeAndFlush(ProxyMessage.buildErrMessage(ExceptionEnum.AUTH_FAILED, "代理端口数超过license限制"));
ctx.channel().close();
return;
}
ProxyServerConfig.getInstance().addClientConfig(clientConfig);
List<Integer> ports = ProxyServerConfig.getInstance().getClientInetPorts(clientKey);
ProxyServerConfig.getInstance().addClientConfig(licenseKey, portMappingList);
List<Integer> ports = ProxyServerConfig.getInstance().getClientInetPorts(licenseKey);
if (ports == null) {
ctx.channel().close();
return;
}
Channel channel = ProxyChannelManager.getCmdChannel(clientKey);
Channel channel = ProxyChannelManager.getCmdChannel(licenseKey);
if (channel != null) {
ctx.channel().close();
return;
}
ProxyChannelManager.addCmdChannel(ports, clientKey, ctx.channel());
ProxyChannelManager.addCmdChannel(ports, licenseKey, ctx.channel());
startUserPortServer(ports);
}
@@ -182,6 +182,10 @@ public class LicenseService {
licenseMapper.reset(id, key, now);
}
public LicenseDO findByKey(String license) {
return licenseMapper.findByKey(license);
}
/**
* 脱敏处理
* 非当前登录人的license,一律脱敏
@@ -203,4 +203,13 @@ public class PortMappingService {
portMappingMapper.delete(id);
}
/**
* 根据license查询可用的端口映射列表
* @param licenseId
* @return
*/
public List<PortMappingDO> findEnableListByLicenseId(Integer licenseId) {
return portMappingMapper.findEnableListByLicenseId(licenseId);
}
}
@@ -119,6 +119,10 @@ public class UserService {
return userMapper.findById(userTokenDO.getUserId());
}
public UserDO findById(Integer id) {
return userMapper.findById(id);
}
public void updateTokenExpirationTime(String token) {
Date now = new Date();
Date expirationTime = DateUtil.addDate(now, Calendar.HOUR, 1);
@@ -73,7 +73,7 @@ public class ProxyChannelManager {
channel.attr(CHANNEL_PORT).set(ports);
channel.attr(CHANNEL_CLIENT_KEY).set(clientKey);
channel.attr(USER_CHANNELS).set(new ConcurrentHashMap<String, Channel>());
channel.attr(USER_CHANNELS).set(new ConcurrentHashMap<>());
cmdChannels.put(clientKey, channel);
}