zero_packet/network/extensions/
headers.rs

1use super::{
2    authentication::AuthenticationHeaderReader, fragment::FragmentHeaderReader,
3    options::OptionsHeaderReader, routing::RoutingHeaderReader,
4};
5use crate::misc::NextHeader;
6
7// Note:
8// According to RFC 8200 packets should not contain more than one occurence of an extension header.
9// An exception is the Destination Options header, which may occur twice.
10// However, IPv6 nodes have to be able to accept and process packets even if they contain any arbitrary
11// number of extension headers. Which means that these packets are still valid, even though they should not exist.
12
13/// Contains all present extension headers in an IPv6 packet.
14///
15/// Each extension header is optional and should appear only once.
16///
17/// Except the Destination Options header, which may occur twice.
18#[derive(Debug)]
19pub struct ExtensionHeaders<'a> {
20    pub hop_by_hop: Option<OptionsHeaderReader<'a>>,
21    pub routing: Option<RoutingHeaderReader<'a>>,
22    pub fragment: Option<FragmentHeaderReader<'a>>,
23    pub auth_header: Option<AuthenticationHeaderReader<'a>>,
24    pub destination_1st: Option<OptionsHeaderReader<'a>>,
25    pub destination_2nd: Option<OptionsHeaderReader<'a>>,
26    pub total_headers_len: usize,
27    pub final_next_header: u8,
28}
29
30impl<'a> ExtensionHeaders<'a> {
31    /// Creates a new `ExtensionHeaders`.
32    #[inline]
33    fn new() -> Self {
34        Self {
35            hop_by_hop: None,
36            routing: None,
37            fragment: None,
38            auth_header: None,
39            destination_1st: None,
40            destination_2nd: None,
41            total_headers_len: 0,
42            final_next_header: 0,
43        }
44    }
45    /// Parses the extension headers from the given byte slice.
46    ///
47    /// They are chained together through the next header field.
48    ///
49    /// Thus, we need to loop through them all to run down the chain.
50    #[inline]
51    pub fn parse(bytes: &'a [u8], next_header: u8) -> Result<Option<Self>, &'static str> {
52        let mut headers = Self::new();
53
54        let mut current_header = next_header;
55        let mut current_bytes = bytes;
56
57        while let Some((next_header, payload)) =
58            headers.parse_next_header(current_header, current_bytes)?
59        {
60            current_header = next_header;
61            current_bytes = payload;
62        }
63
64        if headers.is_empty() {
65            Ok(None)
66        } else {
67            Ok(Some(headers))
68        }
69    }
70
71    /// Parses the next extension header.
72    #[inline]
73    fn parse_next_header(
74        &mut self,
75        next_header: u8,
76        bytes: &'a [u8],
77    ) -> Result<Option<(u8, &'a [u8])>, &'static str> {
78        match NextHeader::from(next_header) {
79            NextHeader::HopByHop => self.parse_hop_by_hop_options(bytes),
80            NextHeader::Routing => self.parse_routing_header(bytes),
81            NextHeader::Fragment => self.parse_fragment_header(bytes),
82            NextHeader::AuthHeader => self.parse_auth_header(bytes),
83            NextHeader::Destination => self.parse_destination_options(bytes),
84            _ => Ok(None),
85        }
86    }
87
88    /// Parses the Hop-by-Hop Options extension header.
89    #[inline]
90    fn parse_hop_by_hop_options(
91        &mut self,
92        bytes: &'a [u8],
93    ) -> Result<Option<(u8, &'a [u8])>, &'static str> {
94        if self.hop_by_hop.is_some() {
95            return Ok(None);
96        }
97
98        if !self.is_empty() {
99            return Err(
100                "If Hop-by-Hop Options is present, then it must be the first extension header.",
101            );
102        }
103
104        let reader = OptionsHeaderReader::new(bytes)?;
105        let next_header = reader.next_header();
106        let payload = reader.payload()?;
107
108        self.total_headers_len += reader.header_len();
109        self.final_next_header = next_header;
110        self.hop_by_hop = Some(reader);
111
112        Ok(Some((next_header, payload)))
113    }
114
115    /// Parses the Routing extension header.
116    #[inline]
117    fn parse_routing_header(
118        &mut self,
119        bytes: &'a [u8],
120    ) -> Result<Option<(u8, &'a [u8])>, &'static str> {
121        if self.routing.is_some() {
122            return Ok(None);
123        }
124
125        let reader = RoutingHeaderReader::new(bytes)?;
126        let next_header = reader.next_header();
127        let payload = reader.payload()?;
128
129        self.total_headers_len += reader.header_len();
130        self.final_next_header = next_header;
131        self.routing = Some(reader);
132
133        Ok(Some((next_header, payload)))
134    }
135
136    /// Parses the Fragment extension header.
137    #[inline]
138    fn parse_fragment_header(
139        &mut self,
140        bytes: &'a [u8],
141    ) -> Result<Option<(u8, &'a [u8])>, &'static str> {
142        if self.fragment.is_some() {
143            return Ok(None);
144        }
145
146        let reader = FragmentHeaderReader::new(bytes)?;
147        let next_header = reader.next_header();
148        let payload = reader.payload();
149
150        self.total_headers_len += reader.header_len();
151        self.final_next_header = next_header;
152        self.fragment = Some(reader);
153
154        Ok(Some((next_header, payload)))
155    }
156
157    /// Parses the Authentication Header extension header.
158    #[inline]
159    fn parse_auth_header(
160        &mut self,
161        bytes: &'a [u8],
162    ) -> Result<Option<(u8, &'a [u8])>, &'static str> {
163        if self.auth_header.is_some() {
164            return Ok(None);
165        }
166
167        let reader = AuthenticationHeaderReader::new(bytes)?;
168        let next_header = reader.next_header();
169        let payload = reader.payload()?;
170
171        self.total_headers_len += reader.header_len();
172        self.final_next_header = next_header;
173        self.auth_header = Some(reader);
174
175        Ok(Some((next_header, payload)))
176    }
177
178    /// Parses the Destination Options extension header.
179    #[inline]
180    fn parse_destination_options(
181        &mut self,
182        bytes: &'a [u8],
183    ) -> Result<Option<(u8, &'a [u8])>, &'static str> {
184        if self.destination_2nd.is_some() {
185            return Ok(None);
186        }
187
188        let reader = OptionsHeaderReader::new(bytes)?;
189        let next_header = reader.next_header();
190        let payload = reader.payload()?;
191
192        self.total_headers_len += reader.header_len();
193        self.final_next_header = next_header;
194
195        if self.destination_1st.is_none() {
196            self.destination_1st = Some(reader);
197        } else {
198            self.destination_2nd = Some(reader);
199        }
200
201        Ok(Some((next_header, payload)))
202    }
203
204    /// Returns if no extension headers are present.
205    #[inline]
206    fn is_empty(&self) -> bool {
207        self.hop_by_hop.is_none()
208            && self.routing.is_none()
209            && self.fragment.is_none()
210            && self.auth_header.is_none()
211            && self.destination_1st.is_none()
212            && self.destination_2nd.is_none()
213    }
214}