Skip to content

Commit a3abf9c

Browse files
committed
fix(tcpdump): partial checksum
In some cases, the checksum calculation is offloaded to hardware and only the partial checksum is calculated (only the pseudo-header). The tcpdump example was not taking this into account and was flagging some packets with incorrect checksums.
1 parent d2d6470 commit a3abf9c

File tree

4 files changed

+55
-5
lines changed

4 files changed

+55
-5
lines changed

src/wire/ip.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -779,9 +779,17 @@ pub mod checksum {
779779
}
780780

781781
// We use this in pretty printer implementations.
782-
pub(crate) fn format_checksum(f: &mut fmt::Formatter, correct: bool) -> fmt::Result {
782+
pub(crate) fn format_checksum(
783+
f: &mut fmt::Formatter,
784+
correct: bool,
785+
partially_correct: bool,
786+
) -> fmt::Result {
783787
if !correct {
784-
write!(f, " (checksum incorrect)")
788+
if partially_correct {
789+
write!(f, " (partial checksum incorrect)")
790+
} else {
791+
write!(f, " (checksum incorrect)")
792+
}
785793
} else {
786794
Ok(())
787795
}
@@ -833,7 +841,10 @@ pub fn pretty_print_ip_payload<T: Into<Repr>>(
833841
)?;
834842
let valid =
835843
udp_packet.verify_checksum(&repr.src_addr(), &repr.dst_addr());
836-
format_checksum(f, valid)
844+
let partially_valid = udp_packet
845+
.verify_partial_checksum(&repr.src_addr(), &repr.dst_addr());
846+
847+
format_checksum(f, valid, partially_valid)
837848
}
838849
}
839850
}
@@ -855,7 +866,10 @@ pub fn pretty_print_ip_payload<T: Into<Repr>>(
855866
write!(f, "{indent}{tcp_repr}")?;
856867
let valid =
857868
tcp_packet.verify_checksum(&repr.src_addr(), &repr.dst_addr());
858-
format_checksum(f, valid)
869+
let partially_valid = tcp_packet
870+
.verify_partial_checksum(&repr.src_addr(), &repr.dst_addr());
871+
872+
format_checksum(f, valid, partially_valid)
859873
}
860874
}
861875
}

src/wire/ipv4.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
705705
return Ok(());
706706
} else {
707707
write!(f, "{indent}{ip_repr}")?;
708-
format_checksum(f, ip_packet.verify_checksum())?;
708+
format_checksum(f, ip_packet.verify_checksum(), false)?;
709709
(ip_repr, ip_packet.payload())
710710
}
711711
}

src/wire/tcp.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,25 @@ impl<T: AsRef<[u8]>> Packet<T> {
351351
Ok([None, None, None])
352352
}
353353

354+
/// Validate the partial checksum.
355+
///
356+
/// # Panics
357+
/// This function panics unless `src_addr` and `dst_addr` belong to the same family,
358+
/// and that family is IPv4 or IPv6.
359+
///
360+
/// # Fuzzing
361+
/// This function always returns `true` when fuzzing.
362+
pub fn verify_partial_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
363+
if cfg!(fuzzing) {
364+
return true;
365+
}
366+
367+
let data = self.buffer.as_ref();
368+
369+
checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Tcp, data.len() as u32)
370+
== self.checksum()
371+
}
372+
354373
/// Validate the packet checksum.
355374
///
356375
/// # Panics

src/wire/udp.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,23 @@ impl<T: AsRef<[u8]>> Packet<T> {
101101
NetworkEndian::read_u16(&data[field::CHECKSUM])
102102
}
103103

104+
/// Validate the partial packet checksum.
105+
///
106+
/// # Panics
107+
/// This function panics unless `src_addr` and `dst_addr` belong to the same family,
108+
/// and that family is IPv4 or IPv6.
109+
///
110+
/// # Fuzzing
111+
/// This function always returns `true` when fuzzing.
112+
pub fn verify_partial_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
113+
if cfg!(fuzzing) {
114+
return true;
115+
}
116+
117+
checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Udp, self.len() as u32)
118+
== self.checksum()
119+
}
120+
104121
/// Validate the packet checksum.
105122
///
106123
/// # Panics

0 commit comments

Comments
 (0)