Skip to content

Instantly share code, notes, and snippets.

@saschagrunert
Created October 12, 2016 07:43
Show Gist options
  • Save saschagrunert/58165670e9c061d555f71a0f7178457e to your computer and use it in GitHub Desktop.
Save saschagrunert/58165670e9c061d555f71a0f7178457e to your computer and use it in GitHub Desktop.
#[macro_use]
extern crate nom;
#[derive(Debug, PartialEq)]
pub struct MacAddress<'a>(&'a u8, &'a u8, &'a u8, &'a u8, &'a u8, &'a u8);
#[derive(Debug, PartialEq)]
pub enum EtherType {
IPv4,
ARP,
VLAN,
IPv6,
}
impl EtherType {
fn from_u16(input: u16) -> Option<EtherType> {
match input {
0x0800 => Some(EtherType::IPv4),
0x0806 => Some(EtherType::ARP),
0x8100 => Some(EtherType::VLAN),
0x86DD => Some(EtherType::IPv6),
_ => None,
}
}
}
#[derive(Debug, PartialEq)]
pub struct Ethernet<'a> {
pub dst: MacAddress<'a>,
pub src: MacAddress<'a>,
pub ethertype: EtherType,
}
impl<'a> Ethernet<'a> {
named!(new<&[u8], Ethernet>,
chain!(
d: take!(6) ~
s: take!(6) ~
e: map_opt!(u16!(true), EtherType::from_u16),
|| Ethernet {
dst: MacAddress(&d[0], &d[1], &d[2], &d[3], &d[4], &d[5]),
src: MacAddress(&s[0], &s[1], &s[2], &s[3], &s[4], &s[5]),
ethertype: e
}
));
}
#[cfg(test)]
mod tests {
use super::*;
use nom::IResult;
#[test]
fn ethernet_frame() {
let b = [0x00, 0x23, 0x54, 0x07, 0x93, 0x6c, 0x00, 0x1b, 0x21, 0x0f, 0x91, 0x9b, 0x08, 0x00, 0x01, 0x02, 0x03];
let parsed = Ethernet::new(&b);
let expect = Ethernet {
dst: MacAddress(&b[0], &b[1], &b[2], &b[3], &b[4], &b[5]),
src: MacAddress(&b[6], &b[7], &b[8], &b[9], &b[10], &b[11]),
ethertype: EtherType::IPv4,
};
assert_eq!(parsed, IResult::Done(&[1, 2, 3][0..3], expect));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment