Skip to content

Commit f9e882e

Browse files
committed
Add Socket::{header_included, set_header_included}
Sets or gets the IP_HDRINCL socket option, only available on raw sockets.
1 parent dc6e996 commit f9e882e

File tree

4 files changed

+68
-2
lines changed

4 files changed

+68
-2
lines changed

src/socket.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,44 @@ fn into_linger(duration: Option<Duration>) -> sys::linger {
991991
/// * Linux: <https://man7.org/linux/man-pages/man7/ip.7.html>
992992
/// * Windows: <https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options>
993993
impl Socket {
994+
/// Get the value of the `IP_HDRINCL` option on this socket.
995+
///
996+
/// For more information about this option, see [`set_header_included`].
997+
///
998+
/// [`set_header_included`]: Socket::set_header_included
999+
#[cfg(all(feature = "all", not(target_os = "redox")))]
1000+
#[cfg_attr(docsrs, doc(all(feature = "all", not(target_os = "redox"))))]
1001+
pub fn header_included(&self) -> io::Result<bool> {
1002+
unsafe {
1003+
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL)
1004+
.map(|included| included != 0)
1005+
}
1006+
}
1007+
1008+
/// Set the value of the `IP_HDRINCL` option on this socket.
1009+
///
1010+
/// If enabled, the user supplies an IP header in front of the user data.
1011+
/// Valid only for [`SOCK_RAW`] sockets; see [raw(7)] for more information.
1012+
/// When this flag is enabled, the values set by `IP_OPTIONS`, [`IP_TTL`],
1013+
/// and [`IP_TOS`] are ignored.
1014+
///
1015+
/// [`SOCK_RAW`]: Type::RAW
1016+
/// [raw(7)]: https://man7.org/linux/man-pages/man7/raw.7.html
1017+
/// [`IP_TTL`]: Socket::set_ttl
1018+
/// [`IP_TOS`]: Socket::set_tos
1019+
#[cfg(all(feature = "all", not(target_os = "redox")))]
1020+
#[cfg_attr(docsrs, doc(all(feature = "all", not(target_os = "redox"))))]
1021+
pub fn set_header_included(&self, included: bool) -> io::Result<()> {
1022+
unsafe {
1023+
setsockopt(
1024+
self.as_raw(),
1025+
sys::IPPROTO_IP,
1026+
sys::IP_HDRINCL,
1027+
included as c_int,
1028+
)
1029+
}
1030+
}
1031+
9941032
/// Get the value of the `IP_TRANSPARENT` option on this socket.
9951033
///
9961034
/// For more information about this option, see [`set_ip_transparent`].
@@ -1016,7 +1054,7 @@ impl Socket {
10161054
/// are routed through the TProxy box (i.e., the system
10171055
/// hosting the application that employs the IP_TRANSPARENT
10181056
/// socket option). Enabling this socket option requires
1019-
/// superuser privileges (the CAP_NET_ADMIN capability).
1057+
/// superuser privileges (the `CAP_NET_ADMIN` capability).
10201058
///
10211059
/// TProxy redirection with the iptables TPROXY target also
10221060
/// requires that this option be set on the redirected socket.

src/sys/unix.rs

+2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ pub(crate) use libc::{
7575
#[cfg(not(target_os = "redox"))]
7676
pub(crate) use libc::{MSG_TRUNC, SO_OOBINLINE};
7777
// Used in `Socket`.
78+
#[cfg(all(feature = "all", not(target_os = "redox")))]
79+
pub(crate) use libc::IP_HDRINCL;
7880
#[cfg(not(any(
7981
target_os = "fuschia",
8082
target_os = "redox",

src/sys/windows.rs

+2
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ pub(crate) use winapi::shared::ws2def::{
6666
IPPROTO_IP, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER, SO_OOBINLINE,
6767
SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, SO_TYPE, TCP_NODELAY,
6868
};
69+
#[cfg(feature = "all")]
70+
pub(crate) use winapi::shared::ws2ipdef::IP_HDRINCL;
6971
pub(crate) use winapi::shared::ws2ipdef::{
7072
IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MREQ as Ipv6Mreq, IPV6_MULTICAST_HOPS,
7173
IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY, IP_ADD_MEMBERSHIP,

tests/socket.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -1082,11 +1082,11 @@ macro_rules! test {
10821082

10831083
let initial = socket.$get_fn().expect("failed to get initial value");
10841084
let arg = $arg;
1085-
let expected = $expected;
10861085
assert_ne!(initial, arg, "initial value and argument are the same");
10871086

10881087
socket.$set_fn(arg).expect("failed to set option");
10891088
let got = socket.$get_fn().expect("failed to get value");
1089+
let expected = $expected;
10901090
assert_eq!(got, expected, "set and get values differ");
10911091
};
10921092
}
@@ -1174,3 +1174,27 @@ test!(
11741174
tcp_user_timeout,
11751175
set_tcp_user_timeout(Some(Duration::from_secs(10)))
11761176
);
1177+
1178+
#[test]
1179+
#[cfg(all(feature = "all", not(target_os = "redox")))]
1180+
fn header_included() {
1181+
let socket = match Socket::new(Domain::IPV4, Type::RAW, None) {
1182+
Ok(socket) => socket,
1183+
// Need certain permissions to create a raw sockets.
1184+
Err(ref err) if err.kind() == io::ErrorKind::PermissionDenied => return,
1185+
#[cfg(unix)]
1186+
Err(ref err) if err.raw_os_error() == Some(libc::EPROTONOSUPPORT) => return,
1187+
Err(err) => panic!("unexpected error creating socket: {}", err),
1188+
};
1189+
1190+
let initial = socket
1191+
.header_included()
1192+
.expect("failed to get initial value");
1193+
assert_eq!(initial, false, "initial value and argument are the same");
1194+
1195+
socket
1196+
.set_header_included(true)
1197+
.expect("failed to set option");
1198+
let got = socket.header_included().expect("failed to get value");
1199+
assert_eq!(got, true, "set and get values differ");
1200+
}

0 commit comments

Comments
 (0)