274 lines
8.0 KiB
Go
274 lines
8.0 KiB
Go
// 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.DNS, &cfg.Shield, shieldManager, &cfg.GFWList, 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("服务已关闭")
|
||
}
|