From c0a9cfd8f5762d3c873f7ab377bebc27f1f2474c Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Mon, 18 May 2026 17:13:19 +0800 Subject: [PATCH] use config proxy state for credential prechecks --- plugins/services/credential_tester.go | 18 +++++++------- plugins/services/credential_tester_test.go | 28 +++++++++++++++++++++- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/plugins/services/credential_tester.go b/plugins/services/credential_tester.go index 59e872f..8e4692f 100644 --- a/plugins/services/credential_tester.go +++ b/plugins/services/credential_tester.go @@ -107,11 +107,12 @@ func TestSingleCredential(ctx context.Context, cred Credential, authFn AuthFunc) // ConcurrentTestConfig 并发测试配置 type ConcurrentTestConfig struct { - Concurrency int // 并发数,默认 10 - MaxRetries int // 最大重试次数,默认 3 - RetryDelay time.Duration // 重试延迟,默认 1s - MaxConsecutiveNetErrors int // 连续网络错误阈值,超过则认为目标不可达,默认 5 - TargetAddr string // 目标地址 host:port,用于 TCP 预检(可选) + Concurrency int // 并发数,默认 10 + MaxRetries int // 最大重试次数,默认 3 + RetryDelay time.Duration // 重试延迟,默认 1s + MaxConsecutiveNetErrors int // 连续网络错误阈值,超过则认为目标不可达,默认 5 + TargetAddr string // 目标地址 host:port,用于 TCP 预检(可选) + UseProxy bool // 代理模式下跳过直连 TCP 预检 } // DefaultConcurrentTestConfig 默认配置 @@ -125,6 +126,7 @@ func DefaultConcurrentTestConfig(config *common.Config) ConcurrentTestConfig { MaxRetries: 3, RetryDelay: time.Second, MaxConsecutiveNetErrors: 5, + UseProxy: config.Network.Socks5Proxy != "" || config.Network.HTTPProxy != "", } } @@ -154,7 +156,7 @@ func TestCredentialsConcurrently( // TCP 预检:快速验证目标可达,避免对不可达目标浪费全部凭据尝试 // 代理模式下跳过:net.DialTimeout 直连无法到达代理后的内网目标 - if testConfig.TargetAddr != "" && !common.IsProxyEnabled() { + if testConfig.TargetAddr != "" && !testConfig.UseProxy { preConn, err := net.DialTimeout("tcp", testConfig.TargetAddr, 3*time.Second) if err != nil { return &ScanResult{ @@ -381,8 +383,8 @@ func ClassifyError(err error, authKeywords, networkKeywords []string) ErrorType func containsIgnoreCase(s, substr string) bool { return len(s) >= len(substr) && (s == substr || - len(substr) == 0 || - findIgnoreCase(s, substr) >= 0) + len(substr) == 0 || + findIgnoreCase(s, substr) >= 0) } // findIgnoreCase 忽略大小写查找子串 diff --git a/plugins/services/credential_tester_test.go b/plugins/services/credential_tester_test.go index 0d2ad1c..1955b11 100644 --- a/plugins/services/credential_tester_test.go +++ b/plugins/services/credential_tester_test.go @@ -268,6 +268,33 @@ func TestTestCredentialsConcurrently_EmptyCredentials(t *testing.T) { } } +func TestTestCredentialsConcurrently_ProxySkipsDirectPrecheck(t *testing.T) { + var calls atomic.Int32 + authFn := func(ctx context.Context, cred Credential) *AuthResult { + calls.Add(1) + return &AuthResult{ + Success: true, + Conn: &mockConn{}, + } + } + + config := ConcurrentTestConfig{ + Concurrency: 1, + MaxRetries: 1, + RetryDelay: time.Millisecond, + TargetAddr: "127.0.0.1:1", + UseProxy: true, + } + + result := TestCredentialsConcurrently(context.Background(), []Credential{{Username: "u", Password: "p"}}, authFn, "test", config) + if !result.Success { + t.Fatalf("proxy mode should skip direct precheck: %v", result.Error) + } + if calls.Load() == 0 { + t.Fatal("auth function was not called") + } +} + // TestTestCredentialsConcurrently_ContextCancel 测试context取消 func TestTestCredentialsConcurrently_ContextCancel(t *testing.T) { credentials := make([]Credential, 100) @@ -451,4 +478,3 @@ func TestRetryLogic_AuthErrorNoRetry(t *testing.T) { // 确保 mockConn 实现 io.Closer 接口 var _ io.Closer = (*mockConn)(nil) -