mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-30 13:25:13 +08:00
💐 Sync 2026-09-13 00:41:32
This commit is contained in:
1 parent
78eb4a4ed1
commit
e04615692f
6 files changed
+432
-199
No files matched your search
+1
-1
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=mosdns
|
||||
PKG_VERSION:=5.3.4
|
||||
PKG_RELEASE:=21
|
||||
PKG_RELEASE:=22
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/IrineSistiana/mosdns/tar.gz/v$(PKG_VERSION)?
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
From 5cb5430d8f942b317e02c2ec4e9383fe12857fb2 Mon Sep 17 00:00:00 2001
|
||||
From: sbwml <admin@cooluc.com>
|
||||
Date: Sat, 12 Sep 2026 00:32:03 +0800
|
||||
Subject: [PATCH] fix(stats_api): do not mark upstream queries without answers
|
||||
as blocked
|
||||
|
||||
Signed-off-by: sbwml <admin@cooluc.com>
|
||||
---
|
||||
plugin/executable/stats_api/stats_api.go | 8 +-
|
||||
plugin/executable/stats_api/stats_api_test.go | 122 ++++++++++++++++++
|
||||
2 files changed, 128 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/plugin/executable/stats_api/stats_api.go
|
||||
+++ b/plugin/executable/stats_api/stats_api.go
|
||||
@@ -975,6 +975,8 @@ func (s *StatsAPI) Exec(ctx context.Cont
|
||||
s.cachedQueries.Add(1)
|
||||
}
|
||||
|
||||
+ hasUpstream := isCached || qCtx.UpstreamSelected != nil
|
||||
+
|
||||
r := qCtx.R()
|
||||
var status string
|
||||
var answers []AnswerDTO
|
||||
@@ -982,7 +984,9 @@ func (s *StatsAPI) Exec(ctx context.Cont
|
||||
|
||||
if r == nil {
|
||||
status = "DROPPED"
|
||||
- isBlocked = true
|
||||
+ if !hasUpstream {
|
||||
+ isBlocked = true
|
||||
+ }
|
||||
} else {
|
||||
if rcodeStr, ok := dns.RcodeToString[r.Rcode]; ok {
|
||||
status = rcodeStr
|
||||
@@ -990,7 +994,7 @@ func (s *StatsAPI) Exec(ctx context.Cont
|
||||
status = fmt.Sprintf("RCODE%d", r.Rcode)
|
||||
}
|
||||
|
||||
- if (r.Rcode == dns.RcodeNameError || r.Rcode == dns.RcodeRefused) && qQuestion.Qtype != dns.TypeHTTPS {
|
||||
+ if !hasUpstream && (r.Rcode == dns.RcodeNameError || r.Rcode == dns.RcodeRefused) && qQuestion.Qtype != dns.TypeHTTPS {
|
||||
isBlocked = true
|
||||
}
|
||||
|
||||
--- a/plugin/executable/stats_api/stats_api_test.go
|
||||
+++ b/plugin/executable/stats_api/stats_api_test.go
|
||||
@@ -712,4 +712,126 @@ func TestStatsAPIExecWithHostsAndArbitra
|
||||
}
|
||||
}
|
||||
|
||||
+func TestStatsAPINoAnswerUpstreamAndBlocked(t *testing.T) {
|
||||
+ s := NewStatsAPI(&Args{Capacity: 100}, zap.NewNop())
|
||||
|
||||
+ // Case 1: Upstream returns NXDOMAIN (no answers) -> NOT blocked
|
||||
+ q1 := new(dns.Msg)
|
||||
+ q1.SetQuestion("apps.itunes-nocookie.com.", dns.TypeA)
|
||||
+ qCtx1 := query_context.NewContext(q1)
|
||||
+ qCtx1.SetUpstreamSelected("https://doh.pub/dns-query", "DoH", "remote", "forward_remote")
|
||||
+
|
||||
+ execUpstreamNX := sequence.ExecutableFunc(func(ctx context.Context, qCtx *query_context.Context) error {
|
||||
+ resp := new(dns.Msg)
|
||||
+ resp.SetReply(qCtx.Q())
|
||||
+ resp.Rcode = dns.RcodeNameError
|
||||
+ qCtx.SetResponse(resp)
|
||||
+ return nil
|
||||
+ })
|
||||
+
|
||||
+ walker1 := sequence.NewChainWalker([]*sequence.ChainNode{{E: execUpstreamNX}}, nil)
|
||||
+ if err := s.Exec(context.Background(), qCtx1, walker1); err != nil {
|
||||
+ t.Fatalf("Exec failed: %v", err)
|
||||
+ }
|
||||
+ if s.blockedQueries.Load() != 0 {
|
||||
+ t.Errorf("expected blockedQueries 0, got %d", s.blockedQueries.Load())
|
||||
+ }
|
||||
+ _, logs1 := s.ringBuffer.QueryLogs(1, 0, "", "all")
|
||||
+ if len(logs1) != 1 || logs1[0].IsBlocked || logs1[0].Status != "NXDOMAIN" || logs1[0].Upstream != "https://doh.pub/dns-query" {
|
||||
+ t.Errorf("expected unblocked NXDOMAIN upstream log, got %+v", logs1)
|
||||
+ }
|
||||
+
|
||||
+ // Case 2: Cache returns NXDOMAIN (no answers) -> NOT blocked
|
||||
+ q2 := new(dns.Msg)
|
||||
+ q2.SetQuestion("cached-nx.example.com.", dns.TypeA)
|
||||
+ qCtx2 := query_context.NewContext(q2)
|
||||
+ qCtx2.SetCacheState(true, false, 300, 300)
|
||||
+
|
||||
+ execCacheNX := sequence.ExecutableFunc(func(ctx context.Context, qCtx *query_context.Context) error {
|
||||
+ resp := new(dns.Msg)
|
||||
+ resp.SetReply(qCtx.Q())
|
||||
+ resp.Rcode = dns.RcodeNameError
|
||||
+ qCtx.SetResponse(resp)
|
||||
+ return nil
|
||||
+ })
|
||||
+
|
||||
+ walker2 := sequence.NewChainWalker([]*sequence.ChainNode{{E: execCacheNX}}, nil)
|
||||
+ if err := s.Exec(context.Background(), qCtx2, walker2); err != nil {
|
||||
+ t.Fatalf("Exec failed: %v", err)
|
||||
+ }
|
||||
+ if s.blockedQueries.Load() != 0 {
|
||||
+ t.Errorf("expected blockedQueries 0, got %d", s.blockedQueries.Load())
|
||||
+ }
|
||||
+ _, logs2 := s.ringBuffer.QueryLogs(1, 0, "", "all")
|
||||
+ if len(logs2) != 1 || logs2[0].IsBlocked || logs2[0].Status != "NXDOMAIN" || logs2[0].Upstream != "cache" {
|
||||
+ t.Errorf("expected unblocked NXDOMAIN cache log, got %+v", logs2)
|
||||
+ }
|
||||
+
|
||||
+ // Case 3: Local reject (no upstream, NXDOMAIN) -> IS blocked
|
||||
+ q3 := new(dns.Msg)
|
||||
+ q3.SetQuestion("ad.reject.com.", dns.TypeA)
|
||||
+ qCtx3 := query_context.NewContext(q3)
|
||||
+
|
||||
+ execLocalReject := sequence.ExecutableFunc(func(ctx context.Context, qCtx *query_context.Context) error {
|
||||
+ resp := new(dns.Msg)
|
||||
+ resp.SetReply(qCtx.Q())
|
||||
+ resp.Rcode = dns.RcodeNameError
|
||||
+ qCtx.SetResponse(resp)
|
||||
+ return nil
|
||||
+ })
|
||||
+
|
||||
+ walker3 := sequence.NewChainWalker([]*sequence.ChainNode{{E: execLocalReject}}, nil)
|
||||
+ if err := s.Exec(context.Background(), qCtx3, walker3); err != nil {
|
||||
+ t.Fatalf("Exec failed: %v", err)
|
||||
+ }
|
||||
+ if s.blockedQueries.Load() != 1 {
|
||||
+ t.Errorf("expected blockedQueries 1, got %d", s.blockedQueries.Load())
|
||||
+ }
|
||||
+ _, logs3 := s.ringBuffer.QueryLogs(1, 0, "", "all")
|
||||
+ if len(logs3) != 1 || !logs3[0].IsBlocked {
|
||||
+ t.Errorf("expected blocked log, got %+v", logs3)
|
||||
+ }
|
||||
+
|
||||
+ // Case 4: Upstream dropped (r == nil with upstream) -> NOT blocked
|
||||
+ q4 := new(dns.Msg)
|
||||
+ q4.SetQuestion("timeout.example.com.", dns.TypeA)
|
||||
+ qCtx4 := query_context.NewContext(q4)
|
||||
+ qCtx4.SetUpstreamSelected("8.8.8.8:53", "UDP", "remote", "forward_remote")
|
||||
+
|
||||
+ execUpstreamDrop := sequence.ExecutableFunc(func(ctx context.Context, qCtx *query_context.Context) error {
|
||||
+ return nil
|
||||
+ })
|
||||
+
|
||||
+ walker4 := sequence.NewChainWalker([]*sequence.ChainNode{{E: execUpstreamDrop}}, nil)
|
||||
+ if err := s.Exec(context.Background(), qCtx4, walker4); err != nil {
|
||||
+ t.Fatalf("Exec failed: %v", err)
|
||||
+ }
|
||||
+ if s.blockedQueries.Load() != 1 { // Still 1 from case 3
|
||||
+ t.Errorf("expected blockedQueries to remain 1, got %d", s.blockedQueries.Load())
|
||||
+ }
|
||||
+ _, logs4 := s.ringBuffer.QueryLogs(1, 0, "", "all")
|
||||
+ if len(logs4) != 1 || logs4[0].IsBlocked || logs4[0].Status != "DROPPED" {
|
||||
+ t.Errorf("expected unblocked DROPPED log, got %+v", logs4)
|
||||
+ }
|
||||
+
|
||||
+ // Case 5: Local drop (r == nil without upstream) -> IS blocked
|
||||
+ q5 := new(dns.Msg)
|
||||
+ q5.SetQuestion("local.drop.com.", dns.TypeA)
|
||||
+ qCtx5 := query_context.NewContext(q5)
|
||||
+
|
||||
+ execLocalDrop := sequence.ExecutableFunc(func(ctx context.Context, qCtx *query_context.Context) error {
|
||||
+ return nil
|
||||
+ })
|
||||
+
|
||||
+ walker5 := sequence.NewChainWalker([]*sequence.ChainNode{{E: execLocalDrop}}, nil)
|
||||
+ if err := s.Exec(context.Background(), qCtx5, walker5); err != nil {
|
||||
+ t.Fatalf("Exec failed: %v", err)
|
||||
+ }
|
||||
+ if s.blockedQueries.Load() != 2 {
|
||||
+ t.Errorf("expected blockedQueries 2, got %d", s.blockedQueries.Load())
|
||||
+ }
|
||||
+ _, logs5 := s.ringBuffer.QueryLogs(1, 0, "", "all")
|
||||
+ if len(logs5) != 1 || !logs5[0].IsBlocked || logs5[0].Status != "DROPPED" {
|
||||
+ t.Errorf("expected blocked DROPPED log, got %+v", logs5)
|
||||
+ }
|
||||
+}
|
||||
Reference in new issue
Block a user