{"record":{"id":"5185bcf78b95f2ec","repo":"shadowsocks/shadowsocks-rust","slug":"redir-destination-must-not-be-an-domain-name-addre","errorCode":null,"errorMessage":"redir destination must not be an domain name address","messagePattern":"redir destination must not be an domain name address","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks-service/src/local/redir/udprelay/mod.rs","lineNumber":125,"sourceCode":"                        } else {\n                            sa\n                        }\n                    }\n                    SocketAddr::V6(ref v6) => {\n                        // If IPv6 is not supported. Try to map it back to IPv4.\n                        if !ip_stack_caps.support_ipv6 || !ip_stack_caps.support_ipv4_mapped_ipv6 {\n                            match v6.ip().to_ipv4_mapped() {\n                                Some(v4) => SocketAddr::new(v4.into(), v6.port()),\n                                None => sa,\n                            }\n                        } else {\n                            sa\n                        }\n                    }\n                }\n            }\n            Address::DomainNameAddress(..) => {\n                let err = io::Error::new(\n                    ErrorKind::InvalidInput,\n                    \"redir destination must not be an domain name address\",\n                );\n                return Err(err);\n            }\n        };\n\n        let inbound = {\n            let mut cache = self.inbound_cache.cache.lock().await;\n            match cache.get(&addr) {\n                Some(socket) => socket.clone(),\n                _ => {\n                    // Create a socket binds to destination addr\n                    // This only works for systems that supports binding to non-local addresses\n                    //\n                    // This socket has to set SO_REUSEADDR and SO_REUSEPORT.\n                    // Outbound addresses could be connected from different source addresses.\n                    let inbound = UdpRedirSocket::bind_nonlocal(self.redir_ty, addr, &self.socket_opts)?;","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks-service/src/local/redir/udprelay/mod.rs#L107-L143","documentation":"The UDP relay for redir (transparent proxy) must send the datagram to the packet's real destination, which pf/nftables/iptables rewriting can only express as an IP address. When the resolved destination is Address::DomainNameAddress, there is no IP to send to in a redir socket, so send_to returns InvalidInput.","triggerScenarios":"Calling UdpRedirSocket::send_to whose target Address is a domain name — e.g. original-destination lookup returned a hostname, or application code passed a domain-based Address into the redir UDP relay instead of an IP SocketAddr.","commonSituations":"Custom integrations feeding domain Addresses into the redir path, DNS configurations where the pf lookup yields non-IP forms, or mixing the ordinary (non-redir) UDP relay API with redir sockets.","solutions":["Resolve the domain to a SocketAddr (via a resolver/lookup) before calling send_to.","Use the non-redir UDP relay/UdpSocket path when targets may be domain names.","Check that the transparent-proxy rules preserve IP-form original destinations (no NAT64/DNS64 rewriting).","Reject or log domain destinations early in your caller instead of reaching send_to."],"exampleFix":"// before\nlet target = Address::DomainNameAddress(\"example.com\".to_owned(), 53);\nsocket.send_to(payload, &target).await?;\n// after\nlet ip = lookup_host((\"example.com\", 53)).await?;\nsocket.send_to(payload, &Address::from(ip)).await?;","handlingStrategy":"validation","validationCode":"// resolve before send_to; reject domain targets early\nif matches!(addr, Address::DomainNameAddress(..)) {\n    return Err(io::Error::new(io::ErrorKind::InvalidInput, \"resolve domain before redir send_to\"));\n}","typeGuard":"fn as_ip(addr: &Address) -> Option<SocketAddr> {\n    match addr {\n        Address::SocketAddress(sa) => Some(*sa),\n        _ => None,\n    }\n}","tryCatchPattern":"match socket.send_to(payload, &addr).await {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {\n        // resolve domain destination then retry once\n        let ip = resolve(&addr).await?;\n        socket.send_to(payload, &Address::from(ip)).await?;\n    }\n    r => r?,\n}","preventionTips":["Always pass IP-form destinations to redir UDP sockets","Resolve domains with the same resolver the proxy would use to avoid asymmetric routing","Disable NAT64/DNS64 on transparent-proxy hosts so lookups stay IP-form"],"tags":["network","udp","transparent-proxy","dns"],"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"}