1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use nom::{rest,be_u16};

use {ParseOps,ConvError};
use packet_writer::{PacketWriter,WriteFields};

named!(bytes_to_ethernet<&[u8], EthHdr>, do_parse!(
    src: take!(6) >>
    dest: take!(6) >>
    eth_type: be_u16 >>
    (EthHdr { mac_src: src, mac_dest: dest, eth_type: EthType::from(eth_type) })
));
named!(strip_ethernet<&[u8]>, do_parse!(
    take!(14) >>
    inner_bytes: rest >>
    (inner_bytes)
));

c_enum!(EthType, u16, {
    IPv4 => 0x0800
});

#[derive(Debug,PartialEq)]
pub struct EthHdr<'a> {
    mac_src: &'a [u8],
    mac_dest: &'a [u8],
    eth_type: EthType,
}

impl<'a> ParseOps<'a> for EthHdr<'a> {
    fn to_bytes(self) -> Result<Vec<u8>, ConvError> {
        let mut pw = PacketWriter::new();
        pw.write_bytes(self.mac_src)?;
        pw.write_bytes(self.mac_dest)?;
        <PacketWriter as WriteFields<Vec<u8>>>::write_u16::<u16>(
            &mut pw, self.eth_type as u16
        )?;
        Ok(pw.get_result())
    }

    fn from_bytes(buf: &'a [u8]) -> Result<Self, ConvError> {
        match bytes_to_ethernet(buf) {
            Ok((_, ip)) => Ok(ip),
            Err(e) => {
                Err(ConvError(
                    format!("Failed to parse - here is the remaining output: {:?}", e)
                ))
            },
        }
    }

    fn strip_header(buf: &[u8]) -> Result<&[u8], ConvError> {
        match strip_ethernet(buf) {
            Ok((_, eth)) => Ok(eth),
            Err(e) => {
                Err(ConvError(
                    format!("Failed to parse - here is the remaining output: {:?}", e)
                ))
            },
        }
    }
}

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

    #[test]
    fn test_write_header() {
        assert_eq!(EthHdr { mac_src: &[1, 2, 3, 4, 5, 6],
                            mac_dest: &[7, 8, 9, 10, 11, 12],
                            eth_type: EthType::IPv4,
        }.to_bytes().unwrap(), &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0x08, 0x00])
    }

    #[test]
    fn test_parse_header() {
        let s = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0x08, 0x00, 15, 16, 17];
        assert_eq!(EthHdr { mac_src: &[1, 2, 3, 4, 5, 6],
                            mac_dest: &[7, 8, 9, 10, 11, 12],
                            eth_type: EthType::IPv4 },
                   EthHdr::from_bytes(s).unwrap())
    }

    #[test]
    fn test_strip_header() {
        let s = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
        assert_eq!(EthHdr::strip_header(s).unwrap(), &[15, 16, 17])
    }
}