Files
dns-server/main.go
T
Alex Yang efebce3c39 whois
2026-04-01 12:22:55 +08:00

274 lines
8.0 KiB
Go
Raw 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.
// DNS Server API
// @title DNS Server API
// @version 1.0
// @description DNS服务器API文档
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.email support@example.com
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// @BasePath /api
package main
import (
"flag"
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"syscall"
"dns-server/config"
"dns-server/dns"
"dns-server/gfw"
"dns-server/http"
"dns-server/logger"
"dns-server/shield"
)
// createDefaultConfig 创建默认配置文件
func createDefaultConfig(configFile string) error {
// 默认配置内容
defaultConfig := `# DNS服务器配置文件
# 格式:INI格式,使用#注释
[dns]
# DNS服务器监听端口
port = 53
# 上游DNS服务器列表,逗号分隔
upstreamDNS = 223.5.5.5:53, 223.6.6.6:53
# DNSSEC专用服务器列表,逗号分隔
dnssecUpstreamDNS = 8.8.8.8:53, 1.1.1.1:53
# 数据保存间隔(秒)
saveInterval = 300
# DNS缓存过期时间(分钟)
cacheTTL = 30
# 是否启用DNSSEC支持
enableDNSSEC = true
# 查询模式:parallel(并行请求)、fastest-ip(最快的IP地址)
queryMode = parallel
# 查询超时时间(毫秒)
queryTimeout = 5000
# 是否启用快速返回机制
enableFastReturn = true
# 不验证DNSSEC的域名模式列表,逗号分隔
noDNSSECDomains =
# 是否启用IPv6解析(AAAA记录)
enableIPv6 = false
# 缓存模式:memory(内存缓存)、file(文件缓存)
cacheMode = memory
# 缓存大小限制(MB
cacheSize = 100
# 最大缓存TTL(分钟)
maxCacheTTL = 120
# 最小缓存TTL(分钟)
minCacheTTL = 5
[http]
# HTTP控制台监听端口
port = 8080
# HTTP控制台监听地址
host = 0.0.0.0
# 是否启用API
enableAPI = true
# 登录用户名
username = admin
# 登录密码
password = admin
[shield]
# 屏蔽规则更新间隔(秒)
updateInterval = 3600
# 屏蔽方法: NXDOMAIN, refused, emptyIP, customIP
blockMethod = NXDOMAIN
# 自定义屏蔽IP,当BlockMethod为"customIP"时使用
customBlockIP =
# 计数数据保存间隔(秒)
statsSaveInterval = 60
# 黑名单配置
# 格式:blacklist_名称 = URL,enabled
blacklist_AdGuard_DNS_filter = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/filter.txt,true
blacklist_Adaway_Default_Blocklist = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-Filters/raw/branch/main/hosts/adaway.txt,true
blacklist_CHN_anti_AD = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-Filters/raw/branch/main/list/easylist.txt,true
blacklist_My_GitHub_Rules = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/rules/costomize.txt,true
[gfwList]
# GFWList域名解析的目标IP地址
ip = 127.0.0.1
# GFWList规则文件路径
content = ./data/gfwlist.txt
# 是否启用GFWList功能
enabled = true
[log]
# 日志级别:debug, info, warn, error
level = debug
# 日志文件最大大小(MB
maxSize = 100
# 日志文件最大备份数
maxBackups = 10
# 日志文件最大保留天数
maxAge = 30
`
// 写入默认配置到文件
return os.WriteFile(configFile, []byte(defaultConfig), 0644)
}
// createRequiredFiles 创建所需的文件和文件夹
func createRequiredFiles(cfg *config.Config) error {
// 创建数据文件夹
dataDir := "./data"
if err := os.MkdirAll(dataDir, 0755); err != nil {
return fmt.Errorf("创建数据文件夹失败: %w", err)
}
// 创建远程规则缓存文件夹
if err := os.MkdirAll("data/remote_rules", 0755); err != nil {
return fmt.Errorf("创建远程规则缓存文件夹失败: %w", err)
}
// 创建日志文件夹
logDir := filepath.Dir("logs/dns-server.log")
if logDir != "." {
if err := os.MkdirAll(logDir, 0755); err != nil {
return fmt.Errorf("创建日志文件夹失败: %w", err)
}
}
// 创建自定义规则文件
if _, err := os.Stat("data/rules.txt"); os.IsNotExist(err) {
if err := os.WriteFile("data/rules.txt", []byte("# 自定义规则文件\n# 格式:域名\n# 例如:example.com\n"), 0644); err != nil {
return fmt.Errorf("创建自定义规则文件失败: %w", err)
}
}
// 创建Hosts文件
if _, err := os.Stat("data/hosts.txt"); os.IsNotExist(err) {
if err := os.WriteFile("data/hosts.txt", []byte("# Hosts文件\n# 格式:IP 域名\n# 例如:127.0.0.1 localhost\n"), 0644); err != nil {
return fmt.Errorf("创建Hosts文件失败: %w", err)
}
}
// 创建GFWList文件
if _, err := os.Stat("data/gfwlist.txt"); os.IsNotExist(err) {
if err := os.WriteFile("data/gfwlist.txt", []byte("# GFWList规则文件\n# 格式:每行一条规则\n# 例如:www.google.com\n"), 0644); err != nil {
return fmt.Errorf("创建GFWList文件失败: %w", err)
}
}
// 创建统计数据文件
if _, err := os.Stat("data/stats.json"); os.IsNotExist(err) {
if err := os.WriteFile("data/stats.json", []byte("{}"), 0644); err != nil {
return fmt.Errorf("创建统计数据文件失败: %w", err)
}
}
// 创建Shield统计数据文件
if _, err := os.Stat("data/shield_stats.json"); os.IsNotExist(err) {
if err := os.WriteFile("data/shield_stats.json", []byte("{}"), 0644); err != nil {
return fmt.Errorf("创建Shield统计数据文件失败: %w", err)
}
}
return nil
}
func main() {
// 命令行参数解析
var configFile string
flag.StringVar(&configFile, "config", "config.ini", "配置文件路径")
flag.Parse()
// 检查配置文件是否存在,如果不存在则创建默认配置文件
if _, err := os.Stat(configFile); os.IsNotExist(err) {
log.Printf("配置文件 %s 不存在,正在创建默认配置文件...", configFile)
if err := createDefaultConfig(configFile); err != nil {
log.Fatalf("创建默认配置文件失败: %v", err)
}
log.Printf("默认配置文件 %s 创建成功", configFile)
}
// 初始化配置
var cfg *config.Config
var err error
cfg, err = config.LoadConfig(configFile)
if err != nil {
log.Fatalf("加载配置失败: %v", err)
}
// 创建所需的文件和文件夹
log.Println("正在创建所需的文件和文件夹...")
if err := createRequiredFiles(cfg); err != nil {
log.Fatalf("创建所需文件和文件夹失败: %v", err)
}
log.Println("所需文件和文件夹创建成功")
// 初始化日志系统
if err := logger.InitLogger("logs/dns-server.log", cfg.Log.Level, 0, 0, 0, false); err != nil {
log.Fatalf("初始化日志系统失败: %v", err)
}
defer logger.Close()
// 初始化屏蔽管理系统
shieldManager := shield.NewShieldManager(&cfg.Shield)
if err := shieldManager.LoadLocalRulesOnly(); err != nil {
logger.Error("加载本地屏蔽规则失败", "error", err)
}
// 初始化GFWList管理系统
gfwManager := gfw.NewGFWListManager(&cfg.GFWList)
if err := gfwManager.LoadRules(); err != nil {
logger.Error("加载GFWList规则失败", "error", err)
}
// 启动DNS服务器
dnsServer := dns.NewServer(cfg, shieldManager, gfwManager)
go func() {
if err := dnsServer.Start(); err != nil {
logger.Error("DNS服务器启动失败", "error", err)
os.Exit(1)
}
}()
// 启动HTTP控制台服务器
httpServer := http.NewServer(cfg, dnsServer, shieldManager, gfwManager)
go func() {
if err := httpServer.Start(); err != nil {
logger.Error("HTTP控制台服务器启动失败", "error", err)
}
}()
// 异步加载远程规则
go func() {
logger.Info("开始异步加载远程屏蔽规则")
if err := shieldManager.LoadRules(); err != nil {
logger.Error("异步加载远程屏蔽规则失败", "error", err)
} else {
logger.Info("远程屏蔽规则异步加载完成")
}
}()
// 启动定时更新任务
go shieldManager.StartAutoUpdate()
logger.Info(fmt.Sprintf("DNS服务器已启动,监听端口: %d", cfg.DNS.Port))
logger.Info(fmt.Sprintf("HTTP控制台已启动,监听端口: %d", cfg.HTTP.Port))
// 监听信号
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
// 清理资源
logger.Info("正在关闭服务...")
dnsServer.Stop()
httpServer.Stop()
shieldManager.StopAutoUpdate()
logger.Info("服务已关闭")
}