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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use super::*;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PacketHeaders<'a> {
pub link: Option<Ethernet2Header>,
pub vlan: Option<VlanHeader>,
pub ip: Option<IpHeader>,
pub transport: Option<TransportHeader>,
pub payload: &'a [u8]
}
impl<'a> PacketHeaders<'a> {
pub fn from_ethernet_slice<'b>(packet: &'b [u8]) -> Result<PacketHeaders<'b>, ReadError> {
use std::io::Cursor;
let mut cursor = Cursor::new(&packet);
let ethernet = Ethernet2Header::read(&mut cursor)?;
let mut ether_type = ethernet.ether_type;
let mut result = PacketHeaders{
link: Some(ethernet),
vlan: None,
ip: None,
transport: None,
payload: &[]
};
use EtherType::*;
const VLAN_TAGGED_FRAME: u16 = VlanTaggedFrame as u16;
const PROVIDER_BRIDGING: u16 = ProviderBridging as u16;
const VLAN_DOUBLE_TAGGED_FRAME: u16 = VlanDoubleTaggedFrame as u16;
result.vlan = match ether_type {
VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => {
use VlanHeader::*;
let outer = SingleVlanHeader::read(&mut cursor)?;
ether_type = outer.ether_type;
match ether_type {
VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => {
let inner = SingleVlanHeader::read(&mut cursor)?;
ether_type = inner.ether_type;
Some(Double(DoubleVlanHeader{
outer: outer,
inner: inner
}))
},
_ => Some(Single(outer))
}
},
_ => None
};
const IPV4: u16 = Ipv4 as u16;
const IPV6: u16 = Ipv6 as u16;
let read_transport = |protocol: u8, cursor: &mut Cursor<&&[u8]>| -> Result<Option<TransportHeader>, ReadError> {
use IpTrafficClass::*;
const UDP: u8 = Udp as u8;
match protocol {
UDP => Ok(Some(TransportHeader::Udp(UdpHeader::read(cursor)?))),
_ => Ok(None)
}
};
match ether_type {
IPV4 => {
let ip = Ipv4Header::read(&mut cursor)?;
ip.skip_options(&mut cursor)?;
result.transport = read_transport(ip.protocol, &mut cursor)?;
result.ip = Some(IpHeader::Version4(ip));
},
IPV6 => {
let ip = Ipv6Header::read(&mut cursor)?;
let next_header = Ipv6Header::skip_all_header_extensions(&mut cursor, ip.next_header)?;
result.transport = read_transport(next_header, &mut cursor)?;
result.ip = Some(IpHeader::Version6(ip));
},
_ => {}
}
result.payload = &packet[(cursor.position() as usize)..];
Ok(result)
}
}