shadow1ng/fscan · error

Failed to listen on port: %w

Error message

Failed to listen on port: %w

What it means

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.

Source

Thrown at plugins/local/forwardshell.go:82

	}

	output.WriteString(i18n.GetText("forwardshell_done") + "\n")
	session.LogSuccess(i18n.Tr("forwardshell_complete", port))

	return &plugins.Result{
		Success: true,
		Type:    plugins.ResultTypeService,
		Output:  output.String(),
		Error:   nil,
	}
}

// startForwardShellServer 启动正向Shell服务器
func (p *ForwardShellPlugin) startForwardShellServer(ctx context.Context, port int, state *common.State, session *common.ScanSession) error {
	// 监听指定端口
	listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
	if err != nil {
		return fmt.Errorf("%s: %w", i18n.GetText("listen_port_failed"), err)
	}
	defer func() { _ = listener.Close() }()

	p.listener = listener
	session.LogSuccess(i18n.Tr("forwardshell_started", port))

	// 设置正向Shell为活跃状态
	state.SetForwardShellActive(true)
	defer func() {
		state.SetForwardShellActive(false)
	}()

	// 主循环处理连接
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Choose a different, free port (check with ss -ltnp / lsof -i :<port>) and rerun.
  2. Kill the stale process holding the port before restarting the agent.
  3. Use a port >= 1024 or run as root if a privileged port is required.
  4. Set SO_REUSEADDR in your own wrapper if TIME_WAIT is the cause (not configurable via this API).

Example fix

// before
cfg := plugins.Config{ForwardPort: 8080} // already in use
// after
cfg := plugins.Config{ForwardPort: 18443} // free high port
Defensive patterns

Strategy: retry

Validate before calling

ln, err := net.Listen("tcp", ":0") // probe
free := ln != nil; if ln != nil { ln.Close() }
if !isPortFree(cfg.ForwardPort) {
    cfg.ForwardPort = pickFreePort()
}

Try / catch

for attempt := 0; attempt < 3; attempt++ {
    err := startForward(ctx, port)
    if err != nil && strings.Contains(err.Error(), "listen") {
        port = pickFreePort(); continue
    }
    break
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/8f108548b9223c13. Report an issue: GitHub.