Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for DSCP and TTL / Hop Limit #2425

Merged
merged 27 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8a030dc
feat: add support for DSCP and TTL / Hop Limit
crisidev Jun 3, 2024
27cac60
Add PR changelog
crisidev Jun 3, 2024
4faed1b
This is not supported on Freebsd
crisidev Jun 3, 2024
342aa6b
IPV6_RECVTCLASS not supported on freebsd
crisidev Jun 3, 2024
84fc5b1
Properly limit IPV6_RECVTCLASS
crisidev Jun 3, 2024
72173b5
Properly limit IP_TOS
crisidev Jun 3, 2024
64efe4e
Restrict everything to target_os linux
crisidev Jun 3, 2024
ee761a8
...
crisidev Jun 4, 2024
8f52422
Protect bind
crisidev Jun 4, 2024
be4a2de
Apply suggestions from code review
crisidev Jun 14, 2024
6e34f92
Address PR comments
crisidev Jun 14, 2024
13b2107
Run cargo fmt
crisidev Jun 14, 2024
c76237c
Merge branch 'nix-rust:master' into master
crisidev Jul 21, 2024
efeac24
Address further comments from PR
crisidev Jul 21, 2024
3c1eed7
Run tests under qemu
crisidev Jul 21, 2024
4946d5f
Use libc from git
crisidev Jul 21, 2024
07691e7
Disable qemu IPTOS / IPV6TCLASS tests on mips
crisidev Jul 21, 2024
0c48b03
Apply suggestions from code review
crisidev Jul 22, 2024
cfb4fde
Fix more code review suggestions
crisidev Jul 22, 2024
1be4b84
Fix missing renames in tests
crisidev Jul 22, 2024
dffe259
Testing
crisidev Jul 22, 2024
1337953
Fixes
crisidev Jul 22, 2024
72c00ee
Fix freebsd
crisidev Jul 22, 2024
684e6b2
Trigger CI again
crisidev Jul 22, 2024
349613c
Trigger CI again
crisidev Jul 22, 2024
c842aa7
Use the same control message in linux and freebsd for ipv4ttl
crisidev Jul 22, 2024
7fd1b3d
test: remove a println
SteveLauC Jul 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ targets = [
]

