实现日志详情域名信息显示

This commit is contained in:
Alex Yang
2025-12-30 10:41:09 +08:00
parent 43f0133886
commit 97413e88f0
13 changed files with 51681 additions and 1933 deletions

View File

@@ -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
}
}
}

View File

@@ -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"}
}

View File

@@ -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)

View File

@@ -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
}

1831
nohup.out

File diff suppressed because it is too large Load Diff

View File

@@ -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
View 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-serverPID: ${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 "$@"

View 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": "腾讯计算机系统有限公司"
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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">

View File

@@ -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'));

View File

@@ -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>