Skip to content

Commit 25b437c

Browse files
crisidevSteveLauC
andauthored
feat: add support for DSCP and TTL / Hop Limit (#2425)
* feat: add support for DSCP and TTL / Hop Limit * Support IP_RECVTTL and IPV6_RECVHOPLIMIT socket options and related control messages for recvmsg. * Support setting DSCP in control messages for both sendmsg and recvmsg. Signed-off-by: Bigo <[email protected]> * Add PR changelog * This is not supported on Freebsd * IPV6_RECVTCLASS not supported on freebsd * Properly limit IPV6_RECVTCLASS * Properly limit IP_TOS * Restrict everything to target_os linux * ... * Protect bind * Apply suggestions from code review Co-authored-by: SteveLauC <[email protected]> * Address PR comments * Run cargo fmt * Address further comments from PR * Run tests under qemu * Use libc from git * Disable qemu IPTOS / IPV6TCLASS tests on mips * Apply suggestions from code review Co-authored-by: SteveLauC <[email protected]> * Fix more code review suggestions * Fix missing renames in tests * Testing * Fixes * Fix freebsd * Trigger CI again * Trigger CI again * Use the same control message in linux and freebsd for ipv4ttl * test: remove a println --------- Signed-off-by: Bigo <[email protected]> Co-authored-by: SteveLauC <[email protected]>
1 parent 5940300 commit 25b437c

File tree

6 files changed

+507
-7
lines changed

6 files changed

+507
-7
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ targets = [
2828
]
2929

3030
[dependencies]
31-
libc = { version = "0.2.155", features = ["extra_traits"] }
31+
libc = { git = "https://github.com/rust-lang/libc", branch = "libc-0.2", features = ["extra_traits"] }
3232
bitflags = "2.3.3"
3333
cfg-if = "1.0"
3434
pin-utils = { version = "0.1.0", optional = true }

changelog/2425.added.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve support for extracting the TTL / Hop Limit from incoming packets
2+
and support for DSCP (ToS / Traffic Class).

src/sys/socket/mod.rs

+153-2
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,43 @@ pub enum ControlMessageOwned {
769769
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
770770
Ipv6OrigDstAddr(libc::sockaddr_in6),
771771

772+
/// Time-to-Live (TTL) header field of the incoming IPv4 packet.
773+
///
774+
/// [Further reading](https://www.man7.org/linux/man-pages/man7/ip.7.html)
775+
#[cfg(linux_android)]
776+
#[cfg(feature = "net")]
777+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
778+
Ipv4Ttl(i32),
779+
780+
/// Time-to-Live (TTL) header field of the incoming IPv4 packet.
781+
///
782+
/// [Further reading](https://datatracker.ietf.org/doc/html/rfc3542.html)
783+
#[cfg(target_os = "freebsd")]
784+
#[cfg(feature = "net")]
785+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
786+
Ipv4Ttl(u8),
787+
788+
/// Hop Limit header field of the incoming IPv6 packet.
789+
///
790+
/// [Further reading for Linux](https://www.man7.org/linux/man-pages/man7/ip.7.html)
791+
/// [Further reading for FreeBSD](https://datatracker.ietf.org/doc/html/rfc3542.html)
792+
#[cfg(any(linux_android, target_os = "freebsd"))]
793+
#[cfg(feature = "net")]
794+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
795+
Ipv6HopLimit(i32),
796+
797+
/// Retrieve the DSCP (ToS) header field of the incoming IPv4 packet.
798+
#[cfg(any(linux_android, target_os = "freebsd"))]
799+
#[cfg(feature = "net")]
800+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
801+
Ipv4Tos(u8),
802+
803+
/// Retrieve the DSCP (Traffic Class) header field of the incoming IPv6 packet.
804+
#[cfg(any(linux_android, target_os = "freebsd"))]
805+
#[cfg(feature = "net")]
806+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
807+
Ipv6TClass(i32),
808+
772809
/// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
773810
/// packets from a single sender.
774811
/// Fixed-size payloads are following one by one in a receive buffer.
@@ -987,6 +1024,42 @@ impl ControlMessageOwned {
9871024
let content_type = unsafe { ptr::read_unaligned(p as *const u8) };
9881025
ControlMessageOwned::TlsGetRecordType(content_type.into())
9891026
},
1027+
#[cfg(linux_android)]
1028+
#[cfg(feature = "net")]
1029+
(libc::IPPROTO_IP, libc::IP_TTL) => {
1030+
let ttl = unsafe { ptr::read_unaligned(p as *const i32) };
1031+
ControlMessageOwned::Ipv4Ttl(ttl)
1032+
},
1033+
#[cfg(target_os = "freebsd")]
1034+
#[cfg(feature = "net")]
1035+
(libc::IPPROTO_IP, libc::IP_RECVTTL) => {
1036+
let ttl: u8 = unsafe { ptr::read_unaligned(p as *const u8) };
1037+
ControlMessageOwned::Ipv4Ttl(ttl)
1038+
},
1039+
#[cfg(any(linux_android, target_os = "freebsd"))]
1040+
#[cfg(feature = "net")]
1041+
(libc::IPPROTO_IPV6, libc::IPV6_HOPLIMIT) => {
1042+
let ttl = unsafe { ptr::read_unaligned(p as *const i32) };
1043+
ControlMessageOwned::Ipv6HopLimit(ttl)
1044+
},
1045+
#[cfg(linux_android)]
1046+
#[cfg(feature = "net")]
1047+
(libc::IPPROTO_IP, libc::IP_TOS) => {
1048+
let tos = unsafe { ptr::read_unaligned(p as *const u8) };
1049+
ControlMessageOwned::Ipv4Tos(tos)
1050+
},
1051+
#[cfg(target_os = "freebsd")]
1052+
#[cfg(feature = "net")]
1053+
(libc::IPPROTO_IP, libc::IP_RECVTOS) => {
1054+
let tos = unsafe { ptr::read_unaligned(p as *const u8) };
1055+
ControlMessageOwned::Ipv4Tos(tos)
1056+
},
1057+
#[cfg(any(linux_android, target_os = "freebsd"))]
1058+
#[cfg(feature = "net")]
1059+
(libc::IPPROTO_IPV6, libc::IPV6_TCLASS) => {
1060+
let tc = unsafe { ptr::read_unaligned(p as *const i32) };
1061+
ControlMessageOwned::Ipv6TClass(tc)
1062+
},
9901063
(_, _) => {
9911064
let sl = unsafe { std::slice::from_raw_parts(p, len) };
9921065
let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
@@ -1124,6 +1197,18 @@ pub enum ControlMessage<'a> {
11241197
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
11251198
Ipv4SendSrcAddr(&'a libc::in_addr),
11261199

1200+
/// Configure the Time-to-Live for v4 traffic.
1201+
#[cfg(linux_android)]
1202+
#[cfg(feature = "net")]
1203+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1204+
Ipv4Ttl(&'a libc::c_int),
1205+
1206+
/// Configure the Time-to-Live for v4 traffic.
1207+
#[cfg(target_os = "freebsd")]
1208+
#[cfg(feature = "net")]
1209+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1210+
Ipv4Ttl(&'a libc::c_uchar),
1211+
11271212
/// Configure the hop limit for v6 multicast traffic.
11281213
///
11291214
/// Set the IPv6 hop limit for this message. The argument is an integer
@@ -1138,9 +1223,9 @@ pub enum ControlMessage<'a> {
11381223
Ipv6HopLimit(&'a libc::c_int),
11391224

11401225
/// SO_RXQ_OVFL indicates that an unsigned 32 bit value
1141-
/// ancilliary msg (cmsg) should be attached to recieved
1226+
/// ancillary msg (cmsg) should be attached to received
11421227
/// skbs indicating the number of packets dropped by the
1143-
/// socket between the last recieved packet and this
1228+
/// socket between the last received packet and this
11441229
/// received packet.
11451230
#[cfg(any(linux_android, target_os = "fuchsia"))]
11461231
RxqOvfl(&'a u32),
@@ -1152,6 +1237,22 @@ pub enum ControlMessage<'a> {
11521237
/// page.
11531238
#[cfg(target_os = "linux")]
11541239
TxTime(&'a u64),
1240+
1241+
/// Configure DSCP / IP TOS for outgoing v4 packets.
1242+
///
1243+
/// Further information can be found [here](https://en.wikipedia.org/wiki/Differentiated_services).
1244+
#[cfg(any(linux_android, target_os = "freebsd"))]
1245+
#[cfg(feature = "net")]
1246+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1247+
Ipv4Tos(&'a u8),
1248+
1249+
/// Configure DSCP / IPv6 TCLASS for outgoing v6 packets.
1250+
///
1251+
/// Further information can be found [here](https://en.wikipedia.org/wiki/Differentiated_services).
1252+
#[cfg(any(linux_android, target_os = "freebsd"))]
1253+
#[cfg(feature = "net")]
1254+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1255+
Ipv6TClass(&'a i32),
11551256
}
11561257

11571258
// An opaque structure used to prevent cmsghdr from being a public type
@@ -1245,6 +1346,9 @@ impl<'a> ControlMessage<'a> {
12451346
#[cfg(any(freebsdlike, netbsdlike))]
12461347
#[cfg(feature = "net")]
12471348
ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8,
1349+
#[cfg(any(linux_android, target_os = "freebsd"))]
1350+
#[cfg(feature = "net")]
1351+
ControlMessage::Ipv4Ttl(ttl) => ttl as *const _ as *const u8,
12481352
#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
12491353
#[cfg(feature = "net")]
12501354
ControlMessage::Ipv6HopLimit(limit) => limit as *const _ as *const u8,
@@ -1256,6 +1360,16 @@ impl<'a> ControlMessage<'a> {
12561360
ControlMessage::TxTime(tx_time) => {
12571361
tx_time as *const _ as *const u8
12581362
},
1363+
#[cfg(any(linux_android, target_os = "freebsd"))]
1364+
#[cfg(feature = "net")]
1365+
ControlMessage::Ipv4Tos(tos) => {
1366+
tos as *const _
1367+
},
1368+
#[cfg(any(linux_android, target_os = "freebsd"))]
1369+
#[cfg(feature = "net")]
1370+
ControlMessage::Ipv6TClass(tclass) => {
1371+
tclass as *const _ as *const u8
1372+
},
12591373
};
12601374
unsafe {
12611375
ptr::copy_nonoverlapping(
@@ -1307,6 +1421,11 @@ impl<'a> ControlMessage<'a> {
13071421
#[cfg(any(freebsdlike, netbsdlike))]
13081422
#[cfg(feature = "net")]
13091423
ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr),
1424+
#[cfg(any(linux_android, target_os = "freebsd"))]
1425+
#[cfg(feature = "net")]
1426+
ControlMessage::Ipv4Ttl(ttl) => {
1427+
mem::size_of_val(ttl)
1428+
},
13101429
#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
13111430
#[cfg(feature = "net")]
13121431
ControlMessage::Ipv6HopLimit(limit) => {
@@ -1320,6 +1439,16 @@ impl<'a> ControlMessage<'a> {
13201439
ControlMessage::TxTime(tx_time) => {
13211440
mem::size_of_val(tx_time)
13221441
},
1442+
#[cfg(any(linux_android, target_os = "freebsd"))]
1443+
#[cfg(feature = "net")]
1444+
ControlMessage::Ipv4Tos(tos) => {
1445+
mem::size_of_val(tos)
1446+
},
1447+
#[cfg(any(linux_android, target_os = "freebsd"))]
1448+
#[cfg(feature = "net")]
1449+
ControlMessage::Ipv6TClass(tclass) => {
1450+
mem::size_of_val(tclass)
1451+
},
13231452
}
13241453
}
13251454

@@ -1347,13 +1476,22 @@ impl<'a> ControlMessage<'a> {
13471476
#[cfg(any(freebsdlike, netbsdlike))]
13481477
#[cfg(feature = "net")]
13491478
ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP,
1479+
#[cfg(any(linux_android, target_os = "freebsd"))]
1480+
#[cfg(feature = "net")]
1481+
ControlMessage::Ipv4Ttl(_) => libc::IPPROTO_IP,
13501482
#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
13511483
#[cfg(feature = "net")]
13521484
ControlMessage::Ipv6HopLimit(_) => libc::IPPROTO_IPV6,
13531485
#[cfg(any(linux_android, target_os = "fuchsia"))]
13541486
ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
13551487
#[cfg(target_os = "linux")]
13561488
ControlMessage::TxTime(_) => libc::SOL_SOCKET,
1489+
#[cfg(any(linux_android, target_os = "freebsd"))]
1490+
#[cfg(feature = "net")]
1491+
ControlMessage::Ipv4Tos(_) => libc::IPPROTO_IP,
1492+
#[cfg(any(linux_android, target_os = "freebsd"))]
1493+
#[cfg(feature = "net")]
1494+
ControlMessage::Ipv6TClass(_) => libc::IPPROTO_IPV6,
13571495
}
13581496
}
13591497

@@ -1392,6 +1530,9 @@ impl<'a> ControlMessage<'a> {
13921530
#[cfg(any(freebsdlike, netbsdlike))]
13931531
#[cfg(feature = "net")]
13941532
ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR,
1533+
#[cfg(any(linux_android, target_os = "freebsd"))]
1534+
#[cfg(feature = "net")]
1535+
ControlMessage::Ipv4Ttl(_) => libc::IP_TTL,
13951536
#[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
13961537
#[cfg(feature = "net")]
13971538
ControlMessage::Ipv6HopLimit(_) => libc::IPV6_HOPLIMIT,
@@ -1403,6 +1544,16 @@ impl<'a> ControlMessage<'a> {
14031544
ControlMessage::TxTime(_) => {
14041545
libc::SCM_TXTIME
14051546
},
1547+
#[cfg(any(linux_android, target_os = "freebsd"))]
1548+
#[cfg(feature = "net")]
1549+
ControlMessage::Ipv4Tos(_) => {
1550+
libc::IP_TOS
1551+
},
1552+
#[cfg(any(linux_android, target_os = "freebsd"))]
1553+
#[cfg(feature = "net")]
1554+
ControlMessage::Ipv6TClass(_) => {
1555+
libc::IPV6_TCLASS
1556+
},
14061557
}
14071558
}
14081559

src/sys/socket/sockopt.rs

+46-2
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ sockopt_impl!(
408408
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
409409
/// Set or receive the Type-Of-Service (TOS) field that is
410410
/// sent with every IP packet originating from this socket
411-
IpTos,
411+
Ipv4Tos,
412412
Both,
413413
libc::IPPROTO_IP,
414414
libc::IP_TOS,
@@ -418,13 +418,35 @@ sockopt_impl!(
418418
#[cfg(feature = "net")]
419419
sockopt_impl!(
420420
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
421-
/// Traffic class associated with outgoing packets
421+
/// If enabled, the IP_TOS ancillary message is passed with incoming packets.
422+
IpRecvTos,
423+
Both,
424+
libc::IPPROTO_IP,
425+
libc::IP_RECVTOS,
426+
bool
427+
);
428+
#[cfg(any(linux_android, target_os = "freebsd"))]
429+
#[cfg(feature = "net")]
430+
sockopt_impl!(
431+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
432+
/// Set the traffic class associated with outgoing packets.
422433
Ipv6TClass,
423434
Both,
424435
libc::IPPROTO_IPV6,
425436
libc::IPV6_TCLASS,
426437
libc::c_int
427438
);
439+
#[cfg(any(linux_android, target_os = "freebsd"))]
440+
#[cfg(feature = "net")]
441+
sockopt_impl!(
442+
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
443+
/// If enabled, the IPV6_TCLASS ancillary message is passed with incoming packets.
444+
Ipv6RecvTClass,
445+
Both,
446+
libc::IPPROTO_IPV6,
447+
libc::IPV6_RECVTCLASS,
448+
bool
449+
);
428450
#[cfg(any(linux_android, target_os = "fuchsia"))]
429451
#[cfg(feature = "net")]
430452
sockopt_impl!(
@@ -1058,6 +1080,17 @@ sockopt_impl!(
10581080
libc::IP_TTL,
10591081
libc::c_int
10601082
);
1083+
#[cfg(any(linux_android, target_os = "freebsd"))]
1084+
#[cfg(feature = "net")]
1085+
sockopt_impl!(
1086+
/// Enables a receiving socket to retrieve the Time-to-Live (TTL) field
1087+
/// from incoming IPv4 packets.
1088+
Ipv4RecvTtl,
1089+
Both,
1090+
libc::IPPROTO_IP,
1091+
libc::IP_RECVTTL,
1092+
bool
1093+
);
10611094
#[cfg(any(apple_targets, linux_android, target_os = "freebsd"))]
10621095
sockopt_impl!(
10631096
/// Set the unicast hop limit for the socket.
@@ -1069,6 +1102,17 @@ sockopt_impl!(
10691102
);
10701103
#[cfg(any(linux_android, target_os = "freebsd"))]
10711104
#[cfg(feature = "net")]
1105+
sockopt_impl!(
1106+
/// Enables a receiving socket to retrieve the Hop Limit field
1107+
/// (similar to TTL in IPv4) from incoming IPv6 packets.
1108+
Ipv6RecvHopLimit,
1109+
Both,
1110+
libc::IPPROTO_IPV6,
1111+
libc::IPV6_RECVHOPLIMIT,
1112+
bool
1113+
);
1114+
#[cfg(any(linux_android, target_os = "freebsd"))]
1115+
#[cfg(feature = "net")]
10721116
sockopt_impl!(
10731117
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
10741118
/// The `recvmsg(2)` call will return the destination IP address for a UDP

0 commit comments

Comments
 (0)