[dependencies]
libc = { version = "0.2.155", features = ["extra_traits"] }
libc = { git = "https://github.com/rust-lang/libc", branch = "libc-0.2", features = ["extra_traits"] }
bitflags = "2.3.3"
cfg-if = "1.0"
pin-utils = { version = "0.1.0", optional = true }
Expand Down
2 changes: 2 additions & 0 deletions changelog/2425.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve support for extracting the TTL / Hop Limit from incoming packets
and support for DSCP (ToS / Traffic Class).
155 changes: 153 additions & 2 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,43 @@ pub enum ControlMessageOwned {
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6OrigDstAddr(libc::sockaddr_in6),

/// Time-to-Live (TTL) header field of the incoming IPv4 packet.
///
/// [Further reading](https://www.man7.org/linux/man-pages/man7/ip.7.html)
#[cfg(linux_android)]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4Ttl(i32),

/// Time-to-Live (TTL) header field of the incoming IPv4 packet.
///
/// [Further reading](https://datatracker.ietf.org/doc/html/rfc3542.html)
#[cfg(target_os = "freebsd")]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4Ttl(u8),

/// Hop Limit header field of the incoming IPv6 packet.
///
/// [Further reading for Linux](https://www.man7.org/linux/man-pages/man7/ip.7.html)
/// [Further reading for FreeBSD](https://datatracker.ietf.org/doc/html/rfc3542.html)
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6HopLimit(i32),

/// Retrieve the DSCP (ToS) header field of the incoming IPv4 packet.
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4Tos(u8),

/// Retrieve the DSCP (Traffic Class) header field of the incoming IPv6 packet.
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6TClass(i32),

/// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
/// packets from a single sender.
/// Fixed-size payloads are following one by one in a receive buffer.
Expand Down Expand Up @@ -987,6 +1024,42 @@ impl ControlMessageOwned {
let content_type = unsafe { ptr::read_unaligned(p as *const u8) };
ControlMessageOwned::TlsGetRecordType(content_type.into())
},
#[cfg(linux_android)]
#[cfg(feature = "net")]
(libc::IPPROTO_IP, libc::IP_TTL) => {
crisidev marked this conversation as resolved.
Show resolved Hide resolved
let ttl = unsafe { ptr::read_unaligned(p as *const i32) };
ControlMessageOwned::Ipv4Ttl(ttl)
},
#[cfg(target_os = "freebsd")]
#[cfg(feature = "net")]
(libc::IPPROTO_IP, libc::IP_RECVTTL) => {
let ttl: u8 = unsafe { ptr::read_unaligned(p as *const u8) };
ControlMessageOwned::Ipv4Ttl(ttl)
},
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
(libc::IPPROTO_IPV6, libc::IPV6_HOPLIMIT) => {
let ttl = unsafe { ptr::read_unaligned(p as *const i32) };
ControlMessageOwned::Ipv6HopLimit(ttl)
},
#[cfg(linux_android)]
#[cfg(feature = "net")]
(libc::IPPROTO_IP, libc::IP_TOS) => {
crisidev marked this conversation as resolved.
Show resolved Hide resolved
let tos = unsafe { ptr::read_unaligned(p as *const u8) };
ControlMessageOwned::Ipv4Tos(tos)
},
#[cfg(target_os = "freebsd")]
#[cfg(feature = "net")]
(libc::IPPROTO_IP, libc::IP_RECVTOS) => {
let tos = unsafe { ptr::read_unaligned(p as *const u8) };
ControlMessageOwned::Ipv4Tos(tos)
},
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
(libc::IPPROTO_IPV6, libc::IPV6_TCLASS) => {
let tc = unsafe { ptr::read_unaligned(p as *const i32) };
ControlMessageOwned::Ipv6TClass(tc)
},
(_, _) => {
let sl = unsafe { std::slice::from_raw_parts(p, len) };
let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
Expand Down Expand Up @@ -1124,6 +1197,18 @@ pub enum ControlMessage<'a> {
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4SendSrcAddr(&'a libc::in_addr),

/// Configure the Time-to-Live for v4 traffic.
#[cfg(linux_android)]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4Ttl(&'a libc::c_int),
crisidev marked this conversation as resolved.
Show resolved Hide resolved

/// Configure the Time-to-Live for v4 traffic.
#[cfg(target_os = "freebsd")]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4Ttl(&'a libc::c_uchar),

/// Configure the hop limit for v6 multicast traffic.
///
/// Set the IPv6 hop limit for this message. The argument is an integer
Expand All @@ -1138,9 +1223,9 @@ pub enum ControlMessage<'a> {
Ipv6HopLimit(&'a libc::c_int),

/// SO_RXQ_OVFL indicates that an unsigned 32 bit value
/// ancilliary msg (cmsg) should be attached to recieved
/// ancillary msg (cmsg) should be attached to received
/// skbs indicating the number of packets dropped by the
/// socket between the last recieved packet and this
/// socket between the last received packet and this
/// received packet.
#[cfg(any(linux_android, target_os = "fuchsia"))]
RxqOvfl(&'a u32),
Expand All @@ -1152,6 +1237,22 @@ pub enum ControlMessage<'a> {
/// page.
#[cfg(target_os = "linux")]
TxTime(&'a u64),

/// Configure DSCP / IP TOS for outgoing v4 packets.
///
/// Further information can be found [here](https://en.wikipedia.org/wiki/Differentiated_services).
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv4Tos(&'a u8),

/// Configure DSCP / IPv6 TCLASS for outgoing v6 packets.
///
/// Further information can be found [here](https://en.wikipedia.org/wiki/Differentiated_services).
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
Ipv6TClass(&'a i32),
crisidev marked this conversation as resolved.
Show resolved Hide resolved
}

// An opaque structure used to prevent cmsghdr from being a public type
Expand Down Expand Up @@ -1245,6 +1346,9 @@ impl<'a> ControlMessage<'a> {
#[cfg(any(freebsdlike, netbsdlike))]
#[cfg(feature = "net")]
ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8,
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv4Ttl(ttl) => ttl as *const _ as *const u8,
#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
#[cfg(feature = "net")]
ControlMessage::Ipv6HopLimit(limit) => limit as *const _ as *const u8,
Expand All @@ -1256,6 +1360,16 @@ impl<'a> ControlMessage<'a> {
ControlMessage::TxTime(tx_time) => {
tx_time as *const _ as *const u8
},
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv4Tos(tos) => {
tos as *const _
},
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv6TClass(tclass) => {
tclass as *const _ as *const u8
},
};
unsafe {
ptr::copy_nonoverlapping(
Expand Down Expand Up @@ -1307,6 +1421,11 @@ impl<'a> ControlMessage<'a> {
#[cfg(any(freebsdlike, netbsdlike))]
#[cfg(feature = "net")]
ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr),
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv4Ttl(ttl) => {
mem::size_of_val(ttl)
},
#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
#[cfg(feature = "net")]
ControlMessage::Ipv6HopLimit(limit) => {
Expand All @@ -1320,6 +1439,16 @@ impl<'a> ControlMessage<'a> {
ControlMessage::TxTime(tx_time) => {
mem::size_of_val(tx_time)
},
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv4Tos(tos) => {
mem::size_of_val(tos)
},
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv6TClass(tclass) => {
mem::size_of_val(tclass)
},
}
}

Expand Down Expand Up @@ -1347,13 +1476,22 @@ impl<'a> ControlMessage<'a> {
#[cfg(any(freebsdlike, netbsdlike))]
#[cfg(feature = "net")]
ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP,
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv4Ttl(_) => libc::IPPROTO_IP,
#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
#[cfg(feature = "net")]
ControlMessage::Ipv6HopLimit(_) => libc::IPPROTO_IPV6,
#[cfg(any(linux_android, target_os = "fuchsia"))]
ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
#[cfg(target_os = "linux")]
ControlMessage::TxTime(_) => libc::SOL_SOCKET,
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv4Tos(_) => libc::IPPROTO_IP,
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv6TClass(_) => libc::IPPROTO_IPV6,
}
}

Expand Down Expand Up @@ -1392,6 +1530,9 @@ impl<'a> ControlMessage<'a> {
#[cfg(any(freebsdlike, netbsdlike))]
#[cfg(feature = "net")]
ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR,
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv4Ttl(_) => libc::IP_TTL,
#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
#[cfg(feature = "net")]
ControlMessage::Ipv6HopLimit(_) => libc::IPV6_HOPLIMIT,
Expand All @@ -1403,6 +1544,16 @@ impl<'a> ControlMessage<'a> {
ControlMessage::TxTime(_) => {
libc::SCM_TXTIME
},
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv4Tos(_) => {
libc::IP_TOS
},
crisidev marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
ControlMessage::Ipv6TClass(_) => {
libc::IPV6_TCLASS
},
}
}

Expand Down
52 changes: 48 additions & 4 deletions src/sys/socket/sockopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,29 +402,51 @@ sockopt_impl!(
libc::SO_PRIORITY,
libc::c_int
);
#[cfg(target_os = "linux")]
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
/// Set or receive the Type-Of-Service (TOS) field that is
/// sent with every IP packet originating from this socket
IpTos,
Ipv4Tos,
Both,
libc::IPPROTO_IP,
libc::IP_TOS,
libc::c_int
);
#[cfg(target_os = "linux")]
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
crisidev marked this conversation as resolved.
Show resolved Hide resolved
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
/// Traffic class associated with outgoing packets
/// If enabled, the IP_TOS ancillary message is passed with incoming packets.
IpRecvTos,
crisidev marked this conversation as resolved.
Show resolved Hide resolved
Both,
libc::IPPROTO_IP,
libc::IP_RECVTOS,
bool
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
/// Set the traffic class associated with outgoing packets.
Ipv6TClass,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_TCLASS,
libc::c_int
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
/// If enabled, the IPV6_TCLASS ancillary message is passed with incoming packets.
Ipv6RecvTClass,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_RECVTCLASS,
bool
);
#[cfg(any(linux_android, target_os = "fuchsia"))]
#[cfg(feature = "net")]
sockopt_impl!(
Expand Down Expand Up @@ -1058,6 +1080,17 @@ sockopt_impl!(
libc::IP_TTL,
libc::c_int
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
/// Enables a receiving socket to retrieve the Time-to-Live (TTL) field
/// from incoming IPv4 packets.
Ipv4RecvTtl,
Both,
libc::IPPROTO_IP,
libc::IP_RECVTTL,
bool
);
#[cfg(any(apple_targets, linux_android, target_os = "freebsd"))]
sockopt_impl!(
/// Set the unicast hop limit for the socket.
Expand All @@ -1069,6 +1102,17 @@ sockopt_impl!(
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
/// Enables a receiving socket to retrieve the Hop Limit field
/// (similar to TTL in IPv4) from incoming IPv6 packets.
Ipv6RecvHopLimit,
Both,
libc::IPPROTO_IPV6,
libc::IPV6_RECVHOPLIMIT,
bool
);
#[cfg(any(linux_android, target_os = "freebsd"))]
#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
/// The `recvmsg(2)` call will return the destination IP address for a UDP
Expand Down
Loading