Initial commit

This commit is contained in:
2026-06-30 15:14:37 +08:00
commit 15dab96872
311 changed files with 95639 additions and 0 deletions
+406
View File
@@ -0,0 +1,406 @@
package ctr
import (
"fmt"
"strconv"
"sync"
"git.zkcoi.com/zkcoi/meshray/core"
"git.zkcoi.com/zkcoi/meshray/core/connect"
"go.uber.org/zap"
)
// Ctr meshray-ctr 调度中心
type Ctr struct {
name string // 组网名称(用于日志)
networkID uint64 // 组网 ID(雪花算法 ID
config *CtrConfig
logger *zap.Logger
// WireGuard 管理器
wgManager *WGManager
// Core 实例(直接集成,无需 gRPC)
coreInst *core.Core
mu sync.RWMutex
}
// CtrConfig 配置
type CtrConfig struct {
// 空配置,保留结构体以备未来扩展
}
// NewCtr 创建调度中心
func NewCtr(name string, networkID uint64, config *CtrConfig, logger *zap.Logger) (*Ctr, error) {
ctr := &Ctr{
name: name,
networkID: networkID,
config: config,
logger: logger,
}
// 初始化 WireGuard 管理器
ctr.wgManager = NewWGManager(logger)
// 初始化 Core 实例(直接集成,无需 gRPC)
ctr.coreInst = core.NewCore(logger)
return ctr, nil
}
// Start 启动调度中心
func (c *Ctr) Start() error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("启动 meshray-ctr",
zap.String("name", c.name),
zap.Uint64("network_id", c.networkID))
// ✅ Watchdog 监控暂不实现(P3 阶段)
// go c.watchdog.Start()
return nil
}
// Stop 停止调度中心
func (c *Ctr) Stop() error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("停止 meshray-ctr",
zap.Uint64("network_id", c.networkID))
// 停止 Core 实例(直接调用方法)
if c.coreInst != nil {
// ✅ Close 方法已实现(会停止所有 Engine)
c.coreInst.Close()
}
// 停止 WireGuard 管理
if err := c.wgManager.Stop(); err != nil {
c.logger.Error("停止 WireGuard 管理失败", zap.Error(err))
}
return nil
}
// CreateNetwork 创建网络(根据组网模式决定行为)
// - 原生模式:仅创建 WG 设备
// - 增强模式:创建 WG 设备 + 启动 Core 实例
func (c *Ctr) CreateNetwork(networkID uint64, subnet string, listenPort int, meshMode string) error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("开始创建网络",
zap.Uint64("network_id", networkID),
zap.String("subnet", subnet),
zap.Int("listen_port", listenPort),
zap.String("mesh_mode", meshMode))
// 1. 创建 WireGuard 设备(两种模式都需要)
networkIDStr := strconv.FormatUint(networkID, 10)
if err := c.wgManager.CreateDevice(networkIDStr, subnet, listenPort); err != nil {
return fmt.Errorf("创建 WireGuard 设备失败:%w", err)
}
c.logger.Debug("WireGuard 设备创建成功",
zap.Uint64("network_id", networkID))
// 2. 仅增强模式需要创建并启动 Core 实例
if meshMode == "enhanced" {
// 直接调用 Core 实例的方法(无需 gRPC)
metrics := core.NewMetrics()
engine, err := c.coreInst.CreateEngine(networkIDStr, metrics)
if err != nil {
c.wgManager.DeleteDevice(networkIDStr) // 回滚 WG设备
c.logger.Error("创建 Engine 失败",
zap.Uint64("network_id", networkID),
zap.Error(err))
return fmt.Errorf("创建 Engine 失败:%w", err)
}
if err := engine.Start(); err != nil {
// ✅ 调用 Stop 方法停止(会清理所有资源)
engine.Stop()
c.wgManager.DeleteDevice(networkIDStr) // 回滚 WG 设备
c.logger.Error("启动 Engine 失败",
zap.Uint64("network_id", networkID),
zap.Error(err))
return fmt.Errorf("启动 Engine 失败:%w", err)
}
c.logger.Info("增强模式:Engine 实例已启动",
zap.Uint64("network_id", networkID))
} else {
c.logger.Info("原生模式:仅创建 WG 设备,不启动 Core",
zap.Uint64("network_id", networkID))
}
c.logger.Info("网络创建成功",
zap.Uint64("network_id", networkID),
zap.String("mesh_mode", meshMode))
return nil
}
// DeleteNetwork 删除网络
func (c *Ctr) DeleteNetwork(networkID uint64) error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("开始删除网络",
zap.Uint64("network_id", networkID))
// 1. Core 实例不需要显式删除(它是内存中的对象)
// 如果需要清理,可以在未来实现 Engine.Stop() 方法
networkIDStr := strconv.FormatUint(networkID, 10)
// 2. 删除 WireGuard 设备
if err := c.wgManager.DeleteDevice(networkIDStr); err != nil {
return fmt.Errorf("删除 WireGuard 设备失败:%w", err)
}
c.logger.Info("网络删除成功",
zap.Uint64("network_id", networkID))
return nil
}
// AddPeer 添加 Peer
func (c *Ctr) AddPeer(networkID uint64, publicKey, allowedIP string) error {
c.mu.RLock()
defer c.mu.RUnlock()
c.logger.Info("添加 Peer",
zap.Uint64("network_id", networkID),
zap.String("public_key", publicKey[:8]+"..."))
// 1. 添加到 WireGuard
networkIDStr := strconv.FormatUint(networkID, 10)
if err := c.wgManager.AddPeer(networkIDStr, publicKey, allowedIP); err != nil {
return fmt.Errorf("添加 Peer 失败:%w", err)
}
// 2. 通知 Core
// 如果已经在 Enhanced 模式,需要接管刚刚加入的这个 Peer
engine, err := c.coreInst.GetEngine(networkIDStr)
if err == nil && engine != nil {
// 引擎存在,说明是 enhanced 模式
// 由 Core 分配一个本地端口
localPort, err := engine.Bind(publicKey, 0)
if err != nil {
c.logger.Error("增强模式动态 AddPeer Bind 失败", zap.Error(err))
} else {
// 通知 WG 更新为本地代理 Endpoint
newEndpoint := fmt.Sprintf("127.0.0.1:%d", localPort)
if err := c.wgManager.UpdatePeerEndpoint(networkIDStr, publicKey, newEndpoint); err != nil {
c.logger.Warn("增强模式自动重写 Endpoint 失败", zap.Error(err))
engine.Unbind(publicKey)
} else {
c.logger.Info("增强模式:动态 Peer 添加并成功代理给 Core",
zap.String("public_key", publicKey[:8]+"..."),
zap.String("new_endpoint", newEndpoint))
}
}
} else {
c.logger.Debug("Core 未启动,普通模式无需代理 Peer", zap.Uint64("network_id", networkID))
}
return nil
}
// RemovePeer 移除 Peer
func (c *Ctr) RemovePeer(networkID uint64, publicKey string) error {
c.mu.RLock()
defer c.mu.RUnlock()
c.logger.Info("移除 Peer",
zap.Uint64("network_id", networkID),
zap.String("public_key", publicKey[:8]+"..."))
// 从 WireGuard 移除
networkIDStr := strconv.FormatUint(networkID, 10)
if err := c.wgManager.RemovePeer(networkIDStr, publicKey); err != nil {
return fmt.Errorf("移除 Peer 失败:%w", err)
}
// 通知 Core 卸载这台 Peer 的监听
engine, err := c.coreInst.GetEngine(networkIDStr)
if err == nil && engine != nil {
engine.Unbind(publicKey)
c.logger.Info("增强模式:Core 已解除对该 Peer 的挂载", zap.String("public_key", publicKey[:8]+"..."))
}
return nil
}
// SetSTUNTURNConfig 为指定网络设置 STUN/TURN 配置
func (c *Ctr) SetSTUNTURNConfig(networkID uint64, stunServers []string, turnServers []connect.TURNServerConfig) error {
c.mu.RLock()
defer c.mu.RUnlock()
networkIDStr := strconv.FormatUint(networkID, 10)
// 获取 Engine 实例
engine, err := c.coreInst.GetEngine(networkIDStr)
if err != nil {
c.logger.Debug("网络未启动增强模式,跳过 STUN/TURN 配置",
zap.Uint64("network_id", networkID))
return nil // 无需错误,因为原生模式不需要
}
// 更新 WebRTC 工厂的 ICE 配置
engine.SetICEConfig(connect.ICEConfig{
STUNServers: stunServers,
TURNServers: turnServers,
})
c.logger.Info("STUN/TURN 配置已设置",
zap.Uint64("network_id", networkID),
zap.Int("stun_count", len(stunServers)),
zap.Int("turn_count", len(turnServers)))
return nil
}
func (c *Ctr) GetStatus(networkID uint64) (*NetworkStatus, error) {
c.mu.RLock()
defer c.mu.RUnlock()
networkIDStr := strconv.FormatUint(networkID, 10)
status := &NetworkStatus{
NetworkID: networkIDStr,
}
// 获取 WireGuard 状态
wgStatus, err := c.wgManager.GetStatus(networkIDStr)
if err != nil {
return nil, err
}
status.WGStatus = wgStatus
// 获取 Core 状态(直接调用 Engine 的方法)
engine, err := c.coreInst.GetEngine(networkIDStr)
if err == nil && engine != nil {
coreStatus, err := engine.GetStatus()
if err == nil {
status.CoreStatus = coreStatus
}
}
return status, nil
}
// SwitchMode 切换传输模式(原生→增强)
// 仅支持 "native" → "enhanced" 单向切换
func (c *Ctr) SwitchMode(networkID uint64, mode string) error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("开始切换传输模式",
zap.Uint64("network_id", networkID),
zap.String("target_mode", mode))
// 1. 验证目标模式
if mode != "enhanced" {
return fmt.Errorf("仅支持切换到 enhanced 模式,当前请求:%s", mode)
}
networkIDStr := strconv.FormatUint(networkID, 10)
// 2. 获取当前 WG 状态(获取 Peer 数量)
wgStatus, err := c.wgManager.GetStatus(networkIDStr)
if err != nil {
return fmt.Errorf("获取 WG 状态失败:%w", err)
}
c.logger.Info("获取到 WG 状态",
zap.Int("peer_count", wgStatus.PeerCount))
// 3. 创建并启动 Core Engine(增强模式核心)
metrics := core.NewMetrics()
engine, err := c.coreInst.CreateEngine(networkIDStr, metrics)
if err != nil {
return fmt.Errorf("创建 Core Engine 失败:%w", err)
}
if err := engine.Start(); err != nil {
return fmt.Errorf("启动 Core Engine 失败:%w", err)
}
c.logger.Info("Core Engine 已启动",
zap.Uint64("network_id", networkID))
// 4. 获取 Peer 列表
peers, err := c.wgManager.ListPeers(networkIDStr)
if err != nil {
return fmt.Errorf("获取 Peer 列表失败:%w", err)
}
// 5. 修改 Peer Endpoint → 127.0.0.1:{port},并且让 Core 绑定
// 增强模式下,所有 Peer 的 Endpoint 都指向本地回环地址
for _, peer := range peers {
// 1. Core 引擎动态接管,传 0 意为让操作系统挑个未占用的随意回环端口
localPort, err := engine.Bind(peer.PublicKey, 0)
if err != nil {
c.logger.Error("Engine Bind 失败",
zap.String("public_key", peer.PublicKey[:8]+"..."),
zap.Error(err))
continue
}
newEndpoint := fmt.Sprintf("127.0.0.1:%d", localPort)
// 2. 将此端口告知 WG 更新 Endpoint
if err := c.wgManager.UpdatePeerEndpoint(networkIDStr, peer.PublicKey, newEndpoint); err != nil {
c.logger.Warn("更新 Peer Endpoint 失败",
zap.String("public_key", peer.PublicKey[:8]+"..."),
zap.Error(err))
// 如果更新失败,解绑 Core
engine.Unbind(peer.PublicKey)
continue
}
c.logger.Info("Peer Endpoint 已成功切换并接入 Core",
zap.String("public_key", peer.PublicKey[:8]+"..."),
zap.String("original_endpoint", peer.Endpoint),
zap.String("new_endpoint", newEndpoint))
}
c.logger.Info("传输模式切换成功(基础功能已实现,P3 阶段待完善)",
zap.Uint64("network_id", networkID),
zap.String("mode", mode))
return nil
}
// UpdateCoreConfig 更新 Core 配置(策略修改后同步)
// ✅ P3-1 阶段实现
func (c *Ctr) UpdateCoreConfig(networkID uint64, config interface{}) error {
c.mu.RLock()
defer c.mu.RUnlock()
c.logger.Info("更新 Core 配置",
zap.Uint64("network_id", networkID))
// ✅ P3-1 阶段 - 暂不实现
// 未来实现:
// 1. 根据策略类型解析配置
// 2. 调用 Core 的 UpdateConfig 方法
// 3. 持久化到数据库
return fmt.Errorf("UpdateCoreConfig 尚未实现(P3-1 阶段)")
}
// GetWGMode 获取系统 WG 模式
func (c *Ctr) GetWGMode() string {
return c.wgManager.GetWGMode()
}
// NetworkStatus 网络状态
type NetworkStatus struct {
NetworkID string `json:"network_id"`
WGStatus *WGStatus `json:"wg_status"`
CoreStatus *core.EngineStatus `json:"core_status,omitempty"`
}
+64
View File
@@ -0,0 +1,64 @@
package ctr
// Client Ctr 客户端接口(Service 层调用)
//
// 职责:
// 1. 定义 Service 层可调用的所有方法
// 2. 解耦 Service 和 Ctr 实现
// 3. 便于单元测试 Mock
//
// 使用示例:
//
// type NetworkService struct {
// ctrClient ctr.Client
// }
//
// func (s *NetworkService) CreateNetwork(req *model.Network) error {
// return s.ctrClient.CreateNetwork(req.ID, req.Subnet, listenPort)
// }
type Client interface {
// ========== 网络生命周期管理 ==========
// CreateNetwork 创建网络
// networkID: 组网 ID(雪花算法 uint64
// subnet: 子网段(例如:"10.0.0.0/24"
// listenPort: WireGuard 监听端口(例如:51820 + hash(networkID)
// meshMode: 组网模式("native" | "enhanced"
CreateNetwork(networkID uint64, subnet string, listenPort int, meshMode string) error
// DeleteNetwork 删除网络
DeleteNetwork(networkID uint64) error
// ========== Peer 管理 ==========
// AddPeer 添加 Peer
// publicKey: Peer 的公钥
// allowedIP: Peer 的允许 IP(例如:"10.0.0.2/32"
AddPeer(networkID uint64, publicKey, allowedIP string) error
// RemovePeer 移除 Peer
RemovePeer(networkID uint64, publicKey string) error
// ========== 状态查询 ==========
// GetStatus 获取网络状态
// 返回 WGStatus 和 CoreStatus(如果 Core 存在)
GetStatus(networkID uint64) (*NetworkStatus, error)
// ========== 模式切换(P3 阶段) ==========
// SwitchMode 切换传输模式(原生→增强)
// mode: "native" | "enhanced"
// ✅ P3-1 阶段实现
SwitchMode(networkID uint64, mode string) error
// ========== 配置同步(P3 阶段) ==========
// UpdateCoreConfig 更新 Core 配置(策略修改后同步)
// config: 新的配置对象(根据策略类型决定)
// ✅ P3-1 阶段实现
UpdateCoreConfig(networkID uint64, config interface{}) error
}
// 确保 Ctr 实现了 Client 接口
var _ Client = (*Ctr)(nil)
+581
View File
@@ -0,0 +1,581 @@
package ctr
import (
"fmt"
"net"
"os/exec"
"runtime"
"strings"
"sync"
"go.uber.org/zap"
"golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
// WGManager WireGuard 管理器(P2 阶段骨架)
type WGManager struct {
devices map[string]*WGDevice // network_id -> device
mu sync.RWMutex
logger *zap.Logger
wgMode string // "kernel" | "userspace"(当前运行模式)
}
// WGDevice WireGuard 设备
type WGDevice struct {
NetworkID string
Name string // wg0, wg1, ...
Config *DeviceConfig
Peers []PeerInfo
Running bool
// 用户态模式下使用的资源引用
tunDevice tun.Device // TUN 设备引用(用户态模式)
wgDevice *device.Device // WireGuard 设备引用(用户态模式)
}
// NewWGManager 创建 WireGuard 管理器(固定使用用户态)
func NewWGManager(logger *zap.Logger) *WGManager {
logger.Info("使用 wireguard-go 用户态模式(跨平台统一)")
return &WGManager{
devices: make(map[string]*WGDevice),
logger: logger,
wgMode: "userspace", // 固定为用户态
}
}
// CreateDevice 创建 WireGuard 设备
func (m *WGManager) CreateDevice(networkID string, subnet string, listenPort int) error {
m.mu.Lock()
defer m.mu.Unlock()
// 检查是否已存在
if _, ok := m.devices[networkID]; ok {
return fmt.Errorf("网络 %s 的设备已存在", networkID)
}
deviceName := fmt.Sprintf("wg%s", networkID)
m.logger.Info("开始创建 WireGuard 设备",
zap.String("network_id", networkID),
zap.String("device", deviceName),
zap.String("subnet", subnet),
zap.Int("listen_port", listenPort))
// 生成密钥对
privateKey, err := wgtypes.GeneratePrivateKey()
if err != nil {
return fmt.Errorf("生成私钥失败:%w", err)
}
publicKey := privateKey.PublicKey()
m.logger.Debug("生成 WG 密钥对",
zap.String("public_key", publicKey.String()))
// 使用用户态模式启动 wireguard-go 进程,并获取资源引用
tunDev, wgDev, err := m.startUserModeWGProcessWithRefs(deviceName, privateKey, listenPort)
if err != nil {
return err
}
// 4. ✅ Core 模块使用回环地址拦截,无需配置 TUN 设备 IP
// WireGuard 用户态设备会自动管理自己的网络接口
m.logger.Info("WireGuard 用户态设备已创建,使用回环地址拦截模式",
zap.String("device", deviceName))
// 5. 启动设备(带回滚)
if err := m.bringUpDevice(deviceName); err != nil {
m.cleanupDevice(deviceName) // 回滚
return fmt.Errorf("启动设备失败:%w", err)
}
// 7. 记录到内存
device := &WGDevice{
NetworkID: networkID,
Name: deviceName,
Config: &DeviceConfig{
PrivateKey: privateKey.String(),
PublicKey: publicKey.String(),
ListenPort: listenPort,
Subnet: subnet,
},
Running: true,
}
// ⚠️ 关键:保存用户态模式资源引用
device.tunDevice = tunDev
device.wgDevice = wgDev
m.logger.Debug("已保存用户态模式资源引用",
zap.String("device", deviceName))
m.devices[networkID] = device
m.logger.Info("WireGuard 设备创建成功(用户态模式)",
zap.String("network_id", networkID),
zap.String("public_key", publicKey.String()))
return nil
}
// AddPeer 添加 Peer
func (m *WGManager) AddPeer(networkID string, publicKey, allowedIP string) error {
m.mu.Lock()
defer m.mu.Unlock()
device, ok := m.devices[networkID]
if !ok {
return fmt.Errorf("网络 %s 的设备不存在", networkID)
}
m.logger.Info("添加 Peer",
zap.String("network_id", networkID),
zap.String("public_key", truncatePublicKey(publicKey)+"..."),
zap.String("allowed_ip", allowedIP))
// 1. 解析公钥
peerKey, err := wgtypes.ParseKey(publicKey)
if err != nil {
return fmt.Errorf("解析公钥失败:%w", err)
}
// 2. 解析 AllowedIP
_, ipNet, err := net.ParseCIDR(allowedIP)
if err != nil {
return fmt.Errorf("解析 AllowedIP 失败:%w", err)
}
// 3. 连接 wgctrl 并配置
client, err := wgctrl.New()
if err != nil {
return fmt.Errorf("wgctrl 连接失败:%w", err)
}
defer client.Close()
// 4. 配置 Peer
config := wgtypes.Config{
Peers: []wgtypes.PeerConfig{
{
PublicKey: peerKey,
ReplaceAllowedIPs: true,
AllowedIPs: []net.IPNet{*ipNet},
},
},
}
if err := client.ConfigureDevice(device.Name, config); err != nil {
return fmt.Errorf("配置 Peer 失败:%w", err)
}
m.logger.Info("Peer 配置成功",
zap.String("network_id", networkID),
zap.String("public_key", truncatePublicKey(publicKey)+"..."),
zap.String("allowed_ip", allowedIP))
// 5. 同时更新内存(保持向后兼容)
peer := PeerInfo{
PublicKey: publicKey,
AllowedIPs: []string{allowedIP},
}
device.Peers = append(device.Peers, peer)
return nil
}
// RemovePeer 移除 Peer
func (m *WGManager) RemovePeer(networkID string, publicKey string) error {
m.mu.Lock()
defer m.mu.Unlock()
device, ok := m.devices[networkID]
if !ok {
return fmt.Errorf("网络 %s 的设备不存在", networkID)
}
m.logger.Info("移除 Peer",
zap.String("network_id", networkID),
zap.String("public_key", truncatePublicKey(publicKey)+"..."))
// 1. 解析公钥
peerKey, err := wgtypes.ParseKey(publicKey)
if err != nil {
return fmt.Errorf("解析公钥失败:%w", err)
}
// 2. 连接 wgctrl 并移除
client, err := wgctrl.New()
if err != nil {
return fmt.Errorf("wgctrl 连接失败:%w", err)
}
defer client.Close()
// 3. 配置移除 Peer(使用 Remove: true
config := wgtypes.Config{
Peers: []wgtypes.PeerConfig{
{
PublicKey: peerKey,
Remove: true,
},
},
}
if err := client.ConfigureDevice(device.Name, config); err != nil {
return fmt.Errorf("移除 Peer 失败:%w", err)
}
m.logger.Info("Peer 移除成功",
zap.String("network_id", networkID),
zap.String("public_key", truncatePublicKey(publicKey)+"..."))
// 4. 同时从内存删除(保持向后兼容)
newPeers := []PeerInfo{}
for _, p := range device.Peers {
if p.PublicKey != publicKey {
newPeers = append(newPeers, p)
}
}
device.Peers = newPeers
return nil
}
// DeleteDevice 删除 WireGuard 设备
func (m *WGManager) DeleteDevice(networkID string) error {
m.mu.Lock()
defer m.mu.Unlock()
device, ok := m.devices[networkID]
if !ok {
return fmt.Errorf("网络 %s 的设备不存在", networkID)
}
m.logger.Info("删除 WireGuard 设备",
zap.String("network_id", networkID),
zap.String("device", device.Name))
// 1. 清理真实设备(内核态或用户态)
m.cleanupDevice(device.Name)
// 2. 从内存删除
delete(m.devices, networkID)
m.logger.Info("WireGuard 设备已删除",
zap.String("network_id", networkID))
return nil
}
// GetStatus 获取设备状态
func (m *WGManager) GetStatus(networkID string) (*WGStatus, error) {
m.mu.RLock()
defer m.mu.RUnlock()
device, ok := m.devices[networkID]
if !ok {
return nil, fmt.Errorf("网络 %s 的设备不存在", networkID)
}
status := &WGStatus{
DeviceName: device.Name,
Running: device.Running,
PeerCount: len(device.Peers),
Subnet: device.Config.Subnet,
}
return status, nil
}
// GetWGMode 获取当前 WG 模式
func (m *WGManager) GetWGMode() string {
m.mu.RLock()
defer m.mu.RUnlock()
return m.wgMode
}
// Stop 停止管理器并释放所有资源
func (m *WGManager) Stop() error {
m.mu.Lock()
defer m.mu.Unlock()
m.logger.Info("正在停止 WireGuard 管理器...")
// 关闭所有设备
for networkID, device := range m.devices {
m.logger.Info("正在关闭设备",
zap.String("network_id", networkID),
zap.String("device_name", device.Name))
// 如果是用户态模式,关闭相关资源
if device.wgDevice != nil {
m.logger.Debug("关闭用户态 WireGuard 设备",
zap.String("device", device.Name))
device.wgDevice.Close()
}
if device.tunDevice != nil {
m.logger.Debug("关闭 TUN 设备",
zap.String("device", device.Name))
device.tunDevice.Close()
}
// 清理内核态设备(忽略返回值)
m.cleanupDevice(device.Name)
delete(m.devices, networkID)
}
m.logger.Info("WireGuard 管理器已停止")
return nil
}
// WGDevice WireGuard 设备(结构已在上面定义)
// DeviceConfig 设备配置
type DeviceConfig struct {
PrivateKey string
PublicKey string
ListenPort int
Subnet string
}
// PeerInfo Peer 信息
type PeerInfo struct {
PublicKey string
Endpoint string
AllowedIPs []string
}
// WGStatus WireGuard 状态
type WGStatus struct {
DeviceName string `json:"device_name"`
Running bool `json:"running"`
PeerCount int `json:"peer_count"`
Subnet string `json:"subnet"`
}
// ListPeers 获取设备下所有 Peer 信息
func (m *WGManager) ListPeers(networkID string) ([]PeerInfo, error) {
m.mu.RLock()
defer m.mu.RUnlock()
device, ok := m.devices[networkID]
if !ok {
return nil, fmt.Errorf("网络 %s 的设备不存在", networkID)
}
return device.Peers, nil
}
// UpdatePeerEndpoint 更新 Peer 的 Endpoint
func (m *WGManager) UpdatePeerEndpoint(networkID string, publicKey string, newEndpoint string) error {
m.mu.Lock()
defer m.mu.Unlock()
device, ok := m.devices[networkID]
if !ok {
return fmt.Errorf("网络 %s 的设备不存在", networkID)
}
m.logger.Info("更新 Peer Endpoint",
zap.String("network_id", networkID),
zap.String("public_key", truncatePublicKey(publicKey)+"..."),
zap.String("new_endpoint", newEndpoint))
// 解析公钥
peerKey, err := wgtypes.ParseKey(publicKey)
if err != nil {
return fmt.Errorf("解析公钥失败:%w", err)
}
// 解析 Endpoint 地址
var udpAddr *net.UDPAddr
if newEndpoint != "" {
addr, err := net.ResolveUDPAddr("udp", newEndpoint)
if err != nil {
return fmt.Errorf("解析 Endpoint 地址 %s 失败:%w", newEndpoint, err)
}
udpAddr = addr
}
// 连接 wgctrl 并配置
client, err := wgctrl.New()
if err != nil {
return fmt.Errorf("wgctrl 连接失败:%w", err)
}
defer client.Close()
// 配置更新 Peer
config := wgtypes.Config{
Peers: []wgtypes.PeerConfig{
{
PublicKey: peerKey,
UpdateOnly: true,
Endpoint: udpAddr,
},
},
}
if err := client.ConfigureDevice(device.Name, config); err != nil {
return fmt.Errorf("更新 Peer 失败:%w", err)
}
// 同时更新内存
for i, p := range device.Peers {
if p.PublicKey == publicKey {
device.Peers[i].Endpoint = newEndpoint
break
}
}
return nil
}
// startUserModeWGProcess 用户态模式启动 wireguard-go(保存资源引用)
func (m *WGManager) startUserModeWGProcess(deviceName string, privateKey wgtypes.Key, listenPort int) error {
tunDev, wgDev, err := m.startUserModeWGProcessWithRefs(deviceName, privateKey, listenPort)
if err != nil {
return err
}
// 兼容旧接口,忽略返回值
_ = tunDev
_ = wgDev
return nil
}
// startUserModeWGProcessWithRefs 用户态模式启动 wireguard-go,返回资源引用
func (m *WGManager) startUserModeWGProcessWithRefs(deviceName string, privateKey wgtypes.Key, listenPort int) (tun.Device, *device.Device, error) {
m.logger.Info("使用用户态模式启动 WireGuard",
zap.String("device", deviceName),
zap.Int("port", listenPort))
// 1. 创建 TUN 设备并保存引用
tunDevice, err := tun.CreateTUN(deviceName, 1420)
if err != nil {
return nil, nil, fmt.Errorf("创建 TUN 设备失败:%w", err)
}
// 2. 创建 UDP bind
bind := conn.NewDefaultBind()
// 3. 创建 WireGuard device 并保存引用
logger := &device.Logger{
Verbosef: func(format string, args ...interface{}) {
m.logger.Debug(fmt.Sprintf(format, args...))
},
Errorf: func(format string, args ...interface{}) {
m.logger.Error(fmt.Sprintf(format, args...))
},
}
wgDevice := device.NewDevice(tunDevice, bind, logger)
// 4. 配置设备
config := fmt.Sprintf("private_key=%s\nlisten_port=%d\n",
privateKey.String(), listenPort)
if err := wgDevice.IpcSet(config); err != nil {
wgDevice.Close()
return nil, nil, fmt.Errorf("配置 WireGuard 设备失败:%w", err)
}
// 5. 启动设备
if err := wgDevice.Up(); err != nil {
wgDevice.Close()
return nil, nil, fmt.Errorf("启动 WireGuard 设备失败:%w", err)
}
m.logger.Info("用户态 WireGuard 启动成功",
zap.String("device", deviceName),
zap.Int("port", listenPort))
// 6. 返回资源引用
return tunDevice, wgDevice, nil
}
// truncatePublicKey 截断公钥用于日志显示(避免数组越界)
func truncatePublicKey(publicKey string) string {
if len(publicKey) <= 8 {
return publicKey
}
return publicKey[:8]
}
// bringUpDevice 启动设备(跨平台实现)
func (m *WGManager) bringUpDevice(deviceName string) error {
m.logger.Info("启动设备",
zap.String("device", deviceName))
var cmd *exec.Cmd
var output []byte
var err error
switch runtime.GOOS {
case "linux":
// Linux: ip link set up device
cmd = exec.Command("ip", "link", "set", "up", deviceName)
output, err = cmd.CombinedOutput()
case "windows":
// Windows: 用户态模式下 wireguard-go 会自动管理设备状态
// 这里不需要额外操作
m.logger.Debug("Windows 平台用户态模式无需手动启动设备")
return nil
case "darwin":
// macOS: ifconfig device up
cmd = exec.Command("ifconfig", deviceName, "up")
output, err = cmd.CombinedOutput()
default:
return fmt.Errorf("不支持的操作系统:%s", runtime.GOOS)
}
if err != nil {
return fmt.Errorf("启动设备失败 (%s): %w", string(output), err)
}
m.logger.Info("设备已启动",
zap.String("device", deviceName))
return nil
}
// cleanupDevice 清理残留设备(回滚用,跨平台实现)
func (m *WGManager) cleanupDevice(deviceName string) {
m.logger.Warn("清理残留设备",
zap.String("device", deviceName))
var cmd *exec.Cmd
var output []byte
switch runtime.GOOS {
case "linux":
// Linux: ip link delete device
cmd = exec.Command("ip", "link", "delete", deviceName)
output, _ = cmd.CombinedOutput()
case "windows":
// Windows: 无法通过命令行直接删除,需要用户手动操作
m.logger.Warn("Windows 平台需要通过 WireGuard 客户端删除设备",
zap.String("device", deviceName))
return
case "darwin":
// macOS: ifconfig device down delete
cmd = exec.Command("ifconfig", deviceName, "down")
_, _ = cmd.CombinedOutput()
// macOS 可能需要额外步骤,这里简化处理
default:
m.logger.Warn("不支持的操作系统,跳过清理",
zap.String("os", runtime.GOOS))
return
}
// 检查是否是"设备不存在"错误
if strings.Contains(string(output), "does not exist") ||
strings.Contains(string(output), "cannot find device") {
m.logger.Debug("设备不存在,无需清理",
zap.String("device", deviceName))
return
}
m.logger.Debug("设备清理完成",
zap.String("device", deviceName))
}