rebuild: split core into separate repo; move wg-go integration to internal/ctr/corebind
- go.mod: require git.zkcoi.com/zkcoi/meshray/core, replace => ../Meshray - internal/ctr/corebind: EnhancedBind + registry + adapter (wg-go integration isolated) - cmd/mr-wg migrated from old core/cmd/meshray-core - core/ removed; CHANGELOG updated; fix checkdb vet warning
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
// Config 是 meshray-core 独立运行(类 frp 风格)的配置文件结构。
|
||||
// 支持 TOML(默认,类 frp)与 JSON 两种格式,按文件扩展名自动选择解码器。
|
||||
//
|
||||
// TOML 示例:
|
||||
//
|
||||
// network_id = "net1"
|
||||
// listen_port = 51820
|
||||
// mtu = 1420
|
||||
// private_key = "" # 留空则自动生成并写入 private_key_file
|
||||
// private_key_file = "key.txt"
|
||||
// interface = "10.0.0.1/24" # 本机隧道 IP
|
||||
// mode = "enhanced" # enhanced=经 9 层传输接管;native=裸 WG 直连
|
||||
//
|
||||
// [[peers]]
|
||||
// public_key = "<对端公钥 base64>"
|
||||
// endpoint = "203.0.113.2:51820" # 增强模式经 9 层拨号对端;留空则仅作为接收方
|
||||
// allowed_ips = ["10.0.0.2/32"]
|
||||
//
|
||||
// [ice]
|
||||
// stun = ["stun:stun.l.google.com:19302"]
|
||||
// turn = ["turn:your.turn:3478"]
|
||||
//
|
||||
// # 传输层级策略:auto=9 层自动降级(默认);manual=仅用下方 layers 指定的层
|
||||
// layer_strategy = "auto"
|
||||
// layers = ["Direct-UDP"] # 仅 manual 生效;单元素=强制固定层;多元素=自定义降级顺序
|
||||
type Config struct {
|
||||
NetworkID string `json:"network_id" toml:"network_id"`
|
||||
ListenPort int `json:"listen_port" toml:"listen_port"`
|
||||
MTU int `json:"mtu" toml:"mtu"`
|
||||
PrivateKey string `json:"private_key" toml:"private_key"`
|
||||
PrivateKeyFile string `json:"private_key_file" toml:"private_key_file"`
|
||||
InterfaceIP string `json:"interface" toml:"interface"`
|
||||
Mode string `json:"mode" toml:"mode"`
|
||||
Peers []PeerConf `json:"peers" toml:"peers"`
|
||||
ICE ICEConf `json:"ice" toml:"ice"`
|
||||
|
||||
// LayerStrategy 传输层级策略:
|
||||
// "auto"(默认)= 按 DefaultLayerOrder 自动 9 层降级;
|
||||
// "manual" = 仅使用 Layers 指定的层(手动),不再自动探测其它层。
|
||||
LayerStrategy string `json:"layer_strategy" toml:"layer_strategy"`
|
||||
// Layers 手动层级列表(仅 layer_strategy=manual 生效)。
|
||||
// 单元素(如 ["TURN-TCP"])= 强制固定该层、禁用降级;
|
||||
// 多元素(如 ["Direct-UDP","TURN-TCP"])= 按列表顺序自定义降级链。
|
||||
Layers []string `json:"layers" toml:"layers"`
|
||||
}
|
||||
|
||||
// PeerConf 对端配置
|
||||
type PeerConf struct {
|
||||
PublicKey string `json:"public_key" toml:"public_key"`
|
||||
Endpoint string `json:"endpoint" toml:"endpoint"`
|
||||
AllowedIPs []string `json:"allowed_ips" toml:"allowed_ips"`
|
||||
}
|
||||
|
||||
// ICEConf STUN/TURN 服务器(增强模式打洞/中继用)
|
||||
type ICEConf struct {
|
||||
STUN []string `json:"stun" toml:"stun"`
|
||||
TURN []string `json:"turn" toml:"turn"`
|
||||
}
|
||||
|
||||
// loadConfig 读取并解析配置文件:按扩展名自动选择 TOML 或 JSON 解码器。
|
||||
// 默认且推荐 TOML(类 frp);旧 .json 配置仍可继续使用。
|
||||
func loadConfig(path string) (*Config, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg := &Config{}
|
||||
// 按扩展名选择解码器:先剥离可能的 .sample 模板后缀,再判扩展名,
|
||||
// 避免 "meshray-core.toml.sample" 被误判为 JSON。
|
||||
lower := strings.ToLower(path)
|
||||
lower = strings.TrimSuffix(lower, ".sample")
|
||||
ext := filepath.Ext(lower)
|
||||
switch ext {
|
||||
case ".toml", ".conf":
|
||||
// TOML:与 frp 风格一致
|
||||
if err := toml.Unmarshal(data, cfg); err != nil {
|
||||
return nil, fmt.Errorf("解析 TOML 配置 %s 失败: %w", path, err)
|
||||
}
|
||||
default:
|
||||
// JSON:兼容旧配置
|
||||
if err := json.Unmarshal(data, cfg); err != nil {
|
||||
return nil, fmt.Errorf("解析 JSON 配置 %s 失败: %w", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.MTU == 0 {
|
||||
cfg.MTU = 1420
|
||||
}
|
||||
if cfg.Mode == "" {
|
||||
cfg.Mode = "enhanced"
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
// 命令 meshray-core:meshray-core 增强层的独立运行入口(类 frp 风格)。
|
||||
//
|
||||
// 直接以自定义 conn.Bind 接管 WireGuard 收发,使所有隧道密文流量经由本仓 9 层传输
|
||||
// (Direct/TURN/WebRTC/...)而非裸 UDP。无需管理器即可在两台机器间建立加密隧道,
|
||||
// 用于端到端验证 core 的收发能力。
|
||||
//
|
||||
// 用法:
|
||||
//
|
||||
// meshray-core -genkey # 生成私钥
|
||||
// meshray-core -c meshray-core.toml # 按配置启动(默认 TOML,类 frp;兼容 .json)
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
meshraycore "git.zkcoi.com/zkcoi/meshray/core/engine"
|
||||
"git.zkcoi.com/zkcoi/meshray/core/connect"
|
||||
corebind "git.zkcoi.com/zkcoi/meshray/internal/ctr/corebind"
|
||||
"go.uber.org/zap"
|
||||
"golang.zx2c4.com/wireguard/conn"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfgPath := flag.String("c", "meshray-core.toml", "配置文件路径(默认 TOML,类 frp;也兼容 .json)")
|
||||
genKey := flag.Bool("genkey", false, "仅生成私钥并打印后退出")
|
||||
flag.Parse()
|
||||
|
||||
if *genKey {
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "生成私钥失败:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(key.String())
|
||||
return
|
||||
}
|
||||
|
||||
cfg, err := loadConfig(*cfgPath)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "加载配置失败:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
logger := newLogger()
|
||||
defer func() { _ = logger.Sync() }()
|
||||
|
||||
// 1. 准备私钥:配置中给出则解析,否则生成并落盘
|
||||
priv, err := resolvePrivateKey(cfg, logger)
|
||||
if err != nil {
|
||||
logger.Fatal("私钥处理失败", zap.Error(err))
|
||||
}
|
||||
|
||||
// 2. 创建 TUN 设备(用户态)。Windows 需已安装 Wintun 驱动。
|
||||
devName := "mrc0"
|
||||
tunDev, err := tun.CreateTUN(devName, cfg.MTU)
|
||||
if err != nil {
|
||||
logger.Fatal("创建 TUN 设备失败(Windows 需 Wintun 驱动)", zap.Error(err))
|
||||
}
|
||||
defer tunDev.Close()
|
||||
|
||||
// 3. 创建 Bind:enhanced=自定义接管;native=裸 WG 默认 Bind
|
||||
var wgBind conn.Bind
|
||||
if cfg.Mode == "native" {
|
||||
logger.Info("以原生直连模式运行(裸 WG UDP)")
|
||||
wgBind = conn.NewDefaultBind()
|
||||
} else {
|
||||
logger.Info("以增强模式运行(9 层传输接管收发)")
|
||||
eb, eerr := corebind.NewEnhancedBind(cfg.ListenPort, cfg.NetworkID, logger)
|
||||
if eerr != nil {
|
||||
logger.Fatal("创建增强 Bind 失败", zap.Error(eerr))
|
||||
}
|
||||
wgBind = eb
|
||||
}
|
||||
|
||||
wgLogger := &device.Logger{
|
||||
Verbosef: func(format string, args ...interface{}) { logger.Debug(fmt.Sprintf(format, args...)) },
|
||||
Errorf: func(format string, args ...interface{}) { logger.Error(fmt.Sprintf(format, args...)) },
|
||||
}
|
||||
wgDev := device.NewDevice(tunDev, wgBind, wgLogger)
|
||||
defer wgDev.Close()
|
||||
|
||||
// 4. 组装 WG 配置(私钥 / 监听端口 / 各 peer)
|
||||
var sb strings.Builder
|
||||
fmt.Fprintf(&sb, "private_key=%s\nlisten_port=%d\n", priv.String(), cfg.ListenPort)
|
||||
for _, p := range cfg.Peers {
|
||||
pub, perr := wgtypes.ParseKey(p.PublicKey)
|
||||
if perr != nil {
|
||||
logger.Fatal("对端公钥解析失败", zap.String("public_key", p.PublicKey), zap.Error(perr))
|
||||
}
|
||||
fmt.Fprintf(&sb, "public_key=%s\n", pub.String())
|
||||
if p.Endpoint != "" {
|
||||
fmt.Fprintf(&sb, "endpoint=%s\n", p.Endpoint)
|
||||
}
|
||||
for _, a := range p.AllowedIPs {
|
||||
fmt.Fprintf(&sb, "allowed_ip=%s\n", a)
|
||||
}
|
||||
fmt.Fprintf(&sb, "persistent_keepalive=25\n")
|
||||
}
|
||||
if err := wgDev.IpcSet(sb.String()); err != nil {
|
||||
logger.Fatal("配置 WireGuard 设备失败", zap.Error(err))
|
||||
}
|
||||
|
||||
// 5. 增强模式:把对端候选(endpoint)注入引擎触发 9 层拨号
|
||||
if eb, ok := wgBind.(*corebind.EnhancedBind); ok {
|
||||
eng := eb.Engine()
|
||||
|
||||
// 5.0 下达 ICE 配置(STUN/TURN),手动 TURN/WebRTC 层级必需
|
||||
if len(cfg.ICE.STUN) > 0 || len(cfg.ICE.TURN) > 0 {
|
||||
turnCfgs := make([]connect.TURNServerConfig, 0, len(cfg.ICE.TURN))
|
||||
for _, t := range cfg.ICE.TURN {
|
||||
turnCfgs = append(turnCfgs, connect.TURNServerConfig{URLs: []string{t}})
|
||||
}
|
||||
ice := connect.ICEConfig{
|
||||
STUNServers: cfg.ICE.STUN,
|
||||
TURNServers: turnCfgs,
|
||||
}
|
||||
if err := eng.SetICEConfig(ice); err != nil {
|
||||
logger.Error("下达 ICE 配置失败", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// 5.1 应用传输层级策略:auto=默认 9 层自动降级;manual=仅用配置的 layers
|
||||
if cfg.LayerStrategy == "manual" {
|
||||
if len(cfg.Layers) == 0 {
|
||||
logger.Fatal("layer_strategy=manual 但 layers 为空")
|
||||
}
|
||||
layers, perr := parseLayers(cfg.Layers)
|
||||
if perr != nil {
|
||||
logger.Fatal("解析手动层级失败", zap.Error(perr))
|
||||
}
|
||||
eng.SetLayerOrder(layers)
|
||||
if len(layers) == 1 {
|
||||
logger.Info("手动层级模式:强制固定层(禁用降级)",
|
||||
zap.String("layer", layers[0].String()))
|
||||
} else {
|
||||
logger.Info("手动层级模式:自定义降级顺序",
|
||||
zap.Strings("layers", cfg.Layers))
|
||||
}
|
||||
} else {
|
||||
logger.Info("自动层级模式:9 层自动降级",
|
||||
zap.Int("default_layers", len(connect.DefaultLayerOrder)))
|
||||
}
|
||||
|
||||
// 5.2 注入对端候选,触发拨号
|
||||
for _, p := range cfg.Peers {
|
||||
if p.Endpoint == "" {
|
||||
continue
|
||||
}
|
||||
if err := eng.NotifyPeerInfo(p.PublicKey, []meshraycore.Candidate{{Addr: p.Endpoint}}); err != nil {
|
||||
logger.Error("注入对端候选失败", zap.String("peer", p.PublicKey), zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 启动设备并配置隧道 IP
|
||||
if err := wgDev.Up(); err != nil {
|
||||
logger.Fatal("启动 WireGuard 设备失败", zap.Error(err))
|
||||
}
|
||||
devName, nameErr := tunDev.Name()
|
||||
if nameErr != nil {
|
||||
logger.Warn("获取 TUN 设备名失败", zap.Error(nameErr))
|
||||
devName = "mrc0"
|
||||
}
|
||||
assignInterfaceIP(devName, cfg.InterfaceIP, logger)
|
||||
|
||||
logger.Info("meshray-core 已启动",
|
||||
zap.String("network_id", cfg.NetworkID),
|
||||
zap.String("mode", cfg.Mode),
|
||||
zap.String("device", devName),
|
||||
zap.String("interface", cfg.InterfaceIP))
|
||||
|
||||
// 7. 阻塞等待退出信号
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sig
|
||||
logger.Info("正在退出...")
|
||||
}
|
||||
|
||||
// resolvePrivateKey 返回私钥:配置给出则解析,否则生成并写入 private_key_file
|
||||
func resolvePrivateKey(cfg *Config, logger *zap.Logger) (wgtypes.Key, error) {
|
||||
if cfg.PrivateKey != "" {
|
||||
return wgtypes.ParseKey(cfg.PrivateKey)
|
||||
}
|
||||
key, err := wgtypes.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return wgtypes.Key{}, err
|
||||
}
|
||||
if cfg.PrivateKeyFile != "" {
|
||||
if werr := os.WriteFile(cfg.PrivateKeyFile, []byte(key.String()), 0600); werr != nil {
|
||||
logger.Warn("写入私钥文件失败", zap.Error(werr))
|
||||
} else {
|
||||
logger.Info("已生成并写入私钥", zap.String("file", cfg.PrivateKeyFile))
|
||||
}
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// assignInterfaceIP 给隧道接口分配 IP 并 up(best-effort,失败仅告警)
|
||||
func assignInterfaceIP(name, cidr string, logger *zap.Logger) {
|
||||
if cidr == "" {
|
||||
return
|
||||
}
|
||||
ip, ipNet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
logger.Error("解析隧道 IP 失败", zap.String("cidr", cidr), zap.Error(err))
|
||||
return
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
run(logger, "ip", "addr", "add", cidr, "dev", name)
|
||||
run(logger, "ip", "link", "set", name, "up")
|
||||
case "windows":
|
||||
// ipNet.Mask 已是网络掩码字节,转点分十进制
|
||||
m := ipNet.Mask
|
||||
maskStr := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3])
|
||||
run(logger, "netsh", "interface", "ip", "set", "address",
|
||||
"name="+name, "static", ip.String(), maskStr)
|
||||
default:
|
||||
logger.Warn("不支持的平台,请手动配置隧道 IP", zap.String("os", runtime.GOOS))
|
||||
}
|
||||
}
|
||||
|
||||
// run 执行外部命令(best-effort,输出仅调试)
|
||||
func run(logger *zap.Logger, name string, args ...string) {
|
||||
cmd := exec.Command(name, args...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
logger.Warn("执行命令失败(可忽略,手动配置即可)",
|
||||
zap.String("cmd", name), zap.String("args", strings.Join(args, " ")),
|
||||
zap.Error(err), zap.String("output", string(out)))
|
||||
}
|
||||
}
|
||||
|
||||
// newLogger 创建生产级 logger
|
||||
func newLogger() *zap.Logger {
|
||||
l, err := zap.NewProduction()
|
||||
if err != nil {
|
||||
l = zap.NewNop()
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// parseLayers 将配置中的层级名列表解析为 connect.Layer 列表,任一无法解析则返回错误
|
||||
func parseLayers(names []string) ([]connect.Layer, error) {
|
||||
layers := make([]connect.Layer, 0, len(names))
|
||||
for _, n := range names {
|
||||
l, ok := connect.ParseLayer(n)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("未知传输层: %q", n)
|
||||
}
|
||||
layers = append(layers, l)
|
||||
}
|
||||
return layers, nil
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"network_id": "net1",
|
||||
"listen_port": 51820,
|
||||
"mtu": 1420,
|
||||
"private_key": "",
|
||||
"private_key_file": "key.txt",
|
||||
"interface": "10.0.0.1/24",
|
||||
"mode": "enhanced",
|
||||
"peers": [
|
||||
{
|
||||
"public_key": "<对端机器 -genkey 生成的私钥对应的公钥>",
|
||||
"endpoint": "对端公网IP:51820",
|
||||
"allowed_ips": ["10.0.0.2/32"]
|
||||
}
|
||||
],
|
||||
"ice": { "stun": [], "turn": [] }
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# meshray-core 独立运行配置(类 frp 风格,TOML)
|
||||
# 用法: meshray-core -c meshray-core.toml
|
||||
# 也兼容旧 JSON 配置(扩展名 .json 自动按 JSON 解析)。
|
||||
|
||||
# 网络标识,同网段节点需一致
|
||||
network_id = "net1"
|
||||
|
||||
# 本地监听端口(WireGuard / 增强模式收发端口)
|
||||
listen_port = 51820
|
||||
|
||||
# 隧道 MTU(0 则默认 1420)
|
||||
mtu = 1420
|
||||
|
||||
# 私钥:留空则自动生成并写入 private_key_file
|
||||
private_key = ""
|
||||
private_key_file = "key.txt"
|
||||
|
||||
# 本机隧道 IP(CIDR)
|
||||
interface = "10.0.0.1/24"
|
||||
|
||||
# 运行模式:
|
||||
# enhanced = 经 9 层传输接管 WG 收发(支持自动降级 / 手动层级)
|
||||
# native = 裸 WireGuard UDP 直连(不经本仓传输层)
|
||||
mode = "enhanced"
|
||||
|
||||
# 传输层级策略:
|
||||
# auto = 默认,9 层自动降级(直连 → 中继 → ... → WS/WSS)
|
||||
# manual = 仅使用下方 layers 指定的层
|
||||
layer_strategy = "auto"
|
||||
|
||||
# 手动层级列表(仅 layer_strategy = "manual" 生效)。
|
||||
# 单元素 = 强制固定该层,禁用降级,例如强制走 TURN 中继:["TURN-TCP"]
|
||||
# 多元素 = 按列表顺序自定义降级链,例如直连优先、不通再中继:["Direct-UDP","TURN-TCP"]
|
||||
# 可选值:Direct-UDP / FakeTCP / RealTCP / TURN-UDP / TURN-QUIC / TURN-TCP /
|
||||
# TURN-TLS / WebRTC / WS(或 WSS)
|
||||
# 注意:该键须置于 [[peers]] 之前(TOML 中 [[peers]] 后键会被归入 peers 表)。
|
||||
layers = ["Direct-UDP"]
|
||||
|
||||
# 对端列表
|
||||
[[peers]]
|
||||
public_key = "对端公钥base64" # 必填
|
||||
endpoint = "203.0.113.2:51820" # 增强模式经 9 层拨号对端;留空则仅作为接收方
|
||||
allowed_ips = ["10.0.0.2/32"]
|
||||
|
||||
# 可选第二个对端
|
||||
# [[peers]]
|
||||
# public_key = "另一个对端公钥base64"
|
||||
# endpoint = "198.51.100.7:51820"
|
||||
# allowed_ips = ["10.0.0.3/32"]
|
||||
|
||||
# STUN/TURN 服务器(增强模式打洞/中继用;手动 TURN/WebRTC 层级必需)
|
||||
[ice]
|
||||
stun = ["stun:stun.l.google.com:19302"]
|
||||
turn = ["turn:your.turn.server:3478"]
|
||||
Reference in New Issue
Block a user