From bfdaa47ea546dd266509584df7cfe2defa743fac Mon Sep 17 00:00:00 2001 From: root Date: Tue, 3 Feb 2026 09:28:11 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9A=A7=E9=81=93=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=96=B0=E5=A2=9E=E5=85=A5=E5=8F=A3=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=90=8E=E8=BD=AC=E5=8F=91=E8=A7=84=E5=88=99=E4=B8=8D=E7=94=9F?= =?UTF-8?q?=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98=20(#9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当编辑隧道添加新入口节点时,现有转发规则的ForwardPort和GOST服务未同步更新, 导致新入口节点的端口实际不可用。 修复方案:在updateTunnel成功更新节点后,同步更新所有使用该隧道的转发规则: - 对移除的入口节点:删除ForwardPort记录和GOST服务 - 对新增的入口节点:分配端口、创建ForwardPort记录和GOST服务 --- .../admin/service/impl/TunnelServiceImpl.java | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/springboot-backend/src/main/java/com/admin/service/impl/TunnelServiceImpl.java b/springboot-backend/src/main/java/com/admin/service/impl/TunnelServiceImpl.java index 07fd3cd..9c242ea 100644 --- a/springboot-backend/src/main/java/com/admin/service/impl/TunnelServiceImpl.java +++ b/springboot-backend/src/main/java/com/admin/service/impl/TunnelServiceImpl.java @@ -430,6 +430,15 @@ public class TunnelServiceImpl extends ServiceImpl impleme if (hasNodeChanges && tunnelUpdateDto.getInNodeId() != null) { List backupChains = deepCopyChainTunnels(oldChainTunnels); + Set oldEntryNodeIds = oldChainTunnels.stream() + .filter(ct -> ct.getChainType() != null && ct.getChainType() == 1) + .map(ChainTunnel::getNodeId) + .collect(Collectors.toSet()); + + Set newEntryNodeIds = tunnelUpdateDto.getInNodeId().stream() + .map(ChainTunnel::getNodeId) + .collect(Collectors.toSet()); + List nodeIds = new ArrayList<>(); Map nodes = new HashMap<>(); @@ -511,6 +520,8 @@ public class TunnelServiceImpl extends ServiceImpl impleme chainTunnelService.saveBatch(newChainTunnels); + syncForwardsForEntryNodeChanges(existingTunnel.getId(), oldEntryNodeIds, newEntryNodeIds); + } catch (Exception e) { chainTunnelService.saveBatch(backupChains); rebuildGostConfig(backupChains, existingTunnel); @@ -1153,5 +1164,148 @@ public class TunnelServiceImpl extends ServiceImpl impleme } } + private void syncForwardsForEntryNodeChanges(Long tunnelId, Set oldEntryNodeIds, Set newEntryNodeIds) { + Set addedNodeIds = new HashSet<>(newEntryNodeIds); + addedNodeIds.removeAll(oldEntryNodeIds); + + Set removedNodeIds = new HashSet<>(oldEntryNodeIds); + removedNodeIds.removeAll(newEntryNodeIds); + + if (addedNodeIds.isEmpty() && removedNodeIds.isEmpty()) { + return; + } + + List forwards = forwardService.list( + new QueryWrapper().eq("tunnel_id", tunnelId.intValue()) + ); + + if (forwards.isEmpty()) { + return; + } + + Tunnel tunnel = this.getById(tunnelId); + if (tunnel == null) { + return; + } + + for (Forward forward : forwards) { + if (forward.getStatus() != 1) { + continue; + } + + UserTunnel userTunnel = userTunnelService.getOne( + new QueryWrapper() + .eq("user_id", forward.getUserId()) + .eq("tunnel_id", tunnelId.intValue()) + ); + + for (Long removedNodeId : removedNodeIds) { + ForwardPort forwardPort = forwardPortService.getOne( + new QueryWrapper() + .eq("forward_id", forward.getId()) + .eq("node_id", removedNodeId) + ); + + if (forwardPort != null) { + String serviceName = buildForwardServiceName(forward.getId(), forward.getUserId(), userTunnel); + JSONArray services = new JSONArray(); + services.add(serviceName + "_tcp"); + services.add(serviceName + "_udp"); + GostUtil.DeleteService(removedNodeId, services); + + forwardPortService.removeById(forwardPort.getId()); + } + } + + for (Long addedNodeId : addedNodeIds) { + ForwardPort existingPort = forwardPortService.getOne( + new QueryWrapper() + .eq("forward_id", forward.getId()) + .eq("node_id", addedNodeId) + ); + + if (existingPort != null) { + continue; + } + + List existingPorts = forwardPortService.list( + new QueryWrapper().eq("forward_id", forward.getId()) + ); + + Integer targetPort = null; + if (!existingPorts.isEmpty()) { + targetPort = existingPorts.get(0).getPort(); + } + + Integer allocatedPort = allocatePortForNode(addedNodeId, targetPort, forward.getId()); + if (allocatedPort == null) { + System.err.println("Failed to allocate port on node " + addedNodeId + " for forward " + forward.getId()); + continue; + } + + ForwardPort newForwardPort = new ForwardPort(); + newForwardPort.setForwardId(forward.getId()); + newForwardPort.setNodeId(addedNodeId); + newForwardPort.setPort(allocatedPort); + forwardPortService.save(newForwardPort); + + Node node = nodeService.getById(addedNodeId); + if (node != null) { + String serviceName = buildForwardServiceName(forward.getId(), forward.getUserId(), userTunnel); + Integer limiter = (userTunnel != null && userTunnel.getSpeedId() != null) ? userTunnel.getSpeedId() : null; + GostUtil.AddAndUpdateService(serviceName, limiter, node, forward, newForwardPort, tunnel, "AddService"); + } + } + } + } + + private Integer allocatePortForNode(Long nodeId, Integer preferredPort, Long forwardId) { + Node node = nodeService.getById(nodeId); + if (node == null || node.getPort() == null) { + return null; + } + + Set usedPorts = new HashSet<>(); + + List chainTunnels = chainTunnelService.list( + new QueryWrapper().eq("node_id", nodeId) + ); + for (ChainTunnel ct : chainTunnels) { + if (ct.getPort() != null) { + usedPorts.add(ct.getPort()); + } + } + + List forwardPorts = forwardPortService.list( + new QueryWrapper() + .eq("node_id", nodeId) + .ne("forward_id", forwardId) + ); + for (ForwardPort fp : forwardPorts) { + if (fp.getPort() != null) { + usedPorts.add(fp.getPort()); + } + } + + List availablePorts = parsePorts(node.getPort()); + + if (preferredPort != null && availablePorts.contains(preferredPort) && !usedPorts.contains(preferredPort)) { + return preferredPort; + } + + for (Integer port : availablePorts) { + if (!usedPorts.contains(port)) { + return port; + } + } + + return null; + } + + private String buildForwardServiceName(Long forwardId, Integer userId, UserTunnel userTunnel) { + int userTunnelId = (userTunnel != null) ? userTunnel.getId() : 0; + return forwardId + "_" + userId + "_" + userTunnelId; + } + }