shadow1ng/fscan · error
%s: %w
Error message
%s: %w
What it means
performNetworkDiscovery wraps a failed conn.Write of the first RPC request buffer (rpcBuffer1) used for RPC network discovery over a raw TCP connection. The i18n message ('RPC request 1 failed'-style) is prefixed to the underlying net error with %w so callers can errors.Is/As the wrapped cause. This is a low-level I/O failure, not an authentication result.
Source
Thrown at plugins/services/findnet.go:142
if len(parts) == 0 {
return i18n.GetText("findnet_complete")
}
return strings.Join(parts, ", ")
}
// RPC数据包定义
var (
rpcBuffer1, _ = hex.DecodeString("05000b03100000004800000001000000b810b810000000000100000000000100c4fefc9960521b10bbcb00aa0021347a00000000045d888aeb1cc9119fe808002b10486002000000")
rpcBuffer2, _ = hex.DecodeString("050000031000000018000000010000000000000000000500")
rpcBuffer3, _ = hex.DecodeString("0900ffff0000")
)
// performNetworkDiscovery 执行RPC网络发现
func (p *FindNetPlugin) performNetworkDiscovery(conn net.Conn) (*NetworkInfo, error) {
// 发送第一个RPC请求
if _, err := conn.Write(rpcBuffer1); err != nil {
return nil, fmt.Errorf("%s: %w", i18n.GetText("findnet_rpc_request1_failed"), err)
}
// 读取响应
reply := make([]byte, 4096)
if _, err := conn.Read(reply); err != nil {
return nil, fmt.Errorf("%s: %w", i18n.GetText("findnet_rpc_response1_failed"), err)
}
// 发送第二个RPC请求
if _, err := conn.Write(rpcBuffer2); err != nil {
return nil, fmt.Errorf("%s: %w", i18n.GetText("findnet_rpc_request2_failed"), err)
}
// 读取网络信息响应
n, err := conn.Read(reply)
if err != nil || n < 42 {
return nil, fmt.Errorf("%s: %w", i18n.GetText("findnet_rpc_response2_failed"), err)
}View on GitHub (pinned to 95cc12e753)
Solutions
- Check that the target port actually hosts the service (nmap/service probe) before scanning
- Retry the scan; transient resets are common on lossy networks
- Inspect the wrapped error with errors.Is(err, syscall.ECONNRESET)/net.Error to classify host vs network issues
- Verify firewall rules don't drop/reset connections to the discovery port
Example fix
// before
if _, err := conn.Write(rpcBuffer1); err != nil {
return nil, fmt.Errorf("%s: %w", i18n.GetText("findnet_rpc_request1_failed"), err)
}
// after
if _, err := conn.Write(rpcBuffer1); err != nil {
if errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) {
return nil, fmt.Errorf("%s: %w", i18n.GetText("findnet_rpc_request1_failed"), err) // host not RPC; skip
}
return nil, fmt.Errorf("%s: %w", i18n.GetText("findnet_rpc_request1_failed"), err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: pre-check connectivity before Scan
conn, err := net.DialTimeout("tcp", target, 3*time.Second)
if err != nil { return fmt.Errorf("target unreachable: %w", err) }
conn.Close() Type guard
func isTransientNetErr(err error) bool {
var ne net.Error
return errors.As(err, &ne) && ne.Timeout() || errors.Is(err, syscall.ECONNRESET) || errors.Is(err, syscall.EPIPE)
} Try / catch
info, err := plugin.performNetworkDiscovery(conn)
if err != nil {
if isTransientNetErr(err) { /* retry or skip host */ }
log.Printf("discovery failed for %s: %v", target, err)
return
} Prevention
- Probe the port with a service check before RPC discovery
- Set explicit read/write deadlines on the connection
- Classify wrapped errors with errors.Is/As instead of string matching
- Retry transient network errors with backoff
When it happens
Trigger: Scan -> performNetworkDiscovery: the first conn.Write(rpcBuffer1) on the target host's RPC port returns an error — connection reset, broken pipe, or write on an already-closed/failed connection.
Common situations: Target host closes the TCP connection immediately upon connect (RPC service not actually listening on that port); firewall or IDS resets the connection after inspecting the payload; scanning a non-RPC port that got bound by another service; network unreachable mid-scan.
Related errors
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/db8f70dbf5dbf958.
Report an issue: GitHub.