// zonat 节点入口:TCP 桥接监听 + 隧道注册表 + 纯 TCP 隧道监听。 // 无管理 API、无数据库;隧道由 agent 经桥接控制流注册。 // agent 登录用 JWT 校验(HS256);token 正式部署由 cloud 签发, // 手工/测试场景可用 -print-token 现场签发。 // // 配置来源优先级:显式命令行 flag > -config 指定的配置文件 > 内置默认。 package main import ( "flag" "fmt" "log/slog" "os" "os/signal" "syscall" "time" "git.zeroonesoft.cn/golib/zonat/internal/node" ) func main() { var ( config = flag.String("config", "", "配置文件路径(node.ini); 显式 flag 可覆盖配置项") addr = flag.String("addr", ":5212", "桥接监听地址") tunnelBind = flag.String("tunnel-bind", "0.0.0.0", "隧道监听绑定地址") jwtSecret = flag.String("jwt-secret", "", "agent 登录 JWT 校验密钥(HS256)") sweep = flag.Duration("sweep", 30*time.Second, "TTL 清扫间隔") portRange = flag.String("port-range", "", "隧道监听端口范围(如 20000-21000); 未指定端口的隧道在范围内取空闲端口, 空=系统随机") // 便捷签发:node -jwt-secret s3cret -print-token -agent a1 -ttl 24h printToken = flag.Bool("print-token", false, "用 -jwt-secret 签发一张 agent 登录 token 后退出") tokenAgent = flag.String("agent", "", "print-token 时写入 agentId claim") tokenTTL = flag.Duration("ttl", 24*time.Hour, "print-token 签发的有效期") ) flag.Parse() if *printToken { if *jwtSecret == "" || *tokenTTL <= 0 { slog.Error("print-token 需要 -jwt-secret 与正的 -ttl") os.Exit(1) } tok, err := node.SignToken(*jwtSecret, *tokenAgent, *tokenTTL) if err != nil { slog.Error("签发失败", "err", err.Error()) os.Exit(1) } fmt.Println(tok) return } // 终值 = 内置默认 ← 配置文件(非零项) ← 显式 flag explicit := map[string]bool{} flag.Visit(func(f *flag.Flag) { explicit[f.Name] = true }) var ( finalAddr = *addr finalTunnelBind = *tunnelBind finalSecret = *jwtSecret finalSweep = *sweep finalRange node.PortRange ) if *config != "" { cfg, err := loadConfigFile(*config) if err != nil { slog.Error("读取配置文件失败", "path", *config, "err", err.Error()) os.Exit(1) } if cfg.Addr != "" { finalAddr = cfg.Addr } if cfg.TunnelBind != "" { finalTunnelBind = cfg.TunnelBind } if cfg.JwtSecret != "" { finalSecret = cfg.JwtSecret } if d := cfg.sweepDuration(); d > 0 { finalSweep = d } if cfg.PortRange != "" { r, err := node.ParsePortRange(cfg.PortRange) if err != nil { slog.Error("配置文件端口范围无效", "err", err.Error()) os.Exit(1) } finalRange = r } } if explicit["addr"] { finalAddr = *addr } if explicit["tunnel-bind"] { finalTunnelBind = *tunnelBind } if explicit["jwt-secret"] { finalSecret = *jwtSecret } if explicit["sweep"] { finalSweep = *sweep } if explicit["port-range"] { r, err := node.ParsePortRange(*portRange) if err != nil { slog.Error("端口范围无效", "err", err.Error()) os.Exit(1) } finalRange = r } if finalSecret == "" { slog.Error("缺少 jwt-secret(agent 登录 JWT 校验密钥; -jwt-secret 或配置文件 server.jwt-secret)") os.Exit(1) } n := node.New() n.JwtSecret = finalSecret n.BindTunnel = finalTunnelBind n.SweepInterval = finalSweep n.TunnelPortRange = finalRange if err := n.Start(finalAddr); err != nil { slog.Error("节点启动失败", "err", err.Error()) os.Exit(1) } quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt, syscall.SIGTERM) <-quit n.Stop() }