{"record":{"id":"1d8fec2642642e15","repo":"shadow1ng/fscan","slug":"network-rate-limited-1d8fec","errorCode":null,"errorMessage":"network_rate_limited","messagePattern":"network_rate_limited","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"common/session.go","lineNumber":97,"sourceCode":"func (s *ScanSession) LogVuln(result string) {\n\tif s.loggingEnabled() {\n\t\tLogVuln(result)\n\t}\n}\n\n// LogError writes through the session's logging policy.\nfunc (s *ScanSession) LogError(errMsg string) {\n\tif s.loggingEnabled() {\n\t\tLogError(errMsg)\n\t}\n}\n\n// DialTCP 创建 TCP 连接，内含限速检查、代理、计数\nfunc (s *ScanSession) DialTCP(ctx context.Context, network, address string, timeout time.Duration) (net.Conn, error) {\n\t// 检查发包限制\n\tif ok, err := CanSendPacketWith(s.Config, s.State); !ok {\n\t\ts.LogError(i18n.Tr(\"tcp_connection_restricted\", address, err.Error()))\n\t\treturn nil, fmt.Errorf(\"%s\", i18n.Tr(\"network_rate_limited\", err.Error()))\n\t}\n\n\t// 获取 dialer\n\tdialer, err := s.getDialer(timeout)\n\tif err != nil {\n\t\ts.LogError(i18n.Tr(\"proxy_dialer_failed\", err))\n\t\ts.State.IncrementTCPFailedPacketCount()\n\t\treturn nil, err\n\t}\n\n\tconn, err := dialer.DialContext(ctx, network, address)\n\tif err != nil {\n\t\ts.State.IncrementTCPFailedPacketCount()\n\t\ts.LogDebug(i18n.Tr(\"connection_failed\", address, err))\n\t\treturn nil, err\n\t}\n\n\t// SO_LINGER=0: 连接关闭时立即发送 RST，避免 TIME_WAIT 堆积","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/common/session.go#L79-L115","documentation":"ScanSession.DialTCP checks CanSendPacketWith before every outbound TCP dial. If the session's rate/packet limits are exhausted, the dial is refused and this error wraps the limit reason. It prevents the scan from exceeding configured network budgets.","triggerScenarios":"Any code path that dials TCP through the session (connectWithRetry, reconnectIfNeeded, service identification, port reachability checks) after the configured send-rate or packet count limit has been hit.","commonSituations":"Long-running scans hitting the configured packets-per-second/total caps; misconfigured ScanSession.Config limits set too low for the target scope; concurrent goroutines consuming the budget faster than expected.","solutions":["Wait/back off until the rate window resets, or reduce scan concurrency so sends stay under the limit.","Raise the packet/rate limits in the ScanSession Config if the budget is genuinely too small.","Check the wrapped reason in err.Error() to distinguish a temporary rate window from a hard cap, and handle accordingly."],"exampleFix":"// before\nconn, err := session.DialTCP(ctx, \"tcp\", addr, timeout) // fails with network_rate_limited\n// after\nif ok, err := common.CanSendPacketWith(session.Config, session.State); ok {\n    conn, err = session.DialTCP(ctx, \"tcp\", addr, timeout)\n} else {\n    time.Sleep(backoff) // wait for rate window to reset, then retry\n}","handlingStrategy":"retry","validationCode":"ok, limitErr := common.CanSendPacketWith(session.Config, session.State)\nif !ok { /* defer or back off before dialing */ }","typeGuard":null,"tryCatchPattern":"conn, err := session.DialTCP(ctx, \"tcp\", addr, timeout)\nif err != nil {\n    var backoff = initialBackoff\n    for retries := 0; retries < maxRetries && err != nil; retries++ {\n        select {\n        case <-time.After(backoff):\n        case <-ctx.Done():\n            return ctx.Err()\n        }\n        conn, err = session.DialTCP(ctx, \"tcp\", addr, timeout)\n        backoff *= 2\n    }\n}","preventionTips":["Check CanSendPacketWith before burst dialing","Tune Config packet/rate limits to target scope and bandwidth","Cap scan concurrency so the shared session budget is respected"],"tags":["rate-limit","network","tcp"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}