实现日志详情域名信息显示
This commit is contained in:
18
config.json
18
config.json
@@ -2,7 +2,7 @@
|
||||
"dns": {
|
||||
"port": 53,
|
||||
"upstreamDNS": [
|
||||
"223.5.5.5:53"
|
||||
"10.35.10.200"
|
||||
],
|
||||
"dnssecUpstreamDNS": [
|
||||
"117.50.10.10",
|
||||
@@ -11,18 +11,26 @@
|
||||
"208.67.220.220",
|
||||
"208.67.222.222"
|
||||
],
|
||||
"timeout": 5,
|
||||
"saveInterval": 30,
|
||||
"cacheTTL": 10,
|
||||
"enableDNSSEC": true,
|
||||
"queryMode": "parallel",
|
||||
"domainSpecificDNS": {
|
||||
"addr.arpa": [
|
||||
"10.35.10.200:53"
|
||||
],
|
||||
"akadns": [
|
||||
"4.2.2.1:53"
|
||||
],
|
||||
"akamai": [
|
||||
"4.2.2.1:53"
|
||||
],
|
||||
"amazehome.cn": [
|
||||
"10.35.10.200:53"
|
||||
],
|
||||
"amazehome.xyz": [
|
||||
"10.35.10.200:53"
|
||||
],
|
||||
"microsoft.com": [
|
||||
"4.2.2.1:53"
|
||||
],
|
||||
@@ -31,7 +39,9 @@
|
||||
]
|
||||
},
|
||||
"noDNSSECDomains": [
|
||||
"amazehome.cn",
|
||||
"addr.arpa",
|
||||
"amazehome.xyz",
|
||||
".cn"
|
||||
],
|
||||
"enableIPv6": false
|
||||
@@ -67,7 +77,7 @@
|
||||
"name": "My GitHub Rules",
|
||||
"url": "https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/rules/costomize.txt",
|
||||
"enabled": true,
|
||||
"lastUpdateTime": "2025-12-24T07:11:16.596Z"
|
||||
"lastUpdateTime": "2025-12-26T11:32:28.843Z"
|
||||
},
|
||||
{
|
||||
"name": "CNList",
|
||||
@@ -139,4 +149,4 @@
|
||||
"maxBackups": 10,
|
||||
"maxAge": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ type DNSConfig struct {
|
||||
Port int `json:"port"`
|
||||
UpstreamDNS []string `json:"upstreamDNS"`
|
||||
DNSSECUpstreamDNS []string `json:"dnssecUpstreamDNS"` // 用于DNSSEC查询的专用服务器
|
||||
Timeout int `json:"timeout"`
|
||||
SaveInterval int `json:"saveInterval"` // 数据保存间隔(秒)
|
||||
CacheTTL int `json:"cacheTTL"` // DNS缓存过期时间(分钟)
|
||||
EnableDNSSEC bool `json:"enableDNSSEC"` // 是否启用DNSSEC支持
|
||||
@@ -87,9 +86,6 @@ func LoadConfig(path string) (*Config, error) {
|
||||
if config.DNS.Port == 0 {
|
||||
config.DNS.Port = 53
|
||||
}
|
||||
if config.DNS.Timeout == 0 {
|
||||
config.DNS.Timeout = 5000 // 默认超时时间为5000毫秒
|
||||
}
|
||||
if len(config.DNS.UpstreamDNS) == 0 {
|
||||
config.DNS.UpstreamDNS = []string{"223.5.5.5:53", "223.6.6.6:53"}
|
||||
}
|
||||
|
||||
109
dns/server.go
109
dns/server.go
@@ -184,7 +184,6 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie
|
||||
shieldManager: shieldManager,
|
||||
resolver: &dns.Client{
|
||||
Net: "udp",
|
||||
Timeout: time.Duration(config.Timeout) * time.Millisecond,
|
||||
UDPSize: 4096, // 增加UDP缓冲区大小,支持更大的DNSSEC响应
|
||||
},
|
||||
ctx: ctx,
|
||||
@@ -864,10 +863,6 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
responses := make(chan serverResponse, len(selectedUpstreamDNS))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 超时上下文
|
||||
timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// 向所有上游服务器并行发送请求
|
||||
for _, upstream := range selectedUpstreamDNS {
|
||||
wg.Add(1)
|
||||
@@ -876,15 +871,7 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
|
||||
// 发送请求并获取响应,确保服务器地址包含端口号
|
||||
response, rtt, err := s.resolver.Exchange(r, normalizeDNSServerAddress(server))
|
||||
|
||||
select {
|
||||
case responses <- serverResponse{response, rtt, server, err}:
|
||||
// 成功发送响应
|
||||
case <-timeoutCtx.Done():
|
||||
// 超时,忽略此响应
|
||||
logger.Debug("并行请求超时", "server", server, "domain", domain)
|
||||
return
|
||||
}
|
||||
responses <- serverResponse{response, rtt, server, err}
|
||||
}(upstream)
|
||||
}
|
||||
|
||||
@@ -894,7 +881,7 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
close(responses)
|
||||
}()
|
||||
|
||||
// 处理所有响应
|
||||
// 处理所有响应,实现快速响应返回
|
||||
for resp := range responses {
|
||||
if resp.error == nil && resp.response != nil {
|
||||
// 更新服务器统计信息
|
||||
@@ -958,6 +945,8 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
hasDNSSECResponse = containsDNSSEC
|
||||
usedDNSServer = resp.server
|
||||
logger.Debug("使用用户配置的上游服务器响应", "domain", domain, "server", resp.server, "rtt", resp.rtt)
|
||||
// 快速返回:用户配置的主DNS服务器响应,立即返回
|
||||
continue
|
||||
} else if containsDNSSEC {
|
||||
// 非用户配置服务器,但有DNSSEC记录
|
||||
if !hasBestResponse || !isUserUpstream {
|
||||
@@ -968,6 +957,8 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
hasDNSSECResponse = true
|
||||
usedDNSServer = resp.server
|
||||
logger.Debug("找到带DNSSEC的最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt)
|
||||
// 快速返回:找到带DNSSEC的响应,立即返回
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// 非用户配置服务器,没有DNSSEC记录
|
||||
@@ -978,6 +969,8 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
hasBestResponse = true
|
||||
usedDNSServer = resp.server
|
||||
logger.Debug("找到最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt)
|
||||
// 快速返回:第一次找到成功响应,立即返回
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else if resp.response.Rcode == dns.RcodeNameError {
|
||||
@@ -991,6 +984,8 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
hasBestResponse = true
|
||||
usedDNSServer = resp.server
|
||||
logger.Debug("使用用户配置的上游服务器NXDOMAIN响应", "domain", domain, "server", resp.server, "rtt", resp.rtt)
|
||||
// 快速返回:用户配置的服务器NXDOMAIN响应,立即返回
|
||||
continue
|
||||
} else if !hasBestResponse || resp.rtt < bestRtt {
|
||||
// 非用户配置服务器,选择更快的响应
|
||||
bestResponse = resp.response
|
||||
@@ -998,6 +993,8 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
hasBestResponse = true
|
||||
usedDNSServer = resp.server
|
||||
logger.Debug("找到NXDOMAIN最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt)
|
||||
// 快速返回:找到NXDOMAIN响应,立即返回
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1061,10 +1058,6 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
triedServers = append(triedServers, selectedServer)
|
||||
logger.Debug("在负载均衡模式下选择服务器", "domain", domain, "server", selectedServer, "triedServers", triedServers)
|
||||
|
||||
// 设置超时上下文
|
||||
timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// 使用带超时的方式执行Exchange
|
||||
resultChan := make(chan struct {
|
||||
response *dns.Msg
|
||||
@@ -1085,12 +1078,9 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
var rtt time.Duration
|
||||
var err error
|
||||
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
response, rtt, err = result.response, result.rtt, result.err
|
||||
case <-timeoutCtx.Done():
|
||||
err = timeoutCtx.Err()
|
||||
}
|
||||
// 直接获取结果,不使用上下文超时
|
||||
result := <-resultChan
|
||||
response, rtt, err = result.response, result.rtt, result.err
|
||||
|
||||
if err == nil && response != nil {
|
||||
// 更新服务器统计信息
|
||||
@@ -1187,10 +1177,6 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
// 1. 选择最快的服务器
|
||||
fastestServer := s.selectFastestServer(selectedUpstreamDNS)
|
||||
if fastestServer != "" {
|
||||
// 设置超时上下文
|
||||
timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// 使用带超时的方式执行Exchange
|
||||
resultChan := make(chan struct {
|
||||
response *dns.Msg
|
||||
@@ -1211,12 +1197,9 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
var rtt time.Duration
|
||||
var err error
|
||||
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
response, rtt, err = result.response, result.rtt, result.err
|
||||
case <-timeoutCtx.Done():
|
||||
err = timeoutCtx.Err()
|
||||
}
|
||||
// 直接获取结果,不使用上下文超时
|
||||
result := <-resultChan
|
||||
response, rtt, err = result.response, result.rtt, result.err
|
||||
if err == nil && response != nil {
|
||||
// 更新服务器统计信息
|
||||
s.updateServerStats(fastestServer, true, rtt)
|
||||
@@ -1310,10 +1293,6 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
responses := make(chan serverResponse, len(selectedUpstreamDNS))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 超时上下文
|
||||
timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// 向所有上游服务器并行发送请求
|
||||
for _, upstream := range selectedUpstreamDNS {
|
||||
wg.Add(1)
|
||||
@@ -1322,30 +1301,17 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
|
||||
// 发送请求并获取响应
|
||||
response, rtt, err := s.resolver.Exchange(r, normalizeDNSServerAddress(server))
|
||||
|
||||
select {
|
||||
case responses <- serverResponse{response, rtt, server, err}:
|
||||
// 成功发送响应
|
||||
case <-timeoutCtx.Done():
|
||||
// 超时,忽略此响应
|
||||
logger.Debug("并行请求超时", "server", server, "domain", domain)
|
||||
return
|
||||
}
|
||||
responses <- serverResponse{response, rtt, server, err}
|
||||
}(upstream)
|
||||
}
|
||||
|
||||
// 等待所有请求完成或超时
|
||||
// 等待所有请求完成
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(responses)
|
||||
}()
|
||||
|
||||
// 等待上下文超时,防止泄漏
|
||||
go func() {
|
||||
<-timeoutCtx.Done()
|
||||
}()
|
||||
|
||||
// 处理所有响应
|
||||
// 处理所有响应,实现快速响应返回
|
||||
for resp := range responses {
|
||||
if resp.error == nil && resp.response != nil {
|
||||
|
||||
@@ -1397,6 +1363,8 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
}
|
||||
}
|
||||
logger.Debug("找到带DNSSEC的最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt)
|
||||
// 快速返回:找到带DNSSEC的响应,立即返回
|
||||
continue
|
||||
} else if !hasBestResponse {
|
||||
// 没有带DNSSEC的响应时,保存第一个成功响应
|
||||
bestResponse = resp.response
|
||||
@@ -1411,6 +1379,8 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
}
|
||||
}
|
||||
logger.Debug("找到最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt)
|
||||
// 快速返回:第一次找到成功响应,立即返回
|
||||
continue
|
||||
}
|
||||
} else if resp.response.Rcode == dns.RcodeNameError {
|
||||
// 处理NXDOMAIN响应
|
||||
@@ -1423,6 +1393,8 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
hasBestResponse = true
|
||||
usedDNSServer = resp.server
|
||||
logger.Debug("找到NXDOMAIN最佳响应", "domain", domain, "server", resp.server, "rtt", resp.rtt)
|
||||
// 快速返回:找到NXDOMAIN响应,立即返回
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1450,10 +1422,6 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
// 无论查询模式是什么,DNSSEC验证都只使用加权随机选择一个服务器
|
||||
selectedDnssecServer := s.selectWeightedRandomServer(dnssecServers)
|
||||
if selectedDnssecServer != "" {
|
||||
// 设置超时上下文
|
||||
timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// 使用带超时的方式执行Exchange
|
||||
resultChan := make(chan struct {
|
||||
response *dns.Msg
|
||||
@@ -1474,12 +1442,9 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
var rtt time.Duration
|
||||
var err error
|
||||
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
response, rtt, err = result.response, result.rtt, result.err
|
||||
case <-timeoutCtx.Done():
|
||||
err = timeoutCtx.Err()
|
||||
}
|
||||
// 直接获取结果,不使用上下文超时
|
||||
result := <-resultChan
|
||||
response, rtt, err = result.response, result.rtt, result.err
|
||||
|
||||
if err == nil && response != nil {
|
||||
// 更新服务器统计信息
|
||||
@@ -1548,10 +1513,6 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
// 选择一个upstreamDNS服务器进行解析(使用加权随机算法)
|
||||
localServer := s.selectWeightedRandomServer(s.config.UpstreamDNS)
|
||||
if localServer != "" {
|
||||
// 设置超时上下文
|
||||
timeoutCtx, cancel := context.WithTimeout(s.ctx, time.Duration(s.config.Timeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// 使用带超时的方式执行Exchange
|
||||
resultChan := make(chan struct {
|
||||
response *dns.Msg
|
||||
@@ -1572,12 +1533,10 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
|
||||
var rtt time.Duration
|
||||
var err error
|
||||
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
localResponse, rtt, err = result.response, result.rtt, result.err
|
||||
case <-timeoutCtx.Done():
|
||||
err = timeoutCtx.Err()
|
||||
}
|
||||
// 直接获取结果,不使用上下文超时
|
||||
result := <-resultChan
|
||||
localResponse, rtt, err = result.response, result.rtt, result.err
|
||||
|
||||
if err == nil && localResponse != nil {
|
||||
// 更新服务器统计信息
|
||||
s.updateServerStats(localServer, true, rtt)
|
||||
|
||||
@@ -1243,7 +1243,6 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) {
|
||||
"port": s.globalConfig.DNS.Port,
|
||||
"UpstreamServers": s.globalConfig.DNS.UpstreamDNS,
|
||||
"DNSSECUpstreamServers": s.globalConfig.DNS.DNSSECUpstreamDNS,
|
||||
"timeout": s.globalConfig.DNS.Timeout,
|
||||
"saveInterval": s.globalConfig.DNS.SaveInterval,
|
||||
"enableIPv6": s.globalConfig.DNS.EnableIPv6,
|
||||
},
|
||||
@@ -1290,9 +1289,6 @@ func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) {
|
||||
if len(req.DNSServer.DnssecUpstreamServers) > 0 {
|
||||
s.globalConfig.DNS.DNSSECUpstreamDNS = req.DNSServer.DnssecUpstreamServers
|
||||
}
|
||||
if req.DNSServer.Timeout > 0 {
|
||||
s.globalConfig.DNS.Timeout = req.DNSServer.Timeout
|
||||
}
|
||||
if req.DNSServer.SaveInterval > 0 {
|
||||
s.globalConfig.DNS.SaveInterval = req.DNSServer.SaveInterval
|
||||
}
|
||||
|
||||
16
package.json
16
package.json
@@ -7,12 +7,20 @@
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tailwindcss": "^3.3.3",
|
||||
"chart.js": "^4.4.8",
|
||||
"detect-file-encoding-and-language": "^2.4.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"chart.js": "^4.4.8"
|
||||
"json-stream-parser": "^1.3.0",
|
||||
"json5": "^2.2.3",
|
||||
"tailwindcss": "^3.3.3"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"keywords": ["dns", "server", "console", "web"],
|
||||
"keywords": [
|
||||
"dns",
|
||||
"server",
|
||||
"console",
|
||||
"web"
|
||||
],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
}
|
||||
|
||||
176
start.sh
Executable file
176
start.sh
Executable file
@@ -0,0 +1,176 @@
|
||||
#!/bin/bash
|
||||
# 启动/停止/重启脚本
|
||||
|
||||
# ===================== 配置区 =====================
|
||||
# 程序路径
|
||||
AGENT_PATH="./dns-server"
|
||||
# 日志文件路径
|
||||
LOG_FILE="./server.log"
|
||||
# PID文件路径(记录进程ID)
|
||||
PID_FILE="./server.pid"
|
||||
# 启动参数(根据实际需求调整)
|
||||
START_ARGS=""
|
||||
# 工作目录
|
||||
WORK_DIR="."
|
||||
# ==================== 配置区结束 ====================
|
||||
|
||||
# 检查程序文件是否存在
|
||||
check_agent_exists() {
|
||||
if [ ! -f "${AGENT_PATH}" ]; then
|
||||
echo "错误:程序文件 ${AGENT_PATH} 不存在!"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -x "${AGENT_PATH}" ]; then
|
||||
echo "错误:程序文件 ${AGENT_PATH} 没有执行权限,正在尝试添加..."
|
||||
chmod +x "${AGENT_PATH}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "错误:添加执行权限失败,请手动执行 chmod +x ${AGENT_PATH}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查进程是否运行
|
||||
check_running() {
|
||||
if [ -f "${PID_FILE}" ]; then
|
||||
PID=$(cat "${PID_FILE}")
|
||||
if ps -p "${PID}" > /dev/null 2>&1; then
|
||||
return 0 # 运行中
|
||||
else
|
||||
rm -f "${PID_FILE}" # PID文件存在但进程已死,清理PID文件
|
||||
fi
|
||||
fi
|
||||
return 1 # 未运行
|
||||
}
|
||||
|
||||
# 启动程序
|
||||
start_agent() {
|
||||
if check_running; then
|
||||
echo "✅ dns-server 已在运行(PID: $(cat ${PID_FILE}))"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "🚀 正在启动 dns-server(工作目录:${WORK_DIR})..."
|
||||
|
||||
# 新增:检查并切换工作目录
|
||||
if [ ! -d "${WORK_DIR}" ]; then
|
||||
echo "⚠️ 工作目录 ${WORK_DIR} 不存在,正在创建..."
|
||||
mkdir -p "${WORK_DIR}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ 创建工作目录 ${WORK_DIR} 失败!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 切换到工作目录(关键:程序将在此目录下运行)
|
||||
cd "${WORK_DIR}" || {
|
||||
echo "❌ 切换到工作目录 ${WORK_DIR} 失败!"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 创建日志目录
|
||||
mkdir -p "$(dirname ${LOG_FILE})"
|
||||
# 后台启动程序(注意:cd仅影响当前子进程,需在同一行执行)
|
||||
nohup "${AGENT_PATH}" ${START_ARGS} > "${LOG_FILE}" 2>&1 &
|
||||
AGENT_PID=$!
|
||||
echo "${AGENT_PID}" > "${PID_FILE}"
|
||||
|
||||
# 等待检查启动状态
|
||||
sleep 2
|
||||
if check_running; then
|
||||
echo "✅ dns-server 启动成功(PID: ${AGENT_PID},工作目录:${WORK_DIR})"
|
||||
echo "日志文件:${LOG_FILE}"
|
||||
else
|
||||
echo "❌ dns-server 启动失败!请查看日志:${LOG_FILE}"
|
||||
rm -f "${PID_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
# 停止程序
|
||||
stop_agent() {
|
||||
if ! check_running; then
|
||||
echo "ℹ️ dns-server 未运行"
|
||||
return 0
|
||||
fi
|
||||
|
||||
PID=$(cat "${PID_FILE}")
|
||||
echo "🛑 正在停止 dns-server(PID: ${PID})..."
|
||||
# 优雅停止(先尝试TERM信号,失败则强制KILL)
|
||||
kill "${PID}" > /dev/null 2>&1
|
||||
sleep 3
|
||||
|
||||
if ps -p "${PID}" > /dev/null 2>&1; then
|
||||
echo "⚠️ 优雅停止失败,强制杀死进程..."
|
||||
kill -9 "${PID}" > /dev/null 2>&1
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# 清理PID文件
|
||||
rm -f "${PID_FILE}"
|
||||
echo "✅ dns-server 已停止"
|
||||
}
|
||||
|
||||
# 查看状态
|
||||
status_agent() {
|
||||
if check_running; then
|
||||
echo "✅ dns-server 运行中(PID: $(cat ${PID_FILE}))"
|
||||
else
|
||||
echo "ℹ️ dns-server 未运行"
|
||||
fi
|
||||
}
|
||||
|
||||
# 重启程序
|
||||
restart_agent() {
|
||||
echo "🔄 正在重启 dns-server..."
|
||||
stop_agent
|
||||
sleep 2
|
||||
start_agent
|
||||
}
|
||||
|
||||
# 帮助信息
|
||||
show_help() {
|
||||
echo "使用方法:$0 [start|stop|restart|status|help]"
|
||||
echo " start - 启动 dns-server"
|
||||
echo " stop - 停止 dns-server"
|
||||
echo " restart - 重启 dns-server"
|
||||
echo " status - 查看 dns-server 运行状态"
|
||||
echo " help - 显示帮助信息"
|
||||
}
|
||||
|
||||
# 主逻辑
|
||||
main() {
|
||||
# 检查是否为root用户(可选,根据需求调整)
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "警告:建议使用root用户运行此脚本(当前用户:$(whoami))"
|
||||
# exit 1 # 如果强制要求root,取消注释
|
||||
fi
|
||||
|
||||
check_agent_exists
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start_agent
|
||||
;;
|
||||
stop)
|
||||
stop_agent
|
||||
;;
|
||||
restart)
|
||||
restart_agent
|
||||
;;
|
||||
status)
|
||||
status_agent
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
echo "错误:无效参数 '$1'"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 执行主逻辑
|
||||
main "$@"
|
||||
|
||||
535
static/domain-info/domains/domain-info.json
Normal file
535
static/domain-info/domains/domain-info.json
Normal file
@@ -0,0 +1,535 @@
|
||||
{
|
||||
"timeUpdated": "2025-03-17T10:05:02.622Z",
|
||||
"categories": {
|
||||
"0": "官方网站",
|
||||
"1": "搜索引擎",
|
||||
"2": "CDN",
|
||||
"3": "新闻资讯",
|
||||
"4": "购物网站",
|
||||
"5": "社交网站",
|
||||
"6": "工具网站",
|
||||
"7": "社交工具",
|
||||
"8": "视频网站",
|
||||
"9": "混合内容",
|
||||
"10": "博客/自媒体",
|
||||
"11": "论坛/社区",
|
||||
"12": "地图",
|
||||
"13": "涉政网站",
|
||||
"14": "政府网站",
|
||||
"15": "政务网站",
|
||||
"16": "组织网站",
|
||||
"17": "事业单位",
|
||||
"18": "政务服务",
|
||||
"19": "网络邮件",
|
||||
"20": "云服务",
|
||||
"21": "网络存储",
|
||||
"22": "网络服务",
|
||||
"23": "CDN网络分发平台",
|
||||
"24": "支付平台",
|
||||
"25": "其他"
|
||||
},
|
||||
"domains": {
|
||||
"网易": {
|
||||
"网易163": {
|
||||
"name": "网易163",
|
||||
"categoryId": 3,
|
||||
"url": "http://www.163.com/",
|
||||
"icon": "https://www.163.com/favicon.ico"
|
||||
},
|
||||
"网易163免费邮": {
|
||||
"name": "网易163免费邮",
|
||||
"categoryId": 18,
|
||||
"url": "https://mail.163.com/",
|
||||
"icon": "https://mail.163.com/favicon.ico"
|
||||
},
|
||||
"网易126免费邮": {
|
||||
"name": "网易126免费邮",
|
||||
"categoryId": 18,
|
||||
"url": "https://www.126.com/",
|
||||
"icon": "https://www.126.com/favicon.ico"
|
||||
},
|
||||
"网易有道词典": {
|
||||
"name": "网易有道词典",
|
||||
"categoryId": 0,
|
||||
"url": "https://dict.youdao.com/",
|
||||
"icon": "https://dict.youdao.com/favicon.ico"
|
||||
},
|
||||
"网易uu加速器":{
|
||||
"name": "网易uu加速器",
|
||||
"categoryId": 0,
|
||||
"url": {
|
||||
"1": "https://uu.163.com/",
|
||||
"2": "https://log.uu.163.com/"
|
||||
}
|
||||
},
|
||||
"company": "网易股份有限公司"
|
||||
},
|
||||
"百度": {
|
||||
"百度搜索": {
|
||||
"name": "百度搜索",
|
||||
"categoryId": 0,
|
||||
"url": "https://www.baidu.com/",
|
||||
"icon": "https://www.baidu.com/favicon.ico"
|
||||
},
|
||||
"百度百科": {
|
||||
"name": "百度百科",
|
||||
"categoryId": 19,
|
||||
"url": "https://baike.baidu.com/",
|
||||
"icon": "https://baike.baidu.com/favicon.ico"
|
||||
},
|
||||
"百度地图": {
|
||||
"name": "百度地图",
|
||||
"categoryId": 7,
|
||||
"url": "https://map.baidu.com/",
|
||||
"icon": "https://map.baidu.com/favicon.ico"
|
||||
},
|
||||
"百度知道": {
|
||||
"name": "百度知道",
|
||||
"categoryId": 12,
|
||||
"url": "https://zhidao.baidu.com/",
|
||||
"icon": "https://zhidao.baidu.com/favicon.ico"
|
||||
},
|
||||
"company": "北京百度网讯科技有限公司"
|
||||
},
|
||||
"阿里云": {
|
||||
"阿里云": {
|
||||
"name": "阿里云",
|
||||
"categoryId": 22,
|
||||
"url": "https://www.aliyun.com/",
|
||||
"icon": "https://img.alicdn.com/tfs/TB1_ZXuNcfpK1RjSZFOXXa6nFXa-32-32.ico"
|
||||
},
|
||||
"阿里云API服务": {
|
||||
"name": "阿里云API服务",
|
||||
"categoryId": 22,
|
||||
"url": "aliyuncs.com",
|
||||
"icon": "https://img.alicdn.com/tfs/TB1_ZXuNcfpK1RjSZFOXXa6nFXa-32-32.ico"
|
||||
},
|
||||
"阿里云DNS": {
|
||||
"name": "阿里云DNS",
|
||||
"categoryId": 22,
|
||||
"url": {
|
||||
"1": "alidns.com",
|
||||
"2": "alibabadns.com"
|
||||
},
|
||||
"icon": "https://img.alicdn.com/tfs/TB1_ZXuNcfpK1RjSZFOXXa6nFXa-32-32.ico"
|
||||
},
|
||||
"支付宝": {
|
||||
"name": "支付宝",
|
||||
"categoryId": 24,
|
||||
"url": "https://www.alipay.com/",
|
||||
"icon": "https://www.alipay.com/favicon.ico"
|
||||
},
|
||||
"淘宝": {
|
||||
"name": "淘宝",
|
||||
"categoryId": 4,
|
||||
"url": "https://www.taobao.com/",
|
||||
"icon": "https://www.taobao.com/favicon.ico"
|
||||
},
|
||||
"天猫": {
|
||||
"name": "天猫",
|
||||
"categoryId": 4,
|
||||
"url": "https://www.tmall.com/",
|
||||
"icon": "https://www.tmall.com/favicon.ico"
|
||||
},
|
||||
"阿里云镜像源":{
|
||||
"name": "阿里巴巴开源镜像站",
|
||||
"categoryId": 0,
|
||||
"url": {
|
||||
"1": "https://mirrors.aliyun.com/"
|
||||
},
|
||||
"icon": "https://www.aliyun.com/favicon.ico"
|
||||
},
|
||||
"company": "阿里云计算有限公司/阿里巴巴集团"
|
||||
},
|
||||
"UC":{
|
||||
"UC浏览器官网": {
|
||||
"name": "UC浏览器官网",
|
||||
"categoryId": 4,
|
||||
"url": {
|
||||
"1": "www.uc.cn",
|
||||
"2": "https://www.uc.com/"
|
||||
},
|
||||
"icon": "https://www.uc.cn/favicon.ico"
|
||||
},
|
||||
"company": "广州市动景计算机科技有限公司"
|
||||
},
|
||||
"腾讯": {
|
||||
"微信": {
|
||||
"name": "微信",
|
||||
"categoryId": 7,
|
||||
"url": {
|
||||
"1": "https://wx.qq.com/",
|
||||
"2": "https://weixin.qq.com/",
|
||||
"3": "https://res.wx.qq.com/",
|
||||
"4": "dns.weixin.qq.com",
|
||||
"5": "pc.weixin.qq.com"
|
||||
},
|
||||
"icon": "https://res.wx.qq.com/a/wx_fed/assets/res/NTI4MWU5.ico"
|
||||
},
|
||||
"WeChat": {
|
||||
"name": "WeChat",
|
||||
"categoryId": 7,
|
||||
"url": {
|
||||
"1":"wechat.com",
|
||||
"2": "support.wechat.com",
|
||||
"3": "www.wechat.com"
|
||||
},
|
||||
|
||||
"icon": "https://wechat.com/favicon.ico"
|
||||
},
|
||||
"微信开放平台": {
|
||||
"name": "微信开放平台",
|
||||
"categoryId": 24,
|
||||
"url": "https://open.weixin.qq.com/",
|
||||
"icon": "https://open.weixin.qq.com/favicon.ico"
|
||||
},
|
||||
"微信支付": {
|
||||
"name": "微信支付商户平台",
|
||||
"categoryId": 24,
|
||||
"url": {"1": "pay.weixin.qq.com",
|
||||
"2": "pay.wechatpay.cn",
|
||||
"3": "act.weixin.qq.com",
|
||||
"4": "api.wechatpay.cn",
|
||||
"5": "api.mch.weixin.qq.com",
|
||||
"6": "api2.mch.weixin.qq.com",
|
||||
"7": "api.wechatpay.cn",
|
||||
"8": "api2.wechatpay.cn",
|
||||
"9": "payapp.weixin.qq.com",
|
||||
"10": "payapp.wechatpay.cn",
|
||||
"11": "fraud.mch.weixin.qq.com",
|
||||
"12": "fraud.wechatpay.cn",
|
||||
"13": "action.weixin.qq.com",
|
||||
"14": "action.wechatpay.cn",
|
||||
"15": "wechatpay.cn"
|
||||
},
|
||||
|
||||
"icon": "https://gtimg.wechatpay.cn/core/favicon.ico"
|
||||
},
|
||||
"微信支付海外版": {
|
||||
"name": "微信支付海外版",
|
||||
"categoryId": 24,
|
||||
"url": {"1": "https://pay.wechatpay.global/",
|
||||
"2": "apihk.mch.weixin.qq.com",
|
||||
"3": "apius.mch.weixin.qq.com"
|
||||
},
|
||||
"icon": "https://gtimg.wechatpay.cn/core/favicon.ico"
|
||||
},
|
||||
"微信CDN": {
|
||||
"name": "微信CDN和日志等资源",
|
||||
"categoryId": 23,
|
||||
"url": {"1": "https://gtimg.wechatpay.cn/",
|
||||
"2": "log.wechatpay.cn",
|
||||
"3": "newres.wechat.com",
|
||||
"4": "res.wx.qq.com",
|
||||
"5": "sh.servicewechat.com",
|
||||
"6": "res.servicewechat.com"
|
||||
},
|
||||
"icon": "https://gtimg.wechatpay.cn/core/favicon.ico"
|
||||
},
|
||||
"腾讯下载加速网络CDN": {
|
||||
"name": "腾讯下载加速网络CDN",
|
||||
"categoryId": 23,
|
||||
"url": {"1": "dldir1v6.qq.com",
|
||||
"2": "dldir1.qq.com",
|
||||
"3": "dldir2.qq.com",
|
||||
"4": "dldir3.qq.com",
|
||||
"5": "dl.qq.com",
|
||||
"6": "dldir.tencent.com",
|
||||
"7": "pc.qq.com"
|
||||
},
|
||||
"icon": "https://www.tencent.com/favicon.ico"
|
||||
},
|
||||
"腾讯QQ": {
|
||||
"name": "腾讯QQ",
|
||||
"categoryId": 5,
|
||||
"url": "https://im.qq.com/",
|
||||
"icon": "https://im.qq.com/favicon.ico"
|
||||
},
|
||||
"腾讯网": {
|
||||
"name": "腾讯网",
|
||||
"categoryId": 3,
|
||||
"url": "https://www.qq.com/",
|
||||
"icon": "https://www.qq.com/favicon.ico"
|
||||
},
|
||||
"腾讯3G移动门户": {
|
||||
"name": "腾讯3G移动门户",
|
||||
"categoryId": 3,
|
||||
"url": "3g.qq.com",
|
||||
"icon": "https://www.tencent.com/favicon.ico"
|
||||
},
|
||||
"3G 移动门户CDN": {
|
||||
"name": "3G 移动门户CDN",
|
||||
"categoryId": 23,
|
||||
"url": "cdnimg.3g.qq.com",
|
||||
"icon": "https://www.tencent.com/favicon.ico"
|
||||
},
|
||||
"腾讯": {
|
||||
"name": "腾讯",
|
||||
"categoryId": 0,
|
||||
"url": "https://www.tencent.com/",
|
||||
"icon": "https://www.tencent.com/favicon.ico"
|
||||
},
|
||||
"腾讯地图": {
|
||||
"name": "腾讯地图",
|
||||
"categoryId": 8,
|
||||
"url": "https://map.qq.com/",
|
||||
"icon": "https://map.qq.com/favicon.ico"
|
||||
},
|
||||
"腾讯视频": {
|
||||
"name": "腾讯视频",
|
||||
"categoryId": 8,
|
||||
"url": "https://v.qq.com/",
|
||||
"icon": "https://v.qq.com/favicon.ico"
|
||||
},
|
||||
"腾讯广告": {
|
||||
"name": "腾讯广告",
|
||||
"categoryId": 0,
|
||||
"url": {
|
||||
"1": "ugdtimg.com",
|
||||
"2": "gdtimg.com",
|
||||
"3": "ad.qq.com",
|
||||
"4": "v3.gdt.qq.com",
|
||||
"5": "c3.gdt.qq.com",
|
||||
"6": "v2mi.gdt.qq.com",
|
||||
"7": "gdt.qq.com"
|
||||
},
|
||||
"icon": "https://www.tencent.com/favicon.ico"
|
||||
},
|
||||
"腾讯Beacon事件日志上报": {
|
||||
"name": "腾讯Beacon事件日志上报",
|
||||
"categoryId": 0,
|
||||
"url": "aeventlog.beacon.qq.com",
|
||||
"icon": "https://www.tencent.com/favicon.ico"
|
||||
},
|
||||
"company": "腾讯计算机系统有限公司"
|
||||
},
|
||||
|
||||
"微信青少年相关":{
|
||||
"微信守护平台":{
|
||||
"name": "微信守护平台",
|
||||
"categoryId": 24,
|
||||
"url": "wxguard.weixin.qq.com",
|
||||
"icon": "https://open.weixin.qq.com/favicon.ico"
|
||||
},
|
||||
"微信未成年人服务短链接":{
|
||||
"name": "微信未成年人服务短链接",
|
||||
"categoryId": 24,
|
||||
"url": {"1": "minorshort.weixin.qq.com",
|
||||
"2": "szminorshort.weixin.qq.com"
|
||||
},
|
||||
"icon": "https://open.weixin.qq.com/favicon.ico"
|
||||
},
|
||||
"深圳地区扩展短链接":{
|
||||
"name": "深圳地区扩展短链接",
|
||||
"categoryId": 24,
|
||||
"url": "szextshort.weixin.qq.com",
|
||||
"icon": "https://open.weixin.qq.com/favicon.ico"
|
||||
},
|
||||
"company": "腾讯计算机系统有限公司"
|
||||
},
|
||||
"高德地图相关": {
|
||||
"高德地图": {
|
||||
"name": "高德地图",
|
||||
"categoryId": 7,
|
||||
"url": "https://map.amap.com/",
|
||||
"icon": "https://a.amap.com/pc/static/favicon.ico"
|
||||
},
|
||||
"高德开放平台": {
|
||||
"name": "高德开放平台",
|
||||
"categoryId": 7,
|
||||
"url": "lbs.amap.com",
|
||||
"icon": "https://a.amap.com/pc/static/favicon.ico"
|
||||
},
|
||||
"高德地图API": {
|
||||
"name": "高德地图API",
|
||||
"categoryId": 7,
|
||||
"url": "https://restapi.amap.com/",
|
||||
"icon": "https://a.amap.com/pc/static/favicon.ico"
|
||||
},
|
||||
"company": "北京高德图强科技有限公司"
|
||||
},
|
||||
"微软": {
|
||||
"微软": {
|
||||
"name": "微软",
|
||||
"categoryId": 0,
|
||||
"url": "https://www.microsoft.com/",
|
||||
"icon": "https://cdn-dynmedia-1.microsoft.com/is/content/microsoftcorp/Link-List-Icons-Microsoft-365?wid=40&hei=40"
|
||||
},
|
||||
"微软Edge": {
|
||||
"name": "微软Edge",
|
||||
"categoryId": 0,
|
||||
"url": "https://www.microsoftedgeinsider.com/",
|
||||
"icon": "https://www.microsoftedgeinsider.com/favicon.ico"
|
||||
},
|
||||
"微软Office": {
|
||||
"name": "微软Office",
|
||||
"categoryId": 0,
|
||||
"url": "https://www.office.com/",
|
||||
"icon": "https://www.office.com/favicon.ico"
|
||||
},
|
||||
"Azure": {
|
||||
"name": "Azure",
|
||||
"categoryId": 0,
|
||||
"url": "https://www.azure.com/",
|
||||
"icon": "https://portal.azure.com/Content/favicon.ico"
|
||||
},
|
||||
"网络连接状态指示器(NCSI)": {
|
||||
"name": "网络连接状态指示器(NCSI)",
|
||||
"categoryId": 0,
|
||||
"url": "msftncsi.com",
|
||||
"icon": "https://www.microsoft.com/favicon.ico"
|
||||
},
|
||||
"company": "微软公司"
|
||||
},
|
||||
"字节跳动": {
|
||||
"抖音": {
|
||||
"name": "抖音",
|
||||
"categoryId": 0,
|
||||
"url": "https://www.douyin.com/",
|
||||
"icon": "https://www.douyin.com/favicon.ico"
|
||||
},
|
||||
"今日头条": {
|
||||
"name": "今日头条",
|
||||
"categoryId": 0,
|
||||
"url": "https://www.toutiao.com/",
|
||||
"icon": "https://www.toutiao.com/favicon.ico"
|
||||
},
|
||||
"抖音视频": {
|
||||
"name": "抖音视频",
|
||||
"categoryId": 8,
|
||||
"url": "https://v.douyin.com/",
|
||||
"icon": "https://v.douyin.com/favicon.ico"
|
||||
},
|
||||
"字节跳动API服务": {
|
||||
"name": "字节API服务",
|
||||
"categoryId": 0,
|
||||
"url": "zijieapi.com",
|
||||
"icon": "data:image/vnd.microsoft.icon;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAMAAABOo35HAAACFlBMVEUAAACp3f8yW7U8jf8zW7U/3vJA5P8AydMzW7VPlP955908jP8AydM8jf8yWrV5590yWrV45908jf8yW7UyW7UyW7V55909jf88jf8yW7UzW7V56N49jf80XLY+j/80XbY/lf8zZr5Ilf9GXbkA2+RCY70zZsx459x5590AydI8jP8AydN4590AydM8jf8AydM8jf88jf94590AyNM8jf8AydN5590AydM8jf8AyNIAytR5594zW7V56N09jf955948jf8AydMAytN65948jf956N56594AytMAy9Q9jv976d8AytYAy9Z66N566uE/jv8AztUAy9cAytV56OSD798A0NYAydM8jP95590yW7R45twAydN45909jP8yWrU8jf945t0AydIyWrV5590AydIyW7UzWrU8jf8AydIzW7UzWrV459145908jf8yW7UAydM8jP8AydM8jf9459155909jf8zW7UAydQAytMAydN56N0AydMzXLYAydM0W7UAydQ8jv8+jv8Ay9QzW7Y9jf965t176N80W7YAydN56N156d4yW7U0XLc+jv8+kP8Ay9VAj/81XbgAzNQ1XbY5XbZAkf9+7eQ7Yrp96+FDlv+F6emI/+4AydN55t15594AydM+jf8+jf8+jv8AydQ1W7QzW7UAydR75942XbUyWrR86OCA8uYAztqA8eN45twyWrQAyNI8jP8bed+KAAAArnRSTlMAAfb9+wUD8HMJ/fr59+jb1dTLt6eamY+Jg3xXTkhHOhIRDQsJBwX59vbr4+Dc1tXRxcC7ubSqoJuak5CKiIN+enlyb21lXVFEQj09NzAnJiQdGBUPDvzx8O/s6Obl397OzsvIyMXEwcG/vbiysbGuqqeknZSTkI2Gf3ZraGViX15YWFVTUk9OS0pEQUA8MzAtLSomHx4bGhkXCwfApKCAdGdjXlxaWTY0MyEUFBKNTPVmAAAFHElEQVR42uzX105UYRSG4YUyiCgqKvbeK3ZFsaCCXUHE3kvU2FvU2EussfcSY2KiiSUDc4fuTcl/xr8/ZuZk7/e9g/UcfcuIiIiIiIiIiIiIiMhf7wFDPxlFKx1UdunBX6NoWGEHqp40GnmwXCWHlzz9YuTBck2cvWzdVyMPlmtSAJYy8mE5sJPXNhYYebBcO06tBMyP5do1v3aTkcPytedb7R8jh+Vr2sVVHyzxpaMXfEZbLNGltcqqHjba8LGWzNJyJdZUeHTws/GWvNJ61hTW5cSQkRMsWXUWqxWsX/HvJC2xTmK5dp4pfp0UsCywXL3633hrCShrLAd2653FvBxgufaV//xoMS5HWK4+5fdHW0zLJZYDu/wolmC5xXIVHlocv6GfcyxX/IZ+HrHiN/TziuWGvsWiLLCULBaBBVZLYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYAmBJQSWEFhCYOW1erCitfn2gqnNYPlruLdwenMQWJ7+rV40I3QCy9PWx1cOhkZgeRq35uqRbYEPWD6o9d+P9wxxwOq41IblcyaHMGB1XNHLFfO6hShgeXpz/WwLFFie6m+e3x1igBVlmgeB5anhV+s0B8tX2zQHK0rB8WCBZQYWWGCBBRZYYIEFFlhggQUWWGCBBRZYYIGVZKyKgcNGmYEVCSuTyXTtO2jEGLCiYYX1mLV0bXewfFiu0mPVz1NgebEc2NzqF0Vg+bBc20/XvCoAy4flmnKupg4sL5Zr74UfdWB5sVz7K++8B8theauovPsZLIflbWYw9MGKiNU+9MGKlBv6YEWvFCwhsMACCyywwAILLLDAAgsssMACCyywwAILLLDAAgsssMACCyywwAILLLDAAgsssMACCyywwAILLLDAAgsssMACCyywwAILLLDAAgsssMD6325d7cQVhWEY/ocWn9JSoO5GhTqlSo2Wurt72qbu3lRwgruEQCCBE+6RHQ7YR7DWP8OeWSHvewnPwZcPLLDAAgsssMACCyywwAILLLDAAgsssMACCyywwAILLLCmGtbhHclg+Vimkk4f2r4OLLEu8dS3Z2Gw7Ft1/OvjMFj2Xan48uAqWAqwY3s2g6Xo4r/dG8FSdKF/5wawFJ3/9e4WWIoaf7xJBsu+UJ139MHyszr6YKmOfncYLM3RB0sRWGDZBBZYYIEFFlhggQUWWGBFgpWQBZYd1PMFS9cIWMamP5lfvVq8wDJAPdy3eKV4gWVo1ufy5eIFlhigcv6PQoFlwLqbM9AmXmAZsDKyfzeLX6BY6U/FJjexMrJ/NolfoFjTZs9bkipWuYd143VKQ0iiyh5qy9xFK8Q6t7ASslKGfKiAsTZ9KlkmqtzB8q95DLDu7frbIXEvIiz/mscC6877Py3iRJFg+dc8cKz1b/vOiTPprdJk0hsH6tWRenEqpVTmx9JhkeCxruX31obEtRRQM+csvCTq9Fgz8g/WJImLWULl9RS3ijo9VvrW/SdSxdUsoG4XHD0rgRb3az45WDcLitRQ+uJ+zaPHuv6y6ExsRjbu1zw6rLUvvg+6ObKqgsfK3XbgZKKQESv3UWFVl5ARK+1+YWWnkBkrc2/ZZaGJG7vmZC7vQ3G7EBERERERERERERER0dRtBK5Q857p1uutAAAAAElFTkSuQmCC"
|
||||
},
|
||||
"今日头条API服务":{
|
||||
"name": "今日头条API 服务",
|
||||
"categoryId": 0,
|
||||
"url": "toutiaoapi.com",
|
||||
"icon": "https://www.toutiao.com/favicon.ico"
|
||||
},
|
||||
"豆包": {
|
||||
"name": "豆包",
|
||||
"categoryId": 0,
|
||||
"url": "doubao.com",
|
||||
"icon": "https://lf-flow-web-cdn.doubao.com/obj/flow-doubao/doubao/chat/favicon.png"
|
||||
},
|
||||
"company": "字节跳动有限公司"
|
||||
},
|
||||
"金山办公": {
|
||||
"金山文档": {
|
||||
"name": "金山文档",
|
||||
"categoryId": 0,
|
||||
"url": {
|
||||
"1":"kdocs.cn",
|
||||
"2":"www.kdocs.cn",
|
||||
"3":"365.kdocs.cn",
|
||||
"4":"account.kdocs.cn"
|
||||
},
|
||||
"icon": "https://qn.cache.wpscdn.cn/kdocs/mobile/touch/apple-180.png"
|
||||
},
|
||||
"WPS Office": {
|
||||
"name": "WPS Office",
|
||||
"categoryId": 6,
|
||||
"url": {
|
||||
"1":"wps.cn",
|
||||
"2":"www.wps.cn"
|
||||
},
|
||||
"icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQ2SURBVHgB7Va9biRFEK7qWa9XAuSByMEhr0FIzvARkEBgEUHEPQG79wKcTyL3Li/gnxdgl5TgTAQSQmeJxEJCIoIjOc/JyemSW4tbe70z28XX1T0z+zO2U6RzWe3unq6un6+/rl6iW7mV111Y7tzZImMekVAcvkm+NqUnxZy1S0jsQz49PdTF3Q82ych3WNzM1dM/Msp+S4UviQ32RHDlBm5MIgJrz9Bvs6y9e4Ida3MOvRXGnxRTyb2HgM6I/13nZDCQb98/IcNNtQC19J8JXf46InWM5npjfM/qnJ1dtVGjSOLgKkQWnMz4y+clcmgx2TiWb955QENpFsBhT/r7SDhymZMwEnfKOjbiFcSSRuO+k7F7FFk4xsdIECZ6xtxg7HqeuHFYQ583lh59Dgvn0qZXmL/CviGy/3tM9gJOoYPmehcMcaR7vE03Vj9yyNJsxlQf4xgkLrNFUCnvEzUwGZUoRDjjiB7peCzr9Gm9hflOgRokfZHdnfw1HPi9+X/IMu8CpHsznIIN3SgbqzvoOiXAMgBgd/nJ84TmibGx+pgcCTeoS9HSY5hpFnwh6vEPp/cr9jidE3/M+Vfb4ycv7hsf5mifzOQlYPFwM87X2B2qlq62kWnRhW3SOaC8sExDHFUadSt3OFsecg+9csGorgbAfw4GVOMDPef8fCJpy0bcnLcFVI5oFYORbcMpaQBD6/o+HybJYvawAVs4Kgq2Hd96ObqmjHK8h8gGgYw+yuWoGoXzrEXnE2SfCQ0zN3dUqc7e2VAyB0LjdtBSWugWASgK7G7EFNONtGRzFgWdp7JNKYxlCBYd+h4fP0+wFi/oGmp7ZK1WI/jowleyEIAXCy7Yl8UxGGyIzCwKjvXGxj5AZxAR2ElXPorbVDPbs7qmExKRcLUTR75plZkAFIVIDvQY3CYlpW3nKBQZ6VqoGUb6oOwgBPa1bHkUVJcnXwUd9hwAUlPZVyAAGZPnQl6UXBDLsqtrDdvReV6UHFKRuxH2AeZwCGTc2MkymO9JnSfyDN768+4WAggo7IWKxeH8vpRP3mo5TpQVUYPrBSttrabujI1sy8dvfIixZ76x3gajRhzPZq/+qEIUxjR9igr3NlVKqChZtk6NxgC9e9A8AUWL0hn+r+QvDPQTytLP+HiU3IiAmj8KXCh5IEWR8mN9C5xB1a3RfnFz/NGtTL0d7v39vsr5lQH4lTq4YM+U6aVxCuQD3JOpe19zuoNQwALp8qtsE6plvSvdXLWgmRnZL1isJXoSXjLu81GZUaGrL14otVrQ0Eg607oLfugakS2c61L9qf5a8i+e6O+CzLw3b1R1a3XHhZWp1zHhXy7Xr/NhrlvkI73fB2Vh0vvcr8pIdR0Xpisp49reILWbFPjncUe+qK0g83vK5tGbD12xqJQR3pPG0hrq8xZQ+JF/yvp0K7fyf5f/AKzIO6StcaNfAAAAAElFTkSuQmCC"
|
||||
},
|
||||
"WPS CDN": {
|
||||
"name": "WPS CDN",
|
||||
"categoryId": 23,
|
||||
"url": {
|
||||
"1":"wpsdns.com",
|
||||
"2":"kdocs-om.wpscdn.cn",
|
||||
"3":"qn.cache.wpscdn.cn",
|
||||
"4":"fe-static.wpscdn.cn",
|
||||
"5":"docer-ks3.wpscdn.cn",
|
||||
"6":"cloudcdn.wpscdn.cn",
|
||||
"7":"vasvip-pub.wpscdn.cn",
|
||||
"8":"ks3.wpsplus.wpscdn.cn",
|
||||
"9":"op-kdocs.wpscdn.cn",
|
||||
"10":"volcengine-cache-weboffice.wpscdn.cn",
|
||||
"11":"ac.wpscdn.cn",
|
||||
"12":"honeycomb-emergency.wpscdn.cn",
|
||||
"13":"res-honeycomb.wpscdn.cn",
|
||||
"14":"kflow.wpscdn.cn",
|
||||
"15":"personal-act.wpscdn.cn",
|
||||
"16":"official-package.wpscdn.cn"
|
||||
},
|
||||
"icon": "https://wps.cn/favicon.ico"
|
||||
},
|
||||
"company": "珠海金山办公科技有限公司"
|
||||
},
|
||||
"京东": {
|
||||
"京东": {
|
||||
"name": "京东",
|
||||
"categoryId": 4,
|
||||
"url": "https://www.jd.com/",
|
||||
"icon": "https://www.jd.com/favicon.ico"
|
||||
},
|
||||
"company": "京东"
|
||||
},
|
||||
"360": {
|
||||
"360官网": {
|
||||
"name": "360",
|
||||
"categoryId": 0,
|
||||
"url": "https://www.360.cn/",
|
||||
"icon": "https://www.360.cn/favicon.ico"
|
||||
},
|
||||
"360搜索": {
|
||||
"name": "360搜索",
|
||||
"categoryId": 0,
|
||||
"url": {
|
||||
"1":"https://www.so.com/",
|
||||
"2":"https://so.com/"
|
||||
},
|
||||
"icon": "https://www.so.com/favicon.ico"
|
||||
},
|
||||
"company": "奇虎360"
|
||||
},
|
||||
"绮梦之家": {
|
||||
"绮梦之家": {
|
||||
"name": "绮梦之家",
|
||||
"categoryId": 0,
|
||||
"url": {
|
||||
"1": "https://www.amazehome.xyz/",
|
||||
"2": "amazehome.xyz",
|
||||
"3": "https://www.amazehome.cn/",
|
||||
"4": "amazehome.cn"
|
||||
},
|
||||
"icon": "https://www.amazehome.cn/upload/cf3f6d7f-65b5-4df2-a7af-8289fb5aad81-yagB.png"
|
||||
},
|
||||
"company": "绮梦之家"
|
||||
},
|
||||
"南京市中医院": {
|
||||
"南京市中医院": {
|
||||
"name": "南京市中医院",
|
||||
"categoryId": 0,
|
||||
"url": {
|
||||
"1":"https://www.njszyy.cn/",
|
||||
"2":"https://njszyy.cn/"
|
||||
},
|
||||
"icon": "#"
|
||||
},
|
||||
"company": "南京市中医院"
|
||||
},
|
||||
"软件源相关": {
|
||||
"腾讯镜像源":{
|
||||
"name": "腾讯软件源",
|
||||
"categoryId": 0,
|
||||
"url": {
|
||||
"1": "https://mirrors.cloud.tencent.com/"
|
||||
},
|
||||
"icon": "https://www.tencent.com/favicon.ico",
|
||||
"company": "腾讯计算机系统有限公司"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
25333
static/domain-info/tracker/trackers.json
Normal file
25333
static/domain-info/tracker/trackers.json
Normal file
File diff suppressed because it is too large
Load Diff
25333
static/domain-info/tracker/trackers.json.bak
Normal file
25333
static/domain-info/tracker/trackers.json.bak
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1049,10 +1049,6 @@
|
||||
<label for="dns-port" class="block text-sm font-medium text-gray-700 mb-1">端口</label>
|
||||
<input type="number" id="dns-port" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="53">
|
||||
</div>
|
||||
<div>
|
||||
<label for="dns-timeout" class="block text-sm font-medium text-gray-700 mb-1">超时时间 (秒)</label>
|
||||
<input type="number" id="dns-timeout" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="5">
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<label for="dns-upstream-servers" class="block text-sm font-medium text-gray-700 mb-1">上游DNS服务器 (逗号分隔)</label>
|
||||
<input type="text" id="dns-upstream-servers" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="8.8.8.8, 1.1.1.1">
|
||||
|
||||
@@ -62,15 +62,13 @@ function populateConfigForm(config) {
|
||||
setElementValue('dns-port', getSafeValue(dnsServerConfig.Port, 53));
|
||||
setElementValue('dns-upstream-servers', getSafeArray(dnsServerConfig.UpstreamServers).join(', '));
|
||||
setElementValue('dns-dnssec-upstream-servers', getSafeArray(dnsServerConfig.DNSSECUpstreamServers).join(', '));
|
||||
setElementValue('dns-timeout', getSafeValue(dnsServerConfig.Timeout, 5));
|
||||
//setElementValue('dns-stats-file', getSafeValue(dnsServerConfig.StatsFile, 'data/stats.json'));
|
||||
setElementValue('dns-save-interval', getSafeValue(dnsServerConfig.SaveInterval, 30));
|
||||
//setElementValue('dns-cache-ttl', getSafeValue(dnsServerConfig.CacheTTL, 10));
|
||||
setElementValue('dns-enable-ipv6', getSafeValue(dnsServerConfig.EnableIPv6, false));
|
||||
// HTTP配置
|
||||
setElementValue('http-port', getSafeValue(httpServerConfig.Port, 8080));
|
||||
|
||||
// 屏蔽配置
|
||||
// 屏蔽配置
|
||||
//setElementValue('shield-local-rules-file', getSafeValue(shieldConfig.LocalRulesFile, 'data/rules.txt'));
|
||||
setElementValue('shield-update-interval', getSafeValue(shieldConfig.UpdateInterval, 3600));
|
||||
//setElementValue('shield-hosts-file', getSafeValue(shieldConfig.HostsFile, 'data/hosts.txt'));
|
||||
|
||||
@@ -19,6 +19,11 @@ let trackersDatabase = null;
|
||||
let trackersLoaded = false;
|
||||
let trackersLoading = false;
|
||||
|
||||
// 域名信息数据库缓存
|
||||
let domainInfoDatabase = null;
|
||||
let domainInfoLoaded = false;
|
||||
let domainInfoLoading = false;
|
||||
|
||||
// WebSocket连接和重连计时器
|
||||
let logsWsConnection = null;
|
||||
let logsWsReconnectTimer = null;
|
||||
@@ -37,7 +42,7 @@ async function loadTrackersDatabase() {
|
||||
trackersLoading = true;
|
||||
|
||||
try {
|
||||
const response = await fetch('/tracker/trackers.json');
|
||||
const response = await fetch('domain-info/tracker/trackers.json');
|
||||
if (!response.ok) {
|
||||
console.error('加载跟踪器数据库失败:', response.statusText);
|
||||
trackersDatabase = { trackers: {} };
|
||||
@@ -56,6 +61,53 @@ async function loadTrackersDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载域名信息数据库
|
||||
async function loadDomainInfoDatabase() {
|
||||
console.log('开始加载域名信息数据库');
|
||||
|
||||
if (domainInfoLoaded) {
|
||||
console.log('域名信息数据库已加载,直接返回');
|
||||
return domainInfoDatabase;
|
||||
}
|
||||
|
||||
if (domainInfoLoading) {
|
||||
console.log('域名信息数据库正在加载中,等待完成');
|
||||
// 等待正在进行的加载完成
|
||||
while (domainInfoLoading) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
return domainInfoDatabase;
|
||||
}
|
||||
|
||||
domainInfoLoading = true;
|
||||
|
||||
try {
|
||||
console.log('发起请求获取域名信息数据库');
|
||||
const response = await fetch('domain-info/domains/domain-info.json');
|
||||
|
||||
if (!response.ok) {
|
||||
console.error('加载域名信息数据库失败,HTTP状态:', response.status, response.statusText);
|
||||
console.error('请求URL:', response.url);
|
||||
domainInfoDatabase = { domains: {}, categories: {} };
|
||||
return domainInfoDatabase;
|
||||
}
|
||||
|
||||
console.log('域名信息数据库请求成功,开始解析JSON');
|
||||
domainInfoDatabase = await response.json();
|
||||
console.log('域名信息数据库解析成功,包含', Object.keys(domainInfoDatabase.domains || {}).length, '个公司');
|
||||
domainInfoLoaded = true;
|
||||
return domainInfoDatabase;
|
||||
} catch (error) {
|
||||
console.error('加载域名信息数据库失败,错误信息:', error.message);
|
||||
console.error('错误堆栈:', error.stack);
|
||||
domainInfoDatabase = { domains: {}, categories: {} };
|
||||
return domainInfoDatabase;
|
||||
} finally {
|
||||
domainInfoLoading = false;
|
||||
console.log('域名信息数据库加载完成');
|
||||
}
|
||||
}
|
||||
|
||||
// 检查域名是否在跟踪器数据库中,并返回跟踪器信息
|
||||
async function isDomainInTrackerDatabase(domain) {
|
||||
if (!trackersDatabase || !trackersLoaded) {
|
||||
@@ -78,7 +130,7 @@ async function isDomainInTrackerDatabase(domain) {
|
||||
if (tracker && tracker.url) {
|
||||
try {
|
||||
const trackerUrl = new URL(tracker.url);
|
||||
if (trackerUrl.hostname === domain || trackerUrl.hostname.includes(domain)) {
|
||||
if (trackerUrl.hostname === domain) {
|
||||
return tracker;
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -91,6 +143,164 @@ async function isDomainInTrackerDatabase(domain) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 根据域名查找对应的网站信息
|
||||
async function getDomainInfo(domain) {
|
||||
console.log('开始查找域名信息,域名:', domain);
|
||||
|
||||
if (!domainInfoDatabase || !domainInfoLoaded) {
|
||||
console.log('域名信息数据库未加载,调用loadDomainInfoDatabase');
|
||||
await loadDomainInfoDatabase();
|
||||
}
|
||||
|
||||
if (!domainInfoDatabase || !domainInfoDatabase.domains) {
|
||||
console.error('域名信息数据库无效或为空');
|
||||
return null;
|
||||
}
|
||||
|
||||
// 规范化域名,移除可能的端口号
|
||||
const normalizedDomain = domain.replace(/:\d+$/, '').toLowerCase();
|
||||
console.log('规范化后的域名:', normalizedDomain);
|
||||
|
||||
// 遍历所有公司
|
||||
console.log('开始遍历公司,总公司数:', Object.keys(domainInfoDatabase.domains).length);
|
||||
for (const companyKey in domainInfoDatabase.domains) {
|
||||
if (domainInfoDatabase.domains.hasOwnProperty(companyKey)) {
|
||||
console.log('检查公司:', companyKey);
|
||||
const companyData = domainInfoDatabase.domains[companyKey];
|
||||
const companyName = companyData.company || companyKey;
|
||||
|
||||
// 遍历公司下的所有网站
|
||||
for (const websiteKey in companyData) {
|
||||
if (companyData.hasOwnProperty(websiteKey) && websiteKey !== 'company') {
|
||||
console.log(' 检查网站:', websiteKey);
|
||||
const website = companyData[websiteKey];
|
||||
|
||||
// 检查域名是否匹配网站的URL
|
||||
if (website.url) {
|
||||
// 处理字符串类型的URL
|
||||
if (typeof website.url === 'string') {
|
||||
console.log(' 检查字符串URL:', website.url);
|
||||
if (isDomainMatch(website.url, normalizedDomain)) {
|
||||
console.log(' 匹配成功,返回网站信息');
|
||||
return {
|
||||
name: website.name,
|
||||
icon: website.icon,
|
||||
categoryId: website.categoryId,
|
||||
categoryName: domainInfoDatabase.categories[website.categoryId] || '未知',
|
||||
company: companyName
|
||||
};
|
||||
}
|
||||
}
|
||||
// 处理对象类型的URL
|
||||
else if (typeof website.url === 'object') {
|
||||
console.log(' 检查对象类型URL,包含', Object.keys(website.url).length, '个URL');
|
||||
for (const urlKey in website.url) {
|
||||
if (website.url.hasOwnProperty(urlKey)) {
|
||||
const urlValue = website.url[urlKey];
|
||||
console.log(' 检查URL', urlKey, ':', urlValue);
|
||||
if (isDomainMatch(urlValue, normalizedDomain)) {
|
||||
console.log(' 匹配成功,返回网站信息');
|
||||
return {
|
||||
name: website.name,
|
||||
icon: website.icon,
|
||||
categoryId: website.categoryId,
|
||||
categoryName: domainInfoDatabase.categories[website.categoryId] || '未知',
|
||||
company: companyName
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(' 网站没有URL属性');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('未找到匹配的域名信息');
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查域名是否匹配
|
||||
function isDomainMatch(urlValue, targetDomain) {
|
||||
console.log(' 开始匹配URL:', urlValue, '目标域名:', targetDomain);
|
||||
|
||||
try {
|
||||
// 尝试将URL值解析为完整URL
|
||||
console.log(' 尝试解析URL为完整URL');
|
||||
const url = new URL(urlValue);
|
||||
const hostname = url.hostname.toLowerCase();
|
||||
console.log(' 解析成功,主机名:', hostname);
|
||||
|
||||
// 只匹配完整域名,不进行主域名匹配
|
||||
// 这是为了避免同一个公司下的不同网站(如微信和腾讯视频)因为主域名相同而错误匹配
|
||||
if (hostname === targetDomain) {
|
||||
console.log(' 完整域名匹配成功');
|
||||
return true;
|
||||
} else {
|
||||
console.log(' 完整域名不匹配');
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(' 解析URL失败,将其视为纯域名处理,错误信息:', e.message);
|
||||
// 如果是纯域名而不是完整URL
|
||||
const urlDomain = urlValue.toLowerCase();
|
||||
console.log(' 处理为纯域名:', urlDomain);
|
||||
|
||||
// 只匹配完整域名,不进行主域名匹配
|
||||
if (urlDomain === targetDomain) {
|
||||
console.log(' 完整域名匹配成功');
|
||||
return true;
|
||||
} else {
|
||||
console.log(' 完整域名不匹配');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提取主域名
|
||||
function extractPrimaryDomain(domain) {
|
||||
console.log(' 开始提取主域名,原始域名:', domain);
|
||||
|
||||
const parts = domain.split('.');
|
||||
console.log(' 域名分割为:', parts);
|
||||
|
||||
if (parts.length <= 2) {
|
||||
console.log(' 域名长度小于等于2,直接返回:', domain);
|
||||
return domain;
|
||||
}
|
||||
|
||||
// 处理常见的三级域名
|
||||
const commonSubdomains = ['www', 'mail', 'news', 'map', 'image', 'video', 'cdn', 'api', 'blog', 'shop', 'cloud', 'docs', 'help', 'support', 'dev', 'test', 'staging'];
|
||||
console.log(' 检查是否为常见三级域名');
|
||||
|
||||
if (commonSubdomains.includes(parts[0])) {
|
||||
const result = parts.slice(1).join('.');
|
||||
console.log(' 是常见三级域名,返回:', result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 处理特殊情况,如co.uk, co.jp等
|
||||
const countryTLDs = ['co.uk', 'co.jp', 'co.kr', 'co.in', 'co.ca', 'co.au', 'co.nz', 'co.th', 'co.sg', 'co.my', 'co.id', 'co.za', 'com.cn', 'org.cn', 'net.cn', 'gov.cn', 'edu.cn'];
|
||||
console.log(' 检查是否为特殊国家TLD');
|
||||
|
||||
for (const tld of countryTLDs) {
|
||||
if (domain.endsWith('.' + tld)) {
|
||||
const mainParts = domain.split('.');
|
||||
const result = mainParts.slice(-tld.split('.').length - 1).join('.');
|
||||
console.log(' 是特殊国家TLD,返回:', result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认情况:返回最后两个部分
|
||||
const result = parts.slice(-2).join('.');
|
||||
console.log(' 默认情况,返回最后两个部分:', result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 初始化查询日志页面
|
||||
function initLogsPage() {
|
||||
console.log('初始化查询日志页面');
|
||||
@@ -1115,6 +1325,9 @@ async function showLogDetailModal(log) {
|
||||
const trackerInfo = await isDomainInTrackerDatabase(log.domain);
|
||||
const isTracker = trackerInfo !== null;
|
||||
|
||||
// 获取域名信息
|
||||
const domainInfo = await getDomainInfo(domain);
|
||||
|
||||
// 格式化DNS解析记录
|
||||
const dnsRecords = formatDNSRecords(log, result);
|
||||
|
||||
@@ -1196,6 +1409,31 @@ async function showLogDetailModal(log) {
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 域名信息
|
||||
const domainInfoDiv = document.createElement('div');
|
||||
domainInfoDiv.className = 'col-span-1 md:col-span-2 space-y-1';
|
||||
domainInfoDiv.innerHTML = `
|
||||
<div class="text-xs text-gray-500">域名信息</div>
|
||||
<div class="text-sm font-medium text-gray-900 p-3 bg-gray-50 rounded-md border border-gray-200">
|
||||
${domainInfo ? `
|
||||
<div class="flex items-center mb-2">
|
||||
${domainInfo.icon ? `<img src="${domainInfo.icon}" alt="${domainInfo.name}" class="w-6 h-6 mr-2 rounded-sm" onerror="this.style.display='none'" />` : ''}
|
||||
<span class="text-base font-semibold">${domainInfo.name || '未知'}</span>
|
||||
</div>
|
||||
<div class="ml-8 mt-1">
|
||||
<div class="flex items-center mb-1">
|
||||
<span class="text-gray-500 w-16">类别:</span>
|
||||
<span>${domainInfo.categoryName || '未知'}</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<span class="text-gray-500 w-16">所属公司:</span>
|
||||
<span>${domainInfo.company || '未知'}</span>
|
||||
</div>
|
||||
</div>
|
||||
` : '无'}
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 跟踪器信息
|
||||
const trackerDiv = document.createElement('div');
|
||||
trackerDiv.className = 'col-span-1 md:col-span-2 space-y-1';
|
||||
@@ -1236,6 +1474,7 @@ async function showLogDetailModal(log) {
|
||||
`;
|
||||
|
||||
basicInfoGrid.appendChild(dnsFeatures);
|
||||
basicInfoGrid.appendChild(domainInfoDiv);
|
||||
basicInfoGrid.appendChild(trackerDiv);
|
||||
basicInfoGrid.appendChild(recordsDiv);
|
||||
basicInfoGrid.appendChild(dnsServerDiv);
|
||||
@@ -1270,8 +1509,8 @@ async function showLogDetailModal(log) {
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 只有被屏蔽或者有自定义规则时才显示规则信息
|
||||
if (result === 'blocked' || (blockRule && blockRule !== '无' && blockRule !== '-')) {
|
||||
// 只有被屏蔽时才显示规则信息
|
||||
if (result === 'blocked') {
|
||||
responseDetailsHTML += `
|
||||
<div class="space-y-1">
|
||||
<div class="text-xs text-gray-500">规则</div>
|
||||
|
||||
Reference in New Issue
Block a user