gost通讯改为ws

This commit is contained in:
qaq
2025-06-25 10:49:06 +08:00
parent f3e9b31ed3
commit f7e82cdc8b
47 changed files with 3528 additions and 1513 deletions
@@ -1,12 +1,10 @@
package com.admin.service.impl;
import cn.hutool.core.util.StrUtil;
import com.admin.common.dto.ForwardDto;
import com.admin.common.dto.ForwardUpdateDto;
import com.admin.common.dto.ForwardWithTunnelDto;
import com.admin.common.dto.GostDto;
import com.admin.common.lang.R;
import com.admin.common.task.SaveConfigAsync;
import com.admin.common.utils.GostUtil;
import com.admin.common.utils.JwtUtil;
import com.admin.entity.*;
@@ -15,13 +13,12 @@ import com.admin.service.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.swing.*;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -35,6 +32,7 @@ import java.util.stream.Collectors;
* @author QAQ
* @since 2025-06-03
*/
@Slf4j
@Service
public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> implements ForwardService {
@@ -86,7 +84,7 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
}
// 4. 分配端口
PortAllocation portAllocation = allocatePorts(tunnel);
PortAllocation portAllocation = allocatePorts(tunnel, forwardDto.getInPort());
if (portAllocation.isHasError()) {
return R.err(portAllocation.getErrorMessage());
}
@@ -97,15 +95,22 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
return R.err("端口转发创建失败");
}
// 6. 调用Gost服务创建转发
R gostResult = createGostServices(forward, tunnel, permissionResult.getLimiter());
// 6. 获取所需的节点信息
NodeInfo nodeInfo = getRequiredNodes(tunnel);
if (nodeInfo.isHasError()) {
this.removeById(forward.getId());
return R.err(nodeInfo.getErrorMessage());
}
// 7. 调用Gost服务创建转发
R gostResult = createGostServices(forward, tunnel, permissionResult.getLimiter(),
nodeInfo, permissionResult.getUserTunnel());
if (gostResult.getCode() != 0) {
this.removeById(forward.getId());
return gostResult;
}
return R.ok();
}
@@ -155,14 +160,31 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
// 5. 更新Forward对象
Forward updatedForward = updateForwardEntity(forwardUpdateDto, existForward, tunnel);
// 6. 调用Gost服务更新转发
R gostResult = updateGostServices(updatedForward, tunnel,
permissionResult != null ? permissionResult.getLimiter() : null);
// 6. 获取所需的节点信息
NodeInfo nodeInfo = getRequiredNodes(tunnel);
if (nodeInfo.isHasError()) {
return R.err(nodeInfo.getErrorMessage());
}
// 7. 调用Gost服务更新转发
R gostResult;
if (isTunnelChanged(existForward, forwardUpdateDto)) {
// 隧道变化时:先删除原配置,再创建新配置
gostResult = updateGostServicesWithTunnelChange(existForward, updatedForward, tunnel,
permissionResult != null ? permissionResult.getLimiter() : null,
nodeInfo, permissionResult != null ? permissionResult.getUserTunnel() : null);
} else {
// 隧道未变化时:直接更新配置
gostResult = updateGostServices(updatedForward, tunnel,
permissionResult != null ? permissionResult.getLimiter() : null,
nodeInfo, permissionResult != null ? permissionResult.getUserTunnel() : null);
}
if (gostResult.getCode() != 0) {
return gostResult;
}
// 7. 保存更新
updatedForward.setStatus(1);
// 8. 保存更新
boolean result = this.updateById(updatedForward);
return result ? R.ok("端口转发更新成功") : R.err("端口转发更新失败");
}
@@ -185,19 +207,27 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
}
// 4. 权限检查(仅普通用户需要)
UserTunnel userTunnel = null;
if (currentUser.getRoleId() != ADMIN_ROLE_ID) {
if (!hasUserTunnelPermission(currentUser.getUserId(), tunnel.getId().intValue())) {
userTunnel = getUserTunnel(currentUser.getUserId(), tunnel.getId().intValue());
if (userTunnel == null) {
return R.err("你没有该隧道权限");
}
}
// 5. 调用Gost服务删除转发
R gostResult = deleteGostServices(forward, tunnel);
// 5. 获取所需的节点信息
NodeInfo nodeInfo = getRequiredNodes(tunnel);
if (nodeInfo.isHasError()) {
return R.err(nodeInfo.getErrorMessage());
}
// 6. 调用Gost服务删除转发
R gostResult = deleteGostServices(forward, tunnel, nodeInfo, userTunnel);
if (gostResult.getCode() != 0) {
return gostResult;
}
// 6. 删除转发记录
// 7. 删除转发记录
boolean result = this.removeById(id);
if (result) {
// 归还用户转发条数(普通用户才需要归还)
@@ -260,6 +290,7 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
}
// 4. 恢复服务时需要额外检查
UserTunnel userTunnel = null;
if (targetStatus == FORWARD_STATUS_ACTIVE) {
if (tunnel.getStatus() != TUNNEL_STATUS_ACTIVE) {
return R.err("隧道已禁用,无法恢复服务");
@@ -271,49 +302,50 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
if (flowCheckResult.getCode() != 0) {
return flowCheckResult;
}
userTunnel = getUserTunnel(currentUser.getUserId(), tunnel.getId().intValue());
if (userTunnel == null) {
return R.err("你没有该隧道权限");
}
}
}
// 5. 权限检查(仅普通用户需要)
if (currentUser.getRoleId() != ADMIN_ROLE_ID) {
if (!hasUserTunnelPermission(currentUser.getUserId(), tunnel.getId().intValue())) {
if (currentUser.getRoleId() != ADMIN_ROLE_ID && userTunnel == null) {
userTunnel = getUserTunnel(currentUser.getUserId(), tunnel.getId().intValue());
if (userTunnel == null) {
return R.err("你没有该隧道权限");
}
}
// 6. 调用Gost服务
Node node = nodeService.getNodeById(tunnel.getInNodeId());
if (node == null) {
return R.err("节点不存在");
// 6. 获取所需的节点信息
NodeInfo nodeInfo = getRequiredNodes(tunnel);
if (nodeInfo.isHasError()) {
return R.err(nodeInfo.getErrorMessage());
}
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), forward.getTunnelId());
// 7. 调用Gost服务
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), forward.getTunnelId(), userTunnel);
GostDto gostResult;
if ("PauseService".equals(gostMethod)) {
gostResult = GostUtil.PauseService(node.getIp() + ":" + node.getPort(), serviceName, node.getSecret());
gostResult = GostUtil.PauseService(nodeInfo.getInNode().getId(), serviceName);
// 隧道转发需要同时暂停远端服务
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD) {
Node outNode = nodeService.getNodeById(tunnel.getOutNodeId());
if (outNode != null) {
GostDto remoteResult = GostUtil.PauseRemoteService(outNode.getIp() + ":" + outNode.getPort(), serviceName, outNode.getSecret());
if (!isGostOperationSuccess(remoteResult)) {
return R.err(operation + "远端服务失败:" + remoteResult.getMsg());
}
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD && nodeInfo.getOutNode() != null) {
GostDto remoteResult = GostUtil.PauseRemoteService(nodeInfo.getOutNode().getId(), serviceName);
if (!isGostOperationSuccess(remoteResult)) {
return R.err(operation + "远端服务失败:" + remoteResult.getMsg());
}
}
} else {
gostResult = GostUtil.ResumeService(node.getIp() + ":" + node.getPort(), serviceName, node.getSecret());
gostResult = GostUtil.ResumeService(nodeInfo.getInNode().getId(), serviceName);
// 隧道转发需要同时恢复远端服务
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD) {
Node outNode = nodeService.getNodeById(tunnel.getOutNodeId());
if (outNode != null) {
GostDto remoteResult = GostUtil.ResumeRemoteService(outNode.getIp() + ":" + outNode.getPort(), serviceName, outNode.getSecret());
if (!isGostOperationSuccess(remoteResult)) {
return R.err(operation + "远端服务失败:" + remoteResult.getMsg());
}
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD && nodeInfo.getOutNode() != null) {
GostDto remoteResult = GostUtil.ResumeRemoteService(nodeInfo.getOutNode().getId(), serviceName);
if (!isGostOperationSuccess(remoteResult)) {
return R.err(operation + "远端服务失败:" + remoteResult.getMsg());
}
}
}
@@ -322,7 +354,7 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
return R.err(operation + "服务失败:" + gostResult.getMsg());
}
// 7. 更新转发状态
// 8. 更新转发状态
forward.setStatus(targetStatus);
forward.setUpdatedTime(System.currentTimeMillis());
boolean result = this.updateById(forward);
@@ -365,12 +397,32 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
return forward;
}
/**
* 获取所需的节点信息
*/
private NodeInfo getRequiredNodes(Tunnel tunnel) {
Node inNode = nodeService.getNodeById(tunnel.getInNodeId());
if (inNode == null) {
return NodeInfo.error("入口节点不存在");
}
Node outNode = null;
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD) {
outNode = nodeService.getNodeById(tunnel.getOutNodeId());
if (outNode == null) {
return NodeInfo.error("出口节点不存在");
}
}
return NodeInfo.success(inNode, outNode);
}
/**
* 检查用户权限和限制
*/
private UserPermissionResult checkUserPermissions(UserInfo currentUser, Tunnel tunnel, Long excludeForwardId) {
if (currentUser.getRoleId() == ADMIN_ROLE_ID) {
return UserPermissionResult.success(null);
return UserPermissionResult.success(null, null);
}
// 获取用户信息
@@ -404,7 +456,7 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
return UserPermissionResult.error(quotaCheckResult.getMsg());
}
return UserPermissionResult.success(userTunnel.getSpeedId());
return UserPermissionResult.success(userTunnel.getSpeedId(), userTunnel);
}
/**
@@ -473,15 +525,33 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
/**
* 分配端口
*/
private PortAllocation allocatePorts(Tunnel tunnel) {
Integer inPort = allocateInPort(tunnel);
if (inPort == null) {
return PortAllocation.error("隧道入口端口已满,无法分配新端口");
private PortAllocation allocatePorts(Tunnel tunnel, Integer specifiedInPort) {
return allocatePorts(tunnel, specifiedInPort, null);
}
/**
* 分配端口
*/
private PortAllocation allocatePorts(Tunnel tunnel, Integer specifiedInPort, Long excludeForwardId) {
Integer inPort;
if (specifiedInPort != null) {
// 用户指定了入口端口,需要检查是否可用
if (!isInPortAvailable(tunnel, specifiedInPort, excludeForwardId)) {
return PortAllocation.error("指定的入口端口 " + specifiedInPort + " 已被占用或不在允许范围内");
}
inPort = specifiedInPort;
} else {
// 用户未指定端口时自动分配
inPort = allocateInPort(tunnel, excludeForwardId);
if (inPort == null) {
return PortAllocation.error("隧道入口端口已满,无法分配新端口");
}
}
Integer outPort = null;
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD) {
outPort = allocateOutPort(tunnel);
outPort = allocateOutPort(tunnel, excludeForwardId);
if (outPort == null) {
return PortAllocation.error("隧道出口端口已满,无法分配新端口");
}
@@ -513,13 +583,27 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
Forward forward = new Forward();
BeanUtils.copyProperties(forwardUpdateDto, forward);
// 如果隧道ID发生变化,需要重新分配端口
if (!existForward.getTunnelId().equals(forwardUpdateDto.getTunnelId())) {
PortAllocation portAllocation = allocatePorts(tunnel);
// 处理端口分配逻辑
boolean tunnelChanged = !existForward.getTunnelId().equals(forwardUpdateDto.getTunnelId());
boolean inPortChanged = forwardUpdateDto.getInPort() != null &&
!Objects.equals(forwardUpdateDto.getInPort(), existForward.getInPort());
if (tunnelChanged || inPortChanged) {
// 隧道变化或入口端口变化时需要重新分配
Integer specifiedInPort = forwardUpdateDto.getInPort();
// 如果没有指定新端口但隧道未变化,保持原端口
if (specifiedInPort == null && !tunnelChanged) {
specifiedInPort = existForward.getInPort();
}
PortAllocation portAllocation = allocatePorts(tunnel, specifiedInPort, forwardUpdateDto.getId());
if (portAllocation.isHasError()) {
throw new RuntimeException(portAllocation.getErrorMessage());
}
forward.setInPort(portAllocation.getInPort());
forward.setOutPort(portAllocation.getOutPort());
} else {
// 隧道未变化,保持原端口
// 隧道和端口都未变化,保持原端口
forward.setInPort(existForward.getInPort());
forward.setOutPort(existForward.getOutPort());
}
@@ -531,27 +615,33 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
/**
* 创建Gost服务
*/
private R createGostServices(Forward forward, Tunnel tunnel, Integer limiter) {
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), forward.getTunnelId());
Node inNode = nodeService.getNodeById(tunnel.getInNodeId());
private R createGostServices(Forward forward, Tunnel tunnel, Integer limiter,
NodeInfo nodeInfo, UserTunnel userTunnel) {
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), forward.getTunnelId(), userTunnel);
// 隧道转发需要创建链和远程服务
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD) {
R chainResult = createChainService(inNode, serviceName, tunnel.getOutIp(), forward.getOutPort(), tunnel.getProtocol());
R chainResult = createChainService(nodeInfo.getInNode(), serviceName, tunnel.getOutIp(), forward.getOutPort(), tunnel.getProtocol());
if (chainResult.getCode() != 0) {
GostUtil.DeleteChains(nodeInfo.getInNode().getId(), serviceName);
return chainResult;
}
R remoteResult = createRemoteService(tunnel.getOutNodeId().intValue(), serviceName, forward, tunnel.getProtocol());
R remoteResult = createRemoteService(nodeInfo.getOutNode(), serviceName, forward, tunnel.getProtocol());
if (remoteResult.getCode() != 0) {
GostUtil.DeleteChains(nodeInfo.getInNode().getId(), serviceName);
GostUtil.DeleteRemoteService(nodeInfo.getOutNode().getId(), serviceName);
return remoteResult;
}
}
// 创建主服务
R serviceResult = createMainService(inNode, serviceName, forward, limiter, tunnel.getType());
R serviceResult = createMainService(nodeInfo.getInNode(), serviceName, forward, limiter, tunnel.getType(), tunnel);
if (serviceResult.getCode() != 0) {
GostUtil.DeleteChains(nodeInfo.getInNode().getId(), serviceName);
if (nodeInfo.getOutNode() != null) {
GostUtil.DeleteRemoteService(nodeInfo.getOutNode().getId(), serviceName);
}
return serviceResult;
}
return R.ok();
@@ -560,19 +650,19 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
/**
* 更新Gost服务
*/
private R updateGostServices(Forward forward, Tunnel tunnel, Integer limiter) {
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), forward.getTunnelId());
Node inNode = nodeService.getNodeById(tunnel.getInNodeId());
private R updateGostServices(Forward forward, Tunnel tunnel, Integer limiter,
NodeInfo nodeInfo, UserTunnel userTunnel) {
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), forward.getTunnelId(), userTunnel);
// 隧道转发需要更新链和远程服务
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD) {
R chainResult = updateChainService(inNode, serviceName, tunnel.getOutIp(), forward.getOutPort(), tunnel.getProtocol());
R chainResult = updateChainService(nodeInfo.getInNode(), serviceName, tunnel.getOutIp(), forward.getOutPort(), tunnel.getProtocol());
if (chainResult.getCode() != 0) {
updateForwardStatusToError(forward);
return chainResult;
}
R remoteResult = updateRemoteService(tunnel.getOutNodeId().intValue(), serviceName, forward, tunnel.getProtocol());
R remoteResult = updateRemoteService(nodeInfo.getOutNode(), serviceName, forward, tunnel.getProtocol());
if (remoteResult.getCode() != 0) {
updateForwardStatusToError(forward);
return remoteResult;
@@ -580,7 +670,7 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
}
// 更新主服务
R serviceResult = updateMainService(inNode, serviceName, forward, limiter, tunnel.getType());
R serviceResult = updateMainService(nodeInfo.getInNode(), serviceName, forward, limiter, tunnel.getType(), tunnel);
if (serviceResult.getCode() != 0) {
updateForwardStatusToError(forward);
return serviceResult;
@@ -589,30 +679,64 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
return R.ok();
}
/**
* 隧道变化时更新Gost服务:先删除原配置,再创建新配置
*/
private R updateGostServicesWithTunnelChange(Forward existForward, Forward updatedForward, Tunnel newTunnel,
Integer limiter, NodeInfo nodeInfo, UserTunnel userTunnel) {
// 1. 获取原隧道信息
Tunnel oldTunnel = tunnelService.getById(existForward.getTunnelId());
if (oldTunnel == null) {
return R.err("原隧道不存在,无法删除旧配置");
}
// 2. 获取原隧道的节点信息
NodeInfo oldNodeInfo = getRequiredNodes(oldTunnel);
if (oldNodeInfo.isHasError()) {
log.warn("获取原隧道{}的节点信息失败: {}", oldTunnel.getId(), oldNodeInfo.getErrorMessage());
} else {
// 3. 删除原有的Gost服务配置
R deleteResult = deleteGostServices(existForward, oldTunnel, oldNodeInfo, userTunnel);
if (deleteResult.getCode() != 0) {
// 删除失败时记录日志,但不影响后续创建(可能原配置已不存在)
log.warn("删除原隧道{}的Gost配置失败: {}", oldTunnel.getId(), deleteResult.getMsg());
}
}
// 4. 创建新的Gost服务配置
R createResult = createGostServices(updatedForward, newTunnel, limiter, nodeInfo, userTunnel);
if (createResult.getCode() != 0) {
updateForwardStatusToError(updatedForward);
return R.err("创建新隧道配置失败: " + createResult.getMsg());
}
return R.ok();
}
/**
* 删除Gost服务
*/
private R deleteGostServices(Forward forward, Tunnel tunnel) {
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), forward.getTunnelId());
Node inNode = nodeService.getNodeById(tunnel.getInNodeId());
private R deleteGostServices(Forward forward, Tunnel tunnel, NodeInfo nodeInfo, UserTunnel userTunnel) {
String serviceName = buildServiceName(forward.getId(), forward.getUserId(), forward.getTunnelId(), userTunnel);
// 删除主服务
GostDto serviceResult = GostUtil.DeleteService(inNode.getIp() + ":" + inNode.getPort(), serviceName, inNode.getSecret());
GostDto serviceResult = GostUtil.DeleteService(nodeInfo.getInNode().getId(), serviceName);
if (!isGostOperationSuccess(serviceResult)) {
return R.err(serviceResult.getMsg());
}
// 隧道转发需要删除链和远程服务
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD) {
GostDto chainResult = GostUtil.DeleteChains(inNode.getIp() + ":" + inNode.getPort(), serviceName, inNode.getSecret());
GostDto chainResult = GostUtil.DeleteChains(nodeInfo.getInNode().getId(), serviceName);
if (!isGostOperationSuccess(chainResult)) {
return R.err(chainResult.getMsg());
}
Node outNode = nodeService.getNodeById(tunnel.getOutNodeId());
GostDto remoteResult = GostUtil.DeleteRemoteService(outNode.getIp() + ":" + outNode.getPort(), serviceName, outNode.getSecret());
if (!isGostOperationSuccess(remoteResult)) {
return R.err(remoteResult.getMsg());
if (nodeInfo.getOutNode() != null) {
GostDto remoteResult = GostUtil.DeleteRemoteService(nodeInfo.getOutNode().getId(), serviceName);
if (!isGostOperationSuccess(remoteResult)) {
return R.err(remoteResult.getMsg());
}
}
}
@@ -624,28 +748,29 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
*/
private R createChainService(Node inNode, String serviceName, String outIp, Integer outPort, String protocol) {
String remoteAddr = outIp + ":" + outPort;
GostDto result = GostUtil.AddChains(inNode.getIp() + ":" + inNode.getPort(), serviceName, remoteAddr, inNode.getSecret(), protocol);
if (outIp.contains(":")) {
remoteAddr = "[" + outIp + "]:" + outPort;
}
GostDto result = GostUtil.AddChains(inNode.getId(), serviceName, remoteAddr, protocol);
return isGostOperationSuccess(result) ? R.ok() : R.err(result.getMsg());
}
/**
* 创建远程服务
*/
private R createRemoteService(Integer outNodeId, String serviceName, Forward forward, String protocol) {
Node outNode = nodeService.getNodeById(outNodeId.longValue());
GostDto result = GostUtil.AddRemoteService(outNode.getIp() + ":" + outNode.getPort(),
private R createRemoteService(Node outNode, String serviceName, Forward forward, String protocol) {
GostDto result = GostUtil.AddRemoteService(outNode.getId(),
serviceName, forward.getOutPort(),
forward.getRemoteAddr(), outNode.getSecret(), protocol);
forward.getRemoteAddr(), protocol);
return isGostOperationSuccess(result) ? R.ok() : R.err(result.getMsg());
}
/**
* 创建主服务
*/
private R createMainService(Node inNode, String serviceName, Forward forward, Integer limiter, Integer tunnelType) {
GostDto result = GostUtil.AddService(inNode.getIp() + ":" + inNode.getPort(), serviceName,
forward.getInPort(), limiter, forward.getRemoteAddr(),
inNode.getSecret(), tunnelType);
private R createMainService(Node inNode, String serviceName, Forward forward, Integer limiter, Integer tunnelType, Tunnel tunnel) {
GostDto result = GostUtil.AddService(inNode.getId(), serviceName,
forward.getInPort(), limiter, forward.getRemoteAddr(), tunnelType, tunnel);
return isGostOperationSuccess(result) ? R.ok() : R.err(result.getMsg());
}
@@ -653,12 +778,14 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
* 更新链服务
*/
private R updateChainService(Node inNode, String serviceName, String outIp, Integer outPort, String protocol) {
// 创建新链
String remoteAddr = outIp + ":" + outPort;
GostDto createResult = GostUtil.UpdateChains(inNode.getIp() + ":" + inNode.getPort(), serviceName, remoteAddr, inNode.getSecret(), protocol);
if (outIp.contains(":")) {
remoteAddr = "[" + outIp + "]:" + outPort;
}
GostDto createResult = GostUtil.UpdateChains(inNode.getId(), serviceName, remoteAddr, protocol);
if (createResult.getMsg().contains(GOST_NOT_FOUND_MSG)) {
createResult = GostUtil.AddChains(inNode.getIp() + ":" + inNode.getPort(), serviceName, remoteAddr, inNode.getSecret(), protocol);
createResult = GostUtil.AddChains(inNode.getId(), serviceName, remoteAddr, protocol);
}
return isGostOperationSuccess(createResult) ? R.ok() : R.err(createResult.getMsg());
}
@@ -666,16 +793,15 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
/**
* 更新远程服务
*/
private R updateRemoteService(Integer outNodeId, String serviceName, Forward forward, String protocol) {
Node outNode = nodeService.getNodeById(outNodeId.longValue());
private R updateRemoteService(Node outNode, String serviceName, Forward forward, String protocol) {
// 创建新远程服务
GostDto createResult = GostUtil.UpdateRemoteService(outNode.getIp() + ":" + outNode.getPort(),
GostDto createResult = GostUtil.UpdateRemoteService(outNode.getId(),
serviceName, forward.getOutPort(),
forward.getRemoteAddr(), outNode.getSecret());
forward.getRemoteAddr());
if (createResult.getMsg().contains(GOST_NOT_FOUND_MSG)) {
createResult = GostUtil.AddRemoteService(outNode.getIp() + ":" + outNode.getPort(),
createResult = GostUtil.AddRemoteService(outNode.getId(),
serviceName, forward.getOutPort(),
forward.getRemoteAddr(), outNode.getSecret(),protocol);
forward.getRemoteAddr(),protocol);
}
return isGostOperationSuccess(createResult) ? R.ok() : R.err(createResult.getMsg());
}
@@ -683,15 +809,14 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
/**
* 更新主服务
*/
private R updateMainService(Node inNode, String serviceName, Forward forward, Integer limiter, Integer tunnelType) {
GostDto result = GostUtil.UpdateService(inNode.getIp() + ":" + inNode.getPort(), serviceName,
forward.getInPort(), limiter, forward.getRemoteAddr(),
inNode.getSecret(), tunnelType);
private R updateMainService(Node inNode, String serviceName, Forward forward, Integer limiter, Integer tunnelType, Tunnel tunnel) {
GostDto result = GostUtil.UpdateService(inNode.getId(), serviceName,
forward.getInPort(), limiter, forward.getRemoteAddr(), tunnelType, tunnel);
if (result.getMsg().contains(GOST_NOT_FOUND_MSG)) {
result = GostUtil.AddService(inNode.getIp() + ":" + inNode.getPort(), serviceName,
result = GostUtil.AddService(inNode.getId(), serviceName,
forward.getInPort(), limiter, forward.getRemoteAddr(),
inNode.getSecret(), tunnelType);
tunnelType, tunnel);
}
return isGostOperationSuccess(result) ? R.ok() : R.err(result.getMsg());
@@ -705,13 +830,6 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
this.updateById(forward);
}
/**
* 检查是否有用户隧道权限
*/
private boolean hasUserTunnelPermission(Integer userId, Integer tunnelId) {
return getUserTunnel(userId, tunnelId) != null;
}
/**
* 获取用户隧道关系
*/
@@ -750,17 +868,67 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
}
/**
* 为隧道分配一个可用的入口端口
* 检查指定的入口端口是否可用
*/
private Integer allocateInPort(Tunnel tunnel) {
private boolean isInPortAvailable(Tunnel tunnel, Integer port) {
return isInPortAvailable(tunnel, port, null);
}
/**
* 检查指定的入口端口是否可用(可排除指定的转发ID)
*/
private boolean isInPortAvailable(Tunnel tunnel, Integer port, Long excludeForwardId) {
// 检查端口是否在隧道允许的范围内
if (port < tunnel.getInPortSta() || port > tunnel.getInPortEnd()) {
return false;
}
// 获取所有使用相同入口节点的隧道
List<Tunnel> tunnelsWithSameInNode = tunnelService.list(new QueryWrapper<Tunnel>().eq("in_node_id", tunnel.getInNodeId()));
Set<Long> tunnelIds = tunnelsWithSameInNode.stream()
.map(Tunnel::getId)
.collect(Collectors.toSet());
// 获取这些隧道的所有转发已使用的入口端口
List<Forward> usedForwards = this.list(new QueryWrapper<Forward>().in("tunnel_id", tunnelIds));
// 获取这些隧道的所有转发已使用的入口端口(排除指定的转发ID)
QueryWrapper<Forward> queryWrapper = new QueryWrapper<Forward>().in("tunnel_id", tunnelIds);
if (excludeForwardId != null) {
queryWrapper.ne("id", excludeForwardId);
}
List<Forward> usedForwards = this.list(queryWrapper);
Set<Integer> usedInPorts = usedForwards.stream()
.map(Forward::getInPort)
.filter(portNum -> portNum != null)
.collect(Collectors.toSet());
// 检查端口是否已被占用
return !usedInPorts.contains(port);
}
/**
* 为隧道分配一个可用的入口端口
*/
private Integer allocateInPort(Tunnel tunnel) {
return allocateInPort(tunnel, null);
}
/**
* 为隧道分配一个可用的入口端口(可排除指定的转发ID)
*/
private Integer allocateInPort(Tunnel tunnel, Long excludeForwardId) {
// 获取所有使用相同入口节点的隧道
List<Tunnel> tunnelsWithSameInNode = tunnelService.list(new QueryWrapper<Tunnel>().eq("in_node_id", tunnel.getInNodeId()));
Set<Long> tunnelIds = tunnelsWithSameInNode.stream()
.map(Tunnel::getId)
.collect(Collectors.toSet());
// 获取这些隧道的所有转发已使用的入口端口(排除指定的转发ID)
QueryWrapper<Forward> queryWrapper = new QueryWrapper<Forward>().in("tunnel_id", tunnelIds);
if (excludeForwardId != null) {
queryWrapper.ne("id", excludeForwardId);
}
List<Forward> usedForwards = this.list(queryWrapper);
Set<Integer> usedInPorts = usedForwards.stream()
.map(Forward::getInPort)
.filter(port -> port != null)
@@ -779,14 +947,26 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
* 为隧道分配一个可用的出口端口
*/
private Integer allocateOutPort(Tunnel tunnel) {
return allocateOutPort(tunnel, null);
}
/**
* 为隧道分配一个可用的出口端口(可排除指定的转发ID)
*/
private Integer allocateOutPort(Tunnel tunnel, Long excludeForwardId) {
// 获取所有使用相同出口节点的隧道
List<Tunnel> tunnelsWithSameOutNode = tunnelService.list(new QueryWrapper<Tunnel>().eq("out_node_id", tunnel.getOutNodeId()));
Set<Long> tunnelIds = tunnelsWithSameOutNode.stream()
.map(Tunnel::getId)
.collect(Collectors.toSet());
// 获取这些隧道的所有转发已使用的出口端口
List<Forward> usedForwards = this.list(new QueryWrapper<Forward>().in("tunnel_id", tunnelIds));
// 获取这些隧道的所有转发已使用的出口端口(排除指定的转发ID)
QueryWrapper<Forward> queryWrapper = new QueryWrapper<Forward>().in("tunnel_id", tunnelIds);
if (excludeForwardId != null) {
queryWrapper.ne("id", excludeForwardId);
}
List<Forward> usedForwards = this.list(queryWrapper);
Set<Integer> usedOutPorts = usedForwards.stream()
.map(Forward::getOutPort)
.filter(port -> port != null)
@@ -802,16 +982,10 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
}
/**
* 构建服务名称,确保管理员和用户操作的一致性
* 构建服务名称,优化后减少重复查询
*/
private String buildServiceName(Long forwardId, Integer userId, Integer tunnelId) {
// 根据userId和tunnelId查询UserTunnel获取正确的user_tunnel_id
UserTunnel userTunnel = userTunnelService.getOne(new QueryWrapper<UserTunnel>()
.eq("user_id", userId)
.eq("tunnel_id", tunnelId));
private String buildServiceName(Long forwardId, Integer userId, Integer tunnelId, UserTunnel userTunnel) {
int userTunnelId = (userTunnel != null) ? userTunnel.getId() : 0;
return forwardId + "_" + userId + "_" + userTunnelId;
}
@@ -825,7 +999,6 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
private final Integer userId;
private final Integer roleId;
private final String userName;
}
/**
@@ -836,19 +1009,21 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
private final boolean hasError;
private final String errorMessage;
private final Integer limiter;
private final UserTunnel userTunnel;
private UserPermissionResult(boolean hasError, String errorMessage, Integer limiter) {
private UserPermissionResult(boolean hasError, String errorMessage, Integer limiter, UserTunnel userTunnel) {
this.hasError = hasError;
this.errorMessage = errorMessage;
this.limiter = limiter;
this.userTunnel = userTunnel;
}
public static UserPermissionResult success(Integer limiter) {
return new UserPermissionResult(false, null, limiter);
public static UserPermissionResult success(Integer limiter, UserTunnel userTunnel) {
return new UserPermissionResult(false, null, limiter, userTunnel);
}
public static UserPermissionResult error(String errorMessage) {
return new UserPermissionResult(true, errorMessage, null);
return new UserPermissionResult(true, errorMessage, null, null);
}
}
@@ -877,4 +1052,30 @@ public class ForwardServiceImpl extends ServiceImpl<ForwardMapper, Forward> impl
return new PortAllocation(true, errorMessage, null, null);
}
}
/**
* 节点信息封装类
*/
@Data
private static class NodeInfo {
private final boolean hasError;
private final String errorMessage;
private final Node inNode;
private final Node outNode;
private NodeInfo(boolean hasError, String errorMessage, Node inNode, Node outNode) {
this.hasError = hasError;
this.errorMessage = errorMessage;
this.inNode = inNode;
this.outNode = outNode;
}
public static NodeInfo success(Node inNode, Node outNode) {
return new NodeInfo(false, null, inNode, outNode);
}
public static NodeInfo error(String errorMessage) {
return new NodeInfo(true, errorMessage, null, null);
}
}
}
@@ -187,6 +187,7 @@ public class NodeServiceImpl extends ServiceImpl<NodeMapper, Node> implements No
node.setId(nodeUpdateDto.getId());
node.setName(nodeUpdateDto.getName());
node.setIp(nodeUpdateDto.getIp());
node.setServerIp(nodeUpdateDto.getServerIp());
node.setUpdatedTime(System.currentTimeMillis());
return node;
}
@@ -297,15 +298,68 @@ public class NodeServiceImpl extends ServiceImpl<NodeMapper, Node> implements No
StringBuilder command = new StringBuilder();
// 第一部分:下载安装脚本
command.append("curl -L https://raw.githubusercontent.com/bqlpfy/forward-panel/refs/heads/main/install.sh")
command.append("curl -L https://ghproxy.com/https://raw.githubusercontent.com/bqlpfy/forward-panel/refs/heads/main/install.sh")
.append(" -o ./install.sh && chmod +x ./install.sh && ");
// 处理服务器地址,如果是IPv6需要添加方括号
String processedServerAddr = processServerAddress(serverAddr);
// 第二部分:执行安装脚本(去掉-u参数)
command.append("./install.sh")
.append(" -a ").append(serverAddr) // 服务器地址
.append(" -p ").append(node.getPort()) // 节点端口
.append(" -s ").append(node.getSecret()); // 节点密钥
.append(" -a ").append(processedServerAddr) // 服务器地址
.append(" -s ").append(node.getSecret()); // 节点密钥
return command.toString();
}
/**
* 处理服务器地址,确保IPv6地址被方括号包裹
*
* @param serverAddr 原始服务器地址,格式可能为 host:port
* @return 处理后的服务器地址
*/
private String processServerAddress(String serverAddr) {
if (StrUtil.isBlank(serverAddr)) {
return serverAddr;
}
// 如果已经被方括号包裹,直接返回
if (serverAddr.startsWith("[")) {
return serverAddr;
}
// 查找最后一个冒号,分离主机和端口
int lastColonIndex = serverAddr.lastIndexOf(':');
if (lastColonIndex == -1) {
// 没有端口号,直接检查是否需要包裹
return isIPv6Address(serverAddr) ? "[" + serverAddr + "]" : serverAddr;
}
String host = serverAddr.substring(0, lastColonIndex);
String port = serverAddr.substring(lastColonIndex);
// 检查主机部分是否为IPv6地址
if (isIPv6Address(host)) {
return "[" + host + "]" + port;
}
return serverAddr;
}
/**
* 判断是否为IPv6地址
*
* @param address 地址字符串(不包含端口号)
* @return 是否为IPv6地址
*/
private boolean isIPv6Address(String address) {
// IPv6地址包含多个冒号,至少2个
if (!address.contains(":")) {
return false;
}
// 计算冒号数量,IPv6地址至少有2个冒号
long colonCount = address.chars().filter(ch -> ch == ':').count();
return colonCount >= 2;
}
}
@@ -289,10 +289,9 @@ public class SpeedLimitServiceImpl extends ServiceImpl<SpeedLimitMapper, SpeedLi
Node node = nodeService.getNodeById(tunnel.getInNodeId());
GostDto gostResult = GostUtil.AddLimiters(
buildNodeAddress(node),
node.getId(),
speedLimit.getId(),
speedInMBps,
node.getSecret()
speedInMBps
);
return isGostOperationSuccess(gostResult) ? R.ok() : R.err(gostResult.getMsg());
@@ -308,14 +307,13 @@ public class SpeedLimitServiceImpl extends ServiceImpl<SpeedLimitMapper, SpeedLi
private R updateGostLimiter(SpeedLimit speedLimit, Tunnel tunnel) {
String speedInMBps = convertBitsToMBps(speedLimit.getSpeed());
Node node = nodeService.getNodeById(tunnel.getInNodeId());
String nodeAddress = buildNodeAddress(node);
// 尝试更新限速器
GostDto gostResult = GostUtil.UpdateLimiters(nodeAddress, speedLimit.getId(), speedInMBps, node.getSecret());
GostDto gostResult = GostUtil.UpdateLimiters(node.getId(), speedLimit.getId(), speedInMBps);
// 如果限速器不存在,则创建新的
if (gostResult.getMsg().contains(GOST_NOT_FOUND_MSG)) {
gostResult = GostUtil.AddLimiters(nodeAddress, speedLimit.getId(), speedInMBps, node.getSecret());
gostResult = GostUtil.AddLimiters(node.getId(), speedLimit.getId(), speedInMBps);
}
return isGostOperationSuccess(gostResult) ? R.ok() : R.err(gostResult.getMsg());
@@ -330,7 +328,7 @@ public class SpeedLimitServiceImpl extends ServiceImpl<SpeedLimitMapper, SpeedLi
*/
private R deleteGostLimiter(Long speedLimitId, Tunnel tunnel) {
Node node = nodeService.getNodeById(tunnel.getInNodeId());
GostDto gostResult = GostUtil.DeleteLimiters(buildNodeAddress(node), speedLimitId, node.getSecret());
GostDto gostResult = GostUtil.DeleteLimiters(node.getId(), speedLimitId);
return isGostOperationSuccess(gostResult) ? R.ok() : R.err(gostResult.getMsg());
}
@@ -345,16 +343,6 @@ public class SpeedLimitServiceImpl extends ServiceImpl<SpeedLimitMapper, SpeedLi
speedLimitService.updateById(speedLimit);
}
/**
* 构建节点地址
*
* @param node 节点对象
* @return 节点地址字符串
*/
private String buildNodeAddress(Node node) {
return node.getIp() + ":" + node.getPort();
}
/**
* 将比特率转换为兆字节每秒
*
@@ -193,6 +193,14 @@ public class TunnelServiceImpl extends ServiceImpl<TunnelMapper, Tunnel> impleme
existingTunnel.setInPortSta(tunnelUpdateDto.getInPortSta());
existingTunnel.setInPortEnd(tunnelUpdateDto.getInPortEnd());
// 更新TCP和UDP监听地址
if (StrUtil.isNotBlank(tunnelUpdateDto.getTcpListenAddr())) {
existingTunnel.setTcpListenAddr(tunnelUpdateDto.getTcpListenAddr());
}
if (StrUtil.isNotBlank(tunnelUpdateDto.getUdpListenAddr())) {
existingTunnel.setUdpListenAddr(tunnelUpdateDto.getUdpListenAddr());
}
if (existingTunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD) {
existingTunnel.setOutIpSta(tunnelUpdateDto.getOutIpSta());
existingTunnel.setOutIpEnd(tunnelUpdateDto.getOutIpEnd());
@@ -400,7 +408,7 @@ public class TunnelServiceImpl extends ServiceImpl<TunnelMapper, Tunnel> impleme
// 设置入口节点信息
tunnel.setInNodeId(tunnelDto.getInNodeId());
tunnel.setInIp(inNode.getIp());
tunnel.setInIp(inNode.getServerIp());
// 设置流量计算类型
tunnel.setFlow(tunnelDto.getFlow());
@@ -415,6 +423,12 @@ public class TunnelServiceImpl extends ServiceImpl<TunnelMapper, Tunnel> impleme
tunnel.setProtocol(null);
}
// 设置TCP和UDP监听地址
tunnel.setTcpListenAddr(StrUtil.isNotBlank(tunnelDto.getTcpListenAddr()) ?
tunnelDto.getTcpListenAddr() : "0.0.0.0");
tunnel.setUdpListenAddr(StrUtil.isNotBlank(tunnelDto.getUdpListenAddr()) ?
tunnelDto.getUdpListenAddr() : "0.0.0.0");
return tunnel;
}
@@ -496,7 +510,7 @@ public class TunnelServiceImpl extends ServiceImpl<TunnelMapper, Tunnel> impleme
// 设置出口参数
tunnel.setOutNodeId(tunnelDto.getOutNodeId());
tunnel.setOutIp(outNode.getIp());
tunnel.setOutIp(outNode.getServerIp());
return R.ok();
}
@@ -651,6 +665,14 @@ public class TunnelServiceImpl extends ServiceImpl<TunnelMapper, Tunnel> impleme
TunnelListDto dto = new TunnelListDto();
dto.setId(tunnel.getId().intValue());
dto.setName(tunnel.getName());
dto.setIp(tunnel.getInIp());
dto.setInPortSta(tunnel.getInPortSta());
dto.setInPortEnd(tunnel.getInPortEnd());
dto.setOutIp(tunnel.getOutIp());
dto.setOutIpSta(tunnel.getOutIpSta());
dto.setOutIpEnd(tunnel.getOutIpEnd());
dto.setType(tunnel.getType());
dto.setProtocol(tunnel.getProtocol());
return dto;
}
@@ -573,7 +573,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
String serviceName = buildServiceName(forward.getId(), userId, userTunnel.getId());
// 删除主服务
GostUtil.DeleteService(buildNodeAddress(inNode), serviceName, inNode.getSecret());
GostUtil.DeleteService(inNode.getId(), serviceName);
// 如果是隧道转发,还需要删除链和远程服务
if (tunnel.getType() == TUNNEL_TYPE_TUNNEL_FORWARD) {
@@ -591,8 +591,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
private void deleteGostTunnelForwardServices(Tunnel tunnel, String serviceName, Node inNode) {
Node outNode = nodeService.getNodeById(tunnel.getOutNodeId());
if (outNode != null) {
GostUtil.DeleteChains(buildNodeAddress(inNode), serviceName, inNode.getSecret());
GostUtil.DeleteRemoteService(buildNodeAddress(outNode), serviceName, outNode.getSecret());
GostUtil.DeleteChains(inNode.getId(), serviceName);
GostUtil.DeleteRemoteService(outNode.getId(), serviceName);
}
}
@@ -621,15 +621,6 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
return forwardId + "_" + userId + "_" + userTunnelId;
}
/**
* 构建节点地址
*
* @param node 节点对象
* @return 节点地址字符串
*/
private String buildNodeAddress(Node node) {
return node.getIp() + ":" + node.getPort();
}
/**
* 删除用户隧道权限
@@ -700,7 +691,6 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
private UserPackageDto.UserInfoDto buildUserInfoDto(User user) {
UserPackageDto.UserInfoDto userInfo = new UserPackageDto.UserInfoDto();
userInfo.setId(user.getId());
userInfo.setName(user.getName());
userInfo.setUser(user.getUser());
userInfo.setStatus(user.getStatus());
userInfo.setFlow(user.getFlow());
@@ -368,9 +368,8 @@ public class UserTunnelServiceImpl extends ServiceImpl<UserTunnelMapper, UserTun
// 1. 先删除主服务
if (inNode != null) {
String inNodeAddress = buildNodeAddress(inNode);
try {
GostUtil.DeleteService(inNodeAddress, serviceName, inNode.getSecret());
GostUtil.DeleteService(inNode.getId(), serviceName);
} catch (Exception e) {
// 主服务删除失败,记录但继续
}
@@ -378,9 +377,8 @@ public class UserTunnelServiceImpl extends ServiceImpl<UserTunnelMapper, UserTun
// 2. 如果是隧道转发,删除远端服务
if (tunnel.getType() == 1 && outNode != null && !outNode.getId().equals(inNode != null ? inNode.getId() : null)) {
String outNodeAddress = buildNodeAddress(outNode);
try {
GostUtil.DeleteRemoteService(outNodeAddress, serviceName, outNode.getSecret());
GostUtil.DeleteRemoteService(outNode.getId(), serviceName);
} catch (Exception e) {
// 远端服务删除失败,记录但继续
}
@@ -388,9 +386,8 @@ public class UserTunnelServiceImpl extends ServiceImpl<UserTunnelMapper, UserTun
// 3. 如果是隧道转发,最后删除转发链
if (tunnel.getType() == 1 && inNode != null) {
String inNodeAddress = buildNodeAddress(inNode);
try {
GostUtil.DeleteChains(inNodeAddress, serviceName, inNode.getSecret());
GostUtil.DeleteChains(inNode.getId(), serviceName);
} catch (Exception e) {
// 转发链删除失败,记录但继续
}
@@ -431,16 +428,7 @@ public class UserTunnelServiceImpl extends ServiceImpl<UserTunnelMapper, UserTun
return forwardId + "_" + userId + "_" + userTunnelId;
}
/**
* 构建节点地址
*
* @param node 节点对象
* @return 节点地址字符串
*/
private String buildNodeAddress(Node node) {
return node.getIp() + ":" + node.getPort();
}
/**
* 检查用户隧道是否启用且有到期时间
*
@@ -507,14 +495,12 @@ public class UserTunnelServiceImpl extends ServiceImpl<UserTunnelMapper, UserTun
}
// 5. 批量更新该用户在该隧道下所有转发的限速配置(只更新入口节点)
String inNodeAddress = buildNodeAddress(inNode);
for (Forward forward : userTunnelForwards) {
String serviceName = buildServiceName(forward.getId(), Long.valueOf(userId), userTunnel.getId());
// 6. 更新入口节点的主服务限速配置(使用批量UpdateService接口)
GostUtil.UpdateService(inNodeAddress, serviceName, forward.getInPort(), speedId,
forward.getRemoteAddr(), inNode.getSecret(), tunnel.getType());
GostUtil.UpdateService(inNode.getId(), serviceName, forward.getInPort(), speedId,
forward.getRemoteAddr(), tunnel.getType(), tunnel);
}
}
}