net_parser_rs/layer3/
ipv6.rs

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) >> //hop limit
42                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) >> //version and stream label
62            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, //version and header length
108        0x00u8, 0x00u8, 0x00u8, //traffic class and label
109        0x00u8, 0x34u8, //payload length
110        0x06u8, //next hop, protocol, tcp
111        0x00u8, //hop limit
112        0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8, 0x0Au8, 0x0Bu8,
113        0x0Cu8, 0x0Du8, 0x0Eu8, 0x0Fu8, 0x0Fu8, //src ip 12:34:56:78:9A:BC:DE:FF
114        0x0Fu8, 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8,
115        0x0Au8, 0x0Bu8, 0x0Cu8, 0x0Du8, 0x0Eu8, //dst ip F0:12:34:56:78:9A:BC:DE
116        //tcp
117        0xC6u8, 0xB7u8, //src port, 50871
118        0x00u8, 0x50u8, //dst port, 80
119        0x00u8, 0x00u8, 0x00u8, 0x01u8, //sequence number, 1
120        0x00u8, 0x00u8, 0x00u8, 0x02u8, //acknowledgement number, 2
121        0x50u8, 0x00u8, //header and flags, 0
122        0x00u8, 0x00u8, //window
123        0x00u8, 0x00u8, //check
124        0x00u8, 0x00u8, //urgent
125        //no options
126        //payload
127        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, //payload, 8 words
131    ];
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}