{"record":{"id":"78c9112fc904296d","repo":"shadowsocks/shadowsocks-rust","slug":"missing-destination-address-in-msghdr","errorCode":null,"errorMessage":"missing destination address in msghdr","messagePattern":"missing destination address in msghdr","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/freebsd.rs","lineNumber":300,"sourceCode":"\n                        return Ok(());\n                    }\n                    (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {\n                        ptr::copy_nonoverlapping(\n                            libc::CMSG_DATA(cmsg),\n                            dst_addr as *mut _,\n                            mem::size_of::<libc::sockaddr_in6>(),\n                        );\n                        *dst_addr_len = mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t;\n\n                        return Ok(());\n                    }\n                    _ => {}\n                }\n                cmsg = libc::CMSG_NXTHDR(msg, cmsg);\n            }\n\n            let err = Error::new(ErrorKind::InvalidData, \"missing destination address in msghdr\");\n            Err(err)\n        })?;\n\n        Ok(addr.as_socket().expect(\"SocketAddr\"))\n    }\n}\n\nfn recv_dest_from(socket: &UdpSocket, buf: &mut [u8]) -> io::Result<(usize, SocketAddr, SocketAddr)> {\n    unsafe {\n        let mut control_buf = [0u8; 64];\n        let mut src_addr: libc::sockaddr_storage = mem::zeroed();\n\n        let mut msg: libc::msghdr = mem::zeroed();\n        msg.msg_name = &mut src_addr as *mut _ as *mut _;\n        msg.msg_namelen = mem::size_of_val(&src_addr) as libc::socklen_t;\n\n        let mut iov = libc::iovec {\n            iov_base: buf.as_mut_ptr() as *mut _,","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/shadowsocks/shadowsocks-rust/blob/8eb0f0a65b1d976ab6bed5787327ef86529b0435/crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/freebsd.rs#L282-L318","documentation":"This error is thrown when a UDP transparent-proxy socket on FreeBSD receives a packet whose IP_RECVORIGDSTADDR/recvmsg control messages did not carry the original destination address. The relay needs that address to forward the packet, so without it the packet is dropped with InvalidData.","triggerScenarios":"Calling recv_dest_from on a FreeBSD redir socket when the packet's cmsg data lacks the IP_ORIGDSTADDR/IPV6_ORIGDSTADDR control message — e.g. the socket was created as a plain UDP socket instead of a tproxy socket, or the IP_RECVDSTADDR/IP_RECVORIGDSTADDR socket option was not set.","commonSituations":"Running shadowsocks redirect/tproxy on FreeBSD with the firewall (pf/ipfw) not redirecting with the option that preserves the original destination, or a kernel/platform where the needed cmsg is stripped.","solutions":["Ensure the firewall rule (e.g. pf 'rdr-to' with divert or ipfw fwd) actually preserves the original destination address for UDP packets","Verify the socket enabled the recv-orig-dest-address socket option (IP_RECVDSTADDR / IPV6_RECVDSTADDR) before reading","Confirm the selected RedirType is supported for UDP on FreeBSD; unsupported types create sockets without the needed options","Check that the received control buffer (cmsg space) is large enough for the address cmsg; enlarge if truncated","Log the raw cmsg when this occurs to see whether the kernel delivered any destination cmsg at all"],"exampleFix":"// before: socket created without orig-dst option\nlet socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;\n// after: enable receiving original destination\nsocket.setsockopt(IPPROTO_IP, IP_RECVDSTADDR, 1)?; // + firewall divert-to rule","handlingStrategy":"validation","validationCode":"// before binding, ensure options & firewall are set\nassert!(socket_has_orig_dst_option(&sock), \"IP_RECVDSTADDR not enabled\");","typeGuard":"fn has_dest_cmsg(cmsgs: &libc::msghdr) -> bool { !cmsgs.msg_controllen == 0 } // check a dst cmsg exists","tryCatchPattern":"match relay.recv_dest_from(&mut buf).await { Err(e) if e.kind()==InvalidData => log::warn!(\"packet w/o orig dst dropped\"), other => other? }","preventionTips":["Always set the recv-orig-destination socket option before recvmsg","Verify pf/ipfw divert rules in deployment scripts","Allocate a large cmsg control buffer","Test with packets that traverse the firewall, not direct loopback sends"],"tags":["network","udp","transparent-proxy","freebsd"],"backgroundTag":"missing-required-argument","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"}