shadowsocks/shadowsocks-rust · error
missing destination address in msghdr
Error message
missing destination address in msghdr
What it means
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.
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
Example fix
// before: socket created without orig-dst option let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?; // after: enable receiving original destination socket.setsockopt(IPPROTO_IP, IP_RECVDSTADDR, 1)?; // + firewall divert-to rule
Defensive patterns
Strategy: validation
Validate before calling
// before binding, ensure options & firewall are set assert!(socket_has_orig_dst_option(&sock), "IP_RECVDSTADDR not enabled");
Type guard
fn has_dest_cmsg(cmsgs: &libc::msghdr) -> bool { !cmsgs.msg_controllen == 0 } // check a dst cmsg exists Try / catch
match relay.recv_dest_from(&mut buf).await { Err(e) if e.kind()==InvalidData => log::warn!("packet w/o orig dst dropped"), other => other? } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- missing destination address in msghdr
- missing destination address in msghdr
- not supported udp transparent proxy type
- not supported udp transparent proxy type
- not supported udp transparent proxy type
AI-assisted analysis of shadowsocks/shadowsocks-rust@8eb0f0a65b (2026-09-09).
Data as JSON: /api/errors/78c9112fc904296d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/freebsd.rs:300
return Ok(());
}
(libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {
ptr::copy_nonoverlapping(
libc::CMSG_DATA(cmsg),
dst_addr as *mut _,
mem::size_of::<libc::sockaddr_in6>(),
);
*dst_addr_len = mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t;
return Ok(());
}
_ => {}
}
cmsg = libc::CMSG_NXTHDR(msg, cmsg);
}
let err = Error::new(ErrorKind::InvalidData, "missing destination address in msghdr");
Err(err)
})?;
Ok(addr.as_socket().expect("SocketAddr"))
}
}
fn recv_dest_from(socket: &UdpSocket, buf: &mut [u8]) -> io::Result<(usize, SocketAddr, SocketAddr)> {
unsafe {
let mut control_buf = [0u8; 64];
let mut src_addr: libc::sockaddr_storage = mem::zeroed();
let mut msg: libc::msghdr = mem::zeroed();
msg.msg_name = &mut src_addr as *mut _ as *mut _;
msg.msg_namelen = mem::size_of_val(&src_addr) as libc::socklen_t;
let mut iov = libc::iovec {
iov_base: buf.as_mut_ptr() as *mut _,View on GitHub (pinned to 8eb0f0a65b)