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
- Confirm the connection is dialed with the standard "tcp" network (it is), making this branch unreachable in practice
- If a custom dialer is injected, ensure it returns *net.TCPAddr for LocalAddr
- 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
- Dial with network "tcp" so LocalAddr is *net.TCPAddr
- If injecting custom dialers, keep the returned conn's LocalAddr a *net.TCPAddr
- Treat the local port as best-effort and degrade gracefully
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.