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#[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 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, 0xFFu8, 0xFEu8, 0xFDu8, 0xFCu8, 0xFBu8, 0xFAu8, 0x00u8, 0x04u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8,
229 ];
230
231 pub const TCP_RAW_DATA: &'static [u8] = &[
232 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0xFFu8, 0xFEu8, 0xFDu8, 0xFCu8, 0xFBu8, 0xFAu8, 0x08u8, 0x00u8, 0x45u8, 0x00u8, 0x00u8, 0x48u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x64u8, 0x06u8, 0x00u8, 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x0Au8, 0x0Bu8, 0x0Cu8, 0x0Du8, 0xC6u8, 0xB7u8, 0x00u8, 0x50u8, 0x00u8, 0x00u8, 0x00u8, 0x01u8, 0x00u8, 0x00u8, 0x00u8, 0x02u8, 0x50u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 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, ];
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 }
321
322 #[test]
323 fn test_multiple_vlans() {
324 }
326}