// protocol.go 定义 zonat 桥接协议的命令字与消息结构。 // 命令字取值与 zonat 桥接命令字对齐(CmdLogin 同 CmdTunnelLogin、CmdTarget 同 CmdTunnelTarget), // 帧格式不变,便于将来与 zonat 互通或平滑迁移。 package agent import ( "fmt" "time" "github.com/xtaci/smux" ) // 帧命令字 const ( // CmdLogin 登录(请求与应答共用同一命令字,同 zonat) CmdLogin byte = 0 // CmdPing 心跳(请求与应答共用同一命令字,同 zonat CmdTunnelPing) CmdPing byte = 3 // CmdTarget 数据流首帧:节点告知 agent 本条公网连接的目标(同 zonat CmdTunnelTarget) CmdTarget byte = 4 // CmdRegisterTunnel agent→节点 注册隧道(应答共用同一命令字,Ret.Port 为分配端口) CmdRegisterTunnel byte = 10 // CmdUnregisterTunnel agent→节点 注销隧道(应答共用同一命令字) CmdUnregisterTunnel byte = 11 // CmdTunnelClosed 节点→agent 推送:隧道已被节点删除(TTL 过期、会话顶替等) CmdTunnelClosed byte = 12 ) // Version 协议/程序版本 const Version = "0.1.0" // Login 登录请求 type Login struct { AgentId string `json:"agentId"` Token string `json:"token"` // JWT,由签发方(如 cloud)生成,节点用密钥校验 Version string `json:"version"` } // Ret 通用应答(zonat JsonRet 的裁剪版) type Ret struct { Code int `json:"code"` Msg string `json:"msg"` Port int `json:"port,omitempty"` // 注册隧道应答:节点分配的监听端口 } // Tunnel 一条隧道的定义(zonat models.Tunnel 的裁剪版)。 // NodeAddr/Token 是 zonat 的多节点扩展:每条隧道自带目标节点与登录令牌, // 由独立连接登录注册,因此一个 agent 的多条隧道可分布在多个不同节点。 // 这两个字段只用于 agent→节点的登录,节点侧不使用也不回传(CmdTarget 不携带)。 type Tunnel struct { Id string `json:"id"` NodeAddr string `json:"nodeAddr,omitempty"` // 该隧道登录的节点桥接地址 Token string `json:"token,omitempty"` // 登录令牌(JWT),仅登录帧使用 ListenPort int `json:"listenPort"` // 0=节点随机分配 TargetIp string `json:"targetIp"` TargetPort int `json:"targetPort"` TTLSec int `json:"ttlSec"` // 空闲自动删除秒数,0=永久 } // TargetAddr 隧道在内网的目标地址 func (t Tunnel) TargetAddr() string { return fmt.Sprintf("%s:%d", t.TargetIp, t.TargetPort) } // SmuxConfig smux 会话参数,与 zonat 保持一致 func SmuxConfig() *smux.Config { return &smux.Config{ Version: 2, KeepAliveInterval: 10 * time.Second, KeepAliveTimeout: 30 * time.Second, MaxFrameSize: 32768, MaxReceiveBuffer: 4194304, MaxStreamBuffer: 65536, } }