mosdns/tools/init.go

332 lines
8.9 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.

/*
* Copyright (C) 2020-2022, IrineSistiana
*
* This file is part of mosdns.
*
* mosdns is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* mosdns is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package tools
import (
"fmt"
"os"
"github.com/IrineSistiana/mosdns/v5/coremain"
"github.com/spf13/cobra"
)
func init() {
probeCmd := &cobra.Command{
Use: "probe",
Short: "Run some server tests.",
}
probeCmd.AddCommand(
newConnReuseCmd(),
newIdleTimeoutCmd(),
newPipelineCmd(),
)
coremain.AddSubCmd(probeCmd)
configCmd := &cobra.Command{
Use: "config",
Short: "Tools that can generate/convert mosdns config file.",
}
configCmd.AddCommand(newGenCmd(), newConvCmd())
coremain.AddSubCmd(configCmd)
// 添加 init 命令用于快速初始化配置
initCmd := &cobra.Command{
Use: "init",
Short: "Initialize mosdns configuration and directories.",
Long: "Create default config.yaml and necessary directories for quick deployment on any server.",
RunE: runInit,
}
var forceFlag bool
initCmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "强制覆盖已存在的配置文件")
coremain.AddSubCmd(initCmd)
}
// runInit 执行初始化操作
func runInit(cmd *cobra.Command, args []string) error {
force, _ := cmd.Flags().GetBool("force")
fmt.Println("========================================")
fmt.Println(" 🚀 MosDNS 初始化向导")
fmt.Println("========================================")
fmt.Println()
// 1. 检查并创建配置文件
configFile := "config.yaml"
if err := createConfigFile(configFile, force); err != nil {
return err
}
// 2. 创建必要的目录结构
if err := createDirectories(); err != nil {
return err
}
// 3. 创建示例数据文件(如果不存在)
if err := createDataFiles(); err != nil {
return err
}
// 4. 显示完成信息
showCompletionInfo()
return nil
}
// createConfigFile 创建默认配置文件
func createConfigFile(filename string, force bool) error {
// 检查文件是否已存在
if _, err := os.Stat(filename); err == nil && !force {
fmt.Printf("⚠️ 配置文件已存在: %s\n", filename)
fmt.Println(" 使用 --force 或 -f 参数强制覆盖")
return nil
}
// 生成默认配置内容
configContent := `# ========================================
# MosDNS 配置文件 - 智能 DNS 服务器
# 自动生成时间: $(date)
# ========================================
# 日志配置
log:
level: info # 日志级别: debug, info, warn, error
file: "" # 日志文件路径(空表示输出到控制台)
# API 管理接口配置
api:
http: "0.0.0.0:8080" # API 监听地址和端口
# Web 管理界面配置
web:
http: "0.0.0.0:5555" # Web UI 监听地址和端口
# 插件配置
plugins:
# ========================================
# 1. 数据源插件
# ========================================
# 中国 IP 地址库(用于智能分流)
- tag: geoip_cn
type: ip_set
args:
files:
- "./data/chn_ip.txt"
# 中国域名列表(用于智能分流)
- tag: geosite_cn
type: domain_set
args:
files:
- "./data/geosite_china-list.txt"
# ========================================
# 2. DNS 上游服务器
# ========================================
# 国内 DNS 上游(用于解析国内域名)
- tag: forward_local
type: forward
args:
concurrent: 2 # 并发查询数量
upstreams:
- addr: "223.5.5.5" # 阿里云 DNS
- addr: "119.29.29.29" # 腾讯云 DNS
# 国外 DNS 上游(用于解析国外域名)
- tag: forward_remote
type: forward
args:
concurrent: 2
upstreams:
- addr: "https://1.1.1.1/dns-query" # Cloudflare DoH
enable_http3: false
- addr: "https://8.8.8.8/dns-query" # Google DoH
enable_http3: false
# ========================================
# 3. 缓存插件
# ========================================
- tag: main_cache
type: cache
args:
size: 100000 # 缓存条目数量
lazy_cache_ttl: 86400 # 惰性缓存 TTL
dump_file: "./cache.dump" # 缓存持久化文件
dump_interval: 3600 # 缓存保存间隔(秒)
# ========================================
# 4. 主执行序列
# ========================================
- tag: main
type: sequence
args:
# 先查缓存
- exec: $main_cache
# 如果是国内域名,使用国内 DNS
- matches:
- qname $geosite_cn
exec: $forward_local
# 其他域名使用国外 DNS
- exec: $forward_remote
# 将结果存入缓存
- matches:
- has_resp
exec: $main_cache
# ========================================
# 5. DNS 服务器
# ========================================
# UDP 服务器
- tag: udp_server
type: udp_server
args:
entry: main # 入口执行序列
listen: ":53" # 监听端口(需要 root 权限)
# TCP 服务器
- tag: tcp_server
type: tcp_server
args:
entry: main
listen: ":53"
`
// 写入文件
if err := os.WriteFile(filename, []byte(configContent), 0644); err != nil {
return fmt.Errorf("创建配置文件失败: %w", err)
}
fmt.Printf("✅ 配置文件已创建: %s\n", filename)
return nil
}
// createDirectories 创建必要的目录结构
func createDirectories() error {
dirs := []string{
"./data", // 数据文件目录
"./config.d", // 配置文件目录
"./config.d/rules", // 规则文件目录
"./logs", // 日志目录(可选)
}
fmt.Println()
fmt.Println("📁 创建目录结构...")
for _, dir := range dirs {
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("创建目录失败 %s: %w", dir, err)
}
fmt.Printf(" ✅ %s\n", dir)
}
return nil
}
// createDataFiles 创建示例数据文件
func createDataFiles() error {
fmt.Println()
fmt.Println("📄 检查数据文件...")
dataFiles := map[string]string{
"./data/chn_ip.txt": `# 中国 IP 地址段(示例)
# 请从以下地址下载完整列表:
# https://github.com/17mon/china_ip_list
# 示例 IP 段
1.0.1.0/24
1.0.2.0/23
`,
"./data/geosite_china-list.txt": `# 中国常见域名列表(示例)
# 请从以下地址下载完整列表:
# https://github.com/felixonmars/dnsmasq-china-list
# 示例域名
domain:baidu.com
domain:qq.com
domain:taobao.com
domain:tmall.com
domain:jd.com
`,
}
for file, content := range dataFiles {
// 如果文件已存在且不为空,跳过
if stat, err := os.Stat(file); err == nil && stat.Size() > 0 {
fmt.Printf(" ⏭️ 已存在: %s\n", file)
continue
}
// 创建示例文件
if err := os.WriteFile(file, []byte(content), 0644); err != nil {
return fmt.Errorf("创建数据文件失败 %s: %w", file, err)
}
fmt.Printf(" ✅ 已创建: %s\n", file)
}
return nil
}
// showCompletionInfo 显示完成信息和后续步骤
func showCompletionInfo() {
wd, _ := os.Getwd()
fmt.Println()
fmt.Println("========================================")
fmt.Println(" 🎉 初始化完成!")
fmt.Println("========================================")
fmt.Println()
fmt.Println("📂 工作目录:", wd)
fmt.Println()
fmt.Println("📋 已创建的文件和目录:")
fmt.Println(" config.yaml - 主配置文件")
fmt.Println(" data/ - 数据文件目录")
fmt.Println(" config.d/rules/ - 规则文件目录")
fmt.Println()
fmt.Println("⚠️ 重要提示:")
fmt.Println(" 1. 数据文件为示例文件,建议下载完整的 CN IP 和域名列表")
fmt.Println(" - CN IP: https://github.com/17mon/china_ip_list")
fmt.Println(" - CN 域名: https://github.com/felixonmars/dnsmasq-china-list")
fmt.Println()
fmt.Println(" 2. 默认端口 53 需要 root 权限,可以修改为其他端口(如 5310")
fmt.Println()
fmt.Println("🚀 启动服务:")
fmt.Println()
fmt.Println(" # 开发模式(非 root")
fmt.Println(" sed -i 's/:53/:5310/g' config.yaml")
fmt.Println(" ./mosdns-linux-amd64 start -c config.yaml")
fmt.Println()
fmt.Println(" # 生产模式(需要 root")
fmt.Println(" sudo ./mosdns-linux-amd64 start -c config.yaml")
fmt.Println()
fmt.Println("🌐 管理界面:")
fmt.Println(" Web UI: http://localhost:5555")
fmt.Println(" API: http://localhost:8080")
fmt.Println()
fmt.Println("========================================")
fmt.Println()
}