126 lines
3.1 KiB
Go
126 lines
3.1 KiB
Go
package main
|
||
|
||
import (
|
||
"flag"
|
||
"fmt"
|
||
"log"
|
||
"os"
|
||
"os/signal"
|
||
"syscall"
|
||
|
||
"dns-server/config"
|
||
"dns-server/dns"
|
||
"dns-server/http"
|
||
"dns-server/logger"
|
||
"dns-server/shield"
|
||
)
|
||
|
||
func main() {
|
||
// 命令行参数解析
|
||
var configFile string
|
||
var daemonMode bool
|
||
flag.StringVar(&configFile, "config", "config.json", "配置文件路径")
|
||
flag.BoolVar(&daemonMode, "daemon", false, "以守护进程模式运行")
|
||
flag.Parse()
|
||
|
||
// 如果是守护进程模式,创建守护进程
|
||
if daemonMode {
|
||
if err := daemonize(); err != nil {
|
||
log.Fatalf("创建守护进程失败: %v", err)
|
||
}
|
||
// 父进程退出
|
||
os.Exit(0)
|
||
}
|
||
|
||
// 初始化配置
|
||
var cfg *config.Config
|
||
var err error
|
||
cfg, err = config.LoadConfig(configFile)
|
||
if err != nil {
|
||
log.Fatalf("加载配置失败: %v", err)
|
||
}
|
||
|
||
// 初始化日志系统
|
||
if err := logger.InitLogger(cfg.Log.File, cfg.Log.Level, 0, 0, 0); err != nil {
|
||
log.Fatalf("初始化日志系统失败: %v", err)
|
||
}
|
||
defer logger.Close()
|
||
|
||
// 初始化屏蔽管理系统
|
||
shieldManager := shield.NewShieldManager(&cfg.Shield)
|
||
if err := shieldManager.LoadRules(); err != nil {
|
||
logger.Error("加载屏蔽规则失败", "error", err)
|
||
}
|
||
|
||
// 启动DNS服务器
|
||
dnsServer := dns.NewServer(&cfg.DNS, &cfg.Shield, shieldManager)
|
||
go func() {
|
||
if err := dnsServer.Start(); err != nil {
|
||
logger.Error("DNS服务器启动失败", "error", err)
|
||
os.Exit(1)
|
||
}
|
||
}()
|
||
|
||
// 启动HTTP控制台服务器
|
||
httpServer := http.NewServer(cfg, dnsServer, shieldManager)
|
||
go func() {
|
||
if err := httpServer.Start(); err != nil {
|
||
logger.Error("HTTP控制台服务器启动失败", "error", err)
|
||
}
|
||
}()
|
||
|
||
// 启动定时更新任务
|
||
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
|
||
|
||
// 清理资源
|
||
log.Println("正在关闭服务...")
|
||
dnsServer.Stop()
|
||
httpServer.Stop()
|
||
shieldManager.StopAutoUpdate()
|
||
// 守护进程模式下不需要删除PID文件
|
||
|
||
log.Println("服务已关闭")
|
||
}
|
||
|
||
// daemonize 创建守护进程
|
||
func daemonize() error {
|
||
// 使用更简单的方式创建守护进程:直接在当前进程中进行守护化处理
|
||
// 1. 重定向标准输入、输出、错误
|
||
nullFile, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
|
||
if err != nil {
|
||
return fmt.Errorf("打开/dev/null失败: %w", err)
|
||
}
|
||
defer nullFile.Close()
|
||
|
||
// 重定向文件描述符
|
||
err = syscall.Dup2(int(nullFile.Fd()), int(os.Stdin.Fd()))
|
||
if err != nil {
|
||
return fmt.Errorf("重定向stdin失败: %w", err)
|
||
}
|
||
err = syscall.Dup2(int(nullFile.Fd()), int(os.Stdout.Fd()))
|
||
if err != nil {
|
||
return fmt.Errorf("重定向stdout失败: %w", err)
|
||
}
|
||
err = syscall.Dup2(int(nullFile.Fd()), int(os.Stderr.Fd()))
|
||
if err != nil {
|
||
return fmt.Errorf("重定向stderr失败: %w", err)
|
||
}
|
||
|
||
// 2. 创建新的会话和进程组
|
||
_, err = syscall.Setsid()
|
||
if err != nil {
|
||
return fmt.Errorf("创建新会话失败: %w", err)
|
||
}
|
||
|
||
fmt.Println("守护进程已启动")
|
||
return nil
|
||
}
|