Skip to content

Commit

Permalink
fix(tcpdump): partial checksum
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
thvdveld committed Nov 28, 2024
1 parent d2d6470 commit 8ec1376
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/wire/ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,10 @@ pub fn pretty_print_ip_payload<T: Into<Repr>>(
)?;
let valid =
udp_packet.verify_checksum(&repr.src_addr(), &repr.dst_addr());
format_checksum(f, valid)
let partially_valid = udp_packet
.verify_partial_checksum(&repr.src_addr(), &repr.dst_addr());

format_checksum(f, valid || partially_valid)
}
}
}
Expand All @@ -855,7 +858,10 @@ pub fn pretty_print_ip_payload<T: Into<Repr>>(
write!(f, "{indent}{tcp_repr}")?;
let valid =
tcp_packet.verify_checksum(&repr.src_addr(), &repr.dst_addr());
format_checksum(f, valid)
let partially_valid = tcp_packet
.verify_partial_checksum(&repr.src_addr(), &repr.dst_addr());

format_checksum(f, valid || partially_valid)
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions src/wire/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,25 @@ impl<T: AsRef<[u8]>> Packet<T> {
Ok([None, None, None])
}

/// Validate the partial checksum.
///
/// # Panics
/// This function panics unless `src_addr` and `dst_addr` belong to the same family,
/// and that family is IPv4 or IPv6.
///
/// # Fuzzing
/// This function always returns `true` when fuzzing.
pub fn verify_partial_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
if cfg!(fuzzing) {
return true;
}

let data = self.buffer.as_ref();

checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Tcp, data.len() as u32)
== self.checksum()
}

/// Validate the packet checksum.
///
/// # Panics
Expand Down
17 changes: 17 additions & 0 deletions src/wire/udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,23 @@ impl<T: AsRef<[u8]>> Packet<T> {
NetworkEndian::read_u16(&data[field::CHECKSUM])
}

/// Validate the partial packet checksum.
///
/// # Panics
/// This function panics unless `src_addr` and `dst_addr` belong to the same family,
/// and that family is IPv4 or IPv6.
///
/// # Fuzzing
/// This function always returns `true` when fuzzing.
pub fn verify_partial_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
if cfg!(fuzzing) {
return true;
}

checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Udp, self.len() as u32)
== self.checksum()
}

/// Validate the packet checksum.
///
/// # Panics
Expand Down

0 comments on commit 8ec1376

Please sign in to comment.