Files
zonat/cmd/node/config.go
T
4566704 4dad7fbbbe 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+范围即可
2026-09-21 18:28:26 +08:00

77 lines
2.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 节点配置文件:`-config node.ini` 启用;显式命令行 flag 优先于配置项,配置项优先于内置默认。
// 零依赖 ini:[节] 下 key = value,`#`/`;` 注释行忽略,等号两侧空白忽略。
package main
import (
"bufio"
"errors"
"os"
"strconv"
"strings"
"time"
)
// nodeConfig 配置文件映射(零值表示未配置,由调用方回退 flag/默认值)
type nodeConfig struct {
Addr string // [server] Addr 桥接监听地址
TunnelBind string // [server] TunnelBind 隧道监听绑定地址
JwtSecret string // [server] JwtSecret agent 登录 JWT 校验密钥
SweepSeconds int // [server] SweepSeconds TTL 清扫间隔(秒)
PortRange string // [tunnel] PortRange 隧道监听端口范围(如 20000-21000)
}
// loadConfigFile 解析 ini 文件;文件不存在返回错误(-config 显式指定了就应当存在)。
func loadConfigFile(path string) (*nodeConfig, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
cfg := &nodeConfig{}
section := ""
sc := bufio.NewScanner(f)
lineNo := 0
for sc.Scan() {
lineNo++
line := strings.TrimSpace(sc.Text())
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
continue
}
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
section = strings.ToLower(strings.TrimSpace(line[1 : len(line)-1]))
continue
}
key, value, ok := strings.Cut(line, "=")
if !ok {
continue // 容错:无等号的行忽略
}
key = strings.ToLower(strings.TrimSpace(key))
value = strings.TrimSpace(value)
switch section + "." + key {
case "server.addr":
cfg.Addr = value
case "server.tunnelbind":
cfg.TunnelBind = value
case "server.jwtsecret":
cfg.JwtSecret = value
case "server.sweepseconds":
cfg.SweepSeconds, err = strconv.Atoi(value)
if err != nil || cfg.SweepSeconds <= 0 {
return nil, errors.New("server.sweepseconds 需为正整数, 行 " + strconv.Itoa(lineNo))
}
case "tunnel.portrange":
cfg.PortRange = value
}
}
return cfg, sc.Err()
}
// sweepDuration 秒数转 Duration;0 表示未配置
func (c *nodeConfig) sweepDuration() time.Duration {
if c.SweepSeconds <= 0 {
return 0
}
return time.Duration(c.SweepSeconds) * time.Second
}