{"record":{"id":"e330b32881a2ce88","repo":"shadow1ng/fscan","slug":"local-address-unavailable","errorCode":null,"errorMessage":"local_address_unavailable","messagePattern":"local_address_unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"plugins/local/socks5proxy.go","lineNumber":267,"sourceCode":"\t}\n\tif targetPort == 0 {\n\t\treturn nil, 0, fmt.Errorf(\"%s\", i18n.GetText(\"socks5_invalid_request\"))\n\t}\n\n\t// 连接目标服务器\n\ttargetAddr := net.JoinHostPort(targetHost, strconv.Itoa(int(targetPort)))\n\ttargetConn, err := net.DialTimeout(\"tcp\", targetAddr, 10*time.Second)\n\tif err != nil {\n\t\t// 发送连接失败响应\n\t\tresponse := []byte{0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}\n\t\t_, _ = clientConn.Write(response)\n\t\treturn nil, 0, fmt.Errorf(\"%s: %w\", i18n.GetText(\"socks5_target_connect_failed\"), err)\n\t}\n\n\t// 获取本地监听端口（从targetConn获取）\n\tlocalAddr, ok := targetConn.LocalAddr().(*net.TCPAddr)\n\tif !ok {\n\t\treturn nil, 0, fmt.Errorf(\"%s\", i18n.GetText(\"local_address_unavailable\"))\n\t}\n\tlocalPort := localAddr.Port\n\n\t// 发送成功响应\n\tresponse := make([]byte, 10)\n\tresponse[0] = 0x05 // SOCKS版本\n\tresponse[1] = 0x00 // 成功\n\tresponse[2] = 0x00 // 保留\n\tresponse[3] = 0x01 // IPv4地址类型\n\t// 绑定地址和端口（使用127.0.0.1:localPort）\n\tcopy(response[4:8], []byte{127, 0, 0, 1})\n\tresponse[8] = byte(localPort >> 8)\n\tresponse[9] = byte(localPort & 0xff)\n\n\t_, err = clientConn.Write(response)\n\tif err != nil {\n\t\t_ = targetConn.Close()\n\t\treturn nil, 0, fmt.Errorf(\"%s: %w\", i18n.GetText(\"socks5_success_response_failed\"), err)","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/local/socks5proxy.go#L249-L285","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom or test net.Dialer wrappers returning non-TCP addr types; hypothetical changes to dial transport.","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"],"exampleFix":"// before\nlocalAddr, ok := targetConn.LocalAddr().(*net.TCPAddr)\nif !ok {\n    return nil, 0, fmt.Errorf(\"%s\", i18n.GetText(\"local_address_unavailable\"))\n}\n// after\nlocalPort := 0\nif localAddr, ok := targetConn.LocalAddr().(*net.TCPAddr); ok {\n    localPort = localAddr.Port\n}","handlingStrategy":"fallback","validationCode":"// unreachable via public API; ensure standard \"tcp\" dial is used","typeGuard":"func tcpLocalPort(c net.Conn) (int, bool) {\n    a, ok := c.LocalAddr().(*net.TCPAddr)\n    if !ok { return 0, false }\n    return a.Port, true\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["socks5","tcp","type-assertion","edge-case"],"backgroundTag":"type-mismatch","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}