From 8d915d62c307765ddec2ee19cd1d784051ad4a42 Mon Sep 17 00:00:00 2001 From: Vitaly _Vi Shukela Date: Tue, 28 Jan 2020 18:56:15 +0300 Subject: [PATCH 1/4] Add TPROXY-related socket options and message This beings `OrigDstAddrV4` and `OrigDstAddrV6` `recvmsg` messages and associated socket options `RecvOrigDstAddrV4` and `RecvOrigDstAddrV6`. Should close #1023. --- src/sys/socket/mod.rs | 103 ++++++++++++++++++++++++++++++++++++-- src/sys/socket/sockopt.rs | 4 ++ 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 52768c9351..6b512c0668 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -529,6 +529,19 @@ pub enum ControlMessageOwned { #[cfg(target_os = "linux")] UdpGroSegments(u16), + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + ))] + OrigDstAddrV4(libc::sockaddr_in), + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + ))] + OrigDstAddrV6(libc::sockaddr_in6), + /// Catch-all variant for unimplemented cmsg types. #[doc(hidden)] Unknown(UnknownCmsg), @@ -622,6 +635,16 @@ impl ControlMessageOwned { let gso_size: u16 = ptr::read_unaligned(p as *const _); ControlMessageOwned::UdpGroSegments(gso_size) }, + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { + let dl = ptr::read_unaligned(p as *const libc::sockaddr_in); + ControlMessageOwned::OrigDstAddrV4(dl) + }, + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => { + let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6); + ControlMessageOwned::OrigDstAddrV6(dl) + }, (_, _) => { let sl = slice::from_raw_parts(p, len); let ucmsg = UnknownCmsg(*header, Vec::::from(&sl[..])); @@ -677,6 +700,34 @@ pub enum ControlMessage<'a> { #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ScmCreds, + /// A message of type `IP_ORIGDSTADDR` which is triggered by setting + /// `RecvOrigDstAddrV4` socket option and is used to get original IPv4 + /// UDP or TCP destination address when actual destination address + /// is overwritten by [`TPROXY`][1], which in turn may be used to + /// make a transparent proxy server. + /// + /// [1]:https://www.kernel.org/doc/Documentation/networking/tproxy.txt + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + ))] + OrigDstAddrV4(&'a libc::sockaddr_in), + + /// A message of type `IPV6_ORIGDSTADDR` which is triggered by setting + /// `RecvOrigDstAddrV6` socket option and is used to get original IPv6 + /// UDP or TCP destination address when actual destination address + /// is overwritten by [`TPROXY`][1], which in turn may be used to + /// make a transparent proxy server. + /// + /// [1]:https://www.kernel.org/doc/Documentation/networking/tproxy.txt + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + ))] + OrigDstAddrV6(&'a libc::sockaddr_in6), + /// Set IV for `AF_ALG` crypto API. /// /// For further information, please refer to the @@ -754,14 +805,30 @@ impl<'a> ControlMessage<'a> { #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::ScmCredentials(creds) => { &creds.0 as *const libc::ucred as *const u8 - } + }, #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ControlMessage::ScmCreds => { // The kernel overwrites the data, we just zero it // to make sure it's not uninitialized memory unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) }; return - } + }, + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + ))] + ControlMessage::OrigDstAddrV4(origaddr) => { + origaddr as *const libc::sockaddr_in as *const u8 + }, + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + ))] + ControlMessage::OrigDstAddrV6(origaddr) => { + origaddr as *const libc::sockaddr_in6 as *const u8 + }, #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetIv(iv) => { let af_alg_iv = libc::af_alg_iv { @@ -817,11 +884,27 @@ impl<'a> ControlMessage<'a> { #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::ScmCredentials(creds) => { mem::size_of_val(creds) - } + }, #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] ControlMessage::ScmCreds => { mem::size_of::() - } + }, + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + ))] + ControlMessage::OrigDstAddrV4(origaddr) => { + mem::size_of_val(origaddr) + }, + #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "freebsd", + ))] + ControlMessage::OrigDstAddrV6(origaddr) => { + mem::size_of_val(origaddr) + }, #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetIv(iv) => { mem::size_of::() + iv.len() @@ -854,6 +937,10 @@ impl<'a> ControlMessage<'a> { ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG, #[cfg(target_os = "linux")] ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP, + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + ControlMessage::OrigDstAddrV4(_) => libc::IPPROTO_IP, + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + ControlMessage::OrigDstAddrV6(_) => libc::IPPROTO_IPV6, } } @@ -869,6 +956,14 @@ impl<'a> ControlMessage<'a> { ControlMessage::AlgSetIv(_) => { libc::ALG_SET_IV }, + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + ControlMessage::OrigDstAddrV4(_) => { + libc::IP_ORIGDSTADDR + }, + #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + ControlMessage::OrigDstAddrV6(_) => { + libc::IPV6_ORIGDSTADDR + }, #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetOp(_) => { libc::ALG_SET_OP diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index fa19fb76cd..bc48db58f9 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -266,6 +266,10 @@ sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::s sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool); #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool); +#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] +sockopt_impl!(Both, RecvOrigDstAddrV4, libc::SOL_IP, libc::IP_RECVORIGDSTADDR, bool); +#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] +sockopt_impl!(Both, RecvOrigDstAddrV6, libc::SOL_IPV6, libc::IPV6_RECVORIGDSTADDR, bool); #[cfg(target_os = "openbsd")] sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool); #[cfg(target_os = "freebsd")] From 49138fcdba82dd5d19f0e3a2d00d942c649da712 Mon Sep 17 00:00:00 2001 From: Mike Taylor Date: Tue, 19 May 2020 23:51:43 -0600 Subject: [PATCH 2/4] Add support for specifying IP_PKTINFO in calls to sendmsg --- src/sys/socket/mod.rs | 108 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 6b512c0668..89089f0f88 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -728,6 +728,26 @@ pub enum ControlMessage<'a> { ))] OrigDstAddrV6(&'a libc::sockaddr_in6), + #[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + Ipv4PacketInfo(&'a libc::in_pktinfo), + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd", + target_os = "netbsd", + ))] + Ipv6PacketInfo(&'a libc::in6_pktinfo), + /// Set IV for `AF_ALG` crypto API. /// /// For further information, please refer to the @@ -829,6 +849,29 @@ impl<'a> ControlMessage<'a> { ControlMessage::OrigDstAddrV6(origaddr) => { origaddr as *const libc::sockaddr_in6 as *const u8 }, + #[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + ControlMessage::Ipv4PacketInfo(pktinfo) => { + pktinfo as *const libc::in_pktinfo as *const u8 + }, + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd", + target_os = "netbsd", + ))] + ControlMessage::Ipv6PacketInfo(pktinfo) => { + pktinfo as *const libc::in6_pktinfo as *const u8 + }, #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetIv(iv) => { let af_alg_iv = libc::af_alg_iv { @@ -905,6 +948,29 @@ impl<'a> ControlMessage<'a> { ControlMessage::OrigDstAddrV6(origaddr) => { mem::size_of_val(origaddr) }, + #[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + ControlMessage::Ipv4PacketInfo(pktinfo) => { + mem::size_of_val(pktinfo) + }, + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd", + target_os = "netbsd", + ))] + ControlMessage::Ipv6PacketInfo(pktinfo) => { + mem::size_of_val(pktinfo) + }, #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::AlgSetIv(iv) => { mem::size_of::() + iv.len() @@ -937,6 +1003,25 @@ impl<'a> ControlMessage<'a> { ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG, #[cfg(target_os = "linux")] ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP, + #[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP, + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd", + target_os = "netbsd", + ))] + ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] ControlMessage::OrigDstAddrV4(_) => libc::IPPROTO_IP, #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] @@ -956,6 +1041,29 @@ impl<'a> ControlMessage<'a> { ControlMessage::AlgSetIv(_) => { libc::ALG_SET_IV }, + #[cfg(any( + target_os = "android", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + ControlMessage::Ipv4PacketInfo(_) => { + libc::IP_PKTINFO + }, + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "openbsd", + target_os = "netbsd", + ))] + ControlMessage::Ipv6PacketInfo(_) => { + libc::IPV6_PKTINFO + }, #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] ControlMessage::OrigDstAddrV4(_) => { libc::IP_ORIGDSTADDR From 8ae627fbb8fbab70a00bf9e3ab6bd599dec14eaf Mon Sep 17 00:00:00 2001 From: Mike Taylor Date: Wed, 20 May 2020 20:39:08 -0600 Subject: [PATCH 3/4] Add support for setting IP_HDRINCL --- src/sys/socket/sockopt.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index bc48db58f9..8c8d5142f9 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -267,6 +267,8 @@ sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool #[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool); #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] +sockopt_impl!(Both, IncludeIpHeaders, libc::IPPROTO_IP, libc::IP_HDRINCL, bool); +#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] sockopt_impl!(Both, RecvOrigDstAddrV4, libc::SOL_IP, libc::IP_RECVORIGDSTADDR, bool); #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] sockopt_impl!(Both, RecvOrigDstAddrV6, libc::SOL_IPV6, libc::IPV6_RECVORIGDSTADDR, bool); From a8e63bed88879df2cfea84f82c6a0385c5de16a5 Mon Sep 17 00:00:00 2001 From: Mike Taylor Date: Wed, 20 May 2020 21:23:32 -0600 Subject: [PATCH 4/4] Reduce scope of IP_ORIGDSTADDR changes not to cover freebsd APIs --- src/sys/socket/mod.rs | 16 ++++------------ src/sys/socket/sockopt.rs | 4 ++-- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 89089f0f88..08d0c94b5c 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -532,13 +532,11 @@ pub enum ControlMessageOwned { #[cfg(any( target_os = "linux", target_os = "android", - target_os = "freebsd", ))] OrigDstAddrV4(libc::sockaddr_in), #[cfg(any( target_os = "linux", target_os = "android", - target_os = "freebsd", ))] OrigDstAddrV6(libc::sockaddr_in6), @@ -635,12 +633,12 @@ impl ControlMessageOwned { let gso_size: u16 = ptr::read_unaligned(p as *const _); ControlMessageOwned::UdpGroSegments(gso_size) }, - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "android", target_os = "linux"))] (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { let dl = ptr::read_unaligned(p as *const libc::sockaddr_in); ControlMessageOwned::OrigDstAddrV4(dl) }, - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "android", target_os = "linux"))] (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => { let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6); ControlMessageOwned::OrigDstAddrV6(dl) @@ -710,7 +708,6 @@ pub enum ControlMessage<'a> { #[cfg(any( target_os = "linux", target_os = "android", - target_os = "freebsd", ))] OrigDstAddrV4(&'a libc::sockaddr_in), @@ -724,7 +721,6 @@ pub enum ControlMessage<'a> { #[cfg(any( target_os = "linux", target_os = "android", - target_os = "freebsd", ))] OrigDstAddrV6(&'a libc::sockaddr_in6), @@ -836,7 +832,6 @@ impl<'a> ControlMessage<'a> { #[cfg(any( target_os = "linux", target_os = "android", - target_os = "freebsd", ))] ControlMessage::OrigDstAddrV4(origaddr) => { origaddr as *const libc::sockaddr_in as *const u8 @@ -844,7 +839,6 @@ impl<'a> ControlMessage<'a> { #[cfg(any( target_os = "linux", target_os = "android", - target_os = "freebsd", ))] ControlMessage::OrigDstAddrV6(origaddr) => { origaddr as *const libc::sockaddr_in6 as *const u8 @@ -935,7 +929,6 @@ impl<'a> ControlMessage<'a> { #[cfg(any( target_os = "linux", target_os = "android", - target_os = "freebsd", ))] ControlMessage::OrigDstAddrV4(origaddr) => { mem::size_of_val(origaddr) @@ -943,7 +936,6 @@ impl<'a> ControlMessage<'a> { #[cfg(any( target_os = "linux", target_os = "android", - target_os = "freebsd", ))] ControlMessage::OrigDstAddrV6(origaddr) => { mem::size_of_val(origaddr) @@ -1064,11 +1056,11 @@ impl<'a> ControlMessage<'a> { ControlMessage::Ipv6PacketInfo(_) => { libc::IPV6_PKTINFO }, - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::OrigDstAddrV4(_) => { libc::IP_ORIGDSTADDR }, - #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "android", target_os = "linux"))] ControlMessage::OrigDstAddrV6(_) => { libc::IPV6_ORIGDSTADDR }, diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 8c8d5142f9..85f5cbe45a 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -268,9 +268,9 @@ sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool); #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] sockopt_impl!(Both, IncludeIpHeaders, libc::IPPROTO_IP, libc::IP_HDRINCL, bool); -#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!(Both, RecvOrigDstAddrV4, libc::SOL_IP, libc::IP_RECVORIGDSTADDR, bool); -#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "android", target_os = "linux"))] sockopt_impl!(Both, RecvOrigDstAddrV6, libc::SOL_IPV6, libc::IPV6_RECVORIGDSTADDR, bool); #[cfg(target_os = "openbsd")] sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool);