From 19446c2c8e62e6e6a06b0fa4f595623c9fe4b6ea Mon Sep 17 00:00:00 2001 From: Night Owl Nerd <256460992+nightowlnerd@users.noreply.github.com> Date: Mon, 2 Feb 2026 18:25:35 +0100 Subject: [PATCH] feat: add --threshold flag for configurable benchmark pass rate --- README.fa.md | 3 ++- README.md | 3 ++- benchmark.go | 18 ++++++++++++++---- config.go | 2 ++ e2e_test.go | 10 +++++----- main.go | 2 +- 6 files changed, 26 insertions(+), 12 deletions(-) diff --git a/README.fa.md b/README.fa.md index 1020889..85c599e 100644 --- a/README.fa.md +++ b/README.fa.md @@ -13,7 +13,7 @@ - 🧪 **تست Burst** - سرورهایی که فقط به یک کوئری جواب می‌دهند اما زیر بار واقعی fail می‌شوند را فیلتر می‌کند (مثل 1.1.1.1 که 0% موفقیت دارد) - 🛡️ **تشخیص DNS Hijacking** - سرورهایی که IP خصوصی برمی‌گردانند را شناسایی و هشدار می‌دهد - ⚡ **مرتب‌سازی بر اساس QPS** - نتایج بر اساس سرعت (queries per second) مرتب می‌شوند -- 🎨 **رنگ‌بندی** - سبز برای ≥85% موفقیت، زرد برای 70-84% +- 🎨 **رنگ‌بندی** - سبز برای ≥threshold+15%، زرد برای threshold تا threshold+15% ## کاربرد @@ -62,6 +62,7 @@ go build -o dnscan . | `--progress` | true | نمایش نوار پیشرفت | | `--verify` | - | مسیر باینری slipstream-client | | `--json` | false | خروجی به فرمت JSON | +| `--threshold` | 70 | حداقل نرخ موفقیت برای بنچمارک (0-100) | ## حالت‌های اسکن diff --git a/README.md b/README.md index d2525d3..5b08f39 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Find working DNS servers for DNS tunnels during internet blackouts. Scans countr - 🧪 **Burst Testing** - Filters servers that respond to single queries but fail under real load (e.g., 1.1.1.1 shows 0% success) - 🛡️ **DNS Hijacking Detection** - Detects and warns when servers return private IPs - ⚡ **QPS Sorting** - Results sorted by throughput (queries per second) -- 🎨 **Color Coding** - Green for ≥85% success, yellow for 70-84% +- 🎨 **Color Coding** - Green for ≥threshold+15%, yellow for threshold to threshold+15% ## Use Case @@ -63,6 +63,7 @@ go build -o dnscan . | `--progress` | true | Show progress bar | | `--verify` | - | Path to slipstream-client binary | | `--json` | false | Output results as JSON | +| `--threshold` | 70 | Minimum success rate for benchmark (0-100) | ## Scan Modes diff --git a/benchmark.go b/benchmark.go index 04e7811..f44b683 100644 --- a/benchmark.go +++ b/benchmark.go @@ -70,23 +70,32 @@ type Benchmarker struct { domain string port int timeout time.Duration + threshold int output io.Writer showProgress bool } -func NewBenchmarker(domain string, port int, timeout time.Duration, output io.Writer, showProgress bool) *Benchmarker { +func NewBenchmarker(domain string, port int, timeout time.Duration, threshold int, output io.Writer, showProgress bool) *Benchmarker { if port == 0 { port = 53 } + if threshold <= 0 || threshold > 100 { + threshold = BenchmarkThreshold + } return &Benchmarker{ domain: domain, port: port, timeout: timeout, + threshold: threshold, output: output, showProgress: showProgress, } } +func (b *Benchmarker) passed(r *BenchmarkResult) bool { + return r.SuccessRate() >= float64(b.threshold) +} + func (b *Benchmarker) Benchmark(ctx context.Context, ips []string) []*BenchmarkResult { if len(ips) == 0 { return nil @@ -137,9 +146,10 @@ func (b *Benchmarker) summary(results []*BenchmarkResult, total int) { } fmt.Fprintf(b.output, "\r\033[1;32mBenchmark: %d/%d | Passed: %d | sorted by QPS\033[0m \n", total, total, len(results)) fmt.Fprintln(b.output, "---") + greenThreshold := float64(b.threshold + 15) for _, r := range results { color := "\033[33m" - if r.SuccessRate() >= 85 { + if r.SuccessRate() >= greenThreshold { color = "\033[32m" } fmt.Fprintf(b.output, "%s%-15s %.0f%% (%.1f qps, p50=%v)\033[0m\n", @@ -157,7 +167,7 @@ func (b *Benchmarker) sequential(ctx context.Context, ips []string, prog *Progre } result := b.benchmark(ctx, ip) prog.Increment() - if result.Passed() { + if b.passed(result) { prog.Success() results = append(results, result) } @@ -214,7 +224,7 @@ func (b *Benchmarker) parallel(ctx context.Context, ips []string, prog *Progress var results []*BenchmarkResult for result := range resultChan { prog.Increment() - if result.Passed() { + if b.passed(result) { prog.Success() results = append(results, result) } diff --git a/config.go b/config.go index 3fb3249..4f5c75d 100644 --- a/config.go +++ b/config.go @@ -20,6 +20,7 @@ type Config struct { JSONOutput bool Progress bool ShowVersion bool + Threshold int } func ParseFlags() *Config { @@ -37,6 +38,7 @@ func ParseFlags() *Config { flag.StringVar(&c.VerifyBinary, "verify", "", "Path to slipstream-client binary") flag.BoolVar(&c.ShowVersion, "version", false, "Show version") flag.BoolVar(&c.JSONOutput, "json", false, "Output results as JSON") + flag.IntVar(&c.Threshold, "threshold", 70, "Minimum success rate for benchmark (0-100)") flag.Parse() diff --git a/e2e_test.go b/e2e_test.go index 8ccd18c..2e6f35a 100644 --- a/e2e_test.go +++ b/e2e_test.go @@ -130,7 +130,7 @@ func TestE2EBenchmark(t *testing.T) { } defer mock.Close() - benchmarker := NewBenchmarker("test.example.com", mock.port, 2*time.Second, nil, false) + benchmarker := NewBenchmarker("test.example.com", mock.port, 2*time.Second, 70, nil, false) results := benchmarker.Benchmark(context.Background(), []string{mock.ip}) if len(results) != 1 { @@ -217,7 +217,7 @@ func TestE2EBenchmarkQPS(t *testing.T) { } defer mock.Close() - benchmarker := NewBenchmarker("test.example.com", mock.port, 2*time.Second, nil, false) + benchmarker := NewBenchmarker("test.example.com", mock.port, 2*time.Second, 70, nil, false) results := benchmarker.Benchmark(context.Background(), []string{mock.ip}) if len(results) != 1 { @@ -253,7 +253,7 @@ func TestE2EBenchmarkMultiple(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - benchmarker := NewBenchmarker("test.example.com", mocks[0].port, 2*time.Second, nil, false) + benchmarker := NewBenchmarker("test.example.com", mocks[0].port, 2*time.Second, 70, nil, false) results := benchmarker.Benchmark(ctx, ips) if len(results) != 3 { @@ -271,7 +271,7 @@ func TestE2EBenchmarkContextCancellation(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() - benchmarker := NewBenchmarker("test.example.com", mock.port, 2*time.Second, nil, false) + benchmarker := NewBenchmarker("test.example.com", mock.port, 2*time.Second, 70, nil, false) results := benchmarker.Benchmark(ctx, []string{mock.ip}) if len(results) > 0 && results[0].Successful == BenchmarkQueries { @@ -305,7 +305,7 @@ func TestE2EBenchmarkResultMetrics(t *testing.T) { } defer mock.Close() - benchmarker := NewBenchmarker("test.example.com", mock.port, 2*time.Second, nil, false) + benchmarker := NewBenchmarker("test.example.com", mock.port, 2*time.Second, 70, nil, false) results := benchmarker.Benchmark(context.Background(), []string{mock.ip}) if len(results) != 1 { diff --git a/main.go b/main.go index b9ed6bd..7f317fb 100644 --- a/main.go +++ b/main.go @@ -68,7 +68,7 @@ func main() { var benchResults []*BenchmarkResult if cfg.Domain != "" && len(workingDNS) > 0 { - benchmarker := NewBenchmarker(cfg.Domain, 53, cfg.Timeout, os.Stderr, cfg.Progress) + benchmarker := NewBenchmarker(cfg.Domain, 53, cfg.Timeout, cfg.Threshold, os.Stderr, cfg.Progress) benchResults = benchmarker.Benchmark(ctx, workingDNS) workingDNS = nil