增加了API断电

This commit is contained in:
Alex Yang
2025-11-28 00:42:11 +08:00
parent b1c63f6713
commit 45ed4d0d6b
5 changed files with 206 additions and 87 deletions

View File

@@ -1,81 +0,0 @@
# DNS服务器项目介绍
## 项目概述
这是一个基于Go语言开发的高性能DNS服务器具备域名屏蔽、Hosts管理、统计分析和远程规则管理等功能。服务器支持通过Web界面进行管理配置同时能够自动更新和缓存远程规则列表。
## 技术架构
### 核心组件
1. DNS服务模块 ( `server.go` )
- 基于 github.com/miekg/dns 库实现高性能DNS查询处理
- 支持配置上游DNS服务器进行递归查询
- 实现域名屏蔽、统计数据收集等核心功能
2. 屏蔽管理系统 ( `manager.go` )
- 管理本地和远程屏蔽规则
- 支持规则缓存、自动更新和统计
- 实现域名和正则表达式规则的解析和匹配
3. HTTP控制台 ( `server.go` )
- 提供Web管理界面
- 实现REST API用于配置管理和数据查询
4. 配置管理 ( `config.go` )
- 定义配置结构和加载功能
- 支持JSON格式配置文件
## 主要功能特性
### 1. 域名屏蔽系统
- 支持本地规则文件和远程规则URL
- 多种屏蔽方式NXDOMAIN、refused、emptyIP、customIP
- 支持域名精确匹配和正则表达式匹配
- 远程规则自动缓存和更新机制
### 2. Hosts管理
- 支持自定义Hosts映射
- 提供Web界面管理Hosts条目
- 自动保存Hosts配置
### 3. 统计分析功能
- 记录屏蔽域名统计信息
- 记录解析域名统计信息
- 提供按小时统计的屏蔽数据
- 支持查询最常屏蔽和解析的域名
### 4. 远程规则管理
- 支持添加多个远程规则URL
- 自动定期更新远程规则
- 本地缓存机制确保规则可用性
- Web界面可视化管理
### 5. 管理界面
- 提供直观的Web控制台
- 支持查看服务器状态和统计信息
- 规则管理和配置修改
- DNS查询测试工具
## 项目结构
```
/root/dns/
├── config/          # 配置管理
├── data/            # 数据目录(包含缓存和统计)
   └── remote_rules/ # 远程规则缓存
├── dns/             # DNS服务器核心
├── http/            # HTTP控制台
├── logger/          # 日志系统
├── shield/          # 屏蔽规则管理
├── static/          # 静态Web文件
├── main.go          # 程序入口
└── config.json      # 配置文件
```
## 配置项说明
主要配置文件 `config.json` 包含以下部分:
- DNS配置 端口、上游DNS服务器、超时设置等
- HTTP配置 :控制台端口、主机绑定等
- 屏蔽配置 规则文件路径、远程规则URL、更新间隔等
- 日志配置 :日志文件路径、级别设置等
## 使用场景
1. 网络内容过滤(广告、恶意网站屏蔽)
2. 本地DNS缓存加速
3. 企业/家庭网络DNS管理
4. 开发测试环境DNS重定向
## 技术栈
- 语言 Go
- DNS库 github.com/miekg/dns
- 日志库 github.com/sirupsen/logrus
- Web前端 HTML/CSS/JavaScript
该DNS服务器具有高性能、功能全面、易于配置等特点适用于需要精确控制DNS查询结果的各种网络环境。

View File

