Skip to content

Instantly share code, notes, and snippets.

@dylnuge
Created December 1, 2022 04:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dylnuge/c41b76bacc8ce5338ebfad2b2fb48b39 to your computer and use it in GitHub Desktop.
Save dylnuge/c41b76bacc8ce5338ebfad2b2fb48b39 to your computer and use it in GitHub Desktop.
Ethernet Frame Header Deserialization, as written by OpenAI's chat
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Cursor, Read};
// This code was mostly authored by https://chat.openai.com/chat
// I asked the following questions to get the code:
// 1. "Do you know what an ethernet frame header is?"
// 2. "Excellent! Can you write me a data structure in Rust which represents an
// ethernet frame header?"
// 3. "This looks great! Can you write me a function in Rust that takes an
// arbitrary stream of bytes and deserializes it into your
// EthernetFrameHeader struct?"
// For the most part I copied the code provided as written, and made no
// adjustments. None of the code included imports, so I added those myself.
// The included coded also didn't include a println to test the struct results
// or a Debug derive on the struct, but the test cases themselves *are* from
// the AI.
// There are a couple issues with this code, but it's generally correct. The
// issues I see, from major to minor, are:
// 1. No CRC handling; the frame check is here included in the payload, which
// is incorrect.
// 2. No bounds check on the deserialize, so bad data will panic
// 3. No handling for VLAN tagging (802.1Q)
// 4. Technically it didn't ask if I wanted to deal with the data link or
// line data; the latter has a preamble and interpacket gap. But I didn't
// specify and data link layer would be the normal assumption here.
// 5. The compiler warnings on `let mut header` and the struct not having pub
// fields (or accessor methods) are, I think, not fair to dock points on.
// The former was example code and `let mut` was fine, and for the latter
// I asked about the data structure only.
// All in all I'm decently happy with this version of the code. I tried earlier
// on the same model and got different results:
// 1. The struct included FCS (good!) and padding (as a [u8; 12]...this is
// wrong on two levels—first, minimum transmission is 64 bytes, so there can
// be up to 46 bytes of padding, and second, the padding doesn't need to be
// stored).
// 2. The code had a bounds check, though the bounds check was len < 14, and
// the code read from bytes beyond that, because...
// 3. ...the code read bytes 15-18 as the FCS (wrong, these are after the
// payload) and everything after 18 as padding (very wrong, especially
// since it was stuffing it into a 12 byte array).
// 4. The code handled endianness differently; instead of using Cursor, it just
// directly pulled bytes, bitshifted them, and ORed them.
// 5. The deserialize returned a Result<EthernetFrameHeader, &'static str>, with
// the only error coming from the aforementioned bounds check.
#[derive(Debug)]
struct EthernetFrameHeader {
destination_mac: [u8; 6],
source_mac: [u8; 6],
ethertype: u16,
payload: Vec<u8>,
}
fn deserialize_ethernet_frame_header(data: &[u8]) -> EthernetFrameHeader {
let mut cursor = Cursor::new(data);
let mut destination_mac = [0; 6];
cursor.read_exact(&mut destination_mac).unwrap();
let mut source_mac = [0; 6];
cursor.read_exact(&mut source_mac).unwrap();
let ethertype = cursor.read_u16::<BigEndian>().unwrap();
let mut payload = Vec::new();
cursor.read_to_end(&mut payload).unwrap();
EthernetFrameHeader {
destination_mac,
source_mac,
ethertype,
payload,
}
}
fn main() {
let mut header = EthernetFrameHeader {
destination_mac: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
source_mac: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55],
ethertype: 0x0800,
payload: Vec::new(),
};
println!("header: {:?}", header);
let data = [
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // destination MAC
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // source MAC
0x08, 0x00, // ethertype
// payload
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
];
let header2 = deserialize_ethernet_frame_header(&data);
println!("header2: {:?}", header2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment