修复规则优先级问题,修复添加自定义规则后需要重启服务器的问题
This commit is contained in:
@@ -2,6 +2,12 @@
|
||||
|
||||
所有对本项目的显著更改都将记录在此文件中。
|
||||
|
||||
## [1.1.4] - 2025-12-21
|
||||
|
||||
### 修复
|
||||
- 修复规则优先级问题:确保自定义规则优先于远程规则
|
||||
- 修复添加自定义规则后需要重启服务器的问题:通过在添加或删除规则后清空DNS缓存实现
|
||||
|
||||
## [1.1.3] - 2025-12-19
|
||||
|
||||
### 移除
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
- 支持域名规则和正则表达式规则
|
||||
- 支持规则例外
|
||||
- 支持远程规则列表
|
||||
- 支持本地规则管理
|
||||
- 支持自定义规则管理
|
||||
|
||||
### 3. 查询日志记录和统计
|
||||
- 实时记录DNS查询日志
|
||||
@@ -116,7 +116,7 @@ http://localhost:8080
|
||||
|
||||
1. 登录Web控制台
|
||||
2. 点击左侧菜单中的"屏蔽管理"
|
||||
3. 在"本地规则管理"中添加或删除规则
|
||||
3. 在"自定义规则管理"中添加或删除规则
|
||||
4. 在"远程黑名单管理"中添加或删除远程规则列表
|
||||
|
||||
### 查看查询日志
|
||||
|
||||
26
config.json
26
config.json
@@ -2,7 +2,7 @@
|
||||
"dns": {
|
||||
"port": 53,
|
||||
"upstreamDNS": [
|
||||
"10.35.10.200:53"
|
||||
"223.5.5.5:53"
|
||||
],
|
||||
"dnssecUpstreamDNS": [
|
||||
"117.50.10.10:53",
|
||||
@@ -18,10 +18,16 @@
|
||||
"enableDNSSEC": true,
|
||||
"queryMode": "loadbalance",
|
||||
"domainSpecificDNS": {
|
||||
"amazehome.cn": [
|
||||
"addr.arpa": [
|
||||
"10.35.10.200:53"
|
||||
],
|
||||
"addr.arpa": [
|
||||
"akadns": [
|
||||
"4.2.2.1:53"
|
||||
],
|
||||
"akamai": [
|
||||
"4.2.2.1:53"
|
||||
],
|
||||
"amazehome.cn": [
|
||||
"10.35.10.200:53"
|
||||
],
|
||||
"amazehome.xyz": [
|
||||
@@ -29,14 +35,7 @@
|
||||
],
|
||||
"microsoft.com": [
|
||||
"4.2.2.1:53"
|
||||
],
|
||||
"akamai": [
|
||||
"4.2.2.1:53"
|
||||
],
|
||||
"akadns": [
|
||||
"4.2.2.1:53"
|
||||
]
|
||||
|
||||
},
|
||||
"noDNSSECDomains": [
|
||||
"amazehome.cn",
|
||||
@@ -59,7 +58,7 @@
|
||||
"name": "AdGuard DNS filter",
|
||||
"url": "https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/filter.txt",
|
||||
"enabled": true,
|
||||
"lastUpdateTime": "2025-11-28T16:13:03.564Z"
|
||||
"lastUpdateTime": "2025-12-21T10:46:36.629Z"
|
||||
},
|
||||
{
|
||||
"name": "Adaway Default Blocklist",
|
||||
@@ -92,7 +91,8 @@
|
||||
{
|
||||
"name": "Hate \u0026 Junk",
|
||||
"url": "http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/hate-and-junk-extended.txt",
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"lastUpdateTime": "2025-12-21T10:46:43.522Z"
|
||||
},
|
||||
{
|
||||
"name": "My Gitlab Hosts",
|
||||
@@ -152,4 +152,4 @@
|
||||
"maxBackups": 10,
|
||||
"maxAge": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ type Server struct {
|
||||
ipGeolocationCacheTTL time.Duration // 缓存有效期
|
||||
|
||||
// DNS查询缓存
|
||||
dnsCache *DNSCache // DNS响应缓存
|
||||
DnsCache *DNSCache // DNS响应缓存
|
||||
|
||||
// 域名DNSSEC状态映射表
|
||||
domainDNSSECStatus map[string]bool // 域名到DNSSEC状态的映射
|
||||
@@ -199,7 +199,7 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie
|
||||
ipGeolocationCache: make(map[string]*IPGeolocation),
|
||||
ipGeolocationCacheTTL: 24 * time.Hour, // 缓存有效期24小时
|
||||
// DNS查询缓存初始化
|
||||
dnsCache: NewDNSCache(cacheTTL),
|
||||
DnsCache: NewDNSCache(cacheTTL),
|
||||
// 初始化域名DNSSEC状态映射表
|
||||
domainDNSSECStatus: make(map[string]bool),
|
||||
// 初始化服务器状态跟踪
|
||||
@@ -419,7 +419,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
var cachedDNSSEC bool
|
||||
|
||||
// 1. 首先检查是否有普通缓存项
|
||||
if tempResponse, tempFound := s.dnsCache.Get(r.Question[0].Name, qType); tempFound {
|
||||
if tempResponse, tempFound := s.DnsCache.Get(r.Question[0].Name, qType); tempFound {
|
||||
cachedResponse = tempResponse
|
||||
found = tempFound
|
||||
cachedDNSSEC = s.hasDNSSECRecords(tempResponse)
|
||||
@@ -562,7 +562,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
responseCopy := response.Copy()
|
||||
// 设置合理的TTL,不超过默认的30分钟
|
||||
defaultCacheTTL := 30 * time.Minute
|
||||
s.dnsCache.Set(r.Question[0].Name, qType, responseCopy, defaultCacheTTL)
|
||||
s.DnsCache.Set(r.Question[0].Name, qType, responseCopy, defaultCacheTTL)
|
||||
logger.Debug("DNS响应已缓存", "domain", domain, "type", queryType, "ttl", defaultCacheTTL, "dnssec", responseDNSSEC)
|
||||
}
|
||||
|
||||
|
||||
@@ -832,6 +832,9 @@ func (s *Server) handleShield(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// 清空DNS缓存,使新规则立即生效
|
||||
s.dnsServer.DnsCache.Clear()
|
||||
|
||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||
return
|
||||
case http.MethodDelete:
|
||||
@@ -850,6 +853,9 @@ func (s *Server) handleShield(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// 清空DNS缓存,使规则变更立即生效
|
||||
s.dnsServer.DnsCache.Clear()
|
||||
|
||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||
return
|
||||
case http.MethodPut:
|
||||
|
||||
6
main.go
6
main.go
@@ -121,10 +121,10 @@ func createRequiredFiles(cfg *config.Config) error {
|
||||
}
|
||||
}
|
||||
|
||||
// 创建本地规则文件
|
||||
// 创建自定义规则文件
|
||||
if _, err := os.Stat(cfg.Shield.LocalRulesFile); os.IsNotExist(err) {
|
||||
if err := os.WriteFile(cfg.Shield.LocalRulesFile, []byte("# 本地规则文件\n# 格式:域名\n# 例如:example.com\n"), 0644); err != nil {
|
||||
return fmt.Errorf("创建本地规则文件失败: %w", err)
|
||||
if err := os.WriteFile(cfg.Shield.LocalRulesFile, []byte("# 自定义规则文件\n# 格式:域名\n# 例如:example.com\n"), 0644); err != nil {
|
||||
return fmt.Errorf("创建自定义规则文件失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ type ShieldStatsData struct {
|
||||
type regexRule struct {
|
||||
pattern *regexp.Regexp
|
||||
original string
|
||||
isLocal bool // 是否为本地规则
|
||||
isLocal bool // 是否为自定义规则
|
||||
source string // 规则来源
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ type ShieldManager struct {
|
||||
config *config.ShieldConfig
|
||||
domainRules map[string]bool
|
||||
domainExceptions map[string]bool
|
||||
domainRulesIsLocal map[string]bool // 标记域名规则是否为本地规则
|
||||
domainExceptionsIsLocal map[string]bool // 标记域名排除规则是否为本地规则
|
||||
domainRulesIsLocal map[string]bool // 标记域名规则是否为自定义规则
|
||||
domainExceptionsIsLocal map[string]bool // 标记域名排除规则是否为自定义规则
|
||||
domainRulesSource map[string]string // 标记域名规则来源
|
||||
domainExceptionsSource map[string]string // 标记域名排除规则来源
|
||||
domainRulesOriginal map[string]string // 存储域名规则的原始字符串
|
||||
@@ -54,7 +54,7 @@ type ShieldManager struct {
|
||||
updateCtx context.Context
|
||||
updateCancel context.CancelFunc
|
||||
updateRunning bool
|
||||
localRulesCount int // 本地规则数量
|
||||
localRulesCount int // 自定义规则数量
|
||||
remoteRulesCount int // 远程规则数量
|
||||
}
|
||||
|
||||
@@ -109,9 +109,9 @@ func (m *ShieldManager) LoadRules() error {
|
||||
m.remoteRulesCount = 0
|
||||
// 保留计数数据,不随规则重新加载而清空
|
||||
|
||||
// 加载本地规则文件
|
||||
// 加载自定义规则文件
|
||||
if err := m.loadLocalRules(); err != nil {
|
||||
logger.Error("加载本地规则失败", "error", err)
|
||||
logger.Error("加载自定义规则失败", "error", err)
|
||||
// 继续执行,不返回错误
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func (m *ShieldManager) LoadRules() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadLocalRules 加载本地规则文件
|
||||
// loadLocalRules 加载自定义规则文件
|
||||
func (m *ShieldManager) loadLocalRules() error {
|
||||
if m.config.LocalRulesFile == "" {
|
||||
return nil
|
||||
@@ -144,7 +144,7 @@ func (m *ShieldManager) loadLocalRules() error {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 记录加载前的规则数量,用于计算本地规则数量
|
||||
// 记录加载前的规则数量,用于计算自定义规则数量
|
||||
beforeDomainRules := len(m.domainRules)
|
||||
beforeRegexRules := len(m.regexRules)
|
||||
|
||||
@@ -154,10 +154,10 @@ func (m *ShieldManager) loadLocalRules() error {
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
m.parseRule(line, true, "本地规则") // 本地规则,isLocal=true,来源为"本地规则"
|
||||
m.parseRule(line, true, "自定义规则") // 自定义规则,isLocal=true,来源为"自定义规则"
|
||||
}
|
||||
|
||||
// 更新本地规则计数
|
||||
// 更新自定义规则计数
|
||||
m.localRulesCount = (len(m.domainRules) - beforeDomainRules) + (len(m.regexRules) - beforeRegexRules)
|
||||
|
||||
return scanner.Err()
|
||||
@@ -445,10 +445,16 @@ func (m *ShieldManager) parseRuleOptions(optionsStr string) map[string]string {
|
||||
// addDomainRule 添加域名规则,支持是否为阻止规则
|
||||
func (m *ShieldManager) addDomainRule(domain string, block bool, isLocal bool, source string, original string) {
|
||||
if block {
|
||||
// 如果是远程规则,检查是否已经存在本地规则,如果存在则不覆盖
|
||||
// 如果是远程规则,检查是否已经存在自定义规则(阻止或排除),如果存在则不覆盖
|
||||
if !isLocal {
|
||||
// 检查是否存在自定义阻止规则
|
||||
if _, exists := m.domainRulesIsLocal[domain]; exists && m.domainRulesIsLocal[domain] {
|
||||
// 已经存在本地规则,不覆盖
|
||||
// 已经存在自定义规则,不覆盖
|
||||
return
|
||||
}
|
||||
// 检查是否存在自定义排除规则
|
||||
if _, exists := m.domainExceptionsIsLocal[domain]; exists && m.domainExceptionsIsLocal[domain] {
|
||||
// 已经存在自定义规则,不覆盖
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -458,10 +464,16 @@ func (m *ShieldManager) addDomainRule(domain string, block bool, isLocal bool, s
|
||||
m.domainRulesOriginal[domain] = original
|
||||
} else {
|
||||
// 添加到排除规则
|
||||
// 如果是远程规则,检查是否已经存在本地规则,如果存在则不覆盖
|
||||
// 如果是远程规则,检查是否已经存在自定义规则(阻止或排除),如果存在则不覆盖
|
||||
if !isLocal {
|
||||
// 检查是否存在自定义阻止规则
|
||||
if _, exists := m.domainRulesIsLocal[domain]; exists && m.domainRulesIsLocal[domain] {
|
||||
// 已经存在自定义规则,不覆盖
|
||||
return
|
||||
}
|
||||
// 检查是否存在自定义排除规则
|
||||
if _, exists := m.domainExceptionsIsLocal[domain]; exists && m.domainExceptionsIsLocal[domain] {
|
||||
// 已经存在本地规则,不覆盖
|
||||
// 已经存在自定义规则,不覆盖
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -481,11 +493,19 @@ func (m *ShieldManager) addRegexRule(re *regexp.Regexp, original string, block b
|
||||
source: source,
|
||||
}
|
||||
if block {
|
||||
// 如果是远程规则,检查是否已经存在相同的本地规则,如果存在则不添加
|
||||
// 如果是远程规则,检查是否已经存在任何自定义规则,如果存在则不添加
|
||||
if !isLocal {
|
||||
// 检查是否存在自定义阻止规则
|
||||
for _, existingRule := range m.regexRules {
|
||||
if existingRule.original == original && existingRule.isLocal {
|
||||
// 已经存在相同的本地规则,不添加
|
||||
if existingRule.pattern.String() == re.String() && existingRule.isLocal {
|
||||
// 已经存在相同的自定义阻止规则,不添加
|
||||
return
|
||||
}
|
||||
}
|
||||
// 检查是否存在自定义排除规则
|
||||
for _, existingRule := range m.regexExceptions {
|
||||
if existingRule.pattern.String() == re.String() && existingRule.isLocal {
|
||||
// 已经存在相同的自定义排除规则,不添加
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -493,11 +513,19 @@ func (m *ShieldManager) addRegexRule(re *regexp.Regexp, original string, block b
|
||||
m.regexRules = append(m.regexRules, rule)
|
||||
} else {
|
||||
// 添加到排除规则
|
||||
// 如果是远程规则,检查是否已经存在相同的本地规则,如果存在则不添加
|
||||
// 如果是远程规则,检查是否已经存在任何自定义规则,如果存在则不添加
|
||||
if !isLocal {
|
||||
// 检查是否存在自定义阻止规则
|
||||
for _, existingRule := range m.regexRules {
|
||||
if existingRule.pattern.String() == re.String() && existingRule.isLocal {
|
||||
// 已经存在相同的自定义阻止规则,不添加
|
||||
return
|
||||
}
|
||||
}
|
||||
// 检查是否存在自定义排除规则
|
||||
for _, existingRule := range m.regexExceptions {
|
||||
if existingRule.original == original && existingRule.isLocal {
|
||||
// 已经存在相同的本地规则,不添加
|
||||
if existingRule.pattern.String() == re.String() && existingRule.isLocal {
|
||||
// 已经存在相同的自定义排除规则,不添加
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -537,8 +565,17 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf
|
||||
result["hostsIP"] = hostsIP
|
||||
|
||||
// 检查排除规则(优先级最高)
|
||||
// 检查域名排除规则
|
||||
if m.domainExceptions[domain] {
|
||||
// 1. 先检查本地域名排除规则
|
||||
if m.domainExceptions[domain] && m.domainExceptionsIsLocal[domain] {
|
||||
result["excluded"] = true
|
||||
result["excludeRule"] = m.domainExceptionsOriginal[domain]
|
||||
result["excludeRuleType"] = "exact_domain"
|
||||
result["blocksource"] = m.domainExceptionsSource[domain]
|
||||
return result
|
||||
}
|
||||
|
||||
// 2. 再检查远程域名排除规则
|
||||
if m.domainExceptions[domain] && !m.domainExceptionsIsLocal[domain] {
|
||||
result["excluded"] = true
|
||||
result["excludeRule"] = m.domainExceptionsOriginal[domain]
|
||||
result["excludeRuleType"] = "exact_domain"
|
||||
@@ -548,9 +585,11 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf
|
||||
|
||||
// 检查子域名排除规则
|
||||
parts := strings.Split(domain, ".")
|
||||
|
||||
// 3. 先检查本地子域名排除规则
|
||||
for i := 0; i < len(parts)-1; i++ {
|
||||
subdomain := strings.Join(parts[i:], ".")
|
||||
if m.domainExceptions[subdomain] {
|
||||
if m.domainExceptions[subdomain] && m.domainExceptionsIsLocal[subdomain] {
|
||||
result["excluded"] = true
|
||||
result["excludeRule"] = m.domainExceptionsOriginal[subdomain]
|
||||
result["excludeRuleType"] = "subdomain"
|
||||
@@ -559,9 +598,32 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf
|
||||
}
|
||||
}
|
||||
|
||||
// 检查正则表达式排除规则
|
||||
// 4. 再检查远程子域名排除规则
|
||||
for i := 0; i < len(parts)-1; i++ {
|
||||
subdomain := strings.Join(parts[i:], ".")
|
||||
if m.domainExceptions[subdomain] && !m.domainExceptionsIsLocal[subdomain] {
|
||||
result["excluded"] = true
|
||||
result["excludeRule"] = m.domainExceptionsOriginal[subdomain]
|
||||
result["excludeRuleType"] = "subdomain"
|
||||
result["blocksource"] = m.domainExceptionsSource[subdomain]
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 先检查本地正则表达式排除规则
|
||||
for _, re := range m.regexExceptions {
|
||||
if re.pattern.MatchString(domain) {
|
||||
if re.isLocal && re.pattern.MatchString(domain) {
|
||||
result["excluded"] = true
|
||||
result["excludeRule"] = re.original
|
||||
result["excludeRuleType"] = "regex"
|
||||
result["blocksource"] = re.source
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 再检查远程正则表达式排除规则
|
||||
for _, re := range m.regexExceptions {
|
||||
if !re.isLocal && re.pattern.MatchString(domain) {
|
||||
result["excluded"] = true
|
||||
result["excludeRule"] = re.original
|
||||
result["excludeRuleType"] = "regex"
|
||||
@@ -571,8 +633,17 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf
|
||||
}
|
||||
|
||||
// 检查阻止规则 - 先检查精确域名匹配,再检查子域名匹配
|
||||
// 检查精确域名匹配
|
||||
if m.domainRules[domain] {
|
||||
// 7. 先检查本地域名阻止规则
|
||||
if m.domainRules[domain] && m.domainRulesIsLocal[domain] {
|
||||
result["blocked"] = true
|
||||
result["blockRule"] = m.domainRulesOriginal[domain]
|
||||
result["blockRuleType"] = "exact_domain"
|
||||
result["blocksource"] = m.domainRulesSource[domain]
|
||||
return result
|
||||
}
|
||||
|
||||
// 8. 再检查远程域名阻止规则
|
||||
if m.domainRules[domain] && !m.domainRulesIsLocal[domain] {
|
||||
result["blocked"] = true
|
||||
result["blockRule"] = m.domainRulesOriginal[domain]
|
||||
result["blockRuleType"] = "exact_domain"
|
||||
@@ -582,9 +653,11 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf
|
||||
|
||||
// 检查子域名匹配(AdGuardHome风格)
|
||||
// 从最长的子域名开始匹配,确保优先级正确
|
||||
|
||||
// 9. 先检查本地子域名阻止规则
|
||||
for i := 0; i < len(parts)-1; i++ {
|
||||
subdomain := strings.Join(parts[i:], ".")
|
||||
if m.domainRules[subdomain] {
|
||||
if m.domainRules[subdomain] && m.domainRulesIsLocal[subdomain] {
|
||||
result["blocked"] = true
|
||||
result["blockRule"] = m.domainRulesOriginal[subdomain]
|
||||
result["blockRuleType"] = "subdomain"
|
||||
@@ -593,9 +666,32 @@ func (m *ShieldManager) CheckDomainBlockDetails(domain string) map[string]interf
|
||||
}
|
||||
}
|
||||
|
||||
// 检查正则表达式匹配
|
||||
// 10. 再检查远程子域名阻止规则
|
||||
for i := 0; i < len(parts)-1; i++ {
|
||||
subdomain := strings.Join(parts[i:], ".")
|
||||
if m.domainRules[subdomain] && !m.domainRulesIsLocal[subdomain] {
|
||||
result["blocked"] = true
|
||||
result["blockRule"] = m.domainRulesOriginal[subdomain]
|
||||
result["blockRuleType"] = "subdomain"
|
||||
result["blocksource"] = m.domainRulesSource[subdomain]
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// 11. 先检查本地正则表达式阻止规则
|
||||
for _, re := range m.regexRules {
|
||||
if re.pattern.MatchString(domain) {
|
||||
if re.isLocal && re.pattern.MatchString(domain) {
|
||||
result["blocked"] = true
|
||||
result["blockRule"] = re.original
|
||||
result["blockRuleType"] = "regex"
|
||||
result["blocksource"] = re.source
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// 12. 再检查远程正则表达式阻止规则
|
||||
for _, re := range m.regexRules {
|
||||
if !re.isLocal && re.pattern.MatchString(domain) {
|
||||
result["blocked"] = true
|
||||
result["blockRule"] = re.original
|
||||
result["blockRuleType"] = "regex"
|
||||
@@ -722,13 +818,13 @@ func (m *ShieldManager) GetHostsIP(domain string) (string, bool) {
|
||||
return ip, exists
|
||||
}
|
||||
|
||||
// AddRule 添加屏蔽规则,用户添加的规则是本地规则
|
||||
// AddRule 添加屏蔽规则,用户添加的规则是自定义规则
|
||||
func (m *ShieldManager) AddRule(rule string) error {
|
||||
m.rulesMutex.Lock()
|
||||
defer m.rulesMutex.Unlock()
|
||||
|
||||
// 解析并添加规则到内存,isLocal=true表示本地规则,来源为"本地规则"
|
||||
m.parseRule(rule, true, "本地规则")
|
||||
// 解析并添加规则到内存,isLocal=true表示自定义规则,来源为"自定义规则"
|
||||
m.parseRule(rule, true, "自定义规则")
|
||||
|
||||
// 持久化保存规则到文件
|
||||
if m.config.LocalRulesFile != "" {
|
||||
@@ -957,7 +1053,7 @@ func (m *ShieldManager) StopAutoUpdate() {
|
||||
logger.Info("规则自动更新已停止")
|
||||
}
|
||||
|
||||
// saveRulesToFile 保存规则到文件,只保存本地规则
|
||||
// saveRulesToFile 保存规则到文件,只保存自定义规则
|
||||
func (m *ShieldManager) saveRulesToFile() error {
|
||||
var rules []string
|
||||
|
||||
@@ -1293,12 +1389,12 @@ func (m *ShieldManager) GetHostsCount() int {
|
||||
return len(m.hostsMap)
|
||||
}
|
||||
|
||||
// GetLocalRules 获取仅本地规则
|
||||
// GetLocalRules 获取仅自定义规则
|
||||
func (m *ShieldManager) GetLocalRules() map[string]interface{} {
|
||||
m.rulesMutex.RLock()
|
||||
defer m.rulesMutex.RUnlock()
|
||||
|
||||
// 转换map和slice为字符串列表,只包含本地规则
|
||||
// 转换map和slice为字符串列表,只包含自定义规则
|
||||
domainRulesList := make([]string, 0)
|
||||
for domain, isLocal := range m.domainRulesIsLocal {
|
||||
if isLocal && m.domainRules[domain] {
|
||||
@@ -1329,7 +1425,7 @@ func (m *ShieldManager) GetLocalRules() map[string]interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
// 计算本地规则数量
|
||||
// 计算自定义规则数量
|
||||
localDomainRulesCount := 0
|
||||
for _, isLocal := range m.domainRulesIsLocal {
|
||||
if isLocal {
|
||||
|
||||
@@ -1138,12 +1138,12 @@
|
||||
},
|
||||
"/shield/localrules": {
|
||||
"get": {
|
||||
"summary": "获取本地规则",
|
||||
"description": "获取Shield的本地规则列表。",
|
||||
"summary": "获取自定义规则",
|
||||
"description": "获取Shield的自定义规则列表。"
|
||||
"tags": ["shield"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功获取本地规则",
|
||||
"description": "成功获取自定义规则",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
@@ -1166,8 +1166,8 @@
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"summary": "添加本地规则",
|
||||
"description": "添加新的本地规则。",
|
||||
"summary": "添加自定义规则",
|
||||
"description": "添加新的自定义规则。",
|
||||
"tags": ["shield"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
@@ -1205,8 +1205,8 @@
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"summary": "删除本地规则",
|
||||
"description": "删除指定ID的本地规则。",
|
||||
"summary": "删除自定义规则",
|
||||
"description": "删除指定ID的自定义规则。",
|
||||
"tags": ["shield"],
|
||||
"parameters": [
|
||||
{
|
||||
@@ -1500,7 +1500,7 @@
|
||||
"blocked": true,
|
||||
"blockRule": "example.com",
|
||||
"blockRuleType": "exact_domain",
|
||||
"blocksource": "本地规则",
|
||||
"blocksource": "自定义规则",
|
||||
"excluded": false,
|
||||
"excludeRule": "",
|
||||
"excludeRuleType": "",
|
||||
|
||||
@@ -630,9 +630,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 本地规则管理 -->
|
||||
<!-- 自定义规则管理 -->
|
||||
<div class="bg-white rounded-lg p-6 card-shadow">
|
||||
<h3 class="text-lg font-semibold mb-6">本地规则管理</h3>
|
||||
<h3 class="text-lg font-semibold mb-6">自定义规则管理</h3>
|
||||
|
||||
<!-- 添加规则表单 -->
|
||||
<div id="add-rule-form" class="mb-6 bg-gray-50 p-4 rounded-lg">
|
||||
@@ -976,11 +976,12 @@
|
||||
</th>
|
||||
<th class="text-left py-3 px-4 text-sm font-medium text-gray-500">响应时间</th>
|
||||
<th class="text-left py-3 px-4 text-sm font-medium text-gray-500">屏蔽规则</th>
|
||||
<th class="text-center py-3 px-4 text-sm font-medium text-gray-500">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="logs-table-body">
|
||||
<tr>
|
||||
<td colspan="5" class="py-8 text-center text-gray-500 border-b border-gray-100">
|
||||
<td colspan="6" class="py-8 text-center text-gray-500 border-b border-gray-100">
|
||||
<i class="fa fa-file-text-o text-4xl mb-2 text-gray-300"></i>
|
||||
<div>暂无查询日志</div>
|
||||
</td>
|
||||
@@ -1056,7 +1057,7 @@
|
||||
<h4 class="text-md font-medium mb-4">屏蔽配置</h4>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label for="shield-local-rules-file" class="block text-sm font-medium text-gray-700 mb-1">本地规则文件</label>
|
||||
<label for="shield-local-rules-file" class="block text-sm font-medium text-gray-700 mb-1">自定义规则文件</label>
|
||||
<input type="text" id="shield-local-rules-file" 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="./rules.txt">
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -282,6 +282,9 @@ function loadLogs() {
|
||||
// 更新日志表格
|
||||
updateLogsTable(logs);
|
||||
|
||||
// 绑定操作按钮事件
|
||||
bindActionButtonsEvents();
|
||||
|
||||
// 更新分页信息
|
||||
updateLogsPagination();
|
||||
|
||||
@@ -388,6 +391,9 @@ function updateLogsTable(logs) {
|
||||
const cacheStatusClass = log.FromCache ? 'text-primary' : 'text-gray-500';
|
||||
const cacheStatusText = log.FromCache ? '缓存' : '非缓存';
|
||||
|
||||
// 检查域名是否被拦截
|
||||
const isBlocked = log.Result === 'blocked';
|
||||
|
||||
row.innerHTML = `
|
||||
<td class="py-3 px-4">
|
||||
<div class="text-sm font-medium">${formattedTime}</div>
|
||||
@@ -404,7 +410,32 @@ function updateLogsTable(logs) {
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm">${log.ResponseTime}ms</td>
|
||||
<td class="py-3 px-4 text-sm text-gray-500">${log.BlockRule || '-'}</td>
|
||||
<td class="py-3 px-4 text-sm text-center">
|
||||
${isBlocked ?
|
||||
`<button class="unblock-btn px-3 py-1 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors text-xs" data-domain="${log.Domain}">放行</button>` :
|
||||
`<button class="block-btn px-3 py-1 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors text-xs" data-domain="${log.Domain}">拦截</button>`
|
||||
}
|
||||
</td>
|
||||
`;
|
||||
|
||||
// 绑定按钮事件
|
||||
const blockBtn = row.querySelector('.block-btn');
|
||||
if (blockBtn) {
|
||||
blockBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
const domain = e.currentTarget.dataset.domain;
|
||||
blockDomain(domain);
|
||||
});
|
||||
}
|
||||
|
||||
const unblockBtn = row.querySelector('.unblock-btn');
|
||||
if (unblockBtn) {
|
||||
unblockBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
const domain = e.currentTarget.dataset.domain;
|
||||
unblockDomain(domain);
|
||||
});
|
||||
}
|
||||
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
@@ -614,6 +645,146 @@ function updateLogsStatsFromWebSocket(stats) {
|
||||
}
|
||||
}
|
||||
|
||||
// 拦截域名
|
||||
async function blockDomain(domain) {
|
||||
try {
|
||||
console.log(`开始拦截域名: ${domain}`);
|
||||
|
||||
// 创建拦截规则,使用AdBlock Plus格式
|
||||
const blockRule = `||${domain}^`;
|
||||
console.log(`创建的拦截规则: ${blockRule}`);
|
||||
|
||||
// 调用API添加拦截规则
|
||||
console.log(`调用API添加拦截规则,路径: /shield, 方法: POST`);
|
||||
const response = await apiRequest('/shield', 'POST', { rule: blockRule });
|
||||
|
||||
console.log(`API响应:`, response);
|
||||
|
||||
// 处理不同的响应格式
|
||||
if (response && (response.success || response.status === 'success')) {
|
||||
// 重新加载日志,显示更新后的状态
|
||||
loadLogs();
|
||||
|
||||
// 刷新规则列表
|
||||
refreshRulesList();
|
||||
|
||||
// 显示成功通知
|
||||
if (typeof window.showNotification === 'function') {
|
||||
window.showNotification(`已成功拦截域名: ${domain}`, 'success');
|
||||
}
|
||||
} else {
|
||||
const errorMsg = response ? (response.message || '添加拦截规则失败') : '添加拦截规则失败: 无效的API响应';
|
||||
console.error(`拦截域名失败: ${errorMsg}`);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('拦截域名失败:', error);
|
||||
|
||||
// 显示错误通知
|
||||
if (typeof window.showNotification === 'function') {
|
||||
window.showNotification(`拦截域名失败: ${error.message}`, 'danger');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定操作按钮事件
|
||||
function bindActionButtonsEvents() {
|
||||
// 绑定拦截按钮事件
|
||||
const blockBtns = document.querySelectorAll('.block-btn');
|
||||
blockBtns.forEach(btn => {
|
||||
btn.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
const domain = e.currentTarget.dataset.domain;
|
||||
await blockDomain(domain);
|
||||
});
|
||||
});
|
||||
|
||||
// 绑定放行按钮事件
|
||||
const unblockBtns = document.querySelectorAll('.unblock-btn');
|
||||
unblockBtns.forEach(btn => {
|
||||
btn.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
const domain = e.currentTarget.dataset.domain;
|
||||
await unblockDomain(domain);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 刷新规则列表
|
||||
async function refreshRulesList() {
|
||||
try {
|
||||
// 调用API重新加载规则
|
||||
const response = await apiRequest('/shield', 'GET');
|
||||
|
||||
if (response) {
|
||||
// 处理规则列表响应
|
||||
let allRules = [];
|
||||
if (response && typeof response === 'object') {
|
||||
// 合并所有类型的规则到一个数组
|
||||
if (Array.isArray(response.domainRules)) allRules = allRules.concat(response.domainRules);
|
||||
if (Array.isArray(response.domainExceptions)) allRules = allRules.concat(response.domainExceptions);
|
||||
if (Array.isArray(response.regexRules)) allRules = allRules.concat(response.regexRules);
|
||||
if (Array.isArray(response.regexExceptions)) allRules = allRules.concat(response.regexExceptions);
|
||||
}
|
||||
|
||||
// 更新规则列表
|
||||
if (window.rules) {
|
||||
rules = allRules;
|
||||
filteredRules = [...rules];
|
||||
|
||||
// 更新规则数量统计
|
||||
if (window.updateRulesCount && typeof window.updateRulesCount === 'function') {
|
||||
window.updateRulesCount(rules.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('刷新规则列表失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 放行域名
|
||||
async function unblockDomain(domain) {
|
||||
try {
|
||||
console.log(`开始放行域名: ${domain}`);
|
||||
|
||||
// 创建放行规则,使用AdBlock Plus格式
|
||||
const allowRule = `@@||${domain}^`;
|
||||
console.log(`创建的放行规则: ${allowRule}`);
|
||||
|
||||
// 调用API添加放行规则
|
||||
console.log(`调用API添加放行规则,路径: /shield, 方法: POST`);
|
||||
const response = await apiRequest('/shield', 'POST', { rule: allowRule });
|
||||
|
||||
console.log(`API响应:`, response);
|
||||
|
||||
// 处理不同的响应格式
|
||||
if (response && (response.success || response.status === 'success')) {
|
||||
// 重新加载日志,显示更新后的状态
|
||||
loadLogs();
|
||||
|
||||
// 刷新规则列表
|
||||
refreshRulesList();
|
||||
|
||||
// 显示成功通知
|
||||
if (typeof window.showNotification === 'function') {
|
||||
window.showNotification(`已成功放行域名: ${domain}`, 'success');
|
||||
}
|
||||
} else {
|
||||
const errorMsg = response ? (response.message || '添加放行规则失败') : '添加放行规则失败: 无效的API响应';
|
||||
console.error(`放行域名失败: ${errorMsg}`);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('放行域名失败:', error);
|
||||
|
||||
// 显示错误通知
|
||||
if (typeof window.showNotification === 'function') {
|
||||
window.showNotification(`放行域名失败: ${error.message}`, 'danger');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 定期更新日志统计数据(备用方案)
|
||||
setInterval(() => {
|
||||
// 只有在查询日志页面时才更新
|
||||
|
||||
@@ -231,7 +231,7 @@ async function loadShieldStats() {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载本地规则
|
||||
// 加载自定义规则
|
||||
async function loadLocalRules() {
|
||||
try {
|
||||
const response = await fetch('/api/shield/localrules');
|
||||
@@ -242,7 +242,7 @@ async function loadLocalRules() {
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// 更新本地规则数量显示
|
||||
// 更新自定义规则数量显示
|
||||
if (document.getElementById('local-rules-count')) {
|
||||
document.getElementById('local-rules-count').textContent = data.localRulesCount || 0;
|
||||
}
|
||||
@@ -250,7 +250,7 @@ async function loadLocalRules() {
|
||||
// 设置当前规则类型
|
||||
currentRulesType = 'local';
|
||||
|
||||
// 合并所有本地规则
|
||||
// 合并所有自定义规则
|
||||
let rules = [];
|
||||
// 添加域名规则
|
||||
if (Array.isArray(data.domainRules)) {
|
||||
@@ -271,8 +271,8 @@ async function loadLocalRules() {
|
||||
|
||||
updateRulesTable(rules);
|
||||
} catch (error) {
|
||||
console.error('加载本地规则失败:', error);
|
||||
showNotification('加载本地规则失败', 'error');
|
||||
console.error('加载自定义规则失败:', error);
|
||||
showNotification('加载自定义规则失败', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1202,7 +1202,7 @@ let currentRulesType = 'local';
|
||||
|
||||
// 设置事件监听器
|
||||
function setupShieldEventListeners() {
|
||||
// 本地规则管理事件
|
||||
// 自定义规则管理事件
|
||||
const saveRuleBtn = document.getElementById('save-rule-btn');
|
||||
if (saveRuleBtn) {
|
||||
saveRuleBtn.addEventListener('click', handleAddRule);
|
||||
@@ -1214,7 +1214,7 @@ function setupShieldEventListeners() {
|
||||
saveBlacklistBtn.addEventListener('click', handleAddBlacklist);
|
||||
}
|
||||
|
||||
// 添加切换查看本地规则和远程规则的事件监听
|
||||
// 添加切换查看自定义规则和远程规则的事件监听
|
||||
const viewLocalRulesBtn = document.getElementById('view-local-rules-btn');
|
||||
if (viewLocalRulesBtn) {
|
||||
viewLocalRulesBtn.addEventListener('click', loadLocalRules);
|
||||
|
||||
52
temp_config.json
Normal file
52
temp_config.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"dns": {
|
||||
"port": 5353,
|
||||
"upstreamDNS": [
|
||||
"223.5.5.5:53",
|
||||
"223.6.6.6:53",
|
||||
"117.50.10.10:53",
|
||||
"10.35.10.200:53"
|
||||
],
|
||||
"dnssecUpstreamDNS": [
|
||||
"117.50.10.10:53",
|
||||
"101.226.4.6:53",
|
||||
"218.30.118.6:53",
|
||||
"208.67.220.220:53",
|
||||
"208.67.222.222:53"
|
||||
],
|
||||
"timeout": 5000,
|
||||
"statsFile": "data/stats.json",
|
||||
"saveInterval": 300,
|
||||
"cacheTTL": 30,
|
||||
"enableDNSSEC": true,
|
||||
"queryMode": "parallel",
|
||||
"domainSpecificDNS": {
|
||||
"amazehome.xyz": ["10.35.10.200:53"]
|
||||
}
|
||||
},
|
||||
"http": {
|
||||
"port": 8081,
|
||||
"host": "0.0.0.0",
|
||||
"enableAPI": true,
|
||||
"username": "admin",
|
||||
"password": "admin"
|
||||
},
|
||||
"shield": {
|
||||
"localRulesFile": "data/rules.txt",
|
||||
"blacklists": [],
|
||||
"updateInterval": 3600,
|
||||
"hostsFile": "data/hosts.txt",
|
||||
"blockMethod": "NXDOMAIN",
|
||||
"customBlockIP": "",
|
||||
"statsFile": "./data/shield_stats.json",
|
||||
"statsSaveInterval": 60,
|
||||
"remoteRulesCacheDir": "data/remote_rules"
|
||||
},
|
||||
"log": {
|
||||
"file": "logs/dns-server-5353.log",
|
||||
"level": "debug",
|
||||
"maxSize": 100,
|
||||
"maxBackups": 10,
|
||||
"maxAge": 30
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// testRuleMatching 测试DNS规则匹配功能
|
||||
func main() {
|
||||
// 定义命令行参数
|
||||
rulePtr := flag.String("rule", "||cntvwb.cn^", "规则字符串")
|
||||
testDomainPtr := flag.String("domain", "vdapprecv.app.cntvwb.cn", "测试域名")
|
||||
flag.Parse()
|
||||
|
||||
// 打印测试信息
|
||||
fmt.Printf("测试规则: %s\n", *rulePtr)
|
||||
fmt.Printf("测试域名: %s\n", *testDomainPtr)
|
||||
|
||||
// 发送HTTP请求到API端点来测试规则匹配
|
||||
fmt.Println("\n测试规则匹配功能...")
|
||||
cmd := exec.Command("curl", "-s", fmt.Sprintf("http://localhost:8080/api/shield/check?domain=%s&rule=%s", *testDomainPtr, *rulePtr))
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
// 如果直接的API测试失败,尝试另一种方法
|
||||
fmt.Printf("直接测试失败: %v, %s\n", err, string(output))
|
||||
fmt.Println("尝试添加规则并测试...")
|
||||
testAddRuleAndCheck(*rulePtr, *testDomainPtr)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("测试结果: %s\n", string(output))
|
||||
|
||||
// 验证规则是否生效(模拟测试)
|
||||
if strings.Contains(*rulePtr, "||cntvwb.cn^") && strings.Contains(*testDomainPtr, "cntvwb.cn") {
|
||||
fmt.Println("\n验证结果:")
|
||||
if strings.Contains(*testDomainPtr, "cntvwb.cn") {
|
||||
fmt.Println("✅ 子域名匹配测试通过:||cntvwb.cn^ 应该阻止所有 cntvwb.cn 的子域名")
|
||||
} else {
|
||||
fmt.Println("❌ 子域名匹配测试失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testAddRuleAndCheck 测试添加规则和检查域名是否被阻止
|
||||
func testAddRuleAndCheck(rule, domain string) {
|
||||
// 尝试通过API添加规则
|
||||
fmt.Printf("添加规则: %s\n", rule)
|
||||
cmd := exec.Command("curl", "-s", "-X", "POST", "http://localhost:8080/api/shield/local-rules", "-H", "Content-Type: application/json", "-d", fmt.Sprintf(`{\"rule\":\"%s\"}`, rule))
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Printf("添加规则失败: %v, %s\n", err, string(output))
|
||||
// 尝试重新加载规则
|
||||
fmt.Println("尝试重新加载规则...")
|
||||
cmd = exec.Command("curl", "-s", "-X", "PUT", "http://localhost:8080/api/shield", "-H", "Content-Type: application/json", "-d", `{\"reload\":true}`)
|
||||
output, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Printf("重新加载规则失败: %v, %s\n", err, string(output))
|
||||
} else {
|
||||
fmt.Printf("重新加载规则结果: %s\n", string(output))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("添加规则结果: %s\n", string(output))
|
||||
|
||||
// 测试域名是否被阻止
|
||||
fmt.Printf("测试域名 %s 是否被阻止...\n", domain)
|
||||
cmd = exec.Command("curl", "-s", fmt.Sprintf("http://localhost:8080/api/shield/check?domain=%s", domain))
|
||||
output, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
fmt.Printf("测试阻止失败: %v, %s\n", err, string(output))
|
||||
} else {
|
||||
fmt.Printf("阻止测试结果: %s\n", string(output))
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"dns": {
|
||||
"port": 5353,
|
||||
"upstreamDNS": [
|
||||
"223.5.5.5:53",
|
||||
"223.6.6.6:53"
|
||||
],
|
||||
"timeout": 5000,
|
||||
"statsFile": "data/test_stats.json",
|
||||
"saveInterval": 300,
|
||||
"cacheTTL": 30,
|
||||
"enableDNSSEC": true,
|
||||
"dnssecValidation": true
|
||||
},
|
||||
"http": {
|
||||
"port": 8081,
|
||||
"host": "0.0.0.0",
|
||||
"enableAPI": true,
|
||||
"username": "admin",
|
||||
"password": "admin"
|
||||
},
|
||||
"shield": {
|
||||
"localRulesFile": "data/test_rules.txt",
|
||||
"blacklists": [],
|
||||
"updateInterval": 3600,
|
||||
"hostsFile": "data/test_hosts.txt",
|
||||
"blockMethod": "NXDOMAIN",
|
||||
"customBlockIP": "",
|
||||
"statsFile": "./data/test_shield_stats.json",
|
||||
"statsSaveInterval": 60,
|
||||
"remoteRulesCacheDir": "data/test_remote_rules"
|
||||
},
|
||||
"log": {
|
||||
"file": "logs/test_dns-server.log",
|
||||
"level": "debug",
|
||||
"maxSize": 100,
|
||||
"maxBackups": 10,
|
||||
"maxAge": 30
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# DNS Web控制台功能测试脚本
|
||||
echo "开始测试DNS Web控制台功能..."
|
||||
echo "=================================="
|
||||
|
||||
# 检查服务器是否运行
|
||||
echo "检查DNS服务器运行状态..."
|
||||
pids=$(ps aux | grep dns-server | grep -v grep)
|
||||
if [ -n "$pids" ]; then
|
||||
echo "✓ DNS服务器正在运行"
|
||||
else
|
||||
echo "✗ DNS服务器未运行,请先启动服务器"
|
||||
fi
|
||||
|
||||
# 测试API基础URL
|
||||
BASE_URL="http://localhost:8080/api"
|
||||
|
||||
# 测试1: 获取统计信息
|
||||
echo "\n测试1: 获取DNS统计信息"
|
||||
curl -s -o /dev/null -w "状态码: %{http_code}\n" "$BASE_URL/stats"
|
||||
|
||||
# 测试2: 获取系统状态
|
||||
echo "\n测试2: 获取系统状态"
|
||||
curl -s -o /dev/null -w "状态码: %{http_code}\n" "$BASE_URL/status"
|
||||
|
||||
# 测试3: 获取屏蔽规则
|
||||
echo "\n测试3: 获取屏蔽规则列表"
|
||||
curl -s -o /dev/null -w "状态码: %{http_code}\n" "$BASE_URL/shield"
|
||||
|
||||
# 测试4: 获取Top屏蔽域名
|
||||
echo "\n测试4: 获取Top屏蔽域名"
|
||||
curl -s -o /dev/null -w "状态码: %{http_code}\n" "$BASE_URL/top-blocked"
|
||||
|
||||
# 测试5: 获取Hosts内容
|
||||
echo "\n测试5: 获取Hosts内容"
|
||||
curl -s -o /dev/null -w "状态码: %{http_code}\n" "$BASE_URL/shield/hosts"
|
||||
|
||||
# 测试6: 访问Web控制台主页
|
||||
echo "\n测试6: 访问Web控制台主页"
|
||||
curl -s -o /dev/null -w "状态码: %{http_code}\n" "http://localhost:8080"
|
||||
|
||||
echo "\n=================================="
|
||||
echo "测试完成!请检查上述状态码。正常情况下应为200。"
|
||||
echo "前端Web控制台可通过浏览器访问: http://localhost:8080"
|
||||
@@ -1,96 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 测试三种查询模式
|
||||
|
||||
echo "=== 测试三种查询模式 ==="
|
||||
|
||||
# 确保dig命令存在
|
||||
if ! command -v dig &> /dev/null; then
|
||||
echo "dig命令不存在,使用nslookup替代"
|
||||
USE_DIG=false
|
||||
else
|
||||
USE_DIG=true
|
||||
fi
|
||||
|
||||
echo "1. 测试并行请求模式"
|
||||
echo "修改配置文件为parallel模式"
|
||||
sed -i 's/"queryMode": "[^"]*"/"queryMode": "parallel"/' config.json
|
||||
cat config.json | grep queryMode
|
||||
|
||||
echo "重启DNS服务器..."
|
||||
pkill -f "go run main.go"
|
||||
sleep 2
|
||||
go run main.go > server.log 2>&1 &
|
||||
SERVER_PID=$!
|
||||
echo "服务器进程ID: $SERVER_PID"
|
||||
sleep 5
|
||||
|
||||
if [ -f server.log ]; then
|
||||
tail -5 server.log
|
||||
fi
|
||||
|
||||
echo "测试DNS查询..."
|
||||
if $USE_DIG; then
|
||||
dig @localhost example.com +short
|
||||
else
|
||||
nslookup example.com localhost | grep -A 2 "Name:"
|
||||
fi
|
||||
|
||||
echo "2. 测试负载均衡模式"
|
||||
echo "修改配置文件为loadbalance模式"
|
||||
sed -i 's/"queryMode": "[^"]*"/"queryMode": "loadbalance"/' config.json
|
||||
cat config.json | grep queryMode
|
||||
|
||||
echo "重启DNS服务器..."
|
||||
pkill -f "go run main.go"
|
||||
sleep 2
|
||||
go run main.go > server.log 2>&1 &
|
||||
SERVER_PID=$!
|
||||
echo "服务器进程ID: $SERVER_PID"
|
||||
sleep 5
|
||||
|
||||
if [ -f server.log ]; then
|
||||
tail -5 server.log
|
||||
fi
|
||||
|
||||
echo "测试DNS查询..."
|
||||
if $USE_DIG; then
|
||||
dig @localhost example.com +short
|
||||
else
|
||||
nslookup example.com localhost | grep -A 2 "Name:"
|
||||
fi
|
||||
|
||||
echo "3. 测试最快的IP地址模式"
|
||||
echo "修改配置文件为fastest-ip模式"
|
||||
sed -i 's/"queryMode": "[^"]*"/"queryMode": "fastest-ip"/' config.json
|
||||
cat config.json | grep queryMode
|
||||
|
||||
echo "重启DNS服务器..."
|
||||
pkill -f "go run main.go"
|
||||
sleep 2
|
||||
go run main.go > server.log 2>&1 &
|
||||
SERVER_PID=$!
|
||||
echo "服务器进程ID: $SERVER_PID"
|
||||
sleep 5
|
||||
|
||||
if [ -f server.log ]; then
|
||||
tail -5 server.log
|
||||
fi
|
||||
|
||||
echo "测试DNS查询..."
|
||||
if $USE_DIG; then
|
||||
dig @localhost example.com +short
|
||||
else
|
||||
nslookup example.com localhost | grep -A 2 "Name:"
|
||||
fi
|
||||
|
||||
echo "=== 测试完成 ==="
|
||||
echo "停止DNS服务器..."
|
||||
pkill -f "go run main.go"
|
||||
|
||||
# 删除日志文件
|
||||
rm -f server.log
|
||||
|
||||
echo "恢复默认配置..."
|
||||
sed -i 's/"queryMode": "[^"]*"/"queryMode": "parallel"/' config.json
|
||||
cat config.json | grep queryMode
|
||||
Reference in New Issue
Block a user