Files
Meshray-Manager/docs/DDNS 双模式实现完成报告.md
T
2026-06-30 15:14:37 +08:00

11 KiB
Raw Blame History

DDNS 双模式实现完成报告

📋 实现概述

本次实现完成了 DDNS(动态 DNS)的双模式架构,将 DDNS 配置与使用完全解耦,支持两种不同的应用场景:

  1. 基础设施配置模式 - 仅配置 DNS 服务商对接信息
  2. 全功能 DDNS 服务模式 - 创建完整的 DNS 记录,支持内网穿透等应用

已完成的工作

1. 前端实现

修改的文件

  • web/src/views/Service/List.vue

核心功能

Tab 4 改名为"增强"(从"服务市场"
DDNS 表单支持两种模式切换
基础设施模式:只配置服务商信息
全功能模式:支持 A/AAAA/TXT/CNAME 记录类型
根据记录类型动态显示字段
表单验证规则区分模式
增强页展示服务卡片
点击卡片自动填充表单

UI 组件

// 模式选择
<el-radio-group v-model="formData.config_mode">
  <el-radio value="infrastructure">🏗️ 基础设施配置</el-radio>
  <el-radio value="fullservice">🚀 全功能 DDNS 服务</el-radio>
</el-radio-group>

// 基础设施模式字段
- DNS 服务商
- 根域名
- API Token / AccessKey

// 全功能模式字段
- 选择 DDNS 配置级联选择
- 记录类型A/AAAA/TXT/CNAME
- 主机记录A/AAAA
- 目标 IPA/AAAA
- 检测端口A/AAAA
- TXT 记录名称和值TXT
- 目标域名CNAME
- TTL

2. 后端实现

修改的文件

  • internal/model/models.go - 数据模型
  • internal/service/service.go - Service 层

数据模型扩展

Service 模型中添加了以下字段:

// DDNS 全功能模式字段
ConfigMode      string `gorm:"type:varchar(16);default:'infrastructure'" json:"config_mode"`
DDNSConfigID    string `gorm:"type:varchar(36)" json:"ddns_config_id,omitempty"`
Subdomain       string `gorm:"type:varchar(255)" json:"subdomain,omitempty"`
TargetIP        string `gorm:"type:varchar(64)" json:"target_ip,omitempty"`
TXTRecordName   string `gorm:"type:varchar(255)" json:"txt_record_name,omitempty"`
TXTValue        string `gorm:"type:text" json:"txt_value,omitempty"`
CNAMETarget     string `gorm:"type:varchar(255)" json:"cname_target,omitempty"`
TTL             int    `gorm:"default:600" json:"ttl,omitempty"`

Service 层校验逻辑

基础设施模式校验

if req.Type == "DDNS" && req.ConfigMode == "infrastructure" {
    // 校验服务商
    if req.Provider == "" {
        return nil, errors.New("请选择 DNS 服务商")
    }
    // 校验域名
    if req.Domain == "" {
        return nil, errors.New("请输入根域名")
    }
    // 根据服务商校验认证信息
    switch req.Provider {
    case "cloudflare":
        if req.Token == "" {
            return nil, errors.New("请输入 API Token")
        }
    case "aliyun":
        if req.AuthUsername == "" || req.AuthPassword == "" {
            return nil, errors.New("请输入 AccessKey ID 和 Secret")
        }
    case "tencent":
        if req.AuthUsername == "" || req.AuthPassword == "" {
            return nil, errors.New("请输入 SecretId 和 SecretKey")
        }
    }
}

全功能模式校验

if req.Type == "DDNS" && req.ConfigMode == "fullservice" {
    // 校验关联的 DDNS 配置
    if req.DDNSConfigID == "" {
        return nil, errors.New("请选择 DDNS 配置")
    }
    // 校验记录类型
    if req.RecordType == "" {
        return nil, errors.New("请选择记录类型")
    }
    // 根据记录类型校验具体字段
    switch req.RecordType {
    case "A", "AAAA":
        if req.Subdomain == "" {
            return nil, errors.New("请输入主机记录")
        }
        if req.TargetIP == "" {
            return nil, errors.New("请输入目标 IP")
        }
        if req.Port <= 0 {
            return nil, errors.New("请输入检测端口")
        }
    case "TXT":
        if req.TXTRecordName == "" {
            return nil, errors.New("请输入 TXT 记录名称")
        }
        if req.TXTValue == "" {
            return nil, errors.New("请输入 TXT 记录值")
        }
    case "CNAME":
        if req.CNAMETarget == "" {
            return nil, errors.New("请输入目标域名")
        }
    }
}

3. 文档

创建的文档

DDNS 双模式架构设计.md - 详细的设计文档
DDNS 双模式功能测试指南.md - 完整的测试用例
DDNS 双模式实现完成报告.md - 本文档


🎯 用户使用流程

场景 1:组网同步 MeshSeed(使用基础设施模式)

步骤 1: 配置 DDNS 服务商
├─ 访问:服务管理 → Tab 3 "DDNS"
├─ 点击:"添加 DDNS"
├─ 配置模式:选择"基础设施配置"
├─ 填写:
│   ├─ DNS 服务商:Cloudflare
│   ├─ 根域名:example.com
│   └─ API Token: cf_abc123...
└─ 提交 → 保存配置

步骤 2: 创建组网时选用
├─ 访问:组网管理 → 创建网络
├─ 基础信息 → 填写网络名称
├─ DDNS 同步配置 → 启用
├─ 选择 DDNS 服务:选择步骤 1 的配置
├─ TXT 记录前缀:自动生成 / 自定义
└─ 提交 → 系统自动创建 TXT 记录

结果:
- TXT 记录名:_meshray.{短 ID}.example.com
- 记录值:加密的 MeshSeed 配置
- 设备加入时自动读取

场景 2:NAS 内网穿透(使用全功能模式)

前置条件:已在 Tab 3 配置 DDNS 服务商

步骤 1: 创建 DDNS 内网穿透服务
├─ 访问:服务管理 → Tab 4 "增强"
├─ 点击:"DDNS 内网穿透"卡片
├─ 配置模式:自动选择"全功能 DDNS 服务"
├─ 填写:
│   ├─ 选择 DDNS 配置:Cloudflare (example.com)
│   ├─ 记录类型:AAAA (IPv6)
│   ├─ 主机记录:nas
│   ├─ 目标 IP: ::ffff:192.168.1.100
│   ├─ 检测端口:80
│   └─ TTL: 600 (10 分钟)
└─ 提交 → 创建 DNS 记录

步骤 2: 系统自动维护
├─ 定时检测本地 IPv6 地址
├─ 如果 IP 变化 → 调用 Cloudflare API 更新
├─ 保持 nas.example.com 始终指向最新 IP
└─ 用户可通过域名随时访问

结果:
- 完整域名:nas.example.com
- 记录类型:AAAA (IPv6)
- 目标:::ffff:192.168.1.100
- 自动更新: enabled

📊 数据库表结构变更

Service 表新增字段

字段名 类型 默认值 说明
config_mode varchar(16) 'infrastructure' 配置模式:infrastructure | fullservice
ddns_config_id varchar(36) NULL 关联的 DDNS 配置 ID(外键)
subdomain varchar(255) NULL 主机记录(子域名)
target_ip varchar(64) NULL 目标 IP 地址
txt_record_name varchar(255) NULL TXT 记录名称
txt_value text NULL TXT 记录值
cname_target varchar(255) NULL CNAME 目标域名
ttl int 600 TTL(秒)

🔧 技术实现细节

1. 前端动态表单

模式切换逻辑

// 监听 config_mode 变化
watch(() => formData.value.config_mode, (newMode) => {
  if (newMode === 'infrastructure') {
    // 清空全功能模式字段
    formData.value.ddns_config_id = ''
    formData.value.subdomain = ''
    formData.value.target_ip = ''
    // ...
  } else if (newMode === 'fullservice') {
    // 清空基础设施模式字段
    formData.value.provider = ''
    formData.value.domain = ''
    formData.value.token = ''
    // ...
  }
})

条件字段显示

<!-- 基础设施模式 -->
<template v-if="formData.config_mode === 'infrastructure'">
  <el-form-item label="DNS 服务商" prop="provider">
    <el-select v-model="formData.provider">
      <el-option label="阿里云 DNS" value="aliyun" />
      <el-option label="Cloudflare" value="cloudflare" />
    </el-select>
  </el-form-item>
</template>

<!-- 全功能模式 -->
<template v-else-if="formData.config_mode === 'fullservice'">
  <el-form-item label="选择 DDNS 配置" prop="ddns_config_id">
    <el-select v-model="formData.ddns_config_id" filterable>
      <el-option
        v-for="config in ddnsConfigs"
        :key="config.id"
        :label="`${config.name} (${config.config?.domain})`"
        :value="config.id"
      />
    </el-select>
  </el-form-item>
</template>

2. 后端校验链

API Handler (CreateService)
  ↓
Service 层 (CreateService)
  ↓
类型检查:req.Type == "DDNS"
  ↓
模式检查:req.ConfigMode
  ↓
├─ infrastructure → 校验服务商 + 认证信息
└─ fullservice → 校验关联配置 + 记录类型 + 具体字段
  ↓
数据库保存

3. 数据关联关系

全功能 DDNS 服务
  ↓
ddns_config_id (外键)
  ↓
基础设施 DDNS 配置
  ↓
解析出:Provider + Domain + API Token
  ↓
调用 DNS 服务商 API
  ↓
创建/更新 DNS 记录

验证清单

前端验证

  • Tab 4 显示为"增强"
  • Tab 3 文案正确
  • DDNS 表单有两种模式选项
  • 基础设施模式字段显示正确
  • 全功能模式字段显示正确
  • 记录类型切换时字段联动
  • 表单验证规则正确
  • 增强页服务卡片显示
  • 点击卡片行为正确
  • 无控制台错误

后端验证

  • 数据模型包含所有新字段
  • Service 层校验逻辑完整
  • 编译无错误
  • 服务正常启动

🚀 下一步工作

待实现的功能

1. DDNS 全功能服务的实际 DNS 操作

优先级: P0
内容:

  • 集成 libdns 库
  • 实现 DNS 记录的 CRUD 操作
  • 支持各云服务商的 API 调用
  • 实现 IP 检测和自动更新

涉及文件:

  • internal/service/ddns_full.go (新建)
  • internal/dnsprovider/ (新建目录)

2. 后台任务调度

优先级: P1
内容:

  • 定时检测 IP 变化
  • 批量更新 DNS 记录
  • 失败重试机制
  • 告警通知

涉及文件:

  • internal/scheduler/ddns_updater.go (新建)

3. 前后端联调测试

优先级: P1
内容:

  • 按照测试指南逐项验证
  • 测试真实的 DNS 服务商 API
  • 验证 IP 检测和更新逻辑
  • 性能测试和压力测试

涉及文件:

  • DDNS 双模式功能测试指南.md

4. 数据库迁移

优先级: P2
内容:

  • 添加新字段的 Migration
  • 数据兼容性处理
  • 旧数据升级

涉及文件:

  • internal/store/sqlite/migrate.go

📝 注意事项

1. 安全性

  • API Token/AccessKey 等敏感信息需要加密存储
  • 数据库字段使用 password 标签避免返回敏感数据
  • 日志中需要脱敏处理

2. 性能优化

  • ⚠️ DDNS 配置列表需要缓存,避免频繁查询
  • ⚠️ IP 检测需要使用多个服务交叉验证
  • ⚠️ DNS 更新需要实现幂等性,避免重复调用

3. 错误处理

  • ⚠️ DNS API 调用失败需要有重试机制
  • ⚠️ 网络异常需要友好提示用户
  • ⚠️ 记录详细的操作日志便于排查

🎉 总结

本次实现完成了 DDNS 双模式架构的前后端基础框架

前端:完整的 UI 交互、表单验证、模式切换
后端:数据模型、校验逻辑、API 接口
文档:架构设计、测试指南、实现报告

当前状态:基础框架完成,可以进行真实 DNS 操作的开发了。

下一步重点:集成 libdns 库,实现真实的 DNS 记录创建和更新功能。


实现日期: 2026-03-20
实现人员: AI Assistant
实现状态: 基础框架完成,等待 DNS 操作集成