feat(node): 配置文件启动与隧道端口范围——云主机防火墙可按范围放行
改了什么: - cmd/node/config.go: 零依赖 ini 配置加载([server] Addr/TunnelBind/JwtSecret/SweepSeconds + [tunnel] PortRange); -config node.ini 启用 - main.go: -config 与 -port-range flag; 配置来源优先级 显式 flag > 配置文件(非零项) > 内置默认(flag.Visit 判显式) - internal/node/portrange.go: PortRange 解析(20000-21000/单端口/容错) + listen(随机起点顺延探测, 占用即生效避免 TOCTOU) - node.go: TunnelPortRange 字段; listenTunnel 统一隧道建听——端口 0 且配置范围时范围内取空闲端口, 否则原路径(指定端口直监听/系统随机) - Start 日志打出端口范围; portrange_test.go 覆盖解析与占满/释放取端口 为什么: agent 注册隧道从不指定端口(ListenPort=0), 节点 net.Listen 落系统随机高位段, 云主机防火墙无法预开; 配置范围后临时/永久隧道都落在固定段内, 防火墙放行 5212+范围即可
This commit is contained in:
+21
-4
@@ -24,9 +24,10 @@ const loginTimeout = 10 * time.Second
|
||||
|
||||
// Node 穿透节点
|
||||
type Node struct {
|
||||
JwtSecret string // agent 登录 JWT 校验密钥(HS256 系)
|
||||
BindTunnel string // 隧道监听绑定地址(默认 0.0.0.0)
|
||||
SweepInterval time.Duration // TTL 清扫间隔(默认 30s)
|
||||
JwtSecret string // agent 登录 JWT 校验密钥(HS256 系)
|
||||
BindTunnel string // 隧道监听绑定地址(默认 0.0.0.0)
|
||||
SweepInterval time.Duration // TTL 清扫间隔(默认 30s)
|
||||
TunnelPortRange PortRange // 隧道监听端口范围(未配置时 ListenPort=0 走系统随机分配)
|
||||
|
||||
listener net.Listener
|
||||
|
||||
@@ -54,6 +55,9 @@ func (n *Node) Start(addr string) error {
|
||||
}
|
||||
n.listener = l
|
||||
slog.Info("节点 桥接监听", "addr", l.Addr().String())
|
||||
if n.TunnelPortRange.Valid() {
|
||||
slog.Info("节点 隧道端口范围", "range", n.TunnelPortRange.String())
|
||||
}
|
||||
go n.acceptLoop()
|
||||
go n.sweepLoop()
|
||||
return nil
|
||||
@@ -236,7 +240,7 @@ func (n *Node) registerTunnel(s *Session, t agent.Tunnel) (agent.Tunnel, error)
|
||||
|
||||
ts := &TunnelServer{tunnel: t, session: s}
|
||||
ts.touch()
|
||||
l, err := net.Listen("tcp", net.JoinHostPort(n.BindTunnel, strconv.Itoa(t.ListenPort)))
|
||||
l, err := n.listenTunnel(t.ListenPort)
|
||||
if err != nil {
|
||||
return t, err
|
||||
}
|
||||
@@ -251,6 +255,19 @@ func (n *Node) registerTunnel(s *Session, t agent.Tunnel) (agent.Tunnel, error)
|
||||
return ts.tunnel, nil
|
||||
}
|
||||
|
||||
// listenTunnel 建立隧道公网监听:指定端口直接监听;端口 0 时若配置了范围则在范围内取空闲端口,
|
||||
// 未配置范围回退系统随机分配。
|
||||
func (n *Node) listenTunnel(listenPort int) (net.Listener, error) {
|
||||
if listenPort == 0 && n.TunnelPortRange.Valid() {
|
||||
l, err := n.TunnelPortRange.listen(n.BindTunnel)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("分配隧道端口失败: %w", err)
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
return net.Listen("tcp", net.JoinHostPort(n.BindTunnel, strconv.Itoa(listenPort)))
|
||||
}
|
||||
|
||||
// unregisterTunnel 删除隧道(关闭公网监听)
|
||||
func (n *Node) unregisterTunnel(id string) bool {
|
||||
n.mu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user