实现解析日志查询功能
This commit is contained in:
158
dns/server.go
158
dns/server.go
@@ -37,6 +37,18 @@ type ClientStats struct {
|
||||
LastSeen time.Time
|
||||
}
|
||||
|
||||
// QueryLog 查询日志记录
|
||||
type QueryLog struct {
|
||||
Timestamp time.Time // 查询时间
|
||||
ClientIP string // 客户端IP
|
||||
Domain string // 查询域名
|
||||
QueryType string // 查询类型
|
||||
ResponseTime int64 // 响应时间(ms)
|
||||
Result string // 查询结果(allowed, blocked, error)
|
||||
BlockRule string // 屏蔽规则(如果被屏蔽)
|
||||
BlockType string // 屏蔽类型(如果被屏蔽)
|
||||
}
|
||||
|
||||
// StatsData 用于持久化的统计数据结构
|
||||
type StatsData struct {
|
||||
Stats *Stats `json:"stats"`
|
||||
@@ -73,11 +85,14 @@ type Server struct {
|
||||
dailyStats map[string]int64 // 按天统计屏蔽数量
|
||||
monthlyStatsMutex sync.RWMutex
|
||||
monthlyStats map[string]int64 // 按月统计屏蔽数量
|
||||
saveTicker *time.Ticker // 用于定时保存数据
|
||||
startTime time.Time // 服务器启动时间
|
||||
saveDone chan struct{} // 用于通知保存协程停止
|
||||
stopped bool // 服务器是否已经停止
|
||||
stoppedMutex sync.Mutex // 保护stopped标志的互斥锁
|
||||
queryLogsMutex sync.RWMutex
|
||||
queryLogs []QueryLog // 查询日志列表
|
||||
maxQueryLogs int // 最大保存日志数量
|
||||
saveTicker *time.Ticker // 用于定时保存数据
|
||||
startTime time.Time // 服务器启动时间
|
||||
saveDone chan struct{} // 用于通知保存协程停止
|
||||
stopped bool // 服务器是否已经停止
|
||||
stoppedMutex sync.Mutex // 保护stopped标志的互斥锁
|
||||
}
|
||||
|
||||
// Stats DNS服务器统计信息
|
||||
@@ -125,6 +140,8 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie
|
||||
hourlyStats: make(map[string]int64),
|
||||
dailyStats: make(map[string]int64),
|
||||
monthlyStats: make(map[string]int64),
|
||||
queryLogs: make([]QueryLog, 0, 1000), // 初始化查询日志切片,容量1000
|
||||
maxQueryLogs: 10000, // 最大保存10000条日志
|
||||
saveDone: make(chan struct{}),
|
||||
stopped: false, // 初始化为未停止状态
|
||||
}
|
||||
@@ -246,25 +263,6 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
// 更新客户端统计
|
||||
s.updateClientStats(sourceIP)
|
||||
|
||||
// 只处理递归查询
|
||||
if r.RecursionDesired == false {
|
||||
response := new(dns.Msg)
|
||||
response.SetReply(r)
|
||||
response.RecursionAvailable = true
|
||||
response.SetRcode(r, dns.RcodeRefused)
|
||||
w.WriteMsg(response)
|
||||
|
||||
// 计算响应时间
|
||||
responseTime := time.Since(startTime).Milliseconds()
|
||||
s.updateStats(func(stats *Stats) {
|
||||
stats.TotalResponseTime += responseTime
|
||||
if stats.Queries > 0 {
|
||||
stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 获取查询域名和类型
|
||||
var domain string
|
||||
var queryType string
|
||||
@@ -284,6 +282,28 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
|
||||
logger.Debug("接收到DNS查询", "domain", domain, "type", queryType, "client", w.RemoteAddr())
|
||||
|
||||
// 只处理递归查询
|
||||
if r.RecursionDesired == false {
|
||||
response := new(dns.Msg)
|
||||
response.SetReply(r)
|
||||
response.RecursionAvailable = true
|
||||
response.SetRcode(r, dns.RcodeRefused)
|
||||
w.WriteMsg(response)
|
||||
|
||||
// 计算响应时间
|
||||
responseTime := time.Since(startTime).Milliseconds()
|
||||
s.updateStats(func(stats *Stats) {
|
||||
stats.TotalResponseTime += responseTime
|
||||
if stats.Queries > 0 {
|
||||
stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries)
|
||||
}
|
||||
})
|
||||
|
||||
// 添加查询日志
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "error", "", "")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查hosts文件是否有匹配
|
||||
if ip, exists := s.shieldManager.GetHostsIP(domain); exists {
|
||||
s.handleHostsResponse(w, r, ip)
|
||||
@@ -295,11 +315,19 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries)
|
||||
}
|
||||
})
|
||||
|
||||
// 添加查询日志
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否被屏蔽
|
||||
if s.shieldManager.IsBlocked(domain) {
|
||||
// 获取屏蔽详情
|
||||
blockDetails := s.shieldManager.CheckDomainBlockDetails(domain)
|
||||
blockRule, _ := blockDetails["blockRule"].(string)
|
||||
blockType, _ := blockDetails["blockRuleType"].(string)
|
||||
|
||||
s.handleBlockedResponse(w, r, domain)
|
||||
// 计算响应时间
|
||||
responseTime := time.Since(startTime).Milliseconds()
|
||||
@@ -309,6 +337,9 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries)
|
||||
}
|
||||
})
|
||||
|
||||
// 添加查询日志
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "blocked", blockRule, blockType)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -322,6 +353,9 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
stats.AvgResponseTime = float64(stats.TotalResponseTime) / float64(stats.Queries)
|
||||
}
|
||||
})
|
||||
|
||||
// 添加查询日志
|
||||
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "")
|
||||
}
|
||||
|
||||
// handleHostsResponse 处理hosts文件匹配的响应
|
||||
@@ -539,6 +573,33 @@ func (s *Server) updateStats(update func(*Stats)) {
|
||||
update(s.stats)
|
||||
}
|
||||
|
||||
// addQueryLog 添加查询日志
|
||||
func (s *Server) addQueryLog(clientIP, domain, queryType string, responseTime int64, result, blockRule, blockType string) {
|
||||
// 创建日志记录
|
||||
log := QueryLog{
|
||||
Timestamp: time.Now(),
|
||||
ClientIP: clientIP,
|
||||
Domain: domain,
|
||||
QueryType: queryType,
|
||||
ResponseTime: responseTime,
|
||||
Result: result,
|
||||
BlockRule: blockRule,
|
||||
BlockType: blockType,
|
||||
}
|
||||
|
||||
// 添加到日志列表
|
||||
s.queryLogsMutex.Lock()
|
||||
defer s.queryLogsMutex.Unlock()
|
||||
|
||||
// 插入到列表开头
|
||||
s.queryLogs = append([]QueryLog{log}, s.queryLogs...)
|
||||
|
||||
// 限制日志数量
|
||||
if len(s.queryLogs) > s.maxQueryLogs {
|
||||
s.queryLogs = s.queryLogs[:s.maxQueryLogs]
|
||||
}
|
||||
}
|
||||
|
||||
// GetStartTime 获取服务器启动时间
|
||||
func (s *Server) GetStartTime() time.Time {
|
||||
return s.startTime
|
||||
@@ -576,6 +637,55 @@ func (s *Server) GetStats() *Stats {
|
||||
}
|
||||
}
|
||||
|
||||
// GetQueryLogs 获取查询日志
|
||||
func (s *Server) GetQueryLogs(limit, offset int) []QueryLog {
|
||||
s.queryLogsMutex.RLock()
|
||||
defer s.queryLogsMutex.RUnlock()
|
||||
|
||||
// 确保偏移量和限制值合理
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = 100 // 默认返回100条日志
|
||||
}
|
||||
|
||||
// 计算返回范围
|
||||
start := offset
|
||||
end := offset + limit
|
||||
if end > len(s.queryLogs) {
|
||||
end = len(s.queryLogs)
|
||||
}
|
||||
if start >= len(s.queryLogs) {
|
||||
return []QueryLog{} // 没有数据,返回空切片
|
||||
}
|
||||
|
||||
return s.queryLogs[start:end]
|
||||
}
|
||||
|
||||
// GetQueryLogsCount 获取查询日志总数
|
||||
func (s *Server) GetQueryLogsCount() int {
|
||||
s.queryLogsMutex.RLock()
|
||||
defer s.queryLogsMutex.RUnlock()
|
||||
return len(s.queryLogs)
|
||||
}
|
||||
|
||||
// GetQueryStats 获取查询统计信息
|
||||
func (s *Server) GetQueryStats() map[string]interface{} {
|
||||
s.statsMutex.Lock()
|
||||
defer s.statsMutex.Unlock()
|
||||
|
||||
// 计算统计数据
|
||||
return map[string]interface{}{
|
||||
"totalQueries": s.stats.Queries,
|
||||
"blockedQueries": s.stats.Blocked,
|
||||
"allowedQueries": s.stats.Allowed,
|
||||
"errorQueries": s.stats.Errors,
|
||||
"avgResponseTime": s.stats.AvgResponseTime,
|
||||
"activeIPs": len(s.stats.SourceIPs),
|
||||
}
|
||||
}
|
||||
|
||||
// GetTopBlockedDomains 获取TOP屏蔽域名列表
|
||||
func (s *Server) GetTopBlockedDomains(limit int) []BlockedDomain {
|
||||
s.blockedDomainsMutex.RLock()
|
||||
|
||||
Reference in New Issue
Block a user