@@ -66,6 +66,24 @@ func (s *Server) Start() error {
if s.config.EnableAPI { if s.config.EnableAPI {
mux.HandleFunc("/api/stats", s.handleStats) mux.HandleFunc("/api/stats", s.handleStats)
mux.HandleFunc("/api/shield", s.handleShield) mux.HandleFunc("/api/shield", s.handleShield)
mux.HandleFunc("/api/shield/localrules", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.Method == http.MethodGet {
localRules := s.shieldManager.GetLocalRules()
json.NewEncoder(w).Encode(localRules)
return
}
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
})
mux.HandleFunc("/api/shield/remoterules", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.Method == http.MethodGet {
remoteRules := s.shieldManager.GetRemoteRules()
json.NewEncoder(w).Encode(remoteRules)
return
}
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
})
mux.HandleFunc("/api/shield/hosts", s.handleShieldHosts) mux.HandleFunc("/api/shield/hosts", s.handleShieldHosts)
mux.HandleFunc("/api/shield/blacklists", s.handleShieldBlacklists) mux.HandleFunc("/api/shield/blacklists", s.handleShieldBlacklists)
mux.HandleFunc("/api/query", s.handleQuery) mux.HandleFunc("/api/query", s.handleQuery)
@@ -596,6 +614,7 @@ func (s *Server) handleTopDomains(w http.ResponseWriter, r *http.Request) {
func (s *Server) handleShield(w http.ResponseWriter, r *http.Request) { func (s *Server) handleShield(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
// 默认处理逻辑
switch r.Method { switch r.Method {
case http.MethodGet: case http.MethodGet:
// 检查是否需要返回完整规则列表 // 检查是否需要返回完整规则列表
@@ -619,6 +638,8 @@ func (s *Server) handleShield(w http.ResponseWriter, r *http.Request) {
} }
json.NewEncoder(w).Encode(shieldInfo) json.NewEncoder(w).Encode(shieldInfo)
return return
}
switch r.Method {
case http.MethodPost: case http.MethodPost:
// 添加屏蔽规则 // 添加屏蔽规则
var req struct { var req struct {

View File

@@ -1,5 +0,0 @@
||hm.baidu.com
||baidu.com
/.*tracking.*/
/adjust.net/
/ad./

View File

@@ -1275,6 +1275,131 @@ func (m *ShieldManager) GetHostsCount() int {
return len(m.hostsMap) return len(m.hostsMap)
} }
// GetLocalRules 获取仅本地规则
func (m *ShieldManager) GetLocalRules() map[string]interface{} {
m.rulesMutex.RLock()
defer m.rulesMutex.RUnlock()
// 转换map和slice为字符串列表只包含本地规则
domainRulesList := make([]string, 0)
for domain, isLocal := range m.domainRulesIsLocal {
if isLocal && m.domainRules[domain] {
domainRulesList = append(domainRulesList, "||"+domain+"^")
}
}
domainExceptionsList := make([]string, 0)
for domain, isLocal := range m.domainExceptionsIsLocal {
if isLocal && m.domainExceptions[domain] {
domainExceptionsList = append(domainExceptionsList, "@@||"+domain+"^")
}
}
// 获取本地正则规则原始字符串
regexRulesList := make([]string, 0)
for _, re := range m.regexRules {
if re.isLocal {
regexRulesList = append(regexRulesList, re.original)
}
}
// 获取本地正则排除规则原始字符串
regexExceptionsList := make([]string, 0)
for _, re := range m.regexExceptions {
if re.isLocal {
regexExceptionsList = append(regexExceptionsList, re.original)
}
}
// 计算本地规则数量
localDomainRulesCount := 0
for _, isLocal := range m.domainRulesIsLocal {
if isLocal {
localDomainRulesCount++
}
}
localRegexRulesCount := 0
for _, re := range m.regexRules {
if re.isLocal {
localRegexRulesCount++
}
}
localRulesCount := localDomainRulesCount + localRegexRulesCount
return map[string]interface{}{
"domainRules": domainRulesList,
"domainExceptions": domainExceptionsList,
"regexRules": regexRulesList,
"regexExceptions": regexExceptionsList,
"localRulesCount": localRulesCount,
"localDomainRulesCount": localDomainRulesCount,
"localRegexRulesCount": localRegexRulesCount,
}
}
// GetRemoteRules 获取仅远程规则
func (m *ShieldManager) GetRemoteRules() map[string]interface{} {
m.rulesMutex.RLock()
defer m.rulesMutex.RUnlock()
// 转换map和slice为字符串列表只包含远程规则
domainRulesList := make([]string, 0)
for domain, isLocal := range m.domainRulesIsLocal {
if !isLocal && m.domainRules[domain] {
domainRulesList = append(domainRulesList, "||"+domain+"^")
}
}
domainExceptionsList := make([]string, 0)
for domain, isLocal := range m.domainExceptionsIsLocal {
if !isLocal && m.domainExceptions[domain] {
domainExceptionsList = append(domainExceptionsList, "@@||"+domain+"^")
}
}
// 获取远程正则规则原始字符串
regexRulesList := make([]string, 0)
for _, re := range m.regexRules {
if !re.isLocal {
regexRulesList = append(regexRulesList, re.original)
}
}
// 获取远程正则排除规则原始字符串
regexExceptionsList := make([]string, 0)
for _, re := range m.regexExceptions {
if !re.isLocal {
regexExceptionsList = append(regexExceptionsList, re.original)
}
}
// 计算远程规则数量
remoteDomainRulesCount := 0
for _, isLocal := range m.domainRulesIsLocal {
if !isLocal {
remoteDomainRulesCount++
}
}
remoteRegexRulesCount := 0
for _, re := range m.regexRules {
if !re.isLocal {
remoteRegexRulesCount++
}
}
remoteRulesCount := remoteDomainRulesCount + remoteRegexRulesCount
return map[string]interface{}{
"domainRules": domainRulesList,
"domainExceptions": domainExceptionsList,
"regexRules": regexRulesList,
"regexExceptions": regexExceptionsList,
"remoteRulesCount": remoteRulesCount,
"remoteDomainRulesCount": remoteDomainRulesCount,
"remoteRegexRulesCount": remoteRegexRulesCount,
"blacklists": m.config.Blacklists,
}
}
// GetRules 获取所有规则 // GetRules 获取所有规则
func (m *ShieldManager) GetRules() map[string]interface{} { func (m *ShieldManager) GetRules() map[string]interface{} {
m.rulesMutex.RLock() m.rulesMutex.RLock()

View File

@@ -53,7 +53,7 @@ async function loadShieldStats() {
async function loadLocalRules() { async function loadLocalRules() {
showLoading('加载本地规则...'); showLoading('加载本地规则...');
try { try {
const response = await fetch('/api/shield?all=true'); const response = await fetch('/api/shield/localrules');
if (!response.ok) { if (!response.ok) {
throw new Error(`加载失败: ${response.status}`); throw new Error(`加载失败: ${response.status}`);
@@ -61,6 +61,11 @@ async function loadLocalRules() {
const data = await response.json(); const data = await response.json();
// 更新本地规则数量显示
if (document.getElementById('local-rules-count')) {
document.getElementById('local-rules-count').textContent = data.localRulesCount || 0;
}
// 合并所有本地规则 // 合并所有本地规则
let rules = []; let rules = [];
// 添加域名规则 // 添加域名规则
@@ -89,6 +94,51 @@ async function loadLocalRules() {
} }
} }
// 加载远程规则
async function loadRemoteRules() {
showLoading('加载远程规则...');
try {
const response = await fetch('/api/shield/remoterules');
if (!response.ok) {
throw new Error(`加载失败: ${response.status}`);
}
const data = await response.json();
// 更新远程规则数量显示
if (document.getElementById('remote-rules-count')) {
document.getElementById('remote-rules-count').textContent = data.remoteRulesCount || 0;
}
// 合并所有远程规则
let rules = [];
// 添加域名规则
if (Array.isArray(data.domainRules)) {
rules = rules.concat(data.domainRules);
}
// 添加域名排除规则
if (Array.isArray(data.domainExceptions)) {
rules = rules.concat(data.domainExceptions);
}
// 添加正则规则
if (Array.isArray(data.regexRules)) {
rules = rules.concat(data.regexRules);
}
// 添加正则排除规则
if (Array.isArray(data.regexExceptions)) {
rules = rules.concat(data.regexExceptions);
}
updateRulesTable(rules);
hideLoading();
} catch (error) {
console.error('加载远程规则失败:', error);
showErrorMessage('加载远程规则失败');
hideLoading();
}
}
// 更新规则表格 // 更新规则表格
function updateRulesTable(rules) { function updateRulesTable(rules) {
const tbody = document.getElementById('rules-table-body'); const tbody = document.getElementById('rules-table-body');
@@ -416,6 +466,15 @@ function setupShieldEventListeners() {
// 远程黑名单管理事件 // 远程黑名单管理事件
document.getElementById('save-blacklist-btn').addEventListener('click', handleAddBlacklist); document.getElementById('save-blacklist-btn').addEventListener('click', handleAddBlacklist);
// 添加切换查看本地规则和远程规则的事件监听
if (document.getElementById('view-local-rules-btn')) {
document.getElementById('view-local-rules-btn').addEventListener('click', loadLocalRules);
}
if (document.getElementById('view-remote-rules-btn')) {
document.getElementById('view-remote-rules-btn').addEventListener('click', loadRemoteRules);
}
} }
// 显示成功消息 // 显示成功消息