{"record":{"id":"8f108548b9223c13","repo":"shadow1ng/fscan","slug":"failed-to-listen-on-port-w","errorCode":null,"errorMessage":"Failed to listen on port: %w","messagePattern":"Failed to listen on port: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/local/forwardshell.go","lineNumber":82,"sourceCode":"\t}\n\n\toutput.WriteString(i18n.GetText(\"forwardshell_done\") + \"\\n\")\n\tsession.LogSuccess(i18n.Tr(\"forwardshell_complete\", port))\n\n\treturn &plugins.Result{\n\t\tSuccess: true,\n\t\tType:    plugins.ResultTypeService,\n\t\tOutput:  output.String(),\n\t\tError:   nil,\n\t}\n}\n\n// startForwardShellServer 启动正向Shell服务器\nfunc (p *ForwardShellPlugin) startForwardShellServer(ctx context.Context, port int, state *common.State, session *common.ScanSession) error {\n\t// 监听指定端口\n\tlistener, err := net.Listen(\"tcp\", fmt.Sprintf(\"0.0.0.0:%d\", port))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%s: %w\", i18n.GetText(\"listen_port_failed\"), err)\n\t}\n\tdefer func() { _ = listener.Close() }()\n\n\tp.listener = listener\n\tsession.LogSuccess(i18n.Tr(\"forwardshell_started\", port))\n\n\t// 设置正向Shell为活跃状态\n\tstate.SetForwardShellActive(true)\n\tdefer func() {\n\t\tstate.SetForwardShellActive(false)\n\t}()\n\n\t// 主循环处理连接\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tdefault:","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/local/forwardshell.go#L64-L100","documentation":"startForwardShellServer calls net.Listen(\"tcp\", \"0.0.0.0:<port>\") to accept incoming reverse connections. When Listen fails, the error is wrapped as listen_port_failed plus the underlying cause. The most common cause is the port already being bound by another process.","triggerScenarios":"Scan starts the forward-shell listener on a port already occupied by another instance of the agent or an unrelated service; binding a privileged port (<1024) without root; IPv6/dual-stack conflicts on the address.","commonSituations":"Two agent instances launched concurrently with the same forward-shell port; a leftover process from a previous run still holding the socket (TIME_WAIT/lingering listener); trying port 443/80 as an unprivileged user.","solutions":["Choose a different, free port (check with ss -ltnp / lsof -i :<port>) and rerun.","Kill the stale process holding the port before restarting the agent.","Use a port >= 1024 or run as root if a privileged port is required.","Set SO_REUSEADDR in your own wrapper if TIME_WAIT is the cause (not configurable via this API)."],"exampleFix":"// before\ncfg := plugins.Config{ForwardPort: 8080} // already in use\n// after\ncfg := plugins.Config{ForwardPort: 18443} // free high port","handlingStrategy":"retry","validationCode":"ln, err := net.Listen(\"tcp\", \":0\") // probe\nfree := ln != nil; if ln != nil { ln.Close() }\nif !isPortFree(cfg.ForwardPort) {\n    cfg.ForwardPort = pickFreePort()\n}","typeGuard":null,"tryCatchPattern":"for attempt := 0; attempt < 3; attempt++ {\n    err := startForward(ctx, port)\n    if err != nil && strings.Contains(err.Error(), \"listen\") {\n        port = pickFreePort(); continue\n    }\n    break\n}","preventionTips":["Allocate forward-shell ports from an ephemeral high range.","Ensure only one agent instance runs per host (pidfile/lock).","Clean up listeners on shutdown so stale sockets do not linger.","Use ports >= 1024 unless the process runs as root."],"tags":["network","listen","port"],"backgroundTag":"address-already-in-use","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"}