优化web显示
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
"name": "CHN-anti-AD",
|
||||
"url": "https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-Filters/raw/branch/main/list/easylist.txt",
|
||||
"enabled": true,
|
||||
"lastUpdateTime": "2025-11-28T15:26:24.833Z"
|
||||
"lastUpdateTime": "2025-12-16T08:50:10.180Z"
|
||||
},
|
||||
{
|
||||
"name": "My GitHub Rules",
|
||||
|
||||
BIN
dns-server
BIN
dns-server
Binary file not shown.
@@ -58,6 +58,7 @@ type QueryLog struct {
|
||||
BlockType string // 屏蔽类型(如果被屏蔽)
|
||||
FromCache bool // 是否来自缓存
|
||||
DNSSEC bool // 是否使用了DNSSEC
|
||||
EDNS bool // 是否使用了EDNS
|
||||
}
|
||||
|
||||
// StatsData 用于持久化的统计数据结构
|
||||
@@ -352,7 +353,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
})
|
||||
|
||||
// 添加查询日志
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "error", "", "", false, false)
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "error", "", "", false, false, true)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -369,7 +370,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
})
|
||||
|
||||
// 添加查询日志
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", false, false)
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", false, false, true)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -391,7 +392,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
})
|
||||
|
||||
// 添加查询日志
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "blocked", blockRule, blockType, false, false)
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "blocked", blockRule, blockType, false, false, true)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -420,7 +421,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
cachedResponseCopy := cachedResponse.Copy() // 创建响应副本避免并发修改问题
|
||||
cachedResponseCopy.Id = r.Id // 更新ID以匹配请求
|
||||
cachedResponseCopy.Compress = true
|
||||
|
||||
|
||||
// 如果客户端请求包含EDNS记录,确保响应也包含EDNS
|
||||
if opt := r.IsEdns0(); opt != nil {
|
||||
// 检查响应是否已经包含EDNS记录
|
||||
@@ -442,7 +443,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
w.WriteMsg(cachedResponseCopy)
|
||||
|
||||
// 计算响应时间
|
||||
@@ -464,7 +465,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
}
|
||||
|
||||
// 添加查询日志 - 标记为缓存
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", true, cachedDNSSEC)
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", true, cachedDNSSEC, true)
|
||||
logger.Debug("从缓存返回DNS响应", "domain", domain, "type", queryType, "dnssec", cachedDNSSEC)
|
||||
return
|
||||
}
|
||||
@@ -493,7 +494,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 写入响应给客户端
|
||||
w.WriteMsg(response)
|
||||
}
|
||||
@@ -540,7 +541,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
}
|
||||
|
||||
// 添加查询日志 - 标记为实时
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", false, responseDNSSEC)
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", false, responseDNSSEC, true)
|
||||
}
|
||||
|
||||
// handleHostsResponse 处理hosts文件匹配的响应
|
||||
@@ -1093,7 +1094,7 @@ func (s *Server) updateStats(update func(*Stats)) {
|
||||
}
|
||||
|
||||
// addQueryLog 添加查询日志
|
||||
func (s *Server) addQueryLog(clientIP, domain, queryType string, responseTime int64, result, blockRule, blockType string, fromCache, dnssec bool) {
|
||||
func (s *Server) addQueryLog(clientIP, domain, queryType string, responseTime int64, result, blockRule, blockType string, fromCache, dnssec, edns bool) {
|
||||
// 获取IP地理位置
|
||||
location := s.getIpGeolocation(clientIP)
|
||||
|
||||
@@ -1110,6 +1111,7 @@ func (s *Server) addQueryLog(clientIP, domain, queryType string, responseTime in
|
||||
BlockType: blockType,
|
||||
FromCache: fromCache,
|
||||
DNSSEC: dnssec,
|
||||
EDNS: edns,
|
||||
}
|
||||
|
||||
// 添加到日志列表
|
||||
|
||||
37528
logs/dns-server.log
37528
logs/dns-server.log
File diff suppressed because it is too large
Load Diff
@@ -1,28 +0,0 @@
|
||||
time="2025-12-16T00:37:59+08:00" level=debug msg="尝试加载Shield统计数据" file=/root/dns/data/test_shield_stats.json
|
||||
time="2025-12-16T00:37:59+08:00" level=info msg="Shield计数数据加载成功" blocked_entries=0 resolved_entries=0
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="规则加载完成,域名规则: 122426, 排除规则: 654, 正则规则: 473, hosts规则: 0"
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="统计数据加载成功"
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="查询日志加载成功" count=118
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="DNS服务器已启动,监听端口: 5353"
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="HTTP控制台已启动,监听端口: 8081"
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="DNS TCP服务器启动,监听端口: 5353"
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="启动统计数据自动保存功能" file=data/test_stats.json interval=300
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="DNS UDP服务器启动,监听端口: 5353"
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="启动Shield计数数据自动保存功能" file=./data/test_shield_stats.json interval=60
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="规则自动更新已启动" interval=3600
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="HTTP控制台服务器启动,监听地址: 0.0.0.0:8081"
|
||||
time="2025-12-16T00:38:00+08:00" level=info msg="Shield计数数据保存成功" blocked_entries=0 file=/root/dns/data/test_shield_stats.json resolved_entries=0
|
||||
time="2025-12-16T00:38:14+08:00" level=debug msg="接收到DNS查询" client="127.0.0.1:52388" domain=google.com type=A
|
||||
time="2025-12-16T00:38:14+08:00" level=debug msg="DNS响应不包含DNSSEC记录" domain=google.com server="223.5.5.5:53"
|
||||
time="2025-12-16T00:38:14+08:00" level=debug msg="DNS查询成功" domain=google.com rtt=6.030332ms server="223.5.5.5:53"
|
||||
time="2025-12-16T00:38:14+08:00" level=debug msg="DNS响应已缓存" domain=google.com ttl=30m0s type=A
|
||||
time="2025-12-16T00:38:44+08:00" level=info msg="正在关闭服务..."
|
||||
time="2025-12-16T00:38:44+08:00" level=info msg="统计数据保存成功" file=/root/dns/data/test_stats.json
|
||||
time="2025-12-16T00:38:44+08:00" level=info msg="查询日志保存成功" file=/root/dns/data/querylog.json
|
||||
time="2025-12-16T00:38:44+08:00" level=info msg="DNS服务器已停止"
|
||||
time="2025-12-16T00:38:44+08:00" level=error msg="HTTP控制台服务器启动失败" error="http: Server closed"
|
||||
time="2025-12-16T00:38:44+08:00" level=info msg="HTTP控制台服务器已停止"
|
||||
time="2025-12-16T00:38:44+08:00" level=info msg="Shield计数数据保存成功" blocked_entries=0 file=/root/dns/data/test_shield_stats.json resolved_entries=0
|
||||
time="2025-12-16T00:38:44+08:00" level=info msg="规则自动更新已停止"
|
||||
time="2025-12-16T00:38:44+08:00" level=info msg="服务已关闭"
|
||||
time="2025-12-16T00:38:44+08:00" level=warning msg="日志系统已关闭"
|
||||
18
package.json
Normal file
18
package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "dns-server-console",
|
||||
"version": "1.0.0",
|
||||
"description": "DNS服务器Web控制台",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tailwindcss": "^3.3.3",
|
||||
"font-awesome": "^4.7.0",
|
||||
"chart.js": "^4.4.8"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"keywords": ["dns", "server", "console", "web"],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
@@ -33,6 +33,203 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/login": {
|
||||
"post": {
|
||||
"summary": "用户登录",
|
||||
"description": "使用用户名和密码登录DNS服务器API。",
|
||||
"tags": ["auth"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"type": "string", "description": "用户名"},
|
||||
"password": {"type": "string", "description": "密码"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"username": "admin",
|
||||
"password": "admin"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "登录成功",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"type": "string", "description": "操作状态"},
|
||||
"message": {"type": "string", "description": "操作信息"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"status": "success",
|
||||
"message": "登录成功"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "请求参数错误",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"error": "无效的请求体"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "用户名或密码错误",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"error": "用户名或密码错误"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logout": {
|
||||
"post": {
|
||||
"summary": "用户注销",
|
||||
"description": "注销当前登录的用户会话。",
|
||||
"tags": ["auth"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "注销成功",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"type": "string", "description": "操作状态"},
|
||||
"message": {"type": "string", "description": "操作信息"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"status": "success",
|
||||
"message": "注销成功"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/change-password": {
|
||||
"post": {
|
||||
"summary": "修改密码",
|
||||
"description": "修改当前登录用户的密码。",
|
||||
"tags": ["auth"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"currentPassword": {"type": "string", "description": "当前密码"},
|
||||
"newPassword": {"type": "string", "description": "新密码"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"currentPassword": "admin",
|
||||
"newPassword": "newpassword"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "密码修改成功",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"type": "string", "description": "操作状态"},
|
||||
"message": {"type": "string", "description": "操作信息"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"status": "success",
|
||||
"message": "密码修改成功"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "请求参数错误",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"error": "无效的请求体"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "当前密码错误",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"error": "当前密码错误"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "服务器内部错误",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"error": "保存密码失败"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/stats": {
|
||||
"get": {
|
||||
"summary": "获取系统统计信息",
|
||||
@@ -58,7 +255,11 @@
|
||||
"TotalResponseTime": {"type": "number", "description": "总响应时间(毫秒)"},
|
||||
"QueryTypes": {"type": "object", "description": "查询类型统计"},
|
||||
"SourceIPs": {"type": "object", "description": "来源IP统计"},
|
||||
"CpuUsage": {"type": "number", "description": "CPU使用率(百分比)"}
|
||||
"CpuUsage": {"type": "number", "description": "CPU使用率(百分比)"},
|
||||
"DNSSECQueries": {"type": "integer", "description": "DNSSEC查询次数"},
|
||||
"DNSSECSuccess": {"type": "integer", "description": "DNSSEC成功次数"},
|
||||
"DNSSECFailed": {"type": "integer", "description": "DNSSEC失败次数"},
|
||||
"DNSSECEnabled": {"type": "boolean", "description": "是否启用DNSSEC"}
|
||||
}
|
||||
},
|
||||
"shield": {"type": "object", "description": "Shield统计信息"},
|
||||
@@ -66,6 +267,11 @@
|
||||
"activeIPs": {"type": "integer", "description": "活跃IP数量"},
|
||||
"avgResponseTime": {"type": "number", "description": "平均响应时间(毫秒)"},
|
||||
"cpuUsage": {"type": "number", "description": "CPU使用率(百分比)"},
|
||||
"dnssecEnabled": {"type": "boolean", "description": "是否启用DNSSEC"},
|
||||
"dnssecQueries": {"type": "integer", "description": "DNSSEC查询次数"},
|
||||
"dnssecSuccess": {"type": "integer", "description": "DNSSEC成功次数"},
|
||||
"dnssecFailed": {"type": "integer", "description": "DNSSEC失败次数"},
|
||||
"dnssecUsage": {"type": "number", "description": "DNSSEC使用率(百分比)"},
|
||||
"time": {"type": "string", "description": "统计时间"}
|
||||
}
|
||||
},
|
||||
@@ -82,13 +288,22 @@
|
||||
"TotalResponseTime": 15625,
|
||||
"QueryTypes": {"A": 850, "AAAA": 250, "CNAME": 150},
|
||||
"SourceIPs": {"192.168.1.100": 500, "192.168.1.101": 750},
|
||||
"CpuUsage": 0.15
|
||||
"CpuUsage": 0.15,
|
||||
"DNSSECQueries": 500,
|
||||
"DNSSECSuccess": 480,
|
||||
"DNSSECFailed": 20,
|
||||
"DNSSECEnabled": true
|
||||
},
|
||||
"shield": {},
|
||||
"topQueryType": "A",
|
||||
"activeIPs": 2,
|
||||
"avgResponseTime": 12.5,
|
||||
"cpuUsage": 0.15,
|
||||
"dnssecEnabled": true,
|
||||
"dnssecQueries": 500,
|
||||
"dnssecSuccess": 480,
|
||||
"dnssecFailed": 20,
|
||||
"dnssecUsage": 40.0,
|
||||
"time": "2023-07-15T14:30:45Z"
|
||||
}
|
||||
}
|
||||
@@ -274,20 +489,16 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hour": {"type": "string", "description": "小时"},
|
||||
"queries": {"type": "integer", "description": "查询次数"},
|
||||
"blocked": {"type": "integer", "description": "被阻止次数"}
|
||||
}
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"labels": {"type": "array", "items": {"type": "string"}, "description": "小时标签"},
|
||||
"data": {"type": "array", "items": {"type": "integer"}, "description": "查询次数数据"}
|
||||
}
|
||||
},
|
||||
"example": [
|
||||
{"hour": "00", "queries": 120, "blocked": 20},
|
||||
{"hour": "01", "queries": 90, "blocked": 15}
|
||||
]
|
||||
"example": {
|
||||
"labels": ["15:00", "16:00", "17:00"],
|
||||
"data": [120, 90, 150]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,20 +516,16 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"date": {"type": "string", "description": "日期"},
|
||||
"queries": {"type": "integer", "description": "查询次数"},
|
||||
"blocked": {"type": "integer", "description": "被阻止次数"}
|
||||
}
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"labels": {"type": "array", "items": {"type": "string"}, "description": "日期标签"},
|
||||
"data": {"type": "array", "items": {"type": "integer"}, "description": "查询次数数据"}
|
||||
}
|
||||
},
|
||||
"example": [
|
||||
{"date": "2023-07-09", "queries": 2500, "blocked": 450},
|
||||
{"date": "2023-07-10", "queries": 2700, "blocked": 480}
|
||||
]
|
||||
"example": {
|
||||
"labels": ["01-02", "01-03", "01-04"],
|
||||
"data": [2500, 2700, 2300]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,20 +543,16 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"date": {"type": "string", "description": "日期"},
|
||||
"queries": {"type": "integer", "description": "查询次数"},
|
||||
"blocked": {"type": "integer", "description": "被阻止次数"}
|
||||
}
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"labels": {"type": "array", "items": {"type": "string"}, "description": "日期标签"},
|
||||
"data": {"type": "array", "items": {"type": "integer"}, "description": "查询次数数据"}
|
||||
}
|
||||
},
|
||||
"example": [
|
||||
{"date": "2023-06-15", "queries": 2500, "blocked": 450},
|
||||
{"date": "2023-06-16", "queries": 2700, "blocked": 480}
|
||||
]
|
||||
"example": {
|
||||
"labels": ["01-01", "01-02", "01-03"],
|
||||
"data": [2500, 2700, 2300]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -387,30 +590,157 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/shield": {
|
||||
"/logs/stats": {
|
||||
"get": {
|
||||
"summary": "获取Shield配置",
|
||||
"description": "获取Shield的完整配置信息,包括启用状态、规则等。",
|
||||
"tags": ["shield"],
|
||||
"summary": "获取日志统计信息",
|
||||
"description": "获取DNS查询日志的统计信息。",
|
||||
"tags": ["logs"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功获取配置信息",
|
||||
"description": "成功获取日志统计信息",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"description": "日志统计信息"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/query": {
|
||||
"get": {
|
||||
"summary": "查询日志",
|
||||
"description": "根据条件查询DNS查询日志。",
|
||||
"tags": ["logs"],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"default": 100
|
||||
},
|
||||
"description": "返回结果数量限制"
|
||||
},
|
||||
{
|
||||
"name": "offset",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"default": 0
|
||||
},
|
||||
"description": "结果偏移量"
|
||||
},
|
||||
{
|
||||
"name": "sort",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "排序字段"
|
||||
},
|
||||
{
|
||||
"name": "direction",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "排序方向"
|
||||
},
|
||||
{
|
||||
"name": "result",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "查询结果过滤"
|
||||
},
|
||||
{
|
||||
"name": "search",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "搜索关键词"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功查询日志",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "日志条目"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/logs/count": {
|
||||
"get": {
|
||||
"summary": "获取日志总数",
|
||||
"description": "获取DNS查询日志的总数。",
|
||||
"tags": ["logs"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功获取日志总数",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {"type": "boolean", "description": "是否启用Shield"},
|
||||
"rulesCount": {"type": "integer", "description": "规则数量"},
|
||||
"lastUpdate": {"type": "string", "description": "最后更新时间"},
|
||||
"blacklists": {"type": "array", "description": "黑名单列表", "items": {"type": "object"}}
|
||||
"count": {"type": "integer", "description": "日志总数"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"enabled": true,
|
||||
"rulesCount": 5000,
|
||||
"lastUpdate": "2023-07-15T10:00:00Z",
|
||||
"blacklists": []
|
||||
"count": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/shield": {
|
||||
"get": {
|
||||
"summary": "获取Shield配置和统计信息",
|
||||
"description": "获取Shield的配置信息和规则统计,包括更新间隔、屏蔽方法、黑名单数量等。",
|
||||
"tags": ["shield"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功获取配置和统计信息",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"updateInterval": {"type": "integer", "description": "更新间隔(秒)"},
|
||||
"blockMethod": {"type": "string", "description": "屏蔽方法"},
|
||||
"blacklistCount": {"type": "integer", "description": "黑名单数量"},
|
||||
"domainRulesCount": {"type": "integer", "description": "域名规则数量"},
|
||||
"domainExceptionsCount": {"type": "integer", "description": "域名例外规则数量"},
|
||||
"regexRulesCount": {"type": "integer", "description": "正则规则数量"},
|
||||
"regexExceptionsCount": {"type": "integer", "description": "正则例外规则数量"},
|
||||
"hostsRulesCount": {"type": "integer", "description": "Hosts规则数量"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"updateInterval": 3600,
|
||||
"blockMethod": "NXDOMAIN",
|
||||
"blacklistCount": 4,
|
||||
"domainRulesCount": 1000,
|
||||
"domainExceptionsCount": 100,
|
||||
"regexRulesCount": 50,
|
||||
"regexExceptionsCount": 10,
|
||||
"hostsRulesCount": 200
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,8 +762,8 @@
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"summary": "更新Shield配置",
|
||||
"description": "更新Shield的全局配置信息。",
|
||||
"summary": "添加屏蔽规则",
|
||||
"description": "添加新的屏蔽规则到Shield。",
|
||||
"tags": ["shield"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
@@ -442,20 +772,18 @@
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {"type": "boolean", "description": "是否启用Shield"},
|
||||
"updateInterval": {"type": "integer", "description": "更新间隔(秒)"}
|
||||
"rule": {"type": "string", "description": "屏蔽规则"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"enabled": true,
|
||||
"updateInterval": 3600
|
||||
"rule": "example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功更新配置",
|
||||
"description": "成功添加规则",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
@@ -492,19 +820,35 @@
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {"error": "更新配置失败"}
|
||||
"example": {"error": "添加规则失败"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"summary": "重启Shield",
|
||||
"description": "重新加载和应用Shield规则。",
|
||||
"delete": {
|
||||
"summary": "删除屏蔽规则",
|
||||
"description": "从Shield中删除指定的屏蔽规则。",
|
||||
"tags": ["shield"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"rule": {"type": "string", "description": "要删除的屏蔽规则"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"rule": "example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功重启Shield",
|
||||
"description": "成功删除规则",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
@@ -517,6 +861,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "请求参数错误",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {"error": "参数格式错误"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "服务器内部错误",
|
||||
"content": {
|
||||
@@ -527,7 +885,46 @@
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {"error": "重启失败"}
|
||||
"example": {"error": "删除规则失败"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"summary": "重新加载规则",
|
||||
"description": "重新加载和应用Shield规则。",
|
||||
"tags": ["shield"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功重新加载规则",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"type": "string", "description": "操作状态"},
|
||||
"message": {"type": "string", "description": "操作信息"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"status": "success",
|
||||
"message": "规则重新加载成功"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "服务器内部错误",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {"error": "重新加载规则失败"}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1139,7 +1536,7 @@
|
||||
"/status": {
|
||||
"get": {
|
||||
"summary": "获取服务器状态",
|
||||
"description": "获取DNS服务器的状态信息。",
|
||||
"description": "获取DNS服务器的状态信息,包括查询统计、运行时间等。",
|
||||
"tags": ["server"],
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -1150,14 +1547,32 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"type": "string", "description": "服务器状态"},
|
||||
"uptime": {"type": "integer", "description": "运行时间(秒)"},
|
||||
"version": {"type": "string", "description": "服务器版本"}
|
||||
"queries": {"type": "integer", "description": "总查询次数"},
|
||||
"blocked": {"type": "integer", "description": "被阻止的查询次数"},
|
||||
"allowed": {"type": "integer", "description": "允许的查询次数"},
|
||||
"errors": {"type": "integer", "description": "错误查询次数"},
|
||||
"lastQuery": {"type": "string", "description": "最近一次查询时间"},
|
||||
"avgResponseTime": {"type": "number", "description": "平均响应时间(毫秒)"},
|
||||
"activeIPs": {"type": "integer", "description": "活跃IP数量"},
|
||||
"startTime": {"type": "string", "description": "服务器启动时间"},
|
||||
"uptime": {"type": "integer", "description": "运行时间(毫秒)"},
|
||||
"cpuUsage": {"type": "number", "description": "CPU使用率(百分比)"},
|
||||
"timestamp": {"type": "string", "description": "当前时间"}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"status": "running",
|
||||
"uptime": 3600,
|
||||
"version": "1.0.0"
|
||||
"queries": 1250,
|
||||
"blocked": 230,
|
||||
"allowed": 1020,
|
||||
"errors": 0,
|
||||
"lastQuery": "2023-07-15T14:30:45Z",
|
||||
"avgResponseTime": 12.5,
|
||||
"activeIPs": 2,
|
||||
"startTime": "2023-07-15T10:00:00Z",
|
||||
"uptime": 16200000,
|
||||
"cpuUsage": 0.15,
|
||||
"timestamp": "2023-07-15T14:30:45Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1168,7 +1583,7 @@
|
||||
"/config": {
|
||||
"get": {
|
||||
"summary": "获取服务器配置",
|
||||
"description": "获取DNS服务器的配置信息。",
|
||||
"description": "获取DNS服务器的配置信息,包括Shield配置。",
|
||||
"tags": ["server"],
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -1178,13 +1593,30 @@
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"port": {"type": "integer", "description": "服务器端口"},
|
||||
"logLevel": {"type": "string", "description": "日志级别"}
|
||||
"shield": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"blockMethod": {"type": "string", "description": "屏蔽方法"},
|
||||
"customBlockIP": {"type": "string", "description": "自定义屏蔽IP"},
|
||||
"blacklists": {"type": "array", "description": "黑名单列表", "items": {"type": "object"}},
|
||||
"updateInterval": {"type": "integer", "description": "更新间隔(秒)"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"port": 53,
|
||||
"logLevel": "info"
|
||||
"shield": {
|
||||
"blockMethod": "NXDOMAIN",
|
||||
"customBlockIP": "",
|
||||
"blacklists": [
|
||||
{
|
||||
"name": "AdGuard DNS filter",
|
||||
"url": "https://example.com/ads.txt",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"updateInterval": 3600
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1193,7 +1625,7 @@
|
||||
},
|
||||
"post": {
|
||||
"summary": "更新服务器配置",
|
||||
"description": "更新DNS服务器的配置信息。",
|
||||
"description": "更新DNS服务器的配置信息,包括Shield配置。",
|
||||
"tags": ["server"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
@@ -1202,13 +1634,30 @@
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"port": {"type": "integer", "description": "服务器端口"},
|
||||
"logLevel": {"type": "string", "description": "日志级别"}
|
||||
"shield": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"blockMethod": {"type": "string", "description": "屏蔽方法"},
|
||||
"customBlockIP": {"type": "string", "description": "自定义屏蔽IP"},
|
||||
"blacklists": {"type": "array", "description": "黑名单列表", "items": {"type": "object"}},
|
||||
"updateInterval": {"type": "integer", "description": "更新间隔(秒)"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
"port": 53,
|
||||
"logLevel": "info"
|
||||
"shield": {
|
||||
"blockMethod": "NXDOMAIN",
|
||||
"customBlockIP": "",
|
||||
"blacklists": [
|
||||
{
|
||||
"name": "AdGuard DNS filter",
|
||||
"url": "https://example.com/ads.txt",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"updateInterval": 3600
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1221,10 +1670,14 @@
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"type": "string", "description": "操作状态"}
|
||||
"success": {"type": "boolean", "description": "是否成功"},
|
||||
"message": {"type": "string", "description": "操作信息"}
|
||||
}
|
||||
},
|
||||
"example": {"status": "success"}
|
||||
"example": {
|
||||
"success": true,
|
||||
"message": "配置已更新"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1238,7 +1691,9 @@
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {"error": "参数格式错误"}
|
||||
"example": {
|
||||
"error": "无效的请求体"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1252,7 +1707,9 @@
|
||||
"error": {"type": "string", "description": "错误信息"}
|
||||
}
|
||||
},
|
||||
"example": {"error": "更新配置失败"}
|
||||
"example": {
|
||||
"error": "保存配置失败"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1298,6 +1755,10 @@
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "auth",
|
||||
"description": "认证相关API"
|
||||
},
|
||||
{
|
||||
"name": "stats",
|
||||
"description": "统计相关API"
|
||||
@@ -1309,6 +1770,10 @@
|
||||
{
|
||||
"name": "server",
|
||||
"description": "服务器相关API"
|
||||
},
|
||||
{
|
||||
"name": "logs",
|
||||
"description": "日志相关API"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -399,7 +399,7 @@ function updateLogsTable(logs) {
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm">
|
||||
<div class="font-medium">${log.Domain}</div>
|
||||
<div class="text-xs text-gray-500 mt-1">类型: ${log.QueryType}, <span class="${statusClass}">${statusText}</span>, <span class="${cacheStatusClass}">${log.FromCache ? '缓存' : '实时'}</span>${log.DNSSEC ? ', <span class="text-green-500"><i class="fa fa-lock"></i> DNSSEC</span>' : ''}</div>
|
||||
<div class="text-xs text-gray-500 mt-1">类型: ${log.QueryType}, <span class="${statusClass}">${statusText}</span>, <span class="${cacheStatusClass}">${log.FromCache ? '缓存' : '实时'}</span>${log.DNSSEC ? ', <span class="text-green-500"><i class="fa fa-lock"></i> DNSSEC</span>' : ''}${log.EDNS ? ', <span class="text-blue-500"><i class="fa fa-exchange"></i> EDNS</span>' : ''}</div>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm">${log.ResponseTime}ms</td>
|
||||
<td class="py-3 px-4 text-sm text-gray-500">${log.BlockRule || '-'}</td>
|
||||
|
||||
24
tailwind.config.js
Normal file
24
tailwind.config.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./static/**/*.{html,js}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: '#165DFF',
|
||||
secondary: '#36CFFB',
|
||||
success: '#00B42A',
|
||||
warning: '#FF7D00',
|
||||
danger: '#F53F3F',
|
||||
info: '#86909C',
|
||||
dark: '#1D2129',
|
||||
light: '#F2F3F5',
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
Reference in New Issue
Block a user