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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::ip::{self, IPProtocol};
use nom::bits;
use nom::bytes;
use nom::error::Error;
use nom::number;
use nom::IResult;
use std::convert::TryFrom;
use std::net::Ipv6Addr;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IPv6Header {
pub version: u8,
pub ds: u8,
pub ecn: u8,
pub flow_label: u32,
pub length: u16,
pub next_header: IPProtocol,
pub hop_limit: u8,
pub source_addr: Ipv6Addr,
pub dest_addr: Ipv6Addr,
}
pub(crate) fn address(input: &[u8]) -> IResult<&[u8], Ipv6Addr> {
let (input, ipv6) = bytes::streaming::take(16u8)(input)?;
Ok((input, Ipv6Addr::from(<[u8; 16]>::try_from(ipv6).unwrap())))
}
pub fn parse_ipv6_header(input: &[u8]) -> IResult<&[u8], IPv6Header> {
let (input, ver_tc) = ip::two_nibbles(input)?;
let (input, tc_fl) = ip::two_nibbles(input)?;
let (input, fl): (_, u32) =
bits::bits::<_, _, Error<_>, _, _>(bits::streaming::take(16u8))(input)?;
let (input, length) = number::streaming::be_u16(input)?;
let (input, next_header) = ip::protocol(input)?;
let (input, hop_limit) = number::streaming::be_u8(input)?;
let (input, source_addr) = address(input)?;
let (input, dest_addr) = address(input)?;
Ok((
input,
IPv6Header {
version: ver_tc.0,
ds: (ver_tc.1 << 2) + ((tc_fl.0 & 0b1100) >> 2),
ecn: tc_fl.0 & 0b11,
flow_label: (u32::from(tc_fl.1) << 16) + fl,
length,
next_header,
hop_limit,
source_addr,
dest_addr,
},
))
}
#[cfg(test)]
mod tests {
use super::{ip::protocol, parse_ipv6_header, IPProtocol, IPv6Header};
use std::net::Ipv6Addr;
const EMPTY_SLICE: &'static [u8] = &[];
macro_rules! mk_protocol_test {
($func_name:ident, $bytes:expr, $correct_proto:expr) => {
#[test]
fn $func_name() {
let bytes = $bytes;
assert_eq!(protocol(&bytes), Ok((EMPTY_SLICE, $correct_proto)));
}
};
}
mk_protocol_test!(protocol_gets_icmp_correct, [1], IPProtocol::ICMP);
mk_protocol_test!(protocol_gets_tcp_correct, [6], IPProtocol::TCP);
mk_protocol_test!(protocol_gets_udp_correct, [17], IPProtocol::UDP);
#[test]
fn ipparse_gets_packet_correct() {
let bytes = [
0x60,
0x20,
0x01, 0xff,
0x05, 0x78,
0x3a,
0x05,
0x20, 0x01, 0x0d, 0xb8, 0x5c, 0xf8, 0x1a, 0xa8, 0x24, 0x81, 0x61, 0xe6, 0x5a, 0xc6,
0x03, 0xe0,
0x20, 0x01, 0x0d, 0xb8, 0x78, 0x90, 0x2a, 0xe9, 0x90, 0x8f, 0xa9, 0xf4, 0x2f, 0x4a,
0x9b, 0x80,
];
let expectation = IPv6Header {
version: 6,
ds: 0,
ecn: 2,
flow_label: 511,
length: 1400,
next_header: IPProtocol::ICMP6,
hop_limit: 5,
source_addr: Ipv6Addr::new(
0x2001, 0xdb8, 0x5cf8, 0x1aa8, 0x2481, 0x61e6, 0x5ac6, 0x3e0,
),
dest_addr: Ipv6Addr::new(
0x2001, 0xdb8, 0x7890, 0x2ae9, 0x908f, 0xa9f4, 0x2f4a, 0x9b80,
),
};
assert_eq!(parse_ipv6_header(&bytes), Ok((EMPTY_SLICE, expectation)));
}
}