{"record":{"id":"9cc4cb38502cb5ab","repo":"shadowsocks/shadowsocks-rust","slug":"client-addr-must-be-ipv6","errorCode":null,"errorMessage":"client addr must be ipv6","messagePattern":"client addr must be ipv6","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks-service/src/local/redir/sys/unix/bsd_pf.rs","lineNumber":133,"sourceCode":"                    let sockaddr = SockAddr::from(*v4);\n                    let sockaddr = sockaddr.as_ptr() as *const sockaddr_in;\n\n                    let addr: *const in_addr = ptr::addr_of!((*sockaddr).sin_addr) as *const _;\n                    let port: libc::in_port_t = (*sockaddr).sin_port;\n\n                    ptr::write_unaligned::<in_addr>(ptr::addr_of_mut!(pnl.saddr.pfa) as *mut _, *addr);\n\n                    cfg_if! {\n                        if #[cfg(any(target_os = \"macos\", target_os = \"ios\"))] {\n                            pnl.sxport.port = port;\n                        } else {\n                            pnl.sport = port;\n                        }\n                    }\n                }\n                SocketAddr::V6(ref v6) => {\n                    if pnl.af != libc::AF_INET6 as libc::sa_family_t {\n                        return Err(Error::new(ErrorKind::InvalidInput, \"client addr must be ipv6\"));\n                    }\n\n                    let sockaddr = SockAddr::from(*v6);\n                    let sockaddr = sockaddr.as_ptr() as *const sockaddr_in6;\n\n                    let addr: *const in6_addr = ptr::addr_of!((*sockaddr).sin6_addr) as *const _;\n                    let port: libc::in_port_t = (*sockaddr).sin6_port;\n\n                    ptr::write_unaligned::<in6_addr>(ptr::addr_of_mut!(pnl.saddr.pfa) as *mut _, *addr);\n\n                    cfg_if! {\n                        if #[cfg(any(target_os = \"macos\", target_os = \"ios\"))] {\n                            pnl.sxport.port = port;\n                        } else {\n                            pnl.sport = port;\n                        }\n                    }\n                }","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks-service/src/local/redir/sys/unix/bsd_pf.rs#L115-L151","documentation":"Mirror of the IPv4 case: tcp_natlook checks that when the client peer address is an IPv6 SocketAddr, the pf natlook state's address family is AF_INET6. A mismatch means the pf state doesn't correspond to an IPv6 flow and the original destination cannot be recovered, so InvalidInput is thrown.","triggerScenarios":"natlook called with an IPv6 peer address while the pf state table entry carries a non-AF_INET6 family — stale/replaced states, or IPv6 traffic actually being NATed through an IPv4 state.","commonSituations":"Dual-stack redirect setups where ip6 rules are missing, NAT64/DNS64 translation changing the family, or pf rules only created for the IPv4 family.","solutions":["Add matching pf redirect rules for the IPv6 family (pass in ... rdr-to with AF_INET6).","Bind the redir listener to an explicit IPv6 address so states are AF_INET6.","Verify no NAT64 translation is rewriting the flow family mid-path.","Check `pfctl -ss` for the actual state family of the connection."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if !peer_addr.is_ipv6() { /* route to the v4 natlook path instead */ }","typeGuard":"fn as_v6(addr: &SocketAddr) -> Option<std::net::SocketAddrV6> {\n    match addr { SocketAddr::V6(v6) => Some(*v6), _ => None }\n}","tryCatchPattern":"match natlook(fd, peer_addr, local_addr).await {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {\n        tracing::warn!(\"pf state family mismatch for {peer_addr}; rejecting connection\");\n        // drop or redirect to an IPv6-capable redir path\n    }\n    r => r?,\n}","preventionTips":["Create pf rdr rules for both inet and inet6 families","Avoid NAT64/DNS64 in front of transparent redirect hosts","Verify with `pfctl -ss` that v6 flows carry AF_INET6 states"],"tags":["network","freebsd","macos","pf","ipv6"],"backgroundTag":"invalid-argument-value","analyzedSha":"8eb0f0a65b1d976ab6bed5787327ef86529b0435","analyzedAt":"2026-09-09T12:20:43.168Z","contentChangedAt":"2026-09-09T12:20:43.168Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}