1use arrayref::array_ref;
2use crate::Error;
3use crate::layer3::InternetProtocolId;
4use log::*;
5use nom::*;
6use std;
7
8const ADDRESS_LENGTH: usize = 16;
9
10#[derive(Clone, Copy, Debug)]
11pub struct IPv6<'a> {
12 pub dst_ip: std::net::IpAddr,
13 pub src_ip: std::net::IpAddr,
14 pub protocol: InternetProtocolId,
15 pub payload: &'a [u8],
16}
17
18fn to_ip_address(i: &[u8]) -> std::net::IpAddr {
19 let ipv6 = std::net::Ipv6Addr::from(array_ref![i, 0, ADDRESS_LENGTH].clone());
20 std::net::IpAddr::V6(ipv6)
21}
22
23named!(
24 ipv6_address<&[u8], std::net::IpAddr>,
25 map!(take!(ADDRESS_LENGTH), to_ip_address)
26);
27
28impl<'a> IPv6<'a> {
29 fn parse_next_header<'b>(
30 input: &'b [u8],
31 payload_length: u16,
32 next_header: InternetProtocolId,
33 ) -> IResult<&'b [u8], IPv6<'b>> {
34 if InternetProtocolId::has_next_option(next_header.clone()) {
35 let (rem, h) = do_parse!(input, h: map_opt!(be_u8, InternetProtocolId::new) >> (h))?;
36
37 IPv6::parse_next_header(rem, payload_length, h)
38 } else {
39 do_parse!(
40 input,
41 _h: take!(1) >> src: ipv6_address >>
43 dst: ipv6_address >>
44 payload: take!(payload_length) >>
45
46 (
47 IPv6 {
48 dst_ip: dst,
49 src_ip: src,
50 protocol: next_header,
51 payload: payload.into()
52 }
53 )
54 )
55 }
56 }
57
58 fn parse_ipv6<'b>(input: &'b [u8]) -> IResult<&'b [u8], IPv6<'b>> {
59 let (rem, (payload_length, next_header)) = do_parse!(
60 input,
61 _f: take!(3) >> p: be_u16 >>
63 h: map_opt!(be_u8, InternetProtocolId::new) >>
64
65 ( (p, h) )
66 )?;
67
68 trace!("Payload Lengt={}", payload_length);
69
70 IPv6::parse_next_header(rem, payload_length, next_header)
71 }
72
73 pub fn new(
74 dst_ip: std::net::Ipv6Addr,
75 src_ip: std::net::Ipv6Addr,
76 protocol: InternetProtocolId,
77 payload: &'a [u8],
78 ) -> IPv6 {
79 IPv6 {
80 dst_ip: std::net::IpAddr::V6(dst_ip),
81 src_ip: std::net::IpAddr::V6(src_ip),
82 protocol: protocol,
83 payload: payload,
84 }
85 }
86
87 pub fn parse<'b>(input: &'b [u8]) -> Result<(&'b [u8], IPv6<'b>), Error> {
88 trace!("Available={}", input.len());
89
90 be_u8(input).map_err(Error::from).and_then(|r| {
91 let (rem, length_check) = r;
92 let version = length_check >> 4;
93 if version == 6 {
94 IPv6::parse_ipv6(rem).map_err(Error::from)
95 } else {
96 Err(Error::Custom { msg: format!("Expected version 6, version was {}", version) } )
97 }
98 })
99 }
100}
101
102#[cfg(test)]
103pub mod tests {
104 use super::*;
105
106 pub const RAW_DATA: &'static [u8] = &[
107 0x65u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x34u8, 0x06u8, 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8, 0x0Au8, 0x0Bu8,
113 0x0Cu8, 0x0Du8, 0x0Eu8, 0x0Fu8, 0x0Fu8, 0x0Fu8, 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8,
115 0x0Au8, 0x0Bu8, 0x0Cu8, 0x0Du8, 0x0Eu8, 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,
128 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
129 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8, 0xfeu8,
130 0xffu8, ];
132
133 #[test]
134 fn parse_ipv6() {
135 let _ = env_logger::try_init();
136
137 let (rem, l3) = IPv6::parse(RAW_DATA).expect("Unable to parse");
138
139 assert_eq!(
140 l3.src_ip,
141 "102:304:506:708:90A:B0C:D0E:F0F"
142 .parse::<std::net::IpAddr>()
143 .expect("Could not parse ip address")
144 );
145 assert_eq!(
146 l3.dst_ip,
147 "F00:102:304:506:708:90A:B0C:D0E"
148 .parse::<std::net::IpAddr>()
149 .expect("Could not parse ip address")
150 );
151
152 let is_tcp = if let InternetProtocolId::Tcp = l3.protocol {
153 true
154 } else {
155 false
156 };
157
158 assert!(is_tcp);
159
160 assert!(rem.is_empty());
161 }
162}