net_parser_rs/layer2/
ethernet.rs

1use crate::Error;
2use crate::common::{MacAddress, Vlan, MAC_LENGTH};
3
4use arrayref::array_ref;
5use byteorder::{BigEndian as BE, WriteBytesExt};
6use log::*;
7use nom::*;
8use std::mem::size_of;
9use std::io::{Cursor, Write};
10
11const ETHERNET_PAYLOAD: u16 = 1500u16;
12
13///
14/// List of valid ethernet types that aren't payload or vlan. https://en.wikipedia.org/wiki/EtherType
15///
16#[derive(Clone, Copy, Debug, PartialEq)]
17pub enum Layer3Id {
18    Lldp,
19    IPv4,
20    IPv6,
21    Arp,
22}
23
24impl Layer3Id {
25    pub fn value(&self) -> u16 {
26        match self {
27            Layer3Id::Lldp => 0x88ccu16,
28            Layer3Id::IPv4 => 0x0800u16,
29            Layer3Id::IPv6 => 0x86ddu16,
30            Layer3Id::Arp => 0x0806u16,
31        }
32    }
33}
34
35#[derive(Clone, Copy, Debug, PartialEq)]
36pub enum VlanTypeId {
37    VlanTagId,
38    ProviderBridging,
39}
40
41impl VlanTypeId {
42    pub fn value(&self) -> u16 {
43        match self {
44            VlanTypeId::VlanTagId => 0x8100u16,
45            VlanTypeId::ProviderBridging => 0x88a8u16
46        }
47    }
48}
49
50#[derive(Clone, Copy, Debug, PartialEq)]
51pub enum EthernetTypeId {
52    PayloadLength(u16),
53    Vlan(VlanTypeId),
54    L3(Layer3Id),
55}
56
57impl EthernetTypeId {
58    fn new(vlan: u16) -> Option<EthernetTypeId> {
59        match vlan {
60            0x8100u16 => Some(EthernetTypeId::Vlan(VlanTypeId::VlanTagId)),
61            0x88a8u16 => Some(EthernetTypeId::Vlan(VlanTypeId::ProviderBridging)),
62            0x88ccu16 => Some(EthernetTypeId::L3(Layer3Id::Lldp)),
63            0x0800u16 => Some(EthernetTypeId::L3(Layer3Id::IPv4)),
64            0x86ddu16 => Some(EthernetTypeId::L3(Layer3Id::IPv6)),
65            0x0806u16 => Some(EthernetTypeId::L3(Layer3Id::Arp)),
66            x if x <= ETHERNET_PAYLOAD => Some(EthernetTypeId::PayloadLength(x)),
67            _ => {
68                //TODO: change to warn once list is more complete
69                debug!("Encountered {:02x} when parsing Ethernet type", vlan);
70                None
71            }
72        }
73    }
74
75    fn value(&self) -> u16 {
76        match self {
77            EthernetTypeId::PayloadLength(v) => *v,
78            EthernetTypeId::Vlan(v) => v.value(),
79            EthernetTypeId::L3(v) => v.value(),
80        }
81    }
82}
83
84#[allow(unused)]
85#[derive(Clone, Copy, Debug)]
86pub struct VlanTag {
87    pub vlan_type: VlanTypeId,
88    pub vlan_value: u16,
89    pub prio: u8,
90    pub dei: u8,
91    pub id: u16,
92}
93
94impl VlanTag {
95    pub fn vlan(&self) -> u16 {
96        self.id
97    }
98}
99
100#[derive(Clone, Debug)]
101pub struct Ethernet<'a> {
102    pub dst_mac: MacAddress,
103    pub src_mac: MacAddress,
104    pub ether_type: EthernetTypeId,
105    pub vlans: std::vec::Vec<VlanTag>,
106    pub payload: &'a [u8],
107}
108
109fn to_mac_address(i: &[u8]) -> MacAddress {
110    MacAddress(array_ref![i, 0, MAC_LENGTH].clone())
111}
112
113named!(mac_address<&[u8], MacAddress>, map!(take!(MAC_LENGTH), to_mac_address));
114
115impl<'a> Ethernet<'a> {
116    pub fn as_bytes(&self) -> Vec<u8> {
117        let vlans_size = self.vlans.len() * (size_of::<u16>() * 2);
118        let inner = Vec::with_capacity(
119            MAC_LENGTH * 2
120                + size_of::<u16>()
121                + vlans_size
122        );
123        let mut writer = Cursor::new(inner);
124        writer.write(&self.dst_mac.0).unwrap();
125        writer.write(&self.src_mac.0).unwrap();
126        for vlan in &self.vlans {
127            writer.write_u16::<BE>(vlan.vlan_type.value()).unwrap();
128            writer.write_u16::<BE>(vlan.vlan_value).unwrap();
129        }
130        writer.write_u16::<BE>(self.ether_type.value()).unwrap();
131        writer.write(self.payload).unwrap();
132        writer.into_inner()
133    }
134    pub fn vlans_to_vlan(vlans: &std::vec::Vec<VlanTag>) -> Vlan {
135        let opt_vlan = vlans.first().map(|v| v.vlan());
136        opt_vlan.unwrap_or(0)
137    }
138
139    pub fn vlan(&self) -> Vlan {
140        Ethernet::vlans_to_vlan(&self.vlans)
141    }
142
143    fn parse_not_vlan_tag<'b>(
144        input: &'b [u8],
145        dst_mac: MacAddress,
146        src_mac: MacAddress,
147        ether_type: EthernetTypeId,
148        agg: std::vec::Vec<VlanTag>,
149    ) -> nom::IResult<&'b [u8], Ethernet<'b>> {
150        do_parse!(
151            input,
152            payload: rest
153                >> (Ethernet {
154                    dst_mac: dst_mac,
155                    src_mac: src_mac,
156                    ether_type: ether_type,
157                    vlans: agg,
158                    payload: payload.into()
159                })
160        )
161    }
162
163    fn parse_vlan_tag<'b>(
164        input: &'b [u8],
165        dst_mac: MacAddress,
166        src_mac: MacAddress,
167        agg: std::vec::Vec<VlanTag>,
168    ) -> nom::IResult<&'b [u8], Ethernet<'b>> {
169        let (input, vlan) =
170            do_parse!(input, vlan: map_opt!(be_u16, EthernetTypeId::new) >> (vlan))?;
171
172        if let EthernetTypeId::Vlan(vlan_type_id) = vlan {
173            let (input, (value, prio, dei, id)) = do_parse!(
174                input,
175                total: be_u16
176                    >> ((
177                        total,
178                        (total & 0x7000) as u8,
179                        (total & 0x8000) as u8,
180                        total & 0x0FFF
181                    ))
182            )?;
183
184            let tag = VlanTag {
185                vlan_type: vlan_type_id,
186                vlan_value: value,
187                prio: prio,
188                dei: dei,
189                id: id,
190            };
191
192            debug!("Encountered vlan {:012b}", tag.vlan());
193
194            let mut agg = agg;
195            agg.push(tag);
196
197            Ethernet::parse_vlan_tag(input, dst_mac, src_mac, agg)
198        } else {
199            debug!("Encountered non vlan {:?}", vlan);
200            Ethernet::parse_not_vlan_tag(input, dst_mac, src_mac, vlan, agg)
201        }
202    }
203
204    pub fn parse<'b>(input: &'b [u8]) -> Result<(&'b [u8], Ethernet), Error> {
205        trace!("Available={}", input.len());
206
207        let r = do_parse!(
208            input,
209            dst_mac: mac_address >> src_mac: mac_address >> ((dst_mac, src_mac))
210        );
211
212        r.and_then(|res| {
213            let (rem, (dst_mac, src_mac)) = res;
214            Ethernet::parse_vlan_tag(rem, dst_mac, src_mac, vec![])
215        }).map_err(Error::from)
216    }
217}
218
219#[cfg(test)]
220pub mod tests {
221    use super::*;
222
223    pub const PAYLOAD_RAW_DATA: &'static [u8] = &[
224        0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, //dst mac 01:02:03:04:05:06
225        0xFFu8, 0xFEu8, 0xFDu8, 0xFCu8, 0xFBu8, 0xFAu8, //src mac FF:FE:FD:FC:FB:FA
226        0x00u8, 0x04u8, //payload ethernet
227        //payload
228        0x01u8, 0x02u8, 0x03u8, 0x04u8,
229    ];
230
231    pub const TCP_RAW_DATA: &'static [u8] = &[
232        0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, //dst mac 01:02:03:04:05:06
233        0xFFu8, 0xFEu8, 0xFDu8, 0xFCu8, 0xFBu8, 0xFAu8, //src mac FF:FE:FD:FC:FB:FA
234        0x08u8, 0x00u8, //ipv4
235        //ipv4
236        0x45u8, //version and header length
237        0x00u8, //tos
238        0x00u8, 0x48u8, //length, 20 bytes for header, 52 bytes for ethernet
239        0x00u8, 0x00u8, //id
240        0x00u8, 0x00u8, //flags
241        0x64u8, //ttl
242        0x06u8, //protocol, tcp
243        0x00u8, 0x00u8, //checksum
244        0x01u8, 0x02u8, 0x03u8, 0x04u8, //src ip 1.2.3.4
245        0x0Au8, 0x0Bu8, 0x0Cu8, 0x0Du8, //dst ip 10.11.12.13
246        //tcp
247        0xC6u8, 0xB7u8, //src port, 50871
248        0x00u8, 0x50u8, //dst port, 80
249        0x00u8, 0x00u8, 0x00u8, 0x01u8, //sequence number, 1
250        0x00u8, 0x00u8, 0x00u8, 0x02u8, //acknowledgement number, 2
251        0x50u8, 0x00u8, //header and flags, 0
252        0x00u8, 0x00u8, //window
253        0x00u8, 0x00u8, //check
254        0x00u8, 0x00u8, //urgent
255        //no options
256        //payload
257        0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
258        0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
259        0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8, 0xfeu8,
260        0xffu8, //payload, 8 words
261    ];
262
263    #[test]
264    fn parse_ethernet_payload() {
265        let _ = env_logger::try_init();
266
267        let (rem, l2) = Ethernet::parse(PAYLOAD_RAW_DATA).expect("Could not parse");
268
269        assert!(rem.is_empty());
270        assert_eq!(
271            l2.dst_mac.0,
272            [0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8]
273        );
274        assert_eq!(
275            l2.src_mac.0,
276            [0xFFu8, 0xFEu8, 0xFDu8, 0xFCu8, 0xFBu8, 0xFAu8]
277        );
278        assert!(l2.vlans.is_empty());
279
280        let proto_correct = if let EthernetTypeId::PayloadLength(_) = l2.ether_type {
281            true
282        } else {
283            false
284        };
285
286        assert!(proto_correct);
287        assert_eq!(l2.as_bytes().as_slice(), PAYLOAD_RAW_DATA);
288    }
289
290    #[test]
291    fn parse_ethernet_tcp() {
292        let _ = env_logger::try_init();
293
294        let (rem, l2) = Ethernet::parse(TCP_RAW_DATA).expect("Could not parse");
295
296        assert!(rem.is_empty());
297        assert_eq!(
298            l2.dst_mac.0,
299            [0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8]
300        );
301        assert_eq!(
302            l2.src_mac.0,
303            [0xFFu8, 0xFEu8, 0xFDu8, 0xFCu8, 0xFBu8, 0xFAu8]
304        );
305        assert!(l2.vlans.is_empty());
306
307        let proto_correct = if let EthernetTypeId::L3(Layer3Id::IPv4) = l2.ether_type {
308            true
309        } else {
310            false
311        };
312
313        assert!(proto_correct);
314        assert_eq!(l2.as_bytes().as_slice(), TCP_RAW_DATA);
315    }
316
317    #[test]
318    fn test_single_vlan() {
319        //TODO
320    }
321
322    #[test]
323    fn test_multiple_vlans() {
324        //TODO
325    }
326}