shadow1ng/fscan · error
service_target_unreachable: %w
Error message
service_target_unreachable: %w
What it means
Before spending the full credential list, TestCredentialsConcurrently performs a TCP pre-check by dialing testConfig.TargetAddr with a short-lived context. If that dial fails, the target is deemed unreachable and the whole test is aborted with this wrapped error (%w wraps the underlying net error). This saves all worker goroutines from timing out one by one against a dead host.
Source
Thrown at plugins/services/credential_tester.go:227
Service: serviceName,
Error: fmt.Errorf("%s", i18n.GetText("service_no_test_creds")),
}
}
testConfig = normalizeConcurrentTestConfig(testConfig)
// TCP 预检:快速验证目标可达,避免对不可达目标浪费全部凭据尝试
// 代理模式下跳过:net.DialTimeout 直连无法到达代理后的内网目标
if testConfig.TargetAddr != "" && !testConfig.UseProxy {
dialCtx, dialCancel := context.WithTimeout(ctx, 3*time.Second)
defer dialCancel()
var dialer net.Dialer
preConn, err := dialer.DialContext(dialCtx, "tcp", testConfig.TargetAddr)
if err != nil {
return &ScanResult{
Success: false,
Service: serviceName,
Error: fmt.Errorf(i18n.Tr("service_target_unreachable", "%w"), err),
}
}
_ = preConn.Close()
}
// 调整并发数
concurrency := testConfig.Concurrency
if concurrency > len(credentials) {
concurrency = len(credentials)
}
// 创建可取消的 context - 找到成功后取消其他 worker
cancelCtx, cancel := context.WithCancel(ctx)
defer cancel()
// 通道(buffer 设为 concurrency+1 避免 worker 阻塞在发送上)
credChan := make(chan Credential, len(credentials))
resultChan := make(chan *ScanResult, concurrency+1)View on GitHub (pinned to 95cc12e753)
Solutions
- Verify the target host and port with an independent probe (nc/telnet) and correct TargetAddr if wrong.
- If the target requires a proxy, configure the proxy in testConfig so the direct precheck is skipped rather than failing.
- Check the underlying wrapped error: 'connection refused' means port closed; 'i/o timeout' means filtered; 'no such host' means DNS.
- Increase the precheck deadline or ensure the parent context is not canceled before the precheck runs.
Example fix
// before testConfig.TargetAddr = "10.0.0.5:9200" // unreachable directly // after testConfig.Proxy = "socks5://proxy.internal:1080" // precheck skipped, dial via proxy
Defensive patterns
Strategy: retry
Validate before calling
conn, err := net.DialTimeout("tcp", testConfig.TargetAddr, 3*time.Second)
if err != nil {
return fmt.Errorf("precheck: target %s unreachable: %w", testConfig.TargetAddr, err)
}
conn.Close() Try / catch
res := TestCredentialsConcurrently(ctx, svc, creds, fn, cfg)
var nerr net.Error
if res.Error != nil && (errors.As(res.Error, &nerr) || errors.Is(res.Error, syscall.ECONNREFUSED)) {
// unreachable: back off and retry later or mark host dead
time.Sleep(backoff)
} Prevention
- Probe targets with a lightweight TCP ping before credential testing
- Configure proxy settings when targets are only reachable via proxy
- Check parent-context cancellation before launching prechecks
- Classify wrapped net errors (refused vs timeout vs DNS) to choose retry vs skip
When it happens
Trigger: TargetAddr host is down, the port is filtered/closed, DNS resolution fails, the precheck context (deadline/cancel) expires before the dial completes, or a proxy configuration makes the direct dialer unable to reach the target.
Common situations: Scanning an internal IP that is only reachable through a proxy; firewall dropping SYN packets; wrong port in the target config; host decommissioned between discovery and credential testing; canceled parent context.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- service_conn_port_failed: %w
- ms17010_connection_error: %w
- ms17010_set_timeout_error: %w
- failed to connect target: %s
- network_rate_limited
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/071b6c124d511881.
Report an issue: GitHub.