shadowsocks/shadowsocks-rust · error
missing destination address in msghdr
Error message
missing destination address in msghdr
What it means
Same as the FreeBSD variant: Linux tproxy UDP received a packet whose recvmsg control data did not include IP_ORIGDSTADDR/IPV6_ORIGDSTADDR, so the original destination could not be recovered and the packet is rejected with InvalidData.
Source
Thrown at crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/linux.rs:306
return Ok(());
}
(libc::SOL_IPV6, libc::IPV6_RECVORIGDSTADDR) => {
ptr::copy(
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)
Solutions
- Ensure iptables/nftables TPROXY rules steer UDP packets to this socket so the kernel includes the original dst cmsg
- Verify IP_RECVORIGDSTADDR (v4) and IPV6_RECVORIGDSTADDR (v6) were set on the socket before recvmsg
- Provide a sufficiently large control-message buffer in recvmsg; truncation drops the cmsg
- If testing locally, expect this error for packets not routed through the tproxy rules — route them or use a plain socket
- Update to a version matching your kernel's cmsg support (IP_RECVORIGDSTADDR availability)
Example fix
// before: recvmsg without orig-dst option // after socket.setsockopt(IPPROTO_IP, IP_RECVORIGDSTADDR, 1)?; // and iptables: -t mangle -A PREROUTING -p udp -j TPROXY --on-port 1080 --tproxy-mark 1
Defensive patterns
Strategy: validation
Validate before calling
assert socket options IP_RECVORIGDSTADDR / IPV6_RECVORIGDSTADDR are set; verify `iptables -t mangle -L` contains TPROXY udp rule before starting the relay.
Type guard
fn has_origdst_cmsg(control: &[u8]) -> bool { control.iter().any(|c| is_origdst_cmsg(c)) } Try / catch
if let Err(e) = sock.recv_dest_from(&mut buf).await { if e.kind()==InvalidData { metrics.drop_no_dst += 1; continue; } return Err(e); } Prevention
- Set both v4 and v6 orig-dst recv options
- Ensure mangle/PREROUTING TPROXY rules with --tproxy-mark
- Use control buffers >= 512 bytes
- Check kernel supports IP_RECVORIGDSTADDR
When it happens
Trigger: recv_dest_from on a Linux TProxy UDP socket when the kernel did not attach the original-destination cmsg — IP_TRANSPARENT set but the IP_RECVORIGDSTADDR socket option missing, or the packet arrived outside the TPROXY redirect path.
Common situations: Incomplete iptables TPROXY setup (missing mangle/PREROUTING rule), packets hitting the socket directly (e.g. tests binding and sending locally), or truncated control buffer.
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
- not supported udp transparent proxy type
- redir destination must not be an domain name address
- missing destination address in msghdr
- 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/bb41ece716651975.
Report an issue: GitHub.