Skip to content

Commit 0788a4a

Browse files
PiotrSikoraThomasdezeeuw
authored andcommitted
Add support for SO_ORIGINAL_DST and IP6T_SO_ORIGINAL_DST.
Those values contain the original destination IPv4/IPv6 address of the connection redirected using iptables REDIRECT or TPROXY. Signed-off-by: Piotr Sikora <[email protected]>
1 parent a961449 commit 0788a4a

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

src/sys/unix.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,68 @@ impl crate::Socket {
17891789
}
17901790
}
17911791

1792+
/// Get the value for the `SO_ORIGINAL_DST` option on this socket.
1793+
///
1794+
/// This value contains the original destination IPv4 address of the connection
1795+
/// redirected using `iptables` `REDIRECT` or `TPROXY`.
1796+
#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1797+
#[cfg_attr(
1798+
docsrs,
1799+
doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
1800+
)]
1801+
pub fn original_dst(&self) -> io::Result<Option<SockAddr>> {
1802+
// Safety: `getsockopt` initialises the `SockAddr` for us.
1803+
unsafe {
1804+
SockAddr::try_init(|storage, len| {
1805+
syscall!(getsockopt(
1806+
self.as_raw(),
1807+
libc::SOL_IP,
1808+
libc::SO_ORIGINAL_DST,
1809+
storage.cast(),
1810+
len
1811+
))
1812+
})
1813+
}
1814+
.map_or_else(
1815+
|e| match e.raw_os_error() {
1816+
Some(libc::ENOENT) => Ok(None),
1817+
_ => Err(e),
1818+
},
1819+
|(_, addr)| Ok(Some(addr)),
1820+
)
1821+
}
1822+
1823+
/// Get the value for the `IP6T_SO_ORIGINAL_DST` option on this socket.
1824+
///
1825+
/// This value contains the original destination IPv6 address of the connection
1826+
/// redirected using `ip6tables` `REDIRECT` or `TPROXY`.
1827+
#[cfg(all(feature = "all", any(target_os = "android", target_os = "linux")))]
1828+
#[cfg_attr(
1829+
docsrs,
1830+
doc(cfg(all(feature = "all", any(target_os = "android", target_os = "linux"))))
1831+
)]
1832+
pub fn original_dst_ipv6(&self) -> io::Result<Option<SockAddr>> {
1833+
// Safety: `getsockopt` initialises the `SockAddr` for us.
1834+
unsafe {
1835+
SockAddr::try_init(|storage, len| {
1836+
syscall!(getsockopt(
1837+
self.as_raw(),
1838+
libc::SOL_IPV6,
1839+
libc::IP6T_SO_ORIGINAL_DST,
1840+
storage.cast(),
1841+
len
1842+
))
1843+
})
1844+
}
1845+
.map_or_else(
1846+
|e| match e.raw_os_error() {
1847+
Some(libc::ENOENT) => Ok(None),
1848+
_ => Err(e),
1849+
},
1850+
|(_, addr)| Ok(Some(addr)),
1851+
)
1852+
}
1853+
17921854
/// Copies data between a `file` and this socket using the `sendfile(2)`
17931855
/// system call. Because this copying is done within the kernel,
17941856
/// `sendfile()` is more efficient than the combination of `read(2)` and

0 commit comments

Comments
 (0)