Remove manual client ID and TLS CLI options
Some checks failed
Build Multi-Platform Binaries / build-frontend (push) Successful in 34s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 1m20s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 1m33s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 1m16s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 1m48s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 1m7s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 1m46s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 1m31s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m58s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 1m35s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Has been cancelled

This commit is contained in:
2026-03-19 19:32:57 +08:00
parent 937536e422
commit e4999abf47
14 changed files with 112 additions and 202 deletions

View File

@@ -10,7 +10,6 @@ import (
type ClientConfig struct {
Server string `yaml:"server"` // 服务器地址
Token string `yaml:"token"` // 认证 Token
ID string `yaml:"id"` // 客户端 ID
NoTLS bool `yaml:"no_tls"` // 禁用 TLS
}

View File

@@ -48,7 +48,7 @@ type Client struct {
}
// NewClient 创建客户端
func NewClient(serverAddr, token, id string) *Client {
func NewClient(serverAddr, token string) *Client {
// 默认数据目录:优先使用用户主目录,失败时回退到当前工作目录
var dataDir string
if home, err := os.UserHomeDir(); err == nil && home != "" {
@@ -71,9 +71,7 @@ func NewClient(serverAddr, token, id string) *Client {
}
// ID 优先级:命令行参数 > 机器ID
if id == "" {
id = getMachineID()
}
id := getMachineID()
// 获取主机名作为客户端名称
hostname, _ := os.Hostname()
@@ -99,7 +97,6 @@ func (c *Client) InitVersionStore() error {
return nil
}
// logf 安全地记录日志(同时输出到标准日志和日志收集器)
func (c *Client) logf(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
@@ -190,8 +187,8 @@ func (c *Client) connect() error {
// 如果服务端分配了新 ID则更新
if authResp.ClientID != "" && authResp.ClientID != c.ID {
c.ID = authResp.ClientID
c.logf("ID updated to: %s", c.ID)
conn.Close()
return fmt.Errorf("server returned unexpected client id: %s", authResp.ClientID)
}
c.logf("Authenticated as %s", c.ID)
@@ -416,15 +413,6 @@ func (c *Client) findRuleByPort(port int) *protocol.ProxyRule {
return nil
}
// handleClientRestart 处理客户端重启请求
func (c *Client) handleClientRestart(stream net.Conn, msg *protocol.Message) {
defer stream.Close()
@@ -449,8 +437,6 @@ func (c *Client) handleClientRestart(stream net.Conn, msg *protocol.Message) {
}
}
// handleUpdateDownload 处理更新下载请求
func (c *Client) handleUpdateDownload(stream net.Conn, msg *protocol.Message) {
defer stream.Close()
@@ -528,7 +514,7 @@ func (c *Client) performSelfUpdate(downloadURL string) error {
// Windows 需要特殊处理
if runtime.GOOS == "windows" {
return performWindowsClientUpdate(binaryPath, currentPath, c.ServerAddr, c.Token, c.ID)
return performWindowsClientUpdate(binaryPath, currentPath, c.ServerAddr, c.Token)
}
// 确定目标路径
@@ -579,7 +565,7 @@ func (c *Client) performSelfUpdate(downloadURL string) error {
c.logf("Update completed successfully, restarting...")
// 重启进程(从新路径启动)
restartClientProcess(targetPath, c.ServerAddr, c.Token, c.ID)
restartClientProcess(targetPath, c.ServerAddr, c.Token)
return nil
}
@@ -608,15 +594,10 @@ func (c *Client) checkUpdatePermissions(execPath string) error {
return nil
}
// performWindowsClientUpdate Windows 平台更新
func performWindowsClientUpdate(newFile, currentPath, serverAddr, token, id string) error {
func performWindowsClientUpdate(newFile, currentPath, serverAddr, token string) error {
// 创建批处理脚本
args := fmt.Sprintf(`-s "%s" -t "%s"`, serverAddr, token)
if id != "" {
args += fmt.Sprintf(` -id "%s"`, id)
}
batchScript := fmt.Sprintf(`@echo off
:: Check for admin rights, request UAC elevation if needed
net session >nul 2>&1
@@ -647,11 +628,8 @@ del "%%~f0"
}
// restartClientProcess 重启客户端进程
func restartClientProcess(path, serverAddr, token, id string) {
func restartClientProcess(path, serverAddr, token string) {
args := []string{"-s", serverAddr, "-t", token}
if id != "" {
args = append(args, "-id", id)
}
cmd := exec.Command(path, args...)
cmd.Stdout = os.Stdout
@@ -660,7 +638,6 @@ func restartClientProcess(path, serverAddr, token, id string) {
os.Exit(0)
}
// handleLogRequest 处理日志请求
func (c *Client) handleLogRequest(stream net.Conn, msg *protocol.Message) {
if c.logger == nil {
@@ -737,8 +714,6 @@ func (c *Client) handleLogStop(stream net.Conn, msg *protocol.Message) {
c.logger.Unsubscribe(req.SessionID)
}
// handleSystemStatsRequest 处理系统状态请求
func (c *Client) handleSystemStatsRequest(stream net.Conn, msg *protocol.Message) {
defer stream.Close()

View File

@@ -7,27 +7,38 @@ import (
"os"
"os/exec"
"runtime"
"sort"
"strings"
)
// getMachineID 获取机器唯一标识
// 优先级系统机器ID > MAC地址哈希
// getMachineID builds a stable fingerprint from multiple host identifiers
// and hashes the combined result into the client ID we expose externally.
func getMachineID() string {
// 尝试获取系统机器 ID
if id := getSystemMachineID(); id != "" {
return hashID(id)
}
// 备选:使用主网卡 MAC 地址
if id := getMACAddress(); id != "" {
return hashID(id)
}
// 都失败则返回空,让服务端生成
return ""
return hashID(strings.Join(collectMachineIDParts(), "|"))
}
func collectMachineIDParts() []string {
parts := []string{"os=" + runtime.GOOS, "arch=" + runtime.GOARCH}
if id := getSystemMachineID(); id != "" {
parts = append(parts, "system="+id)
}
if hostname, err := os.Hostname(); err == nil && hostname != "" {
parts = append(parts, "host="+hostname)
}
if macs := getMACAddresses(); len(macs) > 0 {
parts = append(parts, "macs="+strings.Join(macs, ","))
}
if names := getInterfaceNames(); len(names) > 0 {
parts = append(parts, "ifaces="+strings.Join(names, ","))
}
return parts
}
// getSystemMachineID 获取系统机器 ID
func getSystemMachineID() string {
switch runtime.GOOS {
case "linux":
@@ -41,20 +52,16 @@ func getSystemMachineID() string {
}
}
// getLinuxMachineID 获取 Linux 机器 ID
func getLinuxMachineID() string {
// 优先读取 /etc/machine-id
if data, err := os.ReadFile("/etc/machine-id"); err == nil {
return strings.TrimSpace(string(data))
}
// 备选 /var/lib/dbus/machine-id
if data, err := os.ReadFile("/var/lib/dbus/machine-id"); err == nil {
return strings.TrimSpace(string(data))
}
return ""
}
// getDarwinMachineID 获取 macOS 机器 ID (IOPlatformUUID)
func getDarwinMachineID() string {
cmd := exec.Command("ioreg", "-rd1", "-c", "IOPlatformExpertDevice")
output, err := cmd.Output()
@@ -62,72 +69,84 @@ func getDarwinMachineID() string {
return ""
}
// 解析 IOPlatformUUID
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.Contains(line, "IOPlatformUUID") {
parts := strings.Split(line, "=")
if len(parts) == 2 {
uuid := strings.TrimSpace(parts[1])
uuid = strings.Trim(uuid, "\"")
return uuid
}
for _, line := range strings.Split(string(output), "\n") {
if !strings.Contains(line, "IOPlatformUUID") {
continue
}
parts := strings.Split(line, "=")
if len(parts) != 2 {
continue
}
uuid := strings.TrimSpace(parts[1])
return strings.Trim(uuid, "\"")
}
return ""
}
// getWindowsMachineID 获取 Windows 机器 ID
func getWindowsMachineID() string {
cmd := exec.Command("reg", "query",
`HKLM\SOFTWARE\Microsoft\Cryptography`,
"/v", "MachineGuid")
cmd := exec.Command("reg", "query", `HKLM\SOFTWARE\Microsoft\Cryptography`, "/v", "MachineGuid")
output, err := cmd.Output()
if err != nil {
return ""
}
// 解析注册表输出
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.Contains(line, "MachineGuid") {
fields := strings.Fields(line)
if len(fields) >= 3 {
return fields[len(fields)-1]
}
for _, line := range strings.Split(string(output), "\n") {
if !strings.Contains(line, "MachineGuid") {
continue
}
fields := strings.Fields(line)
if len(fields) >= 3 {
return fields[len(fields)-1]
}
}
return ""
}
// getMACAddress 获取主网卡 MAC 地址
func getMACAddress() string {
func getMACAddresses() []string {
interfaces, err := net.Interfaces()
if err != nil {
return ""
return nil
}
macs := make([]string, 0, len(interfaces))
for _, iface := range interfaces {
// 跳过回环和无效接口
if iface.Flags&net.FlagLoopback != 0 {
continue
}
if iface.Flags&net.FlagUp == 0 {
continue
}
if len(iface.HardwareAddr) == 0 {
continue
}
// 返回第一个有效的 MAC 地址
return iface.HardwareAddr.String()
macs = append(macs, iface.HardwareAddr.String())
}
return ""
sort.Strings(macs)
return macs
}
func getInterfaceNames() []string {
interfaces, err := net.Interfaces()
if err != nil {
return nil
}
names := make([]string, 0, len(interfaces))
for _, iface := range interfaces {
if iface.Flags&net.FlagLoopback != 0 {
continue
}
names = append(names, iface.Name)
}
sort.Strings(names)
return names
}
// hashID 对 ID 进行哈希处理,生成固定长度的客户端 ID
func hashID(id string) string {
hash := sha256.Sum256([]byte(id))
// 取前 16 个字符作为客户端 ID
return hex.EncodeToString(hash[:])[:16]
}