shadow1ng/fscan · info

local_address_unavailable

Error message

local_address_unavailable

What it means

After a successful dial, the code type-asserts targetConn.LocalAddr() to *net.TCPAddr to learn the local outbound port; the assertion failed, so the local port cannot be reported in the SOCKS5 success reply and the request aborts.

Source

Thrown at plugins/local/socks5proxy.go:267

	}
	if targetPort == 0 {
		return nil, 0, fmt.Errorf("%s", i18n.GetText("socks5_invalid_request"))
	}

	// 连接目标服务器
	targetAddr := net.JoinHostPort(targetHost, strconv.Itoa(int(targetPort)))
	targetConn, err := net.DialTimeout("tcp", targetAddr, 10*time.Second)
	if err != nil {
		// 发送连接失败响应
		response := []byte{0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
		_, _ = clientConn.Write(response)
		return nil, 0, fmt.Errorf("%s: %w", i18n.GetText("socks5_target_connect_failed"), err)
	}

	// 获取本地监听端口(从targetConn获取)
	localAddr, ok := targetConn.LocalAddr().(*net.TCPAddr)
	if !ok {
		return nil, 0, fmt.Errorf("%s", i18n.GetText("local_address_unavailable"))
	}
	localPort := localAddr.Port

	// 发送成功响应
	response := make([]byte, 10)
	response[0] = 0x05 // SOCKS版本
	response[1] = 0x00 // 成功
	response[2] = 0x00 // 保留
	response[3] = 0x01 // IPv4地址类型
	// 绑定地址和端口(使用127.0.0.1:localPort)
	copy(response[4:8], []byte{127, 0, 0, 1})
	response[8] = byte(localPort >> 8)
	response[9] = byte(localPort & 0xff)

	_, err = clientConn.Write(response)
	if err != nil {
		_ = targetConn.Close()
		return nil, 0, fmt.Errorf("%s: %w", i18n.GetText("socks5_success_response_failed"), err)

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Confirm the connection is dialed with the standard "tcp" network (it is), making this branch unreachable in practice
  2. If a custom dialer is injected, ensure it returns *net.TCPAddr for LocalAddr
  3. Handle gracefully by falling back to port 0 or skipping the assertion instead of failing the request

Example fix

// before
localAddr, ok := targetConn.LocalAddr().(*net.TCPAddr)
if !ok {
    return nil, 0, fmt.Errorf("%s", i18n.GetText("local_address_unavailable"))
}
// after
localPort := 0
if localAddr, ok := targetConn.LocalAddr().(*net.TCPAddr); ok {
    localPort = localAddr.Port
}
Defensive patterns

Strategy: fallback

Validate before calling

// unreachable via public API; ensure standard "tcp" dial is used

Type guard

func tcpLocalPort(c net.Conn) (int, bool) {
    a, ok := c.LocalAddr().(*net.TCPAddr)
    if !ok { return 0, false }
    return a.Port, true
}

Prevention

When it happens

Trigger: LocalAddr() returns a non-*net.TCPAddr value. Practically almost impossible for a net.DialTimeout("tcp") connection; would require a nonstandard net implementation or mocked conn.

Common situations: Custom or test net.Dialer wrappers returning non-TCP addr types; hypothetical changes to dial transport.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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