增加了API断电
This commit is contained in:
81
ReadMe.md
81
ReadMe.md
@@ -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查询结果的各种网络环境。
|
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示成功消息
|
// 显示成功消息
|
||||||
|
|||||||
Reference in New Issue
Block a user