SIDN

rust workshop

How did we get here?

RustNL

Our rust projects

Our rust projects

Program

  • we have ~2 hours
  • first, some slides
  • then, hands-on workshop

Useful tools

Today: PCAP parsing

Today: PCAP parsing

#[derive(Debug)]
struct SectionHeaderBlock {
    major_version: u16,
    minor_version: u16,
    options: &[u8]
}

impl SectionHeaderBlock {
    fn parse(data: &[u8]) -> Self {
        todo!()
    }
}

For now, just panic

fn parse(data: &[u8]) -> Self {
  let preamble = 4 + 4 + 4 + 2 + 2 + 8;
  if data.len() < preamble {
      panic!("invalid size")
  }
  
  todo!()
}

from bytes to values

// fn from_le_bytes(bytes: [u8; 4]) -> u32;

let byte_order_magic = 
    u32::from_le_bytes(
        data[8..][..4].try_into().unwrap()
    );


endianness

enum Endianness { Le, Be }


let endianness = match byte_order_magic {
    0x1a2b3c4d => Endianness::Le,
    0x4d3c2b1a => Endianness::Be,
    _ => panic!("invalid byte order magic"),
};

let bytes = data[4..][..4].try_into().unwrap();
let block_length = match endianness {
    Endianness::Le => u32::from_le_bytes(bytes),
    Endianness::Be => u32::from_be_bytes(bytes),
};

slices and lifetimes

// pub fn get<I>(slice: &[T], index: I) 
//     -> Option<&<I as SliceIndex<[T]>>::Output>
// where
//     I: SliceIndex<[T]>,


let end = block_length as usize - preamble - 4;
let options = data.get(preamble..end).unwrap();

slices and lifetimes

impl<'a> SectionHeaderBlock<'a> {
    fn parse(data: &'a [u8]) -> Self {
        // ...

        Self {
            major_version,
            minor_version,
            options,
        }
    }
}

tests

#[cfg(test)]
mod tests {
    use super::*;

    const DATA: &[u8] = &[ /* bytes */ ];

    #[test]
    fn it_works() {
        let block = SectionHeaderBlock::parse(DATA);

        assert_eq!(
            Ok(""), 
            std::str::from_utf8(block.options),
        );
    }
}

run a test

> cargo test
Running unittests src/main.rs (target/debug/deps/pcap_parser-d6f024d854d6a202)

running 1 test
test tests::it_works ... FAILED

failures:

---- tests::it_works stdout ----
thread 'tests::it_works' panicked at 'assertion failed: `(left == right)`
  left: `Ok("")`,
 right: `Ok("\u{3}\0-\0Mac OS X 10.10.4, build 14E46 (Darwin 14.4.0)\0\0\0\u{4}\04\0Dumpcap 1.12.6 (v1.12.6-0-gee1fc")`', src/main.rs:69:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

error handling: Option

enum Option<T> {
    Some(T),
    None,
}

impl<'a> SectionHeaderBlock<'a> {
    fn parse(data: &'a [u8]) -> Option<Self> {
        let preamble = 4 + 4 + 4 + 2 + 2 + 8;
        if data.len() < preamble {
            return None;
        }

        // ...

        Some(Self {
            major_version: 0,
            minor_version: 0,
            options,
        })
    }
}

error handling: Result

enum Result<T, E> {
    Ok(T),
    Err(E),
}

enum ParseError {
    TooShort,
    InvalidByteOrder,
}

impl<'a> SectionHeaderBlock<'a> {
    fn parse(data: &'a [u8]) -> Result<Self, ParseError> {
        let preamble = 4 + 4 + 4 + 2 + 2 + 8;
        if data.len() < preamble {
            return Err(ParseError::TooShort);
        }

        // ...

Exercises

SIDN workshop

By folkert de vries

SIDN workshop

  • 49