From 45ed4d0d6b0146103d7ff3a432c241a5e30d18ea Mon Sep 17 00:00:00 2001 From: Alex Yang Date: Fri, 28 Nov 2025 00:42:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86API=E6=96=AD?= =?UTF-8?q?=E7=94=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ReadMe.md | 81 ---------------------------- http/server.go | 21 ++++++++ rules.txt | 5 -- shield/manager.go | 125 ++++++++++++++++++++++++++++++++++++++++++++ static/js/shield.js | 61 ++++++++++++++++++++- 5 files changed, 206 insertions(+), 87 deletions(-) delete mode 100644 ReadMe.md delete mode 100644 rules.txt diff --git a/ReadMe.md b/ReadMe.md deleted file mode 100644 index 73b8109..0000000 --- a/ReadMe.md +++ /dev/null @@ -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查询结果的各种网络环境。 \ No newline at end of file diff --git a/http/server.go b/http/server.go index 5b9dfc9..63510e4 100644 --- a/http/server.go +++ b/http/server.go @@ -66,6 +66,24 @@ func (s *Server) Start() error { if s.config.EnableAPI { mux.HandleFunc("/api/stats", s.handleStats) 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/blacklists", s.handleShieldBlacklists) 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) { w.Header().Set("Content-Type", "application/json") + // 默认处理逻辑 switch r.Method { case http.MethodGet: // 检查是否需要返回完整规则列表 @@ -619,6 +638,8 @@ func (s *Server) handleShield(w http.ResponseWriter, r *http.Request) { } json.NewEncoder(w).Encode(shieldInfo) return + } + switch r.Method { case http.MethodPost: // 添加屏蔽规则 var req struct { diff --git a/rules.txt b/rules.txt deleted file mode 100644 index bd67aa8..0000000 --- a/rules.txt +++ /dev/null @@ -1,5 +0,0 @@ -||hm.baidu.com -||baidu.com -/.*tracking.*/ -/adjust.net/ -/ad./ \ No newline at end of file diff --git a/shield/manager.go b/shield/manager.go index 56513f1..32c53e5 100644 --- a/shield/manager.go +++ b/shield/manager.go @@ -1275,6 +1275,131 @@ func (m *ShieldManager) GetHostsCount() int { 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 获取所有规则 func (m *ShieldManager) GetRules() map[string]interface{} { m.rulesMutex.RLock() diff --git a/static/js/shield.js b/static/js/shield.js index 240dc45..0b9b35d 100644 --- a/static/js/shield.js +++ b/static/js/shield.js @@ -53,7 +53,7 @@ async function loadShieldStats() { async function loadLocalRules() { showLoading('加载本地规则...'); try { - const response = await fetch('/api/shield?all=true'); + const response = await fetch('/api/shield/localrules'); if (!response.ok) { throw new Error(`加载失败: ${response.status}`); @@ -61,6 +61,11 @@ async function loadLocalRules() { const data = await response.json(); + // 更新本地规则数量显示 + if (document.getElementById('local-rules-count')) { + document.getElementById('local-rules-count').textContent = data.localRulesCount || 0; + } + // 合并所有本地规则 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) { const tbody = document.getElementById('rules-table-body'); @@ -416,6 +466,15 @@ function setupShieldEventListeners() { // 远程黑名单管理事件 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); + } } // 显示成功消息