冲突解决 internal/node/node.go: Node 结构体同时保留两侧新增字段
- 远端: HandshakeTimeout (agent 拨号应答 5s 上限, BUG 修复)
- 本地: TunnelPortRange (隧道端口范围, 配置文件功能)
- cmd/node 配置加载器经 node.New() 构造, HandshakeTimeout 默认值不受影响
- 验证: go build/vet 通过, go test ./... 全绿(e2e 3.97s)
This commit is contained in:
2026-09-25 12:39:08 +08:00
6 changed files with 366 additions and 19 deletions
+11 -9
View File
@@ -24,26 +24,28 @@ 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)
TunnelPortRange PortRange // 隧道监听端口范围(未配置时 ListenPort=0 走系统随机分配)
JwtSecret string // agent 登录 JWT 校验密钥(HS256 系)
BindTunnel string // 隧道监听绑定地址(默认 0.0.0.0)
SweepInterval time.Duration // TTL 清扫间隔(默认 30s)
HandshakeTimeout time.Duration // 单条观看连接的 agent 拨号应答上限(默认 5s; 超时立即断开观看端, 数据阶段不受限)
TunnelPortRange PortRange // 隧道监听端口范围(未配置时 ListenPort=0 走系统随机分配)
listener net.Listener
mu sync.Mutex
stopped bool
sessions map[*Session]struct{} // 该节点上的全部 agent 会话(一个 agent 多隧道=多会话)
sessions map[*Session]struct{} // 该节点上的全部 agent 会话(一个 agent 多隧道=多会话)
tunnels map[string]*TunnelServer // tunnelId -> 隧道
}
// New 创建节点
func New() *Node {
return &Node{
BindTunnel: "0.0.0.0",
SweepInterval: 30 * time.Second,
sessions: make(map[*Session]struct{}),
tunnels: make(map[string]*TunnelServer),
BindTunnel: "0.0.0.0",
SweepInterval: 30 * time.Second,
HandshakeTimeout: 5 * time.Second,
sessions: make(map[*Session]struct{}),
tunnels: make(map[string]*TunnelServer),
}
}
+7
View File
@@ -58,6 +58,11 @@ func (t *TunnelServer) handleConn(conn net.Conn) {
}
defer stream.Close()
// 转发握手(告知目标+等 agent 回执)限时: agent 会话半死/目标拨号不回时
// 观看端不再无限挂起, 到点立即断开让观看端快速失败可重试
if hs := t.session.node.HandshakeTimeout; hs > 0 {
_ = stream.SetDeadline(time.Now().Add(hs))
}
tf := agent.NewFrame(agent.FrameVersion, agent.CmdTarget, 0)
if err := tf.Marshal(t.tunnel); err != nil {
return
@@ -67,8 +72,10 @@ func (t *TunnelServer) handleConn(conn net.Conn) {
}
rf, err := agent.ReadFrame(stream)
if err != nil {
slog.Warn("节点 agent拨号应答失败", "id", t.tunnel.Id, "err", err.Error())
return
}
_ = stream.SetDeadline(time.Time{}) // 数据阶段不受握手超时约束
ret := agent.Ret{}
if err := rf.Unmarshal(&ret); err != nil || ret.Code != 0 {
slog.Warn("节点 agent拨号失败", "id", t.tunnel.Id, "msg", ret.Msg)