blob: 8360161aeb2436b84f2a05700235e93e85b9dbe4 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
pub use self::checksum::*;
pub use self::options::*;
/// Whether `size` fits in a `u16`.
pub fn fits_in_u16(size: usize) -> bool {
size < 1 << 16
}
/// Whether `size` fits in a `u32`.
pub fn fits_in_u32(size: usize) -> bool {
// trivially true when usize is 32 bits wide
cfg!(target_pointer_width = "32") || size < 1 << 32
}
mod checksum {
use byteorder::{ByteOrder, NetworkEndian};
// TODO(joshlf):
// - Speed this up by only doing the endianness swap at the end as described
// in RFC 1071 Section 2(B).
// - Explore SIMD optimizations
/// A checksum used by IPv4, TCP, and UDP.
///
/// This checksum operates by computing the 1s complement of the 1s
/// complement sum of successive 16-bit words of the input. It is specified
/// in [RFC 1071].
///
/// [RFC 1071]: https://tools.ietf.org/html/rfc1071
pub struct Checksum {
sum: u32,
// since odd-length inputs are treated specially, we store the trailing
// byte for use in future calls to add_bytes(), and only treat it as a
// true trailing byte in checksum()
trailing_byte: Option<u8>,
}
impl Checksum {
/// Initialize a new checksum.
pub fn new() -> Self {
Checksum {
sum: 0,
trailing_byte: None,
}
}
/// Add bytes to the checksum.
///
/// If `bytes` does not contain an even number of bytes, a single zero byte
/// will be added to the end before updating the checksum.
pub fn add_bytes(&mut self, mut bytes: &[u8]) {
// if there's a trailing byte, consume it first
if let Some(byte) = self.trailing_byte {
if !bytes.is_empty() {
Self::add_u16(&mut self.sum, NetworkEndian::read_u16(&[byte, bytes[0]]));
bytes = &bytes[1..];
self.trailing_byte = None;
}
}
// continue with the normal algorithm
while bytes.len() > 1 {
Self::add_u16(&mut self.sum, NetworkEndian::read_u16(bytes));
bytes = &bytes[2..];
}
if bytes.len() == 1 {
self.trailing_byte = Some(bytes[0]);
}
}
/// Update bytes in an existing checksum.
///
/// `update` updates a checksum to reflect that the already-checksummed
/// bytes `old` have been updated to contain the values in `new`. It
/// implements the algorithm described in Equation 3 in [RFC 1624]. The
/// first byte must be at an even number offset in the original input.
/// If an odd number offset byte needs to be updated, the caller should
/// simply include the preceding byte as well. If an odd number of bytes
/// is given, it is assumed that these are the last bytes of the input.
/// If an odd number of bytes in the middle of the input needs to be
/// updated, the next byte of the input should be added on the end to
/// make an even number of bytes.
///
/// # Panics
///
/// `update` panics if `old.len() != new.len()`.
///
/// [RFC 1624]: https://tools.ietf.org/html/rfc1624
pub fn update(checksum: u16, mut old: &[u8], mut new: &[u8]) -> u16 {
assert_eq!(old.len(), new.len());
// We compute on the sum, not the one's complement of the sum.
// checksum is the one's complement of the sum, so we need to get
// back to the sum. Thus, we negate checksum.
let mut sum = u32::from(!checksum);
while old.len() > 1 {
let old_u16 = NetworkEndian::read_u16(old);
let new_u16 = NetworkEndian::read_u16(new);
// RFC 1624 Eqn. 3
Self::add_u16(&mut sum, !old_u16);
Self::add_u16(&mut sum, new_u16);
old = &old[2..];
new = &new[2..];
}
if old.len() == 1 {
let old_u16 = NetworkEndian::read_u16(&[old[0], 0]);
let new_u16 = NetworkEndian::read_u16(&[new[0], 0]);
// RFC 1624 Eqn. 3
Self::add_u16(&mut sum, !old_u16);
Self::add_u16(&mut sum, new_u16);
}
!Self::normalize(sum)
}
/// Compute the checksum.
///
/// `checksum` returns the checksum of all data added using `add_bytes`
/// so far. Calling `checksum` does *not* reset the checksum. More bytes
/// may be added after calling `checksum`, and they will be added to the
/// checksum as expected.
///
/// If an odd number of bytes have been added so far, the checksum will
/// be computed as though a single 0 byte had been added at the end in
/// order to even out the length of the input.
pub fn checksum(&self) -> u16 {
let mut sum = self.sum;
if let Some(byte) = self.trailing_byte {
Self::add_u16(&mut sum, NetworkEndian::read_u16(&[byte, 0]));
}
!Self::normalize(sum)
}
// Normalize a 32-bit accumulator by mopping up the overflow until it
// fits in a u16.
fn normalize(mut sum: u32) -> u16 {
while (sum >> 16) != 0 {
sum = (sum >> 16) + (sum & 0xFFFF);
}
sum as u16
}
// Add a new u16 to a running sum, checking for overflow. If overflow
// is detected, normalize back to a 16-bit representation and perform
// the addition again.
fn add_u16(sum: &mut u32, u: u16) {
let new = if let Some(new) = sum.checked_add(u32::from(u)) {
new
} else {
let tmp = *sum;
*sum = u32::from(Self::normalize(tmp));
// sum is now in the range [0, 2^16), so this can't overflow
*sum + u32::from(u)
};
*sum = new;
}
}
#[cfg(test)]
mod tests {
use rand::Rng;
use super::*;
use crate::testutil::new_rng;
use crate::wire::testdata::IPV4_HEADERS;
#[test]
fn test_checksum() {
for buf in IPV4_HEADERS {
// compute the checksum as normal
let mut c = Checksum::new();
c.add_bytes(&buf);
assert_eq!(c.checksum(), 0);
// compute the checksum one byte at a time to make sure our
// trailing_byte logic works
let mut c = Checksum::new();
for byte in *buf {
c.add_bytes(&[*byte]);
}
assert_eq!(c.checksum(), 0);
// Make sure that it works even if we overflow u32. Performing this
// loop 2 * 2^16 times is guaranteed to cause such an overflow
// because 0xFFFF + 0xFFFF > 2^16, and we're effectively adding
// (0xFFFF + 0xFFFF) 2^16 times. We verify the overflow as well by
// making sure that, at least once, the sum gets smaller from one
// loop iteration to the next.
let mut c = Checksum::new();
c.add_bytes(&[0xFF, 0xFF]);
let mut prev_sum = c.sum;
let mut overflowed = false;
for _ in 0..((2 * (1 << 16)) - 1) {
c.add_bytes(&[0xFF, 0xFF]);
if c.sum < prev_sum {
overflowed = true;
}
prev_sum = c.sum;
}
assert!(overflowed);
assert_eq!(c.checksum(), 0);
}
}
#[test]
fn test_update() {
for b in IPV4_HEADERS {
let mut buf = Vec::new();
buf.extend_from_slice(b);
let mut c = Checksum::new();
c.add_bytes(&buf);
assert_eq!(c.checksum(), 0);
// replace the destination IP with the loopback address
let old = [buf[16], buf[17], buf[18], buf[19]];
(&mut buf[16..20]).copy_from_slice(&[127, 0, 0, 1]);
let updated = Checksum::update(c.checksum(), &old, &[127, 0, 0, 1]);
let from_scratch = {
let mut c = Checksum::new();
c.add_bytes(&buf);
c.checksum()
};
assert_eq!(updated, from_scratch);
}
}
#[test]
fn test_smoke_update() {
let mut rng = new_rng(70812476915813);
for _ in 0..2048 {
// use an odd length so we test the odd length logic
const BUF_LEN: usize = 31;
let buf: [u8; BUF_LEN] = rng.gen();
let mut c = Checksum::new();
c.add_bytes(&buf);
let (begin, end) = loop {
let begin = rng.gen::<usize>() % BUF_LEN;
let end = begin + (rng.gen::<usize>() % (BUF_LEN + 1 - begin));
// update requires that begin is even and end is either even
// or the end of the input
if begin % 2 == 0 && (end % 2 == 0 || end == BUF_LEN) {
break (begin, end);
}
};
let mut new_buf = buf;
for i in begin..end {
new_buf[i] = rng.gen();
}
let updated =
Checksum::update(c.checksum(), &buf[begin..end], &new_buf[begin..end]);
let from_scratch = {
let mut c = Checksum::new();
c.add_bytes(&new_buf);
c.checksum()
};
assert_eq!(updated, from_scratch);
}
}
}
}
mod options {
use std::marker::PhantomData;
use std::ops::Deref;
use zerocopy::ByteSlice;
/// A parsed set of header options.
///
/// `Options` represents a parsed set of options from a TCP or IPv4 header.
#[derive(Debug)]
pub struct Options<B, O> {
bytes: B,
_marker: PhantomData<O>,
}
/// An iterator over header options.
///
/// `OptionIter` is an iterator over packet header options stored in the
/// format used by IPv4 and TCP, where each option is either a single kind
/// byte or a kind byte, a length byte, and length - 2 data bytes.
///
/// In both IPv4 and TCP, the only single-byte options are End of Options
/// List (EOL) and No Operation (NOP), both of which can be handled
/// internally by OptionIter. Thus, the caller only needs to be able to
/// parse multi-byte options.
pub struct OptionIter<'a, O> {
bytes: &'a [u8],
idx: usize,
_marker: PhantomData<O>,
}
/// Errors returned from parsing options.
///
/// `OptionParseErr` is either `Internal`, which indicates that this module
/// encountered a malformed sequence of options (likely with a length field
/// larger than the remaining bytes in the options buffer), or `External`,
/// which indicates that the `OptionImpl::parse` callback returned an error.
#[derive(Debug, Eq, PartialEq)]
pub enum OptionParseErr<E> {
Internal,
External(E),
}
/// An implementation of an options parser which can return errors.
///
/// This is split from the `OptionImpl` trait so that the associated `Error`
/// type does not depend on the lifetime parameter to `OptionImpl`.
/// Lifetimes aside, `OptionImplError` is conceptually part of `OptionImpl`.
pub trait OptionImplErr {
type Error;
}
// End of Options List in both IPv4 and TCP
const END_OF_OPTIONS: u8 = 0;
// NOP in both IPv4 and TCP
const NOP: u8 = 1;
/// An implementation of an options parser.
///
/// `OptionImpl` provides functions to parse fixed- and variable-length
/// options. It is required in order to construct an `Options` or
/// `OptionIter`.
pub trait OptionImpl<'a>: OptionImplErr {
/// The value to multiply read lengths by.
///
/// By default, this value is 1, but some options (such as NDP) this
/// may be different.
const OPTION_LEN_MULTIPLIER: usize = 1;
/// The End of options type (if one exists).
const END_OF_OPTIONS: Option<u8> = Some(END_OF_OPTIONS);
/// The No-op type (if one exists).
const NOP: Option<u8> = Some(NOP);
/// The type of an option; the output from the `parse` function.
///
/// For long or variable-length data, the user is advised to make
/// `Output` a reference into the bytes passed to `parse`. This is
/// achievable because of the lifetime parameter to this trait.
type Output;
/// Parse an option.
///
/// `parse` takes a kind byte and variable-length data associated and
/// returns `Ok(Some(o))` if the option successfully parsed as `o`,
/// `Ok(None)` if the kind byte was unrecognized, and `Err(err)` if the
/// kind byte was recognized but `data` was malformed for that option
/// kind. `parse` is allowed to not recognize certain option kinds, as
/// the length field can still be used to safely skip over them.
///
/// `parse` must be deterministic, or else `Options::parse` cannot
/// guarantee that future iterations will not produce errors (and
/// panic).
fn parse(kind: u8, data: &'a [u8]) -> Result<Option<Self::Output>, Self::Error>;
}
impl<B, O> Options<B, O>
where
B: ByteSlice,
O: for<'a> OptionImpl<'a>,
{
/// Parse a set of options.
///
/// `parse` parses `bytes` as a sequence of options. `parse` performs a
/// single pass over all of the options to verify that they are
/// well-formed. Once `parse` returns successfully, the resulting
/// `Options` can be used to construct infallible iterators.
pub fn parse(bytes: B) -> Result<Options<B, O>, OptionParseErr<O::Error>> {
// First, do a single pass over the bytes to detect any errors up
// front. Once this is done, since we have a reference to `bytes`,
// these bytes can't change out from under us, and so we can treat
// any iterator over these bytes as infallible. This makes a few
// assumptions, but none of them are that big of a deal. In all
// cases, breaking these assumptions would just result in a runtime
// panic.
// - B could return different bytes each time
// - O::parse could be non-deterministic
let mut idx = 0;
while next::<O>(bytes.deref(), &mut idx)?.is_some() {}
Ok(Options {
bytes,
_marker: PhantomData,
})
}
}
impl<B: Deref<Target = [u8]>, O> Deref for Options<B, O> {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.bytes
}
}
impl<B: Deref<Target = [u8]>, O> Options<B, O> {
/// Get the underlying bytes.
///
/// `bytes` returns a reference to the byte slice backing this
/// `Options`.
pub fn bytes(&self) -> &[u8] {
&self.bytes
}
}
impl<'a, B, O> Options<B, O>
where
B: 'a + ByteSlice,
O: OptionImpl<'a>,
{
/// Create an iterator over options.
///
/// `iter` constructs an iterator over the options. Since the options
/// were validated in `parse`, then so long as `from_kind` and
/// `from_data` are deterministic, the iterator is infallible.
pub fn iter(&'a self) -> OptionIter<'a, O> {
OptionIter {
bytes: &self.bytes,
idx: 0,
_marker: PhantomData,
}
}
}
impl<'a, O> Iterator for OptionIter<'a, O>
where
O: OptionImpl<'a>,
{
type Item = O::Output;
fn next(&mut self) -> Option<O::Output> {
// use match rather than expect because expect requires that Err: Debug
#[cfg_attr(feature = "cargo-clippy", allow(match_wild_err_arm))]
match next::<O>(&self.bytes[..], &mut self.idx) {
Ok(o) => o,
Err(_) => panic!("already-validated options should not fail to parse"),
}
}
}
fn next<'a, O>(
bytes: &'a [u8], idx: &mut usize,
) -> Result<Option<O::Output>, OptionParseErr<O::Error>>
where
O: OptionImpl<'a>,
{
// For an explanation of this format, see the "Options" section of
// https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure
loop {
let bytes = &bytes[*idx..];
if bytes.is_empty() {
return Ok(None);
}
if Some(bytes[0]) == O::END_OF_OPTIONS {
return Ok(None);
}
if Some(bytes[0]) == O::NOP {
*idx += 1;
continue;
}
let len = bytes[1] as usize * O::OPTION_LEN_MULTIPLIER;
if len < 2 || len > bytes.len() {
return Err(OptionParseErr::Internal);
}
*idx += len;
match O::parse(bytes[0], &bytes[2..len]) {
Ok(Some(o)) => return Ok(Some(o)),
Ok(None) => {}
Err(err) => return Err(OptionParseErr::External(err)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug)]
struct DummyOptionImpl;
impl OptionImplErr for DummyOptionImpl {
type Error = ();
}
impl<'a> OptionImpl<'a> for DummyOptionImpl {
type Output = (u8, Vec<u8>);
fn parse(kind: u8, data: &'a [u8]) -> Result<Option<Self::Output>, Self::Error> {
let mut v = Vec::new();
v.extend_from_slice(data);
Ok(Some((kind, v)))
}
}
#[derive(Debug)]
struct AlwaysErrOptionImpl;
impl OptionImplErr for AlwaysErrOptionImpl {
type Error = ();
}
impl<'a> OptionImpl<'a> for AlwaysErrOptionImpl {
type Output = ();
fn parse(_kind: u8, _data: &'a [u8]) -> Result<Option<()>, ()> {
Err(())
}
}
#[derive(Debug)]
struct DummyNdpOptionImpl;
impl OptionImplErr for DummyNdpOptionImpl {
type Error = ();
}
impl<'a> OptionImpl<'a> for DummyNdpOptionImpl {
type Output = (u8, Vec<u8>);
const OPTION_LEN_MULTIPLIER: usize = 8;
const END_OF_OPTIONS: Option<u8> = None;
const NOP: Option<u8> = None;
fn parse(kind: u8, data: &'a [u8]) -> Result<Option<Self::Output>, Self::Error> {
let mut v = Vec::with_capacity(data.len());
v.extend_from_slice(data);
Ok(Some((kind, v)))
}
}
#[test]
fn test_empty_options() {
// all END_OF_OPTIONS
let bytes = [END_OF_OPTIONS; 64];
let options = Options::<_, DummyOptionImpl>::parse(&bytes[..]).unwrap();
assert_eq!(options.iter().count(), 0);
// all NOP
let bytes = [NOP; 64];
let options = Options::<_, DummyOptionImpl>::parse(&bytes[..]).unwrap();
assert_eq!(options.iter().count(), 0);
}
#[test]
fn test_parse() {
// Construct byte sequences in the pattern [3, 2], [4, 3, 2], [5, 4,
// 3, 2], etc. The second byte is the length byte, so these are all
// valid options (with data [], [2], [3, 2], etc).
let mut bytes = Vec::new();
for i in 4..16 {
// from the user's perspective, these NOPs should be transparent
bytes.push(NOP);
for j in (2..i).rev() {
bytes.push(j);
}
// from the user's perspective, these NOPs should be transparent
bytes.push(NOP);
}
let options = Options::<_, DummyOptionImpl>::parse(bytes.as_slice()).unwrap();
for (idx, (kind, data)) in options.iter().enumerate() {
assert_eq!(kind as usize, idx + 3);
assert_eq!(data.len(), idx);
let mut bytes = Vec::new();
for i in (2..(idx + 2)).rev() {
bytes.push(i as u8);
}
assert_eq!(data, bytes);
}
// Test that we get no parse errors so long as
// AlwaysErrOptionImpl::parse is never called.
let bytes = [NOP; 64];
let options = Options::<_, AlwaysErrOptionImpl>::parse(&bytes[..]).unwrap();
assert_eq!(options.iter().count(), 0);
}
#[test]
fn test_parse_ndp_options() {
let mut bytes = Vec::new();
for i in 0..16 {
bytes.push(i);
// NDP uses len*8 for the actual length.
bytes.push(i + 1);
// Write remaining 6 bytes.
for j in 2..((i + 1) * 8) {
bytes.push(j)
}
}
let options = Options::<_, DummyNdpOptionImpl>::parse(bytes.as_slice()).unwrap();
for (idx, (kind, data)) in options.iter().enumerate() {
assert_eq!(kind as usize, idx);
assert_eq!(data.len(), ((idx + 1) * 8) - 2);
let mut bytes = Vec::new();
for i in (2..((idx + 1) * 8)) {
bytes.push(i as u8);
}
assert_eq!(data, bytes);
}
}
#[test]
fn test_parse_err() {
// the length byte is too short
let bytes = [2, 1];
assert_eq!(
Options::<_, DummyOptionImpl>::parse(&bytes[..]).unwrap_err(),
OptionParseErr::Internal
);
// the length byte is 0 (similar check to above, but worth
// explicitly testing since this was a bug in the Linux kernel:
// https://bugzilla.redhat.com/show_bug.cgi?id=1622404)
let bytes = [2, 0];
assert_eq!(
Options::<_, DummyOptionImpl>::parse(&bytes[..]).unwrap_err(),
OptionParseErr::Internal
);
// the length byte is too long
let bytes = [2, 3];
assert_eq!(
Options::<_, DummyOptionImpl>::parse(&bytes[..]).unwrap_err(),
OptionParseErr::Internal
);
// the buffer is fine, but the implementation returns a parse error
let bytes = [2, 2];
assert_eq!(
Options::<_, AlwaysErrOptionImpl>::parse(&bytes[..]).unwrap_err(),
OptionParseErr::External(())
);
}
}
}