Skip to main content

etherparse/net/
ip_auth_header_slice.rs

1use crate::*;
2use core::slice::from_raw_parts;
3
4/// Deprecated use [IpAuthHeaderSlice] instead.
5#[deprecated(
6    since = "0.14.0",
7    note = "Please use the type IpAuthHeaderSlice instead"
8)]
9pub type IpAuthenticationHeaderSlice<'a> = IpAuthHeaderSlice<'a>;
10
11/// A slice containing an IP Authentication Header (rfc4302)
12#[derive(Copy, Clone, Debug, Eq, PartialEq)]
13pub struct IpAuthHeaderSlice<'a> {
14    slice: &'a [u8],
15}
16
17impl<'a> IpAuthHeaderSlice<'a> {
18    /// Creates a ip authentication header slice from a slice.
19    pub fn from_slice(
20        slice: &'a [u8],
21    ) -> Result<IpAuthHeaderSlice<'a>, err::ip_auth::HeaderSliceError> {
22        use err::ip_auth::{HeaderError::*, HeaderSliceError::*};
23
24        // check slice length
25        if slice.len() < IpAuthHeader::MIN_LEN {
26            return Err(Len(err::LenError {
27                required_len: IpAuthHeader::MIN_LEN,
28                len: slice.len(),
29                len_source: LenSource::Slice,
30                layer: err::Layer::IpAuthHeader,
31                layer_start_offset: 0,
32            }));
33        }
34
35        // SAFETY:
36        // Safe the slice length gets checked to be at least 12 beforehand.
37        let payload_len_enc = unsafe { *slice.get_unchecked(1) };
38
39        // check header length minimum size
40        if payload_len_enc < 1 {
41            return Err(Content(ZeroPayloadLen));
42        }
43
44        // check length
45        // note: The unit is different then all other ipv6 extension headers.
46        //       In the other headers the length is in 8 octets, but for authentication
47        //       headers the length is in 4 octets.
48        let len = ((payload_len_enc as usize) + 2) * 4;
49        if slice.len() < len {
50            return Err(Len(err::LenError {
51                required_len: len,
52                len: slice.len(),
53                len_source: LenSource::Slice,
54                layer: err::Layer::IpAuthHeader,
55                layer_start_offset: 0,
56            }));
57        }
58
59        // all good
60        Ok(IpAuthHeaderSlice {
61            // SAFETY:
62            // Safe as slice len is checked to be at last len above.
63            slice: unsafe { from_raw_parts(slice.as_ptr(), len) },
64        })
65    }
66
67    /// Creates a ip authentication header slice from a slice (assumes slice size & content was validated before).
68    ///
69    /// # Safety
70    ///
71    /// This method assumes that the slice was previously validated to contain
72    /// a valid authentication header. This means the slice length must at
73    /// least be at least 8 and `(slice[1] + 2)*4`. The data that the
74    /// slice points must also be valid (meaning no nullptr or alike allowed).
75    ///
76    /// If these preconditions are not fulfilled the behavior of this function
77    /// and the methods of the return IpAuthHeaderSlice will be undefined.
78    pub unsafe fn from_slice_unchecked(slice: &'a [u8]) -> IpAuthHeaderSlice<'a> {
79        IpAuthHeaderSlice {
80            slice: from_raw_parts(slice.as_ptr(), ((*slice.get_unchecked(1) as usize) + 2) * 4),
81        }
82    }
83
84    /// Returns the slice containing the authentication header.
85    #[inline]
86    pub fn slice(&self) -> &'a [u8] {
87        self.slice
88    }
89
90    /// Returns the IP protocol number of the next header or transport layer protocol.
91    ///
92    /// See [IpNumber] or [ip_number] for a definition of the known values.
93    #[inline]
94    pub fn next_header(&self) -> IpNumber {
95        // SAFETY:
96        // Safe as slice length is checked in the constructor
97        // to be at least 12.
98        IpNumber(unsafe { *self.slice.get_unchecked(0) })
99    }
100
101    /// Read the security parameters index from the slice
102    #[inline]
103    pub fn spi(&self) -> u32 {
104        // SAFETY:
105        // Safe as slice length is checked in the constructor
106        // to be at least 12.
107        unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(4)) }
108    }
109
110    /// This unsigned 32-bit field contains a counter value that
111    /// increases by one for each packet sent.
112    #[inline]
113    pub fn sequence_number(&self) -> u32 {
114        // SAFETY:
115        // Safe as slice length is checked in the constructor
116        // to be at least 12.
117        unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(8)) }
118    }
119
120    /// Return a slice with the raw integrity check value
121    pub fn raw_icv(&self) -> &'a [u8] {
122        &self.slice[12..]
123    }
124
125    /// Decode some of the fields and copy the results to a
126    /// Ipv6ExtensionHeader struct together with a slice pointing
127    /// to the non decoded parts.
128    pub fn to_header(&self) -> IpAuthHeader {
129        IpAuthHeader::new(
130            self.next_header(),
131            self.spi(),
132            self.sequence_number(),
133            self.raw_icv(),
134        )
135        .unwrap()
136    }
137}
138
139#[cfg(test)]
140mod test {
141    use super::*;
142    use crate::test_gens::*;
143    use alloc::format;
144    use arrayvec::ArrayVec;
145    use err::ip_auth::{HeaderError::*, HeaderSliceError::*};
146    use proptest::prelude::*;
147
148    proptest! {
149        #[test]
150        fn debug(input in ip_auth_any()) {
151            let buffer = input.to_bytes();
152            let slice = IpAuthHeaderSlice::from_slice(&buffer).unwrap();
153            assert_eq!(
154                &format!(
155                    "IpAuthHeaderSlice {{ slice: {:?} }}",
156                    slice.slice()
157                ),
158                &format!("{:?}", slice)
159            );
160        }
161    }
162
163    #[test]
164    fn clone_eq() {
165        let buffer = IpAuthHeader::new(0.into(), 0, 0, &[0; 4])
166            .unwrap()
167            .to_bytes();
168        let slice = IpAuthHeaderSlice::from_slice(&buffer).unwrap();
169        assert_eq!(slice.clone(), slice);
170    }
171
172    proptest! {
173        #[test]
174        fn from_slice(header in ip_auth_any()) {
175
176            // ok
177            {
178                let mut bytes = ArrayVec::<u8, {IpAuthHeader::MAX_LEN + 2}>::new();
179                bytes.extend(header.to_bytes());
180                bytes.push(1);
181                bytes.push(2);
182
183                let slice = IpAuthHeaderSlice::from_slice(&bytes).unwrap();
184                assert_eq!(slice.slice(), &bytes[..bytes.len() - 2]);
185            }
186
187            // length error
188            {
189                let bytes = header.to_bytes();
190                for len in 0..header.header_len() {
191                    assert_eq!(
192                        IpAuthHeaderSlice::from_slice(&bytes[..len]).unwrap_err(),
193                        Len(err::LenError{
194                            required_len: if len < IpAuthHeader::MIN_LEN {
195                                IpAuthHeader::MIN_LEN
196                            } else {
197                                header.header_len()
198                            },
199                            len: len,
200                            len_source: LenSource::Slice,
201                            layer: err::Layer::IpAuthHeader,
202                            layer_start_offset: 0,
203                        })
204                    );
205                }
206            }
207
208            // payload length error
209            {
210                let mut bytes = header.to_bytes();
211                // set payload length to 0
212                bytes[1] = 0;
213                assert_eq!(
214                    IpAuthHeaderSlice::from_slice(&bytes).unwrap_err(),
215                    Content(ZeroPayloadLen)
216                );
217            }
218        }
219    }
220
221    proptest! {
222        #[test]
223        fn from_slice_unchecked(header in ip_auth_any()) {
224            let bytes = header.to_bytes();
225            let slice = unsafe {
226                IpAuthHeaderSlice::from_slice_unchecked(&bytes)
227            };
228            assert_eq!(slice.slice(), &bytes[..]);
229        }
230    }
231
232    proptest! {
233        #[test]
234        fn getters(header in ip_auth_any()) {
235            let bytes = header.to_bytes();
236            let slice = IpAuthHeaderSlice::from_slice(&bytes).unwrap();
237            assert_eq!(slice.slice(), &bytes[..]);
238            assert_eq!(slice.next_header(), header.next_header);
239            assert_eq!(slice.spi(), header.spi);
240            assert_eq!(slice.sequence_number(), header.sequence_number);
241            assert_eq!(slice.raw_icv(), header.raw_icv());
242        }
243    }
244
245    proptest! {
246        #[test]
247        fn to_header(header in ip_auth_any()) {
248            let bytes = header.to_bytes();
249            assert_eq!(
250                header,
251                IpAuthHeaderSlice::from_slice(&bytes)
252                    .unwrap()
253                    .to_header()
254            );
255        }
256    }
257}