diff --git a/CHANGELOG.md b/CHANGELOG.md index e146c48395..8e5d1faa21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#857](https://github.com/nix-rust/nix/pull/857)) - Added `request_code_write_int!` on FreeBSD/DragonFlyBSD ([#833](https://github.com/nix-rust/nix/pull/833)) +- Added PKTINFO cmsg support on Linux/macOS/iOS. + ([#891](https://github.com/nix-rust/nix/pull/891)) ### Changed - Display and Debug for SysControlAddr now includes all fields. diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index af66bc4715..bb60d9d017 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -414,6 +414,14 @@ impl<'a> Iterator for CmsgIterator<'a> { Some(ControlMessage::ScmTimestamp( &*(cmsg_data.as_ptr() as *const _))) }, + #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios"))] + (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => unsafe { + Some(ControlMessage::Ipv6PacketInfo(& *(cmsg_data.as_ptr() as *const _))) + }, + #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios"))] + (libc::IPPROTO_IP, libc::IP_PKTINFO) => unsafe { + Some(ControlMessage::Ipv4PacketInfo(& *(cmsg_data.as_ptr() as *const _))) + }, (_, _) => unsafe { Some(ControlMessage::Unknown(UnknownCmsg( cmsg, @@ -504,6 +512,10 @@ pub enum ControlMessage<'a> { /// nix::unistd::close(in_socket).unwrap(); /// ``` ScmTimestamp(&'a TimeVal), + #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios"))] + Ipv4PacketInfo(&'a libc::in_pktinfo), + #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios"))] + Ipv6PacketInfo(&'a libc::in6_pktinfo), #[doc(hidden)] Unknown(UnknownCmsg<'a>), } @@ -538,6 +550,14 @@ impl<'a> ControlMessage<'a> { ControlMessage::ScmTimestamp(t) => { mem::size_of_val(t) }, + #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios"))] + ControlMessage::Ipv4PacketInfo(pktinfo) => { + mem::size_of_val(pktinfo) + }, + #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios"))] + ControlMessage::Ipv6PacketInfo(pktinfo) => { + mem::size_of_val(pktinfo) + }, ControlMessage::Unknown(UnknownCmsg(_, bytes)) => { mem::size_of_val(bytes) } @@ -586,6 +606,46 @@ impl<'a> ControlMessage<'a> { copy_bytes(t, buf); }, + #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios"))] + ControlMessage::Ipv4PacketInfo(pktinfo) => { + let cmsg = cmsghdr { + cmsg_len: self.len() as _, + cmsg_level: libc::IPPROTO_IP, + cmsg_type: libc::IP_PKTINFO, + ..mem::uninitialized() + }; + copy_bytes(&cmsg, buf); + + let padlen = cmsg_align(mem::size_of_val(&cmsg)) - + mem::size_of_val(&cmsg); + + let mut tmpbuf = &mut [][..]; + mem::swap(&mut tmpbuf, buf); + let (_padding, mut remainder) = tmpbuf.split_at_mut(padlen); + mem::swap(buf, &mut remainder); + + copy_bytes(pktinfo, buf); + }, + #[cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios"))] + ControlMessage::Ipv6PacketInfo(pktinfo) => { + let cmsg = cmsghdr { + cmsg_len: self.len() as _, + cmsg_level: libc::IPPROTO_IPV6, + cmsg_type: libc::IPV6_PKTINFO, + ..mem::uninitialized() + }; + copy_bytes(&cmsg, buf); + + let padlen = cmsg_align(mem::size_of_val(&cmsg)) - + mem::size_of_val(&cmsg); + + let mut tmpbuf = &mut [][..]; + mem::swap(&mut tmpbuf, buf); + let (_padding, mut remainder) = tmpbuf.split_at_mut(padlen); + mem::swap(buf, &mut remainder); + + copy_bytes(pktinfo, buf); + }, ControlMessage::Unknown(UnknownCmsg(orig_cmsg, bytes)) => { copy_bytes(orig_cmsg, buf); copy_bytes(bytes, buf); diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index cbfd9249c4..a1f395ed17 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -255,6 +255,10 @@ sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool); sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool); #[cfg(target_os = "linux")] sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32); +#[cfg(any(target_os = "android", target_os = "linux", target_os = "ios", target_os = "macos"))] +sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool); +#[cfg(any(target_os = "android", target_os = "linux", target_os = "ios", target_os = "macos"))] +sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool); /* *